2017-03-15 19:43:10 +00:00
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// 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 CL_TIMED_FX_MANAGER_H
# define CL_TIMED_FX_MANAGER_H
# include "nel/misc/vector.h"
# include "nel/misc/noise_value.h"
# include "game_share/season.h"
# include "time_client.h"
# include "fx_manager.h"
class CSeasonFXSheet ;
namespace NL3D
{
class UParticleSystemInstance ;
class UScene ;
}
/** A fx that must be spawn at a given season and hour
* \ author Nicolas Vizerie
* \ author Nevrax France
* \ date 2003
*/
class CTimedFX
{
public :
NLMISC : : CVector SpawnPosition ;
NLMISC : : CQuat Rot ;
NLMISC : : CVector Scale ;
const CSeasonFXSheet * FXSheet ;
# if !FINAL_VERSION
bool FromIG ; // true if the fx comes from an ig, or false if it was generated dynamically
# endif
public :
CTimedFX ( ) : SpawnPosition ( 0.f , 0.f , 0.f ) , FXSheet ( NULL )
{
# if !FINAL_VERSION
FromIG = true ;
# endif
}
NLMISC : : CMatrix getInstanceMatrix ( ) const ;
} ;
typedef std : : vector < CTimedFX > TTimedFXGroup ;
/** Manager to spawn fxs at a given season and hour.
* \ author Nicolas Vizerie
* \ author Nevrax France
* \ date 2003
*/
class CTimedFXManager
{
private :
class CManagedFX ;
struct CTimeStampedFX
{
CClientDate Date ; // the date at which the FX must be added / removed
//sint32 DebugDay;
CManagedFX * FX ; // managed FX
bool operator < ( const CTimeStampedFX & rhs ) const
{
if ( Date = = rhs . Date ) return FX < rhs . FX ;
else return Date < rhs . Date ;
} // we want to deal with early dates sooner
bool operator = = ( const CTimeStampedFX & rhs ) const { return Date = = rhs . Date & & FX = = rhs . FX ; }
CTimeStampedFX ( ) : FX ( NULL ) { }
} ;
typedef std : : set < CTimeStampedFX > TTimeStampedFXPtrSet ;
struct CManagedFXGroup ;
struct CCandidateFXListHead ;
/** A managed FX. Unless it is flagged as 'always intanciated', or is in a group that is shutting down,
* such a fx can only be in one set : _FXToAdd if it is not currently instanciated ( or is shutting down ) , and _FXToRemove if it is instanciated and is not being shut down .
* and will be removed in the future .
*/
class CManagedFX : public CTimedFX
{
public :
enum TState { Unknown = 0 , Permanent , InAddList , InRemoveList } ;
# ifdef NL_DEBUG
CManagedFXGroup * OwnerGroup ;
# endif
NL3D : : UParticleSystemInstance Instance ; // Pointer to the actual FX. NULL if failed to instanciate or if not instanciated
TState State ;
TTimeStampedFXPtrSet : : iterator SetHandle ; // if the fx is in a list (see its state), then it is an iterator into that list (for removal)
//
CManagedFX * * _PrevCandidateFX ; // if the fx has asked to be instanciated, it is inserted in a list of candidate fxs. points the previous "Next" pointer
// even if the fx is currently instanciated, it remains in that list (those are the potnetially instanciated fxs)
CManagedFX * _NextCandidateFX ; // next candidate FX
//
CManagedFX * * _PrevInstanciatedFX ; // link into instanciated fx list, prev (is also a candidate)
CManagedFX * _NextInstanciatedFX ; // link into instanciated fx list, next
// Tmp for debug
# ifdef NL_DEBUG
uint32 Magic ;
# endif
public :
// ctor
CManagedFX ( )
{
Instance = NULL ;
State = Unknown ;
# ifdef NL_DEBUG
OwnerGroup = NULL ;
Magic = 0xbaadcafe ;
# endif
_PrevCandidateFX = NULL ;
_NextCandidateFX = NULL ;
//
_PrevInstanciatedFX = NULL ;
_NextInstanciatedFX = NULL ;
}
// compute start hour of that fx for the given day
void computeStartHour ( sint32 cycle , CClientDate & resultDate , float cycleLength , float dayLength , const NLMISC : : CNoiseValue & nv ) const ;
// compute end hour of that fx for the given day
void computeEndHour ( sint32 cycle , CClientDate & resultDate , float cycleLength , float dayLength , const NLMISC : : CNoiseValue & nv ) const ;
// unlink from list of candidate fxs
void unlinkFromCandidateFXList ( ) ;
// unlink from list of instanciated fx. NB : this doesn't remove the model!
void unlinkFromInstanciatedFXList ( ) ;
/** Shutdown the fx
*/
void shutDown ( NL3D : : UScene * scene , CFXManager & fxManager ) ;
private :
void computeHour ( sint32 cycle , float bias , CClientDate & resultDate , float cycleLength , float dayLength , const NLMISC : : CNoiseValue & nv , float minHour , float maxHour ) const ;
} ;
// A group of managed fx. We never resize these vectors after creation so we can keep pointers in them.
typedef std : : vector < CManagedFX > TManagedFXGroup ;
struct CManagedFXGroup
{
TManagedFXGroup Group ;
# ifdef NL_DEBUG
EGSPD : : CSeason : : TSeason Season ;
# endif
} ;
// a list of group of managed fxs.
typedef std : : list < CManagedFXGroup > TManagedFXGroupList ;
public :
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//\name USER INTERFACE
//@{
// mode of display for debug
enum TDebugDisplayMode { NoText = 0 , PSName , SpawnDate , DebugModeCount } ;
// handle to add/remove a group of managed fxs (see add() / remove())
typedef TManagedFXGroupList : : iterator TFXGroupHandle ;
// dtor
~ CTimedFXManager ( ) ;
/** Init the manager. Must be called before first use
* \ param scene The scene from which instances are created
* \ param startDate Date of init
* \ param dayLength Length of a day , in hours
* \ param noiseFrequency Frequency of noise used to compute pseudo random spwaning dates of fxs ( depends on their spawn position and on the date )
* \ param maxNumberOfFXInstance Max number of fx instances that are allowed to be instanciated at a given time . Nearest fx are instanciated first
* \ param sortDistanceInterval precision with which fx are sorted in distance . For example , with 1 meter precision , fx at 0.2 & 0.5 from the user are considered
* to be at the same distance
* \ param maxDist Max dist at which fxs are sorted . For efficiency , it is important to keep maxDist / sortDistanceInterval
*/
void init ( NL3D : : UScene * scene ,
const CClientDate & startDate ,
float dayLength ,
float noiseFrequency ,
uint maxNumberOfFXInstances ,
float sortDistanceInterval ,
float maxDist
) ;
// Reset all manager content
void reset ( ) ;
/** Register a set of fxs to be managed.
* A handle is returned to remove it later .
*/
TFXGroupHandle add ( const std : : vector < CTimedFX > & fxs , EGSPD : : CSeason : : TSeason season ) ;
/** Remove a FX group that has previously been added
* All FX instances are deleted .
*/
void remove ( TFXGroupHandle handle ) ;
/** Delayed removal of a fx group that has previously been added.
* All FXs are shutdown by removing their emitters .
* This is useful to switch from one season to another .
*/
void shutDown ( TFXGroupHandle handle ) ;
// Update the manager state to match the new date. This add / removes FX as necessary
void update ( const CClientDate & date , EGSPD : : CSeason : : TSeason currSeason , const NLMISC : : CVector & camPos ) ;
// Set a new date, but do not update current fx. The new hour will be taken in account during the next call to 'add'
void setDate ( const CClientDate & date ) ;
// get the current date
const CClientDate & getDate ( ) const { return _CurrDate ; }
// Access to the unique instance of this class
static CTimedFXManager & getInstance ( ) ;
// for debug only
void dumpFXToAdd ( ) const ;
void dumpFXToRemove ( ) const ;
void dumpFXInfo ( ) const ;
// debug bbox and dates of FXs to remove and to add.
void displayFXBoxes ( TDebugDisplayMode displayMode ) const ;
// set max number of fx to be instanciated at a time
void setMaxNumFXInstances ( uint maxNumInstaces ) ;
//@}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private :
// Set of fx to be instanciated in the future. It is managed as a priority queue (sorted by date of instanciation).
TTimeStampedFXPtrSet _FXToAdd ;
// Set of fx to remove in the future, and that are currently instanciated (and are not shutting done). It is managed as a priority queue (sorted by date of removal).
TTimeStampedFXPtrSet _FXToRemove ;
// List of the groups of FXs that are currenlty managed.
TManagedFXGroupList _FXGroups ;
// The scene from which to add / remove instances
NL3D : : UScene * _Scene ;
// Current date of the manager
CClientDate _CurrDate ;
// List of group that are shutting down (that is, shutDown(TFXGroupHandle handle) was called on that group)
std : : list < TFXGroupHandle > _ShuttingDownGroups ;
// Length of a day, in hours
float _DayLength ;
// Noise function used to compute start/end date of fxs
NLMISC : : CNoiseValue _Noise ;
// Init
bool _InitDone ;
//\name DISTANCE SORTING
//@{
// FX to be displayed can be limited in number -> the nearest fx are instanciated in priority
// To achieve this, we keep a list of candidate fx for each interval of distance (thus achieving linear approximate sorting)
typedef std : : vector < CManagedFX * > TCandidateFXListSortedByDist ;
TCandidateFXListSortedByDist _CandidateFXListSortedByDist ; // roughly sorted list of candidate fx. Should be rebuilt completely when players moves (done in linear time)
TCandidateFXListSortedByDist _CandidateFXListSortedByDistTmp ; // already allocated vect for fast resorting of list when player moves
// NB : this vector nevers grows
bool _CandidateFXListTouched ; // the list of candidate has been modified, so the manager should see which fxs should be instanciated, and which fxs should be removed
float _SortDistance ; // length of each distance interval, in meters
uint _MaxNumberOfFXInstances ; // max number of instances that can be 'alive' at a time
//@}
// Linked list of currently instanciated FXs (nearest candidates)
CManagedFX * _InstanciatedFXs ;
NLMISC : : CVector _LastCamPos ;
// fx manager to deals with shutting down fxs
CFXManager _FXManager ;
private :
// ctor
CTimedFXManager ( ) ;
// for debug
void checkIntegrity ( ) ;
// setup user params for a fx
void setupUserParams ( CManagedFX & fi , uint cycle ) ;
// insert a fx in list of candidate for instanciation (also unlink from a previous list)
void linkCandidateFX ( TCandidateFXListSortedByDist & targetList , float dist , CManagedFX * fx ) ;
// link a fx into a list of instances (also unlink from a previous list)
void linkInstanciatedFX ( CManagedFX * & listHead , CManagedFX * fx ) ;
// update list of instanciated fxs (create / removes fxs as necessary)
void updateInstanciatedFXList ( ) ;
// re-sort list of candidate fx by distance (this is necessary when player moves)
void updateCandidateFXListSorting ( ) ;
public :
// convert a cycle and an hour to a date
static void cycleToDate ( sint32 cycle , float hour , float cycleLength , float dayLength , CClientDate & result ) ;
// give the matching cycle for a date
static sint32 dateToCycle ( const CClientDate & date , float cycleLength , float dayLength ) ;
} ;
# endif