/**********************************************************************
 *<
	FILE: imtl.h

	DESCRIPTION: Renderer materials

	CREATED BY: Dan Silva

	HISTORY:

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

#ifndef __IMTL__H
#define __IMTL__H


#include <plugapi.h>
#include <RenderElements.h>

//#include "gport.h"	
#include "custcont.h" 
#include "shape.h"
#include "buildver.h"

#define PROJ_PERSPECTIVE 0   // perspective projection
#define PROJ_PARALLEL 1      // parallel projection

#define AXIS_UV 0
#define AXIS_VW 1
#define AXIS_WU 2

// Values for SymFlags:
#define U_WRAP   (1<<0)
#define V_WRAP   (1<<1)  
#define U_MIRROR (1<<2)
#define V_MIRROR (1<<3)
#define UV_NOISE (1<<4)
#define UV_NOISE_ANI (1<<5)


#define	X_AXIS 0
#define	Y_AXIS 1
#define	Z_AXIS 2

static inline float Intens(const AColor& c) {	return (c.r+c.g+c.b)/3.0f;	}
static inline float Intens(const Color& c) {	return (c.r+c.g+c.b)/3.0f;	}

// Meta-materials post this message to the MtlEditor when user
// clicks on a sub-material button.
#define WM_SUB_MTL_BUTTON	WM_USER + 0x04001

// Materials or Texture maps post this message to the MtlEditor when user
// clicks on a texture map button.
#define WM_TEXMAP_BUTTON	WM_USER + 0x04002

class ShadeContext;
class Bitmap;
class RenderMapsContext; 
class Object;
class UVGen;
class XYZGen;
class Sampler;

// Postage Stamp images ----------
// GetImage fills an array RGB triples.
// Width() and Height() return the dimensions of the image in pixels. 
// The width in bytes of the array is given by the following macro, where w is pixel width. 

#define PS_SMALL 0
#define PS_LARGE 1
#define PS_TINY  2

#define PS_TINY_SIZE  24  // size of the tiny postage stamps
#define PS_SMALL_SIZE 32  // size of the small postage stamps
#define PS_LARGE_SIZE 88  // size of the large postage stamps
#define PSDIM(isz) ((isz==0)?PS_SMALL_SIZE:(isz==1)?PS_LARGE_SIZE:PS_TINY_SIZE)

#define ByteWidth(w) (((w*3+3)/4)*4)

class PStamp: public AnimProperty {
	public:
	virtual int Width()=0;
	virtual int Height()=0;
	virtual void SetImage(UBYTE *img)=0;
	virtual void GetImage(UBYTE *img)=0;
	virtual void DeleteThis()=0;
	virtual IOResult Load(ILoad *iload)=0;
	virtual IOResult Save(ISave *isave)=0;
	};

class TexHandle {
	public:
		virtual DWORD_PTR GetHandle() = 0;
		virtual void DeleteThis() = 0;
	};		

// Values for extraFlags:
#define EX_MULT_ALPHA     1    // if alpha is NOT premultiplied in the Bitmap, set this 
#define EX_RGB_FROM_ALPHA 2    // make map using alpha to define gray level 
#define EX_OPAQUE_ALPHA   4    // make map using opaque alpha 
#define EX_ALPHA_FROM_RGB 8    // make alpha from intensity 

class TexHandleMaker{
	public: 
		// choice of two ways to create a texture handle.
		// From a 3DSMax Bitmap
		virtual TexHandle* CreateHandle(Bitmap *bm, int symflags=0, int extraFlags=0)=0;

		// From a 32 bit DIB
		virtual TexHandle* CreateHandle(BITMAPINFO *bminf, int symflags=0, int extraFlags=0)=0;

		// Create an 32 bit DIB with symmetry, extraflags already incorporated.
		// iff forceW is non-zero, it is used as the width of the final DIB 
		// iff forceH is non-zero, it is used as the height of the final DIB 
		virtual BITMAPINFO *BitmapToDIB(Bitmap *bm, int symflags, int extraFlags, BOOL forceW=0, BOOL forceH=0)=0;

		// From a 32 bit DIB that has symflags, extraflags already incorporated.
		virtual TexHandle* MakeHandle(BITMAPINFO*bminf)=0;  // this takes ownership of the BITMAPINFO*

		// This tells you the size desired of the bitmap. It ultimately
		// needs a bitmap that is a power of 2 in width and height.  If 
		// UseClosestPowerOf2 returns TRUE, then the bitmap need not be square.
		// If you already have a bitmap around, just pass it in to CreateHandle
		// and it will be converted.  If you are making a bitmap from scratch
		// (i.e.) a procedural texture, then you should make it Size() in 
		// width in height, and save us an extra step.  In either case
		// You own your bitmap, and are responsible for ultimately freeing it.

		virtual BOOL UseClosestPowerOf2()=0;
		virtual int Size()=0;
	};


// Callback used with the new multi-texture interface by function SetGfxMtl. 
class MtlMakerCallback: public TexHandleMaker {
	public:
	// This fills all the fields of texinf exept the texhandle and the texture ops.
	// note TexInfo is defined in mlt.h
	virtual void GetGfxTexInfoFromTexmap(TimeValue t, TextureInfo& texinf, Texmap *txm)=0;
	virtual BOOL NumberTexturesSupported()=0; // how many textures does the hardware+driver support
	};


// passed to SetPickMode. This is a callback that gets called as
// the user tries to pick objects in the scene.
class PickObjectProc {
	public:
		// Called when the user picks something.
		// return TRUE to end the pick mode.
		virtual BOOL Pick(INode *node)=0;

		// Return TRUE if this is an acceptable hit, FALSE otherwise.
		virtual BOOL Filter(INode *node)=0;

		// These are called as the mode is entered and exited
		virtual void EnterMode() {}
		virtual void ExitMode() {}

		// Provides two cursor, 1 when over a pickable object and 1 when not.
		virtual HCURSOR GetDefCursor() {return NULL;}
		virtual HCURSOR GetHitCursor() {return NULL;}

		// Return TRUE to allow the user to pick more than one thing.
		// In this case the Pick method may be called more than once.
		virtual BOOL AllowMultiSelect() {return FALSE;}
	};


// Interface that is passed in to the Mtl or Texture Map when it is in the mtl
// editor.
class IMtlParams : public InterfaceServer {
	public:
	// call after mouse up's in mtls params
	// It causes the viewports to be redrawn.
	virtual void MtlChanged()=0;  

	// Adds rollup pages to the Material Params. Returns the window
	// handle of the dialog that makes up the page.
	virtual HWND AddRollupPage( HINSTANCE hInst, TCHAR *dlgTemplate, 
		DLGPROC dlgProc, TCHAR *title, LPARAM param=0,DWORD flags=0, int category = ROLLUP_CAT_STANDARD )=0;

	virtual HWND AddRollupPage( HINSTANCE hInst, DLGTEMPLATE *dlgTemplate, 
		DLGPROC dlgProc, TCHAR *title, LPARAM param=0,DWORD flags=0, int category = ROLLUP_CAT_STANDARD )=0;


	// Adds rollup pages to the Material Params. Returns the window
	// handle of the dialog that makes up the page.
	virtual HWND ReplaceRollupPage( HWND hOldRollup, HINSTANCE hInst, TCHAR *dlgTemplate, 
		DLGPROC dlgProc, TCHAR *title, LPARAM param=0,DWORD flags=0, int category = ROLLUP_CAT_STANDARD  )=0;

	virtual HWND ReplaceRollupPage( HWND hOldRollup, HINSTANCE hInst, DLGTEMPLATE *dlgTemplate, 
		DLGPROC dlgProc, TCHAR *title, LPARAM param=0,DWORD flags=0, int category = ROLLUP_CAT_STANDARD  )=0;

	// Removes a rollup page and destroys it.  When a dialog is destroyed
	// it need not delete all its rollup pages: the Mtl Editor will do
	// this for it, and it is more efficient.
	virtual void DeleteRollupPage( HWND hRollup )=0;

	// When the user mouses down in dead area, the plug-in should pass
	// mouse messages to this function which will pass them on to the rollup.
	virtual void RollupMouseMessage( HWND hDlg, UINT message, 
				WPARAM wParam, LPARAM lParam )=0;

	virtual int IsRollupPanelOpen(HWND hwnd)=0;
	virtual int GetRollupScrollPos()=0;
	virtual void SetRollupScrollPos(int spos)=0;

	virtual void RegisterTimeChangeCallback(TimeChangeCallback *tc)=0;
	virtual void UnRegisterTimeChangeCallback(TimeChangeCallback *tc)=0;

	// Registers a dialog window so IsDlgMesage() gets called for it.
	// This is done automatically for Rollup Pages.
	virtual void RegisterDlgWnd( HWND hDlg )=0;
	virtual int UnRegisterDlgWnd( HWND hDlg )=0;

	// get the current time.
	virtual TimeValue GetTime()=0;	

	// Pick an object from the scene
	virtual void SetPickMode(PickObjectProc *proc)=0;
	virtual void EndPickMode()=0;

	// JBW 10/19/98: get interface to mtl editor rollup
	virtual IRollupWindow *GetMtlEditorRollup()=0;

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

class ParamDlg;
class Texmap;

class RenderData : public InterfaceServer {
	public:
		virtual void DeleteThis() {delete this;/*should be pure virtual*/}
		virtual INT_PTR Execute(int cmd, ULONG_PTR arg1=0, ULONG_PTR arg2=0, ULONG_PTR arg3=0) { return 0;} 
	};

class LightDesc : public RenderData {
	public:
		BOOL affectDiffuse;
		BOOL affectSpecular;
		BOOL  ambientOnly;
		DWORD  extra;
		LightDesc() { affectDiffuse = affectSpecular = TRUE; ambientOnly = FALSE; }
		// determine color and direction of illumination: return FALSE if light behind surface.
		// also computes dot product with normal dot_nl, and diffCoef which is to be used in
		// place of dot_n for diffuse light computations.
	    virtual BOOL Illuminate(ShadeContext& sc, Point3& normal, Color& color, Point3 &dir, float &dot_nl, float &diffuseCoef){ return 0;}
		
		virtual Point3 LightPosition() { return Point3(0,0,0); } 

	};

#define SHADELIM_FLAT 1
#define SHADELIM_GOURAUD 2
#define SHADELIM_PHONG 3

// Transform Reference frames: 
enum RefFrame { REF_CAMERA=0, REF_WORLD, REF_OBJECT };

#define N_MAX_RENDER_ELEMENTS	32

class ShadeOutput : public BaseInterfaceServer {
	public:
		ULONG flags;
		Color c;  // shaded color
		Color t;  // transparency
		float ior;  // index of refraction
		int gbufId;

		// render elements
		int nElements;
		AColor	elementVals[ N_MAX_RENDER_ELEMENTS ];

