2012-05-29 13:31:11 +00:00
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "std3d.h"
# include <algorithm>
# include "nel/misc/aabbox.h"
# include "nel/misc/matrix.h"
# include "nel/misc/common.h"
# include "nel/3d/ps_util.h"
# include "nel/3d/particle_system.h"
# include "nel/3d/ps_zone.h"
# include "nel/3d/driver.h"
# include "nel/3d/material.h"
# include "nel/3d/dru.h"
# include "nel/3d/ps_located.h"
# include "nel/3d/ps_particle.h"
# include "nel/3d/ps_force.h"
# include "nel/3d/ps_emitter.h"
# include "nel/3d/ps_misc.h"
# include "nel/misc/line.h"
# include "nel/misc/system_info.h"
# include "nel/misc/common.h"
//
# include "nel/3d/particle_system_model.h"
# ifdef NL_DEBUG
# define CHECK_PS_INTEGRITY checkIntegrity();
# else
# define CHECK_PS_INTEGRITY
# endif
namespace NL3D {
std : : vector < CPSCollisionInfo > CPSLocated : : _Collisions ;
CPSCollisionInfo * CPSLocated : : _FirstCollision = NULL ;
/// ***************************************************************************************
/**
* Constructor
*/
CPSLocated : : CPSLocated ( ) : /*_MaxNumFaces(0),*/
_Size ( 0 ) ,
_MaxSize ( DefaultMaxLocatedInstance ) ,
_CollisionInfoNbRef ( 0 ) ,
_CollisionNextPos ( NULL ) ,
_InitialLife ( 1.f ) ,
_LifeScheme ( NULL ) ,
_InitialMass ( 1.f ) ,
_MassScheme ( NULL ) ,
_LODDegradation ( false ) ,
_ParametricMotion ( false ) ,
_TriggerOnDeath ( false ) ,
_LastForever ( true ) ,
_TriggerID ( ( uint32 ) ' NONE ' ) ,
_NonIntegrableForceNbRefs ( 0 ) ,
_NumIntegrableForceWithDifferentBasis ( 0 )
{
NL_PS_FUNC ( CPSLocated_CPSLocated )
}
// *****************************************************************************************************
const NLMISC : : CMatrix & CPSLocated : : getLocalToWorldMatrix ( ) const
{
NL_PS_FUNC ( CPSLocated_getLocalToWorldMatrix )
nlassert ( _Owner ) ;
switch ( getMatrixMode ( ) )
{
case PSFXWorldMatrix : return _Owner - > getSysMat ( ) ;
case PSIdentityMatrix : return NLMISC : : CMatrix : : Identity ;
case PSUserMatrix : return _Owner - > getUserMatrix ( ) ;
default :
nlassert ( 0 ) ;
}
nlassert ( 0 ) ;
return NLMISC : : CMatrix : : Identity ;
}
// *****************************************************************************************************
const NLMISC : : CMatrix & CPSLocated : : getWorldToLocalMatrix ( ) const
{
NL_PS_FUNC ( CPSLocated_getWorldToLocalMatrix )
nlassert ( _Owner ) ;
switch ( getMatrixMode ( ) )
{
case PSFXWorldMatrix : return _Owner - > getInvertedSysMat ( ) ;
case PSIdentityMatrix : return NLMISC : : CMatrix : : Identity ;
case PSUserMatrix : return _Owner - > getInvertedUserMatrix ( ) ;
default :
nlassert ( 0 ) ;
}
nlassert ( 0 ) ;
return NLMISC : : CMatrix : : Identity ;
}
/// ***************************************************************************************
float CPSLocated : : evalMaxDuration ( ) const
{
NL_PS_FUNC ( CPSLocated_evalMaxDuration )
if ( _LastForever ) return - 1.f ;
return _LifeScheme ? _LifeScheme - > getMaxValue ( ) : _InitialLife ;
}
/// ***************************************************************************************
void CPSLocated : : checkIntegrity ( ) const
{
NL_PS_FUNC ( CPSLocated_checkIntegrity )
nlassert ( _InvMass . getMaxSize ( ) = = _Pos . getMaxSize ( ) ) ;
nlassert ( _Pos . getMaxSize ( ) = = _Speed . getMaxSize ( ) ) ;
nlassert ( _Speed . getMaxSize ( ) = = _Time . getMaxSize ( ) ) ;
nlassert ( _Time . getMaxSize ( ) = = _TimeIncrement . getMaxSize ( ) ) ;
//
nlassert ( _InvMass . getSize ( ) = = _Pos . getSize ( ) ) ;
nlassert ( _Pos . getSize ( ) = = _Speed . getSize ( ) ) ;
nlassert ( _Speed . getSize ( ) = = _Time . getSize ( ) ) ;
nlassert ( _Time . getSize ( ) = = _TimeIncrement . getSize ( ) ) ;
//
if ( hasCollisionInfos ( ) )
{
nlassert ( _CollisionNextPos - > getSize ( ) = = _Pos . getSize ( ) ) ;
nlassert ( _CollisionNextPos - > getMaxSize ( ) = = _Pos . getMaxSize ( ) ) ;
}
//
}
/// ***************************************************************************************
bool CPSLocated : : setLastForever ( )
{
NL_PS_FUNC ( CPSLocated_setLastForever )
CHECK_PS_INTEGRITY
_LastForever = true ;
if ( _Owner & & _Owner - > getBypassMaxNumIntegrationSteps ( ) )
{
// Should test that the system is still valid.
if ( ! _Owner - > canFinish ( ) )
{
_LastForever = false ;
nlwarning ( " <CPSLocated::setLastForever> Can't set flag : this causes the system to last forever, and it has been flagged with 'BypassMaxNumIntegrationSteps'. Flag is not set " ) ;
return false ;
}
}
CHECK_PS_INTEGRITY
return true ;
}
/// ***************************************************************************************
void CPSLocated : : systemDateChanged ( )
{
NL_PS_FUNC ( CPSLocated_systemDateChanged )
CHECK_PS_INTEGRITY
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > systemDateChanged ( ) ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : releaseRefTo ( const CParticleSystemProcess * other )
{
NL_PS_FUNC ( CPSLocated_releaseRefTo )
CHECK_PS_INTEGRITY
// located bindables
{
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > releaseRefTo ( other ) ;
}
}
// dtor observers
{
for ( TDtorObserversVect : : iterator it = _DtorObserversVect . begin ( ) ; it ! = _DtorObserversVect . end ( ) ; + + it )
{
if ( ( * it ) - > getOwner ( ) = = other )
{
CPSLocatedBindable * refMaker = * it ;
refMaker - > notifyTargetRemoved ( this ) ;
break ;
}
}
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : releaseAllRef ( )
{
NL_PS_FUNC ( CPSLocated_releaseAllRef )
CHECK_PS_INTEGRITY
// located bindables
{
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > releaseAllRef ( ) ;
}
}
// we must do a copy, because the subsequent call can modify this vector
TDtorObserversVect copyVect ( _DtorObserversVect . begin ( ) , _DtorObserversVect . end ( ) ) ;
// call all the dtor observers
for ( TDtorObserversVect : : iterator it = copyVect . begin ( ) ; it ! = copyVect . end ( ) ; + + it )
{
( * it ) - > notifyTargetRemoved ( this ) ;
}
_DtorObserversVect . clear ( ) ;
nlassert ( _CollisionInfoNbRef = = 0 ) ; //If this is not = 0, then someone didnt call releaseCollisionInfo
// If this happen, you can register with the registerDTorObserver
// (observer pattern)
// and override notifyTargetRemove to call releaseCollisionInfo
nlassert ( _IntegrableForces . size ( ) = = 0 ) ;
nlassert ( _NonIntegrableForceNbRefs = = 0 ) ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : notifyMotionTypeChanged ( void )
{
NL_PS_FUNC ( CPSLocated_notifyMotionTypeChanged )
CHECK_PS_INTEGRITY
for ( TLocatedBoundCont : : const_iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > motionTypeChanged ( _ParametricMotion ) ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : integrateSingle ( float startDate , float deltaT , uint numStep ,
uint32 indexInLocated ,
NLMISC : : CVector * destPos ,
uint stride ) const
{
NL_PS_FUNC ( CPSLocated_integrateSingle )
CHECK_PS_INTEGRITY
nlassert ( supportParametricMotion ( ) & & _ParametricMotion ) ;
if ( _IntegrableForces . size ( ) ! = 0 )
{
bool accumulate = false ;
for ( TForceVect : : const_iterator it = _IntegrableForces . begin ( ) ; it ! = _IntegrableForces . end ( ) ; + + it )
{
nlassert ( ( * it ) - > isIntegrable ( ) ) ;
( * it ) - > integrateSingle ( startDate , deltaT , numStep , this , indexInLocated , destPos , accumulate , stride ) ;
accumulate = true ;
}
}
else // no forces applied, just deduce position from date, initial pos and speed
{
# ifdef NL_DEBUG
NLMISC : : CVector * endPos = ( NLMISC : : CVector * ) ( ( uint8 * ) destPos + stride * numStep ) ;
# endif
const CPSLocated : : CParametricInfo & pi = _PInfo [ indexInLocated ] ;
destPos = FillBufUsingSubdiv ( pi . Pos , pi . Date , startDate , deltaT , numStep , destPos , stride ) ;
if ( numStep ! = 0 )
{
float currDate = startDate - pi . Date ;
nlassert ( currDate > = 0 ) ;
do
{
# ifdef NL_DEBUG
nlassert ( destPos < endPos ) ;
# endif
destPos - > x = pi . Pos . x + currDate * pi . Speed . x ;
destPos - > y = pi . Pos . y + currDate * pi . Speed . y ;
destPos - > z = pi . Pos . z + currDate * pi . Speed . z ;
currDate + = deltaT ;
destPos = ( NLMISC : : CVector * ) ( ( uint8 * ) destPos + stride ) ;
}
while ( - - numStep ) ;
}
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : performParametricMotion ( TAnimationTime date )
{
NL_PS_FUNC ( CPSLocated_performParametricMotion )
CHECK_PS_INTEGRITY
if ( ! _Size ) return ;
nlassert ( supportParametricMotion ( ) & & _ParametricMotion ) ;
if ( _IntegrableForces . size ( ) ! = 0 )
{
bool accumulate = false ;
for ( TForceVect : : iterator it = _IntegrableForces . begin ( ) ; it ! = _IntegrableForces . end ( ) ; + + it )
{
nlassert ( ( * it ) - > isIntegrable ( ) ) ;
( * it ) - > integrate ( date , this , 0 , _Size , & _Pos [ 0 ] , & _Speed [ 0 ] , accumulate ) ;
accumulate = true ;
}
}
else
{
CPSLocated : : TPSAttribParametricInfo : : const_iterator it = _PInfo . begin ( ) ,
endIt = _PInfo . end ( ) ;
TPSAttribVector : : iterator posIt = _Pos . begin ( ) ;
float deltaT ;
do
{
deltaT = date - it - > Date ;
posIt - > x = it - > Pos . x + deltaT * it - > Speed . x ;
posIt - > y = it - > Pos . y + deltaT * it - > Speed . y ;
posIt - > z = it - > Pos . z + deltaT * it - > Speed . z ;
+ + posIt ;
+ + it ;
}
while ( it ! = endIt ) ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
/// allocate parametric infos
void CPSLocated : : allocateParametricInfos ( void )
{
NL_PS_FUNC ( CPSLocated_allocateParametricInfos )
CHECK_PS_INTEGRITY
if ( _ParametricMotion ) return ;
nlassert ( supportParametricMotion ( ) ) ;
nlassert ( _Owner ) ;
const float date = _Owner - > getSystemDate ( ) ;
_PInfo . resize ( _MaxSize ) ;
// copy back infos from current position and speeds
TPSAttribVector : : const_iterator posIt = _Pos . begin ( ) , endPosIt = _Pos . end ( ) ;
TPSAttribVector : : const_iterator speedIt = _Speed . begin ( ) ;
while ( posIt ! = endPosIt )
{
_PInfo . insert ( CParametricInfo ( * posIt , * speedIt , date ) ) ;
+ + posIt ;
}
_ParametricMotion = true ;
notifyMotionTypeChanged ( ) ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
/// release parametric infos
void CPSLocated : : releaseParametricInfos ( void )
{
NL_PS_FUNC ( CPSLocated_releaseParametricInfos )
CHECK_PS_INTEGRITY
if ( ! _ParametricMotion ) return ;
NLMISC : : contReset ( _PInfo ) ;
_ParametricMotion = false ;
notifyMotionTypeChanged ( ) ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
/// Test whether this located support parametric motion
bool CPSLocated : : supportParametricMotion ( void ) const
{
NL_PS_FUNC ( CPSLocated_supportParametricMotion )
return _NonIntegrableForceNbRefs = = 0 & & _NumIntegrableForceWithDifferentBasis = = 0 ;
}
/// ***************************************************************************************
/** When set to true, this tells the system to use parametric motion. This is needed in a few case only,
* and can only work if all the forces that apply to the system are integrable
*/
void CPSLocated : : enableParametricMotion ( bool enable /*= true*/ )
{
NL_PS_FUNC ( CPSLocated_enableParametricMotion )
CHECK_PS_INTEGRITY
nlassert ( supportParametricMotion ( ) ) ;
if ( enable )
{
allocateParametricInfos ( ) ;
}
else
{
releaseParametricInfos ( ) ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : setMatrixMode ( TPSMatrixMode matrixMode )
{
NL_PS_FUNC ( CPSLocated_setMatrixMode )
CHECK_PS_INTEGRITY
if ( matrixMode ! = getMatrixMode ( ) )
{
for ( TLocatedBoundCont : : const_iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > basisChanged ( matrixMode ) ;
}
CParticleSystemProcess : : setMatrixMode ( matrixMode ) ;
for ( TForceVect : : iterator fIt = _IntegrableForces . begin ( ) ; fIt ! = _IntegrableForces . end ( ) ; + + fIt )
{
integrableForceBasisChanged ( ( * fIt ) - > getOwner ( ) - > getMatrixMode ( ) ) ;
}
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
/*
void CPSLocated : : notifyMaxNumFacesChanged ( void )
{
CHECK_PS_INTEGRITY
if ( ! _Owner ) return ;
// we examine whether we have particle attached to us, and ask for the max number of faces they may want
_MaxNumFaces = 0 ;
for ( TLocatedBoundCont : : const_iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
if ( ( * it ) - > getType ( ) = = PSParticle )
{
uint maxNumFaces = ( ( CPSParticle * ) ( * it ) ) - > getMaxNumFaces ( ) ;
///nlassertex(maxNumFaces < ((1 << 16) - 1), ("%s", (*it)->getClassName().c_str()));
_MaxNumFaces + = maxNumFaces ;
}
}
CHECK_PS_INTEGRITY
}
*/
/// ***************************************************************************************
uint CPSLocated : : getNumWantedTris ( ) const
{
NL_PS_FUNC ( CPSLocated_getNumWantedTris )
CHECK_PS_INTEGRITY
if ( ! _Owner ) return 0 ;
uint numWantedTris = 0 ;
for ( TLocatedBoundCont : : const_iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
if ( ( * it ) - > getType ( ) = = PSParticle )
{
numWantedTris + = NLMISC : : safe_cast < CPSParticle * > ( * it ) - > getNumWantedTris ( ) ;
}
}
CHECK_PS_INTEGRITY
return numWantedTris ;
}
/*
/// ***************************************************************************************
uint CPSLocated : : querryMaxWantedNumFaces ( void )
{
return _MaxNumFaces ;
}
*/
/// ***************************************************************************************
/// tells whether there are alive entities / particles in the system
bool CPSLocated : : hasParticles ( void ) const
{
NL_PS_FUNC ( CPSLocated_hasParticles )
CHECK_PS_INTEGRITY
for ( TLocatedBoundCont : : const_iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
if ( ( * it ) - > getType ( ) = = PSParticle & & ( * it ) - > hasParticles ( ) ) return true ;
}
CHECK_PS_INTEGRITY
return false ;
}
/// ***************************************************************************************
/// tells whether there are alive emitters
bool CPSLocated : : hasEmitters ( void ) const
{
NL_PS_FUNC ( CPSLocated_hasEmitters )
CHECK_PS_INTEGRITY
for ( TLocatedBoundCont : : const_iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
if ( ( * it ) - > getType ( ) = = PSEmitter & & ( * it ) - > hasEmitters ( ) ) return true ;
}
CHECK_PS_INTEGRITY
return false ;
}
/// ***************************************************************************************
void CPSLocated : : getLODVect ( NLMISC : : CVector & v , float & offset , TPSMatrixMode matrixMode )
{
NL_PS_FUNC ( CPSLocated_getLODVect )
nlassert ( _Owner ) ;
CHECK_PS_INTEGRITY
_Owner - > getLODVect ( v , offset , matrixMode ) ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
float CPSLocated : : getUserParam ( uint numParam ) const
{
NL_PS_FUNC ( CPSLocated_getUserParam )
nlassert ( _Owner ) ;
CHECK_PS_INTEGRITY
return _Owner - > getUserParam ( numParam ) ;
}
/// ***************************************************************************************
CScene * CPSLocated : : getScene ( void )
{
NL_PS_FUNC ( CPSLocated_getScene )
nlassert ( _Owner ) ;
CHECK_PS_INTEGRITY
return _Owner - > getScene ( ) ;
}
/// ***************************************************************************************
void CPSLocated : : incrementNbDrawnParticles ( uint num )
{
NL_PS_FUNC ( CPSLocated_incrementNbDrawnParticles )
CHECK_PS_INTEGRITY
CParticleSystem : : NbParticlesDrawn + = num ; // for benchmark purpose
}
/// ***************************************************************************************
void CPSLocated : : setInitialLife ( TAnimationTime lifeTime )
{
NL_PS_FUNC ( CPSLocated_setInitialLife )
CHECK_PS_INTEGRITY
_LastForever = false ;
_InitialLife = lifeTime ;
delete _LifeScheme ;
_LifeScheme = NULL ;
/** Reset all particles current date to 0. This is needed because we do not check
* if particle life is over when the date of the system has not gone beyond the life duration of particles
*/
for ( uint k = 0 ; k < _Size ; + + k )
{
_Time [ k ] = 0.f ;
}
//
if ( _Owner )
{
_Owner - > systemDurationChanged ( ) ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : setLifeScheme ( CPSAttribMaker < float > * scheme )
{
NL_PS_FUNC ( CPSLocated_setLifeScheme )
CHECK_PS_INTEGRITY
nlassert ( scheme ) ;
nlassert ( ! scheme - > hasMemory ( ) ) ; // scheme with memory is invalid there !!
_LastForever = false ;
delete _LifeScheme ;
_LifeScheme = scheme ;
//
if ( _Owner )
{
_Owner - > systemDurationChanged ( ) ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : setInitialMass ( float mass )
{
NL_PS_FUNC ( CPSLocated_setInitialMass )
CHECK_PS_INTEGRITY
_InitialMass = mass ;
delete _MassScheme ;
_MassScheme = NULL ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : setMassScheme ( CPSAttribMaker < float > * scheme )
{
NL_PS_FUNC ( CPSLocated_setMassScheme )
CHECK_PS_INTEGRITY
nlassert ( scheme ) ;
nlassert ( ! scheme - > hasMemory ( ) ) ; // scheme with memory is invalid there !!
delete _MassScheme ;
_MassScheme = scheme ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
/// get a matrix that helps to express located B coordinate in located A basis
const NLMISC : : CMatrix & CPSLocated : : getConversionMatrix ( const CParticleSystem & ps , TPSMatrixMode destMode , TPSMatrixMode srcMode )
{
NL_PS_FUNC ( CPSLocated_getConversionMatrix )
switch ( destMode )
{
case PSFXWorldMatrix :
switch ( srcMode )
{
case PSFXWorldMatrix : return NLMISC : : CMatrix : : Identity ;
case PSIdentityMatrix : return ps . getInvertedSysMat ( ) ;
case PSUserMatrix : return ps . getUserToFXMatrix ( ) ;
default :
nlassert ( 0 ) ;
}
break ;
case PSIdentityMatrix :
switch ( srcMode )
{
case PSFXWorldMatrix : return ps . getSysMat ( ) ;
case PSIdentityMatrix : return NLMISC : : CMatrix : : Identity ;
case PSUserMatrix : return ps . getUserMatrix ( ) ;
default :
nlassert ( 0 ) ;
}
break ;
case PSUserMatrix :
switch ( srcMode )
{
case PSFXWorldMatrix : return ps . getFXToUserMatrix ( ) ;
case PSIdentityMatrix : return ps . getInvertedUserMatrix ( ) ;
case PSUserMatrix : return NLMISC : : CMatrix : : Identity ;
default :
nlassert ( 0 ) ;
}
break ;
default :
nlassert ( 0 ) ;
}
nlassert ( 0 ) ;
return NLMISC : : CMatrix : : Identity ;
}
/// ***************************************************************************************
NLMISC : : CVector CPSLocated : : computeI ( void ) const
{
NL_PS_FUNC ( CPSLocated_computeI )
CHECK_PS_INTEGRITY
const NLMISC : : CMatrix & sysMat = _Owner - > getSysMat ( ) ;
if ( getMatrixMode ( ) = = PSIdentityMatrix )
{
if ( ! sysMat . hasScalePart ( ) )
{
return _Owner - > getInvertedViewMat ( ) . getI ( ) ;
}
else
{
return sysMat . getScaleUniform ( ) * _Owner - > getInvertedViewMat ( ) . getI ( ) ;
}
}
else
{
if ( ! sysMat . hasScalePart ( ) )
{
// we must express the I vector in the system basis, so we need to multiply it by the inverted matrix of the system
return getWorldToLocalMatrix ( ) . mulVector ( _Owner - > getInvertedViewMat ( ) . getI ( ) ) ;
}
else
{
return sysMat . getScaleUniform ( ) * getWorldToLocalMatrix ( ) . mulVector ( _Owner - > getInvertedViewMat ( ) . getI ( ) ) ;
}
}
}
/// ***************************************************************************************
NLMISC : : CVector CPSLocated : : computeIWithZAxisAligned ( void ) const
{
NL_PS_FUNC ( CPSLocated_computeIWithZAxisAligned )
CHECK_PS_INTEGRITY
const NLMISC : : CMatrix & sysMat = _Owner - > getSysMat ( ) ;
const CVector & camI = _Owner - > getInvertedViewMat ( ) . getI ( ) ;
CVector I ( camI . x , camI . y , 0.f ) ;
I . normalize ( ) ;
if ( getMatrixMode ( ) = = PSIdentityMatrix )
{
if ( ! sysMat . hasScalePart ( ) )
{
return I ;
}
else
{
return sysMat . getScaleUniform ( ) * I ;
}
}
else
{
if ( ! sysMat . hasScalePart ( ) )
{
// we must express the I vector in the system basis, so we need to multiply it by the inverted matrix of the system
return getWorldToLocalMatrix ( ) . mulVector ( I ) ;
}
else
{
return sysMat . getScaleUniform ( ) * getWorldToLocalMatrix ( ) . mulVector ( I ) ;
}
}
}
/// ***************************************************************************************
NLMISC : : CVector CPSLocated : : computeJ ( void ) const
{
NL_PS_FUNC ( CPSLocated_computeJ )
CHECK_PS_INTEGRITY
const NLMISC : : CMatrix & sysMat = _Owner - > getSysMat ( ) ;
if ( getMatrixMode ( ) = = PSIdentityMatrix )
{
if ( ! sysMat . hasScalePart ( ) )
{
return _Owner - > getInvertedViewMat ( ) . getJ ( ) ;
}
else
{
return sysMat . getScaleUniform ( ) * _Owner - > getInvertedViewMat ( ) . getJ ( ) ;
}
}
else
{
if ( ! sysMat . hasScalePart ( ) )
{
// we must express the J vector in the system basis, so we need to multiply it by the inverted matrix of the system
return getWorldToLocalMatrix ( ) . mulVector ( _Owner - > getInvertedViewMat ( ) . getJ ( ) ) ;
}
else
{
return sysMat . getScaleUniform ( ) * getWorldToLocalMatrix ( ) . mulVector ( _Owner - > getInvertedViewMat ( ) . getJ ( ) ) ;
}
}
}
/// ***************************************************************************************
NLMISC : : CVector CPSLocated : : computeK ( void ) const
{
NL_PS_FUNC ( CPSLocated_computeK )
CHECK_PS_INTEGRITY
const NLMISC : : CMatrix & sysMat = _Owner - > getSysMat ( ) ;
if ( getMatrixMode ( ) = = PSIdentityMatrix )
{
if ( ! sysMat . hasScalePart ( ) )
{
return _Owner - > getInvertedViewMat ( ) . getK ( ) ;
}
else
{
return sysMat . getScaleUniform ( ) * _Owner - > getInvertedViewMat ( ) . getK ( ) ;
}
}
else
{
if ( ! sysMat . hasScalePart ( ) )
{
// we must express the K vector in the system basis, so we need to multiply it by the inverted matrix of the system
return getWorldToLocalMatrix ( ) . mulVector ( _Owner - > getInvertedViewMat ( ) . getK ( ) ) ;
}
else
{
return sysMat . getScaleUniform ( ) * getWorldToLocalMatrix ( ) . mulVector ( _Owner - > getInvertedViewMat ( ) . getK ( ) ) ;
}
}
}
/// ***************************************************************************************
NLMISC : : CVector CPSLocated : : computeKWithZAxisAligned ( void ) const
{
NL_PS_FUNC ( CPSLocated_computeKWithZAxisAligned )
CHECK_PS_INTEGRITY
const NLMISC : : CMatrix & sysMat = _Owner - > getSysMat ( ) ;
if ( getMatrixMode ( ) = = PSIdentityMatrix )
{
if ( ! sysMat . hasScalePart ( ) )
{
return CVector : : K ;
}
else
{
return CVector ( 0.f , 0.f , sysMat . getScaleUniform ( ) ) ;
}
}
else
{
if ( ! sysMat . hasScalePart ( ) )
{
// we must express the K vector in the system basis, so we need to multiply it by the inverted matrix of the system
return getWorldToLocalMatrix ( ) . mulVector ( CVector : : K ) ;
}
else
{
return getWorldToLocalMatrix ( ) . mulVector ( CVector ( 0.f , 0.f , sysMat . getScaleUniform ( ) ) ) ;
}
}
}
/// ***************************************************************************************
IDriver * CPSLocated : : getDriver ( ) const
{
NL_PS_FUNC ( CPSLocated_getDriver )
CHECK_PS_INTEGRITY
nlassert ( _Owner ) ;
nlassert ( _Owner - > getDriver ( ) ) ; // you haven't called setDriver on the system
return _Owner - > getDriver ( ) ;
}
/// ***************************************************************************************
/// dtor
CPSLocated : : ~ CPSLocated ( )
{
NL_PS_FUNC ( CPSLocated_CPSLocated )
CHECK_PS_INTEGRITY
// we must do a copy, because the subsequent call can modify this vector
TDtorObserversVect copyVect ( _DtorObserversVect . begin ( ) , _DtorObserversVect . end ( ) ) ;
// call all the dtor observers
for ( TDtorObserversVect : : iterator it = copyVect . begin ( ) ; it ! = copyVect . end ( ) ; + + it )
{
( * it ) - > notifyTargetRemoved ( this ) ;
}
nlassert ( _CollisionInfoNbRef = = 0 ) ; //If this is not = 0, then someone didnt call releaseCollisionInfo
// If this happen, you can register with the registerDTorObserver
// (observer pattern)
// and override notifyTargetRemove to call releaseCollisionInfo
nlassert ( _IntegrableForces . size ( ) = = 0 ) ;
nlassert ( _NonIntegrableForceNbRefs = = 0 ) ;
// delete all bindable
for ( TLocatedBoundCont : : iterator it2 = _LocatedBoundCont . begin ( ) ; it2 ! = _LocatedBoundCont . end ( ) ; + + it2 )
{
( * it2 ) - > finalize ( ) ;
delete * it2 ;
}
_LocatedBoundCont . clear ( ) ;
delete _LifeScheme ;
delete _MassScheme ;
delete _CollisionNextPos ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
/**
* sorted insertion ( by decreasing priority order ) of a bindable ( particle e . g an aspect , emitter ) in a located
*/
bool CPSLocated : : bind ( CPSLocatedBindable * lb )
{
NL_PS_FUNC ( CPSLocated_bind )
CHECK_PS_INTEGRITY
nlassert ( std : : find ( _LocatedBoundCont . begin ( ) , _LocatedBoundCont . end ( ) , lb ) = = _LocatedBoundCont . end ( ) ) ;
TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ;
while ( it ! = _LocatedBoundCont . end ( ) & & * * it < * lb ) // the "<" operator sort them correctly
{
+ + it ;
}
_LocatedBoundCont . insert ( it , lb ) ;
lb - > setOwner ( this ) ;
lb - > resize ( _MaxSize ) ;
// any located bindable that is bound to us should have no element in it for now !!
// we resize it anyway...
uint32 initialSize = _Size ;
CPSEmitterInfo ei ;
ei . setDefaults ( ) ;
for ( uint k = 0 ; k < initialSize ; + + k )
{
_Size = k ;
lb - > newElement ( ei ) ;
}
_Size = initialSize ;
if ( _ParametricMotion ) lb - > motionTypeChanged ( true ) ;
/// the max number of shapes may have changed
//notifyMaxNumFacesChanged();
if ( _Owner )
{
CParticleSystem * ps = _Owner ;
if ( ps - > getBypassMaxNumIntegrationSteps ( ) )
{
if ( ! ps - > canFinish ( ) )
{
unbind ( getIndexOf ( lb ) ) ;
nlwarning ( " <CPSLocated::bind> Can't bind the located : this causes the system to last forever, and it has been flagged with 'BypassMaxNumIntegrationSteps'. Located is not bound. " ) ;
return false ;
}
}
// if there's an extern id, register in lb list
if ( lb - > getExternID ( ) ! = 0 )
{
// register in ID list
ps - > registerLocatedBindableExternID ( lb - > getExternID ( ) , lb ) ;
}
_Owner - > systemDurationChanged ( ) ;
}
CHECK_PS_INTEGRITY
return true ;
}
/// ***************************************************************************************
void CPSLocated : : remove ( const CPSLocatedBindable * p )
{
NL_PS_FUNC ( CPSLocated_remove )
CHECK_PS_INTEGRITY
TLocatedBoundCont : : iterator it = std : : find ( _LocatedBoundCont . begin ( ) , _LocatedBoundCont . end ( ) , p ) ;
nlassert ( it ! = _LocatedBoundCont . end ( ) ) ;
( * it ) - > finalize ( ) ;
delete * it ;
_LocatedBoundCont . erase ( it ) ;
if ( _Owner )
{
_Owner - > systemDurationChanged ( ) ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : registerDtorObserver ( CPSLocatedBindable * anObserver )
{
NL_PS_FUNC ( CPSLocated_registerDtorObserver )
CHECK_PS_INTEGRITY
// check whether the observer wasn't registered twice
nlassert ( std : : find ( _DtorObserversVect . begin ( ) , _DtorObserversVect . end ( ) , anObserver ) = = _DtorObserversVect . end ( ) ) ;
_DtorObserversVect . push_back ( anObserver ) ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : unregisterDtorObserver ( CPSLocatedBindable * anObserver )
{
NL_PS_FUNC ( CPSLocated_unregisterDtorObserver )
CHECK_PS_INTEGRITY
// check that it was registered
TDtorObserversVect : : iterator it = std : : find ( _DtorObserversVect . begin ( ) , _DtorObserversVect . end ( ) , anObserver ) ;
nlassert ( it ! = _DtorObserversVect . end ( ) ) ;
_DtorObserversVect . erase ( it ) ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : postNewElement ( const NLMISC : : CVector & pos ,
const NLMISC : : CVector & speed ,
CPSLocated & emitterLocated ,
uint32 indexInEmitter ,
TPSMatrixMode speedCoordSystem ,
TAnimationTime lifeTime )
{
NL_PS_FUNC ( CPSLocated_postNewElement )
nlassert ( CParticleSystem : : InsideSimLoop ) ; // should be called only inside the sim loop!
// In the event loop life of emitter is updated just after particles are spawned, so we must check there if the particle wasn't emitted when the
// emitter was already destroyed
// When postNewElement is called, the particle and the emitter that created it live at the same date, so EmitterLife - ParticleLife should be > 1.f
float emitterLife ;
if ( ! emitterLocated . getLastForever ( ) )
{
if ( emitterLocated . _LifeScheme )
{
emitterLife = emitterLocated . _Time [ indexInEmitter ] - lifeTime * CParticleSystem : : RealEllapsedTimeRatio * emitterLocated . _TimeIncrement [ indexInEmitter ] ;
if ( emitterLife > = 1.f )
{
return ; // emitter had finished its life
}
}
else
{
emitterLife = emitterLocated . _Time [ indexInEmitter ] * emitterLocated . _InitialLife - lifeTime * CParticleSystem : : RealEllapsedTimeRatio ;
if ( emitterLife > = emitterLocated . _InitialLife )
{
return ; // emitter had finished its life
}
if ( emitterLocated . _InitialLife ! = 0.f )
{
emitterLife / = emitterLocated . _InitialLife ;
}
}
}
else
{
emitterLife = emitterLocated . getTime ( ) [ indexInEmitter ] ;
}
// now check that the emitter didn't collide before it spawned a particle
if ( emitterLocated . hasCollisionInfos ( ) )
{
const CPSCollisionInfo & ci = _Collisions [ indexInEmitter ] ;
if ( ci . Dist ! = - 1.f )
{
// a collision occured, check time from collision to next time step
if ( ( emitterLocated . getPos ( ) [ indexInEmitter ] - ci . NewPos ) * ( pos - ci . NewPos ) > 0.f ) return ; // discard emit that are farther than the collision
}
}
// create a request to create a new element
CParticleSystem : : CSpawnVect & sp = * CParticleSystem : : _Spawns [ getIndex ( ) ] ;
if ( ! _Owner - > getAutoCountFlag ( ) & & sp . MaxNumSpawns = = sp . SpawnInfos . size ( ) ) return ; // no more place to spawn
if ( getMaxSize ( ) > = ( ( 1 < < 16 ) - 1 ) ) return ;
sp . SpawnInfos . resize ( sp . SpawnInfos . size ( ) + 1 ) ;
CPSSpawnInfo & si = sp . SpawnInfos . back ( ) ;
si . EmitterInfo . Pos = emitterLocated . getPos ( ) [ indexInEmitter ] ;
si . EmitterInfo . Speed = emitterLocated . getSpeed ( ) [ indexInEmitter ] ;
si . EmitterInfo . InvMass = emitterLocated . getInvMass ( ) [ indexInEmitter ] ;
si . EmitterInfo . Life = emitterLife ;
si . EmitterInfo . Loc = & emitterLocated ;
si . SpawnPos = pos ;
si . Speed = speed ;
si . SpeedCoordSystem = speedCoordSystem ;
si . LifeTime = lifeTime ;
}
/// ***************************************************************************************
sint32 CPSLocated : : newElement ( const CPSSpawnInfo & si , bool doEmitOnce /* = false */ , TAnimationTime ellapsedTime )
{
NL_PS_FUNC ( CPSLocated_newElement )
CHECK_PS_INTEGRITY
sint32 creationIndex ;
// get the convertion matrix from the emitter basis to the emittee basis
// if the emitter is null, we assume that the coordinate are given in the chosen basis for this particle type
if ( _MaxSize = = _Size )
{
if ( _Owner & & _Owner - > getAutoCountFlag ( ) & & getMaxSize ( ) < ( ( 1 < < 16 ) - 1 ) )
{
// we are probably in edition mode -> auto-count mode helps to compute ideal particle array size
// but at the expense of costly allocations
uint maxSize = getMaxSize ( ) ;
resize ( ( uint32 ) std : : min ( ( uint ) NLMISC : : raiseToNextPowerOf2 ( maxSize + 1 ) , ( uint ) ( ( 1 < < 16 ) - 1 ) ) ) ; // force a reserve with next power of 2 (no important in edition mode)
resize ( maxSize + 1 ) ;
CParticleSystem : : _SpawnPos . resize ( maxSize + 1 ) ;
}
else
{
return - 1 ;
}
}
// During creation, we interpolate the position of the system (by using the ellapsed time) if particle are created in world basis and if the emitter is in local basis.
// Example a fireball FX let particles in world basis, but the fireball is moving. If we dont interpolate position between 2 frames, emission will appear to be "sporadic".
// For now, we manage the local to world case. The world to local is possible, but not very useful
switch ( si . EmitterInfo . Loc ? si . EmitterInfo . Loc - > getMatrixMode ( ) : this - > getMatrixMode ( ) )
{
case PSFXWorldMatrix :
switch ( this - > getMatrixMode ( ) )
{
case PSFXWorldMatrix :
{
creationIndex = _Pos . insert ( si . SpawnPos ) ;
}
break ;
case PSIdentityMatrix :
{
CVector fxPosDelta ;
_Owner - > interpolateFXPosDelta ( fxPosDelta , si . LifeTime ) ;
creationIndex = _Pos . insert ( _Owner - > getSysMat ( ) * si . SpawnPos + fxPosDelta ) ;
}
break ;
case PSUserMatrix :
{
CVector fxPosDelta ;
_Owner - > interpolateFXPosDelta ( fxPosDelta , si . LifeTime ) ;
CVector userMatrixPosDelta ;
_Owner - > interpolateUserPosDelta ( userMatrixPosDelta , si . LifeTime ) ;
creationIndex = _Pos . insert ( _Owner - > getInvertedUserMatrix ( ) * ( _Owner - > getSysMat ( ) * si . SpawnPos + fxPosDelta - userMatrixPosDelta ) ) ;
}
break ;
default :
nlassert ( 0 ) ;
}
break ;
case PSIdentityMatrix :
switch ( this - > getMatrixMode ( ) )
{
case PSFXWorldMatrix :
{
CVector fxPosDelta ;
_Owner - > interpolateFXPosDelta ( fxPosDelta , si . LifeTime ) ;
creationIndex = _Pos . insert ( _Owner - > getInvertedSysMat ( ) * ( si . SpawnPos - fxPosDelta ) ) ;
}
break ;
case PSIdentityMatrix :
{
creationIndex = _Pos . insert ( si . SpawnPos ) ;
}
break ;
case PSUserMatrix :
{
CVector userMatrixPosDelta ;
_Owner - > interpolateUserPosDelta ( userMatrixPosDelta , si . LifeTime ) ;
creationIndex = _Pos . insert ( _Owner - > getInvertedUserMatrix ( ) * ( si . SpawnPos - userMatrixPosDelta ) ) ;
}
break ;
default :
nlassert ( 0 ) ;
}
break ;
case PSUserMatrix :
switch ( this - > getMatrixMode ( ) )
{
case PSFXWorldMatrix :
{
CVector fxPosDelta ;
_Owner - > interpolateFXPosDelta ( fxPosDelta , si . LifeTime ) ;
CVector userMatrixPosDelta ;
_Owner - > interpolateUserPosDelta ( userMatrixPosDelta , si . LifeTime ) ;
creationIndex = _Pos . insert ( _Owner - > getInvertedSysMat ( ) * ( _Owner - > getUserMatrix ( ) * si . SpawnPos + userMatrixPosDelta - fxPosDelta ) ) ;
}
break ;
case PSIdentityMatrix :
{
CVector userMatrixPosDelta ;
_Owner - > interpolateUserPosDelta ( userMatrixPosDelta , si . LifeTime ) ;
creationIndex = _Pos . insert ( _Owner - > getUserMatrix ( ) * si . SpawnPos + userMatrixPosDelta ) ;
}
break ;
case PSUserMatrix :
{
creationIndex = _Pos . insert ( si . SpawnPos ) ;
}
break ;
default :
nlassert ( 0 ) ;
}
break ;
default :
nlassert ( 0 ) ;
}
nlassert ( creationIndex ! = - 1 ) ; // all attributs must contains the same number of elements
if ( si . SpeedCoordSystem = = this - > getMatrixMode ( ) ) // is speed vector expressed in the good basis ?
{
_Speed . insert ( si . Speed ) ;
}
else
{
// must do conversion of speed
nlassert ( _Owner ) ;
const NLMISC : : CMatrix & convMat = getConversionMatrix ( * _Owner , this - > getMatrixMode ( ) , si . SpeedCoordSystem ) ;
_Speed . insert ( convMat . mulVector ( si . Speed ) ) ;
}
_InvMass . insert ( 1.f / ( ( _MassScheme & & si . EmitterInfo . Loc ) ? _MassScheme - > get ( si . EmitterInfo ) : _InitialMass ) ) ;
if ( CParticleSystem : : InsideSimLoop )
{
CParticleSystem : : _SpawnPos [ creationIndex ] = _Pos [ creationIndex ] ;
}
// compute age of particle when it has been created
if ( getLastForever ( ) )
{
// age of particle is in seconds
_Time . insert ( CParticleSystem : : RealEllapsedTimeRatio * si . LifeTime ) ;
_TimeIncrement . insert ( _InitialLife ! = 0.f ? 1.f / _InitialLife : 1.f ) ;
}
else
{
const float totalLifeTime = ( _LifeScheme & & si . EmitterInfo . Loc ) ? _LifeScheme - > get ( si . EmitterInfo ) : _InitialLife ;
float timeIncrement = totalLifeTime ? 1.f / totalLifeTime : 10E6 f ;
_TimeIncrement . insert ( timeIncrement ) ;
_Time . insert ( CParticleSystem : : RealEllapsedTimeRatio * si . LifeTime * timeIncrement ) ;
}
// test whether parametric motion is used, and generate the infos that are needed then
if ( _ParametricMotion )
{
_PInfo . insert ( CParametricInfo ( _Pos [ creationIndex ] , _Speed [ creationIndex ] , _Owner - > getSystemDate ( ) + CParticleSystem : : RealEllapsedTime - CParticleSystem : : RealEllapsedTimeRatio * si . LifeTime ) ) ;
}
else
{
_Pos [ creationIndex ] + = si . LifeTime * _Speed [ creationIndex ] ;
}
///////////////////////////////////////////
// generate datas for all bound objects //
///////////////////////////////////////////
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > newElement ( si . EmitterInfo ) ;
// if element is an emitter, then must bias the emission time counter because it will be updated of frameDT, but the particle has been alive for (frameDT - deltaT)
if ( ( * it ) - > getType ( ) = = PSEmitter )
{
CPSEmitter * pEmit = NLMISC : : safe_cast < CPSEmitter * > ( * it ) ;
pEmit - > _Phase [ creationIndex ] - = std : : max ( 0.f , ( ellapsedTime - si . LifeTime ) ) ;
}
}
if ( doEmitOnce & & ! CPSEmitter : : getBypassEmitOnDeath ( ) )
{
// can be called only outside the sim loop (when the user triggers an emitters for example)
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
if ( ( * it ) - > getType ( ) = = PSEmitter )
{
CPSEmitter * pEmit = NLMISC : : safe_cast < CPSEmitter * > ( * it ) ;
if ( pEmit - > getEmissionType ( ) = = CPSEmitter : : once )
{
for ( uint k = 0 ; k < getSize ( ) ; + + k )
{
pEmit - > singleEmit ( k , 1 ) ;
}
}
}
}
}
if ( _CollisionNextPos )
{
_CollisionNextPos - > insert ( ) ;
}
+ + _Size ; // if this is modified, you must also modify the getNewElementIndex in this class
// because that method give the index of the element being created for overrider of the newElement method
// of the CPSLocatedClass (which is called just above)
CHECK_PS_INTEGRITY
return creationIndex ;
}
/// ***************************************************************************************
sint32 CPSLocated : : newElement ( const CVector & pos , const CVector & speed , CPSLocated * emitter , uint32 indexInEmitter ,
TPSMatrixMode speedCoordSystem , bool doEmitOnce /* = false */ )
{
NL_PS_FUNC ( CPSLocated_newElement )
CPSSpawnInfo si ;
si . EmitterInfo . Loc = emitter ;
if ( emitter )
{
si . EmitterInfo . Pos = emitter - > getPos ( ) [ indexInEmitter ] ;
si . EmitterInfo . Speed = emitter - > getSpeed ( ) [ indexInEmitter ] ;
si . EmitterInfo . InvMass = emitter - > getInvMass ( ) [ indexInEmitter ] ;
si . EmitterInfo . Life = emitter - > getTime ( ) [ indexInEmitter ] ;
}
else
{
si . EmitterInfo . Pos = NLMISC : : CVector : : Null ;
si . EmitterInfo . Speed = NLMISC : : CVector : : Null ;
si . EmitterInfo . InvMass = 1.f ;
si . EmitterInfo . Life = 0.f ;
}
si . SpawnPos = pos ;
si . Speed = speed ;
si . SpeedCoordSystem = speedCoordSystem ;
si . LifeTime = 0.f ;
return newElement ( si , doEmitOnce , 0.f ) ;
}
/// ***************************************************************************************
static inline uint32 IDToLittleEndian ( uint32 input )
{
NL_PS_FUNC ( IDToLittleEndian )
# ifdef NL_LITTLE_ENDIAN
return input ;
# else
return ( ( input & ( 0xff < < 24 ) ) > > 24 )
| | ( ( input & ( 0xff < < 16 ) ) > > 8 )
| | ( ( input & ( 0xff < < 8 ) ) < < 8 )
| | ( ( input & 0xff ) < < 24 ) ;
# endif
}
/// ***************************************************************************************
inline void CPSLocated : : deleteElementBase ( uint32 index )
{
NL_PS_FUNC ( CPSLocated_deleteElementBase )
// remove common located's attributes
_InvMass . remove ( index ) ;
_Pos . remove ( index ) ;
_Speed . remove ( index ) ;
_Time . remove ( index ) ;
_TimeIncrement . remove ( index ) ;
if ( _CollisionNextPos )
{
_CollisionNextPos - > remove ( index ) ;
}
if ( _ParametricMotion )
{
_PInfo . remove ( index ) ;
}
- - _Size ;
if ( _TriggerOnDeath )
{
const uint32 id = IDToLittleEndian ( _TriggerID ) ;
nlassert ( _Owner ) ;
uint numLb = _Owner - > getNumLocatedBindableByExternID ( id ) ;
for ( uint k = 0 ; k < numLb ; + + k )
{
CPSLocatedBindable * lb = _Owner - > getLocatedBindableByExternID ( id , k ) ;
if ( lb - > getType ( ) = = PSEmitter )
{
CPSEmitter * e = NLMISC : : safe_cast < CPSEmitter * > ( lb ) ;
e - > setEmitTrigger ( ) ;
}
}
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : deleteElement ( uint32 index )
{
NL_PS_FUNC ( CPSLocated_deleteElement )
# ifdef NL_DEBUG
if ( CParticleSystem : : InsideSimLoop )
{
nlassert ( CParticleSystem : : InsideRemoveLoop ) ;
}
# endif
CHECK_PS_INTEGRITY
nlassert ( index < _Size ) ;
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > deleteElement ( index ) ;
}
deleteElementBase ( index ) ;
}
/// ***************************************************************************************
void CPSLocated : : deleteElement ( uint32 index , TAnimationTime timeToNextSimStep )
{
NL_PS_FUNC ( CPSLocated_deleteElement )
# ifdef NL_DEBUG
if ( CParticleSystem : : InsideSimLoop )
{
nlassert ( CParticleSystem : : InsideRemoveLoop ) ;
}
# endif
nlassert ( index < _Size ) ;
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > deleteElement ( index , timeToNextSimStep ) ;
}
deleteElementBase ( index ) ;
}
/// Resize the located container
/// ***************************************************************************************
void CPSLocated : : resize ( uint32 newSize )
{
NL_PS_FUNC ( CPSLocated_resize )
CHECK_PS_INTEGRITY
nlassert ( newSize < ( 1 < < 16 ) ) ;
if ( newSize < _Size )
{
for ( uint32 k = _Size - 1 ; k > = newSize ; - - k )
{
deleteElement ( k ) ;
if ( k = = 0 ) break ; // we're dealing with unsigned quantities
}
_Size = newSize ;
}
_MaxSize = newSize ;
_InvMass . resize ( newSize ) ;
_Pos . resize ( newSize ) ;
_Speed . resize ( newSize ) ;
_Time . resize ( newSize ) ;
_TimeIncrement . resize ( newSize ) ;
if ( _ParametricMotion )
{
_PInfo . resize ( newSize ) ;
}
if ( _CollisionNextPos )
{
_CollisionNextPos - > resize ( newSize ) ;
}
// resize attributes for all bound objects
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > resize ( newSize ) ;
}
/// compute the new max number of faces
//notifyMaxNumFacesChanged();
CHECK_PS_INTEGRITY
}
// dummy struct for serial of a field that has been removed
class CDummyCollision
{
public :
void serial ( NLMISC : : IStream & f ) throw ( NLMISC : : EStream )
{
NL_PS_FUNC ( CDummyCollision_serial )
f . serialVersion ( 1 ) ;
float dummyDist = 0.f ;
NLMISC : : CVector dummyNewPos , dummyNewSpeed ;
f . serial ( dummyDist , dummyNewPos , dummyNewSpeed ) ;
} ;
} ;
/// ***************************************************************************************
void CPSLocated : : serial ( NLMISC : : IStream & f ) throw ( NLMISC : : EStream )
{
NL_PS_FUNC ( CPSLocated_serial )
// version 7 : - removed the field _NbFramesToSkip to get some space (it is never used)
// - removed the requestStack (system graph can't contains loops now)
// - removed _CollisonInfos because they are now static
// version 4 to version 5 : bugfix with reading of collisions
sint ver = f . serialVersion ( 7 ) ;
CParticleSystemProcess : : serial ( f ) ;
if ( f . isReading ( ) & & ! CParticleSystem : : getSerializeIdentifierFlag ( ) )
{
// just skip the name
sint32 len ;
f . serial ( len ) ;
f . seek ( len , NLMISC : : IStream : : current ) ;
}
else
{
f . serial ( _Name ) ;
}
f . serial ( _InvMass ) ;
f . serial ( _Pos ) ;
f . serial ( _Speed ) ;
f . serial ( _Time ) ;
if ( f . isReading ( ) )
{
// tmp fix : some fx were saved with a life that is != to 0
// this cause an assertion in CPSLocated::updateLife, because all particle are assumed to have an age of 0 when the system is started
// TODO : saving _Time is maybe unecessary... or find something better for CPSLocated::updateLife
uint timeSize = _Time . getSize ( ) ;
if ( timeSize ! = 0 )
{
std : : fill ( & _Time [ 0 ] , & _Time [ 0 ] + timeSize , 0.f ) ;
}
}
f . serial ( _TimeIncrement ) ;
f . serial ( _Size ) ;
f . serial ( _MaxSize ) ;
bool lastForever = _LastForever ;
f . serial ( lastForever ) ;
_LastForever = lastForever ;
if ( ver < 7 )
{
nlassert ( f . isReading ( ) ) ;
// serial a dummy ptr (previous code did a serial ptr)
uint64 dummyPtr ;
f . serial ( dummyPtr ) ;
if ( dummyPtr )
{
# ifdef PS_FAST_ALLOC
extern NLMISC : : CContiguousBlockAllocator * PSBlockAllocator ;
NLMISC : : CContiguousBlockAllocator * oldAlloc = PSBlockAllocator ;
PSBlockAllocator = NULL ;
# endif
static CPSAttrib < CDummyCollision > col ;
col . clear ( ) ;
f . serial ( col ) ;
# ifdef PS_FAST_ALLOC
PSBlockAllocator = oldAlloc ;
# endif
}
}
f . serial ( _CollisionInfoNbRef ) ; // TODO avoid to serialize this ?
//
if ( f . isReading ( ) )
{
if ( _CollisionInfoNbRef )
{
_CollisionNextPos = new TPSAttribVector ;
_CollisionNextPos - > resize ( _Pos . getMaxSize ( ) ) ;
for ( uint k = 0 ; k < _Size ; + + k )
{
_CollisionNextPos - > insert ( ) ;
}
}
}
//CHECK_PS_INTEGRITY
if ( f . isReading ( ) )
{
delete _LifeScheme ;
delete _MassScheme ;
bool useScheme ;
f . serial ( useScheme ) ;
if ( useScheme )
{
f . serialPolyPtr ( _LifeScheme ) ;
}
else
{
f . serial ( _InitialLife ) ;
_LifeScheme = NULL ;
}
f . serial ( useScheme ) ;
if ( useScheme )
{
f . serialPolyPtr ( _MassScheme ) ;
}
else
{
f . serial ( _InitialMass ) ;
nlassert ( _InitialMass > 0 ) ;
_MassScheme = NULL ;
}
}
else
{
bool bFalse = false , bTrue = true ;
if ( _LifeScheme )
{
f . serial ( bTrue ) ;
f . serialPolyPtr ( _LifeScheme ) ;
}
else
{
f . serial ( bFalse ) ;
f . serial ( _InitialLife ) ;
}
if ( _MassScheme )
{
f . serial ( bTrue ) ;
f . serialPolyPtr ( _MassScheme ) ;
}
else
{
f . serial ( bFalse ) ;
nlassert ( _InitialMass > 0 ) ;
f . serial ( _InitialMass ) ;
}
}
if ( ver < 7 )
{
uint32 dummy = 0 ; // was previously the field "_NbFramesToSkip"
f . serial ( dummy ) ;
}
f . serialContPolyPtr ( _DtorObserversVect ) ;
if ( ver < 7 )
{
nlassert ( f . isReading ( ) ) ;
// previously, there was a request stack serialized (because system permitted loops)
uint32 size ;
f . serial ( size ) ;
nlassert ( size = = 0 ) ;
/*
for ( uint32 k = 0 ; k < size ; + + k )
{
TNewElementRequestStack : : value_type t ;
f . serial ( t ) ;
_RequestStack . push ( t ) ;
}
*/
}
if ( ver < 7 )
{
nlassert ( f . isReading ( ) ) ;
bool dummy ;
f . serial ( dummy ) ; // was previously the flag "_UpdateLock"
}
f . serialContPolyPtr ( _LocatedBoundCont ) ;
// check that owners are good
# ifdef NL_DEBUG
for ( uint k = 0 ; k < _LocatedBoundCont . size ( ) ; + + k )
{
nlassert ( _LocatedBoundCont [ k ] - > getOwner ( ) = = this ) ;
}
# endif
if ( ver > 1 )
{
bool lodDegradation = _LODDegradation ;
f . serial ( lodDegradation ) ;
_LODDegradation = lodDegradation ;
}
if ( ver > 2 )
{
bool parametricMotion = _ParametricMotion ;
f . serial ( parametricMotion ) ;
_ParametricMotion = parametricMotion ;
}
if ( f . isReading ( ) )
{
// evaluate our max number of faces
//notifyMaxNumFacesChanged();
if ( _ParametricMotion )
{
_ParametricMotion = false ;
allocateParametricInfos ( ) ;
_ParametricMotion = true ;
}
}
if ( ver > 3 )
{
bool triggerOnDeath = _TriggerOnDeath ;
f . serial ( triggerOnDeath ) ;
_TriggerOnDeath = triggerOnDeath ;
f . serial ( _TriggerID ) ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
// integrate speed of particles. Makes eventually use of SSE instructions when present
static void IntegrateSpeed ( uint count , float * src1 , const float * src2 , float * dest , float ellapsedTime )
{
NL_PS_FUNC ( IntegrateSpeed )
#if 0 // this works, but is not enabled for now. The precision is not that good...
/*
# ifdef NL_OS_WINDOWS
if ( NLMISC : : CCpuInfo : : hasSSE ( )
& & ( ( uint ) src1 & 15 ) = = ( ( uint ) src2 & 15 )
& & ! ( ( uint ) src1 & 3 )
& & ! ( ( uint ) src2 & 3 )
) // must must be sure that memory alignment is identical
{
// compute first datas in order to align to 16 byte boudary
uint alignCount = ( ( uint ) src1 > > 2 ) & 3 ; // number of float to process
while ( alignCount - - )
{
* src1 + + + = ellapsedTime * * src2 + + ;
}
count - = alignCount ;
if ( count > 3 )
{
float et [ 4 ] = { ellapsedTime , ellapsedTime , ellapsedTime , ellapsedTime } ;
// sse part of computation
__asm
{
mov ecx , count
shr ecx , 2
xor edx , edx
mov eax , src1
mov ebx , src2
movups xmm0 , et [ 0 ]
myLoop :
movaps xmm2 , [ ebx + 8 * edx ]
movaps xmm1 , [ eax + 8 * edx ]
mulps xmm2 , xmm0
addps xmm1 , xmm2
movaps [ eax + 8 * edx ] , xmm1
add edx , 2
dec ecx
jne myLoop
}
}
// proceed with left float
count & = 3 ;
if ( count )
{
src1 + = alignCount ;
src2 + = alignCount ;
do
{
* src1 + = ellapsedTime * * src2 ;
+ + src1 ;
+ + src2 ;
}
while ( - - count ) ;
}
}
else
# endif
*/
# endif
{
// standard version
// standard version
uint countDiv8 = count > > 3 ;
count & = 7 ; // takes count % 8
if ( dest = = src1 )
{
while ( countDiv8 - - )
{
src1 [ 0 ] + = ellapsedTime * src2 [ 0 ] ;
src1 [ 1 ] + = ellapsedTime * src2 [ 1 ] ;
src1 [ 2 ] + = ellapsedTime * src2 [ 2 ] ;
src1 [ 3 ] + = ellapsedTime * src2 [ 3 ] ;
src1 [ 4 ] + = ellapsedTime * src2 [ 4 ] ;
src1 [ 5 ] + = ellapsedTime * src2 [ 5 ] ;
src1 [ 6 ] + = ellapsedTime * src2 [ 6 ] ;
src1 [ 7 ] + = ellapsedTime * src2 [ 7 ] ;
src2 + = 8 ;
src1 + = 8 ;
}
while ( count - - )
{
* src1 + + + = ellapsedTime * * src2 + + ;
}
}
else
{
while ( countDiv8 - - )
{
dest [ 0 ] = src1 [ 0 ] + ellapsedTime * src2 [ 0 ] ;
dest [ 1 ] = src1 [ 1 ] + ellapsedTime * src2 [ 1 ] ;
dest [ 2 ] = src1 [ 2 ] + ellapsedTime * src2 [ 2 ] ;
dest [ 3 ] = src1 [ 3 ] + ellapsedTime * src2 [ 3 ] ;
dest [ 4 ] = src1 [ 4 ] + ellapsedTime * src2 [ 4 ] ;
dest [ 5 ] = src1 [ 5 ] + ellapsedTime * src2 [ 5 ] ;
dest [ 6 ] = src1 [ 6 ] + ellapsedTime * src2 [ 6 ] ;
dest [ 7 ] = src1 [ 7 ] + ellapsedTime * src2 [ 7 ] ;
src2 + = 8 ;
src1 + = 8 ;
dest + = 8 ;
}
while ( count - - )
{
* dest + + = * src1 + + + ellapsedTime * * src2 + + ;
}
}
}
}
/// ***************************************************************************************
void CPSLocated : : computeMotion ( )
{
NL_PS_FUNC ( CPSLocated_computeMotion )
nlassert ( _Size ) ;
// there are 2 integration steps : with and without collisions
if ( ! _CollisionNextPos ) // no collisionner are used
{
{
MINI_TIMER ( PSMotion3 )
if ( _Size ! = 0 ) // avoid referencing _Pos[0] if there's no size, causes STL vectors to assert...
IntegrateSpeed ( _Size * 3 , & _Pos [ 0 ] . x , & _Speed [ 0 ] . x , & _Pos [ 0 ] . x , CParticleSystem : : EllapsedTime ) ;
}
}
else
{
{
MINI_TIMER ( PSMotion4 )
// compute new position after the timeStep
IntegrateSpeed ( _Size * 3 , & _Pos [ 0 ] . x , & _Speed [ 0 ] . x , & ( * _CollisionNextPos ) [ 0 ] . x , CParticleSystem : : EllapsedTime ) ;
nlassert ( CPSLocated : : _Collisions . size ( ) > = _Size ) ;
computeCollisions ( 0 , & _Pos [ 0 ] , & ( * _CollisionNextPos ) [ 0 ] ) ;
// update new poositions by just swapping the 2 vectors
_CollisionNextPos - > swap ( _Pos ) ;
}
}
}
/// ***************************************************************************************
void CPSLocated : : computeNewParticleMotion ( uint firstInstanceIndex )
{
NL_PS_FUNC ( CPSLocated_computeNewParticleMotion )
nlassert ( _CollisionNextPos ) ;
resetCollisions ( _Size ) ;
computeCollisions ( firstInstanceIndex , & CParticleSystem : : _SpawnPos [ 0 ] , & _Pos [ 0 ] ) ;
}
/// ***************************************************************************************
void CPSLocated : : resetCollisions ( uint numInstances )
{
NL_PS_FUNC ( CPSLocated_resetCollisions )
CPSCollisionInfo * currCollision = _FirstCollision ;
while ( currCollision )
{
currCollision - > Dist = - 1.f ;
currCollision = currCollision - > Next ;
}
_FirstCollision = NULL ;
if ( numInstances > _Collisions . size ( ) )
{
uint oldSize = ( uint ) _Collisions . size ( ) ;
_Collisions . resize ( numInstances ) ;
for ( uint k = oldSize ; k < numInstances ; + + k )
{
_Collisions [ k ] . Index = k ;
}
}
}
/// ***************************************************************************************
void CPSLocated : : updateCollisions ( )
{
NL_PS_FUNC ( CPSLocated_updateCollisions )
CPSCollisionInfo * currCollision = _FirstCollision ;
if ( getLastForever ( ) )
{
while ( currCollision )
{
_Pos [ currCollision - > Index ] = currCollision - > NewPos ;
std : : swap ( _Speed [ currCollision - > Index ] , currCollision - > NewSpeed ) ; // keep speed because may be needed when removing particles
// notify each located bindable that a bounce occured ...
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > bounceOccured ( currCollision - > Index , computeDateFromCollisionToNextSimStep ( currCollision - > Index , getAgeInSeconds ( currCollision - > Index ) ) ) ;
}
if ( currCollision - > CollisionZone - > getCollisionBehaviour ( ) = = CPSZone : : destroy )
{
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleRemoveListIndex [ currCollision - > Index ] = = - 1 ) ;
# endif
CParticleSystem : : _ParticleToRemove . push_back ( currCollision - > Index ) ;
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleToRemove . size ( ) < = _Size ) ;
# endif
CParticleSystem : : _ParticleRemoveListIndex [ currCollision - > Index ] = ( sint ) CParticleSystem : : _ParticleToRemove . size ( ) - 1 ;
}
currCollision = currCollision - > Next ;
}
}
else
{
while ( currCollision )
{
if ( _Time [ currCollision - > Index ] > = 1.f )
{
// check whether particles died before the collision. If so, just continue (particle has already been inserted in the remove list), and cancel the collision
float timeToCollision = currCollision - > Dist / _Speed [ currCollision - > Index ] . norm ( ) ;
if ( _Time [ currCollision - > Index ] / _TimeIncrement [ currCollision - > Index ] - timeToCollision * CParticleSystem : : RealEllapsedTimeRatio > = 1.f )
{
// says that collision did not occurs
currCollision - > Dist = - 1.f ;
currCollision = currCollision - > Next ;
continue ;
}
}
// if particle is too old, check whether it died before the collision
_Pos [ currCollision - > Index ] = currCollision - > NewPos ;
std : : swap ( _Speed [ currCollision - > Index ] , currCollision - > NewSpeed ) ;
// notify each located bindable that a bounce occured ...
if ( ! _LocatedBoundCont . empty ( ) )
{
TAnimationTime timeFromcollisionToNextSimStep = computeDateFromCollisionToNextSimStep ( currCollision - > Index , getAgeInSeconds ( currCollision - > Index ) ) ;
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > bounceOccured ( currCollision - > Index , timeFromcollisionToNextSimStep ) ;
}
}
if ( currCollision - > CollisionZone - > getCollisionBehaviour ( ) = = CPSZone : : destroy )
{
if ( _Time [ currCollision - > Index ] < 1.f )
{
// insert particle only if not already dead
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleRemoveListIndex [ currCollision - > Index ] = = - 1 ) ;
# endif
CParticleSystem : : _ParticleToRemove . push_back ( currCollision - > Index ) ;
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleToRemove . size ( ) < = _Size ) ;
# endif
CParticleSystem : : _ParticleRemoveListIndex [ currCollision - > Index ] = ( sint ) CParticleSystem : : _ParticleToRemove . size ( ) - 1 ;
}
}
currCollision = currCollision - > Next ;
}
}
}
/// ***************************************************************************************
void CPSLocated : : doLODDegradation ( )
{
NL_PS_FUNC ( CPSLocated_doLODDegradation )
nlassert ( CParticleSystem : : InsideSimLoop ) ;
nlassert ( ! CParticleSystem : : InsideRemoveLoop ) ;
CParticleSystem : : InsideRemoveLoop = true ;
if ( CParticleSystem : : EllapsedTime > 0 )
{
nlassert ( _Owner ) ;
// compute the number of particles to show
const uint maxToHave = ( uint ) ( _MaxSize * _Owner - > getOneMinusCurrentLODRatio ( ) ) ;
if ( _Size > maxToHave ) // too much instances ?
{
// choose a random element to start at, and a random step
// this will avoid a pulse effect when the system is far away
uint pos = maxToHave ? rand ( ) % maxToHave : 0 ;
uint step = maxToHave ? rand ( ) % maxToHave : 0 ;
do
{
deleteElement ( pos ) ;
pos + = step ;
if ( pos > = maxToHave ) pos - = maxToHave ;
}
while ( _Size ! = maxToHave ) ;
}
}
CParticleSystem : : InsideRemoveLoop = false ;
}
/// ***************************************************************************************
void CPSLocated : : step ( TPSProcessPass pass )
{
NL_PS_FUNC ( CPSLocated_step )
CHECK_PS_INTEGRITY
if ( ! _Size ) return ;
if ( pass ! = PSMotion )
{
{
/*
uint64 * target ;
switch ( pass )
{
case PSEmit : target = & PSStatEmit ; break ;
case PSCollision : target = & PSStatCollision ; break ;
default :
target = & PSStatRender ;
break ;
}
MINI_TIMER ( * target )
*/
// apply the pass to all bound objects
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
if ( ( * it ) - > isActive ( ) )
{
if ( ( * it ) - > getLOD ( ) = = PSLod1n2 | | _Owner - > getLOD ( ) = = ( * it ) - > getLOD ( ) ) // has this object the right LOD ?
{
( * it ) - > step ( pass ) ;
}
}
}
}
}
else
{
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
if ( ( * it ) - > isActive ( ) )
{
( * it ) - > step ( pass ) ;
}
}
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : updateLife ( )
{
NL_PS_FUNC ( CPSLocated_updateLife )
CHECK_PS_INTEGRITY
if ( ! _Size ) return ;
if ( ! _LastForever )
{
if ( _LifeScheme ! = NULL )
{
TPSAttribTime : : iterator itTime = _Time . begin ( ) , itTimeInc = _TimeIncrement . begin ( ) ;
for ( uint32 k = 0 ; k < _Size ; + + k )
{
* itTime + = CParticleSystem : : RealEllapsedTime * * itTimeInc ;
if ( * itTime > = 1.0f )
{
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleRemoveListIndex [ k ] = = - 1 ) ;
# endif
CParticleSystem : : _ParticleToRemove . push_back ( k ) ;
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleToRemove . size ( ) < = _Size ) ;
# endif
CParticleSystem : : _ParticleRemoveListIndex [ k ] = ( sint ) CParticleSystem : : _ParticleToRemove . size ( ) - 1 ;
}
+ + itTime ;
+ + itTimeInc ;
}
}
else /// all particles have the same lifetime
{
if ( _InitialLife ! = 0 )
{
nlassert ( _Owner ) ;
float timeInc = CParticleSystem : : RealEllapsedTime / _InitialLife ;
if ( _Owner - > getSystemDate ( ) + 0.1f + 2.f * timeInc > = ( _InitialLife - CParticleSystem : : RealEllapsedTime ) )
{
// NB : 0.1f + 2.f * timeInc added to avoid case were time of particle is slighty greater than 1.f after life update because that test failed
TPSAttribTime : : iterator itTime = _Time . begin ( ) ;
for ( uint32 k = 0 ; k < _Size ; + + k )
{
* itTime + = timeInc ;
if ( * itTime > = 1.0f )
{
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleRemoveListIndex [ k ] = = - 1 ) ;
# endif
CParticleSystem : : _ParticleToRemove . push_back ( k ) ;
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleToRemove . size ( ) < = _Size ) ;
# endif
CParticleSystem : : _ParticleRemoveListIndex [ k ] = ( sint ) CParticleSystem : : _ParticleToRemove . size ( ) - 1 ;
}
+ + itTime ;
}
}
else
{
// system has not lasted enough for any particle to die
TPSAttribTime : : iterator itTime = _Time . begin ( ) , itEndTime = _Time . end ( ) ;
do
{
* itTime + = timeInc ;
+ + itTime ;
}
while ( itTime ! = itEndTime ) ;
}
}
else
{
for ( uint k = 0 ; k < _Size ; + + k )
{
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleRemoveListIndex [ k ] = = - 1 ) ;
# endif
CParticleSystem : : _ParticleToRemove . push_back ( k ) ;
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleToRemove . size ( ) < = _Size ) ;
# endif
CParticleSystem : : _ParticleRemoveListIndex [ k ] = ( sint ) CParticleSystem : : _ParticleToRemove . size ( ) - 1 ;
}
}
}
}
else
{
// the time attribute gives the life in seconds
TPSAttribTime : : iterator itTime = _Time . begin ( ) , endItTime = _Time . end ( ) ;
for ( ; itTime ! = endItTime ; + + itTime )
{
* itTime + = CParticleSystem : : RealEllapsedTime ;
}
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
// When a particle is deleted, it is replaced by the last particle in the array
// if this particle is to be deleted to, must update its new index
static inline void removeParticleFromRemoveList ( uint indexToRemove , uint arraySize )
{
NL_PS_FUNC ( removeParticleFromRemoveList )
if ( indexToRemove ! = arraySize )
{
if ( CParticleSystem : : _ParticleRemoveListIndex [ arraySize ] ! = - 1 )
{
// when a particle is deleted, it is replaced by the last particle in the array
// if this particle is to be deleted too, must update its new index (becomes the index of the particle that has just been deleted)
CParticleSystem : : _ParticleToRemove [ CParticleSystem : : _ParticleRemoveListIndex [ arraySize ] ] = indexToRemove ;
CParticleSystem : : _ParticleRemoveListIndex [ indexToRemove ] = CParticleSystem : : _ParticleRemoveListIndex [ arraySize ] ;
CParticleSystem : : _ParticleRemoveListIndex [ arraySize ] = - 1 ; // not to remove any more
}
else
{
CParticleSystem : : _ParticleRemoveListIndex [ indexToRemove ] = - 1 ;
}
}
else
{
CParticleSystem : : _ParticleRemoveListIndex [ arraySize ] = - 1 ;
}
}
void checkRemoveArray ( uint size )
{
NL_PS_FUNC ( checkRemoveArray )
for ( uint k = 0 ; k < size ; + + k )
{
if ( CParticleSystem : : _ParticleRemoveListIndex [ k ] ! = - 1 )
{
nlassert ( std : : find ( CParticleSystem : : _ParticleRemoveListIndex . begin ( ) , CParticleSystem : : _ParticleRemoveListIndex . end ( ) , CParticleSystem : : _ParticleRemoveListIndex [ k ] ) ! = CParticleSystem : : _ParticleRemoveListIndex . end ( ) ) ;
}
}
for ( uint k = 0 ; k < CParticleSystem : : _ParticleToRemove . size ( ) ; + + k )
{
nlassert ( CParticleSystem : : _ParticleRemoveListIndex [ CParticleSystem : : _ParticleToRemove [ k ] ] = = ( sint ) k ) ;
}
}
/// ***************************************************************************************
# ifndef NL_DEBUG
inline
# endif
TAnimationTime CPSLocated : : computeDateFromCollisionToNextSimStep ( uint particleIndex , float particleAgeInSeconds )
{
NL_PS_FUNC ( CPSLocated_computeDateFromCollisionToNextSimStep )
// compute time from the start of the sim step to the birth of the particle (or 0 if already born)
float ageAtStart = CParticleSystem : : RealEllapsedTime > particleAgeInSeconds ? CParticleSystem : : RealEllapsedTime - particleAgeInSeconds : 0.f ;
ageAtStart / = CParticleSystem : : RealEllapsedTimeRatio ;
// compute time to collision. The 'NewSpeed' field is swapped with speed of particle at the sim step start when 'updateCollision' is called, and thus contains the old speed.
float norm = _Collisions [ particleIndex ] . NewSpeed . norm ( ) ;
if ( norm = = 0.f ) return 0.f ;
float timeToCollision = _Collisions [ particleIndex ] . Dist / norm ;
// So time from collision to end of sim step is :
TAnimationTime result = CParticleSystem : : EllapsedTime - ageAtStart - timeToCollision ;
return std : : max ( 0.f , result ) ;
}
/// ***************************************************************************************
void CPSLocated : : removeOldParticles ( )
{
NL_PS_FUNC ( CPSLocated_removeOldParticles )
nlassert ( CParticleSystem : : RealEllapsedTime > 0.f ) ;
# ifdef NL_DEBUG
CParticleSystem : : InsideRemoveLoop = true ;
checkRemoveArray ( _Size ) ;
# endif
// remove all elements that were marked as too old
// if there are emitters marked as 'on' death, should correct position by moving backward (because motion is done on a whole time step, so particle is further than it should be)
if ( getLastForever ( ) )
{
// if the particle lasts for ever it can be destroyed only if it touch a collision zone flaged as 'destroy'
// during the call to 'updateCollisions', the list of particles to remove will be updated so just test it
if ( hasCollisionInfos ( ) )
{
for ( std : : vector < uint > : : iterator it = CParticleSystem : : _ParticleToRemove . begin ( ) ; it ! = CParticleSystem : : _ParticleToRemove . end ( ) ; + + it )
{
if ( _Collisions [ * it ] . Dist ! = - 1.f )
{
deleteElement ( * it , computeDateFromCollisionToNextSimStep ( * it , _Time [ * it ] ) ) ;
}
else
{
deleteElement ( * it ) ;
}
removeParticleFromRemoveList ( * it , _Size ) ;
}
}
}
else
if ( hasCollisionInfos ( ) ) // particle has collision, and limited lifetime
{
float ellapsedTimeRatio = CParticleSystem : : EllapsedTime / CParticleSystem : : RealEllapsedTime ;
for ( std : : vector < uint > : : iterator it = CParticleSystem : : _ParticleToRemove . begin ( ) ; it ! = CParticleSystem : : _ParticleToRemove . end ( ) ; + + it )
{
TAnimationTime timeUntilNextSimStep ;
if ( _Collisions [ * it ] . Dist = = - 1.f )
{
// no collision occured
if ( _Time [ * it ] > 1.f )
{
if ( _LifeScheme )
{
_Pos [ * it ] - = _Speed [ * it ] * ( ( _Time [ * it ] - 1.f ) / _TimeIncrement [ * it ] ) * ellapsedTimeRatio ;
timeUntilNextSimStep = ( _Time [ * it ] - 1.f ) / _TimeIncrement [ * it ] ;
}
else
{
_Pos [ * it ] - = _Speed [ * it ] * ( ( _Time [ * it ] - 1.f ) * _InitialLife ) * ellapsedTimeRatio ;
timeUntilNextSimStep = ( _Time [ * it ] - 1.f ) * _InitialLife ;
}
_Time [ * it ] = 0.9999f ;
}
else
{
timeUntilNextSimStep = 0.f ;
}
}
else
{
// a collision occured before particle died, so pos is already good
if ( _LifeScheme )
{
timeUntilNextSimStep = computeDateFromCollisionToNextSimStep ( * it , _Time [ * it ] / _TimeIncrement [ * it ] ) ;
// compute age of particle when collision occured
_Time [ * it ] - = timeUntilNextSimStep * _TimeIncrement [ * it ] ;
NLMISC : : clamp ( _Time [ * it ] , 0.f , 1.f ) ; // avoid imprecisions
}
else
{
timeUntilNextSimStep = computeDateFromCollisionToNextSimStep ( * it , _Time [ * it ] * _InitialLife ) ;
// compute age of particle when collision occured
_Time [ * it ] - = timeUntilNextSimStep / ( _InitialLife = = 0.f ? 1.f : _InitialLife ) ;
NLMISC : : clamp ( _Time [ * it ] , 0.f , 1.f ) ; // avoid imprecisions
}
}
deleteElement ( * it , timeUntilNextSimStep ) ;
removeParticleFromRemoveList ( * it , _Size ) ;
}
}
else // particle has no collisions, and limited lifetime
{
float ellapsedTimeRatio = CParticleSystem : : EllapsedTime / CParticleSystem : : RealEllapsedTime ;
if ( ! isParametricMotionEnabled ( ) )
{
if ( _LifeScheme )
{
for ( std : : vector < uint > : : iterator it = CParticleSystem : : _ParticleToRemove . begin ( ) ; it ! = CParticleSystem : : _ParticleToRemove . end ( ) ; + + it )
{
# ifdef NL_DEBUG
for ( std : : vector < uint > : : iterator it2 = it ; it2 ! = CParticleSystem : : _ParticleToRemove . end ( ) ; + + it2 )
{
nlassert ( * it2 < _Size ) ;
}
# endif
TAnimationTime timeUntilNextSimStep ;
if ( _Time [ * it ] > 1.f )
{
// move position backward (compute its position at death)
timeUntilNextSimStep = ( ( _Time [ * it ] - 1.f ) / _TimeIncrement [ * it ] ) * ellapsedTimeRatio ;
_Pos [ * it ] - = _Speed [ * it ] * timeUntilNextSimStep ;
// force time to 1 because emitter 'on death' may rely on the date of emitter to compute its attributes
_Time [ * it ] = 0.9999f ;
}
else
{
timeUntilNextSimStep = 0.f ;
}
deleteElement ( * it , timeUntilNextSimStep ) ;
removeParticleFromRemoveList ( * it , _Size ) ;
# ifdef NL_DEBUG
for ( std : : vector < uint > : : iterator it2 = it + 1 ; it2 ! = CParticleSystem : : _ParticleToRemove . end ( ) ; + + it2 )
{
nlassert ( * it2 < _Size ) ;
}
# endif
}
}
else
{
for ( std : : vector < uint > : : iterator it = CParticleSystem : : _ParticleToRemove . begin ( ) ; it ! = CParticleSystem : : _ParticleToRemove . end ( ) ; + + it )
{
TAnimationTime timeUntilNextSimStep ;
if ( _Time [ * it ] > 1.f )
{
// move position backward
timeUntilNextSimStep = ( _Time [ * it ] - 1.f ) * _InitialLife * ellapsedTimeRatio ;
_Pos [ * it ] - = _Speed [ * it ] * timeUntilNextSimStep ;
// force time to 1 because emitter 'on death' may rely on the date of emitter to compute its attributes
_Time [ * it ] = 0.9999f ;
}
else
{
timeUntilNextSimStep = 0.f ;
}
deleteElement ( * it , timeUntilNextSimStep ) ;
removeParticleFromRemoveList ( * it , _Size ) ;
}
}
}
else
{
// parametric case
if ( _LifeScheme )
{
for ( std : : vector < uint > : : iterator it = CParticleSystem : : _ParticleToRemove . begin ( ) ; it ! = CParticleSystem : : _ParticleToRemove . end ( ) ; + + it )
{
TAnimationTime timeUntilNextSimStep ;
if ( _Time [ * it ] > 1.f )
{
// move position backward (compute its position at death)
timeUntilNextSimStep = ( _Time [ * it ] - 1.f ) / _TimeIncrement [ * it ] ;
computeParametricPos ( _Owner - > getSystemDate ( ) + CParticleSystem : : RealEllapsedTime - timeUntilNextSimStep , * it , _Pos [ * it ] ) ;
timeUntilNextSimStep * = ellapsedTimeRatio ;
// force time to 1 because emitter 'on death' may rely on the date of emitter to compute its attributes
_Time [ * it ] = 0.9999f ;
}
else
{
timeUntilNextSimStep = 0.f ;
}
deleteElement ( * it , timeUntilNextSimStep ) ;
removeParticleFromRemoveList ( * it , _Size ) ;
}
}
else
{
for ( std : : vector < uint > : : iterator it = CParticleSystem : : _ParticleToRemove . begin ( ) ; it ! = CParticleSystem : : _ParticleToRemove . end ( ) ; + + it )
{
TAnimationTime timeUntilNextSimStep ;
if ( _Time [ * it ] > 1.f )
{
// move position backward
timeUntilNextSimStep = ( _Time [ * it ] - 1.f ) * _InitialLife ;
computeParametricPos ( _Owner - > getSystemDate ( ) + CParticleSystem : : RealEllapsedTime - timeUntilNextSimStep , * it , _Pos [ * it ] ) ;
timeUntilNextSimStep * = ellapsedTimeRatio ;
// force time to 1 because emitter 'on death' may rely on the date of emitter to compute its attributes
_Time [ * it ] = 0.9999f ;
}
else
{
timeUntilNextSimStep = 0.f ;
}
deleteElement ( * it , timeUntilNextSimStep ) ;
removeParticleFromRemoveList ( * it , _Size ) ;
}
}
}
}
# ifdef NL_DEBUG
CParticleSystem : : InsideRemoveLoop = false ;
# endif
CParticleSystem : : _ParticleToRemove . clear ( ) ;
# ifdef NL_DEBUG
if ( ! _LastForever )
{
for ( uint k = 0 ; k < _Size ; + + k )
{
nlassert ( _Time [ k ] > = 0.f & & _Time [ k ] < = 1.f ) ;
}
}
# endif
}
/// ***************************************************************************************
void CPSLocated : : addNewlySpawnedParticles ( )
{
NL_PS_FUNC ( CPSLocated_addNewlySpawnedParticles )
# ifdef NL_DEBUG
CParticleSystem : : InsideNewElementsLoop = true ;
# endif
CParticleSystem : : CSpawnVect & spawns = * CParticleSystem : : _Spawns [ getIndex ( ) ] ;
if ( spawns . SpawnInfos . empty ( ) ) return ;
uint numSpawns = 0 ;
if ( ! _Owner - > getAutoCountFlag ( ) )
{
CParticleSystem : : _SpawnPos . resize ( getMaxSize ( ) ) ;
numSpawns = std : : min ( ( uint ) ( _MaxSize - _Size ) , ( uint ) spawns . SpawnInfos . size ( ) ) ;
}
else
{
numSpawns = ( uint ) spawns . SpawnInfos . size ( ) ;
}
CParticleSystem : : TSpawnInfoVect : : const_iterator endIt = spawns . SpawnInfos . begin ( ) + numSpawns ;
if ( _LastForever )
{
for ( CParticleSystem : : TSpawnInfoVect : : const_iterator it = spawns . SpawnInfos . begin ( ) ; it ! = endIt ; + + it )
{
// sint32 insertionIndex =
newElement ( * it , false , CParticleSystem : : EllapsedTime ) ;
}
}
else
{
// to avoid warning in autocount mode
//CParticleSystem::InsideSimLoop = false;
for ( CParticleSystem : : TSpawnInfoVect : : const_iterator it = spawns . SpawnInfos . begin ( ) ; it ! = endIt ; + + it )
{
sint32 insertionIndex = newElement ( * it , false , CParticleSystem : : EllapsedTime ) ;
# ifdef NL_DEBUG
nlassert ( insertionIndex ! = - 1 ) ;
# endif
if ( _Time [ insertionIndex ] > = 1.f )
{
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleRemoveListIndex [ insertionIndex ] = = - 1 ) ;
# endif
CParticleSystem : : _ParticleToRemove . push_back ( insertionIndex ) ;
# ifdef NL_DEBUG
nlassert ( CParticleSystem : : _ParticleToRemove . size ( ) < = _Size ) ;
# endif
CParticleSystem : : _ParticleRemoveListIndex [ insertionIndex ] = ( sint ) CParticleSystem : : _ParticleToRemove . size ( ) - 1 ;
}
}
//CParticleSystem::InsideSimLoop = true;
}
spawns . SpawnInfos . clear ( ) ;
# ifdef NL_DEBUG
CParticleSystem : : InsideNewElementsLoop = false ;
# endif
}
/// ***************************************************************************************
bool CPSLocated : : computeBBox ( NLMISC : : CAABBox & box ) const
{
NL_PS_FUNC ( CPSLocated_computeBBox )
CHECK_PS_INTEGRITY
if ( ! _Size ) return false ; // something to compute ?
TLocatedBoundCont : : const_iterator it ;
TPSAttribVector : : const_iterator it2 ;
// check whether any object bound to us need a bbox
for ( it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
if ( ( * it ) - > doesProduceBBox ( ) )
{
break ;
}
}
if ( it = = _LocatedBoundCont . end ( ) )
{
return false ;
}
CVector min = _Pos [ 0 ] , max = _Pos [ 0 ] ;
for ( it2 = _Pos . begin ( ) ; it2 ! = _Pos . end ( ) ; + + it2 )
{
const CVector & v = ( * it2 ) ;
min . minof ( min , v ) ;
max . maxof ( max , v ) ;
}
box . setMinMax ( min , max ) ;
// we've considered that located had no extent in space
// now, we must call each objects that are bound to the located in order
// to complete the bbox if they have no null extent
NLMISC : : CAABBox tmpBox , startBox = box ;
for ( it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
if ( ( * it ) - > doesProduceBBox ( ) )
{
tmpBox = startBox ;
if ( ( * it ) - > completeBBox ( tmpBox ) )
{
box = NLMISC : : CAABBox : : computeAABBoxUnion ( tmpBox , box ) ;
}
}
}
CHECK_PS_INTEGRITY
return true ;
}
/// Setup the driver model matrix. It is set accordingly to the basis used for rendering
/// ***************************************************************************************
void CPSLocated : : setupDriverModelMatrix ( void )
{
NL_PS_FUNC ( CPSLocated_setupDriverModelMatrix )
CHECK_PS_INTEGRITY
getDriver ( ) - > setupModelMatrix ( getLocalToWorldMatrix ( ) ) ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : queryCollisionInfo ( void )
{
NL_PS_FUNC ( CPSLocated_queryCollisionInfo )
CHECK_PS_INTEGRITY
if ( _CollisionInfoNbRef )
{
+ + _CollisionInfoNbRef ;
}
else
{
_CollisionNextPos = new TPSAttribVector ;
_CollisionInfoNbRef = 1 ;
_CollisionNextPos - > resize ( _MaxSize ) ;
for ( uint k = 0 ; k < _Size ; + + k )
{
_CollisionNextPos - > insert ( ) ;
}
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : releaseCollisionInfo ( void )
{
NL_PS_FUNC ( CPSLocated_releaseCollisionInfo )
CHECK_PS_INTEGRITY
nlassert ( _CollisionInfoNbRef ) ; // check whether queryCollisionInfo was called
// so the number of refs must not = 0
- - _CollisionInfoNbRef ;
if ( _CollisionInfoNbRef = = 0 )
{
delete _CollisionNextPos ;
_CollisionNextPos = NULL ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : registerIntegrableForce ( CPSForce * f )
{
NL_PS_FUNC ( CPSLocated_registerIntegrableForce )
CHECK_PS_INTEGRITY
nlassert ( std : : find ( _IntegrableForces . begin ( ) , _IntegrableForces . end ( ) , f ) = = _IntegrableForces . end ( ) ) ; // force registered twice
_IntegrableForces . push_back ( f ) ;
if ( getMatrixMode ( ) ! = f - > getOwner ( ) - > getMatrixMode ( ) )
{
+ + _NumIntegrableForceWithDifferentBasis ;
releaseParametricInfos ( ) ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : unregisterIntegrableForce ( CPSForce * f )
{
NL_PS_FUNC ( CPSLocated_unregisterIntegrableForce )
CHECK_PS_INTEGRITY
nlassert ( f - > getOwner ( ) ) ; // f must be attached to a located
CPSVector < CPSForce * > : : V : : iterator it = std : : find ( _IntegrableForces . begin ( ) , _IntegrableForces . end ( ) , f ) ;
nlassert ( it ! = _IntegrableForces . end ( ) ) ;
_IntegrableForces . erase ( it ) ;
if ( getMatrixMode ( ) ! = f - > getOwner ( ) - > getMatrixMode ( ) )
{
- - _NumIntegrableForceWithDifferentBasis ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : addNonIntegrableForceRef ( void )
{
NL_PS_FUNC ( CPSLocated_addNonIntegrableForceRef )
CHECK_PS_INTEGRITY
+ + _NonIntegrableForceNbRefs ;
releaseParametricInfos ( ) ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : releaseNonIntegrableForceRef ( void )
{
NL_PS_FUNC ( CPSLocated_releaseNonIntegrableForceRef )
CHECK_PS_INTEGRITY
nlassert ( _NonIntegrableForceNbRefs ! = 0 ) ;
- - _NonIntegrableForceNbRefs ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
void CPSLocated : : integrableForceBasisChanged ( TPSMatrixMode matrixMode )
{
NL_PS_FUNC ( CPSLocated_integrableForceBasisChanged )
CHECK_PS_INTEGRITY
if ( getMatrixMode ( ) ! = matrixMode )
{
+ + _NumIntegrableForceWithDifferentBasis ;
releaseParametricInfos ( ) ;
}
else
{
- - _NumIntegrableForceWithDifferentBasis ;
}
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
CPSLocatedBindable * CPSLocated : : unbind ( uint index )
{
NL_PS_FUNC ( CPSLocated_unbind )
CHECK_PS_INTEGRITY
nlassert ( index < _LocatedBoundCont . size ( ) ) ;
CPSLocatedBindable * lb = _LocatedBoundCont [ index ] ;
lb - > setOwner ( NULL ) ;
_LocatedBoundCont . erase ( _LocatedBoundCont . begin ( ) + index ) ;
return lb ;
CHECK_PS_INTEGRITY
}
/// ***************************************************************************************
bool CPSLocated : : isBound ( const CPSLocatedBindable * lb ) const
{
NL_PS_FUNC ( CPSLocated_isBound )
CHECK_PS_INTEGRITY
TLocatedBoundCont : : const_iterator it = std : : find ( _LocatedBoundCont . begin ( ) , _LocatedBoundCont . end ( ) , lb ) ;
return it ! = _LocatedBoundCont . end ( ) ;
}
/// ***************************************************************************************
uint CPSLocated : : getIndexOf ( const CPSLocatedBindable * lb ) const
{
NL_PS_FUNC ( CPSLocated_getIndexOf )
CHECK_PS_INTEGRITY
for ( uint k = 0 ; k < _LocatedBoundCont . size ( ) ; + + k )
{
if ( _LocatedBoundCont [ k ] = = lb ) return k ;
}
nlassert ( 0 ) ;
return 0 ;
}
///////////////////////////////////////
// CPSLocatedBindable implementation //
///////////////////////////////////////
/// ***************************************************************************************
CPSLocatedBindable : : CPSLocatedBindable ( ) : _Owner ( NULL ) , _ExternID ( 0 ) , _LOD ( PSLod1n2 ) , _Active ( true )
{
NL_PS_FUNC ( CPSLocatedBindable_CPSLocatedBindable )
_Owner = NULL ;
}
/// ***************************************************************************************
void CPSLocatedBindable : : setOwner ( CPSLocated * psl )
{
NL_PS_FUNC ( CPSLocatedBindable_setOwner )
if ( psl = = _Owner ) return ;
if ( psl = = NULL )
{
releaseAllRef ( ) ;
if ( _Owner )
{
// empty this located bindable. Need to be empty if it must be rebound to another located.
for ( uint k = 0 ; k < _Owner - > getSize ( ) ; + + k )
{
deleteElement ( 0 ) ;
}
}
}
if ( _Owner & & _Owner - > getOwner ( ) )
{
_Owner - > getOwner ( ) - > releaseRefForUserSysCoordInfo ( getUserMatrixUsageCount ( ) ) ;
}
_Owner = psl ;
if ( _Owner & & _Owner - > getOwner ( ) )
{
_Owner - > getOwner ( ) - > addRefForUserSysCoordInfo ( getUserMatrixUsageCount ( ) ) ;
}
}
/// ***************************************************************************************
void CPSLocatedBindable : : finalize ( void )
{
NL_PS_FUNC ( CPSLocatedBindable_finalize )
if ( _Owner & & _Owner - > getOwner ( ) )
{
_Owner - > getOwner ( ) - > releaseRefForUserSysCoordInfo ( getUserMatrixUsageCount ( ) ) ;
}
}
/// ***************************************************************************************
CPSLocatedBindable : : ~ CPSLocatedBindable ( )
{
NL_PS_FUNC ( CPSLocatedBindable_CPSLocatedBindableDtor )
if ( _ExternID )
{
if ( _Owner & & _Owner - > getOwner ( ) )
{
_Owner - > getOwner ( ) - > unregisterLocatedBindableExternID ( this ) ;
}
}
}
/// ***************************************************************************************
void CPSLocatedBindable : : notifyTargetRemoved ( CPSLocated * ptr )
{
NL_PS_FUNC ( CPSLocatedBindable_notifyTargetRemoved )
ptr - > unregisterDtorObserver ( this ) ;
}
/// ***************************************************************************************
void CPSLocatedBindable : : serial ( NLMISC : : IStream & f ) throw ( NLMISC : : EStream )
{
NL_PS_FUNC ( CPSLocatedBindable_IStream )
sint ver = f . serialVersion ( 4 ) ;
f . serialPtr ( _Owner ) ;
if ( ver > 1 ) f . serialEnum ( _LOD ) ;
if ( ver > 2 )
{
if ( f . isReading ( ) & & ! CParticleSystem : : getSerializeIdentifierFlag ( ) )
{
// just skip the name
sint32 len ;
f . serial ( len ) ;
f . seek ( len , NLMISC : : IStream : : current ) ;
}
else
{
f . serial ( _Name ) ;
}
}
if ( ver > 3 )
{
if ( f . isReading ( ) )
{
uint32 id ;
f . serial ( id ) ;
setExternID ( id ) ;
}
else
{
f . serial ( _ExternID ) ;
}
}
}
/// ***************************************************************************************
void CPSLocatedBindable : : displayIcon2d ( const CVector tab [ ] , uint nbSegs , float scale )
{
NL_PS_FUNC ( CPSLocatedBindable_displayIcon2d )
uint32 size = _Owner - > getSize ( ) ;
if ( ! size ) return ;
setupDriverModelMatrix ( ) ;
const CVector I = computeI ( ) ;
const CVector K = computeK ( ) ;
static std : : vector < NLMISC : : CLine > lines ;
lines . clear ( ) ;
// ugly slow code, but not for runtime
for ( uint k = 0 ; k < size ; + + k )
{
// center of the current particle
const CVector p = _Owner - > getPos ( ) [ k ] ;
for ( uint l = 0 ; l < nbSegs ; + + l )
{
NLMISC : : CLine li ;
li . V0 = p + scale * ( tab [ l < < 1 ] . x * I + tab [ l < < 1 ] . y * K ) ;
li . V1 = p + scale * ( tab [ ( l < < 1 ) + 1 ] . x * I + tab [ ( l < < 1 ) + 1 ] . y * K ) ;
lines . push_back ( li ) ;
}
CMaterial mat ;
mat . setBlendFunc ( CMaterial : : one , CMaterial : : one ) ;
mat . setZWrite ( false ) ;
mat . setLighting ( false ) ;
mat . setBlend ( true ) ;
mat . setZFunc ( CMaterial : : less ) ;
CPSLocated * loc ;
uint32 index ;
CPSLocatedBindable * lb ;
_Owner - > getOwner ( ) - > getCurrentEditedElement ( loc , index , lb ) ;
mat . setColor ( ( lb = = NULL | | this = = lb ) & & loc = = _Owner & & index = = k ? CRGBA : : Red : CRGBA ( 127 , 127 , 127 ) ) ;
CDRU : : drawLinesUnlit ( lines , mat , * getDriver ( ) ) ;
}
}
/// ***************************************************************************************
CFontManager * CPSLocatedBindable : : getFontManager ( void )
{
NL_PS_FUNC ( CPSLocatedBindable_getFontManager )
nlassert ( _Owner ) ;
return _Owner - > getFontManager ( ) ;
}
/// ***************************************************************************************
/// Shortcut to get the font manager if one was set (const version)
const CFontManager * CPSLocatedBindable : : getFontManager ( void ) const
{
NL_PS_FUNC ( CPSLocatedBindable_getFontManager )
nlassert ( _Owner ) ;
return _Owner - > getFontManager ( ) ;
}
/// ***************************************************************************************
// Shortcut to get the matrix of the system
const NLMISC : : CMatrix & CPSLocatedBindable : : getSysMat ( void ) const
{
NL_PS_FUNC ( CPSLocatedBindable_getSysMat )
nlassert ( _Owner ) ;
return _Owner - > getOwner ( ) - > getSysMat ( ) ;
}
/// ***************************************************************************************
/// shortcut to get the inverted matrix of the system
const NLMISC : : CMatrix & CPSLocatedBindable : : getInvertedSysMat ( void ) const
{
NL_PS_FUNC ( CPSLocatedBindable_getInvertedSysMat )
nlassert ( _Owner ) ;
return _Owner - > getOwner ( ) - > getInvertedSysMat ( ) ;
}
/// ***************************************************************************************
/// shortcut to get the view matrix
const NLMISC : : CMatrix & CPSLocatedBindable : : getViewMat ( void ) const
{
NL_PS_FUNC ( CPSLocatedBindable_getViewMat )
nlassert ( _Owner ) ;
return _Owner - > getOwner ( ) - > getViewMat ( ) ;
}
/// ***************************************************************************************
/// shortcut to get the inverted view matrix
const NLMISC : : CMatrix & CPSLocatedBindable : : getInvertedViewMat ( void ) const
{
NL_PS_FUNC ( CPSLocatedBindable_getInvertedViewMat )
nlassert ( _Owner ) ;
return _Owner - > getOwner ( ) - > getInvertedViewMat ( ) ;
}
/// ***************************************************************************************
/// shortcut to setup the model matrix (system basis or world basis)
void CPSLocatedBindable : : setupDriverModelMatrix ( void )
{
NL_PS_FUNC ( CPSLocatedBindable_setupDriverModelMatrix )
nlassert ( _Owner ) ;
_Owner - > setupDriverModelMatrix ( ) ;
}
/// ***************************************************************************************
void CPSLocatedBindable : : setExternID ( uint32 id )
{
NL_PS_FUNC ( CPSLocatedBindable_setExternID )
if ( id = = _ExternID ) return ;
CParticleSystem * ps = NULL ;
if ( _Owner & & _Owner - > getOwner ( ) )
{
ps = _Owner - > getOwner ( ) ;
}
if ( ps )
{
ps - > unregisterLocatedBindableExternID ( this ) ;
_ExternID = 0 ;
}
if ( id ! = 0 )
{
if ( ps ) ps - > registerLocatedBindableExternID ( id , this ) ;
_ExternID = id ;
}
}
/// ***************************************************************************************
void CPSLocatedBindable : : releaseAllRef ( )
{
NL_PS_FUNC ( CPSLocatedBindable_releaseAllRef )
}
/////////////////////////////////////////////
// CPSTargetLocatedBindable implementation //
/////////////////////////////////////////////
/// ***************************************************************************************
void CPSTargetLocatedBindable : : serial ( NLMISC : : IStream & f ) throw ( NLMISC : : EStream )
{
NL_PS_FUNC ( CPSTargetLocatedBindable_serial )
( void ) f . serialVersion ( 1 ) ;
f . serialPtr ( _Owner ) ;
f . serial ( _Name ) ;
if ( f . isReading ( ) )
{
// delete previous attached bindables...
for ( TTargetCont : : iterator it = _Targets . begin ( ) ; it ! = _Targets . end ( ) ; + + it )
{
delete ( * it ) ;
}
_Targets . clear ( ) ;
}
f . serialContPolyPtr ( _Targets ) ;
}
/// ***************************************************************************************
void CPSTargetLocatedBindable : : attachTarget ( CPSLocated * ptr )
{
NL_PS_FUNC ( CPSTargetLocatedBindable_attachTarget )
// a target can't be shared between different particle systems
# ifdef NL_DEBUG
if ( _Owner )
{
nlassert ( _Owner - > getOwner ( ) = = ptr - > getOwner ( ) ) ;
}
# endif
// see whether this target has not been registered before
nlassert ( std : : find ( _Targets . begin ( ) , _Targets . end ( ) , ptr ) = = _Targets . end ( ) ) ;
_Targets . push_back ( ptr ) ;
// we register us to be notified when the target disappear
ptr - > registerDtorObserver ( this ) ;
}
/// ***************************************************************************************
void CPSTargetLocatedBindable : : notifyTargetRemoved ( CPSLocated * ptr )
{
NL_PS_FUNC ( CPSTargetLocatedBindable_notifyTargetRemoved )
TTargetCont : : iterator it = std : : find ( _Targets . begin ( ) , _Targets . end ( ) , ptr ) ;
nlassert ( it ! = _Targets . end ( ) ) ;
releaseTargetRsc ( * it ) ;
_Targets . erase ( it ) ;
CPSLocatedBindable : : notifyTargetRemoved ( ptr ) ;
}
// dtor
/// ***************************************************************************************
void CPSTargetLocatedBindable : : finalize ( void )
{
NL_PS_FUNC ( CPSTargetLocatedBindable_finalize )
/** Release the collisionInfos we've querried. We can't do it in the dtor, as calls to releaseTargetRsc wouldn't be polymorphics for derived class!
* And the behaviour of releaseTergetRsc is implemented in derived class
*/
for ( TTargetCont : : iterator it = _Targets . begin ( ) ; it ! = _Targets . end ( ) ; + + it )
{
releaseTargetRsc ( * it ) ;
}
CPSLocatedBindable : : finalize ( ) ;
}
/// ***************************************************************************************
CPSTargetLocatedBindable : : ~ CPSTargetLocatedBindable ( )
{
NL_PS_FUNC ( CPSTargetLocatedBindable_CPSTargetLocatedBindable )
// we unregister to all the targets
for ( TTargetCont : : iterator it = _Targets . begin ( ) ; it ! = _Targets . end ( ) ; + + it )
{
( * it ) - > unregisterDtorObserver ( this ) ;
}
}
/// ***************************************************************************************
void CPSTargetLocatedBindable : : releaseRefTo ( const CParticleSystemProcess * other )
{
NL_PS_FUNC ( CPSTargetLocatedBindable_releaseRefTo )
TTargetCont : : iterator it = std : : find ( _Targets . begin ( ) , _Targets . end ( ) , other ) ;
if ( it = = _Targets . end ( ) ) return ;
releaseTargetRsc ( * it ) ;
( * it ) - > unregisterDtorObserver ( this ) ;
_Targets . erase ( it ) ;
nlassert ( std : : find ( _Targets . begin ( ) , _Targets . end ( ) , other ) = = _Targets . end ( ) ) ;
}
/// ***************************************************************************************
void CPSTargetLocatedBindable : : releaseAllRef ( )
{
NL_PS_FUNC ( CPSTargetLocatedBindable_releaseAllRef )
for ( TTargetCont : : iterator it = _Targets . begin ( ) ; it ! = _Targets . end ( ) ; + + it )
{
releaseTargetRsc ( * it ) ;
( * it ) - > unregisterDtorObserver ( this ) ;
}
_Targets . clear ( ) ;
CPSLocatedBindable : : releaseAllRef ( ) ;
}
/// ***************************************************************************************
uint CPSLocated : : getUserMatrixUsageCount ( ) const
{
NL_PS_FUNC ( CPSLocated_getUserMatrixUsageCount )
uint count = 0 ;
for ( TLocatedBoundCont : : const_iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
count + = ( * it ) - > getUserMatrixUsageCount ( ) ;
}
return count + CParticleSystemProcess : : getUserMatrixUsageCount ( ) ;
}
/// ***************************************************************************************
void CPSLocated : : enumTexs ( std : : vector < NLMISC : : CSmartPtr < ITexture > > & dest , IDriver & drv )
{
NL_PS_FUNC ( CPSLocated_enumTexs )
for ( TLocatedBoundCont : : const_iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > enumTexs ( dest , drv ) ;
}
}
/// ***************************************************************************************
void CPSLocated : : setZBias ( float value )
{
NL_PS_FUNC ( CPSLocated_setZBias )
for ( TLocatedBoundCont : : const_iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > setZBias ( value ) ;
}
}
/// ***************************************************************************************
void CPSLocated : : computeCollisions ( uint firstInstanceIndex , const NLMISC : : CVector * posBefore , const NLMISC : : CVector * posAfter )
{
NL_PS_FUNC ( CPSLocated_computeCollisions )
for ( TDtorObserversVect : : iterator it = _DtorObserversVect . begin ( ) ; it ! = _DtorObserversVect . end ( ) ; + + it )
{
if ( ( * it ) - > getType ( ) = = PSZone )
{
static_cast < CPSZone * > ( * it ) - > computeCollisions ( * this , firstInstanceIndex , posBefore , posAfter ) ;
}
}
}
/// ***************************************************************************************
void CPSLocated : : computeSpawns ( uint firstInstanceIndex , bool includeEmitOnce )
{
NL_PS_FUNC ( CPSLocated_computeSpawns )
nlassert ( CParticleSystem : : InsideSimLoop ) ;
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
if ( ! ( * it ) - > isActive ( ) ) continue ;
if ( ( * it ) - > getType ( ) = = PSEmitter )
{
CPSEmitter * emit = static_cast < CPSEmitter * > ( * it ) ;
emit - > updateEmitTrigger ( ) ;
switch ( emit - > getEmissionType ( ) )
{
case CPSEmitter : : regular :
emit - > computeSpawns ( firstInstanceIndex ) ;
break ;
case CPSEmitter : : once :
// if we're at first frame, then do emit for each emitter
nlassert ( _Owner ) ;
if ( _Owner - > getSystemDate ( ) = = 0.f | | includeEmitOnce )
{
// if first pass, then do the emit a single time
// if firstInstanceIndex != 0 then we're dealing with newly created particles, so do the spawn too
emit - > doEmitOnce ( firstInstanceIndex ) ;
}
break ;
default :
break ;
}
}
}
}
/// ***************************************************************************************
void CPSLocated : : computeForces ( )
{
NL_PS_FUNC ( CPSLocated_computeForces )
nlassert ( CParticleSystem : : InsideSimLoop ) ;
for ( TDtorObserversVect : : iterator it = _DtorObserversVect . begin ( ) ; it ! = _DtorObserversVect . end ( ) ; + + it )
{
if ( ( * it ) - > getType ( ) = = PSForce )
{
CPSForce * force = static_cast < CPSForce * > ( * it ) ;
force - > computeForces ( * this ) ;
}
}
}
/// ***************************************************************************************
void CPSCollisionInfo : : update ( const CPSCollisionInfo & other )
{
NL_PS_FUNC ( CPSCollisionInfo_update )
if ( Dist = = - 1 )
{
// link collision in the global list of active collisions
Next = CPSLocated : : _FirstCollision ;
CPSLocated : : _FirstCollision = this ;
Dist = other . Dist ;
NewPos = other . NewPos ;
NewSpeed = other . NewSpeed ;
CollisionZone = other . CollisionZone ;
}
else if ( other . Dist < Dist ) // is the new collision better (e.g it happens sooner) ?
{
Dist = other . Dist ;
NewPos = other . NewPos ;
NewSpeed = other . NewSpeed ;
CollisionZone = other . CollisionZone ;
}
}
/// ***************************************************************************************
void CPSLocated : : checkLife ( ) const
{
NL_PS_FUNC ( CPSLocated_checkLife )
if ( ! getLastForever ( ) )
{
for ( uint k = 0 ; k < getSize ( ) ; + + k )
{
nlassert ( getTime ( ) [ k ] > = 0.f ) ;
nlassert ( getTime ( ) [ k ] < = 1.f ) ;
}
}
}
/// ***************************************************************************************
void CPSLocated : : onShow ( bool shown )
{
for ( TLocatedBoundCont : : iterator it = _LocatedBoundCont . begin ( ) ; it ! = _LocatedBoundCont . end ( ) ; + + it )
{
( * it ) - > onShow ( shown ) ;
}
}
} // NL3D