
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
// Copyright (C) 2015 Faust Logic, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

#ifndef _AFX_CONSTRAINT_H_
#define _AFX_CONSTRAINT_H_

#include "core/util/tVector.h"
#include "T3D/shapeBase.h"

#include "afxEffectDefs.h"

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxConstraintDef

class afxEffectBaseData;

struct afxConstraintDef : public afxEffectDefs
{
  enum DefType
  {
    CONS_UNDEFINED,
    CONS_PREDEFINED,
    CONS_SCENE,
    CONS_EFFECT,
    CONS_GHOST
  };

  DefType           mDef_type;

  StringTableEntry  mCons_src_name;
  StringTableEntry  mCons_node_name;
  F32               mHistory_time;
  U8                mSample_rate;

  bool              mRuns_on_server;
  bool              mRuns_on_client;
  bool              mPos_at_box_center;
  bool              mTreat_as_camera;

  /*C*/             afxConstraintDef();

  bool              isDefined();

  bool              isArbitraryObject();
  void              reset();
  bool              parseSpec(const char* spec, bool runs_on_server, bool runs_on_client);

  static void       gather_cons_defs(Vector<afxConstraintDef>& defs, Vector<afxEffectBaseData*>& fx);

  static StringTableEntry  SCENE_CONS_KEY;
  static StringTableEntry  EFFECT_CONS_KEY;
  static StringTableEntry  GHOST_CONS_KEY;
};


//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxConstraint
//  Abstract base-class for a simple constraint mechanism used to constrain
//  special effects to spell related objects such as the spellcaster, target,
//  projectile, or impact location.
//
//  note -- the direction vectors don't really fit... should probably consider separate
//    constraint types for position, orientation, and possibly a look-at constraint.
//

class SceneObject;
class afxConstraintMgr;
  
class afxConstraint : public SimObject, public afxEffectDefs
{
  friend class afxConstraintMgr;
  typedef SimObject Parent;

protected:
  afxConstraintMgr* mMgr;
  afxConstraintDef  mCons_def;
  bool              mIs_defined;
  bool              mIs_valid;
  Point3F           mLast_pos;
  MatrixF           mLast_xfm;
  F32               mHistory_time;
  bool              mIs_alive;
  bool              mGone_missing;
  U32               mChange_code;

public:
  /*C*/             afxConstraint(afxConstraintMgr*);
  virtual           ~afxConstraint();

  virtual bool      getPosition(Point3F& pos, F32 hist=0.0f) 
                      { pos = mLast_pos; return mIs_valid; }
  virtual bool      getTransform(MatrixF& xfm, F32 hist=0.0f) 
                      { xfm = mLast_xfm; return mIs_valid;}
  virtual bool      getAltitudes(F32& terrain_alt, F32& interior_alt) { return false; }

  virtual bool      isDefined() { return mIs_defined; }
  virtual bool      isValid() { return mIs_valid; }
  virtual U32       getChangeCode() { return mChange_code; }

  virtual U32       setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans, bool is_death_anim) 
                                  { return 0; };
  virtual void      resetAnimation(U32 tag) { };
  virtual U32       lockAnimation() { return 0; }
  virtual void      unlockAnimation(U32 tag) { }
  virtual F32       getAnimClipDuration(const char* clip) { return 0.0f; }

  virtual S32       getDamageState() { return -1; }
  virtual void      setLivingState(bool state) { mIs_alive = state; };
  virtual bool      getLivingState() { return mIs_alive; };

  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)=0;

  virtual SceneObject* getSceneObject()=0;
  virtual void      restoreObject(SceneObject*)=0;
  virtual U16       getScopeId()=0;

  virtual U32       getTriggers()=0;

  virtual void      set_scope_id(U16 scope_id) { }
  virtual void      unset() { }
};


//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxConstraintMgr

class ShapeBase;
class afxEffectWrapper;
class afxShapeConstraint;
class afxObjectConstraint;
class BitStream;
class NetConnection;

struct afxConstraintID
{
  S16 index;
  S16 sub_index;

  afxConstraintID() { index = -1; sub_index = 0; }
  afxConstraintID(S16 idx, S16 sub=0) { index = idx; sub_index = sub; }
  bool undefined() const { return (index < 0); }
};
 
