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/debug.h"
20 #include "nel/misc/common.h"
21 #include "nel/misc/hierarchical_timer.h"
22 #include "nel/3d/particle_system_model.h"
23 #include "nel/3d/particle_system_shape.h"
24 #include "nel/3d/particle_system.h"
25 #include "nel/3d/scene.h"
26 #include "nel/3d/anim_detail_trav.h"
27 #include "nel/3d/clip_trav.h"
28 #include "nel/3d/render_trav.h"
29 #include "nel/3d/skeleton_model.h"
31 #include "nel/3d/cluster.h" // ask trap
42 uint64 PSStatsRegisterPSModelObserver
= 0;
43 uint64 PSStatsRemovePSModelObserver
= 0;
44 uint64 PSStatsUpdateOpacityInfos
= 0;
45 uint64 PSStatsUpdateLightingInfos
= 0;
46 uint64 PSStatsGetAABBox
= 0;
47 uint64 PSStatsReallocRsc
= 0;
48 uint64 PSStatsReleasePSPointer
= 0;
49 uint64 PSStatsRefreshRscDeletion
= 0;
50 uint64 PSStatsReleaseRsc
= 0;
51 uint64 PSStatsReleaseRscAndInvalidate
= 0;
52 uint64 PSStatsGetNumTriangles
= 0;
53 uint64 PSStatsCheckAgainstPyramid
= 0;
54 uint64 PSStatsTraverseAnimDetail
= 0;
55 uint64 PSStatsDoAnimate
= 0;
56 uint64 PSStatsDoAnimatePart1
= 0;
57 uint64 PSStatsDoAnimatePart2
= 0;
58 uint64 PSStatsDoAnimatePart3
= 0;
59 uint64 PSStatsTraverseRender
= 0;
60 uint64 PSStatsTraverseClip
= 0;
61 uint64 PSStatsClipSystemInstanciated
= 0;
62 uint64 PSStatsClipSystemNotInstanciated
= 0;
63 uint64 PSStatsClipSystemCheckAgainstPyramid
= 0;
64 uint64 PSStatsInsertInVisibleList
= 0;
65 uint64 PSStatsCheckDestroyCondition
= 0;
66 uint64 PSStatsForceInstanciate
= 0;
67 uint64 PSStatsTraverseAnimDetailPart1
= 0;
68 uint64 PSStatsTraverseAnimDetailPart2
= 0;
69 uint64 PSStatsTraverseAnimDetailPart3
= 0;
70 uint64 PSStatsTraverseAnimDetailPart4
= 0;
84 uint PSStatsNumDoAnimateCalls
= 0;
88 uint64 PSStatsZonePlane
= 0;
89 uint64 PSStatsZoneSphere
= 0;
90 uint64 PSStatsZoneDisc
= 0;
91 uint64 PSStatsZoneRectangle
= 0;
92 uint64 PSStatsZoneCylinder
= 0;
98 uint64 PSStatCollision
= 0;
99 uint64 PSStatEmit
= 0;
100 uint64 PSStatRender
= 0;
108 ///=====================================================================================
110 CParticleSystemModel::CParticleSystemModel() : _ParticleSystem(NULL
),
112 _EllapsedTime(0.01f
),
113 _EllapsedTimeRatio(1.f
),
114 _AnimType(CParticleSystem::AnimVisible
),
115 _AutoGetEllapsedTime(true),
116 _ToolDisplayEnabled(false),
117 _TransparencyStateTouched(true),
118 _LightableStateTouched(true),
121 _InsertedInVisibleList(false),
122 _InClusterAndVisible(false),
123 _EmitterActive(true),
125 _BypassGlobalUserParam(0),
126 _UserColor(CRGBA::White
),
128 _LastVisibility(CHrcTrav::Show
)
131 setTransparency(true);
132 IAnimatable::resize(AnimValueLast
);
133 _TriggerAnimatedValue
.Value
= true;
135 // AnimDetail behavior: Must be traversed in AnimDetail, even if no channel mixer registered
136 CTransform::setIsForceAnimDetail(true);
138 for(uint k
= 0; k
< MaxPSUserParam
; ++k
)
140 _UserParam
[k
].Value
= 0.f
;
143 // RenderFilter: We are a Landscape
144 _RenderFilterType
= UScene::FilterPS
;
147 ///=====================================================================================
148 void CParticleSystemModel::setEditionMode(bool enable
/*= true*/)
152 /// we need to have the system resources instanciated if we want to work with it
153 if (!_ParticleSystem
)
160 _EditionMode
= enable
;
163 ///=====================================================================================
164 void CParticleSystemModel::registerPSModelObserver(IPSModelObserver
*obs
)
166 MINI_TIMER(PSStatsRegisterPSModelObserver
)
167 nlassert(!isPSModelObserver(obs
)); // this observer has already been registered
168 _Observers
.push_back(obs
);
171 ///=====================================================================================
172 void CParticleSystemModel::removePSModelObserver(IPSModelObserver
*obs
)
174 MINI_TIMER(PSStatsRemovePSModelObserver
);
175 nlassert(isPSModelObserver(obs
)); // the observer must have been registered
176 std::vector
<IPSModelObserver
*>::iterator it
= std::find(_Observers
.begin(), _Observers
.end(), obs
);
177 _Observers
.erase(it
);
181 ///=====================================================================================
182 bool CParticleSystemModel::isPSModelObserver(IPSModelObserver
*obs
)
184 return std::find(_Observers
.begin(), _Observers
.end(), obs
) != _Observers
.end();
188 ///=====================================================================================
189 void CParticleSystemModel::registerBasic()
191 // register the model
192 CScene::registerModel(ParticleSystemModelId
, TransformShapeId
, CParticleSystemModel::creator
);
195 ///=====================================================================================
196 void CParticleSystemModel::updateOpacityInfos(void)
198 MINI_TIMER(PSStatsUpdateOpacityInfos
);
199 nlassert(_ParticleSystem
);
200 if (!_TransparencyStateTouched
) return;
201 nlassert(_ParticleSystem
);
202 setOpacity(_ParticleSystem
->hasOpaqueObjects() || _ToolDisplayEnabled
);
203 setTransparency(_ParticleSystem
->hasTransparentObjects());
204 _TransparencyStateTouched
= false;
207 ///=====================================================================================
208 void CParticleSystemModel::updateLightingInfos(void)
210 MINI_TIMER(PSStatsUpdateLightingInfos
)
211 nlassert(_ParticleSystem
);
212 if (!_LightableStateTouched
) return;
213 CTransform::setIsLightable(_ParticleSystem
->hasLightableObjects());
214 _LightableStateTouched
= false;
217 ///=====================================================================================
218 void CParticleSystemModel::getAABBox(NLMISC::CAABBox
&bbox
) const
220 MINI_TIMER(PSStatsGetAABBox
)
223 _ParticleSystem
->computeBBox(bbox
);
227 NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*) Shape
)->getAABBox(bbox
);
231 ///=====================================================================================
232 CParticleSystemModel::~CParticleSystemModel()
236 // Auto detach me from skeleton. Must do it here, not in ~CTransform().
237 if(_FatherSkeletonModel
)
239 // detach me from the skeleton.
240 // clip and hrc hierarchy is modified.
241 _FatherSkeletonModel
->detachSkeletonSon(this);
242 nlassert(_FatherSkeletonModel
==NULL
);
247 ///=====================================================================================
248 /// Called when the resource (attached system) for this system must be reallocated
249 void CParticleSystemModel::reallocRsc()
251 //MINI_TIMER(PSStatsReallocRsc)
252 nlassert(_ParticleSystem
== NULL
);
254 CParticleSystemShape
*shape
= NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*) Shape
);
255 if (shape
->isShared())
257 // there's a single CparticleSystemInstance even if there are several models
258 _ParticleSystem
= shape
->instanciatePS(*_Scene
, &shape
->Allocator
);
262 _ParticleSystem
= shape
->instanciatePS(*_Scene
, &_Allocator
);
265 _ParticleSystem
= NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*) Shape
)->instanciatePS(*_Scene
);
267 nlassert(_ParticleSystem
);
269 CParticleSystemManager
&psmgt
= _Scene
->getParticleSystemManager();
270 _ModelHandle
= psmgt
.addSystemModel(this);
271 _AnimType
= _ParticleSystem
->getAnimType();
272 if (_ParticleSystem
->getAnimType() == CParticleSystem::AnimAlways
)
274 _AnimatedModelHandle
= psmgt
.addPermanentlyAnimatedSystem(this);
276 // touch user params animated value. If the system rsc have been released before, this force to restore them
277 for (uint k
= 0; k
< MaxPSUserParam
; ++k
)
279 touch((uint
)CParticleSystemModel::PSParam0
+ k
, OwnerBit
);
281 _ParticleSystem
->setUserColor(_UserColor
);
283 if (!_EmitterActive
) _ParticleSystem
->activateEmitters(false);
284 if (!_SoundActive
) _ParticleSystem
->stopSound();
286 if (_ZBias
!= 0.f
) _ParticleSystem
->setZBias(_ZBias
);
289 ///=====================================================================================
290 void CParticleSystemModel::releasePSPointer()
292 MINI_TIMER(PSStatsReleasePSPointer
)
293 nlassert(_ParticleSystem
!= NULL
);
294 sint numRefs
= _ParticleSystem
.getNbRef();
297 // Backup user params (in animated value) so that they will be restored when the system is recreated
298 for (uint k
= 0; k
< MaxPSUserParam
; ++k
)
300 _UserParam
[k
].Value
= _ParticleSystem
->getUserParam(k
);
305 _Scene
->getParticleSystemManager().removeSystemModel(_ModelHandle
);
306 if (_ParticleSystem
->getAnimType() == CParticleSystem::AnimAlways
)
308 if (_AnimatedModelHandle
.Valid
)
310 _Scene
->getParticleSystemManager().removePermanentlyAnimatedSystem(_AnimatedModelHandle
);
314 _ParticleSystem
= NULL
; // one less ref with the smart ptr
316 CParticleSystemShape
*shape
= NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*) Shape
);
317 if (shape
->isShared())
321 // release allocator in the shape
322 shape
->Allocator
.release();
328 ///=====================================================================================
329 void CParticleSystemModel::refreshRscDeletion(const std::vector
<CPlane
> &worldFrustumPyramid
, const NLMISC::CVector
&viewerPos
)
331 MINI_TIMER(PSStatsRefreshRscDeletion
)
332 if (_EditionMode
) return;
333 /** Here we test whether the system has not gone out of scope.
334 * Why do we test this here addtionnaly to the clip traversal ?
335 * Simply because the clip traversal is not called if the cluster it is inserted in is not parsed.
336 * This is not good, because we want to keep few CParticleSystem instance.
337 * This method solve that problem. This is called by the particle system manager when each scene has rendered
341 nlassert(_ParticleSystem
);
342 CParticleSystemShape
*shape
= NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*) Shape
);
344 /* NLMISC::CVector sysPos = getTransformMode() == DirectMatrix ?
345 getMatrix().getPos() :
348 NLMISC::CVector sysPos
= getWorldMatrix().getPos();
350 NLMISC::CVector v
= sysPos
- viewerPos
;
351 /// test if not too far
352 const float dist2
= v
* v
;
354 if (dist2
> shape
->_MaxViewDist
* shape
->_MaxViewDist
) // too far ?
357 if (shape
->_DestroyModelWhenOutOfRange
)
365 if (shape
->_DestroyWhenOutOfFrustum
)
367 if (checkAgainstPyramid(worldFrustumPyramid
) == false)
369 if (shape
->_DestroyModelWhenOutOfRange
)
381 ///=====================================================================================
382 void CParticleSystemModel::releaseRsc()
384 MINI_TIMER(PSStatsReleaseRsc
)
385 if (!_ParticleSystem
) return;
389 ///=====================================================================================
390 void CParticleSystemModel::releaseRscAndInvalidate()
392 MINI_TIMER(PSStatsReleaseRscAndInvalidate
)
393 if (!_ParticleSystem
) return;
397 static std::vector
<IPSModelObserver
*> copyVect
;
398 copyVect
.resize(_Observers
.size());
399 std::copy(_Observers
.begin(), _Observers
.end(), copyVect
.begin());
401 for (std::vector
<IPSModelObserver
*>::iterator it
= copyVect
.begin(); it
!= copyVect
.end(); ++it
)
403 (*it
)->invalidPS(this); // if this crash, then you forgot to call removePSModelObserver !
406 CParticleSystemShape
*shape
= NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*) Shape
);
407 if (!shape
->isShared())
409 _Allocator
.release();
412 // if system if shared, the allocator is placed in the shape, so no-op there
416 ///=====================================================================================
417 IAnimatedValue
* CParticleSystemModel::getValue (uint valueId
)
419 nlassert(valueId
< AnimValueLast
);
420 if (valueId
< OwnerBit
) return CTransformShape::getValue(valueId
);
421 if (valueId
< PSTrigger
)
424 return &_UserParam
[valueId
- (uint
) PSParam0
];
426 return &_TriggerAnimatedValue
;
429 ///=====================================================================================
430 const char *CParticleSystemModel::getPSParamName (uint valueId
)
432 nlassert(valueId
< AnimValueLast
);
433 const char *name
[] = { "PSParam0", "PSParam1", "PSParam2", "PSParam3" };
434 return name
[valueId
- (uint
) PSParam0
];
437 ///=====================================================================================
438 const char *CParticleSystemModel::getValueName (uint valueId
) const
440 nlassert(valueId
< AnimValueLast
);
441 if (valueId
< OwnerBit
) return CTransformShape::getValueName(valueId
);
442 if (valueId
< PSTrigger
) return getPSParamName(valueId
);
446 ///=====================================================================================
447 ITrack
* CParticleSystemModel::getDefaultTrack (uint valueId
)
449 nlassert(valueId
< AnimValueLast
);
452 CParticleSystemShape
*pss
= NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*) Shape
);
456 case PosValue
: return pss
->getDefaultPos();
457 case RotQuatValue
: return pss
->getDefaultRotQuat();
458 case ScaleValue
: return pss
->getDefaultScale();
460 if (valueId
< OwnerBit
) return CTransformShape::getDefaultTrack(valueId
); // delegate to parent
462 // this value belong to us
463 if (valueId
< PSTrigger
)
465 return pss
->getUserParamDefaultTrack(valueId
- (uint
) PSParam0
);
467 return pss
->getDefaultTriggerTrack();
470 ///=====================================================================================
471 void CParticleSystemModel::registerToChannelMixer(CChannelMixer
*chanMixer
, const std::string
&prefix
/* =std::string() */)
473 CTransformShape::registerToChannelMixer(chanMixer
, prefix
);
474 addValue(chanMixer
, PSParam0
, OwnerBit
, prefix
, true);
475 addValue(chanMixer
, PSParam1
, OwnerBit
, prefix
, true);
476 addValue(chanMixer
, PSParam2
, OwnerBit
, prefix
, true);
477 addValue(chanMixer
, PSParam3
, OwnerBit
, prefix
, true);
478 addValue(chanMixer
, PSTrigger
, OwnerBit
, prefix
, true);
482 ///=====================================================================================
483 float CParticleSystemModel::getNumTriangles (float distance
)
485 MINI_TIMER(PSStatsGetNumTriangles
)
486 if (!_ParticleSystem
) return 0;
487 if (!_InsertedInVisibleList
) return 0;
488 return (float) _ParticleSystem
->getWantedNumTris(distance
);
491 ///=========================================================================================
492 bool CParticleSystemModel::checkAgainstPyramid(const std::vector
<CPlane
> &pyramid
) const
494 MINI_TIMER(PSStatsCheckAgainstPyramid
)
495 nlassert(_ParticleSystem
);
496 NLMISC::CAABBox bbox
;
497 _ParticleSystem
->computeBBox(bbox
);
498 const CMatrix
&mat
= getWorldMatrix();
500 // Transform the pyramid in Object space.
501 for(sint i
=0; i
< (sint
) pyramid
.size(); i
++)
503 // test whether the bbox is entirely in the neg side of the plane
504 if (!bbox
.clipBack(pyramid
[i
] * mat
))
513 //////////////////////////////////////////////
514 // CParticleSystem AnimDetail implementation //
515 //////////////////////////////////////////////
517 ///=====================================================================================
518 void CParticleSystemModel::traverseAnimDetail()
520 MINI_TIMER(PSStatsTraverseAnimDetail
)
521 CTransformShape::traverseAnimDetail();
522 CParticleSystem
*ps
= getPS();
523 if (!_WorldVis
) return;
524 if (_Invalidated
) return;
525 if (getVisibility() == CHrcTrav::Hide
) return;
528 MINI_TIMER(PSStatsTraverseAnimDetailPart1
)
529 if (!_EditionMode
&& !_InClusterAndVisible
)
531 CParticleSystemShape
*pss
= NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*)Shape
);
532 if (pss
->_DestroyWhenOutOfFrustum
)
534 if (pss
->_DestroyModelWhenOutOfRange
)
536 releaseRscAndInvalidate();
538 else // remove rsc but do not invalidate the system
547 // check for trigger. If the trigger is false, and there is a system instanciated, we delete it.
550 if (!_TriggerAnimatedValue
.Value
)
552 // system is off, or hasn't been instanciated now...
563 MINI_TIMER(PSStatsTraverseAnimDetailPart2
)
565 // the system or its center is in the view frustum, but it may not have been instanciated from its shape now
571 ps
= _ParticleSystem
;
575 CClipTrav
&clipTrav
= getOwnerScene()->getClipTrav();
578 MINI_TIMER(PSStatsTraverseAnimDetailPart3
)
579 if (_InClusterAndVisible
|| ps
->getAnimType() == CParticleSystem::AnimInCluster
)
582 if (ps
->isSharingEnabled()) /// with shared system, we only animate one version!
584 if (ps
->_LastUpdateDate
== clipTrav
.CurrentDate
)
590 ps
->_LastUpdateDate
= clipTrav
.CurrentDate
;
595 ps
->_LastUpdateDate
= clipTrav
.CurrentDate
;
597 ps
->_LastUpdateDate
= clipTrav
.CurrentDate
;
600 if (ps
->getAnimType() != CParticleSystem::AnimAlways
) // if the animation is always perfomred,
601 // then animation is done by the particle system manager
602 // just before the render trav
611 MINI_TIMER(PSStatsTraverseAnimDetailPart4
)
612 // add a render model if in cluster & not hidden
613 if (_InClusterAndVisible
)
615 getOwnerScene()->getRenderTrav().addRenderModel(this);
620 ///=====================================================================================
621 void CParticleSystemModel::doAnimate()
623 ++ PSStatsNumDoAnimateCalls
;
624 MINI_TIMER(PSStatsDoAnimate
)
625 nlassert(!_Invalidated
);
626 CParticleSystem
*ps
= getPS();
627 CClipTrav
&clipTrav
= getOwnerScene()->getClipTrav();
628 const CMatrix
&mat
= getWorldMatrix();
631 MINI_TIMER(PSStatsDoAnimatePart1
)
633 // Set the 'hide' flag. This prevent trails from being created is the system is hidden, moved, and then showed in the next frame.
634 ps
->hide(!this->isHrcVisible());
636 ps
->setUserMatrix(&_UserMatrix
);
637 ps
->setViewMat(clipTrav
.ViewMatrix
);
638 updateOpacityInfos();
639 updateLightingInfos();
641 //ps->setSysMat(getWorldMatrix());
642 nlassert(ps
->getScene());
646 MINI_TIMER(PSStatsDoAnimatePart2
)
648 // setup the number of faces we allow
649 ps
->setNumTris((uint
) getNumTrianglesAfterLoadBalancing());
652 // set the global user param that are bypassed
653 nlctassert(MaxPSUserParam
< 8); // there should be less than 8 parameters because of mask stored in a byte
654 ps
->_BypassGlobalUserParam
= _BypassGlobalUserParam
;
656 // setup system user parameters for parameters that have been touched
657 for (uint k
= 0; k
< MaxPSUserParam
; ++k
)
659 if (isTouched((uint
)CParticleSystemModel::PSParam0
+ k
))
661 ps
->setUserParam(k
, _UserParam
[k
].Value
);
662 clearFlag((uint
)CParticleSystemModel::PSParam0
+ k
);
665 if (isAutoGetEllapsedTimeEnabled())
667 setEllapsedTime(ps
->getScene()->getEllapsedTime() * getEllapsedTimeRatio());
671 MINI_TIMER(PSStatsDoAnimatePart3
)
672 TAnimationTime delay
= getEllapsedTime();
674 CParticleSystemShape
*pss
= NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*)Shape
);
677 pss
->_ProcessOrder
.clear(); // force to eval each frame because ps could be modified
679 ps
->step(CParticleSystem::Anim
, delay
, *pss
, *this);
684 //////////////////////////////////////////////
685 // CParticleSystem Render implementation //
686 //////////////////////////////////////////////
687 void CParticleSystemModel::traverseRender()
689 MINI_TIMER(PSStatsTraverseRender
)
695 if (CTransform::isLightable())
697 // affect global lighting color
698 const CLightContribution
&lc
= getLightContribution();
699 NLMISC::CRGBA
lighting(0, 0, 0, 255);
700 for(uint k
= 0; k
< NL3D_MAX_LIGHT_CONTRIBUTION
; ++k
)
702 if (lc
.PointLight
[k
] == NULL
) break;
703 NLMISC::CRGBA currLightContrib
;
704 currLightContrib
.modulateFromui(lc
.PointLight
[k
]->getDiffuse(), lc
.AttFactor
[k
]);
705 lighting
.add(lighting
, currLightContrib
);
708 //lighting.add(lighting, lc.LocalAmbient);
709 //lighting.add(lighting,lc.MergedPointLight);
712 NLMISC::CRGBA sunDiffuse
;
713 sunDiffuse
.modulateFromui(_Scene
->getSunDiffuse(), lc
.SunContribution
);
714 lighting
.add(lighting
, sunDiffuse
);
715 NLMISC::CRGBA sunAmbient
;
716 sunAmbient
.modulateFromui(_Scene
->getSunAmbient(), lc
.SunContribution
);
717 lighting
.add(lighting
, sunAmbient
);
718 _ParticleSystem
->setLightingColor(lighting
);
720 CTransformShape::traverseRender();
727 * CParticleSystem Clip implementation
728 * IMPORTANT : the _Visible attribute is interpreted as 'in traversed clusters'. We need this because we want
729 * to know when a p.s is in clusters, but not visible. As a matter of fact we may need to have system that are animated
730 * as long as in cluster, but not visible.
733 void CParticleSystemModel::traverseClip()
735 MINI_TIMER(PSStatsTraverseClip
)
736 // disable H_AUTO, because slowdown when lot of models (eg 1000-2000 tested in forest)
737 //H_AUTO ( NL3D_Particles_Clip );
739 // CTransformShape::traverseClip();
740 // Traverse the Clip sons.
741 uint numClipChildren
= clipGetNumChildren();
742 for(uint i
=0;i
<numClipChildren
;i
++)
743 clipGetChild(i
)->traverseClip();
745 if (!_WorldVis
) return;
746 if (_Invalidated
) return;
747 CClipTrav
&clipTrav
= getOwnerScene()->getClipTrav();
750 if (_ClipDate
!= clipTrav
.CurrentDate
)
752 _InsertedInVisibleList
= false;
753 _InClusterAndVisible
= false;
754 _ClipDate
= clipTrav
.CurrentDate
;
756 if (_InClusterAndVisible
) return; // already visible
759 CParticleSystem
*ps
= _ParticleSystem
;
762 if (ps
) // system instanciated
764 MINI_TIMER(PSStatsClipSystemInstanciated
)
765 // if there are no more particles, no need to even clip..
766 if (checkDestroyCondition(ps
)) return;
767 // check for anim mode change
768 if (_AnimType
!= ps
->getAnimType())
770 CParticleSystemManager
&psmgt
= _Scene
->getParticleSystemManager();
771 if (_AnimType
== CParticleSystem::AnimAlways
) // was previously always animated ?
773 if (_AnimatedModelHandle
.Valid
)
775 psmgt
.removePermanentlyAnimatedSystem(_AnimatedModelHandle
);
778 _AnimType
= ps
->getAnimType();
779 if (_AnimType
== CParticleSystem::AnimAlways
)
781 _AnimatedModelHandle
= psmgt
.addPermanentlyAnimatedSystem(this);
786 // check whether display filtered or not
787 if( !(_Scene
->getFilterRenderFlags() & _RenderFilterType
) )
793 // special case : system sticked to a skeleton
794 if( _AncestorSkeletonModel
!=NULL
)
796 bool visible
= _AncestorSkeletonModel
->isClipVisible();
797 // Special test: if we are sticked to a skeletonModel, and if we are still visible, maybe we don't have to
798 if(_Visible
&& _FatherSkeletonModel
)
800 // if our skeletonModel father is displayed with a Lod, maybe we are not to be displayed
801 if(_FatherSkeletonModel
->isDisplayedAsLodCharacter())
803 // We are visible only if we where sticked to the skeleton with forceCLod==true.
804 // This is also true if we are actually a skeletonModel
805 if(!getShowWhenLODSticked())
806 // otherWise we are not visible. eg: this is the case of skins and some sticked object
814 MINI_TIMER(PSStatsInsertInVisibleList
)
815 insertInVisibleList();
817 _InClusterAndVisible
= true;
820 else // not visible, may need animation however..
822 if (!ps
) // no resc allocated
824 CParticleSystemShape
*pss
= NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*)Shape
);
826 // invalidate the system if too far
827 const CVector pos
= _AncestorSkeletonModel
->getWorldMatrix().getPos();
828 const CVector d
= pos
- clipTrav
.CamPos
;
829 if (d
* d
> pss
->_MaxViewDist
* pss
->_MaxViewDist
)
832 if (pss
->_DestroyModelWhenOutOfRange
)
840 // NB : The test to see whether the system is not too far is performed by the particle system manager
844 MINI_TIMER(PSStatsInsertInVisibleList
)
845 insertInVisibleList();
855 const std::vector
<CPlane
> &pyramid
= clipTrav
.WorldPyramid
;
856 /** traverse the sons
857 * we must do this before us, because this object may delete himself from the scene
860 // now the pyramid is directly expressed in the world
861 const CMatrix
&mat
= getWorldMatrix();
864 // Transform the pyramid in Object space.
867 if(!ps
) ///====================== system resource not allocated, test if it entered the scope
869 MINI_TIMER(PSStatsClipSystemNotInstanciated
)
870 CParticleSystemShape
*pss
= NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*)Shape
);
873 // the system wasn't present the last time, we use its center to see if it's back in the view frustum,
874 // or if it is near enough.
875 // if this is the case, we say it isn't clipped, so it will be reinstanciated from the shape
876 // during the DetailAnimTraversal
878 const CVector pos
= getWorldMatrix().getPos();
880 const CVector d
= pos
- clipTrav
.CamPos
;
883 // check whether system not too far
884 if (d
* d
> pss
->_MaxViewDist
* pss
->_MaxViewDist
)
887 if (pss
->_DestroyModelWhenOutOfRange
)
894 // test the shape to see whether we have a precomputed bbox
895 if (!pss
->_UsePrecomputedBBox
)
897 ///============================= the system has no precomputed bbox
899 for(sint i
=0; i
< (sint
)pyramid
.size(); i
++)
901 if ( (pyramid
[i
] * mat
).d
> 0.0f
) // in its basis, the system is at the center
905 MINI_TIMER(PSStatsInsertInVisibleList
)
906 insertInVisibleList();
912 MINI_TIMER(PSStatsInsertInVisibleList
)
913 insertInVisibleList();
915 _InClusterAndVisible
= true;
920 ///============================= the system has a precomputed bbox
922 for(sint i
=0; i
< (sint
)pyramid
.size(); i
++)
924 if ( !pss
->_PrecomputedBBox
.clipBack(pyramid
[i
] * mat
) )
927 MINI_TIMER(PSStatsInsertInVisibleList
)
928 insertInVisibleList();
934 MINI_TIMER(PSStatsInsertInVisibleList
)
935 insertInVisibleList();
937 _InClusterAndVisible
= true;
943 //=========================================================================================================
944 // the system is already instanciated
947 /// Pyramid test. IMPORTANT : The test to see whether the system is not too far is performed by the particle system manager
948 // In edition mode, it isn't done by the manager (system never removed), so we do it here in this case
951 CParticleSystemShape
*pss
= NLMISC::safe_cast
<CParticleSystemShape
*>((IShape
*)Shape
);
953 const CVector pos
= getWorldMatrix().getPos();
954 const CVector d
= pos
- clipTrav
.CamPos
;
955 // check whether system not too far
956 if (d
* d
> ps
->getMaxViewDist() * ps
->getMaxViewDist())
958 return; // not visible
961 if (checkAgainstPyramid(pyramid
) == false)
963 MINI_TIMER(PSStatsClipSystemCheckAgainstPyramid
)
966 // system near, but maybe not in cluster..
968 MINI_TIMER(PSStatsInsertInVisibleList
)
969 insertInVisibleList();
977 MINI_TIMER(PSStatsInsertInVisibleList
)
978 insertInVisibleList();
981 _InClusterAndVisible
= true;
985 //===================================================================
986 bool CParticleSystemModel::clip()
988 // no-op clip() because all done in special traverse()
993 //===================================================================
994 bool CParticleSystemModel::checkDestroyCondition(CParticleSystem
*ps
)
996 MINI_TIMER(PSStatsCheckDestroyCondition
)
1000 /** NB : we don't do this test here for always animated system, as it is done
1001 * by the CParticleSystemManager, because this code is not sure to be executed if the system has been clipped by a cluster
1003 if (ps
->getAnimType() != CParticleSystem::AnimAlways
)
1005 if (ps
->isDestroyConditionVerified())
1007 releaseRscAndInvalidate();
1015 //===================================================================
1016 void CParticleSystemModel::bypassGlobalUserParamValue(uint userParamIndex
,bool byPass
/*=true*/)
1018 nlctassert(MaxPSUserParam
< 8); // there should be less than 8 parameters because of mask stored in a byte
1019 nlassert(userParamIndex
< MaxPSUserParam
);
1020 if (byPass
) _BypassGlobalUserParam
|= (1 << userParamIndex
);
1021 else _BypassGlobalUserParam
&= ~(1 << userParamIndex
);
1024 //===================================================================
1025 bool CParticleSystemModel::isGlobalUserParamValueBypassed(uint userParamIndex
) const
1027 nlctassert(MaxPSUserParam
< 8); // there should be less than 8 parameters because of mask stored in a byte
1028 nlassert(userParamIndex
< MaxPSUserParam
);
1029 return (_BypassGlobalUserParam
& (1 << userParamIndex
)) != 0;
1032 //===================================================================
1033 void CParticleSystemModel::enableDisplayTools(bool enable
/*=true*/)
1035 _ToolDisplayEnabled
= enable
;
1036 touchTransparencyState();
1037 touchLightableState();
1040 //===================================================================
1041 void CParticleSystemModel::invalidateAutoAnimatedHandle()
1043 _AnimatedModelHandle
.Valid
= false;
1046 //===================================================================
1047 void CParticleSystemModel::activateEmitters(bool active
)
1049 if (active
== _EmitterActive
) return;
1050 _EmitterActive
= active
;
1051 if (_ParticleSystem
) _ParticleSystem
->activateEmitters(active
);
1054 //===================================================================
1055 bool CParticleSystemModel::hasActiveEmitters() const
1058 if (_ParticleSystem
)
1060 if (_ParticleSystem
->hasEmittersTemplates())
1062 nlassert(_ParticleSystem
->hasActiveEmitters() == _EmitterActive
);
1066 return _EmitterActive
;
1069 //===================================================================
1070 void CParticleSystemModel::setUserColor(NLMISC::CRGBA userColor
)
1072 if (_ParticleSystem
) _ParticleSystem
->setUserColor(userColor
);
1073 _UserColor
= userColor
;
1076 //===================================================================
1077 void CParticleSystemModel::forceInstanciate()
1079 MINI_TIMER(PSStatsForceInstanciate
)
1080 if (_Invalidated
) return;
1081 if (_ParticleSystem
) return;
1085 //===================================================================
1086 void CParticleSystemModel::setZBias(float value
)
1088 if (value
== _ZBias
) return;
1090 if (_ParticleSystem
) _ParticleSystem
->setZBias(_ZBias
);
1093 //===================================================================
1094 void CParticleSystemModel::forceSetUserMatrix(const NLMISC::CMatrix
&userMatrix
)
1096 _UserMatrix
= userMatrix
;
1099 getPS()->setUserMatrix(&_UserMatrix
);
1103 //===================================================================
1104 void CParticleSystemModel::stopSound()
1106 if (!_SoundActive
) return;
1107 if (_ParticleSystem
) _ParticleSystem
->stopSound();
1108 _SoundActive
= false;
1111 //===================================================================
1112 void CParticleSystemModel::reactivateSound()
1114 if (_SoundActive
) return;
1115 if (_ParticleSystem
) _ParticleSystem
->reactivateSound();
1116 _SoundActive
= true;
1119 //===================================================================
1120 void CParticleSystemModel::update()
1122 CTransformShape::update();
1123 if (_LocalVis
!= _LastVisibility
)
1125 if (_ParticleSystem
)
1127 _ParticleSystem
->onShow(_LocalVis
== CHrcTrav::Show
);
1129 _LastVisibility
= _LocalVis
;