		CoreExport void MixIn(ShadeOutput& a, float f);  // (*this) =  (1-f)*(*this) + f*a;
//		ShadeOutput(){};
		ShadeOutput():nElements(0), flags(0), gbufId(0){};
		ShadeOutput( int nEle ):flags(0), gbufId(0){ nElements = nEle; }
		void Reset( int nEle = -1 )
		{ 
			flags = 0;
			gbufId = 0;
			c.Black(); t.Black(); ior = 1.0f;
			// clear nEle's worth of render elements
			if (nEle >= 0)
				nElements = nEle;
			for( int i=0; i < nElements; ++i )
				elementVals[i].r = elementVals[i].g =
					elementVals[i].b = elementVals[i].a = 0.0f;
		}
		ShadeOutput* Clone(){
			ShadeOutput* pNew = new ShadeOutput;
			pNew->flags = flags; pNew->c = c; pNew->t = t; pNew->ior = ior;
			pNew->gbufId = gbufId; pNew->nElements = nElements;
			for( int i=0; i < nElements; ++i )
				pNew->elementVals[i] = elementVals[i];
			return pNew;
		}

		// Render Element interface
		// allocate new val, return index
		int NewElementVal(){
			DbgAssert((nElements+1)<N_MAX_RENDER_ELEMENTS); 
			return nElements++; 
		}
		int NElementVals(){ return nElements; }
		// override new val & set nElements directly, for clear mostly
		void SetNElements( int n ){
			DbgAssert( n>=0 && n<N_MAX_RENDER_ELEMENTS); 
			nElements = n;
		}
		// return rgba value of element n
		AColor ElementVal( int n ){ 
			DbgAssert( n>=0 && n<N_MAX_RENDER_ELEMENTS); 
			return elementVals[n]; 
		}
		// set rgba value of element n
		void SetElementVal( int n, AColor c ){ 
			DbgAssert( n>=0 && n<N_MAX_RENDER_ELEMENTS); 
			elementVals[n] = c; 
		}
		// sum rgba value intof element n
		void AccumElementVal( int n, AColor c ){ 
			DbgAssert( n>=0 && n<N_MAX_RENDER_ELEMENTS); 
			elementVals[n] += c; 
		}
		// sum all color components of a shade output
		void Sum( ShadeOutput* pSample ){
			c += pSample->c; t += pSample->t;
			for( int i = 0; i < nElements; ++i )
				elementVals[i] += pSample->elementVals[i];
		}
		void Scale( float x ){
			c *= x; t *= x;
			for( int i = 0; i < nElements; ++i )
				elementVals[i] *= x;
		}
		// sum all color components, w/o alpha of a shade output
		void SumClr( ShadeOutput* pSample ){
			c += pSample->c; 
			for( int i = 0; i < nElements; ++i ){
				elementVals[i].r += pSample->elementVals[i].r;
				elementVals[i].g += pSample->elementVals[i].g;
				elementVals[i].b += pSample->elementVals[i].b;
			}
		}

		ShadeOutput& operator += ( ShadeOutput& a ){
			c += a.c;  
			t += a.t; 
			for( int i = 0; i < nElements; ++i )
				elementVals[i] += a.elementVals[i];
			return *this;
		}
/*		ShadeOutput& operator *= ( float x ){
			c *= x; t *= x; 
			for( int i = 0; i < nElements; ++i )
				elementVals[i] *= x;
			return *this;
		}
*/
		ShadeOutput& operator *= ( Color x ){
			c *= x; // t *= x; 
			AColor ac( x );
			ac.a = Intens( x );
			for( int i = 0; i < nElements; ++i )
				elementVals[i] *= ac;
			return *this;
		}

		ShadeOutput& operator = ( ShadeOutput& a ){
			flags = a.flags;
			c = a.c; t = a.t; 
			ior = a.ior;
			gbufId = a.gbufId;
			nElements = a.nElements;
			for( int i = 0; i < nElements; ++i )
				elementVals[i] = a.elementVals[i];
			return *this;
		}


	};


class RenderInstance;

struct ISect {
	float t;   // ray parameter
	BOOL exit;
	BOOL backFace;
	RenderInstance *inst;
	int fnum;  // face number
	Point3 bc; // barycentric coords
	Point3 p;  // intersection point, object coords
	Point3 pc;  // intersection point, camera coords
	ULONG matreq;
	int mtlNum;
	ISect *next;
	};

class ISectList {
	public:
	ISect *first;
	ISectList() { first = NULL; }
	~ISectList() { Init(); }
	BOOL IsEmpty() { return first?0:1; }
	CoreExport void Add(ISect *is); 
	CoreExport void Prune(float a); 
	CoreExport void Init();
	};
	
CoreExport ISect *GetNewISect();
CoreExport void DiscardISect(ISect *is);

// Value given to blurFrame for non blurred objects  ( Object motion blur)
#define NO_MOTBLUR (-1) 

class FilterKernel;
class IRenderElement;
class ToneOperator;
typedef 	Tab<IRenderElement*>	RenderElementTab;

class RenderGlobalContext : public BaseInterfaceServer
{
protected:
	IRenderElementMgr *mpIRenderElementMgr; // current render element manager

public:
	Renderer *renderer;
	int projType; 	// PROJ_PERSPECTIVE or PROJ_PARALLEL
	int devWidth, devHeight;
	float xscale, yscale;
	float xc,yc;
	BOOL antialias;
	Matrix3 camToWorld, worldToCam;
	float nearRange, farRange;
	float devAspect;          // PIXEL aspect ratio of device pixel H/W
	float frameDur;
	Texmap *envMap;
	Color globalLightLevel;
	Atmospheric *atmos;
	ToneOperator* pToneOp;	// The tone operator, may be NULL
	TimeValue time;
	BOOL wireMode;		// wire frame render mode?
	float wire_thick;	// global wire thickness
	BOOL force2Side;	// is force two-sided rendering enabled
	BOOL inMtlEdit;		// rendering in mtl editor?
	BOOL fieldRender;	// are we rendering fields
	BOOL first_field;	// is this the first field or the second?
	BOOL field_order;	// which field is first: 0->even first,  1->odd first

	BOOL objMotBlur;	// is object motion blur enabled
	int nBlurFrames;	// number of object motion blur time slices

#ifdef SIMPLIFY_AREA_LIGHTS
	bool simplifyAreaLights; //should area lights degrade to point lights
#endif


	// Methods
	RenderGlobalContext() : pToneOp(NULL), mpIRenderElementMgr(NULL) { }

	// render element methods
	IRenderElementMgr *GetRenderElementMgr() { return mpIRenderElementMgr; }
	void SetRenderElementMgr(IRenderElementMgr *pIRenderElementMgr) { mpIRenderElementMgr = pIRenderElementMgr; }
	int NRenderElements()
	{
#ifndef WEBVERSION
		return mpIRenderElementMgr ? mpIRenderElementMgr->NumRenderElements() : 0;
#else 
		return 0;
#endif
	} 
	IRenderElement* GetRenderElement(int n)
	{
#ifndef WEBVERSION
		return mpIRenderElementMgr ? mpIRenderElementMgr->GetRenderElement(n) : NULL;
#else 
		return NULL;
#endif
	}
	
	Point2 MapToScreen(Point3 p)
	{ 	
		if (projType==1)
		{
			return Point2(  xc + xscale*p.x , yc + yscale*p.y);
		}
		else
		{
			if (p.z==0.0f)
				p.z = .000001f;
			return Point2( xc + xscale*p.x/p.z,  yc + yscale*p.y/p.z);
		}
	}

	virtual FilterKernel* GetAAFilterKernel(){ return NULL; }
	virtual float GetAAFilterSize(){ return 0.0f; }

	// Access RenderInstances
	virtual int NumRenderInstances() { return 0; }
	virtual RenderInstance* GetRenderInstance( int i ) { return NULL; }

	// Evaluate the global environment map using ray as point of view,
	// optionally with atmospheric effect.
	virtual AColor EvalGlobalEnvironMap(ShadeContext &sc, Ray &r, BOOL applyAtmos)
	{ 
		return AColor(0.0f,0.0f,0.0f,1.0f); 
	}

	virtual void IntersectRay(RenderInstance *inst, Ray& ray, ISect &isct, ISectList &xpList, BOOL findExit) {}
	virtual BOOL IntersectWorld(Ray &ray, int skipID, ISect &hit, ISectList &xplist, int blurFrame = NO_MOTBLUR) { return FALSE; }

	virtual ViewParams *GetViewParams() { return NULL; } 