typedef Vector<afxConstraint*> afxConstraintList;

class afxConstraintMgr : public afxEffectDefs
{
  typedef SimObject Parent;

  struct preDef
  {
    StringTableEntry  name;
    U32               type;
  };

  Vector<afxConstraintList*>  mConstraints_v;

  Vector<StringTableEntry>  mNames_on_server;
  Vector<S32>               mGhost_ids;
  Vector<preDef>            mPredefs;
  U32                       mStartTime;
  bool                      mOn_server;
  bool                      mInitialized;
  F32                       mScoping_dist_sq;

  SceneObject*        find_object_from_name(StringTableEntry);
  S32                 find_cons_idx_from_name(StringTableEntry);
  S32                 find_effect_cons_idx_from_name(StringTableEntry);

  void                create_constraint(const afxConstraintDef&);    
  void                set_ref_shape(afxConstraintID which_id, ShapeBase*);
  void                set_ref_shape(afxConstraintID which_id, U16 scope_id);

public:
  /*C*/               afxConstraintMgr();
  /*D*/               ~afxConstraintMgr();

  void                defineConstraint(U32 type, StringTableEntry);

  afxConstraintID     setReferencePoint(StringTableEntry which, Point3F point);
  afxConstraintID     setReferencePoint(StringTableEntry which, Point3F point, Point3F vector);
  afxConstraintID     setReferenceTransform(StringTableEntry which, MatrixF& xfm);
  afxConstraintID     setReferenceObject(StringTableEntry which, SceneObject*);
  afxConstraintID     setReferenceObjectByScopeId(StringTableEntry which, U16 scope_id, bool is_shape);
  afxConstraintID     setReferenceEffect(StringTableEntry which, afxEffectWrapper*);
  afxConstraintID     createReferenceEffect(StringTableEntry which, afxEffectWrapper*);

  void                setReferencePoint(afxConstraintID which_id, Point3F point);
  void                setReferencePoint(afxConstraintID which_id, Point3F point, Point3F vector);
  void                setReferenceTransform(afxConstraintID which_id, MatrixF& xfm);
  void                setReferenceObject(afxConstraintID which_id, SceneObject*);
  void                setReferenceObjectByScopeId(afxConstraintID which_id, U16 scope_id, bool is_shape);
  void                setReferenceEffect(afxConstraintID which_id, afxEffectWrapper*);

  void                invalidateReference(afxConstraintID which_id);
                      
  afxConstraintID     getConstraintId(const afxConstraintDef&);
  afxConstraint*      getConstraint(afxConstraintID cons_id);

  void                sample(F32 dt, U32 now, const Point3F* cam_pos=0);

  void                setStartTime(U32 timestamp) { mStartTime = timestamp; }
  void                initConstraintDefs(Vector<afxConstraintDef>&, bool on_server, F32 scoping_dist=-1.0f); 
  void                packConstraintNames(NetConnection* conn, BitStream* stream);
  void                unpackConstraintNames(BitStream* stream);

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// scope-tracking
private:
  Vector<SceneObject*>  scopeable_objs;
  Vector<U16>           scopeable_ids;
  Vector<afxConstraint*>* missing_objs;
  Vector<afxConstraint*>* missing_objs2;
  Vector<afxConstraint*> missing_objs_a;
  Vector<afxConstraint*> missing_objs_b;

public:
  void                  addScopeableObject(SceneObject*);
  void                  removeScopeableObject(SceneObject*);
  void                  clearAllScopeableObjs();

  void                  postMissingConstraintObject(afxConstraint*, bool is_deleting=false);
  void                  restoreScopedObject(SceneObject*, afxChoreographer* ch);
  void                  adjustProcessOrdering(afxChoreographer*);

  F32                   getScopingDistanceSquared() const { return mScoping_dist_sq; }
};

inline afxConstraintID afxConstraintMgr::setReferencePoint(StringTableEntry which, Point3F point)
{
  return setReferencePoint(which, point, Point3F(0,0,1));
}

inline void afxConstraintMgr::setReferencePoint(afxConstraintID which, Point3F point) 
{
  setReferencePoint(which, point, Point3F(0,0,1));
}



