/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #ifndef PLMATRIXCHANNEL_INC #define PLMATRIXCHANNEL_INC // local #include "plScalarChannel.h" // global #include "hsTypes.h" // you need types to include Matrix #include "hsMatrix44.h" #include "plTransform/hsAffineParts.h" // local prototypes class plQuatChannel; class plPointChannel; // external prototypes class plController; class hsAffineParts; class plAnimTimeConvert; class plMatrixChannelApplicator; class plControllerCacheInfo; ////////////////// // PLMATRIXCHANNEL ////////////////// // an animation channel that outputs matrices class plMatrixChannel : public plAGChannel { protected: hsMatrix44 fResult; hsAffineParts fAP; public: plMatrixChannel(); virtual ~plMatrixChannel(); // AG PROTOCOL virtual const hsMatrix44 & Value(double time, bool peek = false); virtual void Value(hsMatrix44 &matrix, double time, bool peek = false); virtual const hsAffineParts & AffineValue(double time, bool peek = false); // combine it (allocates combine object) virtual plAGChannel * MakeCombine(plAGChannel * channelB); // blend it (allocates blend object) virtual plAGChannel * MakeBlend(plAGChannel * channelB, plScalarChannel * channelBias, int blendPriority); // const eval at time zero virtual plAGChannel * MakeZeroState(); // make a timeScale instance virtual plAGChannel * MakeTimeScale(plScalarChannel *timeSource); virtual plAGPinType GetPinType() { return kAGPinTransform; }; virtual void Dump(int indent, bool optimized, double time); // PLASMA PROTOCOL CLASSNAME_REGISTER( plMatrixChannel ); GETINTERFACE_ANY( plMatrixChannel, plAGChannel ); }; /////////////////// // PLMATRIXCONSTANT /////////////////// // A matrix source that just keeps handing out the same value class plMatrixConstant : public plMatrixChannel { public: plMatrixConstant(); plMatrixConstant(const hsMatrix44 &value); virtual ~plMatrixConstant(); void Set(const hsMatrix44 &value); // PLASMA PROTOCOL CLASSNAME_REGISTER( plMatrixConstant ); GETINTERFACE_ANY( plMatrixConstant, plMatrixChannel ); virtual void Write(hsStream *stream, hsResMgr *mgr); virtual void Read(hsStream *s, hsResMgr *mgr); }; //////////////////// // PLMATRIXTIMESCALE //////////////////// // Adapts the time scale before passing it to the next channel in line. // Use to instance animations while allowing each instance to run at different speeds. class plMatrixTimeScale : public plMatrixChannel { protected: plScalarChannel *fTimeSource; plMatrixChannel *fChannelIn; public: plMatrixTimeScale(); plMatrixTimeScale(plMatrixChannel *channel, plScalarChannel *timeSource); virtual ~plMatrixTimeScale(); virtual hsBool IsStoppedAt(double time); virtual const hsMatrix44 & Value(double time, bool peek = false); virtual const hsAffineParts & AffineValue(double time, bool peek = false); virtual plAGChannel * Detach(plAGChannel * channel); virtual void Dump(int indent, bool optimized, double time); // PLASMA PROTOCOL CLASSNAME_REGISTER( plMatrixTimeScale ); GETINTERFACE_ANY( plMatrixTimeScale, plMatrixChannel ); }; //////////////// // PLMATRIXBLEND //////////////// // blends two matrices into one with weighting class plMatrixBlend : public plMatrixChannel { protected: plMatrixChannel * fChannelA; plMatrixChannel * fOptimizedA; plMatrixChannel * fChannelB; plMatrixChannel * fOptimizedB; plScalarChannel * fChannelBias; int fPriority; public: // xTORs plMatrixBlend(); plMatrixBlend(plMatrixChannel * channelA, plMatrixChannel * channelB, plScalarChannel * channelBias, int priority); virtual ~plMatrixBlend(); virtual plAGChannel * MakeBlend(plAGChannel *newChannel, plScalarChannel *channelBias, int blendPriority); // you cannot blend on top of a channel that has higher priority than you do. virtual UInt16 GetPriority(); // SPECIFICS const plMatrixChannel * GetChannelA() const { return fChannelA; } void SetChannelA(plMatrixChannel * channel) { fChannelA = channel; } const plMatrixChannel * GetChannelB() const { return fChannelB; } void SetChannelB(plMatrixChannel * channel) { fChannelB = channel; } const plScalarChannel * GetChannelBias() const { return fChannelBias; } void SetChannelBias(plScalarChannel * channel) { fChannelBias = channel; } //virtual void SetBlend(float blend) { fBlend = blend; }; //virtual float GetBlend() { return fBlend; }; virtual hsBool IsStoppedAt(double time); // AG PROTOCOL virtual const hsMatrix44 & Value(double time, bool peek = false); virtual const hsAffineParts & AffineValue(double time, bool peek = false); // remove the specified channel from our graph virtual plAGChannel * Detach(plAGChannel * channel); virtual void Dump(int indent, bool optimized, double time); plAGChannel* Optimize(double time); // PLASMA PROTOCOL CLASSNAME_REGISTER( plMatrixBlend ); GETINTERFACE_ANY( plMatrixBlend, plMatrixChannel ); }; ///////////////////// // PLMATRIXCONTROLLER ///////////////////// // converts a plController-style animation into a plMatrixChannel class plMatrixControllerChannel : public plMatrixChannel { protected: plController *fController; public: // xTORs plMatrixControllerChannel(); plMatrixControllerChannel(plController *controller, hsAffineParts *parts); virtual ~plMatrixControllerChannel(); // AG PROTOCOL virtual const hsAffineParts & AffineValue(double time, bool peek = false); virtual const hsAffineParts & AffineValue(double time, bool peek, plControllerCacheInfo *cache); virtual const hsMatrix44 & Value(double time, bool peek = false); virtual const hsMatrix44 & Value(double time, bool peek, plControllerCacheInfo *cache); virtual plAGChannel * MakeCacheChannel(plAnimTimeConvert *atc); virtual void Dump(int indent, bool optimized, double time); // PLASMA PROTOCOL // rtti CLASSNAME_REGISTER( plMatrixControllerChannel ); GETINTERFACE_ANY( plMatrixControllerChannel, plMatrixChannel ); // persistence virtual void Write(hsStream *stream, hsResMgr *mgr); virtual void Read(hsStream *s, hsResMgr *mgr); }; ///////////////////////////////// // PLMATRIXCONTROLLERCACHECHANNEL ///////////////////////////////// // Same as plMatrixController, but with caching info class plMatrixControllerCacheChannel : public plMatrixChannel { protected: plControllerCacheInfo *fCache; plMatrixControllerChannel *fControllerChannel; public: plMatrixControllerCacheChannel(); plMatrixControllerCacheChannel(plMatrixControllerChannel *channel, plControllerCacheInfo *cache); virtual ~plMatrixControllerCacheChannel(); virtual const hsMatrix44 & Value(double time, bool peek = false); virtual const hsAffineParts & AffineValue(double time, bool peek = false); virtual plAGChannel * Detach(plAGChannel * channel); // PLASMA PROTOCOL CLASSNAME_REGISTER( plMatrixControllerCacheChannel ); GETINTERFACE_ANY( plMatrixControllerCacheChannel, plMatrixChannel ); // Created at runtime only, so no Read/Write }; ///////////////////// // PLQUATPOINTCOMBINE ///////////////////// // combines a quaternion and a point into a matrix class plQuatPointCombine : public plMatrixChannel { protected: plQuatChannel *fQuatChannel; plPointChannel *fPointChannel; public: // xTORs plQuatPointCombine(); plQuatPointCombine(plQuatChannel *quatChannel, plPointChannel *pointChannel); virtual ~plQuatPointCombine(); // SPECIFICS const plQuatChannel * GetQuatChannel() const { return fQuatChannel; } void SetQuatChannel(plQuatChannel * channel) { fQuatChannel = channel; } plPointChannel * GetPointChannel() const { return fPointChannel; } void SetPointChannel(plPointChannel * channel) { fPointChannel = channel; } // AG PROTOCOL virtual const hsMatrix44 & Value(double time); virtual const hsAffineParts & AffineValue(double time); // remove the specified channel from our graph virtual plAGChannel * Detach(plAGChannel * channel); // PLASMA PROTOCOL CLASSNAME_REGISTER( plQuatPointCombine ); GETINTERFACE_ANY( plQuatPointCombine, plMatrixChannel ); }; ///////////////////// // // Applicator classes class plMatrixChannelApplicator : public plAGApplicator { protected: virtual void IApply(const plAGModifier *mod, double time); public: CLASSNAME_REGISTER( plMatrixChannelApplicator ); GETINTERFACE_ANY( plMatrixChannelApplicator, plAGApplicator ); virtual hsBool CanCombine(plAGApplicator *app) { return false; } virtual plAGPinType GetPinType() { return kAGPinTransform; } }; // PLMATRIXDELAYEDCORRECTIONAPPLICATOR // Used for blending in sudden location changes due to synch messages. // This app tacks on a correction to the l2p transform // (so l2p is set as animL2P*correction) // interpolating this to the identity matrix over time. class plMatrixDelayedCorrectionApplicator : public plMatrixChannelApplicator { protected: hsAffineParts fCorAP; // AP of the correction. double fDelayStart; // Start time of the delayed correction // apply our animation * our correction to the node virtual void IApply(const plAGModifier *mod, double time); public: plMatrixDelayedCorrectionApplicator() : fDelayStart(-1000.f), fIgnoreNextCorrection(true) { fCorAP.Reset(); } CLASSNAME_REGISTER( plMatrixDelayedCorrectionApplicator ); GETINTERFACE_ANY( plMatrixDelayedCorrectionApplicator, plMatrixChannelApplicator ); void SetCorrection(hsMatrix44 &correction); virtual hsBool AutoDelete() { return false; } // should we remove it when its input channel is gone? // applicator arbitration... virtual plAGPinType GetPinType() { return kAGPinTransform; } virtual hsBool CanBlend(plAGApplicator *app); hsBool fIgnoreNextCorrection; static const hsScalar fDelayLength; // static var for now. }; // PLMATRIXDIFFERENCEAPP // Each frame, this guy takes the difference between his current value // and his last value and applies that to the current world // transform of the target. // You could also call it the Temporal Matrix Difference Applicator, // but that sucks to type. class plMatrixDifferenceApp : public plMatrixChannelApplicator { public: /** Forget the previous cached transform and start again */ void Reset(double time); /** Should this applicator be automatically removed when its channel goes away? */ virtual hsBool AutoDelete() { return false; } // applicator arbitration virtual plAGPinType GetPinType() { return kAGPinTransform; } virtual hsBool CanBlend(plAGApplicator *app); CLASSNAME_REGISTER(plMatrixDifferenceApp); GETINTERFACE_ANY(plMatrixDifferenceApp, plMatrixChannelApplicator); protected: virtual void IApply(const plAGModifier *mod, double time); hsMatrix44 fLastL2A; // local to animation space hsMatrix44 fLastA2L; // animation space to local bool fNew; // true if we haven't cached anything yet }; #endif