	virtual FILE* DebugFile() { return NULL; }

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


// > 4/19/02 - 12:25am --MQM-- 
// PLUG-IN DEVELOPER NOTE:
//
//    In this release we are using the xshadeID in the
//    ShadeContext to store information during Light Tracer 
//    and VIZ Radiosity renderings.  The developer should be
//    sure to copy the xshadeID whenever creating new shade
//    contexts based off of an existing ShadeContext instance.
//
//    The renderer performs two passes when a radiosity
//    plugin is on.  The first pass is a very minimal pass,
//    and the second is the normal pass.  Shader plugins
//    can test for the pre-pass flag and possibly do less
//    (or no) work.
//
//    During the regular pass, the Light Tracer will max out
//    the rayLevel to halt raytraced reflections during regathering.  
//    Shaders should also not do specular shading or other things 
//    that will increase variance and/or slow regathering performance 
//    down. 

// we are inside of a regathering ray
#define SHADECONTEXT_REGATHERING_FLAG 			0x80000000	
#define SHADECONTEXT_IS_REGATHERING( sc )		( (sc).xshadeID & SHADECONTEXT_REGATHERING_FLAG )

// we are in a pre-pass in the scanline renderer
#define SHADECONTEXT_PREPASS_FLAG 				0x40000000	
#define SHADECONTEXT_IS_PREPASS( sc )			( (sc).xshadeID & SHADECONTEXT_PREPASS_FLAG )

// in recursive eval, so we don't try to 
// regather something that we're already 
// in the middle of...
#define SHADECONTEXT_RECURSIVE_EVAL_FLAG		0x20000000	
#define SHADECONTEXT_IS_RECURSIVE_EVAL( sc )	( (sc).xshadeID & SHADECONTEXT_RECURSIVE_EVAL_FLAG )

// matte material needs a way of getting the shadow values out
// of light tracer.  (this is going away when we can change the sdk!!)
#define SHADECONTEXT_GUESS_SHADOWS_FLAG			0x10000000
#define SHADECONTEXT_GUESS_SHADOWS( sc )		( (sc).xshadeID & SHADECONTEXT_GUESS_SHADOWS_FLAG )

// scanline renderer thread #
#define SHADECONTEXT_THREAD_MASK				0x0000F000	
#define SHADECONTEXT_THREAD_SHIFT				12
#define SHADECONTEXT_GET_THREAD( sc )			( ( (sc).xshadeID & SHADECONTEXT_THREAD_MASK )  >> SHADECONTEXT_THREAD_SHIFT )
#define SHADECONTEXT_SET_THREAD( sc, thread )	{ (sc).xshadeID = ( (sc).xshadeID & (~SHADECONTEXT_THREAD_MASK) )  |  ( ( (thread) << SHADECONTEXT_THREAD_SHIFT ) & SHADECONTEXT_THREAD_MASK ); }

// worker thread #
#define SHADECONTEXT_WORKER_MASK				0x00000F00
#define SHADECONTEXT_WORKER_SHIFT				8
#define SHADECONTEXT_GET_WORKER( sc )			( ( (sc).xshadeID & SHADECONTEXT_WORKER_MASK )  >> SHADECONTEXT_WORKER_SHIFT )
#define SHADECONTEXT_SET_WORKER( sc, worker )	{ (sc).xshadeID = ( (sc).xshadeID & (~SHADECONTEXT_WORKER_MASK) )  |  ( ( (worker) << SHADECONTEXT_WORKER_SHIFT ) & SHADECONTEXT_WORKER_MASK ); }

// bounce # (1..255, 0 not used)
#define SHADECONTEXT_BOUNCE_MASK				0x000000FF
#define SHADECONTEXT_GET_BOUNCE( sc )			( (sc).xshadeID & SHADECONTEXT_BOUNCE_MASK )
#define SHADECONTEXT_SET_BOUNCE( sc, bounce )	{ (sc).xshadeID = ( (sc).xshadeID & (~SHADECONTEXT_BOUNCE_MASK) )  |  ( (bounce) & SHADECONTEXT_BOUNCE_MASK ); }

// general macro to init regathering info in the shade context.
// this wipes out other flags in the xshadeID (prepass, etc)
#define SHADECONTEXT_SET_REGATHERING_INFO( sc, thread, worker, bounce ) \
    { (sc).xshadeID = SHADECONTEXT_REGATHERING_FLAG  |  \
        ( ( (thread) << SHADECONTEXT_THREAD_SHIFT ) & SHADECONTEXT_THREAD_MASK )  |  \
        ( ( (worker) << SHADECONTEXT_WORKER_SHIFT ) & SHADECONTEXT_WORKER_MASK )  |  \
        ( (bounce) & SHADECONTEXT_BOUNCE_MASK ); }


#define SCMODE_NORMAL  0
#define SCMODE_SHADOW  1

//
// Shade Context: passed into Mtls and Texmaps
//
class ShadeContext : public InterfaceServer {
	public:
	ULONG mode;							// normal, shadow ...
	BOOL doMaps;						// apply texture maps?
	BOOL filterMaps;					// should texture be filtered		            
	BOOL shadow;						// apply shadows?
	BOOL backFace;						// are we on the back side of a 2-Sided face?
	int mtlNum;							// sub-mtl number for multi-materials
	Color ambientLight;					// ambient light 
	int nLights;						// number of lights;
	int rayLevel;
	int xshadeID;  						// different for every shade call in a render.
	LightDesc *atmosSkipLight;
	RenderGlobalContext *globContext;
	ShadeOutput out;                    // where a shading leaves its results

	// Reset output & render elements: 
	// param < 0 clears existing elements, leaving nElements unchanged
	// n >= 0 clears n elements & set nElements to n, default is 0
	void ResetOutput( int n = -1 ) { out.Reset(n); }	
	
	virtual Class_ID ClassID() { return Class_ID(0,0); }  // to distinguish different ShadeContexts.
	virtual BOOL InMtlEditor()=0;	// is this rendering the mtl editor sample sphere?
	virtual int Antialias() {return 0;}
	virtual int ProjType() { return 0;} // returns: 0: perspective, 1: parallel
	virtual LightDesc* Light(int n)=0;	// get the nth light. 
	virtual TimeValue CurTime()=0;     	// current time value
	virtual int NodeID() { return -1; }
	virtual INode *Node() { return NULL; }
	virtual Object *GetEvalObject() { return NULL; } // Returns the evaluated object for this node. 
												   // Will be NULL if object is motion blurred	
	virtual Point3 BarycentricCoords() { return Point3(0,0,0);}  // coords relative to triangular face 
	virtual int FaceNumber()=0;			// 
	virtual Point3 Normal()=0;  		// interpolated surface normal, in cameara coords: affected by SetNormal()
	virtual void SetNormal(Point3 p) {}	// used for perturbing normal
	virtual Point3 OrigNormal() { return Normal(); } // original surface normal: not affected by SetNormal();
	virtual Point3 GNormal()=0; 		// geometric (face) normal
	virtual float  Curve() { return 0.0f; }   	    // estimate of dN/dsx, dN/dsy
	virtual Point3 V()=0;       		// Unit view vector: from camera towards P 
	virtual void SetView(Point3 p)=0;	// Set the view vector
	virtual Point3 OrigView() { return V(); } // Original view vector: not affected by SetView();
	virtual	Point3 ReflectVector()=0;	// reflection vector
	virtual	Point3 RefractVector(float ior)=0;	// refraction vector
	virtual void SetIOR(float ior) {} // Set index of refraction
	virtual float GetIOR() { return 1.0f; } // Get index of refraction
	virtual Point3 CamPos()=0;			// camera position
	virtual Point3 P()=0;				// point to be shaded;
	virtual Point3 DP()=0;    		  	// deriv of P, relative to pixel, for AA
	virtual void DP(Point3& dpdx, Point3& dpdy){};  // deriv of P, relative to pixel
	virtual Point3 PObj()=0;   		  	// point in obj coords
	virtual Point3 DPObj()=0;   	   	// deriv of PObj, rel to pixel, for AA
	virtual Box3 ObjectBox()=0; 	  	// Object extents box in obj coords
	virtual Point3 PObjRelBox()=0;	  	// Point rel to obj box [-1 .. +1 ] 
	virtual Point3 DPObjRelBox()=0;	  	// deriv of Point rel to obj box [-1 .. +1 ] 
	virtual void ScreenUV(Point2& uv, Point2 &duv)=0; // screen relative uv (from lower left)
	virtual IPoint2 ScreenCoord()=0; // integer screen coordinate (from upper left)
	virtual Point2 SurfacePtScreen(){ return Point2(0.0,0.0); } // return the surface point in screen coords

	virtual Point3 UVW(int channel=0)=0;  			// return UVW coords for point
	virtual Point3 DUVW(int channel=0)=0; 			// return UVW derivs for point
	virtual void DPdUVW(Point3 dP[3],int channel=0)=0; // Bump vectors for UVW (camera space)

	// BumpBasisVectors: this is going to replace DPdUVW: Now compute bump vectors for 
	//  specific 2D cases only.
	//    axis = AXIS_UV, AXIS_VW, AXIS_WU		
	//    return:     0 => not implemented,  1=> implemented
	// If this function is implemented, it will be used instead of DPdUVW.
	virtual int BumpBasisVectors(Point3 dP[2], int axis, int channel=0) { return 0; } 


	virtual BOOL IsSuperSampleOn(){ return FALSE; }
	virtual BOOL IsTextureSuperSampleOn(){ return FALSE; }
	virtual int GetNSuperSample(){ return 0; }
	virtual float GetSampleSizeScale(){ return 1.0f; }

	// UVWNormal: returns a vector in UVW space normal to the face in UVW space. This can 
	// be CrossProd(U[1]-U[0],U[2]-U[1]), where U[i] is the texture coordinate
	// at the ith vertex of the current face.  Used for hiding textures on
	// back side of objects.
	virtual Point3 UVWNormal(int channel=0) { return Point3(0,0,1); }  

	// diameter of view ray at this point
	virtual float RayDiam() { return Length(DP()); } 

	// angle of ray cone hitting this point: gets increased/decreased by curvature 
	// on reflection
	virtual float RayConeAngle() { return 0.0f; } 

	CoreExport virtual AColor EvalEnvironMap(Texmap *map, Point3 view); //evaluate map with given viewDir
	virtual void GetBGColor(Color &bgcol, Color& transp, BOOL fogBG=TRUE)=0;   // returns Background color, bg transparency

	// Camera ranges set by user in camera's UI.
	virtual float CamNearRange() {return 0.0f;}
	virtual float CamFarRange() {return 0.0f;}

	// Transform to and from internal space
	virtual Point3 PointTo(const Point3& p, RefFrame ito)=0; 
	virtual Point3 PointFrom(const Point3& p, RefFrame ifrom)=0; 
	virtual Point3 VectorTo(const Point3& p, RefFrame ito)=0; 
	virtual Point3 VectorFrom(const Point3& p, RefFrame ifrom)=0; 
	CoreExport virtual Point3 VectorToNoScale(const Point3& p, RefFrame ito); 
	CoreExport virtual Point3 VectorFromNoScale(const Point3& p, RefFrame ifrom); 

	// After being evaluated, if a map or material has a non-zero GBufID, it should
	// call this routine to store it into the shade context.
	virtual void SetGBufferID(int gbid) { out.gbufId = gbid; }

	virtual FILE* DebugFile() { return NULL; }

	virtual AColor EvalGlobalEnvironMap(Point3 dir) { return AColor(0,0,0,0); }

	virtual BOOL GetCache(Texmap *map, AColor &c){ return FALSE; }
	virtual BOOL GetCache(Texmap *map, float &f) { return FALSE; }
	virtual BOOL GetCache(Texmap *map, Point3 &p){ return FALSE; }
	virtual void PutCache(Texmap *map, const AColor &c){}
	virtual void PutCache(Texmap *map, const float f) {}
	virtual void PutCache(Texmap *map, const Point3 &p){}
	virtual void TossCache(Texmap *map) {}
	// Generic expansion function
	virtual INT_PTR Execute(int cmd, ULONG_PTR arg1=0, ULONG_PTR arg2=0, ULONG_PTR arg3=0) { return 0; } 

	// These are used to prevent self shadowing by volumetric lights
	LightDesc *GetAtmosSkipLight() { return atmosSkipLight; }
	void SetAtmosSkipLight(LightDesc *lt) { atmosSkipLight = lt; }

	// render element methods
	virtual int NRenderElements() { 
		return globContext ? globContext->NRenderElements():0;
	}
	virtual IRenderElement *GetRenderElement(int n) { 
		return globContext ? globContext->GetRenderElement(n) : NULL;
	}

	// diffuse illum utility, computes incoming diffuse illumination, for matte/shadow
	CoreExport virtual Color DiffuseIllum();

	// used to preshade in different ways
//	virtual IRenderMode GetIRenderMode(){ return IRM_NORMAL; }
//	IRenderMode GetIRenderMode(){ return iRenderMode; }
//	void SetIRenderMode( IRenderMode mode ){ iRenderMode = mode; }

	// NOTE: All of these methods are inline. The inline definitions not
	// declared here are declared in toneop.h

	// Does this tone operator really map physical values to RGB. This method
	// is provided so shaders can determine whether the shading calculations
	// are in physical or RGB space.
	bool IsPhysicalSpace() const;