//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxPointConstraint
//  This constrains to a specific 3D position such as an impact location.
//

class afxPointConstraint : public afxConstraint
{
  typedef afxConstraint  Parent;

protected:
  Point3F           mPoint;
  Point3F           mVector;

public:
  /*C*/             afxPointConstraint(afxConstraintMgr*);
  virtual           ~afxPointConstraint();

  virtual void      set(Point3F point, Point3F vector);
  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);

  virtual SceneObject* getSceneObject() { return 0; }
  virtual void      restoreObject(SceneObject*) { }
  virtual U16       getScopeId() { return 0; }
  virtual U32       getTriggers() { return 0; }

  virtual void      unset() { set(Point3F::Zero, Point3F(0,0,1)); }
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxTransformConstraint
//  This constrains to a specific 3D transformation.
//

class afxTransformConstraint : public afxConstraint
{
  typedef afxConstraint  Parent;

protected:
  MatrixF           mXfm;

public:
  /*C*/             afxTransformConstraint(afxConstraintMgr*);
  virtual           ~afxTransformConstraint();

  virtual void      set(const MatrixF& xfm);
  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);

  virtual SceneObject* getSceneObject() { return 0; }
  virtual void      restoreObject(SceneObject*) { }
  virtual U16       getScopeId() { return 0; }
  virtual U32       getTriggers() { return 0; }

  virtual void      unset() { set(MatrixF::Identity); }
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxShapeConstraint
//  This constrains to a hierarchical shape (subclasses of ShapeBase), such as a 
//  Player or a Vehicle. You can also constrain to named sub-nodes of a shape.

class ShapeBase;
class SceneObject;

class afxShapeConstraint : public afxConstraint
{
  friend class afxConstraintMgr;
  typedef afxConstraint  Parent;

protected:
  StringTableEntry  mArb_name;
  ShapeBase*        mShape;
  U16               mScope_id;
  U32               mClip_tag;
  U32               mLock_tag;

public:
  /*C*/             afxShapeConstraint(afxConstraintMgr*);
  /*C*/             afxShapeConstraint(afxConstraintMgr*, StringTableEntry arb_name);
  virtual           ~afxShapeConstraint();

  virtual void      set(ShapeBase* shape);
  virtual void      set_scope_id(U16 scope_id);
  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);

  virtual U32       setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans, bool is_death_anim);
  virtual void      resetAnimation(U32 tag);
  virtual U32       lockAnimation();
  virtual void      unlockAnimation(U32 tag);
  virtual F32       getAnimClipDuration(const char* clip);

  void              remapAnimation(U32 tag, ShapeBase* other_shape);

  virtual S32       getDamageState();

  virtual SceneObject* getSceneObject() { return mShape; }
  virtual void      restoreObject(SceneObject*);
  virtual U16       getScopeId() { return mScope_id; }
  virtual U32       getTriggers();

  virtual void      onDeleteNotify(SimObject*);

  virtual void      unset() { set(0); }
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxShapeNodeConstraint

class afxShapeNodeConstraint : public afxShapeConstraint
{
  friend class afxConstraintMgr;
  typedef afxShapeConstraint  Parent;

protected:
  StringTableEntry  mArb_node;
  S32               mShape_node_ID;

public:
  /*C*/             afxShapeNodeConstraint(afxConstraintMgr*);
  /*C*/             afxShapeNodeConstraint(afxConstraintMgr*, StringTableEntry arb_name, StringTableEntry arb_node);

  virtual void      set(ShapeBase* shape);
  virtual void      set_scope_id(U16 scope_id);
  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);
  virtual void      restoreObject(SceneObject*);

  S32               getNodeID() const { return mShape_node_ID; }

  virtual void      onDeleteNotify(SimObject*);
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxObjectConstraint
//  This constrains to a simple 3D object (subclasses of SceneObject), such as an 
//  afxMagicMissile or a Projectile. You cannot constrain to sub-nodes with an
//  afxObjectConstraint, use afxShapeConstraint instead.

class SceneObject;

class afxObjectConstraint : public afxConstraint
{
  friend class afxConstraintMgr;
  typedef afxConstraint  Parent;

protected:
  StringTableEntry  mArb_name;
  SceneObject*      mObj;
  U16               mScope_id;
  bool              mIs_camera;

public:
                    afxObjectConstraint(afxConstraintMgr*);
                    afxObjectConstraint(afxConstraintMgr*, StringTableEntry arb_name);
  virtual           ~afxObjectConstraint();

