/**********************************************************************
 *<
	FILE: object.h
				  
	DESCRIPTION:  Defines Object Classes

	CREATED BY: Dan Silva

	HISTORY: created 9 September 1994

 *>     Copyright (c) 1994, All Rights Reserved.
 **********************************************************************/

#ifndef _OBJECT_

#define _OBJECT_

#include "inode.h"
#include "maxapi.h"
#include "plugapi.h"
#include "snap.h"
#include "genshape.h"
#include <hitdata.h>
#include "imtl.h"

typedef short MtlIndex; 
typedef short TextMapIndex;

CoreExport void setHitType(int t);
CoreExport int  getHitType(void);
CoreExport BOOL doingXORDraw(void);

// Hit test types:
#define HITTYPE_POINT   1
#define HITTYPE_BOX             2
#define HITTYPE_CIRCLE  3
#define HITTYPE_SOLID   4
#define HITTYPE_FENCE   5

// Flags for hit test.
#define HIT_SELONLY				(1<<0)
#define HIT_UNSELONLY			(1<<2)
#define HIT_ABORTONHIT			(1<<3)
#define HIT_SELSOLID			(1<<4)
#define HIT_ANYSOLID			(1<<5)
#define HIT_TRANSFORMGIZMO		(1<<6)	// CCJ - 06/29/98 - Hittest transform gizmo
#define HIT_SWITCH_GIZMO		(1<<7)	// CCJ - 06/29/98 - Switch axis when hit

// These are filters for hit testing. They also
// are combined into the flags parameter.
#define HITFLTR_ALL                     (1<<10)
#define HITFLTR_OBJECTS         (1<<11)
#define HITFLTR_CAMERAS         (1<<12)
#define HITFLTR_LIGHTS          (1<<13)
#define HITFLTR_HELPERS         (1<<14)
#define HITFLTR_WSMOBJECTS      (1<<15)
#define HITFLTR_SPLINES         (1<<16)

// Starting at this bit through the 31st bit can be used
// by plug-ins for sub-object hit testing
#define HITFLAG_STARTUSERBIT    24


#define VALID(x) (x)

class Modifier;
class Object;
class NameTab; 
class Texmap;
  
typedef Object* ObjectHandle;

MakeTab(TextMapIndex)
typedef TextMapIndexTab TextTab;

//---------------------------------------------------------------  
class IdentityTM: public Matrix3 {
	public:
		IdentityTM() { IdentityMatrix(); }              
	};

CoreExport extern IdentityTM idTM;


//-------------------------------------------------------------
// This is passed in to GetRenderMesh to allow objects to do
// view dependent rendering.
//

// flag defines for View::flags
#define RENDER_MESH_DISPLACEMENT_MAP  1   // enable displacement mapping

class View {
	public: 
		float screenW, screenH;  // screen dimensions
		Matrix3 worldToView;
		virtual Point2 ViewToScreen(Point3 p)=0;
		// the following added for GAP
		int projType;
		float fov, pixelSize;
		Matrix3 affineTM;         // worldToCam
		DWORD flags;

		// Call during render to check if user has cancelled render.  
		// Returns TRUE iff user has cancelled.
		virtual BOOL CheckForRenderAbort() { return FALSE; }

		// Generic expansion function
		virtual int Execute(int cmd, ULONG arg1=0, ULONG arg2=0, ULONG arg3=0) { return 0; } 

		View() { projType = -1; flags = RENDER_MESH_DISPLACEMENT_MAP; } // projType not set, this is to deal with older renderers.
	};
//-------------------------------------------------------------

// Class ID of general deformable object.
extern CoreExport Class_ID defObjectClassID;

//-------------------------------------------------------------

// Class ID of general texture-mappable object.
extern CoreExport Class_ID mapObjectClassID;

//-------------------------------------------------------------
// ChannelMask: bits specific channels in the OSM dataflow. 

typedef unsigned long ChannelMask;

// an array of channel masks for all the channels *within*
// the Object.
CoreExport extern ChannelMask chMask[];

class Object;

//-- ObjectState ------------------------------------------------------------
// This is what is passed down the pipeline, and ultimately used by the Node
//  to Display, Hittest, render:

// flags bits

class ObjectState {
		ulong flags;
		Matrix3 *tm;
		Interval tmvi;   
		int mtl;
		Interval mtlvi;                         
		void AllocTM();
	public: 
		Object *obj;  // object: provides interval with obj->ObjectValidity()
		CoreExport ObjectState();
		CoreExport ObjectState(Object *ob);
		CoreExport ObjectState(const ObjectState& os); 
		CoreExport ~ObjectState();
		void OSSetFlag(ulong f) { flags |= f; }
		void OSClearFlag(ulong f) { flags &= ~f; }
		ulong OSTestFlag(ulong f) const { return flags&f; }
		CoreExport void OSCopyFlag(ulong f, const ObjectState& fromos);
		CoreExport ObjectState& operator=(const ObjectState& os);
		Interval tmValid() const { return tmvi; }
		Interval mtlValid() const  { return mtlvi; }
		CoreExport Interval Validity(TimeValue t) const;
		CoreExport int TMIsIdentity() const;
		CoreExport void SetTM(Matrix3* mat, Interval iv);
		CoreExport Matrix3* GetTM() const;
		CoreExport void SetIdentityTM();
		CoreExport void ApplyTM(Matrix3* mat, Interval iv);
		CoreExport void CopyTM(const ObjectState &fromos);
		CoreExport void CopyMtl(const ObjectState &fromos);
		CoreExport void Invalidate(ChannelMask channels, BOOL checkLock=FALSE);
		CoreExport void DeleteObj(BOOL checkLock=FALSE);
	};

class INodeTab : public Tab<INode*> {
	public:         
		void DisposeTemporary() {
			for (int i=0; i<Count(); i++) (*this)[i]->DisposeTemporary();
			}
	};

//---------------------------------------------------------------  
// A reference to a pointer to an instance of this class is passed in
// to ModifyObject(). The value of the pointer starts out as NULL, but
// the modifier can set it to point at an actual instance of a derived
// class. When the mod app is deleted, if the pointer is not NULL, the
// LocalModData will be deleted - the virtual destructor alows this to work.

class LocalModData {
	public:
		virtual ~LocalModData() {}
		virtual LocalModData *Clone()=0;
		virtual void* GetInterface(ULONG id) { return NULL; }  // to access sub-obj selection interfaces, JBW 2/5/99
	}; 

class ModContext {
	public:
	Matrix3                 *tm;
	Box3                    *box;
	LocalModData    *localData;
	
	CoreExport ~ModContext();
	CoreExport ModContext();
	CoreExport ModContext(const ModContext& mc);
	CoreExport ModContext(Matrix3 *tm, Box3 *box, LocalModData *localData);
	};

class ModContextList : public Tab<ModContext*> {};


class HitRecord;


// Values passed to NewSetByOperator()
#define NEWSET_MERGE			1
#define NEWSET_INTERSECTION		2
#define NEWSET_SUBTRACT			3


// Flags passed to Display()
#define USE_DAMAGE_RECT                 (1<<0)  
#define DISP_SHOWSUBOBJECT              (1<<1)

// The base class of Geometric objects, Lights, Cameras, Modifiers, 
//  Deformation objects--
// --anything with a 3D representation in the UI scene. 

class IParamArray;

class BaseObject: public ReferenceTarget {
	public:
		CoreExport void* GetInterface(ULONG id);

		virtual int HitTest(TimeValue t, INode* inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt){return 0;};
		virtual void SetExtendedDisplay(int flags)      {}      // for setting mode-dependent display attributes
		virtual int Display(TimeValue t, INode* inode, ViewExp *vpt, int flags) { return 0; };   // quick render in viewport, using current TM.         
		virtual void Snap(TimeValue t, INode* inode, SnapInfo *snap, IPoint2 *p, ViewExp *vpt) {}       // Check for snap, updating SnapInfo
		virtual void GetWorldBoundBox(TimeValue t, INode * inode, ViewExp* vp, Box3& box ){};  // Box in world coords.
		virtual void GetLocalBoundBox(TimeValue t, INode* inode, ViewExp* vp,  Box3& box ){};  // box in objects local coords
		virtual CreateMouseCallBack* GetCreateMouseCallBack()=0;
		