	// Map an scaled energy value into RGB. The first version of the
	// method converts a color value and the second converts a monochrome
	// value. The converted color value is stored in <i>energy</i>.
	// The converted monochrome value is returned.
	template< class T >
	void ScaledToRGB( T& energy ) const
		{ if ( globContext != NULL && globContext->pToneOp != NULL )
			globContext->pToneOp->ScaledToRGB( energy ); }
	float ScaledToRGB( float energy ) const;

	// Map an energy value int out.c into RGB. The converted value is stored in
	// out.c.
	void ScaledToRGB( );

	// Scale physical values so they can be used in the renderer. The
	// first version of the method converts a color value and the second
	// converts a monochrome value. The converted color value is stored
	// in <i>energy</i>. The converted monochrome value is returned.
	template< class T >
	void ScalePhysical(T& energy) const
		{ if ( globContext != NULL && globContext->pToneOp != NULL )
			globContext->pToneOp->ScalePhysical( energy ); }
	float ScalePhysical(float energy) const;

	// Scale RGB values, just supplied to invert ScalePhysical. The first
	// version of the method converts a color value and the second
	// converts a monochrome value. The converted color value is stored
	// in <i>energy</i>. The converted monochrome value is returned.
	template< class T >
	void ScaleRGB(T& energy) const
		{ if ( globContext != NULL && globContext->pToneOp != NULL )
			globContext->pToneOp->ScaleRGB( energy ); }
	float ScaleRGB(float energy) const;

	ShadeContext() {
		mode = SCMODE_NORMAL; nLights = 0; shadow = TRUE;  rayLevel = 0; 
		globContext = NULL; atmosSkipLight = NULL; 
	}
};

		
// Material and Texmap flags values
#define MTL_IN_SCENE          	(1<<0)
#define MTL_BEING_EDITED     	(1<<1)  // mtl params being displayed in medit
#define MTL_SUB_BEING_EDITED 	(1<<2)  // sub mtl or tex being displayed in medit 
#define MTL_TEX_DISPLAY_ENABLED (1<<3)  // Viewport display enabled for THIS mtl/tex (see MTL_SUB_DISPLAY_ENABLED)
#define MTL_MEDIT_BACKGROUND    (1<<8)  // Show background in Mtl Editor
#define MTL_MEDIT_BACKLIGHT		(1<<9)  // Backlight in Mtl Editor

#define MTL_OBJTYPE_SHIFT		10
#define MTL_MEDIT_OBJTYPE		(1<<MTL_OBJTYPE_SHIFT) // Object type displayed in Mtl Editor
#define MTL_MEDIT_OBJTYPE_MASK	((1<<MTL_OBJTYPE_SHIFT)|(1<<(MTL_OBJTYPE_SHIFT+1))|(1<<(MTL_OBJTYPE_SHIFT+2)))

#define MTL_TILING_SHIFT		13
#define MTL_MEDIT_TILING		(1<<MTL_TILING_SHIFT) // Object type displayed in Mtl Editor
#define MTL_MEDIT_TILING_MASK	((1<<MTL_TILING_SHIFT)|(1<<(MTL_TILING_SHIFT+1))|(1<<(MTL_TILING_SHIFT+2)))

#ifndef NO_MTLEDITOR_VIDCOLORCHECK  // orb 01-08-2002
#define MTL_MEDIT_VIDCHECK		(1<<16)
#endif

#define MTL_BROWSE_OPEN1		(1<<18)
#define MTL_BROWSE_OPEN2		(1<<19)
#define MTL_SUB_DISPLAY_ENABLED (1<<20)  // flag indicates that texture display is enabled for map or mtl in this subtree

#define MTL_CLONED				(1<<28)  // flag indicates material or texture was created by being cloned from another material or texture. 
#define MTL_HW_MAT_PRESENT		(1<<29)
#define MTL_HW_MAT_ENABLED		(1<<30)

#define MTL_WORK_FLAG			(1<<31)

#define MTL_DISPLAY_ENABLE_FLAGS (MTL_TEX_DISPLAY_ENABLED|MTL_SUB_DISPLAY_ENABLED)  // Interactive texture display enabled for THIS mtl base

#define MTL_HW_TEX_ENABLED		(1<<17)	// flag to indicate whether the texture should be part of the realtime shader

// Material Requirements flags: returned by Requirements() function
#define MTLREQ_2SIDE    		(1<<0)  // 2-sided material
#define MTLREQ_WIRE     		(1<<1)  // Wire frame
#define MTLREQ_WIRE_ABS 		(1<<2)  // Wire frame, absolute size
#define MTLREQ_TRANSP   		(1<<3) 	// transparency
#define MTLREQ_UV				(1<<4)  // requires UVW coords
#define MTLREQ_FACEMAP			(1<<5)  // use "face map" UV coords
#define MTLREQ_XYZ				(1<<6)  // requires object XYZ coords
#define MTLREQ_OXYZ 			(1<<7)  // requires object ORIGINAL XYZ coords
#define MTLREQ_BUMPUV			(1<<8)  // requires UV bump vectors
#define MTLREQ_BGCOL			(1<<9)  // requires background color (e.g. Matte mtl)
#define MTLREQ_PHONG			(1<<10) // requires interpolated normal
#define MTLREQ_AUTOREFLECT 		(1<<11) // needs to build auto-reflect map
#define MTLREQ_AUTOMIRROR 		(1<<12) // needs to build auto-mirror map
#define MTLREQ_NOATMOS 			(1<<13) // suppress atmospheric shader (used by Matte mtl)
#define MTLREQ_ADDITIVE_TRANSP	(1<<14) // composite additively 
#define MTLREQ_VIEW_DEP			(1<<15) // mtl/map is view dependent 
#define MTLREQ_UV2				(1<<16)  // requires second uv channel values (vertex colors)
#define MTLREQ_BUMPUV2			(1<<17)  // requires second uv channel bump vectors
#define MTLREQ_PREPRO	    	(1<<18)  // Pre-processing. BuildMaps will be called on every frame
#define MTLREQ_DONTMERGE_FRAGMENTS 	(1<<19) // inhibit sub-pixel fragment merging, when mtl creates
										    // discontinuities across edges that would normally be smooth.
#define MTLREQ_DISPLACEMAP 		(1<<20) //Material has Displacement map channel
#define MTLREQ_SUPERSAMPLE 		(1<<21) //Material requires supersampling
#define MTLREQ_WORLDCOORDS 		(1<<22) //World coordinates are used in mtl/map evaluation
#define MTLREQ_TRANSP_IN_VP  	(1<<23) //transparent in viewport ( opacity < 100, or opacity map & ShowMapInVP set)
#define MTLREQ_FACETED		  	(1<<24) //render faceted in the viewports
/* JH 5/21/03 Adjusting for R6
#define MTLREQ_2SIDE_SHADOW  	(1<<25) // USED IN RENDERER.
#define MTLREQ_REND2  			(1<<26) // USED IN RENDERER.
#define MTLREQ_REND3  			(1<<27) // USED IN RENDERER.
#define MTLREQ_REND4  			(1<<28) // USED IN RENDERER.
#define MTLREQ_REND5 			(1<<29) // USED IN RENDERER.
#define MTLREQ_REND6 			(1<<30) // USED IN RENDERER.
#define MTLREQ_NOEXPOSURE		(1<<31) // don't do the tone-op (ie, for matte/shadow material, etc)
*/
#define MTLREQ_NOEXPOSURE		(1<<25) // don't do the tone-op (ie, for matte/shadow material, etc)
#define MTLREQ_SS_GLOBAL		(1<<26) //Material requires supersampling but use global sampler

#define MTLREQ_REND1  			(1<<28) // USED IN RENDERER.
#define MTLREQ_REND2  			(1<<29) // USED IN RENDERER.
#define MTLREQ_REND3  			(1<<30) // USED IN RENDERER.
#define MTLREQ_REND4  			(1<<31) // USED IN RENDERER.

#define MAPSLOT_TEXTURE      0 	// texture maps: 
#define MAPSLOT_ENVIRON      1 	// environment maps: generate UVW on-the-fly using view vector, default to spherical
#define MAPSLOT_DISPLACEMENT 2 	// displacement maps: a type of texture map.
#define MAPSLOT_BACKGROUND   3 	// background maps: generate UVW on-the-fly using view vector, default to screen

// Where to get texture vertices: returned by GetUVWSource();
#define UVWSRC_EXPLICIT		0	// use explicit mesh texture vertices (whichever map channel)
#define UVWSRC_OBJXYZ		1	// generate planar uvw mapping from object xyz on-the-fly
#define UVWSRC_EXPLICIT2	2	// use explicit mesh map color vertices as a tex map
#define UVWSRC_WORLDXYZ		3	// generate planar uvw mapping from world xyz on-the-fly
#ifdef GEOREFSYS_UVW_MAPPING
#define UVWSRC_GEOXYZ		4	// generate planar uvw mapping from geo referenced world xyz on-the-fly
#endif
#define UVWSRC_FACEMAP		5	// use face map
#define UVWSRC_HWGEN		6	// use hardware generated texture coords

class ISubMap {
public:
	
	// Methods to access sub texture maps of material or texmap
	virtual int NumSubTexmaps() { return 0; }
	virtual Texmap* GetSubTexmap(int i) { return NULL; }
	virtual int MapSlotType(int i)=0;
	virtual void SetSubTexmap(int i, Texmap *m) { }

	// query ISubMap about the On/Off state of each sub map.
	virtual int SubTexmapOn(int i) { return 1; } 

	CoreExport virtual TSTR GetSubTexmapSlotName(int i);
	CoreExport TSTR GetSubTexmapTVName(int i);

	// called by the ParamMap2 AUTO_UI system if the material/map is letting
	// the system build an AutoMParamDlg for it.  SetDlgThing() is called on
	// a material/map coming into an exsting set of ParamDlgs, once for each 
	// secondary ParamDlg and it should set the appropriate 'thing' into the
	// given dlg (for example, Texout* or UVGen*).  Return FALSE if dlg is unrecognized.
	// See Gradient::SetDlgThing() for an example.
	virtual BOOL SetDlgThing(ParamDlg* dlg) { return FALSE; }

	// use this for drag-and-drop of texmaps
	CoreExport void CopySubTexmap(HWND hwnd, int ifrom, int ito);
	
	virtual ReferenceTarget *GetRefTarget()=0;
};

// Base class from which materials and textures are subclassed.
class MtlBase: public ReferenceTarget, public ISubMap {
	friend class Texmap;
	TSTR name;
	ULONG mtlFlags;
	int defaultSlotType;
	int activeCount;
	public:
		MtlBase *activeMB; 
		Quat meditRotate;
		ULONG gbufID;
		CoreExport MtlBase();
		TSTR& GetName() { return name; }
		CoreExport void SetName(TSTR s);
		void SetMtlFlag(int mask, BOOL val=TRUE) { 
			if (val) mtlFlags |= mask; else mtlFlags &= ~mask;
			}
		void ClearMtlFlag(int mask) { mtlFlags &= ~mask; }
		int TestMtlFlag(int mask) { return(mtlFlags&mask?1:0); }