  virtual void      set(SceneObject* obj);
  virtual void      set_scope_id(U16 scope_id);
  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);

  virtual SceneObject* getSceneObject() { return mObj; }
  virtual void      restoreObject(SceneObject*);
  virtual U16       getScopeId() { return mScope_id; }
  virtual U32       getTriggers();

  virtual void      onDeleteNotify(SimObject*);

  virtual void      unset() { set(0); }
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxEffectConstraint
//  This constrains to a hierarchical shape (subclasses of ShapeBase), such as a 
//  Player or a Vehicle. You can also constrain to named sub-nodes of a shape.

class afxEffectWrapper;

class afxEffectConstraint : public afxConstraint
{
  friend class afxConstraintMgr;
  typedef afxConstraint  Parent;

protected:
  StringTableEntry  mEffect_name;
  afxEffectWrapper* mEffect;
  U32               mClip_tag;
  bool              mIs_death_clip;
  U32               mLock_tag;

public:
  /*C*/             afxEffectConstraint(afxConstraintMgr*);
  /*C*/             afxEffectConstraint(afxConstraintMgr*, StringTableEntry effect_name);
  virtual           ~afxEffectConstraint();

  virtual bool      getPosition(Point3F& pos, F32 hist=0.0f); 
  virtual bool      getTransform(MatrixF& xfm, F32 hist=0.0f);
  virtual bool      getAltitudes(F32& terrain_alt, F32& interior_alt);

  virtual void      set(afxEffectWrapper* effect);
  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos) { }

  virtual U32       setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans, bool is_death_anim);
  virtual void      resetAnimation(U32 tag);
  virtual F32       getAnimClipDuration(const char* clip);

  virtual SceneObject* getSceneObject() { return 0; }
  virtual void      restoreObject(SceneObject*) { }
  virtual U16       getScopeId() { return 0; }
  virtual U32       getTriggers();

  virtual void      unset() { set(0); }
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxEffectNodeConstraint

class afxEffectNodeConstraint : public afxEffectConstraint
{
  friend class afxConstraintMgr;
  typedef afxEffectConstraint  Parent;

protected:
  StringTableEntry  mEffect_node;
  S32               mEffect_node_ID;

public:
  /*C*/             afxEffectNodeConstraint(afxConstraintMgr*);
  /*C*/             afxEffectNodeConstraint(afxConstraintMgr*, StringTableEntry name, StringTableEntry node);

  virtual bool      getPosition(Point3F& pos, F32 hist=0.0f); 
  virtual bool      getTransform(MatrixF& xfm, F32 hist=0.0f);

  virtual void      set(afxEffectWrapper* effect);

  S32               getNodeID() const { return mEffect_node_ID; }
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxSampleBuffer

class afxSampleBuffer
{
protected:
  U32               mBuffer_sz;
  U32               mBuffer_ms;
  U32               mMS_per_sample;
  U32               mElapsed_ms;
  U32               mLast_sample_ms;
  U32               mNext_sample_num;
  U32               mNum_samples;

  virtual void      recSample(U32 idx, void* data) = 0;
  bool              compute_idx_from_lag(F32 lag, U32& idx);
  bool              compute_idx_from_lag(F32 lag, U32& idx1, U32& idx2, F32& t);

public:
  /*C*/             afxSampleBuffer();
  virtual           ~afxSampleBuffer();

  virtual void      configHistory(F32 hist_len, U8 sample_rate);
  void              recordSample(F32 dt, U32 elapsed_ms, void* data);
  virtual void      getSample(F32 lag, void* data, bool& oob) = 0;
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxSampleXfmBuffer

class afxSampleXfmBuffer : public afxSampleBuffer
{
  typedef afxSampleBuffer  Parent;

protected:
  MatrixF*          mXfm_buffer;

  virtual void      recSample(U32 idx, void* data);

public:
  /*C*/             afxSampleXfmBuffer();
  virtual           ~afxSampleXfmBuffer();