		// This is the name that will appear in the history browser.
		virtual TCHAR *GetObjectName() { return _T("Object"); }

		// Sends the REFMSG_IS_OK_TO_CHANGE_TOPOLOGY off to see if any
		// modifiers or objects down the pipeline depend on topology.
		// modName will be set to the dependent modifier's name if there is one.
		CoreExport virtual BOOL OKToChangeTopology(TSTR &modName);

		// Return true if this object(or modifier) is cabable of changing 
		//topology when it's parameters are being edited.
		virtual BOOL ChangeTopology() {return TRUE;}

		virtual void ForceNotify(Interval& i)
			{NotifyDependents(i, PART_ALL,REFMSG_CHANGE);}
				
		// If an object or modifier wishes it can make its parameter block
		// available for other plug-ins to access. The system itself doesn't
		// actually call this method -- this method is optional.
		virtual IParamArray *GetParamBlock() {return NULL;}
		
		// If a plug-in make its parameter block available then it will
		// need to provide #defines for indices into the parameter block.
		// These defines should probably not be directly used with the
		// parameter block but instead converted by this function that the
		// plug-in implements. This way if a parameter moves around in a 
		// future version of the plug-in the #define can be remapped.
		// -1 indicates an invalid parameter id
		virtual int GetParamBlockIndex(int id) {return -1;}


		///////////////////////////////////////////////////////////////////////////
		///////////////////////////////////////////////////////////////////////////
		//
		// The following methods are for sub-object selection. If the
		// derived class is NOT a modifier, the modContext pointer passed
		// to some of the methods will be NULL.
		//

		// Affine transform methods
		virtual void Move( TimeValue t, Matrix3& partm, Matrix3& tmAxis, Point3& val, BOOL localOrigin=FALSE ){}
		virtual void Rotate( TimeValue t, Matrix3& partm, Matrix3& tmAxis, Quat& val, BOOL localOrigin=FALSE ){}
		virtual void Scale( TimeValue t, Matrix3& partm, Matrix3& tmAxis, Point3& val, BOOL localOrigin=FALSE ){}

		// The following is called before the first Move(), Rotate() or Scale() call and
		// before a hold is in effect
		virtual void TransformStart(TimeValue t) {}

		// The following is called before the first Move(), Rotate() or Scale() call and
		// after a hold is in effect
		virtual void TransformHoldingStart(TimeValue t) {}

		// The following is called after the user has completed the Move, Rotate or Scale operation and
		// before the undo object has been accepted.
		virtual void TransformHoldingFinish(TimeValue t) {}             

		// The following is called after the user has completed the Move, Rotate or Scale operation and
		// after the undo object has been accepted.
		virtual void TransformFinish(TimeValue t) {}            

		// The following is called when the transform operation is cancelled by a right-click and
		// the undo has been cancelled.
		virtual void TransformCancel(TimeValue t) {}            

		virtual int HitTest(TimeValue t, INode* inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt, ModContext* mc) { return 0; }
		virtual int Display(TimeValue t, INode* inode, ViewExp *vpt, int flags, ModContext* mc) { return 0; };   // quick render in viewport, using current TM.         
		virtual void GetWorldBoundBox(TimeValue t,INode* inode, ViewExp *vpt, Box3& box, ModContext *mc) {}
		
		virtual void CloneSelSubComponents(TimeValue t) {}
		virtual void AcceptCloneSelSubComponents(TimeValue t) {}

		// Changes the selection state of the component identified by the
		// hit record.
		virtual void SelectSubComponent(
			HitRecord *hitRec, BOOL selected, BOOL all, BOOL invert=FALSE) {}
		
		// Clears the selection for the given sub-object type.
		virtual void ClearSelection(int selLevel) {}
		virtual void SelectAll(int selLevel) {}
		virtual void InvertSelection(int selLevel) {}

		// Returns the index of the subobject entity identified by hitRec.
		virtual int SubObjectIndex(HitRecord *hitRec) {return 0;}               
		
		// This notifies an object being edited that the current sub object
		// selection level has changed. level==0 indicates object level selection.
		// level==1 or greater refer to the types registered by the object in the
		// order they appeared in the list when registered.
		// If level >= 1, the object should specify sub-object xform modes in the
		// modes structure (defined in cmdmode.h).
		virtual void ActivateSubobjSel(int level, XFormModes& modes ) {}

		// An object that supports sub-object selection can choose to
		// support named sub object selection sets. Methods in the the
		// interface passed to objects allow them to add items to the
		// sub-object selection set drop down.
		// The following methods are called when the user picks items
		// from the list.
		virtual BOOL SupportsNamedSubSels() {return FALSE;}
		virtual void ActivateSubSelSet(TSTR &setName) {}
		virtual void NewSetFromCurSel(TSTR &setName) {}
		virtual void RemoveSubSelSet(TSTR &setName) {}

		// New for version 2. To support the new edit named selections dialog,
		// plug-ins must implemented the following methods:
		virtual void SetupNamedSelDropDown() {}
		virtual int NumNamedSelSets() {return 0;}
		virtual TSTR GetNamedSelSetName(int i) {return _T("");}
		virtual void SetNamedSelSetName(int i,TSTR &newName) {}
		virtual void NewSetByOperator(TSTR &newName,Tab<int> &sets,int op) {}


		// New way of dealing with sub object coordinate systems.
		// Plug-in enumerates its centers or TMs and calls the callback once for each.
		// NOTE:cb->Center() should be called the same number of times and in the
		// same order as cb->TM()
		// NOTE: The SubObjAxisCallback class is defined in animatable and used in both the
		// controller version and this version of GetSubObjectCenters() and GetSubObjectTMs()
		virtual void GetSubObjectCenters(SubObjAxisCallback *cb,TimeValue t,INode *node,ModContext *mc) {}
		virtual void GetSubObjectTMs(SubObjAxisCallback *cb,TimeValue t,INode *node,ModContext *mc) {}                          


		// Find out if the Object or Modifer is is generating UVW's
		// on map channel 1.
		virtual BOOL HasUVW () { return 0; }
		// or on any map channel:
		virtual BOOL HasUVW (int mapChannel) { return (mapChannel==1) ? HasUVW() : FALSE; }

		// Change the state of the object's Generate UVW boolean.
		// IFF the state changes, the object should send a REFMSG_CHANGED down the pipe.
		virtual void SetGenUVW(BOOL sw) {  }	// applies to mapChannel 1
		virtual void SetGenUVW (int mapChannel, BOOL sw) { if (mapChannel==1) SetGenUVW (sw); }

		// Notify the BaseObject that the end result display has been switched.
		// (Sometimes this is needed for display changes.)
		virtual void ShowEndResultChanged (BOOL showEndResult) { }

		//
		//
		///////////////////////////////////////////////////////////////////////////
		///////////////////////////////////////////////////////////////////////////
		
	private:
	};

//-------------------------------------------------------------
// Callback object used by Modifiers to deform "Deformable" objects
class Deformer {
	public:
		virtual Point3 Map(int i, Point3 p) = 0; 
		void ApplyToTM(Matrix3* tm);
	};

// Mapping types passed to ApplyUVWMap()
#define MAP_PLANAR              0
#define MAP_CYLINDRICAL 1
#define MAP_SPHERICAL   2
#define MAP_BALL                3
#define MAP_BOX                 4

/*------------------------------------------------------------------- 
   Object is the class of all objects that can be pointed to by a node:
   It INcludes Lights,Cameras, Geometric objects, derived objects,
   and deformation Objects (e.g. FFD lattices)
   It EXcludes Modifiers
---------------------------------------------------------------------*/
#define OBJECT_LOCKED 0x8000000

