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/3d/ps_force.h"
20 #include "nel/3d/driver.h"
21 #include "nel/3d/index_buffer.h"
22 #include "nel/3d/material.h"
23 #include "nel/3d/vertex_buffer.h"
24 #include "nel/3d/computed_string.h"
25 #include "nel/3d/font_manager.h"
26 #include "nel/3d/particle_system.h"
27 #include "nel/misc/common.h"
28 #include "nel/3d/ps_util.h"
29 #include "nel/3d/ps_misc.h"
43 NL_PS_FUNC(CPSForce_CPSForce
)
48 void CPSForce::serial(NLMISC::IStream
&f
)
50 NL_PS_FUNC(CPSForce_serial
)
52 CPSTargetLocatedBindable::serial(f
);
53 CPSLocatedBindable::serial(f
);
57 void CPSForce::registerToTargets(void)
59 NL_PS_FUNC(CPSForce_registerToTargets
)
60 for (TTargetCont::iterator it
= _Targets
.begin(); it
!= _Targets
.end(); ++it
)
62 if (this->isIntegrable())
64 (*it
)->registerIntegrableForce(this);
68 (*it
)->addNonIntegrableForceRef();
74 void CPSForce::step(TPSProcessPass pass
)
76 NL_PS_FUNC(CPSForce_step
)
88 void CPSForce::attachTarget(CPSLocated
*ptr
)
90 NL_PS_FUNC(CPSForce_attachTarget
)
92 CPSTargetLocatedBindable::attachTarget(ptr
);
93 // check whether we are integrable, and if so, add us to the list
94 if (this->isIntegrable())
96 ptr
->registerIntegrableForce(this);
100 ptr
->addNonIntegrableForceRef();
104 void CPSForce::releaseTargetRsc(CPSLocated
*target
)
106 NL_PS_FUNC(CPSForce_releaseTargetRsc
)
107 if (this->isIntegrable())
109 target
->unregisterIntegrableForce(this);
113 target
->releaseNonIntegrableForceRef();
119 void CPSForce::basisChanged(TPSMatrixMode matrixMode
)
121 NL_PS_FUNC(CPSForce_basisChanged
)
122 if (!this->isIntegrable()) return;
123 for (TTargetCont::iterator it
= _Targets
.begin(); it
!= _Targets
.end(); ++it
)
125 (*it
)->integrableForceBasisChanged(matrixMode
);
130 void CPSForce::cancelIntegrable(void)
132 NL_PS_FUNC(CPSForce_cancelIntegrable
)
134 for (TTargetCont::iterator it
= _Targets
.begin(); it
!= _Targets
.end(); ++it
)
136 if ((*it
)->getMatrixMode() == _Owner
->getMatrixMode())
138 (*it
)->unregisterIntegrableForce(this);
139 (*it
)->addNonIntegrableForceRef();
145 void CPSForce::renewIntegrable(void)
147 NL_PS_FUNC(CPSForce_renewIntegrable
)
149 for (TTargetCont::iterator it
= _Targets
.begin(); it
!= _Targets
.end(); ++it
)
151 if ((*it
)->getMatrixMode() == _Owner
->getMatrixMode())
153 (*it
)->registerIntegrableForce(this);
154 (*it
)->releaseNonIntegrableForceRef();
161 ///////////////////////////////////////
162 // CPSForceIntensity implementation //
163 ///////////////////////////////////////
165 void CPSForceIntensity::setIntensity(float value
)
167 NL_PS_FUNC(CPSForceIntensity_setIntensity
)
168 if (_IntensityScheme
)
170 delete _IntensityScheme
;
171 _IntensityScheme
= NULL
;
177 CPSForceIntensity::~CPSForceIntensity()
179 NL_PS_FUNC(CPSForceIntensity_CPSForceIntensityDtor
)
180 delete _IntensityScheme
;
183 void CPSForceIntensity::setIntensityScheme(CPSAttribMaker
<float> *scheme
)
185 NL_PS_FUNC(CPSForceIntensity_setIntensityScheme
)
187 delete _IntensityScheme
;
188 _IntensityScheme
= scheme
;
189 if (getForceIntensityOwner() && scheme
->hasMemory()) scheme
->resize(getForceIntensityOwner()->getMaxSize(), getForceIntensityOwner()->getSize());
192 void CPSForceIntensity::serialForceIntensity(NLMISC::IStream
&f
)
194 NL_PS_FUNC(CPSForceIntensity_IStream
)
198 if (_IntensityScheme
)
202 f
.serialPolyPtr(_IntensityScheme
);
213 bool constantIntensity
;
214 f
.serial(constantIntensity
);
215 if (constantIntensity
)
221 f
.serialPolyPtr(_IntensityScheme
);
227 ////////////////////////////////////////
228 // CPSForceIntensityHelper //
229 ////////////////////////////////////////
232 void CPSForceIntensityHelper::serial(NLMISC::IStream
&f
)
234 NL_PS_FUNC(CPSForceIntensityHelper_serial
)
237 serialForceIntensity(f
);
246 ////////////////////////////////////////
247 // CPSDirectionalForce implementation //
248 ////////////////////////////////////////
250 void CPSDirectionnalForce::computeForces(CPSLocated
&target
)
252 NL_PS_FUNC(CPSDirectionnalForce_computeForces
)
253 nlassert(CParticleSystem::InsideSimLoop
);
254 // perform the operation on each target
256 for (uint32 k
= 0; k
< _Owner
->getSize(); ++k
)
261 if (_GlobalValueHandle
.isValid()) // is direction a global variable ?
263 dir
= _GlobalValueHandle
.get(); // takes direction from global variable instead
269 toAddLocal
= CParticleSystem::EllapsedTime
* (_IntensityScheme
? _IntensityScheme
->get(_Owner
, k
) : _K
) * dir
;
270 toAdd
= CPSLocated::getConversionMatrix(&target
, this->_Owner
).mulVector(toAddLocal
); // express this in the target basis
271 TPSAttribVector::iterator it
= target
.getSpeed().begin(), itend
= target
.getSpeed().end();
272 // 1st case : non-constant mass
273 if (target
.getMassScheme())
275 TPSAttribFloat::const_iterator invMassIt
= target
.getInvMass().begin();
276 for (;it
!= itend
; ++it
, ++invMassIt
)
278 (*it
) += *invMassIt
* toAdd
;
284 // the mass is constant
285 toAdd
/= target
.getInitialMass();
286 for (; it
!= itend
; ++it
)
295 void CPSDirectionnalForce::show()
297 NL_PS_FUNC(CPSDirectionnalForce_show
)
300 CPSLocatedBindable
*lb
;
301 _Owner
->getOwner()->getCurrentEditedElement(loc
, index
, lb
);
303 setupDriverModelMatrix();
306 if (_GlobalValueHandle
.isValid()) // is direction a global variable ?
308 dir
= _GlobalValueHandle
.get(); // takes direction from global variable instead
315 // for each element, see if it is the selected element, and if yes, display in red
316 for (uint k
= 0; k
< _Owner
->getSize(); ++k
)
318 const CRGBA col
= (((lb
== NULL
|| this == lb
) && loc
== _Owner
&& index
== k
) ? CRGBA::Red
: CRGBA(127, 127, 127));
319 CPSUtil::displayArrow(getDriver(), _Owner
->getPos()[k
], dir
, 1.f
, col
, CRGBA(80, 80, 0));
323 void CPSDirectionnalForce::serial(NLMISC::IStream
&f
)
325 NL_PS_FUNC(CPSDirectionnalForce_serial
)
326 // Version 2 : added link to a global vector value
328 sint ver
= f
.serialVersion(2);
329 CPSForceIntensityHelper::serial(f
);
333 _GlobalValueHandle
.reset();
337 bool useHandle
= _GlobalValueHandle
.isValid();
341 // a global value is used
344 std::string handleName
;
345 f
.serial(handleName
);
346 // retrieve a handle to the global value from the particle system
347 _GlobalValueHandle
= CParticleSystem::getGlobalVectorValueHandle(handleName
);
351 std::string handleName
= _GlobalValueHandle
.getName();
352 f
.serial(handleName
);
362 void CPSDirectionnalForce::enableGlobalVectorValue(const std::string
&name
)
364 NL_PS_FUNC(CPSDirectionnalForce_enableGlobalVectorValue
)
367 _GlobalValueHandle
.reset();
370 _GlobalValueHandle
= CParticleSystem::getGlobalVectorValueHandle(name
);
373 std::string
CPSDirectionnalForce::getGlobalVectorValueName() const
375 NL_PS_FUNC(CPSDirectionnalForce_getGlobalVectorValueName
)
376 return _GlobalValueHandle
.isValid() ? _GlobalValueHandle
.getName() : "";
379 ////////////////////////////
380 // gravity implementation //
381 ////////////////////////////
382 void CPSGravity::computeForces(CPSLocated
&target
)
384 NL_PS_FUNC(CPSGravity_computeForces
)
385 nlassert(CParticleSystem::InsideSimLoop
);
386 // perform the operation on each target
388 for (uint32 k
= 0; k
< _Owner
->getSize(); ++k
)
390 CVector toAddLocal
= CParticleSystem::EllapsedTime
* CVector(0, 0, _IntensityScheme
? - _IntensityScheme
->get(_Owner
, k
) : - _K
);
391 toAdd
= CPSLocated::getConversionMatrix(&target
, this->_Owner
).mulVector(toAddLocal
); // express this in the target basis
392 TPSAttribVector::iterator it
= target
.getSpeed().begin(), itend
= target
.getSpeed().end();
394 if (toAdd
.x
&& toAdd
.y
)
396 for (; it
!= itend
; ++it
)
402 else // only the z component is not null, which should be the majority of cases ...
404 for (; it
!= itend
; ++it
)
413 void CPSGravity::show()
415 NL_PS_FUNC(CPSGravity_show
)
416 CVector I
= computeI();
417 CVector K
= CVector(0,0,1);
419 // this is not designed for efficiency (target : edition code)
423 IDriver
*driver
= getDriver();
424 const float toolSize
= 0.2f
;
426 vb
.setVertexFormat(CVertexBuffer::PositionFlag
);
427 vb
.setNumVertices(6);
429 CVertexBufferReadWrite vba
;
431 vba
.setVertexCoord(0, -toolSize
* I
);
432 vba
.setVertexCoord(1, toolSize
* I
);
433 vba
.setVertexCoord(2, CVector(0, 0, 0));
434 vba
.setVertexCoord(3, -6.0f
* toolSize
* K
);
435 vba
.setVertexCoord(4, -toolSize
* I
- 5.0f
* toolSize
* K
);
436 vba
.setVertexCoord(5, toolSize
* I
- 5.0f
* toolSize
* K
);
438 pb
.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT
);
439 pb
.setNumIndexes(2*4);
441 CIndexBufferReadWrite ibaWrite
;
443 ibaWrite
.setLine(0, 0, 1);
444 ibaWrite
.setLine(2, 2, 3);
445 ibaWrite
.setLine(4, 4, 3);
446 ibaWrite
.setLine(6, 3, 5);
449 material
.setColor(CRGBA(127, 127, 127));
450 material
.setLighting(false);
451 material
.setBlendFunc(CMaterial::one
, CMaterial::one
);
452 material
.setZWrite(false);
453 material
.setBlend(true);
458 for (TPSAttribVector::const_iterator it
= _Owner
->getPos().begin(); it
!= _Owner
->getPos().end(); ++it
)
462 mat
= getLocalToWorldMatrix() * mat
;
464 driver
->setupModelMatrix(mat
);
465 driver
->activeVertexBuffer(vb
);
466 driver
->activeIndexBuffer(pb
);
467 driver
->renderLines(material
, 0, pb
.getNumIndexes()/2);
471 // affiche un g a cote de la force
473 CVector pos
= *it
+ CVector(1.5f
* toolSize
, 0, -1.2f
* toolSize
);
475 pos
= getLocalToWorldMatrix() * pos
;
478 // must have set this
479 nlassert(getFontGenerator() && getFontGenerator());
481 CPSUtil::print(driver
, std::string("G")
482 , *getFontGenerator()
485 , 80.0f
* toolSize
);
491 void CPSGravity::serial(NLMISC::IStream
&f
)
493 NL_PS_FUNC(CPSGravity_IStream
)
495 CPSForceIntensityHelper::serial(f
);
499 bool CPSGravity::isIntegrable(void) const
501 NL_PS_FUNC(CPSGravity_isIntegrable
)
502 return _IntensityScheme
== NULL
;
505 void CPSGravity::integrate(float date
, CPSLocated
*src
, uint32 startIndex
, uint32 numObjects
, NLMISC::CVector
*destPos
, NLMISC::CVector
*destSpeed
,
507 uint posStride
, uint speedStride
510 NL_PS_FUNC(CPSGravity_integrate
)
511 #define NEXT_SPEED destSpeed = (NLMISC::CVector *) ((uint8 *) destSpeed + speedStride);
512 #define NEXT_POS destPos = (NLMISC::CVector *) ((uint8 *) destPos + posStride);
516 if (!destPos
&& !destSpeed
) return;
518 CPSLocated::TPSAttribParametricInfo::const_iterator it
= src
->_PInfo
.begin() + startIndex
,
519 endIt
= src
->_PInfo
.begin() + startIndex
+ numObjects
;
520 if (!accumulate
) // compute coords from initial condition, and applying this force
522 if (destPos
&& !destSpeed
) // fills dest pos only
526 deltaT
= date
- it
->Date
;
527 destPos
->x
= it
->Pos
.x
+ deltaT
* it
->Speed
.x
;
528 destPos
->y
= it
->Pos
.y
+ deltaT
* it
->Speed
.y
;
529 destPos
->z
= it
->Pos
.z
+ deltaT
* it
->Speed
.z
- 0.5f
* deltaT
* deltaT
* _K
;
534 else if (!destPos
&& destSpeed
) // fills dest speed only
538 deltaT
= date
- it
->Date
;
539 destSpeed
->x
= it
->Speed
.x
;
540 destSpeed
->y
= it
->Speed
.y
;
541 destSpeed
->z
= it
->Speed
.z
- deltaT
* _K
;
546 else // fills both speed and pos
550 deltaT
= date
- it
->Date
;
551 destPos
->x
= it
->Pos
.x
+ deltaT
* it
->Speed
.x
;
552 destPos
->y
= it
->Pos
.y
+ deltaT
* it
->Speed
.y
;
553 destPos
->z
= it
->Pos
.z
+ deltaT
* it
->Speed
.z
- 0.5f
* deltaT
* deltaT
* _K
;
555 destSpeed
->x
= it
->Speed
.x
;
556 destSpeed
->y
= it
->Speed
.y
;
557 destSpeed
->z
= it
->Speed
.z
- deltaT
* _K
;
565 else // accumulate datas
567 if (destPos
&& !destSpeed
) // fills dest pos only
571 deltaT
= date
- it
->Date
;
572 destPos
->z
-= 0.5f
* deltaT
* deltaT
* _K
;
577 else if (!destPos
&& destSpeed
) // fills dest speed only
581 deltaT
= date
- it
->Date
;
582 destSpeed
->z
-= deltaT
* _K
;
587 else // fills both speed and pos
591 deltaT
= date
- it
->Date
;
592 destPos
->z
-= 0.5f
* deltaT
* deltaT
* _K
;
593 destSpeed
->z
-= deltaT
* _K
;
605 void CPSGravity::integrateSingle(float startDate
, float deltaT
, uint numStep
,
606 const CPSLocated
*src
, uint32 indexInLocated
,
607 NLMISC::CVector
*destPos
,
608 bool accumulate
/*= false*/,
609 uint stride
/* = sizeof(NLMISC::CVector)*/) const
611 NL_PS_FUNC(CPSGravity_CVector
)
612 nlassert(src
->isParametricMotionEnabled());
613 //nlassert(deltaT > 0);
614 nlassert(numStep
> 0);
616 NLMISC::CVector
*endPos
= (NLMISC::CVector
*) ( (uint8
*) destPos
+ stride
* numStep
);
618 const CPSLocated::CParametricInfo
&pi
= src
->_PInfo
[indexInLocated
];
619 const NLMISC::CVector
&startPos
= pi
.Pos
;
624 destPos
= FillBufUsingSubdiv(startPos
, pi
.Date
, startDate
, deltaT
, numStep
, destPos
, stride
);
627 float currDate
= startDate
- pi
.Date
;
628 nlassert(currDate
>= 0);
629 const NLMISC::CVector
&startSpeed
= pi
.Speed
;
633 nlassert(destPos
< endPos
);
635 float halfTimeSquare
= 0.5f
* currDate
* currDate
;
636 destPos
->x
= startPos
.x
+ currDate
* startSpeed
.x
;
637 destPos
->y
= startPos
.y
+ currDate
* startSpeed
.y
;
638 destPos
->z
= startPos
.z
+ currDate
* startSpeed
.z
- _K
* halfTimeSquare
;
640 destPos
= (NLMISC::CVector
*) ( (uint8
*) destPos
+ stride
);
647 uint numToSkip
= ScaleFloatGE(startDate
, deltaT
, pi
.Date
, numStep
);
648 if (numToSkip
< numStep
)
650 numStep
-= numToSkip
;
651 float currDate
= startDate
+ deltaT
* numToSkip
- pi
.Date
;
655 nlassert(destPos
< endPos
);
657 float halfTimeSquare
= 0.5f
* currDate
* currDate
;
658 destPos
->z
-= _K
* halfTimeSquare
;
660 destPos
= (NLMISC::CVector
*) ( (uint8
*) destPos
+ stride
);
669 void CPSGravity::setIntensity(float value
)
671 NL_PS_FUNC(CPSGravity_setIntensity
)
672 if (_IntensityScheme
)
674 CPSForceIntensityHelper::setIntensity(value
);
675 renewIntegrable(); // integrable again
679 CPSForceIntensityHelper::setIntensity(value
);
683 void CPSGravity::setIntensityScheme(CPSAttribMaker
<float> *scheme
)
685 NL_PS_FUNC(CPSGravity_setIntensityScheme
)
686 if (!_IntensityScheme
)
688 cancelIntegrable(); // not integrable anymore
690 CPSForceIntensityHelper::setIntensityScheme(scheme
);
694 /////////////////////////////////////////
695 // CPSCentralGravity implementation //
696 /////////////////////////////////////////
698 void CPSCentralGravity::computeForces(CPSLocated
&target
)
700 NL_PS_FUNC(CPSCentralGravity_computeForces
)
701 nlassert(CParticleSystem::InsideSimLoop
);
702 // for each central gravity, and each target, we check if they are in the same basis
703 // if not, we need to transform the central gravity attachment pos into the target basis
704 uint32 size
= _Owner
->getSize();
705 // a vector that goes from the gravity to the object
709 for (uint32 k
= 0; k
< size
; ++k
)
711 const float ellapsedTimexK
= CParticleSystem::EllapsedTime
* (_IntensityScheme
? _IntensityScheme
->get(_Owner
, k
) : _K
);
712 const CMatrix
&m
= CPSLocated::getConversionMatrix(&target
, this->_Owner
);
713 const CVector center
= m
* (_Owner
->getPos()[k
]);
714 TPSAttribVector::iterator it2
= target
.getSpeed().begin(), it2End
= target
.getSpeed().end();
715 TPSAttribFloat::const_iterator invMassIt
= target
.getInvMass().begin();
716 TPSAttribVector::const_iterator posIt
= target
.getPos().begin();
717 for (; it2
!= it2End
; ++it2
, ++invMassIt
, ++posIt
)
719 // our equation does 1 / r attenuation, which is not realistic, but fast ...
720 centerToObj
= center
- *posIt
;
722 dist
= centerToObj
* centerToObj
;
725 (*it2
) += (*invMassIt
) * ellapsedTimexK
* (1.f
/ dist
) * centerToObj
;
731 void CPSCentralGravity::show()
733 NL_PS_FUNC(CPSCentralGravity_show
)
734 CVector I
= CVector::I
;
735 CVector J
= CVector::J
;
737 const CVector tab
[] = { -I
- J
, I
- J
744 const uint tabSize
= sizeof(tab
) / (2 * sizeof(CVector
));
746 const float sSize
= 0.08f
;
747 displayIcon2d(tab
, tabSize
, sSize
);
750 void CPSCentralGravity::serial(NLMISC::IStream
&f
)
752 NL_PS_FUNC(CPSCentralGravity_IStream
)
754 CPSForceIntensityHelper::serial(f
);
758 /////////////////////////////////
759 // CPSSpring implementation //
760 /////////////////////////////////
764 void CPSSpring::computeForces(CPSLocated
&target
)
766 NL_PS_FUNC(CPSSpring_computeForces
)
767 nlassert(CParticleSystem::InsideSimLoop
);
768 // for each spring, and each target, we check if they are in the same basis
769 // if not, we need to transform the spring attachment pos into the target basis
770 uint32 size
= _Owner
->getSize();
771 for (uint32 k
= 0; k
< size
; ++k
)
773 const float ellapsedTimexK
= CParticleSystem::EllapsedTime
* (_IntensityScheme
? _IntensityScheme
->get(_Owner
, k
) : _K
);
774 const CMatrix
&m
= CPSLocated::getConversionMatrix(&target
, this->_Owner
);
775 const CVector center
= m
* (_Owner
->getPos()[k
]);
776 TPSAttribVector::iterator it
= target
.getSpeed().begin(), itEnd
= target
.getSpeed().end();
777 TPSAttribFloat::const_iterator invMassIt
= target
.getInvMass().begin();
778 TPSAttribVector::const_iterator posIt
= target
.getPos().begin();
779 for (; it
!= itEnd
; ++it
, ++invMassIt
, ++posIt
)
781 // apply the spring equation
782 (*it
) += (*invMassIt
) * ellapsedTimexK
* (center
- *posIt
);
788 void CPSSpring::serial(NLMISC::IStream
&f
)
790 NL_PS_FUNC(CPSSpring_serial
)
792 CPSForceIntensityHelper::serial(f
);
797 void CPSSpring::show()
799 NL_PS_FUNC(CPSSpring_show
)
800 CVector I
= CVector::I
;
801 CVector J
= CVector::J
;
802 static const CVector tab
[] =
817 const uint tabSize
= sizeof(tab
) / (2 * sizeof(CVector
));
818 const float sSize
= 0.08f
;
819 displayIcon2d(tab
, tabSize
, sSize
);
823 /////////////////////////////////////////
824 // CPSCylindricVortex implementation //
825 /////////////////////////////////////////
826 void CPSCylindricVortex::computeForces(CPSLocated
&target
)
828 NL_PS_FUNC(CPSCylindricVortex_computeForces
)
829 nlassert(CParticleSystem::InsideSimLoop
);
830 uint32 size
= _Owner
->getSize();
831 for (uint32 k
= 0; k
< size
; ++k
) // for each vortex
833 const float invR
= 1.f
/ _Radius
[k
];
834 const float radius2
= _Radius
[k
] * _Radius
[k
];
835 // intensity for this vortex
837 float intensity
= (_IntensityScheme
? _IntensityScheme
->get(_Owner
, k
) : _K
);
838 // express the vortex position and plane normal in the located basis
839 const CMatrix
&m
= CPSLocated::getConversionMatrix(&target
, this->_Owner
);
840 const CVector center
= m
* (_Owner
->getPos()[k
]);
841 const CVector n
= m
.mulVector(_Normal
[k
]);
842 TPSAttribVector::iterator speedIt
= target
.getSpeed().begin(), speedItEnd
= target
.getSpeed().end();
843 TPSAttribFloat::const_iterator invMassIt
= target
.getInvMass().begin();
844 TPSAttribVector::const_iterator posIt
= target
.getPos().begin();
845 // projection of the current located pos on the vortex axis
847 // a vector that go from the vortex center to the point we're dealing with
849 // the square of the dist of the projected pos
851 CVector realTangentialSpeed
;
852 CVector tangentialSpeed
;
854 for (; speedIt
!= speedItEnd
; ++speedIt
, ++invMassIt
, ++posIt
)
856 v2p
= *posIt
- center
;
857 p
= v2p
- (v2p
* n
) * n
;
859 if (d2
< radius2
) // not out of range ?
865 // compute the speed vect that we should have (normalized)
866 realTangentialSpeed
= n
^ p
;
867 tangentialSpeed
= (*speedIt
* realTangentialSpeed
) * realTangentialSpeed
;
868 radialSpeed
= (p
* *speedIt
) * p
;
869 // update radial speed;
870 *speedIt
-= _RadialViscosity
* CParticleSystem::EllapsedTime
* radialSpeed
;
871 // update tangential speed
872 *speedIt
-= _TangentialViscosity
* intensity
* CParticleSystem::EllapsedTime
* (tangentialSpeed
- (1.f
- d
* invR
) * realTangentialSpeed
);
880 void CPSCylindricVortex::show()
882 NL_PS_FUNC(CPSCylindricVortex_show
)
885 CPSLocatedBindable
*lb
;
886 _Owner
->getOwner()->getCurrentEditedElement(loc
, index
, lb
);
889 // must have set this
890 nlassert(getFontGenerator() && getFontGenerator());
891 setupDriverModelMatrix();
893 for (uint k
= 0; k
< _Owner
->getSize(); ++k
)
895 const CRGBA col
= ((lb
== NULL
|| this == lb
) && loc
== _Owner
&& index
== k
? CRGBA::Red
: CRGBA(127, 127, 127));
897 CPSUtil::buildSchmidtBasis(_Normal
[k
], m
);
898 CPSUtil::displayDisc(*getDriver(), _Radius
[k
], _Owner
->getPos()[k
], m
, 32, col
);
899 CPSUtil::displayArrow(getDriver(), _Owner
->getPos()[k
], _Normal
[k
], 1.f
, col
, CRGBA(200, 0, 200));
900 // display a V letter at the center
901 CPSUtil::print(getDriver(), std::string("v"), *getFontGenerator(), *getFontManager(), _Owner
->getPos()[k
], 80.f
);
906 void CPSCylindricVortex::setMatrix(uint32 index
, const CMatrix
&m
)
908 NL_PS_FUNC(CPSCylindricVortex_setMatrix
)
909 nlassert(index
< _Normal
.getSize());
910 _Normal
[index
] = m
.getK();
911 _Owner
->getPos()[index
] = m
.getPos();
914 CMatrix
CPSCylindricVortex::getMatrix(uint32 index
) const
916 NL_PS_FUNC(CPSCylindricVortex_getMatrix
)
918 CPSUtil::buildSchmidtBasis(_Normal
[index
], m
);
919 m
.setPos(_Owner
->getPos()[index
] );
924 void CPSCylindricVortex::serial(NLMISC::IStream
&f
)
926 NL_PS_FUNC(CPSCylindricVortex_IStream
)
928 CPSForceIntensityHelper::serial(f
);
931 f
.serial(_RadialViscosity
);
932 f
.serial(_TangentialViscosity
);
935 void CPSCylindricVortex::newElement(const CPSEmitterInfo
&info
)
937 NL_PS_FUNC(CPSCylindricVortex_newElement
)
938 CPSForceIntensityHelper::newElement(info
);
939 _Normal
.insert(CVector::K
);
942 void CPSCylindricVortex::deleteElement(uint32 index
)
944 NL_PS_FUNC(CPSCylindricVortex_deleteElement
)
945 CPSForceIntensityHelper::deleteElement(index
);
946 _Normal
.remove(index
);
947 _Radius
.remove(index
);
949 void CPSCylindricVortex::resize(uint32 size
)
951 NL_PS_FUNC(CPSCylindricVortex_resize
)
952 nlassert(size
< (1 << 16));
953 CPSForceIntensityHelper::resize(size
);
954 _Normal
.resize(size
);
955 _Radius
.resize(size
);
960 * a magnetic field that has the given direction
963 void CPSMagneticForce::serial(NLMISC::IStream
&f
)
965 NL_PS_FUNC(CPSMagneticForce_serial
)
967 CPSDirectionnalForce::serial(f
);
970 void CPSMagneticForce::computeForces(CPSLocated
&target
)
972 NL_PS_FUNC(CPSMagneticForce_computeForces
)
973 nlassert(CParticleSystem::InsideSimLoop
);
974 // perform the operation on each target
975 for (uint32 k
= 0; k
< _Owner
->getSize(); ++k
)
977 float intensity
= CParticleSystem::EllapsedTime
* (_IntensityScheme
? _IntensityScheme
->get(_Owner
, k
) : _K
);
978 NLMISC::CVector toAdd
= CPSLocated::getConversionMatrix(&target
, this->_Owner
).mulVector(_Dir
); // express this in the target basis
979 TPSAttribVector::iterator it
= target
.getSpeed().begin(), itend
= target
.getSpeed().end();
980 // 1st case : non-constant mass
981 if (target
.getMassScheme())
983 TPSAttribFloat::const_iterator invMassIt
= target
.getInvMass().begin();
984 for (; it
!= itend
; ++it
, ++invMassIt
)
986 (*it
) += intensity
* *invMassIt
* (*it
^ toAdd
);
991 float i
= intensity
/ target
.getInitialMass();
992 for (; it
!= itend
; ++it
)
994 (*it
) += i
* (*it
^ toAdd
);
1002 * Brownian force implementation
1005 const uint BFNumPredefinedPos
= 8192; // should be a power of 2
1006 const uint BFPredefinedNumInterp
= 256; /** this should divide BFNumPredefinedPos. This define the number
1007 * of values used to interpolate between 2 position of the npose
1008 * (because we don't filter values when we access them)
1010 const uint BFNumPrecomputedImpulsions
= 1024; /// used to avoid to have to call rand for each particle the force applies on...
1012 NLMISC::CVector
CPSBrownianForce::PrecomputedPos
[BFNumPredefinedPos
]; // after the sequence we must be back to the start position
1013 NLMISC::CVector
CPSBrownianForce::PrecomputedSpeed
[BFNumPredefinedPos
];
1014 NLMISC::CVector
CPSBrownianForce::PrecomputedImpulsions
[BFNumPrecomputedImpulsions
];
1016 ///==========================================================
1017 CPSBrownianForce::CPSBrownianForce(float intensity
/* = 1.f*/) : _ParametricFactor(1.f
)
1019 NL_PS_FUNC(CPSBrownianForce_CPSBrownianForce
)
1020 setIntensity(intensity
);
1021 if (CParticleSystem::getSerializeIdentifierFlag()) _Name
= std::string("BrownianForce");
1025 ///==========================================================
1026 bool CPSBrownianForce::isIntegrable(void) const
1028 NL_PS_FUNC(CPSBrownianForce_isIntegrable
)
1029 return _IntensityScheme
== NULL
;
1033 ///==========================================================
1034 void CPSBrownianForce::integrate(float date
, CPSLocated
*src
,
1037 NLMISC::CVector
*destPos
,
1038 NLMISC::CVector
*destSpeed
,
1040 uint posStride
, uint speedStride
1043 NL_PS_FUNC(CPSBrownianForce_integrate
)
1044 /// MASS DIFFERENT FROM 1 IS NOT SUPPORTED
1046 if (!destPos
&& !destSpeed
) return;
1047 CPSLocated::TPSAttribParametricInfo::const_iterator it
= src
->_PInfo
.begin() + startIndex
,
1048 endIt
= src
->_PInfo
.begin() + startIndex
+ numObjects
;
1049 float lookUpFactor
= _ParametricFactor
* BFNumPredefinedPos
;
1050 float speedFactor
= _ParametricFactor
* _K
;
1051 if (!accumulate
) // compute coords from initial condition, and applying this force
1053 if (destPos
&& !destSpeed
) // fills dest pos only
1057 float deltaT
= date
- it
->Date
;
1058 uint index
= (uint
) (lookUpFactor
* deltaT
) & (BFNumPredefinedPos
- 1);
1059 destPos
->set(it
->Pos
.x
+ deltaT
* it
->Speed
.x
+ _K
* PrecomputedPos
[index
].x
,
1060 it
->Pos
.y
+ deltaT
* it
->Speed
.y
+ _K
* PrecomputedPos
[index
].y
,
1061 it
->Pos
.z
+ deltaT
* it
->Speed
.z
+ _K
* PrecomputedPos
[index
].z
);
1066 else if (!destPos
&& destSpeed
) // fills dest speed only
1070 deltaT
= date
- it
->Date
;
1071 uint index
= (uint
) (lookUpFactor
* deltaT
) & (BFNumPredefinedPos
- 1);
1072 destSpeed
->x
= it
->Speed
.x
+ speedFactor
* PrecomputedSpeed
[index
].x
;
1073 destSpeed
->y
= it
->Speed
.y
+ speedFactor
* PrecomputedSpeed
[index
].y
;
1074 destSpeed
->z
= it
->Speed
.z
+ speedFactor
* PrecomputedSpeed
[index
].z
;
1079 else // fills both speed and pos
1083 deltaT
= date
- it
->Date
;
1084 uint index
= (uint
) (lookUpFactor
* deltaT
) & (BFNumPredefinedPos
- 1);
1085 destPos
->x
= it
->Pos
.x
+ deltaT
* it
->Speed
.x
+ _K
* PrecomputedPos
[index
].x
;
1086 destPos
->y
= it
->Pos
.y
+ deltaT
* it
->Speed
.y
+ _K
* PrecomputedPos
[index
].y
;
1087 destPos
->z
= it
->Pos
.z
+ deltaT
* it
->Speed
.z
+ _K
* PrecomputedPos
[index
].z
;
1089 destSpeed
->x
= it
->Speed
.x
+ speedFactor
* PrecomputedSpeed
[index
].x
;
1090 destSpeed
->y
= it
->Speed
.y
+ speedFactor
* PrecomputedSpeed
[index
].y
;
1091 destSpeed
->z
= it
->Speed
.z
+ speedFactor
* PrecomputedSpeed
[index
].z
;
1099 else // accumulate datas
1101 if (destPos
&& !destSpeed
) // fills dest pos only
1105 deltaT
= date
- it
->Date
;
1106 uint index
= (uint
) (lookUpFactor
* deltaT
) & (BFNumPredefinedPos
- 1);
1107 destPos
->set(destPos
->x
+ _K
* PrecomputedPos
[index
].x
,
1108 destPos
->y
+ _K
* PrecomputedPos
[index
].y
,
1109 destPos
->z
+ _K
* PrecomputedPos
[index
].z
);
1114 else if (!destPos
&& destSpeed
) // fills dest speed only
1118 deltaT
= date
- it
->Date
;
1119 uint index
= (uint
) (lookUpFactor
* deltaT
) & (BFNumPredefinedPos
- 1);
1120 destSpeed
->set(destSpeed
->x
+ speedFactor
* PrecomputedSpeed
[index
].x
,
1121 destSpeed
->y
+ speedFactor
* PrecomputedSpeed
[index
].y
,
1122 destSpeed
->z
+ speedFactor
* PrecomputedSpeed
[index
].z
);
1127 else // fills both speed and pos
1131 deltaT
= date
- it
->Date
;
1132 uint index
= (uint
) (lookUpFactor
* deltaT
) & (BFNumPredefinedPos
- 1);
1133 destPos
->set(destPos
->x
+ _K
* PrecomputedPos
[index
].x
,
1134 destPos
->y
+ _K
* PrecomputedPos
[index
].y
,
1135 destPos
->z
+ _K
* PrecomputedPos
[index
].z
);
1136 destSpeed
->set(destSpeed
->x
+ speedFactor
* PrecomputedSpeed
[index
].x
,
1137 destSpeed
->y
+ speedFactor
* PrecomputedSpeed
[index
].y
,
1138 destSpeed
->z
+ speedFactor
* PrecomputedSpeed
[index
].z
);
1148 ///==========================================================
1149 void CPSBrownianForce::integrateSingle(float startDate
, float deltaT
, uint numStep
,
1150 const CPSLocated
*src
, uint32 indexInLocated
,
1151 NLMISC::CVector
*destPos
,
1155 NL_PS_FUNC(CPSBrownianForce_integrateSingle
)
1156 nlassert(src
->isParametricMotionEnabled());
1157 //nlassert(deltaT > 0);
1158 nlassert(numStep
> 0);
1160 NLMISC::CVector
*endPos
= (NLMISC::CVector
*) ( (uint8
*) destPos
+ stride
* numStep
);
1162 const CPSLocated::CParametricInfo
&pi
= src
->_PInfo
[indexInLocated
];
1163 const NLMISC::CVector
&startPos
= pi
.Pos
;
1166 float lookUpFactor
= _ParametricFactor
* BFPredefinedNumInterp
;
1169 /// fill start of datas (particle didn't exist at that time, so we fill by the start position)
1170 destPos
= FillBufUsingSubdiv(startPos
, pi
.Date
, startDate
, deltaT
, numStep
, destPos
, stride
);
1173 float currDate
= startDate
- pi
.Date
;
1174 nlassert(currDate
>= 0);
1175 const NLMISC::CVector
&startSpeed
= pi
.Speed
;
1179 nlassert(destPos
< endPos
);
1181 uint index
= (uint
) (lookUpFactor
* currDate
) & (BFNumPredefinedPos
- 1);
1182 destPos
->x
= startPos
.x
+ currDate
* startSpeed
.x
+ _K
* PrecomputedPos
[index
].x
;
1183 destPos
->y
= startPos
.y
+ currDate
* startSpeed
.y
+ _K
* PrecomputedPos
[index
].y
;
1184 destPos
->z
= startPos
.z
+ currDate
* startSpeed
.z
+ _K
* PrecomputedPos
[index
].z
;
1186 destPos
= (NLMISC::CVector
*) ( (uint8
*) destPos
+ stride
);
1193 uint numToSkip
= ScaleFloatGE(startDate
, deltaT
, pi
.Date
, numStep
);
1194 if (numToSkip
< numStep
)
1196 numStep
-= numToSkip
;
1197 float currDate
= startDate
+ deltaT
* numToSkip
- pi
.Date
;
1201 nlassert(destPos
< endPos
);
1203 uint index
= (uint
) (lookUpFactor
* currDate
) & (BFNumPredefinedPos
- 1);
1204 destPos
->x
+= _K
* PrecomputedPos
[index
].x
;
1205 destPos
->y
+= _K
* PrecomputedPos
[index
].y
;
1206 destPos
->z
+= _K
* PrecomputedPos
[index
].z
;
1208 destPos
= (NLMISC::CVector
*) ( (uint8
*) destPos
+ stride
);
1217 ///==========================================================
1218 void CPSBrownianForce::initPrecalc()
1220 NL_PS_FUNC(CPSBrownianForce_initPrecalc
)
1221 /// create the pos table
1222 nlassert(BFNumPredefinedPos
% BFPredefinedNumInterp
== 0);
1224 NLMISC::CVector
p0(0, 0, 0), p1
;
1225 const uint numStep
= BFNumPredefinedPos
/ BFPredefinedNumInterp
;
1226 NLMISC::CVector
*dest
= PrecomputedPos
;
1228 for (k
= 0; k
< numStep
; ++k
)
1230 if (k
!= numStep
- 1)
1232 p1
.set(2.f
* (NLMISC::frand(1.f
) - 0.5f
),
1233 2.f
* (NLMISC::frand(1.f
) - 0.5f
),
1234 2.f
* (NLMISC::frand(1.f
) - 0.5f
));
1241 float lambdaStep
= 1.f
/ BFPredefinedNumInterp
;
1242 for (l
= 0; l
< BFPredefinedNumInterp
; ++l
)
1244 *dest
++ = lambda
* p1
+ (1.f
- lambda
) * p0
;
1245 lambda
+= lambdaStep
;
1250 // now, filter the table several time to get something more smooth
1251 for (k
= 0; k
< (BFPredefinedNumInterp
<< 2) ; ++k
)
1253 for (l
= 1; l
< (BFNumPredefinedPos
- 1); ++l
)
1255 PrecomputedPos
[l
] = 0.5f
* (PrecomputedPos
[l
- 1] + PrecomputedPos
[l
+ 1]);
1260 // compute the table of speeds, by using on a step of 1.s
1261 for (l
= 1; l
< (BFNumPredefinedPos
- 1); ++l
)
1263 PrecomputedSpeed
[l
] = 0.5f
* (PrecomputedPos
[l
+ 1] - PrecomputedPos
[l
- 1]);
1265 PrecomputedSpeed
[BFNumPredefinedPos
- 1] = NLMISC::CVector::Null
;
1267 // compute the table of impulsion
1268 for (k
= 0; k
< BFNumPrecomputedImpulsions
; ++k
)
1270 static double divRand
= (2.f
/ RAND_MAX
);
1271 PrecomputedImpulsions
[k
].set( (float) (rand() * divRand
- 1),
1272 (float) (rand() * divRand
- 1),
1273 (float) (rand() * divRand
- 1)
1278 ///==========================================================
1279 void CPSBrownianForce::setIntensity(float value
)
1281 NL_PS_FUNC(CPSBrownianForce_setIntensity
)
1282 if (_IntensityScheme
)
1284 CPSForceIntensity::setIntensity(value
);
1285 renewIntegrable(); // integrable again
1289 CPSForceIntensity::setIntensity(value
);
1294 ///==========================================================
1295 void CPSBrownianForce::setIntensityScheme(CPSAttribMaker
<float> *scheme
)
1297 NL_PS_FUNC(CPSBrownianForce_setIntensityScheme
)
1298 if (!_IntensityScheme
)
1300 cancelIntegrable(); // not integrable anymore
1302 CPSForceIntensity::setIntensityScheme(scheme
);
1305 ///==========================================================
1306 void CPSBrownianForce::computeForces(CPSLocated
&target
)
1308 NL_PS_FUNC(CPSBrownianForce_computeForces
)
1309 nlassert(CParticleSystem::InsideSimLoop
);
1310 // perform the operation on each target
1311 for (uint32 k
= 0; k
< _Owner
->getSize(); ++k
)
1313 float intensity
= _IntensityScheme
? _IntensityScheme
->get(_Owner
, k
) : _K
;
1314 uint32 size
= target
.getSize();
1315 if (!size
) continue;
1316 TPSAttribVector::iterator it2
= target
.getSpeed().begin(), it2End
;
1317 /// start at a random position in the precomp impulsion tab
1318 uint startPos
= (uint
) ::rand() % BFNumPrecomputedImpulsions
;
1319 NLMISC::CVector
*imp
= PrecomputedImpulsions
+ startPos
;
1321 if (target
.getMassScheme())
1323 float intensityXtime
= intensity
* CParticleSystem::EllapsedTime
;
1324 TPSAttribFloat::const_iterator invMassIt
= target
.getInvMass().begin();
1327 uint toProcess
= std::min((uint
) (BFNumPrecomputedImpulsions
- startPos
), (uint
) size
);
1328 it2End
= it2
+ toProcess
;
1331 float factor
= intensityXtime
* *invMassIt
;
1332 it2
->set(it2
->x
+ factor
* imp
->x
,
1333 it2
->y
+ factor
* imp
->y
,
1334 it2
->z
+ factor
* imp
->x
);
1339 while (it2
!= it2End
);
1341 imp
= PrecomputedImpulsions
;
1350 uint toProcess
= std::min((uint
) (BFNumPrecomputedImpulsions
- startPos
) , (uint
) size
);
1351 it2End
= it2
+ toProcess
;
1352 float factor
= intensity
* CParticleSystem::EllapsedTime
/ target
.getInitialMass();
1355 it2
->set(it2
->x
+ factor
* imp
->x
,
1356 it2
->y
+ factor
* imp
->y
,
1357 it2
->z
+ factor
* imp
->x
);
1361 while (it2
!= it2End
);
1363 imp
= PrecomputedImpulsions
;
1371 ///=======================================================================
1372 void CPSBrownianForce::serial(NLMISC::IStream
&f
)
1374 NL_PS_FUNC(CPSBrownianForce_serial
)
1375 sint ver
= f
.serialVersion(3);
1379 f
.serial(dummy
); // old data in version 2 not used anymore
1380 CPSForce::serial(f
);
1381 f
.serial(dummy
); // old data in version 2 not used anymore
1382 serialForceIntensity(f
);
1385 registerToTargets();
1391 CPSForceIntensityHelper::serial(f
);
1392 f
.serial(_ParametricFactor
);