  virtual void      configHistory(F32 hist_len, U8 sample_rate);
  virtual void      getSample(F32 lag, void* data, bool& oob);
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxPointHistConstraint
//  This class extends afxPointConstraint to remember its values for a period of time.

class afxPointHistConstraint : public afxPointConstraint
{
  friend class afxConstraintMgr;
  typedef afxPointConstraint  Parent;

protected:
  afxSampleBuffer*  mSamples;

public:
  /*C*/             afxPointHistConstraint(afxConstraintMgr*);
  virtual           ~afxPointHistConstraint();

  virtual void      set(Point3F point, Point3F vector);
  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);

  virtual bool      getPosition(Point3F& pos, F32 hist=0.0f);
  virtual bool      getTransform(MatrixF& xfm, F32 hist=0.0f);
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxPointHistConstraint
//  This class extends afxTransformConstraint to remember its values for a period of time.

class afxTransformHistConstraint : public afxTransformConstraint
{
  friend class afxConstraintMgr;
  typedef afxTransformConstraint  Parent;

protected:
  afxSampleBuffer*  mSamples;

public:
  /*C*/             afxTransformHistConstraint(afxConstraintMgr*);
  virtual           ~afxTransformHistConstraint();

  virtual void      set(const MatrixF& xfm);
  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);

  virtual bool      getPosition(Point3F& pos, F32 hist=0.0f);
  virtual bool      getTransform(MatrixF& xfm, F32 hist=0.0f);
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxShapeHistConstraint
//  This class extends afxShapeConstraint to remember its values for a period of time.

class afxShapeHistConstraint : public afxShapeConstraint
{
  friend class afxConstraintMgr;
  typedef afxShapeConstraint  Parent;

protected:
  afxSampleBuffer*  mSamples;

public:
  /*C*/             afxShapeHistConstraint(afxConstraintMgr*);
  /*C*/             afxShapeHistConstraint(afxConstraintMgr*, StringTableEntry arb_name);
  virtual           ~afxShapeHistConstraint();

  virtual void      set(ShapeBase* shape);
  virtual void      set_scope_id(U16 scope_id);
  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);

  virtual bool      getPosition(Point3F& pos, F32 hist=0.0f);
  virtual bool      getTransform(MatrixF& xfm, F32 hist=0.0f);

  virtual void      onDeleteNotify(SimObject*);
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxShapeNodeHistConstraint
//  This class extends afxShapeConstraint to remember its values for a period of time.

class afxShapeNodeHistConstraint : public afxShapeNodeConstraint
{
  friend class afxConstraintMgr;
  typedef afxShapeNodeConstraint  Parent;

protected:
  afxSampleBuffer*  mSamples;

public:
  /*C*/             afxShapeNodeHistConstraint(afxConstraintMgr*);
  /*C*/             afxShapeNodeHistConstraint(afxConstraintMgr*, StringTableEntry arb_name, StringTableEntry arb_node);
  virtual           ~afxShapeNodeHistConstraint();

  virtual void      set(ShapeBase* shape);
  virtual void      set_scope_id(U16 scope_id);
  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);

  virtual bool      getPosition(Point3F& pos, F32 hist=0.0f);
  virtual bool      getTransform(MatrixF& xfm, F32 hist=0.0f);

  virtual void      onDeleteNotify(SimObject*);
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxObjectHistConstraint
//  This class extends afxObjectConstraint to remember its values for a period of time.

class SceneObject;

class afxObjectHistConstraint : public afxObjectConstraint
{
  friend class afxConstraintMgr;
  typedef afxObjectConstraint  Parent;

protected:
  afxSampleBuffer* mSamples;

public:
                    afxObjectHistConstraint(afxConstraintMgr*);
                    afxObjectHistConstraint(afxConstraintMgr*, StringTableEntry arb_name);
  virtual           ~afxObjectHistConstraint();

  virtual void      set(SceneObject* obj);
  virtual void      set_scope_id(U16 scope_id);
  virtual void      sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos);

  virtual bool      getPosition(Point3F& pos, F32 hist=0.0f);
  virtual bool      getTransform(MatrixF& xfm, F32 hist=0.0f);

  virtual void      onDeleteNotify(SimObject*);
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

#endif // _AFX_CONSTRAINT_H_