class ShapeObject;

class Object: public BaseObject {
		ulong locked;   // lock flags for each channel + object locked flag
		Interval noEvalInterval;  // used in ReducingCaches
	public:
		Object() { locked = OBJECT_LOCKED; noEvalInterval = FOREVER; }

		virtual int IsRenderable()=0;  // is this a renderable object?
		virtual void InitNodeName(TSTR& s)=0;
		virtual int UsesWireColor() { return TRUE; }    // TRUE if the object color is used for display
		virtual int DoOwnSelectHilite() { return 0; }
		// validity interval of Object as a whole at current time
		virtual Interval ObjectValidity(TimeValue t) { return FOREVER; }

		// This used to be in GeomObject but I realized that other types of objects may
		// want this (mainly to participate in normal align) such as grid helper objects.
		virtual int IntersectRay(TimeValue t, Ray& r, float& at, Point3& norm) {return FALSE;}

		// Objects that don't support IntersectRay() (like helpers) can implement this
		// method to provide a default vector for normal align.
		virtual BOOL NormalAlignVector(TimeValue t,Point3 &pt, Point3 &norm) {return FALSE;}

		// locking of object as whole. defaults to NOT modifiable.
		void LockObject() { locked |= OBJECT_LOCKED; }
		void UnlockObject() { locked &= ~OBJECT_LOCKED; }
		int  IsObjectLocked() { return locked&OBJECT_LOCKED; }

		// the validity intervals are now in the object.
		virtual ObjectState Eval(TimeValue t)=0;

		// Access the lock flags for th specified channels
		void LockChannels(ChannelMask channels) { locked |= channels; } 
		void UnlockChannels(ChannelMask channels) { locked &= ~channels; }
		ChannelMask     GetChannelLocks() { return locked; }    
		void SetChannelLocks(ChannelMask channels) { locked = channels; }       
		ChannelMask GetChannelLocks(ChannelMask m) { return locked; }
		
		// Can this object have channels cached?
		// Particle objects flow up the pipline without making shallow copies of themselves and therefore cannot be cached
		virtual BOOL CanCacheObject() {return TRUE;}

		// This is called by a node when the node's world space state has
		// become invalid. Normally an object does not (and should not) be
		// concerned with this, but in certain cases (particle systems) an
		// object is effectively a world space object an needs to be notified.
		virtual void WSStateInvalidate() {}

		// Identifies the object as a world space object. World space
		// objects (particles for example) can not be instanced because
		// they exist in world space not object space.
		virtual BOOL IsWorldSpaceObject() {return FALSE;}
		
		// This is only valid for world-space objects (they must return TRUE for
		// the IsWorldSpaceObject method).  It locates the node which contains the
		// object.  Non-world-space objects will return NULL for this!
		CoreExport INode *GetWorldSpaceObjectNode();

		// Is the derived class derived from ParticleObject?
		virtual BOOL IsParticleSystem() {return FALSE;}

		// copy specified flags from obj
		CoreExport void CopyChannelLocks(Object *obj, ChannelMask needChannels);

		// access the current validity interval for the nth channel
		CoreExport virtual Interval ChannelValidity(TimeValue t, int nchan);
		virtual void SetChannelValidity(int nchan, Interval v) { }
		CoreExport void UpdateValidity(int nchan, Interval v);  // AND in interval v to channel validity

		// invalidate the specified channels
		virtual void InvalidateChannels(ChannelMask channels) { }

		// topology has been changed by a modifier -- update mesh strip/edge lists
		virtual void TopologyChanged() { }

		//
		// does this object implement the generic Deformable Object procs?
		//
		virtual int IsDeformable() { return 0; } 

		// DeformableObject procs: only need be implemented  
		// IsDeformable() returns TRUE.
		virtual int NumPoints(){ return 0;}
		virtual Point3 GetPoint(int i) { return Point3(0,0,0); }
		virtual void SetPoint(int i, const Point3& p) {}             
			
		// Completes the deformable object access with two methods to
		// query point selection. 
		// IsPointSelected returns a TRUE/FALSE value
		// PointSelection returns the weighted point selection, if supported.
		// Harry D, 11/98
		virtual BOOL IsPointSelected (int i) { return FALSE; }
		virtual float PointSelection (int i) {
			return IsPointSelected(i) ? 1.0f : 0.0f;
		}

		// These allow the NURBS Relational weights to be modified
		virtual BOOL HasWeights() { return FALSE; }
		virtual double GetWeight(int i) { return 1.0; }
		virtual void SetWeight(int i, const double w) {}

        // Get the count of faces and vertices for the polyginal mesh
        // of an object.  If it return FALSE, then this function
        // isn't supported.  Plug-ins should use GetPolygonCount(Object*, int&, int&)
        // to count the polys in an arbitrary object
        virtual BOOL PolygonCount(TimeValue t, int& numFaces, int& numVerts) { return FALSE; }

		// informs the object that its points have been deformed,
		// so it can invalidate its cache.
		virtual void PointsWereChanged(){}

		// deform the object with a deformer.
		CoreExport virtual void Deform(Deformer *defProc, int useSel=0);

		// box in objects local coords or optional space defined by tm
		// If useSel is true, the bounding box of selected sub-elements will be taken.
		CoreExport virtual void GetDeformBBox(TimeValue t, Box3& box, Matrix3 *tm=NULL, BOOL useSel=FALSE );

		//
		// does this object implement the generic Mappable Object procs?
		//
		virtual int IsMappable() { return 0; }
		virtual int NumMapChannels () { return IsMappable(); }	// returns number possible.
		virtual int NumMapsUsed () { return NumMapChannels(); }	// at least 1+(highest channel in use).

		// This does the texture map application -- Only need to implement if
		// IsMappable returns TRUE
		virtual void ApplyUVWMap(int type,
			float utile, float vtile, float wtile,
			int uflip, int vflip, int wflip, int cap,
			const Matrix3 &tm,int channel=1) {}

		// Objects need to be able convert themselves 
		// to TriObjects. Most modifiers will ask for
		// Deformable Objects, and triobjects will suffice.

		CoreExport virtual int CanConvertToType(Class_ID obtype);
		CoreExport virtual Object* ConvertToType(TimeValue t, Class_ID obtype);
		
		// Indicate the types this object can collapse to
		virtual Class_ID PreferredCollapseType() {return Class_ID(0,0);}
		CoreExport virtual void GetCollapseTypes(Tab<Class_ID> &clist,Tab<TSTR*> &nlist);

		// return the current sub-selection state
		virtual DWORD GetSubselState() {return 0;} 
		virtual void SetSubSelState(DWORD s) {}

		// If the requested channels are locked, replace their data
		// with a copy/ and unlock them, otherwise leave them alone
		CoreExport void ReadyChannelsForMod(ChannelMask channels);

		// Virtual methods to be implemented by plug-in object:-----
		
		// Makes a copy of its "shell" and shallow copies only the
		// specified channels.  Also copies the validity intervals of
		// the copied channels, and sets Invalidates the other intervals.
		virtual Object *MakeShallowCopy(ChannelMask channels) { return NULL; }

		// Shallow-copies the specified channels from the fromOb to this.
		// Also copies the validity intervals. 
		virtual void ShallowCopy(Object* fromOb, ChannelMask channels) {}

		// This replaces locked channels with newly allocated copies.
		// It will only be called if the channel is locked.
		virtual void NewAndCopyChannels(ChannelMask channels) {}                

		// Free the specified channels
		virtual void FreeChannels(ChannelMask channels) {}                                      
	  
		Interval GetNoEvalInterval() { return noEvalInterval; }
		void SetNoEvalInterval(Interval iv) {noEvalInterval = iv; }

		// Give the object chance to reduce its caches, 
		// depending on the noEvalInterval.
		CoreExport virtual void ReduceCaches(TimeValue t);

		// Is this object a construction object:
		virtual int IsConstObject() { return 0; }               