		// Used internally by materials editor.
		int GetMeditObjType() { return (mtlFlags&MTL_MEDIT_OBJTYPE_MASK)>>MTL_OBJTYPE_SHIFT; }	
		void SetMeditObjType(int t) { mtlFlags &= ~MTL_MEDIT_OBJTYPE_MASK; mtlFlags |= t<<MTL_OBJTYPE_SHIFT; }

		
#ifndef NO_MTLEDITOR_SAMPLEUVTILING // orb 01-08-2002
		int GetMeditTiling() { return (mtlFlags&MTL_MEDIT_TILING_MASK)>>MTL_TILING_SHIFT; }	
		void SetMeditTiling(int t) { mtlFlags &= ~MTL_MEDIT_TILING_MASK; mtlFlags |= t<<MTL_TILING_SHIFT; }
#endif // NO_MTLEDITOR_SAMPLEUVTILING 

		// recursively determine if there are any multi-materials or texmaps 
		// in tree
		CoreExport BOOL AnyMulti();

		BOOL TextureDisplayEnabled() { return TestMtlFlag(MTL_TEX_DISPLAY_ENABLED); }

		// Return the "className(instance Name)". 
		// The default implementation should be used in most cases.
	    CoreExport virtual TSTR GetFullName();

		// Mtls and Texmaps must use this to copy the common portion of 
		// themselves when cloning
		CoreExport MtlBase& operator=(const MtlBase& m);

		virtual int BuildMaps(TimeValue t, RenderMapsContext &rmc) { return 1; }

		// This gives the cumulative requirements of the mtl and its
		// tree. The default just OR's together the local requirements
		// of the Mtl with the requirements of all its children.
		// For most mtls, all they need to implement is LocalRequirements,
		// if any.
		CoreExport virtual ULONG Requirements(int subMtlNum); 

		// Specifies various requirements for the material: Should NOT
		// include requirements of its sub-mtls and sub-maps.
		virtual ULONG LocalRequirements(int subMtlNum) { return 0; } 

		// This gives the UVW channel requirements of the mtl and its
		// tree. The default implementation just OR's together the local mapping requirements
		// of the Mtl with the requirements of all its children.
		// For most mtls, all they need to implement is LocalMappingsRequired, if any.
		// mapreq and bumpreq will be initialized to empty sets with MAX_MESHMAPS elements
		// set 1's in mapreq for uvw channels required
		// set 1's in bumpreq for bump mapping channels required
		CoreExport virtual void MappingsRequired(int subMtlNum, BitArray & mapreq, BitArray &bumpreq);

		// Specifies UVW channel requirements for the material: Should NOT
		// include UVW channel requirements of its sub-mtls and sub-maps.
		virtual void LocalMappingsRequired(int subMtlNum, BitArray & mapreq, BitArray &bumpreq) {  }

		// This returns true for materials or texmaps that select sub-
		// materials based on mesh faceMtlIndex. Used in 
		// interactive render.
		virtual	BOOL IsMultiMtl() { return FALSE; }

		// Methods to access sub texture maps of material or texmap
		virtual int MapSlotType(int i) { return defaultSlotType; }

		// This must be called on a sub-Mtl or sub-Map when it is removed,
		// in case it or any of its submaps are active in the viewport.
		CoreExport void DeactivateMapsInTree();

		// To make texture & material evaluation more efficient, this function is
		// called whenever time has changed.  It will be called at the
		// beginning of every frame during rendering.
		virtual	void Update(TimeValue t, Interval& valid)=0;

		// set back to default values
		virtual void Reset()=0;

		// call this to determine the validity interval of the mtl or texture
		virtual Interval Validity(TimeValue t)=0;
		
		// this gets called when the mtl or texture is to be displayed in the
		// mtl editor params area.
		virtual ParamDlg* CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp)=0;
		
		// save the common mtlbase stuff.
		// these must be called in a chunk at the beginning of every mtl and
		// texmap.
		CoreExport IOResult Save(ISave *isave);
        CoreExport IOResult Load(ILoad *iload);
		
#ifndef NO_MTLEDITOR_EFFECTSCHANNELS // orb 01-08-2002
		// GBuffer functions
		ULONG GetGBufID() { return gbufID; }
		void SetGBufID(ULONG id) { gbufID = id; }
#endif // NO_MTLEDITOR_EFFECTSCHANNELS
		
		// Default File enumerator.
		CoreExport void EnumAuxFiles(NameEnumCallback& nameEnum, DWORD flags);

		// Postage Stamp
		CoreExport virtual PStamp* GetPStamp(int sz); // sz = 0: small(32x32), 1: large(88x88), 2: tiny(24x24)  		
		CoreExport virtual PStamp* CreatePStamp(int sz, BOOL Render = FALSE);    		
		CoreExport virtual void DiscardPStamp(int sz);   		

		// Schematic View 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 bool SvCanSetName(IGraphObjectManager *gom, IGraphNode *gNode);
		CoreExport bool SvSetName(IGraphObjectManager *gom, IGraphNode *gNode, TSTR &name);
		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);

		// Methods for doing interactive texture display
		virtual BOOL SupportTexDisplay() { return FALSE; }   // supports map display in viewport
		virtual DWORD_PTR GetActiveTexHandle(TimeValue t, TexHandleMaker& thmaker) {return 0;}
		CoreExport void IncrActive();
		CoreExport void DecrActive(); 
		int Active() { return activeCount; }
		virtual void ActivateTexDisplay(BOOL onoff) {}

		// Multiple textures in viewports:
		virtual BOOL SupportsMultiMapsInViewport() { return FALSE; }
		virtual void SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb) {}
		virtual void* GetInterface(ULONG id){ if(id==I_SUBMAP) return (ISubMap*)this; else return ReferenceTarget::GetInterface(id); }
		virtual BaseInterface *GetInterface(Interface_ID id) { return ReferenceTarget::GetInterface(id); }
		virtual ReferenceTarget *GetRefTarget(){return this;}

		// Animatable Properties
		CoreExport virtual int SetProperty(ULONG id, void *data);
		CoreExport virtual void *GetProperty(ULONG id);
		CoreExport virtual void BaseClone(ReferenceTarget *from, ReferenceTarget *to, RemapDir &remap);
	};


// Every MtlBase sub-class defines a ParamDlg to manage its part of
// the material editor.
class ParamDlg : public InterfaceServer {
	public:
		virtual Class_ID ClassID()=0;
		virtual void SetThing(ReferenceTarget *m)=0;
		virtual ReferenceTarget* GetThing()=0;
		virtual void SetTime(TimeValue t)=0;
		virtual	void ReloadDialog()=0;
		virtual void DeleteThis()=0;
		virtual void ActivateDlg(BOOL onOff)=0;
		// These need to be implemented if using a TexDADMgr or a MtlDADMgr
		virtual int FindSubTexFromHWND(HWND hwnd){ return -1;} 
		virtual int FindSubMtlFromHWND(HWND hwnd){ return -1;} 
		// Generic expansion function
		virtual INT_PTR Execute(int cmd, ULONG_PTR arg1=0, ULONG_PTR arg2=0, ULONG_PTR arg3=0) { return 0; } 

	};

// Pre-defined categories of texture maps
CoreExport TCHAR TEXMAP_CAT_2D[];  // 2D maps
CoreExport TCHAR TEXMAP_CAT_3D[];  // 3D maps
CoreExport TCHAR TEXMAP_CAT_COMP[]; // Composite
CoreExport TCHAR TEXMAP_CAT_COLMOD[]; // Color modifier
CoreExport TCHAR TEXMAP_CAT_ENV[];  // Environment

class NameAccum {
	public:
		virtual	void AddMapName(TCHAR *name)=0;
	};

// this interface is a dummy interface returned by texmap::getinterface
// if the map is a ray tracing type map.
#define IID_RAYTRACE_MAP	0xff8d87a5

class IRayTexmap : public InterfaceServer {
public:
	bool isRayTraceMap() { return true; }
};

// virual texture map interface
class Texmap: public MtlBase {
	public:
		int cacheID;    // used by renderer for caching returned values
				
		CoreExport Texmap();

		SClass_ID SuperClassID() { return TEXMAP_CLASS_ID; }
		virtual void GetClassName(TSTR& s) { s= TSTR(_T("Texture")); }  

		// Evaluate the color of map for the context.
		virtual	AColor EvalColor(ShadeContext& sc)=0;
	
		// Evaluate the map for a "mono" channel.
		// this just permits a bit of optimization 
		virtual	float  EvalMono(ShadeContext& sc) {
			return Intens(EvalColor(sc));
			}
		
		// For Bump mapping, need a perturbation to apply to a normal.
		// Leave it up to the Texmap to determine how to do this.
		virtual	Point3 EvalNormalPerturb(ShadeContext& sc)=0;

		// This query is made of maps plugged into the Reflection or 
		// Refraction slots:  Normally the view vector is replaced with
		// a reflected or refracted one before calling the map: if the 
		// plugged in map doesn't need this , it should return TRUE.
		virtual BOOL HandleOwnViewPerturb() { return FALSE; }


		// This gets the viewport display bitmap in DIB format, useful when combining several maps
		// for hardware-supported multiple texture display.  // DS 4/17/00
		// IF mono=TRUE, the map should do a mono evaluation and place the result in RGB.
		// forceW and forceH, if non-zero, overide dimensions specified by thmaker.
		virtual CoreExport BITMAPINFO* GetVPDisplayDIB(TimeValue t, TexHandleMaker& thmaker, Interval &valid, BOOL mono=FALSE, int forceW=0, int forceH=0);  

		virtual	void GetUVTransform(Matrix3 &uvtrans) { uvtrans.IdentityMatrix(); }
		virtual int GetTextureTiling() { return  U_WRAP|V_WRAP; }
		virtual void InitSlotType(int sType) { defaultSlotType = sType; }			   
		virtual int MapSlotType(int i) { return defaultSlotType; }
		virtual int GetUVWSource() { return UVWSRC_EXPLICIT; }
		virtual int GetMapChannel () { return 1; }	// only relevant if above returns UVWSRC_EXPLICIT

		virtual UVGen *GetTheUVGen() { return NULL; }  // maps with a UVGen should implement this
		virtual XYZGen *GetTheXYZGen() { return NULL; } // maps with a XYZGen should implement this

		// System function to set slot type for all subtexmaps in a tree.
		CoreExport void RecursInitSlotType(int sType);			   
		virtual void SetOutputLevel(TimeValue t, float v) {}

		// called prior to render: missing map names should be added to NameAccum.
		// return 1: success,   0:failure. 
		virtual int LoadMapFiles(TimeValue t) { return 1; } 

		// render a 2-d bitmap version of map.
		CoreExport virtual void RenderBitmap(TimeValue t, Bitmap *bm, float scale3D=1.0f, BOOL filter = FALSE);

		CoreExport void RefAdded(RefMakerHandle rm);

		// Schematic View Animatable Overides...
		CoreExport SvGraphNodeReference SvTraverseAnimGraph(IGraphObjectManager *gom, Animatable *owner, int id, DWORD flags);

