/********************************************************************** *< FILE: control.h DESCRIPTION: Control definitions CREATED BY: Dan Silva and Rolf Berteig HISTORY: created 9 September 1994 *> Copyright (c) 1994, All Rights Reserved. **********************************************************************/ #ifndef __CONTROL__ #define __CONTROL__ #include "plugapi.h" extern CoreExport void ApplyScaling(Matrix3 &m, const ScaleValue &v); extern CoreExport void InitControlLists(); class ScaleValue; class ViewExp; class INode; class XFormModes; class INodeTab; class View; CoreExport ScaleValue operator+(const ScaleValue& s0, const ScaleValue& s1); CoreExport ScaleValue operator-(const ScaleValue& s0, const ScaleValue& s1); CoreExport ScaleValue operator*(const ScaleValue& s, float f); CoreExport ScaleValue operator*(float f, const ScaleValue& s); CoreExport ScaleValue operator+(const ScaleValue& s, float f); CoreExport ScaleValue operator+(float f, const ScaleValue& s); class ScaleValue { public: Point3 s; Quat q; ScaleValue() {} ScaleValue(const Point3& as) { s = as; q = IdentQuat(); } ScaleValue(const Point3& as, const Quat& aq) {s = as; q = aq;} ScaleValue& operator+=(const ScaleValue& s) {(*this)=(*this)+s;return (*this);} ScaleValue& operator*=(const float s) {(*this)=(*this)*s;return (*this);} ScaleValue& operator=(const ScaleValue &v) {s=v.s;q=v.q;return (*this);} float& operator[](int el) {return s[el];} }; // Types of ORTs #define ORT_BEFORE 1 #define ORT_AFTER 2 // ORTs #define ORT_CONSTANT 1 #define ORT_CYCLE 2 #define ORT_LOOP 3 // This is cycle with continuity. #define ORT_OSCILLATE 4 #define ORT_LINEAR 5 #define ORT_IDENTITY 6 #define ORT_RELATIVE_REPEAT 7 // This structure is for collecting the return results of // GetLocalTMComponents(). struct TMComponentsArg { TMComponentsArg():position(0),rotation(0),scale(0),rotRep(kUnknown) {} TMComponentsArg(Point3* pos, Interval* posInv, float* rot, Interval* rotInv, ScaleValue* scl, Interval* sclInv) : position(pos),posValidity(posInv),rotation(rot),rotValidity(rotInv) , scale(scl),sclValidity(sclInv) {} enum RotationRep { // kXYZ should equals EULERTYPE_XYZ, which is 0.(c.f. euler.h) kXYZ, kXZY, kYZX, kYXZ, kZXY, kZYX, kXYX, kYZY, kZXZ, kQuat, kUnknown }; Point3* position; Interval* posValidity; // if not null, rotation should be a float[4] float* rotation; Interval* rotValidity; RotationRep rotRep; ScaleValue* scale; Interval* sclValidity; }; // An object of this class represents a Matrix3. However, its value can be // obtained only by invoking the operator(). Derived classes may override // this operator to delay its computation until operator() is called. // class Matrix3Indirect { public: Matrix3Indirect(){} Matrix3Indirect(const Matrix3& m):mat(m){} virtual ~Matrix3Indirect(){} virtual const Matrix3& operator()() const { return mat; } virtual void Set(const Matrix3& m) { mat = m; } virtual Matrix3Indirect* Clone() const {return new Matrix3Indirect(mat);} virtual void PreTranslate(const Point3& p){ mat.PreTranslate(p);} virtual void PreRotateX(float x){ mat.PreRotateX(x); } virtual void PreRotateY(float y){ mat.PreRotateY(y); } virtual void PreRotateZ(float z){ mat.PreRotateZ(z); } virtual void PreRotate(const Quat& q){PreRotateMatrix(mat,q);} protected: Matrix3 mat; }; /*---------------------------------------------------------------------*/ // A list of ease curves. class EaseCurveList : public ReferenceTarget { friend class AddEaseRestore; friend class DeleteEaseRestore; private: Tab eases; public: EaseCurveList() {OpenTreeEntry(1,ALL_TRACK_VIEWS);} CoreExport ~EaseCurveList(); CoreExport TimeValue ApplyEase(TimeValue t,Interval &valid); CoreExport void AppendEaseCurve(Control *cont); CoreExport void DeleteEaseCurve(int i); CoreExport void DisableEaseCurve(int i); CoreExport void EnableEaseCurve(int i); CoreExport BOOL IsEaseEnabled(int i); int NumEaseCurves() {return eases.Count();} // Animatable void GetClassName(TSTR& s) { s= TSTR(_T("EaseCurve")); } Class_ID ClassID() { return Class_ID(EASE_LIST_CLASS_ID,0); } SClass_ID SuperClassID() { return EASE_LIST_CLASS_ID; } CoreExport int NumSubs(); CoreExport Animatable* SubAnim(int i); CoreExport TSTR SubAnimName(int i); int SubNumToRefNum(int subNum) {return subNum;} BOOL BypassTreeView() { return TRUE; } void DeleteThis() { delete this; } ParamDimension* GetParamDimension(int i) {return stdTimeDim;} CoreExport BOOL AssignController(Animatable *control,int subAnim); CoreExport void* GetInterface(ULONG id); CoreExport IOResult Save(ISave *isave); CoreExport IOResult Load(ILoad *iload); // Reference CoreExport int NumRefs(); CoreExport RefTargetHandle GetReference(int i); CoreExport void SetReference(int i, RefTargetHandle rtarg); CoreExport RefTargetHandle Clone(RemapDir &remap = NoRemap()); CoreExport RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message); }; class EaseCurveAnimProp : public AnimProperty { public: EaseCurveList *el; EaseCurveAnimProp() { el=NULL; } DWORD ID() {return PROPID_EASELIST;} }; #define GetEaseListInterface(anim) ((EaseCurveList*)anim->GetInterface(I_EASELIST)) /*---------------------------------------------------------------------*/ // A list of multiplier curves. class MultCurveList : public ReferenceTarget { friend class AddMultRestore; friend class DeleteMultRestore; private: Tab mults; public: MultCurveList() {OpenTreeEntry(1,ALL_TRACK_VIEWS);} CoreExport ~MultCurveList(); CoreExport float GetMultVal(TimeValue t,Interval &valid); CoreExport void AppendMultCurve(Control *cont); CoreExport void DeleteMultCurve(int i); CoreExport void DisableMultCurve(int i); CoreExport void EnableMultCurve(int i); CoreExport BOOL IsMultEnabled(int i); int NumMultCurves() {return mults.Count();} // Animatable void GetClassName(TSTR& s) { s= TSTR(_T("MultCurve")); } Class_ID ClassID() { return Class_ID(MULT_LIST_CLASS_ID,0); } SClass_ID SuperClassID() { return MULT_LIST_CLASS_ID; } CoreExport int NumSubs(); CoreExport Animatable* SubAnim(int i); CoreExport TSTR SubAnimName(int i); int SubNumToRefNum(int subNum) {return subNum;} BOOL BypassTreeView() { return TRUE; } void DeleteThis() { delete this; } ParamDimension* GetParamDimension(int i) {return stdNormalizedDim;} CoreExport BOOL AssignController(Animatable *control,int subAnim); CoreExport void* GetInterface(ULONG id); CoreExport IOResult Save(ISave *isave); CoreExport IOResult Load(ILoad *iload); // Reference CoreExport int NumRefs(); CoreExport RefTargetHandle GetReference(int i); CoreExport void SetReference(int i, RefTargetHandle rtarg); CoreExport RefTargetHandle Clone(RemapDir &remap = NoRemap()); CoreExport RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message); }; class MultCurveAnimProp : public AnimProperty { public: MultCurveList *ml; MultCurveAnimProp() { ml=NULL; } DWORD ID() {return PROPID_MULTLIST;} }; #define GetMultListInterface(anim) ((MultCurveList*)anim->GetInterface(I_MULTLIST)) /*---------------------------------------------------------------------*/ // // For hit testing controller apparatus // class CtrlHitRecord { friend class CtrlHitLog; CtrlHitRecord *next; public: INode *nodeRef; DWORD distance; ulong hitInfo; DWORD infoExtra; CtrlHitRecord() {next=NULL; distance=0; hitInfo=0; nodeRef=NULL;} CtrlHitRecord(CtrlHitRecord *nxt,INode *nr, DWORD d, ulong inf, DWORD extra) { next=nxt;nodeRef=nr;distance=d;hitInfo=inf;infoExtra=extra;} CtrlHitRecord *Next() {return next;} }; class CtrlHitLog { CtrlHitRecord *first; int hitIndex; public: CtrlHitLog() { first = NULL; } ~CtrlHitLog() { Clear(); } CoreExport void Clear(); CoreExport void ClearHitIndex() { hitIndex = 0; } CoreExport void IncrHitIndex() { hitIndex++; } CtrlHitRecord* First() { return first; } CoreExport CtrlHitRecord* ClosestHit(); void LogHit(INode *nr,DWORD dist,ulong info,DWORD infoExtra) {first = new CtrlHitRecord(first,nr,dist,info,infoExtra);} }; // For enumerating IK paramaters class IKEnumCallback { public: virtual void proc(Control *c, int index)=0; }; class IKDeriv { public: virtual int NumEndEffectors()=0; virtual Point3 EndEffectorPos(int index)=0; virtual void DP(Point3 dp,int index)=0; virtual void DR(Point3 dr,int index)=0; virtual void NextDOF()=0; }; // Flags passed to CompDerivs #define POSITION_DERIV (1<<0) #define ROTATION_DERIV (1<<1) // This class is used to store IK parameters that have been // copied to a clipboard. class IKClipObject { public: // Identifies the creator of the clip object virtual SClass_ID SuperClassID()=0; virtual Class_ID ClassID()=0; virtual void DeleteThis()=0; }; // Values for 'which' pasted to Copy/PasteIKParams #define COPYPASTE_IKPOS 1 #define COPYPASTE_IKROT 2 // Passed to InitIKJoints() which is called when importing // R4 3DS files that have IK joint data. class InitJointData { public: BOOL active[3]; BOOL limit[3]; BOOL ease[3]; Point3 min, max, damping; }; // New for R4: include preferred angle class InitJointData2 : public InitJointData { public: Point3 preferredAngle; DWORD flags; // not used (must be 0) - for future expansion InitJointData2() {flags=0;} }; // This structure is passed to GetDOFParams(). // Controllers that support IK can provide info about their DOFs // so that bones can display this information. // The first 3 DOFs are assumed to be position // and the next 3 are assumed to be rotation class DOFParams { public: BOOL display[6]; // Should this DOF be displayed? Point3 axis[6]; // DOF axis Point3 pos[6]; // Base of axis BOOL limit[6]; // is joint limited? float min[6]; // min limit float max[6]; // max limit float curval[6]; // Current value of the parameter BOOL sel[6]; // should DOF be highlighted BOOL endEffector; // is there an end effector for this controller Matrix3 eeTM; // world TM of the end effector if present }; // These two ways values can be retreived or set. // For get: // RELATIVE = Apply // ABSOLUTE = Just get the value // For set: // RELATIVE = Add the value to the existing value (i.e Move/Rotate/Scale) // ABSOLUTE = Just set the value enum GetSetMethod {CTRL_RELATIVE,CTRL_ABSOLUTE}; // Control class provides default implementations for load and save which save the ORT type in these chunks: #define CONTROLBASE_CHUNK 0x8499 #define INORT_CHUNK 0x3000 #define OUTORT_CHUNK 0x3001 #define CONT_DISABLED_CHUNK 0x3002 // Inheritance flags. #define INHERIT_POS_X (1<<0) #define INHERIT_POS_Y (1<<1) #define INHERIT_POS_Z (1<<2) #define INHERIT_ROT_X (1<<3) #define INHERIT_ROT_Y (1<<4) #define INHERIT_ROT_Z (1<<5) #define INHERIT_SCL_X (1<<6) #define INHERIT_SCL_Y (1<<7) #define INHERIT_SCL_Z (1<<8) #define INHERIT_ALL 511 class Control : public ReferenceTarget { public: Control() {SetORT(ORT_CONSTANT,ORT_BEFORE);SetORT(ORT_CONSTANT,ORT_AFTER);}; virtual ~Control() {}; virtual void Copy(Control *from)=0; virtual void CommitValue(TimeValue t) {} virtual void RestoreValue(TimeValue t) {} virtual INode* GetTarget() { return NULL; } virtual RefResult SetTarget(INode *targ) {return REF_SUCCEED;} // Implemented by transform controllers that have position controller // that can be edited in the trajectory branch virtual Control *GetPositionController() {return NULL;} virtual Control *GetRotationController() {return NULL;} virtual Control *GetScaleController() {return NULL;} virtual BOOL SetPositionController(Control *c) {return FALSE;} virtual BOOL SetRotationController(Control *c) {return FALSE;} virtual BOOL SetScaleController(Control *c) {return FALSE;} // If a controller has an 'X', 'Y', or 'Z' controller, it can implement // these methods so that its sub controllers can respect track view filters virtual Control *GetXController() {return NULL;} virtual Control *GetYController() {return NULL;} virtual Control *GetZController() {return NULL;} // Implemented by look at controllers that have a float valued roll // controller so that the roll can be edited via the transform type-in virtual Control *GetRollController() {return NULL;} virtual BOOL SetRollController(Control *c) {return FALSE;} // Implemented by any Point3 controller that wishes to indicate that it is intended // to control floating point RGB color values virtual BOOL IsColorController() {return FALSE;} // Implemented by TM controllers that support // filtering out inheritance virtual DWORD GetInheritanceFlags() {return INHERIT_ALL;} virtual BOOL SetInheritanceFlags(DWORD f,BOOL keepPos) {return FALSE;} // return TRUE if TM controller supports inheritance virtual BOOL IsLeaf() {return TRUE;} virtual int IsKeyable() {return 1;} // If a controller does not want to allow another controller // to be assigned on top of it, it can return FALSE to this method. virtual BOOL IsReplaceable() {return TRUE;} // This is called on TM, pos, rot, and scale controllers when their // input matrix is about to change. If they return FALSE, the node will // call SetValue() to make the necessary adjustments. virtual BOOL ChangeParents(TimeValue t,const Matrix3& oldP,const Matrix3& newP,const Matrix3& tm) {return FALSE;} // val points to an instance of a data type that corresponds with the controller // type. float for float controllers, etc. // Note that for SetValue on Rotation controllers, if the SetValue is // relative, val points to an AngAxis while if it is absolute it points // to a Quat. virtual void GetValue(TimeValue t, void *val, Interval &valid, GetSetMethod method=CTRL_ABSOLUTE)=0; virtual void SetValue(TimeValue t, void *val, int commit=1, GetSetMethod method=CTRL_ABSOLUTE)=0; // Definition: LocalMatrix = WorldMatrix * ParentWorldMatrix^(-1) // This method returns the PRS components of the local // matrix. In general, controller cannot decide on the local matrix // without knowing the parent matrix. However, many // controllers, such as default controllers, are well defined // without the parent matrix. In these cases, it is more // efficient compute the local components directly without // going through the world matrix. Therefore, the argument // parentMatrix is a reference to Matrix3Indirect. This would // allow clients to supply a "delayed parent matrix," which // will be computed only if it is necessary. It returns true // for Matrix3, Position, Rotation, or Scale controllers, and // return false otherwise. // The PRS components will be put in argument cmpts in the // respective fields with corresponding validity // intervals. NULL pointer, of TMComponentsArg::position for // example, indicates that the client is not concerned about // the component. When it is not NULL, the corresponding // pointer to the validity interval MUST NOT be NULL. When it // is not NULL, TMComponentsArg::rotation is a float[4]. // rotRep tells what the numbers mean. // Position, Rotation, or Scale, controllers will put results // at the respective component when the corresponding pointer // is not NULL. // Upon entry, parentMatrix should represent the parent matrix up // to the first requested components. For Matrix3 controllers, for // example, if cmpts.position==NULL && cmpts.rotation!=NULL, then // parentMatrix should be matrix that includes the parent node matrix // plus the position of this node. Upon return, this matrix may be // modified. CoreExport virtual bool GetLocalTMComponents(TimeValue t, TMComponentsArg& cmpts, Matrix3Indirect& parentMatrix); // Transform controllers that do not inherit their parent's transform // should override this method. Returning FALSE will cause SetValue // to be called even in the case when the parent is also being transformed. virtual BOOL InheritsParentTransform() { return TRUE; } virtual int GetORT(int type) {return (aflag>>(type==ORT_BEFORE?A_ORT_BEFORESHIFT:A_ORT_AFTERSHIFT))&A_ORT_MASK;} CoreExport virtual void SetORT(int ort,int type); // Sets the enabled/disabled state for ORTs CoreExport virtual void EnableORTs(BOOL enable); // Default implementations of load and save handle loading and saving of out of range type. // Call these from derived class load and save. // NOTE: Must call these before any of the derived class chunks are loaded or saved. CoreExport IOResult Save(ISave *isave); CoreExport IOResult Load(ILoad *iload); // For IK // Note: IK params must be given in the order they are applied to // the parent matrix. When derivatives are computed for a parameter // that parameter will apply itself to the parent matrix so the next // parameter has the appropriate reference frame. If a controller isn't // participating in IK then it should return FALSE and the client (usually PRS) // will apply the controller's value to the parent TM. virtual void EnumIKParams(IKEnumCallback &callback) {} virtual BOOL CompDeriv(TimeValue t,Matrix3& ptm,IKDeriv& derivs,DWORD flags) {return FALSE;} virtual float IncIKParam(TimeValue t,int index,float delta) {return 0.0f;} virtual void ClearIKParam(Interval iv,int index) {return;} virtual BOOL CanCopyIKParams(int which) {return FALSE;} virtual IKClipObject *CopyIKParams(int which) {return NULL;} virtual BOOL CanPasteIKParams(IKClipObject *co,int which) {return FALSE;} virtual void PasteIKParams(IKClipObject *co,int which) {} virtual void InitIKJoints(InitJointData *posData,InitJointData *rotData) {} virtual BOOL GetIKJoints(InitJointData *posData,InitJointData *rotData) {return FALSE;} virtual BOOL GetDOFParams(TimeValue t,Matrix3 &ptm,DOFParams &dofs,BOOL nodeSel) {return FALSE;} virtual BOOL CreateLockKey(TimeValue t, int which) {return FALSE;} virtual void MirrorIKConstraints(int axis,int which,BOOL pasteMirror=FALSE) {} virtual BOOL TerminateIK() {return FALSE;} // controllers can act as terminators. // New for R4 virtual void InitIKJoints2(InitJointData2 *posData,InitJointData2 *rotData) {} virtual BOOL GetIKJoints2(InitJointData2 *posData,InitJointData2 *rotData) {return FALSE;} // Called on a transform controller when the a message is received from a pin node virtual RefResult PinNodeChanged(RefMessage message,Interval changeInt, PartID &partID) {return REF_SUCCEED;} // Called on a transform controller when one of the node level IK parameters has been changed virtual void NodeIKParamsChanged() {} // Called in a transform controller when a node invalidates its TM cache virtual void TMInvalidated() {} // Let's the TM controller determine if it's OK to bind (IK bind) to a particular node. virtual BOOL OKToBindToNode(INode *node) {return TRUE;} // Ease curves virtual BOOL CanApplyEaseMultCurves() {return TRUE;} CoreExport TimeValue ApplyEase(TimeValue t,Interval &valid); CoreExport void AppendEaseCurve(Control *cont); CoreExport void DeleteEaseCurve(int i); CoreExport int NumEaseCurves(); // Multiplier curves CoreExport float GetMultVal(TimeValue t,Interval &valid); CoreExport void AppendMultCurve(Control *cont); CoreExport void DeleteMultCurve(int i); CoreExport int NumMultCurves(); // These are implemented to handle ease curves. If a controller // is a leaf controller, then it MUST NOT BY DEFINITION have any // sub controllers or references. If it is a leaf controller, then // these are implemented to handle the ease curve list. // If it is NOT a leaf controller, then these can be overridden. CoreExport int NumRefs(); CoreExport RefTargetHandle GetReference(int i); CoreExport void SetReference(int i, RefTargetHandle rtarg); CoreExport int NumSubs(); CoreExport Animatable* SubAnim(int i); CoreExport TSTR SubAnimName(int i); // Default implementations of some Animatable methods CoreExport void* GetInterface(ULONG id); CoreExport int PaintFCurves( ParamDimensionBase *dim, HDC hdc, Rect& rcGraph, Rect& rcPaint, float tzoom, int tscroll, float vzoom, int vscroll, DWORD flags ); CoreExport int GetFCurveExtents( ParamDimensionBase *dim, float &min, float &max, DWORD flags); // This is called on transform controller after a node is // cloned and the clone process has finished virtual void PostCloneNode() {} // Slave TM controllers can implement this to prevent plug-ins // deleting their node via the DeleteNode API. virtual BOOL PreventNodeDeletion() {return FALSE;} // New interface for visibility float controllers to allow view dependent visibility // The default implementation will call GetValue() CoreExport virtual float EvalVisibility(TimeValue t,View &view,Box3 pbox,Interval &valid); // Called on visibility controllers. Gives them the option to completely hide an object in the viewports virtual BOOL VisibleInViewports() {return TRUE;} // Called on transform controllers or visibility controllers when a node is cloned and the user has chosen to instance virtual BOOL CanInstanceController() {return TRUE;} // Should be called by any leaf controller's clone method so // that ease and multipier curves are cloned. CoreExport void CloneControl(Control *ctrl,RemapDir &remap); //------------------------------------------------------- // Controllers that wish to have an apparatus available in // the scene will implement these methods: // NOTE: Most of these methods are duplicated in BaseObject or Object // (see object.h for descriptions). virtual int Display(TimeValue t, INode* inode, ViewExp *vpt, int flags) { return 0; }; virtual int HitTest(TimeValue t, INode* inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt) { return 0; } virtual void GetWorldBoundBox(TimeValue t,INode* inode, ViewExp *vpt, Box3& box) {} virtual void ActivateSubobjSel(int level, XFormModes& modes ) {} virtual void SelectSubComponent(CtrlHitRecord *hitRec, BOOL selected, BOOL all, BOOL invert=FALSE) {} virtual void ClearSelection(int selLevel) {} virtual int SubObjectIndex(CtrlHitRecord *hitRec) {return 0;} virtual void SelectAll(int selLevel) {} virtual void InvertSelection(int selLevel) {} virtual void GetSubObjectCenters(SubObjAxisCallback *cb,TimeValue t,INode *node) {} virtual void GetSubObjectTMs(SubObjAxisCallback *cb,TimeValue t,INode *node) {} // Modify sub object apparatuses virtual void SubMove( TimeValue t, Matrix3& partm, Matrix3& tmAxis, Point3& val, BOOL localOrigin=FALSE ){} virtual void SubRotate( TimeValue t, Matrix3& partm, Matrix3& tmAxis, Quat& val, BOOL localOrigin=FALSE ){} virtual void SubScale( TimeValue t, Matrix3& partm, Matrix3& tmAxis, Point3& val, BOOL localOrigin=FALSE ){} // Schematic View Animatable Overides... CoreExport SvGraphNodeReference SvTraverseAnimGraph(IGraphObjectManager *gom, Animatable *object, int id, DWORD flags); // Called when the user rescales time in the time configuration dialog. If FALSE // is returned from this method then MapKeys() will be used to perform the scaling. // Controllers can override this method to handle things like rescaling tagents that // MapKeys() won't affect and return TRUE if they don't want map keys to be called. virtual BOOL RescaleTime(Interval oseg, Interval nseg) {return FALSE;} //watje these are to allow a control to get sampled at a different rate than //what trackview does by default so the controller can speed up redraws //this is the pixel sample rate for when the curve is drawn virtual int GetDrawPixelStep() {return 5;} //this is the ticks sample rate for when the curve is checked for its y extents virtual int GetExtentTimeStep() {return 40;} }; // Any controller that does not evaluate itself as a function of it's // input can subclass off this class. // GetValueLocalTime() will never ask the controller to apply the value, // it will always ask for it absolute. class StdControl : public Control { public: virtual void GetValueLocalTime(TimeValue t, void *val, Interval &valid, GetSetMethod method=CTRL_ABSOLUTE)=0; virtual void SetValueLocalTime(TimeValue t, void *val, int commit=1, GetSetMethod method=CTRL_ABSOLUTE)=0; CoreExport void GetValue(TimeValue t, void *val, Interval &valid, GetSetMethod method=CTRL_ABSOLUTE); CoreExport void SetValue(TimeValue t, void *val, int commit=1, GetSetMethod method=CTRL_ABSOLUTE); // Computes the local components without calling parentMatrix // for position, rotation, and Scale controllers. CoreExport bool GetLocalTMComponents(TimeValue t, TMComponentsArg& cmpts, Matrix3Indirect& parentMatrix); virtual void Extrapolate(Interval range,TimeValue t,void *val,Interval &valid,int type)=0; virtual void *CreateTempValue()=0; virtual void DeleteTempValue(void *val)=0; virtual void ApplyValue(void *val, void *delta)=0; virtual void MultiplyValue(void *val, float m)=0; }; // Each super class of controller may have a specific packet defined that // the 'val' pointer will point to instead of a literal value. // In reality, probably only the Transform controller will do this. enum SetXFormCommand { XFORM_MOVE, XFORM_ROTATE, XFORM_SCALE, XFORM_SET }; class SetXFormPacket { public: SetXFormCommand command; Matrix3 tmParent; Matrix3 tmAxis; // if command is XFORM_SET, this will contain the new value for the XFORM. Point3 p; Quat q; AngAxis aa; BOOL localOrigin; // XFORM_SET SetXFormPacket(const Matrix3& mat,const Matrix3& par=Matrix3(1)) {command=XFORM_SET,tmParent=par,tmAxis=mat;} // XFORM_MOVE SetXFormPacket(Point3 pt, const Matrix3& par=Matrix3(1), const Matrix3& a=Matrix3(1)) {command=XFORM_MOVE;tmParent=par;tmAxis=a;p=pt;localOrigin=FALSE;} // XFORM_ROTATE SetXFormPacket(Quat qt, BOOL l, const Matrix3& par=Matrix3(1), const Matrix3& a=Matrix3(1)) {command=XFORM_ROTATE;tmParent=par;tmAxis=a;q=qt;aa=AngAxis(q);localOrigin=l;} SetXFormPacket(AngAxis aA, BOOL l, const Matrix3& par=Matrix3(1), const Matrix3& a=Matrix3(1)) {command=XFORM_ROTATE;tmParent=par;tmAxis=a;q=Quat(aA);aa=aA;localOrigin=l;} // XFORM_SCALE SetXFormPacket(Point3 pt, BOOL l, const Matrix3& par=Matrix3(1), const Matrix3& a=Matrix3(1)) {command=XFORM_SCALE;tmParent=par;tmAxis=a;p=pt;localOrigin=l;} // Just in case you want to do it by hand... SetXFormPacket() {}; }; // This is a special control base class for controllers that control // morphing of geomoetry. // // The 'val' pointer used with GetValue will point to an object state. // This would be the result of evaluating a combination of targets and // producing a new object that is some combination of the targets. // // The 'val' pointer used with SetValue will point to a // SetMorphTargetPacket data structure. This has a pointer to // an object (entire pipeline) and the name of the target. // A pointer to one of these is passed to SetValue class SetMorphTargetPacket { public: Matrix3 tm; Object *obj; TSTR name; BOOL forceCreate; // Make sure the key is created even if it is at frame 0 SetMorphTargetPacket(Object *o,TSTR n,Matrix3 &m,BOOL fc=FALSE) {obj = o;name = n;tm = m;forceCreate=fc;} SetMorphTargetPacket(Object *o,TSTR n,BOOL fc=FALSE) {obj = o;name = n;tm = Matrix3(1);forceCreate=fc;} }; class MorphControl : public Control { public: // Access the object pipelines of the controller's targets. Note // that these are pointers to the pipelines, not the result of // evaluating the pipelines. virtual int NumMorphTargs() {return 0;} virtual Object *GetMorphTarg(int i) {return NULL;} virtual void DeleteMorphTarg(int i) {} virtual void GetMorphTargName(int i,TSTR &name) {name.printf(_T("Target #%d"),i);} virtual void SetMorphTargName(int i,TSTR name) {} virtual Matrix3 GetMorphTargTM(int i) {return Matrix3(1);} // Checks an object to see if it is an acceptable target. virtual BOOL ValidTarget(TimeValue t,Object *obj) {return FALSE;} // When a REFMSG_SELECT_BRANCH message is received the morph controller should // mark the target indicated and be prepared to return its ID from this method. virtual int GetFlaggedTarget() {return -1;} // Should call these methods on targets virtual BOOL HasUVW() { return 1; } virtual void SetGenUVW(BOOL sw) { } }; //------------------------------------------------------------- // Control base class for Master Controllers // class MasterPointControl : public Control { public: // Set the number of sub-controllers virtual void SetNumSubControllers(int num, BOOL keep=FALSE) {} // Return the number of sub-controllers virtual int GetNumSubControllers() { return 0; } // Delete all the sub-controllers that are set to TRUE in the BitArray virtual void DeleteControlSet (BitArray set) {} // Add a new sub-controller virtual int AddSubController(Control* ctrl) { return 0; } // Return i'th of sub-controller virtual Control* GetSubController(int i) { return NULL; } // Set the i'th sub-controller virtual void SetSubController(int i, Control* ctrl) {} }; //----------------------------------------------------------------// // // Some stuff to help with ORTs - these could actually be Interval methods inline TimeValue CycleTime(Interval i,TimeValue t) { int res, dur = i.Duration()-1; if (dur<=0) return t; res = (t-i.Start())%dur; if (ti.End()) { return (abs(t-i.End())/dur)+1; } else { return 0; } } // Types that use this template must support: // T + T, T - T, T * float, T + float template T LinearExtrapolate(TimeValue t0, TimeValue t1, T &val0, T &val1, T &endVal) { return (T)(endVal + (val1-val0) * float(t1-t0)); } template T RepeatExtrapolate(Interval range, TimeValue t, T &startVal, T &endVal, T &cycleVal) { int cycles = NumCycles(range,t); T delta; if (t T IdentityExtrapolate(TimeValue endPoint, TimeValue t, T &endVal ) { return (T)(endVal + float(t-endPoint)); } CoreExport Quat LinearExtrapolate(TimeValue t0, TimeValue t1, Quat &val0, Quat &val1, Quat &endVal); CoreExport Quat RepeatExtrapolate(Interval range, TimeValue t, Quat &startVal, Quat &endVal, Quat &cycleVal); CoreExport Quat IdentityExtrapolate(TimeValue endPoint, TimeValue t, Quat &endVal ); CoreExport ScaleValue LinearExtrapolate(TimeValue t0, TimeValue t1, ScaleValue &val0, ScaleValue &val1, ScaleValue &endVal); CoreExport ScaleValue RepeatExtrapolate(Interval range, TimeValue t, ScaleValue &startVal, ScaleValue &endVal, ScaleValue &cycleVal); CoreExport ScaleValue IdentityExtrapolate(TimeValue endPoint, TimeValue t, ScaleValue &endVal); template T LinearInterpolate(const T &v0,const T &v1,float u) { return (T)((1.0f-u)*v0 + u*v1); } inline Quat LinearInterpolate(const Quat &v0,const Quat &v1,float u) { return Slerp(v0,v1,u); } inline ScaleValue LinearInterpolate(const ScaleValue &v0,const ScaleValue &v1,float u) { ScaleValue res; res.s = ((float)1.0-u)*v0.s + u*v1.s; res.q = Slerp(v0.q,v1.q,u); return res; } inline Interval TestInterval(Interval iv, DWORD flags) { TimeValue start = iv.Start(); TimeValue end = iv.End(); if (!(flags&TIME_INCLEFT)) { start++; } if (!(flags&TIME_INCRIGHT)) { end--; } if (end