		// Retreives sub-object branches from an object that supports branching.
		// Certain objects combine a series of input objects (pipelines) into
		// a single object. These objects act as a multiplexor allowing the
		// user to decide which branch(s) they want to see the history for.
		//
		// It is up to the object how they want to let the user choose. The object
		// may use sub object selection to allow the user to pick a set of
		// objects for which the common history will be displayed.
		// 
		// When the history changes for any reason, the object should send
		// a notification (REFMSG_BRANCHED_HISTORY_CHANGED) via NotifyDependents.
		//
		virtual int NumPipeBranches() {return 0;}
		virtual Object *GetPipeBranch(int i) {return NULL;}
		
		// When an object has sub-object branches, it is likely that the
		// sub-objects are transformed relative to the object. This method
		// gives the object a chance to modify the node's transformation so
		// that operations (like edit modifiers) will work correctly when 
		// editing the history of the sub object branch.
		virtual INode *GetBranchINode(TimeValue t,INode *node,int i) {return node;}

		// Shape viewports can reference shapes contained within objects, so we
		// need to be able to access shapes within an object.  The following methods
		// provide this access
		virtual int NumberOfContainedShapes() { return -1; }    // NOT a container!
		virtual ShapeObject *GetContainedShape(TimeValue t, int index) { return NULL; }
		virtual void GetContainedShapeMatrix(TimeValue t, int index, Matrix3 &mat) {}
		virtual BitArray ContainedShapeSelectionArray() { return BitArray(); }

        // Return TRUE for ShapeObject class or GeomObjects that are Shapes too
        virtual BOOL IsShapeObject() { return FALSE; }
    
		// For debugging only. TriObject inplements this method by making sure
		// its face's vert indices are all valid.
		virtual BOOL CheckObjectIntegrity() {return TRUE;}              

		// Find out if the Object is generating UVW's
		virtual BOOL HasUVW() { return 0; }
		// or on any map channel:
		virtual BOOL HasUVW (int mapChannel) { return (mapChannel==1) ? HasUVW() : FALSE; }

		// This is overridden by DerivedObjects to search up the pipe for the base object
		virtual Object *FindBaseObject() { return this;	}

		// Access a parametric position on the surface of the object
		virtual BOOL IsParamSurface() {return FALSE;}
		virtual int NumSurfaces(TimeValue t) {return 1;}
		// Single-surface version (surface 0)
		virtual Point3 GetSurfacePoint(TimeValue t, float u, float v,Interval &iv) {return Point3(0,0,0);}
		// Multiple-surface version (Implement if you override NumSurfaces)
		virtual Point3 GetSurfacePoint(TimeValue t, int surface, float u, float v,Interval &iv) {return Point3(0,0,0);}
		// Get information on whether a surface is closed (default is closed both ways)
		virtual void SurfaceClosed(TimeValue t, int surface, BOOL &uClosed, BOOL &vClosed) {uClosed = vClosed = TRUE;}

		// Allow an object to return extended Properties fields
		// Return TRUE if you take advantage of these, and fill in all strings
		virtual BOOL GetExtendedProperties(TimeValue t, TSTR &prop1Label, TSTR &prop1Data, TSTR &prop2Label, TSTR &prop2Data) {return FALSE;}

		// Allow the object to enlarge its viewport rectangle, if it wants to.
		virtual void MaybeEnlargeViewportRect(GraphicsWindow *gw, Rect &rect) {}