		// --- Texmap evaluation ---

		// Returns true only if all submaps and itself have a meaningful output.
		// Returns false if at least one sutexmap or itself does not have a 
		// meaningful output,
		CoreExport virtual bool IsOutputMeaningful( ShadeContext& sc );

		// The default implementation returns false
		virtual bool IsLocalOutputMeaningful( ShadeContext& sc ) { return false; }

		// Is the texture High Dynamic Range?
		virtual int IsHighDynamicRange( ) const { return false; }
	};


class TexmapContainer: public ReferenceTarget {
	SClass_ID SuperClassID() { return TEXMAP_CONTAINER_CLASS_ID; }
	CoreExport SvGraphNodeReference SvTraverseAnimGraph(IGraphObjectManager *gom, Animatable *owner, int id, DWORD flags);
	};

// ID's for different DynamicProperties: passed into
// GetDynamicProperty()

#define DYN_BOUNCE 1
#define DYN_STATIC_FRICTION 2
#define DYN_SLIDING_FRICTION 3

// begin - ke/mjm - 03.16.00 - merge reshading code
// class IReshadeFragment;
// end - ke/mjm - 03.16.00 - merge reshading code


// virtual material interface
class Mtl: public MtlBase {
	RenderData *renderData;
	public:

		CoreExport Mtl();
		SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
		virtual void GetClassName(TSTR& s) { s= TSTR(_T("Mtl")); }  

		MtlBase* GetActiveTexmap() { return activeMB; }
		void SetActiveTexmap( MtlBase *txm) { activeMB = txm; }

		CoreExport void RefDeleted();
		CoreExport void RefAdded(RefMakerHandle rm);  

		// Must call Update(t) before calling these functions!
		// Their purpose is for setting up the material for the
		// GraphicsWindow renderer.
		virtual Color GetAmbient(int mtlNum=0, BOOL backFace=FALSE)=0;
		virtual Color GetDiffuse(int mtlNum=0, BOOL backFace=FALSE)=0;	    
		virtual Color GetSpecular(int mtlNum=0, BOOL backFace=FALSE)=0;
		virtual float GetShininess(int mtlNum=0, BOOL backFace=FALSE)=0;
		virtual	float GetShinStr(int mtlNum=0, BOOL backFace=FALSE)=0;		
		virtual float GetXParency(int mtlNum=0, BOOL backFace=FALSE)=0;

		// >>>>> Self-Illum
		virtual BOOL GetSelfIllumColorOn(int mtlNum=0, BOOL backFace=FALSE) { return TRUE; }
		virtual float GetSelfIllum(int mtlNum=0, BOOL backFace=FALSE) { return 0.0f; }
		virtual Color GetSelfIllumColor(int mtlNum=0, BOOL backFace=FALSE){ Color c( .0f,.0f,.0f); return c; }

		// sampler
		virtual Sampler * GetPixelSampler(int mtlNum=0, BOOL backFace=FALSE){ return NULL; }

		// used by the scanline renderer
		virtual float WireSize(int mtlNum=0, BOOL backFace=FALSE) { return 1.0f; }

		// why incomplete sets?? 
		// used onlt for default material creation....add no more
		virtual void SetAmbient(Color c, TimeValue t)=0;		
		virtual void SetDiffuse(Color c, TimeValue t)=0;		
		virtual void SetSpecular(Color c, TimeValue t)=0;
		virtual void SetShininess(float v, TimeValue t)=0;		
		virtual BOOL SupportsShaders() { return FALSE; } // moved from class StdMat

		// if supporting render elements
		virtual BOOL SupportsRenderElements() { return FALSE; } 

/*************
// begin - ke/mjm - 03.16.00 - merge reshading code
		// if supporting shaders, plug-in mtl should inherit from StdMat2
		enum ReshadeRequirements{ RR_None = 0, RR_NeedPreshade, RR_NeedReshade }; // mjm - 06.02.00

		virtual BOOL SupportsReShading(ShadeContext& sc) { return FALSE; }
		// GetReshadeValidity is called by the interactive reshader after being notified that the material has changed.
		// the return value indicates if the material is still valid, or needs to be preshaded or reshaded. the value
		// should pertain only to the latest change to the material
		// if a material doesn't support reshading, it doesn't need to override this function -- any change will cause
		// the nodes to which it's attached to be rerendered.
		virtual ReshadeRequirements GetReshadeRequirements() { return RR_NeedPreshade; } // mjm - 06.02.00
		virtual void PreShade(ShadeContext& sc, IReshadeFragment* pFrag ) { }
		virtual void PostShade(ShadeContext& sc, IReshadeFragment* pFrag, int& nextTexIndex) { }
// end - ke/mjm - 03.16.00 - merge reshading code
***********/

		// The main method: called by the renderer to compute color and transparency
		// output returned in sc.out
		virtual void Shade(ShadeContext& sc)=0;

		// Methods to access sub-materials of meta-materials 
		virtual int NumSubMtls() { return 0; }
		virtual Mtl* GetSubMtl(int i) { return NULL; }
		virtual void SetSubMtl(int i, Mtl *m) { }
//		virtual int SubMtlOn(int i) { return 1; } 
		virtual int VPDisplaySubMtl() { return -1; }  // which sub-mtl to display in the viewport: -1 indicates not implemented.
		CoreExport virtual TSTR GetSubMtlSlotName(int i);
		CoreExport TSTR GetSubMtlTVName(int i);					  
		CoreExport void CopySubMtl(HWND hwnd, int ifrom, int ito);

		// Dynamics properties
		virtual CoreExport float GetDynamicsProperty(TimeValue t, int mtlNum, int propID);
		virtual CoreExport void SetDynamicsProperty(TimeValue t, int mtlNum, int propID, float value);
		
		// Displacement mapping
		virtual float EvalDisplacement(ShadeContext& sc) { return 0.0f; }
		virtual Interval DisplacementValidity(TimeValue t) { return FOREVER; }

		// Schematic View Animatable Overides...
		CoreExport bool SvCanInitiateLink(IGraphObjectManager *gom, IGraphNode *gNode);

		// allows plugins to control the display of the Discard/Keep Old Material dialog when being
		// created in a MtlEditor slot.  Added by JBW for scripted material plugins.
		// return TRUE to prevent the Keep Old Material dialog from poping.
		virtual BOOL DontKeepOldMtl() { return FALSE; }

		// allow renderer to attach auxiliary data to each material.
		virtual void SetRenderData( RenderData *rdata) { renderData = rdata; }
		virtual RenderData *GetRenderData() { return renderData; }

		// --- Material evaluation ---

		// Returns true if the evaluated color\value (output) is constant 
		// over all possible inputs. 
		virtual bool IsOutputConst( ShadeContext& sc, int stdID ) { return false; }

		// Evaluate the material on a single standard texmap channel (ID_AM, etc) 
		// at a UVW cordinated and over an area described in the ShadingContext
		virtual bool EvalColorStdChannel( ShadeContext& sc, int stdID, Color& outClr) { return false; }
		CoreExport virtual bool EvalMonoStdChannel( ShadeContext& sc, int stdID, float& outVal) ;
	};

//  A texture map implements this class and passes it into  EvalUVMap,
//  EvalUVMapMono, and EvalDeriv to evaluate itself with tiling & mirroring
class MapSampler {
	public:
		// required:
		virtual	AColor Sample(ShadeContext& sc, float u,float v)=0;
		virtual	AColor SampleFilter(ShadeContext& sc, float u,float v, float du, float dv)=0;
		// optional:
		virtual void SetTileNumbers(int iu, int iv) {} // called before SampleFunctions to tell what tile your in
		virtual	float SampleMono(ShadeContext& sc, float u,float v) { return Intens(Sample(sc,u,v)); }
		virtual	float SampleMonoFilter(ShadeContext& sc, float u,float v, float du, float dv){
			return Intens(SampleFilter(sc,u,v,du,dv)); 
			}
	};


// This class generates UV coordinates based on the results of a UV 
// Source and user specified transformation.
// A reference to one of these is referenced by all 2D texture maps.
class UVGen: public MtlBase {
	public:
		// Get texture coords and derivatives for antialiasing
		virtual void GetUV( ShadeContext& sc, Point2& UV, Point2& dUV)=0;
		
		// This is how a Texmap evaluates itself
		virtual AColor EvalUVMap(ShadeContext &sc, MapSampler* samp,  BOOL filter=TRUE)=0;
		virtual float EvalUVMapMono(ShadeContext &sc, MapSampler* samp, BOOL filter=TRUE)=0;
		virtual	Point2 EvalDeriv( ShadeContext& sc, MapSampler* samp, BOOL filter=TRUE)=0;

		// Get dPdu and dPdv for bump mapping
		virtual	void GetBumpDP( ShadeContext& sc, Point3& dPdu, Point3& dPdv)=0;

		virtual void GetUVTransform(Matrix3 &uvtrans)=0;

		virtual int GetTextureTiling()=0;
		virtual void SetTextureTiling(int t)=0;

		virtual int GetUVWSource()=0;
		virtual int GetMapChannel () { return 1; }	// only relevant if above returns UVWSRC_EXPLICIT
		virtual void SetUVWSource(int s)=0;
		virtual void SetMapChannel (int s) { }

		virtual int SymFlags()=0;
		virtual void SetSymFlags(int f)=0;

		virtual int GetSlotType()=0; 
		virtual void InitSlotType(int sType)=0; 

		virtual int GetAxis()=0;  // returns AXIS_UV, AXIS_VW, AXIS_WU
		virtual void SetAxis(int ax)=0;  //  AXIS_UV, AXIS_VW, AXIS_WU

		// The clip flag controls whether the U,V values passed to MapSampler by 
		//  EvalUVMap and EvalUVMapMono are clipped to the [0..1] interval or not. 
		// It defaults to ON (i.e., clipped).
		virtual void SetClipFlag(BOOL b)=0;	
		virtual BOOL GetClipFlag()=0;

		virtual BOOL IsStdUVGen() { return FALSE; } // class StdUVGen implements this to return TRUE

		SClass_ID SuperClassID() { return UVGEN_CLASS_ID; }

		virtual void SetRollupOpen(BOOL open)=0;
		virtual BOOL GetRollupOpen()=0;
		CoreExport SvGraphNodeReference SvTraverseAnimGraph(IGraphObjectManager *gom, Animatable *owner, int id, DWORD flags);
		CoreExport TSTR SvGetName(IGraphObjectManager *gom, IGraphNode *gNode, bool isBeingEdited)
			{
			return Animatable::SvGetName(gom, gNode, isBeingEdited);
			}
	};

