tge/lib/maxsdk40/control.h
2017-04-17 06:17:10 -06:00

990 lines
36 KiB
C++
Executable File

/**********************************************************************
*<
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<Control*> 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<Control*> 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 (t<i.Start()) {
return i.End()+res;
} else {
return i.Start()+res;
}
}
inline int NumCycles(Interval i,TimeValue t)
{
int dur = i.Duration()-1;
if (dur<=0) return 1;
if (t<i.Start()) {
return (abs(t-i.Start())/dur)+1;
} else
if (t>i.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 <class T> T
LinearExtrapolate(TimeValue t0, TimeValue t1, T &val0, T &val1, T &endVal)
{
return (T)(endVal + (val1-val0) * float(t1-t0));
}
template <class T> T
RepeatExtrapolate(Interval range, TimeValue t,
T &startVal, T &endVal, T &cycleVal)
{
int cycles = NumCycles(range,t);
T delta;
if (t<range.Start()) {
delta = startVal - endVal;
} else {
delta = endVal - startVal;
}
return (T)(cycleVal + delta * float(cycles));
}
template <class 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 <class T> 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<start) {
iv.SetEmpty();
} else {
iv.Set(start,end);
}
return iv;
}
inline Quat ScaleQuat(Quat q, float s)
{
float angle;
Point3 axis;
AngAxisFromQ(q,&angle,axis);
return QFromAngAxis(angle*s,axis);
}
//-------------------------------------------------------------------
// A place to store values during Hold/Restore periods
//
//********************************************************
// TempStore: This is a temporary implementation:
// It uses a linear search-
// A hash-coded dictionary would be faster.
// (if there are ever a lot of entries)
//********************************************************
struct Slot {
void *key;
void *pdata;
int nbytes;
Slot *next;
public:
Slot() { pdata = NULL; }
~Slot() {
if (pdata) free(pdata);
pdata = NULL;
}
};
class TempStore {
Slot *slotList;
Slot* Find(int n, void *data, void *ptr);
public:
TempStore() { slotList = NULL; }
~TempStore() { ClearAll(); }
CoreExport void ClearAll(); // empty out the store
CoreExport void PutBytes(int n, void *data, void *ptr);
CoreExport void GetBytes(int n, void *data, void *ptr);
CoreExport void Clear(void *ptr); // Remove single entry
void PutFloat(float f, void *ptr) {
PutBytes(sizeof(float),(void *)&f,ptr);
}
CoreExport void PutInt(int i, void *ptr) {
PutBytes(sizeof(int),(void *)&i,ptr);
}
CoreExport void GetFloat(float *f, void *ptr) {
GetBytes(sizeof(float),(void *)f,ptr);
}
CoreExport void GetInt(int *i, void *ptr) {
GetBytes(sizeof(int),(void *)i,ptr);
}
CoreExport void PutPoint3(Point3 f, void *ptr) {
PutBytes(sizeof(Point3),(void *)&f,ptr);
}
CoreExport void GetPoint3(Point3 *f, void *ptr) {
GetBytes(sizeof(Point3),(void *)f,ptr);
}
CoreExport void PutQuat( Quat f, void *ptr) {
PutBytes(sizeof(Quat),(void *)&f,ptr);
}
CoreExport void GetQuat( Quat *f, void *ptr) {
GetBytes(sizeof(Quat),(void *)f,ptr);
}
CoreExport void PutScaleValue( ScaleValue f, void *ptr) {
PutBytes(sizeof(ScaleValue),(void *)&f,ptr);
}
CoreExport void GetScaleValue( ScaleValue *f, void *ptr) {
GetBytes(sizeof(ScaleValue),(void *)f,ptr);
}
};
extern CoreExport TempStore tmpStore; // this should be in the scene data struct.
CoreExport int Animating(); // is the animate switch on??
CoreExport void AnimateOn(); // turn animate on
CoreExport void AnimateOff(); // turn animate off
CoreExport void SuspendAnimate(); // suspend animation (uses stack)
CoreExport void ResumeAnimate(); // resume animation ( " )
CoreExport TimeValue GetAnimStart();
CoreExport TimeValue GetAnimEnd();
CoreExport void SetAnimStart(TimeValue s);
CoreExport void SetAnimEnd(TimeValue e);
CoreExport Control *NewDefaultFloatController();
CoreExport Control *NewDefaultPoint3Controller();
CoreExport Control *NewDefaultMatrix3Controller();
CoreExport Control *NewDefaultPositionController();
CoreExport Control *NewDefaultRotationController();
CoreExport Control *NewDefaultScaleController();
CoreExport Control *NewDefaultBoolController();
CoreExport Control *NewDefaultColorController();
CoreExport Control *NewDefaultMasterPointController();
CoreExport Control* CreateInterpFloat();
CoreExport Control* CreateInterpPosition();
CoreExport Control* CreateInterpPoint3();
CoreExport Control* CreateInterpRotation();
CoreExport Control* CreateInterpScale();
CoreExport Control* CreatePRSControl();
CoreExport Control* CreateLookatControl();
CoreExport Control* CreateMasterPointControl();
CoreExport void SetDefaultController(SClass_ID sid, ClassDesc *desc);
CoreExport ClassDesc *GetDefaultController(SClass_ID sid);
CoreExport void SetDefaultColorController(ClassDesc *desc);
CoreExport void SetDefaultBoolController(ClassDesc *desc);
CoreExport BOOL GetSetKeyMode();
CoreExport void SetSetKeyMode(BOOL onOff);
CoreExport void SuspendSetKeyMode();
CoreExport void ResumeSetKeyMode();
CoreExport BOOL IsSetKeyModeFeatureEnabled();
#endif //__CONTROL__