		// Animatable Overides...
		CoreExport SvGraphNodeReference SvTraverseAnimGraph(IGraphObjectManager *gom, Animatable *owner, int id, DWORD flags);
		CoreExport bool SvHandleDoubleClick(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport TSTR SvGetName(IGraphObjectManager *gom, IGraphNode *gNode, bool isBeingEdited);
		CoreExport COLORREF SvHighlightColor(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport bool SvIsSelected(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport MultiSelectCallback* SvGetMultiSelectCallback(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport bool SvCanSelect(IGraphObjectManager *gom, IGraphNode *gNode);
	};


// This function should be used to count polygons in an object.
// It uses Object::PolygonCount() if it is supported, and converts to
// a TriObject and counts faces and vertices otherwise.
CoreExport void GetPolygonCount(TimeValue t, Object* pObj, int& numFaces, int& numVerts);

/*------------------------------------------------------------------- 
  CameraObject:  
---------------------------------------------------------------------*/

#define CAM_HITHER_CLIP         1
#define CAM_YON_CLIP            2

#define ENV_NEAR_RANGE          0
#define ENV_FAR_RANGE           1

struct CameraState {
	BOOL isOrtho;	// true if cam is ortho, false for persp
	float fov;      // field-of-view for persp cams, width for ortho cams
	float tdist;    // target distance for free cameras
	BOOL horzLine;  // horizon line display state
	int manualClip;
	float hither;
	float yon;
	float nearRange;
	float farRange;
	};

class  CameraObject: public Object {
	public:
	SClass_ID SuperClassID() { return CAMERA_CLASS_ID; }
	int IsRenderable() { return(0);}
	virtual void InitNodeName(TSTR& s) { s = _T("Camera"); }
	virtual int UsesWireColor() { return FALSE; }   // TRUE if the object color is used for display
	
	// Method specific to cameras:
	virtual RefResult EvalCameraState(TimeValue time, Interval& valid, CameraState* cs)=0;
	virtual void SetOrtho(BOOL b)=0;
	virtual BOOL IsOrtho()=0;
	virtual void SetFOV(TimeValue time, float f)=0; 
	virtual float GetFOV(TimeValue t, Interval& valid = Interval(0,0))=0;
	virtual void SetTDist(TimeValue time, float f)=0; 
	virtual float GetTDist(TimeValue t, Interval& valid = Interval(0,0))=0;
	virtual int GetManualClip()=0;
	virtual void SetManualClip(int onOff)=0;
	virtual float GetClipDist(TimeValue t, int which, Interval &valid=Interval(0,0))=0;
	virtual void SetClipDist(TimeValue t, int which, float val)=0;
	virtual void SetEnvRange(TimeValue time, int which, float f)=0; 
	virtual float GetEnvRange(TimeValue t, int which, Interval& valid = Interval(0,0))=0;
	virtual void SetEnvDisplay(BOOL b, int notify=TRUE)=0;
	virtual BOOL GetEnvDisplay(void)=0;
	virtual void RenderApertureChanged(TimeValue t)=0;
	virtual void UpdateTargDistance(TimeValue t, INode* inode) {}
	};


/*------------------------------------------------------------------- 
  LightObject:   
---------------------------------------------------------------------*/

#define LIGHT_ATTEN_START       0
#define LIGHT_ATTEN_END         1

struct LightState {
    LightType type;
	Matrix3 tm;
	Color color;
	float 	intens;  // multiplier value
	float 	hotsize; 
	float 	fallsize;
	int		useNearAtten;
	float	nearAttenStart;
	float	nearAttenEnd;
	int   	useAtten;
	float 	attenStart;
	float 	attenEnd;
	int   	shape;
	float 	aspect;
	BOOL   	overshoot;
	BOOL   	shadow;
    BOOL 	on;      // light is on
	BOOL	affectDiffuse;
	BOOL	affectSpecular;
	BOOL 	ambientOnly;  // affect only ambient component
	DWORD   extra;
	};

class LightDesc;
class RendContext;


// This is a callback class that can be given to a ObjLightDesc
// to have a ray traced through the light volume.
class LightRayTraversal {
	public:
		// This is called for every step (return FALSE to halt the integration).
		// t0 and t1 define the segment in terms of the given ray.
		// illum is the light intensity over the entire segment. It can be
		// assumed that the light intensty is constant for the segment.
		virtual BOOL Step(float t0, float t1, Color illum, float distAtten)=0;
	};

// Flags passed to TraverseVolume
#define TRAVERSE_LOWFILTSHADOWS (1<<0)
#define TRAVERSE_HIFILTSHADOWS  (1<<1)
#define TRAVERSE_USESAMPLESIZE	(1<<2)

// A light must be able to create one of these to give to the renderer.
// The Illuminate() method (inherited from LightDesc) is called by the renderer
// to illuminate a surface point.
class ObjLightDesc : public LightDesc {
	public:         
		// This data will be set up by the default implementation of Update()
		LightState ls;
		INode *inode;
		BOOL uniformScale; // for optimizing
		Point3 lightPos;
		Matrix3 lightToWorld;
		Matrix3 worldToLight;
		Matrix3 lightToCam;   // updated in UpdateViewDepParams
		Matrix3 camToLight;   // updated in UpdateViewDepParams
		int renderNumber;   // set by the renderer. Used in RenderInstance::CastsShadowsFrom()

		CoreExport ObjLightDesc(INode *n);
		CoreExport virtual ~ObjLightDesc();

		virtual NameTab* GetExclList() { return NULL; }  

		// update light state that depends on position of objects&lights in world.
		CoreExport virtual int Update(TimeValue t, const RendContext &rc, RenderGlobalContext *rgc, BOOL shadows, BOOL shadowGeomChanged);

		// update light state that depends on global light level.
		CoreExport virtual void UpdateGlobalLightLevel(Color globLightLevel) {}

		// update light state that depends on view matrix.
		CoreExport virtual int UpdateViewDepParams(const Matrix3& worldToCam);

		// default implementation 
		CoreExport virtual Point3 LightPosition() { return lightPos; }
		
		// This function traverses a ray through the light volume.
		// 'ray' defines the parameter line that will be traversed.
		// 'minStep' is the smallest step size that caller requires, Note that
		// the callback may be called in smaller steps if they light needs to
		// take smaller steps to avoid under sampling the volume.
		// 'tStop' is the point at which the traversal will stop (ray.p+tStop*ray.dir).
		// Note that the traversal can terminate earlier if the callback returns FALSE.
		// 'proc' is the callback object.
		//
		// attenStart/End specify a percent of the light attenuation distances
		// that should be used for lighting durring the traversal.
		//
		// The shade context passed in should only be used for state (like are
		// shadows globaly disabled). The position, normal, etc. serve no purpose.
		virtual void TraverseVolume(
			ShadeContext& sc,       
			const Ray &ray, int samples, float tStop,
			float attenStart, float attenEnd,
			DWORD flags,
			LightRayTraversal *proc) {}
	};

// Values returned from GetShadowMethod()
#define LIGHTSHADOW_NONE                0
#define LIGHTSHADOW_MAPPED              1
#define LIGHTSHADOW_RAYTRACED   2


class  LightObject: public Object {
	public:
	SClass_ID SuperClassID() { return LIGHT_CLASS_ID; }
	int IsRenderable() { return(0);}
	virtual void InitNodeName(TSTR& s) { s = _T("Light"); }

	// Methods specific to Lights:
	virtual RefResult EvalLightState(TimeValue time, Interval& valid, LightState *ls)=0;
	virtual ObjLightDesc *CreateLightDesc(INode *n) {return NULL;}
	virtual void SetUseLight(int onOff)=0;
	virtual BOOL GetUseLight(void)=0;
	virtual void SetHotspot(TimeValue time, float f)=0; 
	virtual float GetHotspot(TimeValue t, Interval& valid = Interval(0,0))=0;
	virtual void SetFallsize(TimeValue time, float f)=0; 
	virtual float GetFallsize(TimeValue t, Interval& valid = Interval(0,0))=0;
	virtual void SetAtten(TimeValue time, int which, float f)=0; 
	virtual float GetAtten(TimeValue t, int which, Interval& valid = Interval(0,0))=0;
	virtual void SetTDist(TimeValue time, float f)=0; 
	virtual float GetTDist(TimeValue t, Interval& valid = Interval(0,0))=0;
	virtual void SetConeDisplay(int s, int notify=TRUE)=0;
	virtual BOOL GetConeDisplay(void)=0;
	virtual int GetShadowMethod() {return LIGHTSHADOW_NONE;}
	virtual void SetRGBColor(TimeValue t, Point3& rgb) {}
	virtual Point3 GetRGBColor(TimeValue t, Interval &valid = Interval(0,0)) {return Point3(0,0,0);}        
	virtual void SetIntensity(TimeValue time, float f) {}
	virtual float GetIntensity(TimeValue t, Interval& valid = Interval(0,0)) {return 0.0f;}
	virtual void SetAspect(TimeValue t, float f) {}
	virtual float GetAspect(TimeValue t, Interval& valid = Interval(0,0)) {return 0.0f;}    
	virtual void SetUseAtten(int s) {}
	virtual BOOL GetUseAtten(void) {return FALSE;}
	virtual void SetAttenDisplay(int s) {}
	virtual BOOL GetAttenDisplay(void) {return FALSE;}      
	virtual void Enable(int enab) {}
	virtual void SetMapBias(TimeValue t, float f) {}
	virtual float GetMapBias(TimeValue t, Interval& valid = Interval(0,0)) {return 0.0f;}
	virtual void SetMapRange(TimeValue t, float f) {}
	virtual float GetMapRange(TimeValue t, Interval& valid = Interval(0,0)) {return 0.0f;}
	virtual void SetMapSize(TimeValue t, int f) {}
	virtual int GetMapSize(TimeValue t, Interval& valid = Interval(0,0)) {return 0;}
	virtual void SetRayBias(TimeValue t, float f) {}
	virtual float GetRayBias(TimeValue t, Interval& valid = Interval(0,0)) {return 0.0f;}
	virtual int GetUseGlobal() {return 0;}
	virtual void SetUseGlobal(int a) {}
	virtual int GetShadow() {return 0;}
	virtual void SetShadow(int a) {}
	virtual int GetShadowType() {return 0;}
	virtual void SetShadowType(int a) {}
	virtual int GetAbsMapBias() {return 0;}
	virtual void SetAbsMapBias(int a) {}
	virtual int GetOvershoot() {return 0;}
	virtual void SetOvershoot(int a) {}
	virtual int GetProjector() {return 0;}
	virtual void SetProjector(int a) {}
	virtual NameTab* GetExclList() {return NULL;}
	virtual BOOL Include() {return FALSE;}
	virtual Texmap* GetProjMap() {return NULL;}
	virtual void SetProjMap(Texmap* pmap) {}
	virtual void UpdateTargDistance(TimeValue t, INode* inode) {}
	};

/*------------------------------------------------------------------- 
  HelperObject:
---------------------------------------------------------------------*/

class  HelperObject: public Object {
	public:
	SClass_ID SuperClassID() { return HELPER_CLASS_ID; }
	int IsRenderable() { return(0); }
	virtual void InitNodeName(TSTR& s) { s = _T("Helper"); }
	virtual int UsesWireColor() { return FALSE; }   // TRUE if the object color is used for display
	virtual BOOL NormalAlignVector(TimeValue t,Point3 &pt, Point3 &norm) {pt=Point3(0,0,0);norm=Point3(0,0,-1);return TRUE;}
	};

/*------------------------------------------------------------------- 
  ConstObject:
---------------------------------------------------------------------*/

#define GRID_PLANE_NONE		-1
#define GRID_PLANE_TOP		0
#define GRID_PLANE_LEFT		1
#define GRID_PLANE_FRONT	2
#define GRID_PLANE_BOTTOM	3
#define GRID_PLANE_RIGHT	4
#define GRID_PLANE_BACK		5

class  ConstObject: public HelperObject {
	private:
		bool m_transient;
	public:
		ConstObject():m_transient(false){};
	
	// Override this function in HelperObject!
	int IsConstObject() { return 1; }

	// Methods specific to construction grids:
	virtual void GetConstructionTM( TimeValue t, INode* inode, ViewExp *vpt, Matrix3 &tm ) = 0;     // Get the transform for this view
	virtual void SetConstructionPlane(int which, int notify=TRUE) = 0;
	virtual int  GetConstructionPlane(void) = 0;
	virtual Point3 GetSnaps( TimeValue t ) = 0;    // Get snap values
	virtual void SetSnaps(TimeValue t, Point3 p) = 0;

	virtual BOOL NormalAlignVector(TimeValue t,Point3 &pt, Point3 &norm) {pt=Point3(0,0,0);norm=Point3(0,0,-1);return TRUE;}

	//JH 09/28/98 for design ver
	bool IsTransient()const {return m_transient;}
	void SetTransient(bool state = true) {m_transient = state;}

	//JH 11/16/98
	virtual void SetExtents(TimeValue t, Point3 halfbox)=0;
	virtual Point3 GetExtents(TimeValue t)=0;
	//JH 09/28/98 for design ver
//	bool IsImplicit()const {return m_implicit;}
//	void SetImplicit(bool state = true) {m_implicit = state;}

	};

/*------------------------------------------------------------------- 
  GeomObject: these are the Renderable objects.  
---------------------------------------------------------------------*/

class  GeomObject: public Object {
	public:         
		virtual void InitNodeName(TSTR& s) { s = _T("Object"); }
		SClass_ID SuperClassID() { return GEOMOBJECT_CLASS_ID; }
		
		virtual int IsRenderable() { return(1); }               

		// If an object creates different  meshes depending on the 
		// particular instance (view-dependent) it should return 1.
		virtual int IsInstanceDependent() { return 0; }

		// GetRenderMesh should be implemented by all renderable GeomObjects.
		// set needDelete to TRUE if the render should delete the mesh, FALSE otherwise
		// Primitives that already have a mesh cached can just return a pointer
		// to it (and set needDelete = FALSE).
		CoreExport virtual Mesh* GetRenderMesh(TimeValue t, INode *inode, View& view, BOOL& needDelete);

		// If this returns NULL, then GetRenderMesh will be called
		CoreExport virtual PatchMesh* GetRenderPatchMesh(TimeValue t, INode *inode, View& view, BOOL& needDelete);

		CoreExport Class_ID PreferredCollapseType();

		virtual BOOL CanDoDisplacementMapping() { return 0; }

	private:
	};


//-- Particle Systems ---------------------------------------------------

// A force field can be applied to a particle system by a SpaceWarp.
// The force field provides a function of position in space, velocity
// and time that gives a force.
// The force is then used to compute an acceleration on a particle
// which modifies its velocity. Typically, particles are assumed to
// to have a normalized uniform mass==1 so the acceleration is F/M = F.
class ForceField {
	public:
		virtual Point3 Force(TimeValue t,const Point3 &pos, const Point3 &vel, int index)=0;
		virtual void DeleteThis() {}
	};

// A collision object can be applied to a particle system by a SpaceWarp.
// The collision object checks a particle's position and velocity and
// determines if the particle will colide with it in the next dt amount of
// time. If so, it modifies the position and velocity.
class CollisionObject {
	public:
		// Check for collision. Return TRUE if there was a collision and the position and velocity have been modified.
		virtual BOOL CheckCollision(TimeValue t,Point3 &pos, Point3 &vel, float dt,int index, float *ct=NULL, BOOL UpdatePastCollide=TRUE)=0;
		virtual Object *GetSWObject()=0;
	};


// Values returned from ParticleCenter()
#define PARTCENTER_HEAD		1  // Particle geometry lies behind the particle position
#define PARTCENTER_CENTER	2  // Particle geometry is centered around particle position
#define PARTCENTER_TAIL		3  // Particle geometry lies in front of the particle position

// The particle system class derived from GeomObject and still has
// GEOMOBJECT_CLASS_ID as its super class.
//
// Given an object, to determine if it is a ParticleObject, call
// GetInterface() with the ID  I_PARTICLEOBJ or use the macro
// GetParticleInterface(anim) which returns a ParticleObject* or NULL.
class ParticleObject: public GeomObject {
	public:
		BOOL IsParticleSystem() {return TRUE;}

		virtual void ApplyForceField(ForceField *ff)=0;
		virtual BOOL ApplyCollisionObject(CollisionObject *co)=0; // a particle can choose no to support this and return FALSE

		// A particle object IS deformable, but does not let itself be
		// deformed using the usual GetPoint/SetPoint methods. Instead
		// a space warp must apply a force field to deform the particle system.
		int IsDeformable() {return TRUE;} 

		// Particle objects don't actually do a shallow copy and therefore 
		// cannot be cached.
		BOOL CanCacheObject() {return FALSE;}


		virtual BOOL NormalAlignVector(TimeValue t,Point3 &pt, Point3 &norm) {pt=Point3(0,0,0);norm=Point3(0,0,-1);return TRUE;}


		// These methods provide information about individual particles
		virtual Point3 ParticlePosition(TimeValue t,int i) {return Point3(0,0,0);}
		virtual Point3 ParticleVelocity(TimeValue t,int i) {return Point3(0,0,0);}
		virtual float ParticleSize(TimeValue t,int i) {return 0.0f;}
		virtual int ParticleCenter(TimeValue t,int i) {return PARTCENTER_CENTER;}
		virtual TimeValue ParticleAge(TimeValue t, int i) {return -1;}
		virtual TimeValue ParticleLife(TimeValue t, int i) {return -1;}

		// This tells the renderer if the ParticleObject's topology doesn't change over time
		// so it can do better motion blur.  This means the correspondence of vertex id to
		// geometrical vertex must be invariant.
		virtual BOOL HasConstantTopology() { return FALSE; }
	};

//----------------------------------------------------------------------


/*------------------------------------------------------------------- 
  ShapeObject: these are the open or closed hierarchical shape objects.  
---------------------------------------------------------------------*/

class PolyShape;
class BezierShape;
class MeshCapInfo;
class PatchCapInfo;
class ShapeHierarchy;

// This class may be requested in the pipeline via the GENERIC_SHAPE_CLASS_ID,
// also set up in the Class_ID object genericShapeClassID

// Options for steps in MakePolyShape (>=0: Use fixed steps)
#define PSHAPE_BUILTIN_STEPS -2         // Use the shape's built-in steps/adaptive settings (default)
#define PSHAPE_ADAPTIVE_STEPS -1        // Force adaptive steps

// Parameter types for shape interpolation (Must match types in spline3d.h & polyshp.h)
#define PARAM_SIMPLE 0		// Parameter space based on segments
#define PARAM_NORMALIZED 1	// Parameter space normalized to curve length

class ShapeObject: public GeomObject {
		BOOL renderable;	// Is it renderable?
		float thickness;	// Renderable thickness
		BOOL generateUVs;	// Generate UV coords on renderable shape if TRUE
	public:
		CoreExport ShapeObject();
		CoreExport ~ShapeObject();	// Must call this on destruction

        virtual BOOL IsShapeObject() { return TRUE; }

		virtual int IntersectRay(TimeValue t, Ray& ray, float& at, Point3& norm) {return FALSE;}
		virtual void InitNodeName(TSTR& s) { s = _T("Shape"); }
		SClass_ID SuperClassID() { return SHAPE_CLASS_ID; }
		virtual int IsRenderable() { return (int)renderable;}
		CoreExport virtual void CopyBaseData(ShapeObject &from);
		// Access methods
		virtual BOOL GetRenderable() { return renderable; }
		virtual float GetThickness() { return thickness; }
		virtual BOOL GetGenUVs() { return generateUVs; }
		CoreExport virtual void SetRenderable(BOOL sw);
		CoreExport virtual void SetThickness(float t);
		CoreExport virtual void SetGenUVs(BOOL sw);
		CoreExport virtual Mesh* GetRenderMesh(TimeValue t, INode *inode, View& view, BOOL& needDelete);
		CoreExport virtual void GetRenderMeshInfo(TimeValue t, INode *inode, View& view, int &nverts, int &nfaces);	// Get info on the rendering mesh
		virtual int NumberOfVertices(TimeValue t, int curve = -1) { return 0; }	// Informational only, curve = -1: total in all curves
		virtual int NumberOfCurves()=0;                 // Number of curve polygons in the shape
		virtual BOOL CurveClosed(TimeValue t, int curve)=0;     // Returns TRUE if the curve is closed
		virtual Point3 InterpCurve3D(TimeValue t, int curve, float param, int ptype=PARAM_SIMPLE)=0;    // Interpolate from 0-1 on a curve
		virtual Point3 TangentCurve3D(TimeValue t, int curve, float param, int ptype=PARAM_SIMPLE)=0;   // Get tangent at point on a curve
		virtual float LengthOfCurve(TimeValue t, int curve)=0;  // Get the length of a curve
		virtual int NumberOfPieces(TimeValue t, int curve)=0;   // Number of sub-curves in a curve
		virtual Point3 InterpPiece3D(TimeValue t, int curve, int piece, float param, int ptype=PARAM_SIMPLE)=0; // Interpolate from 0-1 on a sub-curve
		virtual Point3 TangentPiece3D(TimeValue t, int curve, int piece, float param, int ptype=PARAM_SIMPLE)=0;        // Get tangent on a sub-curve
		virtual MtlID GetMatID(TimeValue t, int curve, int piece) { return 0; }
		virtual BOOL CanMakeBezier() { return FALSE; }                  // Return TRUE if can turn into a bezier representation
		virtual void MakeBezier(TimeValue t, BezierShape &shape) {}     // Create the bezier representation
		virtual ShapeHierarchy &OrganizeCurves(TimeValue t, ShapeHierarchy *hier=NULL)=0;       // Ready for lofting, extrusion, etc.
		virtual void MakePolyShape(TimeValue t, PolyShape &shape, int steps = PSHAPE_BUILTIN_STEPS, BOOL optimize = FALSE)=0;   // Create a PolyShape representation with optional fixed steps & optimization
		virtual int MakeCap(TimeValue t, MeshCapInfo &capInfo, int capType)=0;  // Generate mesh capping info for the shape
		virtual int MakeCap(TimeValue t, PatchCapInfo &capInfo) { return 0; }	// Only implement if CanMakeBezier=TRUE -- Gen patch cap info
		virtual BOOL AttachShape(TimeValue t, INode *thisNode, INode *attachNode, BOOL weldEnds=FALSE, float weldThreshold=0.0f) { return FALSE; }	// Return TRUE if attached
		// UVW Mapping switch access
		virtual BOOL HasUVW() { return GetGenUVs(); }
		virtual void SetGenUVW(BOOL sw) { SetGenUVs(sw); }
		// These handle loading and saving the data in this class. Should be called
		// by derived class BEFORE it loads or saves any chunks
		CoreExport virtual IOResult Save(ISave *isave);
		CoreExport virtual IOResult Load(ILoad *iload);		

		CoreExport virtual Class_ID PreferredCollapseType();
		CoreExport virtual BOOL GetExtendedProperties(TimeValue t, TSTR &prop1Label, TSTR &prop1Data, TSTR &prop2Label, TSTR &prop2Data);
		CoreExport virtual void RescaleWorldUnits(float f);
	private:
	};

// Set ShapeObject's global Constant Cross-Section angle threshold (angle in radians) --
// Used for renderable shapes.
CoreExport void SetShapeObjectCCSThreshold(float angle);

/*------------------------------------------------------------------- 
  WSMObject : This is the helper object for the WSM modifier
---------------------------------------------------------------------*/

class  WSMObject: public Object {
	public:                                         
		SClass_ID SuperClassID() { return WSM_OBJECT_CLASS_ID; }                
		virtual Modifier *CreateWSMMod(INode *node)=0;
		virtual int UsesWireColor() { return FALSE; }   // TRUE if the object color is used for display
		virtual BOOL NormalAlignVector(TimeValue t,Point3 &pt, Point3 &norm) {pt=Point3(0,0,0);norm=Point3(0,0,-1);return TRUE;}
		virtual BOOL SupportsDynamics() { return FALSE; } // TRUE if spacewarp or collision object supports Dynamics

		virtual ForceField *GetForceField(INode *node) {return NULL;}		
	private:
	};



//--- Interface to XRef objects ---------------------------------------------------

class IXRefObject: public Object {
	public:
		Class_ID ClassID() {return Class_ID(XREFOBJ_CLASS_ID,0);}
		SClass_ID SuperClassID() {return SYSTEM_CLASS_ID;}

		// Initialize a new XRef object
		virtual void Init(TSTR &fname, TSTR &oname, Object *ob, BOOL asProxy=FALSE)=0;

		virtual void SetFileName(TCHAR *name, BOOL proxy=FALSE, BOOL update=TRUE)=0;
		virtual void SetObjName(TCHAR *name, BOOL proxy=FALSE)=0;
		virtual void SetUseProxy(BOOL onOff,BOOL redraw=TRUE)=0;
		virtual void SetRenderProxy(BOOL onOff)=0;
		virtual void SetUpdateMats(BOOL onOff)=0;
		virtual void SetIgnoreAnim(BOOL onOff,BOOL redraw=TRUE)=0;
		
		virtual TSTR GetFileName(BOOL proxy=FALSE)=0;
		virtual TSTR GetObjName(BOOL proxy=FALSE)=0;
		virtual TSTR &GetCurFileName()=0;
		virtual TSTR &GetCurObjName()=0;
		virtual BOOL GetUseProxy()=0;
		virtual BOOL GetRenderProxy()=0;
		virtual BOOL GetUpdateMats()=0;
		virtual BOOL GetIgnoreAnim()=0;		
		
		// Causes browse dialogs to appear
		virtual void BrowseObject(BOOL proxy)=0;
		virtual void BrowseFile(BOOL proxy)=0;

		// Try to reload ref
		virtual void ReloadXRef()=0;
	};



//---------------------------------------------------------------------------------


class ControlMatrix3;

// Used with EnumModContexts()
class ModContextEnumProc {
	public:
		virtual BOOL proc(ModContext *mc)=0;  // Return FALSE to stop, TRUE to continue.
	};

/*------------------------------------------------------------------- 
  Modifier: these are the ObjectSpace and World Space modifiers: They are 
  subclassed off of BaseObject so that they can put up a graphical 
  representation in the viewport. 
---------------------------------------------------------------------*/

class  Modifier: public BaseObject {
		friend class ModNameRestore;
		TSTR modName;
	public:
		
		CoreExport virtual TSTR GetName();
		CoreExport virtual void SetName(TSTR n);

		SClass_ID SuperClassID() { return OSM_CLASS_ID; }
		
		// Disables all mod apps that reference this modifier _and_ have a select
		// anim flag turned on.
		void DisableModApps() { NotifyDependents(FOREVER,PART_OBJ,REFMSG_DISABLE); }
		void EnableModApps() {  NotifyDependents(FOREVER,PART_OBJ,REFMSG_ENABLE); }
		
		// This disables or enables the mod. All mod apps referencing will be affected.
		void DisableMod() { 
			SetAFlag(A_MOD_DISABLED);
			NotifyDependents(FOREVER,PART_ALL|PART_OBJECT_TYPE,REFMSG_CHANGE); 
			}
		void EnableMod() {      
			ClearAFlag(A_MOD_DISABLED);
			NotifyDependents(FOREVER,PART_ALL|PART_OBJECT_TYPE,REFMSG_CHANGE); 
			}
		int IsEnabled() { return !TestAFlag(A_MOD_DISABLED); }

		// Same as above but for viewports only
		void DisableModInViews() { 
			SetAFlag(A_MOD_DISABLED_INVIEWS);
			NotifyDependents(FOREVER,PART_ALL|PART_OBJECT_TYPE,REFMSG_CHANGE); 
			}
		void EnableModInViews() {      
			ClearAFlag(A_MOD_DISABLED_INVIEWS);
			NotifyDependents(FOREVER,PART_ALL|PART_OBJECT_TYPE,REFMSG_CHANGE); 
			}
		int IsEnabledInViews() { return !TestAFlag(A_MOD_DISABLED_INVIEWS); }

		CoreExport virtual Interval LocalValidity(TimeValue t);
		virtual ChannelMask ChannelsUsed()=0;
		virtual ChannelMask ChannelsChanged()=0;
		// this is used to invalidate cache's in Edit Modifiers:
		virtual void NotifyInputChanged(Interval changeInt, PartID partID, RefMessage message, ModContext *mc) {}

		// These call ChannelsUsed/Changed() but also OR in GFX_DATA_CHANNEL as appropriate.
		CoreExport ChannelMask TotalChannelsUsed();
		CoreExport ChannelMask TotalChannelsChanged();
		
		// This is the method that is called when the modifier is needed to 
		// apply its effect to the object. Note that the INode* is always NULL
		// for object space modifiers.
		virtual void ModifyObject(TimeValue t, ModContext &mc, ObjectState* os, INode *node)=0;

		// this should return FALSE for things like edit modifiers
		virtual int NeedUseSubselButton() { return 1; }
			  
		// Modifiers that place a dependency on topology should return TRUE
		// for this method. An example would be a modifier that stores a selection
		// set base on vertex indices.
		virtual BOOL DependOnTopology(ModContext &mc) {return FALSE;}

		// this can return:
		//   DEFORM_OBJ_CLASS_ID -- not really a class, but so what
		//   MAPPABLE_OBJ_CLASS_ID -- ditto
		//   TRIOBJ_CLASS_ID
		//   BEZIER_PATCH_OBJ_CLASS_ID
		virtual Class_ID InputType()=0;

		virtual void ForceNotify(Interval& i) 
			{NotifyDependents(i,ChannelsChanged(),REFMSG_CHANGE );}

		virtual IOResult SaveLocalData(ISave *isave, LocalModData *ld) { return IO_OK; }  
		virtual IOResult LoadLocalData(ILoad *iload, LocalModData **pld) { return IO_OK; }  

		// These handle loading and saving the modifier name. Should be called
		// by derived class BEFORE it loads or saves any chunks
		CoreExport IOResult Save(ISave *isave);
		CoreExport IOResult Load(ILoad *iload);

		// This will call proc->proc once for each application of the modifier.
		CoreExport void EnumModContexts(ModContextEnumProc *proc);

		// Animatable Overides...
		CoreExport SvGraphNodeReference SvTraverseAnimGraph(IGraphObjectManager *gom, Animatable *owner, int id, DWORD flags);
		CoreExport TSTR SvGetName(IGraphObjectManager *gom, IGraphNode *gNode, bool isBeingEdited);
		CoreExport bool SvCanSetName(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport bool SvSetName(IGraphObjectManager *gom, IGraphNode *gNode, TSTR &name);
		CoreExport bool SvHandleDoubleClick(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport COLORREF SvHighlightColor(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport bool SvIsSelected(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport MultiSelectCallback* SvGetMultiSelectCallback(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport bool SvCanSelect(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport bool SvCanInitiateLink(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport bool SvCanConcludeLink(IGraphObjectManager *gom, IGraphNode *gNode, IGraphNode *gNodeChild);
		CoreExport bool SvLinkChild(IGraphObjectManager *gom, IGraphNode *gNodeThis, IGraphNode *gNodeChild);
		CoreExport bool SvCanRemoveThis(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport bool SvRemoveThis(IGraphObjectManager *gom, IGraphNode *gNode);
	private:
	};

class  OSModifier: public Modifier {
	public:
		SClass_ID SuperClassID() { return OSM_CLASS_ID; }
	};

class  WSModifier: public Modifier {
	public:
		SClass_ID SuperClassID() { return WSM_CLASS_ID; }
	};

void CoreExport MakeHitRegion(HitRegion& hr, int type, int crossing, int epsi, IPoint2 *p);

class PolyLineProc {
	public:
	virtual int proc(Point3 *p, int n)=0;
	virtual void SetLineColor(float r, float g, float b) {}
	virtual void SetLineColor(Point3 c) {}
	virtual void Marker(Point3 *p,MarkerType type) {}
	};

class DrawLineProc:public PolyLineProc {
	GraphicsWindow *gw;
	public:
		DrawLineProc() { gw = NULL; }
		DrawLineProc(GraphicsWindow *g) { gw = g; }
		int proc(Point3 *p, int n) { gw->polyline(n, p, NULL, NULL, 0, NULL); return 0; }
		void SetLineColor(float r, float g, float b) {gw->setColor(LINE_COLOR,r,g,b);}
		void SetLineColor(Point3 c) {gw->setColor(LINE_COLOR,c);}
		void Marker(Point3 *p,MarkerType type) {gw->marker(p,type);}
	};

class BoxLineProc:public PolyLineProc {
	Box3 box;
	Matrix3 *tm;
	public:
		BoxLineProc() { box.Init();}
		BoxLineProc(Matrix3* m) { tm = m;  box.Init(); }
		Box3& Box() { return box; }
		CoreExport int proc(Point3 *p, int n);
		CoreExport void Marker(Point3 *p,MarkerType type);
	};


// Apply the PolyLineProc to each edge (represented by an array of Point3's) of the box
// after passing it through the Deformer def.
void CoreExport DoModifiedBox(Box3& box, Deformer &def, PolyLineProc& lp);
void CoreExport DoModifiedLimit(Box3& box, float z, int axis, Deformer &def, PolyLineProc& lp);
void CoreExport DrawCenterMark(PolyLineProc& lp, Box3& box );

// Some functions to draw mapping icons
void CoreExport DoSphericalMapIcon(BOOL sel,float radius, PolyLineProc& lp);
void CoreExport DoCylindricalMapIcon(BOOL sel,float radius, float height, PolyLineProc& lp);
void CoreExport DoPlanarMapIcon(BOOL sel,float width, float length, PolyLineProc& lp);

//---------------------------------------------------------------------
// Data structures for keeping log of hits during sub-object hit-testing.
//---------------------------------------------------------------------

class HitLog;
class HitRecord {
	friend class HitLog;    
	HitRecord *next;
	public:         
		INode *nodeRef;
		ModContext *modContext;
		DWORD distance;
		ulong hitInfo;
		HitData *hitData;
		HitRecord() { next = NULL; modContext = NULL; distance = 0; hitInfo = 0; hitData = NULL;}
		HitRecord(INode *nr, ModContext *mc, DWORD d, ulong inf, HitData *hitdat) {
			next = NULL;
			nodeRef = nr; modContext = mc; distance = d; hitInfo = inf; hitData = hitdat;
			}               
		HitRecord(HitRecord *n,INode *nr, ModContext *mc, DWORD d, ulong inf, HitData *hitdat) {
			next = n;
			nodeRef = nr; modContext = mc; distance = d; hitInfo = inf; hitData = hitdat;
			}               
		HitRecord *     Next() { return next; }
		~HitRecord() { if (hitData) { delete hitData; hitData = NULL; } }
	};                                      

class HitLog {
	HitRecord *first;
	int hitIndex;
	public:
		HitLog()  { first = NULL; hitIndex = 0; }
		~HitLog() { Clear(); }
		CoreExport void Clear();
		CoreExport void ClearHitIndex()		{ hitIndex = 0; }
		CoreExport void IncrHitIndex()		{ hitIndex++; }
		HitRecord* First() { return first; }
		CoreExport HitRecord* ClosestHit();
		CoreExport void LogHit(INode *nr, ModContext *mc, DWORD dist, ulong info, HitData *hitdat = NULL);
	};


// Creates a new empty derived object, sets it to point at the given
// object and returns a pointer to the derived object.
CoreExport Object *MakeObjectDerivedObject(Object *obj);


// Category strings for space warp objects:

#define SPACEWARP_CAT_GEOMDEF		1
#define SPACEWARP_CAT_MODBASED		2
#define SPACEWARP_CAT_PARTICLE		3

CoreExport TCHAR *GetSpaceWarpCatString(int id);


#endif //_OBJECT_