// This class generates Point3 coordinates based on the ShadeContext.
// A reference to one of these is referenced by all 3D texture maps.
class XYZGen: public MtlBase {
	public:
		// Get texture coords and derivatives for antialiasing
		virtual void GetXYZ( ShadeContext& sc, Point3& p, Point3& dp)=0;
		SClass_ID SuperClassID() { return XYZGEN_CLASS_ID; }
		virtual void SetRollupOpen(BOOL open)=0;
		virtual BOOL GetRollupOpen()=0;
		virtual BOOL IsStdXYZGen() { return FALSE; } // class StdXYZGen implements this to return TRUE
		virtual	void GetBumpDP( ShadeContext& sc, Point3* dP) {}; // returns 3 unit vectors for computing differentials
		CoreExport SvGraphNodeReference SvTraverseAnimGraph(IGraphObjectManager *gom, Animatable *owner, int id, DWORD flags);
		CoreExport TSTR SvGetName(IGraphObjectManager *gom, IGraphNode *gNode, bool isBeingEdited)
			{
			return Animatable::SvGetName(gom, gNode, isBeingEdited);
			}
	};

// This class is used by texture maps to put up the output filter 
// rollup, and perform the output filtering.
class TextureOutput: public MtlBase {
	public:
		virtual AColor Filter(AColor c) = 0;
		virtual float Filter(float f) = 0;
		virtual Point3 Filter(Point3 p) = 0;
		virtual float GetOutputLevel(TimeValue t) = 0;
		virtual void SetOutputLevel(TimeValue t, float v) = 0;
		virtual void SetInvert(BOOL onoff)=0;
		virtual BOOL GetInvert()=0;
		virtual void SetRollupOpen(BOOL open)=0;
		virtual BOOL GetRollupOpen()=0;
		SClass_ID SuperClassID() { return TEXOUTPUT_CLASS_ID; }
		CoreExport SvGraphNodeReference SvTraverseAnimGraph(IGraphObjectManager *gom, Animatable *owner, int id, DWORD flags);
		CoreExport TSTR SvGetName(IGraphObjectManager *gom, IGraphNode *gNode, bool isBeingEdited)
			{
			return Animatable::SvGetName(gom, gNode, isBeingEdited);
			}
	};

//////////////////////////////////////////////////////////////
//
// post mapping params for shaders & render elements
class Shader;

#ifndef USE_LIMITED_STDMTL
#define STD2_NMAX_TEXMAPS	24
#else
#define STD2_NMAX_TEXMAPS	12
#endif

class IllumParams : public BaseInterfaceServer {
public:
	// these are the inputs to the shader, mostly textured channels
//	ULONG mtlFlags;
	Shader* pShader;	// for render elements to call the shader & mtl again, may be null
	Mtl* pMtl;			// max mtl being shaded, null if bgnd
//	Point3 N, V;
	Color channels[ STD2_NMAX_TEXMAPS ];	//inputs, to be textured

	float finalOpac;		// textured opacity w/ stdfalloff (reg opac in channels)
	float reflectAmt;				// combined reflection.a * reflectAmt 
	float refractAmt;				// combined reflection.a * amt 
	ULONG hasComponents;	// bits for active components(e.g.currently has active refl map)
	ULONG stdParams;
	int*  stdIDToChannel;	// combined shader & mtl. Note: may be NULL (for example, matte/shadow)

	// these are the component-wise outputs from the shading process
	Color ambIllumOut, diffIllumOut, transIllumOut, selfIllumOut; // the diffuse clrs
	Color specIllumOut, reflIllumOut;	// the specular colors

	// User Illumination outputs for render elements, name matched
	int	nUserIllumOut;		// one set of names for all illum params instances
	TCHAR** userIllumNames;  // we just keep ptr to shared name array, not destroyed
	Color* userIllumOut;	// the user illum color array, new'd & deleted w/ the class

	float diffIllumIntens; // used only by reflection dimming, intensity of diffIllum prior to color multiply
	float finalAttenuation; // for combining components

	// these are the outputs of the combiner
	Color finalC;	// final clr: combiner composites into this value.
	Color finalT;	// shader transp clr out

public:
	// Illum params are allocated by materials during shading process to
	// communicate with shaders & render elements
	// So materials need to know how many userIllum slots they will use
	// most materials know this, but std2 will have to get it from the shader
	IllumParams( int nUserOut = 0, TCHAR** pUserNames = NULL ){ 
		nUserIllumOut = nUserOut;
		userIllumOut = ( nUserOut )? new Color[ nUserOut ] : NULL;
		userIllumNames = pUserNames;
		hasComponents = stdParams = 0;
		stdIDToChannel = NULL;
		pMtl = NULL;
		pShader = NULL;
	}

//	IllumParams(){ 
//		nUserIllumOut = 0;
//		userIllumOut = NULL;
//		userIllumNames = NULL;
//	}


	~IllumParams(){
	// We Dont destroy the name array as it's shared by all
		if( userIllumOut )
			delete [] userIllumOut;
	}

	// returns number of user illum channels for this material
	int nUserIllumChannels(){ return nUserIllumOut; }

	// returns null if no name array specified
	TCHAR* GetUserIllumName( int n ) { 
		DbgAssert( n < nUserIllumOut );
		if( userIllumNames )
			return userIllumNames[n];
		return NULL;
	}

	// render elements, mtls & shaders can use this to find the index associated with a name
	// returns -1 if it can't find the name
	int FindUserIllumName( TCHAR* name ){
		int n = -1;
		for( int i = 0; i < nUserIllumOut; ++i ){
			DbgAssert( userIllumNames );
			if( _tcscmp( name, userIllumNames[i] ) == 0 ){
				n = i;
				break;
			}
		}
		return n;
	}

	// knowing the index, these set/get the user illum output color
	void SetUserIllumOutput( int n, Color& out ){
		DbgAssert( n < nUserIllumOut );
		userIllumOut[n] = out;
	}
	void SetUserIllumOutput( TCHAR* name, Color& out ){
		for( int i = 0; i < nUserIllumOut; ++i ){
			DbgAssert( userIllumNames );
			if( _tcscmp( name, userIllumNames[i] )== 0){
				userIllumOut[i] = out;
				break;
			}
		}
		DbgAssert( i < nUserIllumOut );
	}

	Color GetUserIllumOutput( int n ){
		DbgAssert( n < nUserIllumOut );
		return userIllumOut[n];
	}
	Color GetUserIllumOutput( TCHAR* name, int n ){
		for( int i = 0; i < nUserIllumOut; ++i ){
			DbgAssert( userIllumNames );
			if( _tcscmp( name, userIllumNames[i] )== 0){
				return userIllumOut[i];
			}
		}
		return Color(0,0,0);
	}

	void ClearOutputs() { 
		finalC = finalT = ambIllumOut=diffIllumOut=transIllumOut=selfIllumOut=
		specIllumOut=reflIllumOut= Color( 0.0f, 0.0f, 0.0f ); 
		finalAttenuation = diffIllumIntens = 0.0f;
		for( int i=0; i < nUserIllumOut; ++i )
			userIllumOut[i] = finalC;
	}

	void ClearInputs() { 
		/*mtlFlags = */ stdParams = hasComponents = 0;
		pShader = NULL; pMtl = NULL;
		stdIDToChannel = NULL;
		refractAmt = reflectAmt = 0.0f; 
		for( int i=0; i < STD2_NMAX_TEXMAPS; ++i )
			channels[ i ] = Color( 0, 0, 0 );
	}
};

///////////////////////////////////////////////////////////////////
//
//	Reshading interfaces
//
class Color32;

class IReshadeFragment : public InterfaceServer 
{
public:
	virtual int	NChannels()=0;
	virtual int	NFirstChannel()=0; 
	virtual int	NTextures()=0;

	virtual Color32	Channel( int nChan )=0;
	virtual void SetChannel( int nChan, Color32 c )=0;
	virtual void AddChannel( Color32 c )=0;

	virtual void AddColorChannel( RGBA tex )=0;
	virtual void AddFloatChannel( float f )=0;
	virtual void AddIntChannel( int i )=0;
	virtual void AddUnitVecChannel( Point3 v )=0;
	virtual void AddPoint2Channel( Point2 p )=0;
	virtual void AddPoint3Channel( Point3 p )=0;

	virtual void SetColorChannel( int nChan, RGBA tex )=0;
	virtual void SetFloatChannel( int nChan, float f )=0;
	virtual void SetIntChannel( int nChan, int i )=0;
	virtual void SetUnitVecChannel( int nChan, Point3 v )=0;
	virtual void SetPoint2Channel( int nChan, Point2 p )=0;
	virtual void SetPoint3Channel( int nChan, Point3 p )=0;

	virtual RGBA GetColorChannel( int nChan )=0;
	virtual float GetFloatChannel( int nChan )=0;
	virtual int GetIntChannel( int nChan )=0;
	virtual Point3 GetUnitVecChannel( int nChan )=0;
	virtual Point2 GetPoint2Channel( int nChan )=0;
	virtual Point3 GetPoint3Channel( int nChan )=0;
};

// must be greater than I_USERINTERFACE in maxsdk/include/animtbl.h
#define IID_IReshading	0xabe00001

// Materials support this interface to support preshading/reshading
class IReshading
{
public:
		// if supporting shaders, plug-in mtl should inherit from StdMat2
		enum ReshadeRequirements{ RR_None = 0, RR_NeedPreshade, RR_NeedReshade }; // mjm - 06.02.00

		// this is implied by the GetInterface( IID_IReshading ) call on the mtl
//		virtual BOOL SupportsReShading(ShadeContext& sc) { return FALSE; }

		// GetReshadeRequirements is called by the interactive reshader after being notified that the material has changed.
		// the return value indicates if the material is still valid, or needs to be preshaded or reshaded. the value
		// should pertain only to the latest change to the material
		// if a material doesn't support reshading, it doesn't need to override this function -- any change will cause
		// the nodes to which it's attached to be rerendered.
		virtual ReshadeRequirements GetReshadeRequirements() { return RR_NeedPreshade; } // mjm - 06.02.00
		virtual void PreShade(ShadeContext& sc, IReshadeFragment* pFrag ) { }
		virtual void PostShade(ShadeContext& sc, IReshadeFragment* pFrag, 
						int& nextTexIndex, IllumParams* ip = NULL ) { }

};

// must be greater than I_USERINTERFACE in maxsdk/include/animtbl.h
#define IID_IValidityToken	0xabe00002

class IValidityToken
{
public:
	virtual BOOL NeedsUpdate( ULONG currentToken )= 0;
	virtual void SetToken( ULONG token )= 0;
	virtual ULONG GetToken() = 0;
	virtual void SetMessage( ULONG message )= 0;
	virtual ULONG GetMessage() = 0;
};


class IValidityTokenImp : public IValidityToken
{
protected:
	ULONG	mLocalToken;
	ULONG	mMessage;

public:
	// if the object has been changed the localtoken will equal the
	// current token
	BOOL NeedsUpdate( ULONG currentToken ){
		return mLocalToken >= currentToken;
	}
	// mtls/maps set the token to next frame when changed
	// from core interface GetNextValidityToken()
	void SetToken( ULONG token ) {
		mLocalToken = token;
	}
	// not used, but here for debug & future use
	ULONG GetToken() {
		return mLocalToken;
	}

