484 lines
14 KiB
C++
484 lines
14 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_CHANNEL_MIXER_H
|
|
#define NL_CHANNEL_MIXER_H
|
|
|
|
#include "nel/misc/types_nl.h"
|
|
#include "nel/misc/debug.h"
|
|
#include "nel/misc/smart_ptr.h"
|
|
#include "nel/3d/animation_time.h"
|
|
#include "nel/3d/animation_set.h"
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
namespace NL3D
|
|
{
|
|
|
|
class CAnimation;
|
|
class IAnimatable;
|
|
class IAnimatedValue;
|
|
class ITrack;
|
|
class CAnimationSet;
|
|
|
|
/**
|
|
* A channel mixer. Animated value are registred in it.
|
|
* Each animated value create a channel in the mixer. Then, mixer animates
|
|
* all those channels with 1 to CChannelMixer::NumAnimationSlot animations.
|
|
*
|
|
* Animation are referenced in an animation slot (CSlot).
|
|
*
|
|
* Each slot have an IAnimation pointer, a weight for this animation
|
|
* between [0.f ~ 1.f] and a time for this animation.
|
|
*
|
|
* Each CChannel have a weight on each animation slot between [0.f ~ 1.f].
|
|
*
|
|
* Blending is normalized internaly so, weight sum have not to be == 1.f.
|
|
*
|
|
* \author Cyril 'Hulud' Corvazier
|
|
* \author Nevrax France
|
|
* \date 2001
|
|
*/
|
|
class CChannelMixer : public NLMISC::CRefCount
|
|
{
|
|
public:
|
|
|
|
/// \name Const values
|
|
|
|
enum
|
|
{
|
|
/// Number of animation slot in the CChannelMixer
|
|
NumAnimationSlot=8
|
|
};
|
|
|
|
private:
|
|
|
|
/// \name Internal classes
|
|
|
|
/// An animation slot.
|
|
class CSlot
|
|
{
|
|
friend class CChannelMixer;
|
|
|
|
/// Default Ctor
|
|
CSlot ()
|
|
{
|
|
// Not modified
|
|
_Dirt=false;
|
|
|
|
// default is 1.
|
|
_Weight= 1.f;
|
|
|
|
// Set it empty
|
|
empty ();
|
|
}
|
|
|
|
/// Empty the slot
|
|
void empty ()
|
|
{
|
|
_Animation=NULL;
|
|
_SkeletonWeight=NULL;
|
|
_InvertedSkeletonWeight=false;
|
|
}
|
|
|
|
/// Is the slot empty ?
|
|
bool isEmpty ()
|
|
{
|
|
return _Animation==NULL;
|
|
}
|
|
|
|
private:
|
|
/// Animation pointer to use by this slot. If NULL, slot is empty.
|
|
const CAnimation* _Animation;
|
|
|
|
/// Skeleton weight pointer
|
|
const CSkeletonWeight* _SkeletonWeight;
|
|
|
|
/// Skeleton weight pointer inverted or not
|
|
bool _InvertedSkeletonWeight;
|
|
|
|
/// Time to use to eval the animation.
|
|
TAnimationTime _Time;
|
|
|
|
/**
|
|
* Global weight to apply to the animation of this slot.
|
|
* This weight can be given in any range because renormalisation is done in final
|
|
* weight evaluation. If weight is 0.f, the final mix is not influenced by the animation
|
|
* of this slot.
|
|
*/
|
|
float _Weight;
|
|
|
|
/// Dirt flag. True if the animation of this slot as been modified
|
|
bool _Dirt;
|
|
};
|
|
|
|
/**
|
|
* An animated channel of the CChannelMixer. This class is used internaly in the
|
|
* CChannelMixer.
|
|
*
|
|
* \author Cyril 'Hulud' Corvazier
|
|
* \author Nevrax France
|
|
* \date 2001
|
|
*/
|
|
class CChannel
|
|
{
|
|
friend class CChannelMixer;
|
|
public:
|
|
enum {EnableUserFlag= 1, EnableLodFlag= 2, EnableAllFlag= 3};
|
|
|
|
public:
|
|
/// Default ctor
|
|
CChannel ()
|
|
{
|
|
// not in the list
|
|
_InTheList=false;
|
|
// enabled by default.
|
|
_EnableFlags= EnableAllFlag;
|
|
}
|
|
private:
|
|
/// True if this channel is in the list
|
|
bool _InTheList;
|
|
|
|
/// the detail mode.
|
|
bool _Detail;
|
|
|
|
/// enabled Flags. User | Lod
|
|
uint8 _EnableFlags;
|
|
|
|
/// Is this Animated Value a CQuat Animated Value???
|
|
bool _IsQuat;
|
|
|
|
|
|
/// Name of the channel in the channel mixer. Must be the same than the animated value name.
|
|
std::string _ChannelName;
|
|
|
|
/// A pointer on the IAnimatable object that handles the channel value. (ref ptr to ensure Animated value access)
|
|
NLMISC::CRefPtr<IAnimatable> _Object;
|
|
|
|
/// A pointer on the IAnimatedValue animated by this channel. If NULL, the channel is empty
|
|
IAnimatedValue* _Value;
|
|
|
|
/// The id of the animated value in the IAnimatable object.
|
|
uint32 _ValueId;
|
|
|
|
/// The id of the OwnerBit to touch the IAnimatable object. Useful for IAnimatable derivation.
|
|
uint32 _OwnerValueId;
|
|
|
|
/// The default track pointer used when track are missing in the animation. Can't be NULL.
|
|
const ITrack* _DefaultTracks;
|
|
|
|
/**
|
|
* A track pointer on each slot CAnimation. Can't be NULL. If no track found for this
|
|
* channel, the pointer is _DefaultTracks.
|
|
*/
|
|
const ITrack* _Tracks[NumAnimationSlot];
|
|
|
|
/**
|
|
* A weight array for to blend each slot.
|
|
* This value must be between 0.f and 1.f. If it is 0.f, the slot is not used. If it is 1.f,
|
|
* the slot is used at 100%. This weight can be set using a "skeleton template weight".
|
|
* Default value is 1.f.
|
|
*/
|
|
float _Weights[NumAnimationSlot];
|
|
|
|
/**
|
|
* Pointer on the next channel selected for the animations selected in the slots
|
|
*
|
|
* This list is used to only visit the channels animated by the animations set in the slots
|
|
* of the mixer
|
|
*/
|
|
CChannel* _Next;
|
|
|
|
};
|
|
public:
|
|
/// Constructor. The default constructor resets the slots and the channels.
|
|
CChannelMixer();
|
|
~CChannelMixer();
|
|
|
|
/// \name Setup the mixer
|
|
|
|
/**
|
|
* Set the animation set used by this channel mixer.
|
|
* The pointer is hold by the channel mixer until it changes.
|
|
*/
|
|
void setAnimationSet (const CAnimationSet* animationSet);
|
|
|
|
/**
|
|
* Get the animation set used by this channel mixer.
|
|
* The pointer is hold by the channel mixer until it changes. Return NULL if no animationSet defined.
|
|
*/
|
|
const CAnimationSet* getAnimationSet () const;
|
|
|
|
/**
|
|
* Launch evaluation of all channels.
|
|
*
|
|
* This is the main method. It evals animations selected in the slots for listed
|
|
* channels.
|
|
*
|
|
* Only the channels that are animated by animations selected in the slots are evaluated.
|
|
* They are stored in a linked list managed by the channel array.
|
|
*
|
|
* Others are initialized with the default channel value.
|
|
*
|
|
* \param detail true if eval the detail part of animation. (done after clipping).
|
|
* \param evalDetailDate chann mixer store the last date of anim detail evaluated. if same, do nothing,
|
|
* else if < or >, compute the anim. ingored if detail is false.
|
|
*/
|
|
void eval (bool detail, uint64 evalDetailDate=0);
|
|
|
|
/**
|
|
* Launch evaluation of some channels.
|
|
*
|
|
* \param channelIdArray array that contains the id of the channel to eval.
|
|
* \param numID number of ids in the array
|
|
*
|
|
*/
|
|
void evalChannels(sint *channelIdArray, uint numID);
|
|
|
|
/**
|
|
* Force evaluation of a single channel
|
|
*/
|
|
inline void evalSingleChannel(sint channelId);
|
|
|
|
/// \name Channel access
|
|
|
|
/**
|
|
* Add a channel for a specific value of an IAnimatable object.
|
|
* Warning: this method will assign the default value in the animated value.
|
|
*
|
|
* \param channelName is the name of the channel.
|
|
* \param animatable is a pointer on the IAnimatable object in which the value is stored. It will be kept
|
|
* by the CChannelMixer until it is removed from the channel.
|
|
* \param value is a pointer on the value the channel works with. It will be kept
|
|
* by the CChannelMixer until it is removed from the channel.
|
|
* \param defaultValue is a track used by default if a track is not presents in the animation for this channel.
|
|
* It will be kept by the CChannelMixer until it is removed from the channel.
|
|
* \param valueId is the value ID in the IAnimatable object.
|
|
* \param ownerId is the owner Bit of the animated vlaue, in the IAnimatable object. touched when the animatedvalue is touched.
|
|
* \param detail true if this channel must be evaluated in detail mode (see eval()).
|
|
* \return -1 if the track was not found in the animationSet, else it return the channelId
|
|
* as if returned by CAnimationSet::getChannelIdByName(channelName).
|
|
*/
|
|
sint addChannel (const std::string& channelName, IAnimatable* animatable, IAnimatedValue* value, ITrack* defaultValue, uint32 valueId, uint32 ownerValueId, bool detail);
|
|
|
|
/// Reset the channel list if the mixer. All channels are removed from the mixer.
|
|
void resetChannels ();
|
|
|
|
|
|
/** disabling a channel means it is no more modified during animation. Default is enabled.
|
|
* NB: this channel must have been added (via addChannel()....).
|
|
* \param channelId channelId get from CAnimationSet::getChannelIdByName() or addChannel()
|
|
*/
|
|
void enableChannel (uint channelId, bool enable);
|
|
|
|
/** see enableChannel(). return false if channel does not exist...
|
|
* \param channelId channelId get from CAnimationSet::getChannelIdByName() or addChannel()
|
|
*/
|
|
bool isChannelEnabled (uint channelId) const;
|
|
|
|
/** Same as enableChannel but for Animation Lod system. The channel is animated only if both
|
|
* enableChannel() and lodEnableChannel() are true. Default is enabled.
|
|
* NB: this channel must have been added (via addChannel()....).
|
|
* \param channelId channelId get from CAnimationSet::getChannelIdByName() or addChannel()
|
|
*/
|
|
void lodEnableChannel (uint channelId, bool enable);
|
|
|
|
/** see enableChannel(). return false if channel does not exist...
|
|
* \param channelId channelId get from CAnimationSet::getChannelIdByName() or addChannel()
|
|
*/
|
|
bool isChannelLodEnabled (uint channelId) const;
|
|
|
|
|
|
/// \name Slots acces
|
|
|
|
/**
|
|
* Set slot animation.
|
|
*
|
|
* You must set an animationSet in the channel mixer before calling this.
|
|
*
|
|
* Calling this method will dirt the mixer, ie, all the mixer's channels will
|
|
* be visited to check if they are used by the new animation. If they are, they
|
|
* will be linked in the internal CChannel list.
|
|
*
|
|
* \param slot is the slot number to change the animation. Must be >= 0 and < NumAnimationSlot.
|
|
* \param animation is the new animation index in the animationSet use by this slot.
|
|
* \see CAnimationSet, CAnimation
|
|
*/
|
|
void setSlotAnimation (uint slot, uint animation);
|
|
|
|
/// Get the animation used by a given slot
|
|
const CAnimation *getSlotAnimation(uint slot) const;
|
|
|
|
/**
|
|
* Set time of a slot.
|
|
*
|
|
* This time will be used to eval the animation set in this slot.
|
|
* Each slot can have different time.
|
|
*
|
|
* Calling this method won't dirt the mixer.
|
|
*
|
|
* \param slot is the slot number to change the time. Must be >= 0 and < NumAnimationSlot.
|
|
* \param time is the new time to use in the slot.
|
|
* \see TAnimationTime
|
|
*/
|
|
void setSlotTime (uint slot, TAnimationTime time)
|
|
{
|
|
// Check alot arg
|
|
nlassert (slot<NumAnimationSlot);
|
|
|
|
// Set the time
|
|
_SlotArray[slot]._Time=time;
|
|
}
|
|
|
|
/**
|
|
* Set slot weight.
|
|
*
|
|
* This weight will be used to eval the animation set in this slot.
|
|
* Each slot can have different weight. Calling this method won't dirt the mixer.
|
|
*
|
|
* By default the weight of the slot is 1.0f.
|
|
*
|
|
* \param slot is the slot number to change the weight.
|
|
* \param weight is the new weight to use in the slot. No range for this weight. If the weight == 0.f,
|
|
* the slot have no effect on the final mix.
|
|
*/
|
|
void setSlotWeight (uint slot, float weight)
|
|
{
|
|
// Check alot arg
|
|
nlassert (slot<NumAnimationSlot);
|
|
|
|
// Set the time
|
|
_SlotArray[slot]._Weight=weight;
|
|
}
|
|
|
|
/**
|
|
* Empty a slot.
|
|
*
|
|
* Calling this method will dirt the mixer, ie, all the mixer's channels will
|
|
* be visited to check if they are used by the old animation. If they are, they
|
|
* will be linked in the internal CChannel list.
|
|
*
|
|
* Warning: this method will assign the default value in the animated value that are removed from the active channel queue.
|
|
*
|
|
* \param slot is the slot number to empty. Must be >= 0 and < NumAnimationSlot.
|
|
*/
|
|
void emptySlot (uint slot);
|
|
|
|
/**
|
|
* Reset the slot of the mixer. All slot will be empty.
|
|
*
|
|
* Calling this method will dirt the mixer, ie, all the mixer's channels will
|
|
* be visited to check if they are used by the old animation. If they are, they
|
|
* will be linked in the internal CChannel list.
|
|
*
|
|
*/
|
|
void resetSlots ();
|
|
|
|
/**
|
|
* Apply a skeleton template weight on a specific slot.
|
|
*
|
|
* This method apply the weight of each node contains in skelWeight to the channel's slot weight.
|
|
*
|
|
* \param slot is the slot number to empty. Must be >= 0 and < NumAnimationSlot.
|
|
* \param skeleton is the index of a skeleton in the animationSet.
|
|
* \param invert is true if the weights to attach to the channels are the weights of the skeleton template.
|
|
* false if the weights to attach to the channels are the 1.f-weights of the skeleton template.
|
|
*/
|
|
void applySkeletonWeight (uint slot, uint skeleton, bool invert=false);
|
|
|
|
/**
|
|
* Reset the skeleton weight for a specific slot.
|
|
*
|
|
* This method apply set each channel's slot weight to 1.f.
|
|
*
|
|
* \param slot is the slot number to empty. Must be >= 0 and < NumAnimationSlot.
|
|
*/
|
|
void resetSkeletonWeight (uint slot);
|
|
|
|
/// reset to -1 the evalDetailDate. Hence next eval(true,..) will be forced to compute
|
|
void resetEvalDetailDate();
|
|
|
|
private:
|
|
|
|
/// /name Internal methods
|
|
|
|
/// Clean the mixer
|
|
void cleanAll ();
|
|
|
|
/// Dirt all slots
|
|
void dirtAll ();
|
|
|
|
/// Refresh channel list
|
|
void refreshList ();
|
|
|
|
// The slot array
|
|
CSlot _SlotArray[NumAnimationSlot];
|
|
|
|
// The animation set
|
|
const CAnimationSet* _AnimationSet;
|
|
|
|
// The set of CChannel infos. Only channels added by addChannel are present.
|
|
std::map<uint, CChannel> _Channels;
|
|
|
|
// The first Global channel. If NULL, no channel to animate. (animed in eval(false))
|
|
CChannel* _FirstChannelGlobal;
|
|
|
|
// The first detail channel. If NULL, no channel to animate. (animed in eval(true))
|
|
CChannel* _FirstChannelDetail;
|
|
|
|
// last date of evalDetail().
|
|
sint64 _LastEvalDetailDate;
|
|
|
|
// The channels list is dirty if true.
|
|
bool _Dirt;
|
|
|
|
// true if must update animateList. (set in refreshList())
|
|
bool _ListToEvalDirt;
|
|
|
|
// Raw lists of channels to animate, acording to _EnableFlags
|
|
std::vector<CChannel*> _GlobalListToEval;
|
|
std::vector<CChannel*> _DetailListToEval;
|
|
|
|
/// Refresh animate list
|
|
void refreshListToEval ();
|
|
|
|
/**
|
|
* Force evaluation of a single channel
|
|
*
|
|
* \param chan the channel to eval
|
|
* \param numActiveSlots number of active slots
|
|
* \param activeSlot array of contiguous slots ids (there are 'numActiveSlots' of them)
|
|
*/
|
|
void evalSingleChannel (CChannel &chan, uint numActiveSlots, uint activeSlot[NumAnimationSlot]);
|
|
};
|
|
|
|
|
|
/////////////
|
|
// INLINES //
|
|
/////////////
|
|
|
|
inline void CChannelMixer::evalSingleChannel(sint channelId)
|
|
{
|
|
evalChannels(&channelId, 1);
|
|
}
|
|
|
|
|
|
} // NL3D
|
|
|
|
|
|
#endif // NL_CHANNEL_MIXER_H
|
|
|
|
/* End of channel_mixer.h */
|