khanat-opennel-code/code/nel/include/nel/3d/ps_located.h

1072 lines
40 KiB
C++

// 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/>.
#ifndef NL_PARTICLE_SYSTEM_LOCATED_H
#define NL_PARTICLE_SYSTEM_LOCATED_H
#include <stack>
namespace NL3D
{
const uint32 DefaultMaxLocatedInstance = 1; // the default value for a located container
}
#include "nel/misc/types_nl.h"
#include "nel/misc/vector.h"
#include "nel/3d/particle_system_process.h"
#include "nel/3d/ps_attrib.h" // an attribute template container
#include "nel/3d/ps_lod.h"
#include "nel/3d/ps_spawn_info.h"
#include "nel/misc/stream.h"
//
#include "nel/misc/object_arena_allocator.h"
namespace NLMISC
{
class CAABBox;
class CMatrix;
class CVector;
}
namespace NL3D
{
template <class T> class CPSAttribMaker;
class CPSLocatedBindable;
class CPSTargetLocatedBindable;
class CPSZone;
class CPSForce;
class IDriver;
class CFontManager;
class CFontGenerator;
class CScene;
class CParticleSystem;
/// This structure helps to perform the collision step, by telling which collisionner is the nearest if there are several candidate
/// a distance of -1 indicates that no collisions occured
struct CPSCollisionInfo
{
CPSCollisionInfo *Next;
float Dist; // Distance to the nearest collider, or -1 if not collision occured
NLMISC::CVector NewPos;
NLMISC::CVector NewSpeed; // The speed of particle after a collision occured. After the updated of collision it is swapped with the post-collision speed
CPSZone *CollisionZone; // The zone on which the bounce occured, can be useful to check the behaviour in case of collision
uint32 Index;
CPSCollisionInfo()
{
Dist = -1.f;
}
// update the collision info, and eventually link it in the list of active collisions
void update(const CPSCollisionInfo &other);
};
/**
* this class is a located : it belongs to a particle system, and it represents
* any kind of object that has a position in the world.
* A located don't do anything by itself. You must bind objects to it, such as a particle,
* a force and so on.
* It is important to remember that a located holds all instance of object of
* one type (force, emitter, particles or both...), not only one.
* Not sharable accross systems
*/
class CPSLocated : public CParticleSystemProcess
{
public:
PS_FAST_OBJ_ALLOC
/// Constructor
CPSLocated();
/// dtor
virtual ~CPSLocated();
// from CParticleSystemProcess
virtual bool isLocated() const { NL_PS_FUNC(isLocated); return true; }
/** attach a bindable object to this located, such as a force or a particle
* a bindable must be attached only once (-> nlassert)
* The bindable is then owned by the system and will be deleted by it.
* \return true if the operation could be performed. It can fail when this cause the system the system to last forever,
* which is incompatible with the 'BypassMaxNumIntegrationSteps' in CParticleSystem
*/
bool bind(CPSLocatedBindable *lb);
/** Detach a bindable object from this located. Ownership is transferred to the caller
* Any reference the object may have in the system is lost (targets..)
* After that is may be inserted another system.
*/
CPSLocatedBindable *unbind(uint index);
/// test whether a located bindable is attached to that object
bool isBound(const CPSLocatedBindable *lb) const;
/** Get the index of a located bindable that is bound to that object.
* If it isn't bound, an assertion is raised
*/
uint getIndexOf(const CPSLocatedBindable *lb) const;
/** remove a bound object from the located
* if the object doesnt exist -> nlassert
* it is deleted
*/
void remove(const CPSLocatedBindable *lb);
/** From CParticleSystemProcess.
* Release any reference this located may have on the given process.
* For example, this is used when detaching a located of a system.
*/
virtual void releaseRefTo(const CParticleSystemProcess *other);
/** From CParticleSystemProcess.
* Release any reference this located may have to other process of the system
* For example, this is used when detaching a process of a system.
*/
virtual void releaseAllRef();
/**
* count the number of bound objects
*/
uint32 getNbBoundObjects(void) const { NL_PS_FUNC(getNbBoundObjects); return (uint32)_LocatedBoundCont.size(); }
/**
* get a pointer to a bound object (const version)
*/
const CPSLocatedBindable *getBoundObject(uint32 index) const
{
nlassert(index < _LocatedBoundCont.size());
return _LocatedBoundCont[index];
}
/**
* get a pointer to a bound object
*/
CPSLocatedBindable *getBoundObject(uint32 index)
{
nlassert(index < _LocatedBoundCont.size());
return _LocatedBoundCont[index];
}
/** Post a new Element to be created. This should be called by emitters only (r.g in the sim loop)
* Calling this outside the sim loop will cause an assert.
*/
void postNewElement(const NLMISC::CVector &pos,
const NLMISC::CVector &speed,
CPSLocated &emitterLocated,
uint32 indexInEmitter,
TPSMatrixMode speedCoordSystem,
TAnimationTime lifeTime);
/**
* Generate one more instance in a located.
* The coordinates are given in the chosen basis for the located.
* If the emitterLocated ptr is not null, then the coordinate are taken from the emitterLocated basis
* and are expressed in this located basis.
* Will succeed only if it hasn't reach the max number of allowed instances
* return will be -1 if call failed or an index to the created object.
* Index is only valid after creation. Any processing pass on the system will make it invalid.
* It can be used with any attribute modification method of located and located bindable
* \param indexInEmitter The index of the emitter (in the emitterLocated object)
* \param basisConversionForSpeed : if false, the speed vector is taken as if even if emitter and emittee basis are differents.
* \param lifeTime : for how much time particle has been alive
* \param ellapsedTime : time ellapsed since the beginning of the sim step.
* \param doEmitOnce : When the element is created, all emitters flagged as 'EmitOnce' will be triggered
*/
sint32 newElement(const NLMISC::CVector &pos,
const NLMISC::CVector &speed,
CPSLocated *emitterLocated,
uint32 indexInEmitter,
TPSMatrixMode speedCoordSystem,
bool doEmitOnce = false
);
/**
* Delete one located in the container
* not present -> nlassert
*/
void deleteElement(uint32 index);
// get the age of an element in seconds
inline TAnimationTime getAgeInSeconds(uint elementIndex) const;
/// shortcut to get the scene
CScene *getScene(void);
/// shortcut to the same method of the owning particle system
void getLODVect(NLMISC::CVector &v, float &offset, TPSMatrixMode matrixMode);
/** Shorcut to increase the particle counter (number of particle drawn, for benchmark purpose )
* should be called only by bound object that display particles
*/
void incrementNbDrawnParticles(uint num);
/**
* Get the index of the new element that is created
* Valid only after the newElement method (overridable) of a LocatedBindable is called
*: you get the index of the located being generated, if you need its pos, speed, or mass.
*/
uint32 getNewElementIndex(void) const { return _Size; }
/** Compute the aabbox of this located, (expressed in world basis
* \return true if there is any aabbox
* \param aabbox a ref to the result box
*/
bool computeBBox(NLMISC::CAABBox &aabbox) const;
/** Set the duration of locateds.
* Any previous call to setLastForever() is discarded
* Any previous scheme for lifetime is dicarded
*/
void setInitialLife(TAnimationTime lifeTime);
/** Set a scheme (allocated by new, released by that object) that generate the duration of locateds.
* Such a scheme can't own its memory.
* Any previous call to setLastForever() is discarded
* Any previous scheme for lifetime is discarded
*/
void setLifeScheme(CPSAttribMaker<float> *scheme);
/// get the life of created particles (valid if they have a limited life time)
TAnimationTime getInitialLife(void) const { return _InitialLife; }
/// get the life scheme of created particle, null if none (valid if they have a limited life time)
CPSAttribMaker<float> *getLifeScheme(void) { return _LifeScheme; }
const CPSAttribMaker<float> *getLifeScheme(void) const { return _LifeScheme; }
/** Set the mass of locateds.
* Any previous scheme for Mass is dicarded
*/
void setInitialMass(float mass);
/** Set a scheme (allocated by new, released by that object) that generate the mass of locateds.
* Such a scheme can't own its memory.
* Any previous scheme for Mass is discarded
*/
void setMassScheme(CPSAttribMaker<float> *scheme);
/// get the mass of created particle
float getInitialMass(void) const { return _InitialMass; }
/// get the scheme that compute mass of created particles, null if none
CPSAttribMaker<float> *getMassScheme(void) { return _MassScheme; }
const CPSAttribMaker<float> *getMassScheme(void) const { return _MassScheme; }
/** set immortality for located
* \see setInitialLife
* \return true if the operation could be performed. It can fail when this cause the system the system to last forever,
* which is incompatible with the 'BypassMaxNumIntegrationSteps' in CParticleSystem
*/
bool setLastForever();
/// retrieve immortality for locateds
bool getLastForever(void) const { return _LastForever; }
/// get mass inverse attrib ref
TPSAttribFloat &getInvMass(void) { return _InvMass; }
/// get mass inverse attrib const ref
const TPSAttribFloat &getInvMass(void) const { return _InvMass; }
/// get Pos attrib ref
TPSAttribVector &getPos(void) { return _Pos; }
/// get Pos attrib const ref
const TPSAttribVector &getPos(void) const { return _Pos; }
/// get Speed attrib ref
TPSAttribVector &getSpeed(void) { return _Speed; }
/// get Speed attrib const ref
const TPSAttribVector &getSpeed(void) const { return _Speed; }
/// get Time attrib ref
TPSAttribTime &getTime(void) { return _Time; }
/// get Time attrib const ref
const TPSAttribTime &getTime(void) const { return _Time; }
/// get TotalTime attrib ref
TPSAttribTime &getTimeIncrement(void) { return _TimeIncrement; }
/// get TotalTime attrib const ref
const TPSAttribTime &getTimeIncrement(void) const { return _TimeIncrement; }
/**
* process the system
*/
virtual void step(TPSProcessPass pass);
// move and collides particles (with previously computed collisions)
void computeMotion();
//move and collide particles that have been newly spawned
void computeNewParticleMotion(uint firstInstanceIndex);
// Update position and speed of particles after collisions
void updateCollisions();
/// get the current number of instance in this located container
uint32 getSize(void) const
{
return _Size;
}
/** get the max number of instance in this located container
* \see resize()
*/
uint32 getMaxSize(void) const
{
NL_PS_FUNC(getMaxSize)
return _MaxSize;
}
/**
* Resize the located container, in order to accept more instances
*/
void resize(uint32 newSize);
/// serialization
void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
/// Shortcut to get an instance of the 3d driver
IDriver *getDriver() const;
/// shorcut to get a user param that was set in the owner system
float getUserParam(uint numParam) const;
NLMISC_DECLARE_CLASS(CPSLocated);
/// Setup the driver model matrix. It is set accrodingly to the basis of the located
void setupDriverModelMatrix(void);
/** Compute a vector that will map to (1 0 0) after view and model transform.
* This allow to have object that always faces the user, whatever basis they are in
*/
NLMISC::CVector computeI(void) const;
NLMISC::CVector computeIWithZAxisAligned(void) const;
/** Compute a vector that will map to (0 1 0) after view and model transform.
* This allow to have object that always faces the user, whatever basis they are in
*/
NLMISC::CVector computeJ(void) const;
/** Compute a vector that will map to (0 0 1) after view and model transform.
* This allow to have object that always faces the user, whatever basis they are in
*/
NLMISC::CVector computeK(void) const;
NLMISC::CVector computeKWithZAxisAligned(void) const;
/** call this if you need collision infos.
* The collide info attribute is not included by default to save memory.
* The first call will create the attribute, and others will add references.
* You can then access the infos by calling getCollisioInfo
* You must call releaseCollideInfo after use.
*/
void queryCollisionInfo(void);
/// Release the collideInfos attribute
void releaseCollisionInfo(void);
/// test whether this located has collision infos
bool hasCollisionInfos() const { return _CollisionNextPos != NULL; }
// Compute spawns. Should be called only inside the sim loop.
void computeSpawns(uint firstInstanceIndex, bool includeEmitOnce);
// Compute forces that apply on that located. Should be called only inside the sim loop.
void computeForces();
// compute collisions
void computeCollisions(uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter);
// get a conversion matrix between 2 matrix modes
static const NLMISC::CMatrix &getConversionMatrix(const CParticleSystem &ps, TPSMatrixMode to, TPSMatrixMode from);
/** get a matrix that helps to express located B coordinate in located A basis
* A and B must belong to the same system
*/
static const NLMISC::CMatrix &getConversionMatrix(const CPSLocated *A, const CPSLocated *B);
const NLMISC::CMatrix &getLocalToWorldMatrix() const;
const NLMISC::CMatrix &getWorldToLocalMatrix() const;
/** Register a dtor observer; (that derives from CPSLocatedBindable)
* Each observer will be called when this object dtor is called (call of method notifyTargetRemoved() )
* This allow for objects that hold this as a target to know when it is suppressed
* (example : collision objects hold located as targets)
* When an observer is detroyed, it MUST call unregisterDtorObserver,
* The same observer can only register once, otherwise, an assertion occurs
*/
void registerDtorObserver(CPSLocatedBindable *observer);
/** remove a dtor observer (not present -> nlassert)
* see register dtor observer
*/
void unregisterDtorObserver(CPSLocatedBindable *anObserver);
/// set the located bindable name (edition purpose)
void setName(const std::string &name) { _Name = name; }
/// get the located bindable name (edition purpose)
std::string getName(void) const { return _Name; }
/// tells whether there are alive entities / particles in the system
virtual bool hasParticles(void) const;
/// tells whether there are alive emitters / particles in the system
virtual bool hasEmitters(void) const;
/** Enable the to force LOD degradation. This will suppress instances immediately, (during the motion pass) so that
* there won't be more than maxNbInstance * dist / maxDist instances. This may not be desirable
* every time since particle dissapear on screen, which may be noticeable.
*/
void forceLODDegradation(bool enable = true) { _LODDegradation = enable; }
/** Test whether LOD degradation was activated
* \see forceLODDegradation()
*/
bool hasLODDegradation(void) const { return _LODDegradation; }
/// for the CPSLocated to reevaluate the max number of faces it may need
//void notifyMaxNumFacesChanged(void);
/// ask for the max number of faces the located wants (for LOD balancing)
virtual uint getNumWantedTris() const;
// Inherited from CParticlesystemProcess. Change the coord system for thta system.
virtual void setMatrixMode(TPSMatrixMode matrixMode);
/// Test whether this located support parametric motion
bool supportParametricMotion(void) const;
/** 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. An assertion happens otherwise
*/
void enableParametricMotion(bool enable = true);
/// test whether parametric motion is enabled
bool isParametricMotionEnabled(void) const { return _ParametricMotion;}
/// inherited from CParticlesystemProcess perform parametric motion for this located to reach the given date
virtual void performParametricMotion(TAnimationTime date);
/// make the particle older of the given amount. Should not be called directly, as it is called by the system during its step method
/// Dying particles are marked (removed in a later pass by called removeOldParticles)
void updateLife();
/// Remove old particles that were marked as 'dead'
void removeOldParticles();
/// Add newly spawned particles
void addNewlySpawnedParticles();
/** Compute the trajectory of the given located.
* NB : only works with object that have parametric trajectories
*/
void integrateSingle(float startDate, float deltaT, uint numStep,
uint32 indexInLocated,
NLMISC::CVector *destPos,
uint posStride = sizeof(NLMISC::CVector)) const;
// compute position for a single element at the given date
// NB : only works with object that have parametric trajectories
inline void computeParametricPos(float date, uint indexInLocated, NLMISC::CVector &dest) const;
/// Enable a trigger on death. It is used to create emission on an emitter with a given ID
void enableTriggerOnDeath(bool enable = true) { _TriggerOnDeath = enable; }
/// Test whether a trigger on death has been enabled
bool isTriggerOnDeathEnabled(void) const { return _TriggerOnDeath; }
/// Set an ID for the emitter to be triggered on death
void setTriggerEmitterID(uint32 id)
{
nlassert(_TriggerOnDeath);
_TriggerID = id;
}
/// Get the ID for the emitter to be triggered on death
uint32 getTriggerEmitterID(void) const
{
nlassert(_TriggerOnDeath);
return _TriggerID;
}
/** eval max duration of the located (if no scheme is used, this is the lifetime)
* nb : return -1 if located last for ever
*/
float evalMaxDuration() const;
// from CParticleSystemProcess
virtual uint getUserMatrixUsageCount() const;
// from CParticleSystemProcess
virtual void enumTexs(std::vector<NLMISC::CSmartPtr<ITexture> > &dest, IDriver &drv);
// from CParticleSystemProcess
virtual void setZBias(float value);
// For debug only, check if particles life is in the range [0, 1]
void checkLife() const;
// from CParticleSystemProcess
virtual void onShow(bool shown);
protected:
friend class CPSForce; // this is intended only for integrable forces that want to use
// registerIntegrableForce, and removeIntegrableForce
/// Cache the max number of faces this located may want
//uint32 _MaxNumFaces;
// Current number of instances in the container
uint32 _Size;
// Max number of instance in the container
uint32 _MaxSize;
// Nb of collisions zones that reference that object
uint32 _CollisionInfoNbRef;
// Keep vector of next positions during sim step (to avoid a copy after position have been computed). Used only if there are collisions
TPSAttribVector *_CollisionNextPos;
// The life to use, or a scheme that generate it
// if the scheme if NULL, initial life is used instead
float _InitialLife;
CPSAttribMaker<float> *_LifeScheme;
// The mass to use, or a scheme that generate it
// if the scheme if null, initial mass is used instead
float _InitialMass;
CPSAttribMaker<float> *_MassScheme;
bool _LODDegradation : 1; // True when LOD degradation apply to this located
bool _ParametricMotion : 1; // When set to true, this tells the system to use parametric motion. Only parametric forces must have been applied.
bool _TriggerOnDeath : 1; // When set to true, then when any particle is destroyed, all particles with ID '_TriggerID' will be destroyed too
bool _LastForever : 1; // True if the located can't die.
uint32 _TriggerID;
/** Number of forces, (counts collision zones too). that are not integrable over time. If this is not 0, then the trajectory
* cannot be computed at any time. A force that is integrable must be in the same basis than the located.
*/
uint16 _NonIntegrableForceNbRefs;
/// Number of forces that apply on that located that have the same basis that this one (required for parametric animation)
uint16 _NumIntegrableForceWithDifferentBasis;
// Name of located
std::string _Name;
// Container of all object that are bound to a located
typedef CPSVector<CPSLocatedBindable *>::V TLocatedBoundCont;
// The list of all located
TLocatedBoundCont _LocatedBoundCont;
// Needed atributes for a located
// a container of masses. the inverse for mass are used in order to speed up forces computation
TPSAttribFloat _InvMass;
TPSAttribVector _Pos;
TPSAttribVector _Speed;
TPSAttribTime _Time;
TPSAttribTime _TimeIncrement;
public:
/** WARNING : private use by forces only. This struct is used for parametric trajectory. These kind of trajectory can only be computed in a few case,
* but are useful in some cases.
*/
struct CParametricInfo
{
CParametricInfo() {}
CParametricInfo(NLMISC::CVector pos, NLMISC::CVector speed, float date)
: Pos(pos), Speed(speed), Date(date)
{
}
NLMISC::CVector Pos; // the inital pos of emission
NLMISC::CVector Speed; // the inital direction of emission
TAnimationTime Date; // the initial date of emission
};
/// WARNING : private use by forces only
typedef CPSAttrib<CParametricInfo> TPSAttribParametricInfo;
/** WARNING : private use by forces only. this vector is only used if parametric motion is achievable and enabled, because of the extra storage space
*
*/
CPSAttrib<CParametricInfo> _PInfo;
protected:
typedef CPSVector<CPSLocatedBindable *>::V TDtorObserversVect;
TDtorObserversVect _DtorObserversVect;
// a vector of integrable forces that apply on this located
typedef CPSVector<CPSForce *>::V TForceVect;
TForceVect _IntegrableForces;
/// allocate parametric infos
void allocateParametricInfos(void);
/// release paametric infos
void releaseParametricInfos(void);
/// notify the attached object that we have switch between parametric / incremental motion
void notifyMotionTypeChanged(void);
// for debug : check that system integrity is ok, otherwise -> assert
void checkIntegrity() const;
public:
/// PRIVATE USE: register a force that is integrable on this located. It must have been registered only once
void registerIntegrableForce(CPSForce *f);
/// PRIVATE USE: unregister a force that is integrable with this located
void unregisterIntegrableForce(CPSForce *f);
/// PRIVATE USE: says that an integrable force basis has changed, and says which is the right basis
void integrableForceBasisChanged(TPSMatrixMode basis);
/// PRIVATE USE: add a reference count that says that non-integrable forces have been added
void addNonIntegrableForceRef(void);
/// PRIVATE USE: decrease the reference count to say that a non-integrable force has been removed.
void releaseNonIntegrableForceRef(void);
/// PRIVATE USE : access to parametric infos
TPSAttribParametricInfo &getParametricInfos() { return _PInfo; }
/// PRIVATE USE : called by the system when its date has been manually changed
virtual void systemDateChanged();
// PRIVATE USE :reset collisions
void resetCollisions(uint numInstances);
/// PRIVATE USE :Should be only called by the sim loop when hasLODDegradation() returns true. /see forceLODDegradation
void doLODDegradation();
private:
// Special version for deleteElement, should be only called during the update loop.
// If gives the amount of time that will ellapse until the end of the simulation step, so that,
// if a particle is emitted 'On death' of its emitter, it will have a correct pos at the next simultion step
void deleteElement(uint32 index, TAnimationTime timeUntilNextSimStep);
// Delete basic info for an element. Called by both versions of deleteElement
void deleteElementBase(uint32 index);
// compute time from the collision to the next sim step
TAnimationTime computeDateFromCollisionToNextSimStep(uint particleIndex, float particleAgeInSeconds);
// create a new element
sint32 newElement(const CPSSpawnInfo &si, bool doEmitOnce, TAnimationTime ellapsedTime);
public:
static CPSCollisionInfo *_FirstCollision;
// collisions infos, made public to access by collision zones
static std::vector<CPSCollisionInfo> _Collisions;
};
///////////////////////////////////////
// IMPLEMENTATION OF INLINE METHODS //
///////////////////////////////////////
// ******************************************************************************************
// ******************************************************************************************
// ******************************************************************************************
// kind of bindable objects
const uint32 PSForce = 0;
const uint32 PSParticle = 1;
const uint32 PSEmitter = 2;
const uint32 PSLight = 3;
const uint32 PSZone = 4;
const uint32 PSSound = 5;
/**
* an instance of these class can be bound to a particle system located
* this include forces, particle, and so on...
*/
class CPSLocatedBindable : public NLMISC::IStreamable
{
public:
PS_FAST_OBJ_ALLOC
///\name Object
//@{
/// ctor
CPSLocatedBindable();
/// serialization
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
/** this should be called before to delete any bindable inserted in a system, but this is done
* by the system, so you should never need calling it. This has been introduced because calls in dtor are not polymorphic
* to derived class (which are already destroyed anyway), and some infos are needed in some dtor. The default behaviour does nothing
*/
virtual void finalize(void);
/// dtor
virtual ~CPSLocatedBindable();
//@}
/// Activate / Deactivate this object. When not active, the owning system won't try to call the 'step' method
void setActive(bool active) { _Active = active; }
bool isActive() const { return _Active; }
/**
* Gives the type for this bindable.
* types are encoded as constant uint32
*/
virtual uint32 getType(void) const = 0;
/**
* Get the priority of the bindable
* The more high it is, the earlier it is dealt with
*/
virtual uint32 getPriority(void) const = 0;
/// process one pass for this bindable
virtual void step(TPSProcessPass pass) = 0;
/** Can be used by located bindable that have located as targets (emitter, collision zone, forces)
* to be notified that one of their target has been removed.
* To do this :
* The object that focus the target must call registerDTorObserver on the target, with himself as a parameter
* When the target is removed, this target will call this method for all registered CPSLocated
* The default behaviour remove this object as an observer
*
* \see CPSLocated::registerDTorObserver()
*/
virtual void notifyTargetRemoved(CPSLocated *ptr);
/** Release any reference this obj may have on the given process.
* For example, this is used when detaching a located bindable from a system.
*/
virtual void releaseRefTo(const CParticleSystemProcess * /* other */) {}
/** Release any reference this obj may have to other process of the system
* For example, this is used when detaching a located bindable from a system.
*/
virtual void releaseAllRef();
/***
* The following is used to complete an aabbox that was computed using the located positions
* You may not need to do anything with that, unless your bindable has a space extents. For exAmple,
* with a particle which has a radius of 2, you must enlarge the bbox to get the correct one.
* The default behaviour does nothing
* \return true if you modified the bbox
*/
virtual bool completeBBox(NLMISC::CAABBox &/* box */) const { return false;}
/***
* Override the following to say that you don't want to be part of a bbox computation
*/
virtual bool doesProduceBBox(void) const { return true; }
/// shortcut to get an instance of the driver
IDriver *getDriver() const
{
nlassert(_Owner);
nlassert(_Owner->getDriver());
return _Owner->getDriver();
}
/// Shortcut to get the font generator if one was set
CFontGenerator *getFontGenerator(void)
{
nlassert(_Owner);
return _Owner->getFontGenerator();
}
/// Shortcut to get the font generator if one was set (const version)
const CFontGenerator *getFontGenerator(void) const
{
nlassert(_Owner);
return _Owner->getFontGenerator();
}
/// Shortcut to get the font manager if one was set
CFontManager *getFontManager(void);
/// Shortcut to get the font manager if one was set (const version)
const CFontManager *getFontManager(void) const;
/// Shortcut to get the matrix of the system
const NLMISC::CMatrix &getSysMat(void) const;
/// Shortcut to get the local to world matrix
const NLMISC::CMatrix &getLocalToWorldMatrix() const;
/// shortcut to get the inverted matrix of the system
const NLMISC::CMatrix &getInvertedSysMat(void) const;
/// shortcut to get the view matrix
const NLMISC::CMatrix &getViewMat(void) const;
/// shortcut to get the inverted view matrix
const NLMISC::CMatrix &getInvertedViewMat(void) const;
/// shortcut to setup the model matrix (system basis or world basis)
void setupDriverModelMatrix(void);
/** Compute a vector that will map to (1 0 0) after view and model transform.
* This allow to have object that always faces the user, whatever basis they are in
*/
inline NLMISC::CVector computeI(void) const { return _Owner->computeI(); }
// Same version, but with Z-Axis aligned on world z-axis
inline NLMISC::CVector computeIWithZAxisAligned(void) const { return _Owner->computeIWithZAxisAligned(); }
/** Compute a vector that will map to (0 1 0) after view and model transform.
* This allow to have object that always faces the user, whatever basis they are in
*/
inline NLMISC::CVector computeJ(void) const { return _Owner->computeJ(); }
/** Compute a vector that will map to (0 0 1) after view and model transform.
* This allow to have object that always faces the user, whatever basis they are in
*/
inline NLMISC::CVector computeK(void) const { return _Owner->computeK(); }
inline NLMISC::CVector computeKWithZAxisAligned(void) const { return _Owner->computeKWithZAxisAligned(); }
/// get the located that owns this bindable
CPSLocated *getOwner(void) { return _Owner; }
/// get the located that owns this bindable (const version)
const CPSLocated *getOwner(void) const { return _Owner; }
/// set the located bindable name (edition purpose)
void setName(const std::string &name) { _Name = name; }
/// get the located bindable name (edition purpose)
std::string getName(void) const { return _Name; }
/** set the LODs that apply to that object (warning : it is based on the position of the system, and don't act on a per instance basis ...)
* To have per instance precision, you must use an attribute maker that has LOD as its input
*/
void setLOD(TPSLod lod) { _LOD = lod; }
/// get the valid lods for that object
TPSLod getLOD(void) const { return _LOD; }
/// tells whether there are alive entities / particles
virtual bool hasParticles(void) const { return false; }
/// tells whether there are alive emitters
virtual bool hasEmitters(void) const { return false; }
/** set the extern ID of this located bindable. 0 means no extern access. The map of ID-locatedBindable. Is in th
* particle system, so this located bindable must have been attached to a particle system, otherwise an assertion is raised
*/
void setExternID(uint32 id);
/// get the extern ID of this located bindable
uint32 getExternID(void) const { return _ExternID; }
/** Called when the basis of the owner changed. the default behaviour does nothing
* \param newBasis : True if in the system basis, false for the world basis.
*/
virtual void basisChanged(TPSMatrixMode /* systemBasis */) {}
/// called when a located has switch between incrmental / parametric motion. The default does nothing
virtual void motionTypeChanged(bool /* parametric */) {}
// returns the number of sub-objects (including this one, that requires the user matrix for its computations)
virtual bool getUserMatrixUsageCount() const { return 0; }
// enum tex used by the object, and append them to dest
virtual void enumTexs(std::vector<NLMISC::CSmartPtr<ITexture> > &/* dest */, IDriver &/* drv */) {}
// change z-bias in material (default does nothing)
virtual void setZBias(float /* value */) {}
// called when the show / hide flag has been changed
virtual void onShow(bool /* shown */) {}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
protected:
friend class CPSLocated;
/** Generate a new element for this bindable. They are generated according to the propertie of the class
*/
virtual void newElement(const CPSEmitterInfo &info) = 0;
// Delete element at the given index
virtual void deleteElement(uint32 index) = 0;
// Delete element at the given index. Gives the remaining time until the next sim loop
virtual void deleteElement(uint32 index, TAnimationTime /* timeUntilNextSimStep */) { deleteElement(index); }
/** Resize the bindable attributes containers
* should not be called directly. Call CPSLocated::resize instead
*/
virtual void resize(uint32 size) = 0;
/** a bounce occured, so some action could be done. The default behaviour does nothing
* \param index the index of the element that bounced
*/
virtual void bounceOccured(uint32 /* index */, TAnimationTime /* timeToNextsimStep */) {}
/** show an drawing to represent the object, and in red if it is selected
* \param tab : a table of 2 * nbSeg vector. only the x and y coordinates are used
* \param nbSeg : the number of segment
* \param scale : the scale to use for drawing
*/
void displayIcon2d(const NLMISC::CVector tab[], uint nbSegs, float scale);
/// set the located that hold this located bindable
virtual void setOwner(CPSLocated *psl);
protected:
CPSLocated *_Owner;
uint32 _ExternID;
/// tells when this object must be dealt with
TPSLod _LOD;
// Name for this bindable
std::string _Name;
//
bool _Active; // Say if this bindable is active. If not active, the owning system won't try to call 'step' on that object. True by default
public:
/** PRIVATE USE : called by the system when its date has been manually changed.
* This his usually for object that expect time to be always increasing, so that they can reset their datas
*/
virtual void systemDateChanged() {}
};
/**
* less operator on located bindable. They're sorted in decreasing priority order
*/
inline bool operator<(const CPSLocatedBindable &lhs, const CPSLocatedBindable &rhs)
{
return rhs.getPriority() > lhs.getPriority();
}
// ******************************************************************************************
// ******************************************************************************************
// ******************************************************************************************
/** This class is a located bindable that can focus on several target
* Can be inherited by bindable like forces or collision zones
*/
class CPSTargetLocatedBindable : public CPSLocatedBindable
{
public:
/** Add a new type of located for this to apply on. nlassert if already present.
* You should only call this if this object and the target are already inserted in a system.
* By overriding this and calling the CPSTargetLocatedBindable version,
* you can also send some notificiation to the object that's being attached.
*/
virtual void attachTarget(CPSLocated *ptr);
/** remove a target
* \see attachTarget
*/
void detachTarget(CPSLocated *ptr)
{
notifyTargetRemoved(ptr);
}
/** From CPSLocatedBindable.
* Release any reference this obj may have on the given process.
* For example, this is used when detaching a located of a system.
*/
virtual void releaseRefTo(const CParticleSystemProcess *other);
/** From CPSLocatedBindable
* Release any reference this obj may have to other process of the system
* For example, this is used when detaching a located bindable from a system.
*/
virtual void releaseAllRef();
/// return the number of targets
uint32 getNbTargets(void) const { return (uint32)_Targets.size(); }
/// Return a ptr on a target. Invalid range -> nlassert
CPSLocated *getTarget(uint32 index)
{
nlassert(index < _Targets.size());
return _Targets[index];
}
/// Return a const ptr on a target. Invalid range -> nlassert
const CPSLocated *getTarget(uint32 index) const
{
nlassert(index < _Targets.size());
return _Targets[index];
}
/** it is called when a target is destroyed or detached
* Override this if you allocated resources from the target (to release them)
* NOTE : as objects are no polymorphic while being destroyed, this class
* can't call your releaseTargetRsc override in its destructor, it does it in its finalize method,
* which is called by the particle system
*/
virtual void releaseTargetRsc(CPSLocated * /* target */) {}
/// Seralization, must be called by derivers
void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
/// Finalize this object : the default is to call releaseTargetRsc on targets
virtual void finalize(void);
virtual ~CPSTargetLocatedBindable();
protected:
friend class CPSLocated;
/** Inherited from CPSLocatedBindable. A target has been remove If not present -> assert
* This also call releaseTargetRsc for clean up
*/
virtual void notifyTargetRemoved(CPSLocated *ptr);
typedef CPSVector<CPSLocated *>::V TTargetCont;
TTargetCont _Targets;
};
/////////////
// INLINES //
/////////////
// *****************************************************************************************************
inline const NLMISC::CMatrix &CPSLocated::getConversionMatrix(const CPSLocated *A,const CPSLocated *B)
{
nlassert(A);
nlassert(B);
nlassert(A->_Owner == B->_Owner); // conversion must be made between entity of the same system
const CParticleSystem *ps = A->_Owner;
nlassert(ps);
return getConversionMatrix(*ps, A->getMatrixMode(), B->getMatrixMode());
}
// *****************************************************************************************************
inline TAnimationTime CPSLocated::getAgeInSeconds(uint elementIndex) const
{
nlassert(elementIndex < _Size);
if (_LastForever) return _Time[elementIndex];
if (_LifeScheme) return _Time[elementIndex] / _TimeIncrement[elementIndex];
return _Time[elementIndex] * _InitialLife;
}
// *****************************************************************************************************
inline void CPSLocated::computeParametricPos(float date, uint indexInLocated, NLMISC::CVector &dest) const
{
integrateSingle(date, 1.f, 1, indexInLocated, &dest);
}
// *****************************************************************************************************
inline const NLMISC::CMatrix &CPSLocatedBindable::getLocalToWorldMatrix() const
{
nlassert(_Owner);
return _Owner->getLocalToWorldMatrix();
}
} // NL3D
#endif // NL_PARTICLE_SYSTEM_LOCATED_H
/* End of particle_system_located.h */