	// once the render know which mtls maps were changed, this can be used to 
	// send a secondary message e.g. map/colorVal or map/uv, etc.
	void SetMessage( ULONG message ) {
		mMessage = message;
	}
	ULONG GetMessage() {
		return mMessage;
	}
};

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

typedef MtlBase* MtlBaseHandle;
typedef Mtl* MtlHandle;
typedef Texmap* TexmapHandle;


// Simple list of materials
class MtlList: public Tab<MtlHandle> {
	public:
		CoreExport int AddMtl(Mtl *m, BOOL checkUnique=TRUE);
		CoreExport int FindMtl(Mtl *m);
		CoreExport int FindMtlByName(TSTR& name);
		void RemoveEntry(int n) { Delete(n,1); }
		void Empty() { Resize(0); }
	};

// Materials library
class MtlLib: public ReferenceTarget, public MtlList {
	public:
		SClass_ID SuperClassID() { return REF_MAKER_CLASS_ID; }
		CoreExport Class_ID ClassID();
		CoreExport void DeleteAll();
		void GetClassName(TSTR& s) { s= TSTR(_T("MtlLib")); }  
		CoreExport ~MtlLib();

		int NumSubs() { 
			return Count(); 
			}  
		Animatable* SubAnim(int i) { 
			return (*this)[i]; 
			}
		CoreExport TSTR SubAnimName(int i);
		CoreExport virtual void Remove(Mtl *m);
		CoreExport virtual void Add(Mtl *m);

		// From ref
		RefResult AutoDelete() { return REF_SUCCEED; }
		CoreExport void DeleteThis();
		int NumRefs() { return Count();}
		RefTargetHandle GetReference(int i) { return (RefTargetHandle)(*this)[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 );

		// IO
		CoreExport IOResult Save(ISave *isave);
        CoreExport IOResult Load(ILoad *iload);

	};


// A MtlBase Version of the above
class MtlBaseList: public Tab<MtlBaseHandle> {
	public:
		CoreExport int AddMtl(MtlBase *m, BOOL checkUnique=TRUE);
		CoreExport int FindMtl(MtlBase *m);
		CoreExport int FindMtlByName(TSTR& name);
		void RemoveEntry(int n) { Delete(n,1); }
		void Empty() { Resize(0); }
	};

class MtlBaseLib : public ReferenceTarget, public MtlBaseList {
	public:
		SClass_ID SuperClassID() { return REF_MAKER_CLASS_ID; }
		CoreExport Class_ID ClassID();
		CoreExport void DeleteAll();
		void GetClassName(TSTR& s) { s= TSTR(_T("MtlBaseLib")); }  
		CoreExport ~MtlBaseLib();

		int NumSubs() {return Count();}		
		Animatable* SubAnim(int i) {return (*this)[i];}
		CoreExport TSTR SubAnimName(int i);
		
		CoreExport virtual void Remove(MtlBase *m);
		CoreExport virtual void Add(MtlBase *m);
		CoreExport virtual void RemoveDuplicates();

		// From ref
		RefResult AutoDelete() {return REF_SUCCEED;}
		CoreExport void DeleteThis();
		int NumRefs() { return Count();}
		RefTargetHandle GetReference(int i) { return (RefTargetHandle)(*this)[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 );

		// IO
		CoreExport IOResult Save(ISave *isave);
        CoreExport IOResult Load(ILoad *iload);
	};


// Simple list of numbers
class NumList: public Tab<int> {
	public:
		CoreExport int Add(int j, BOOL checkUnique=TRUE);
		CoreExport int Find(int j);
	};

class MtlRemap {
	public:
		virtual Mtl* Map(Mtl *oldAddr)=0;
	};

//--------------------------------------------------------------------------------
// Use this class to implement Drag-and-Drop for materials sub-Texmaps.
// If this class is used the ParamDlg method FindSubTexFromHWND() must be implemented.
//--------------------------------------------------------------------------------
class TexDADMgr: public DADMgr {
	ParamDlg *dlg;
	public:
		TexDADMgr(ParamDlg *d=NULL) { dlg = d;}
		void Init(ParamDlg *d) { dlg = d; }
		// called on the draggee to see what if anything can be dragged from this x,y
		SClass_ID GetDragType(HWND hwnd, POINT p) { return TEXMAP_CLASS_ID; }
		// called on potential dropee to see if can drop type at this x,y
		CoreExport BOOL OkToDrop(ReferenceTarget *dropThis, HWND hfrom, HWND hto, POINT p, SClass_ID type, BOOL isNew);
		int SlotOwner() { return OWNER_MTL_TEX;	}
	    CoreExport ReferenceTarget *GetInstance(HWND hwnd, POINT p, SClass_ID type);
		CoreExport void Drop(ReferenceTarget *dropThis, HWND hwnd, POINT p, SClass_ID type);
		CoreExport BOOL  LetMeHandleLocalDAD(); 
		CoreExport void  LocalDragAndDrop(HWND h1, HWND h2, POINT p1, POINT p2);
		BOOL  AutoTooltip(){ return TRUE; }
	};


//--------------------------------------------------------------------------------
// Use this class to implement Drag-and-Drop for materials sub-materials.
// If this class is used the ParamDlg method FindSubMtlFromHWND() must be implemented.
//--------------------------------------------------------------------------------
class MtlDADMgr: public DADMgr {
	ParamDlg *dlg;
	public:
		MtlDADMgr(ParamDlg *d=NULL) { dlg = d;}
		void Init(ParamDlg *d) { dlg = d; }
		// called on the draggee to see what if anything can be dragged from this x,y
		SClass_ID GetDragType(HWND hwnd, POINT p) { return MATERIAL_CLASS_ID; }
		// called on potential dropee to see if can drop type at this x,y
		CoreExport BOOL OkToDrop(ReferenceTarget *dropThis, HWND hfrom, HWND hto, POINT p, SClass_ID type, BOOL isNew);
		int SlotOwner() { return OWNER_MTL_TEX;	}
	    CoreExport ReferenceTarget *GetInstance(HWND hwnd, POINT p, SClass_ID type);
		CoreExport void Drop(ReferenceTarget *dropThis, HWND hwnd, POINT p, SClass_ID type);
		CoreExport BOOL  LetMeHandleLocalDAD(); 
		CoreExport void  LocalDragAndDrop(HWND h1, HWND h2, POINT p1, POINT p2);
		BOOL  AutoTooltip(){ return TRUE; }
	};


// this class used for Drag/and/dropping Bitmaps
class DADBitmapCarrier: public ReferenceTarget {
	TSTR name;
	public:
	void SetName(TSTR &nm) { name = nm; }
	TSTR& GetName() { return name; }		

	Class_ID ClassID() { return Class_ID(0,1); }
	SClass_ID SuperClassID() { return BITMAPDAD_CLASS_ID; }		
	void DeleteThis() { }
	RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, 
	         PartID& partID,  RefMessage message) { return REF_DONTCARE; }		
	RefTargetHandle Clone(RemapDir &remap = NoRemap()) { assert(0); return NULL; }

	};

// Get a pointer to the BitmapCarrier (their's only two of these: one for the
// source, and one for the destination:  don't try to delete these; 
CoreExport DADBitmapCarrier *GetDADBitmapCarrier();


CoreExport void SetLoadingMtlLib(MtlLib *ml);
CoreExport void SetLoadingMtlBaseLib(MtlBaseLib *ml);

CoreExport ClassDesc* GetMtlLibCD();
CoreExport ClassDesc* GetMtlBaseLibCD();

CoreExport UVGen* GetNewDefaultUVGen();
CoreExport XYZGen* GetNewDefaultXYZGen();
CoreExport TextureOutput* GetNewDefaultTextureOutput();
inline int IsMtl(Animatable *m) { return m->SuperClassID()==MATERIAL_CLASS_ID; }
inline int IsTex(Animatable *m) { return m->SuperClassID()==TEXMAP_CLASS_ID; }
inline int IsMtlBase(Animatable *m) { return IsMtl(m)||IsTex(m); }

// Combines the two materials into a multi-material.
// Either of the two input materials can themselves be multis.
// c1 and c2 will be set to the mat count for mat1 and mat2.
CoreExport Mtl *CombineMaterials(Mtl *mat1, Mtl *mat2, int &mat2Offset);

// Expand multi material size to the largest face ID
CoreExport Mtl *FitMaterialToMeshIDs(Mesh &mesh,Mtl *mat);
CoreExport Mtl *FitMaterialToShapeIDs(BezierShape &shape, Mtl *mat);
CoreExport Mtl *FitMaterialToPatchIDs(PatchMesh &patch, Mtl *mat);
CoreExport Mtl *FitMaterialToPolyMeshIDs (MNMesh & mesh, Mtl *mat);

// Adjust face IDs so that no face ID is greater then them multi size
CoreExport void FitMeshIDsToMaterial(Mesh &mesh, Mtl *mat);
CoreExport void FitShapeIDsToMaterial(BezierShape &shape, Mtl *mat);
CoreExport void FitPatchIDsToMaterial(PatchMesh &patch, Mtl *mat);
CoreExport void FitPolyMeshIDsToMaterial (MNMesh & mesh, Mtl *mat);

// Remove unused mats in a multi and shift face IDs.
CoreExport Mtl *CondenseMatAssignments(Mesh &mesh, Mtl *mat);
CoreExport Mtl *CondenseMatAssignments(BezierShape &shape, Mtl *mat);
CoreExport Mtl *CondenseMatAssignments(PatchMesh &patch, Mtl *mat);
CoreExport Mtl *CondenseMatAssignments (MNMesh &mesh, Mtl *mat);


// Attach materials dialog support -- TH 3/9/99

// Attach Mat values
#define ATTACHMAT_IDTOMAT 0
#define ATTACHMAT_MATTOID 1
#define ATTACHMAT_NEITHER 2

class AttachMatDlgUser {
	public:
		virtual int GetAttachMat()=0;
		virtual BOOL GetCondenseMat()=0;
		virtual void SetAttachMat(int value)=0;
		virtual void SetCondenseMat(BOOL sw)=0;
	};

CoreExport BOOL DoAttachMatOptionDialog(IObjParam *ip, AttachMatDlgUser *user);

#define IID_INewSubMapNotification Interface_ID(0x3fe013b2, 0x31815874)

// Optional interface which can be implemented by classes derived from MtlBase.
// If this interface is returned from GetInterface, then this method is called
// when a new sub-texmap is added to the material.  It lets the material set
// material-specific defaults on the texture map.  This is only called when
// adding newly created textures to the material.
class INewSubTexmapNotification: public BaseInterface
{
public:
    virtual void NewSubTexmapAdded(int i, Texmap *m) = 0;
	Interface_ID	GetID() { return IID_INewSubMapNotification; }
};

#define DEFAULT_TEXTURE_MAP_SIZE_INCHES 48.0f
#define DEFAULT_TEXTURE_MAP_SIZE_METERS 1.0f

#endif

