Class MtlBase

3DS Max Plug-In SDK

Class MtlBase

See Also: Class ReferenceTarget, Class ISubMap, Class Mtl, Class Texmap, Class ShadeContext, Class RenderMapsContext, Class RenderGlobalContext, Class UVGen, Class XYZGen, Class PStamp, Class Quat.

class MtlBase : public ReferenceTarget, public ISubMap

Description:

This is the base class from which materials and textures are subclassed. Methods are provided to access the name, flags, and sub-materials/maps. There is also a method that is called when the material or texture is to be displayed in the material editor parameters area.

Note the following about dialog proc processing of sub-map buttons:

When you post the message:

PostMessage(hwmedit, WM_TEXMAP_BUTTON, i,(LPARAM)theMtl);

You are telling the system that the user clicked on the button for the 'i-th' sub-map of theMtl. The message doesn't propogate up -- it goes directly to the materials editor. It then uses calls on theMtl->SetSubTexmap() and theMtl->GetSubTexmap() to assign the new map. So even if your material has some complicated internal hierachical structure of references, to the system it is still a simple "logical" hierarchy of a material with some sub-texmaps.

Data Members:

public:

Quat meditRotate;

This data member is available in release 2.0 and later only.

This describes the rotation of the sample geometry in the materials editor.

ULONG gbufID;

This is the G-Buffer ID of the material or texmap. This is a "effects number" assigned in the materials editor to a map or material, and it will be written into the effects channel of the G-Buffer when a pixel with that material on it is rendered. To implement this, each map or material, in the beginning of its Shade(), EvalColor(), or EvalMono() methods should have the code:

if (gbufID) sc.SetGBufferID(gbufID);

Method Groups:

The following hyperlinks take you to the start of groups of related methods within the class:

Naming Methods

BuildMaps Method

Flag Access Methods

Requirement Methods

Sub-Mtl-Texture Access

Update / Reset / Validity

Loading / Saving Methods

User Interface Methods

Multiple Map Display in the Viewports

G Buffer Methods

Enumerate Auxilliary Files Implementation

Postage Stamp Image Methods

Internal Methods

Operators

Methods:

Prototype:

MtlBase();

Remarks:

Constructor. The flags and G-buffer id are initialized.

Naming Methods

Prototype:

TSTR& GetName()

Remarks:

Implemented by the System.

Returns the name of the material or texture.

Prototype:

void SetName(TSTR s);

Remarks:

Implemented by the System.

Stores the name of the material or texture.

Prototype:

virtual TSTR GetFullName();

Remarks:

Implemented by the System.

This method returns the name that appears in the track view. It returns the "Instance Name(class Name)". For example "Green Glass (Standard)". The default implementation should be used.

Flag Access Methods

Prototype:

void SetMtlFlag(int mask, BOOL val=TRUE)

Remarks:

Implemented by the System.

Alters the flags, either setting or clearing them, using the mask and method passed.

Parameters:

int mask

The flags to alter. See List of Material Flags.

BOOL val=TRUE

If TRUE the mask is ORed into the flags (mtlFlags |= mask); otherwise (mtlFlags &= ~mask).

Prototype:

void ClearMtlFlag(int mask)

Remarks:

Implemented by the System.

Clears the specified flags.

Parameters:

int mask

The flags to clear. See List of Material Flags.

Prototype:

int TestMtlFlag(int mask)

Remarks:

Implemented by the System.

Tests the specified flags. Returns nonzero if the flags are set; otherwise zero. See List of Material Flags.

Parameters:

int mask

The flags to test.

Prototype:

BOOL AnyMulti();

Remarks:

Implemented by the System.

This method may be called to recursively determine if there are any multi-materials or texmaps in the tree.

Return Value:

TRUE if the material or texture map has any mult-materials; otherwise FALSE.

Requirement Methods

Prototype:

virtual ULONG Requirements(int subMtlNum);

Remarks:

Implemented by the Plug-In.

This method returns the cumulative requirements of the material and its sub-materials and maps. The default implementation just ORs together the local requirements of the material with the requirements of all its children. Most materials will only need to implement LocalRequirements().

Parameters:

int subMtlNum

Specifies the number of the sub-material whose requirements should be returned. -1 may be used to return a value generated by looping over all the sub-materials and ORing together the requirements.

Return Value:

See List of Material Requirements.

Default Implementation:

The default implementation automatically traverses the sub-material/map tree. On any MtlBase that returns TRUE for IsMultiMtl() it will only recursively call the sub material (or map) for the subMtlNum called. The exception to this is when subMtlNum<0: in this case all sub-mtls and submaps are enumerated. Therefore the LocalRequirements() method below only needs to consider the material or map itself, not the sub-mtls and sub-maps.

Prototype:

virtual ULONG LocalRequirements(int subMtlNum)

Remarks:

Implemented by the Plug-In.

Specifies various requirements for this material. The value returned from this method should not include requirements of its sub-materials and sub-maps.

Parameters:

int subMtlNum

Specifies the number of the sub-material whose requirements should be returned.

Return Value:

See List of Material Requirements.

Default Implementation:

{ return 0; }

Prototype:

virtual void MappingsRequired(int subMtlNum, BitArray & mapreq, BitArray &bumpreq);

Remarks:

This method is available in release 3.0 and later only.

This method gives the UVW channel requirements of the material and its tree. The default implementation just OR's together the local mapping requirements of the material with the requirements of all its children. For most materials, all they need to implement is the LocalMappingsRequired() method.

Parameters:

int subMtlNum

Specifies the number of the sub-material whose mapping information is retrieved.

BitArray &mapreq

This array of bits is initialized to an empty set with MAX_MESHMAPS elements. Each bit corresponds to a mapping channel. Set a bit to one to indicate the material requires the corresponding UVW channel.

BitArray &bumpreq

This array of bits is initialized to an empty set with MAX_MESHMAPS elements. Each bit corresponds to a mapping channel. Set a bit to one to indicate the material requires the corresponding bump mapping channel.

Prototype:

virtual void LocalMappingsRequired(int subMtlNum, BitArray &mapreq, BitArray &bumpreq);

Remarks:

This method is available in release 3.0 and later only.

This method specifies UVW channel requirements for the material: This method should not include UVW channel requirements of any sub-materials and sub-maps.

Parameters:

int subMtlNum

Specifies the number of the sub-material whose mapping information is retrieved.

BitArray &mapreq

This array of bits is initialized to an empty set with MAX_MESHMAPS elements. Each bit corresponds to a mapping channel. Set a bit to one to indicate the material requires the corresponding UVW channel.

BitArray &bumpreq

This array of bits is initialized to an empty set with MAX_MESHMAPS elements. Each bit corresponds to a mapping channel. Set a bit to one to indicate the material requires the corresponding bump mapping channel.

Default Implementation:

{}

Sample Code:

All 2D textures that use UVGen or otherwise select mapping channels need to implement this method Here's an example:

void LocalMappingsRequired(int subMtlNum, BitArray & mapreq, BitArray &bumpreq) {

uvGen->MappingsRequired(subMtlNum,mapreq,bumpreq);

}

All 3D textures that use the XYZGen to put up a coordinates rollup must implement this method. Here's an example:

void LocalMappingsRequired(int subMtlNum, BitArray & mapreq,BitArray &bumpreq) {

xyzGen->MappingsRequired(subMtlNum,mapreq,bumpreq);

}

BuildMaps Method

Prototype:

virtual int BuildMaps(TimeValue t, RenderMapsContext &rmc)

Remarks:

Implemented by the Plug-In.

This method is called for a plug-in to do any work it needs to do prior to rendering. For example this is used by the 3ds max Mirror and Auto Reflect materials to render their bitmaps.

Parameters:

TimeValue t

The current time.

RenderMapsContext &rmc

Provides information about the view being rendered and can provide access to the global rendering environment information via RenderGlobalContext *gc = rmc.GetGlobalContext(). See Class RenderMapsContext and Class RenderGlobalContext.

Return Value:

Nonzero on success; zero on failure. In the case of failure the renderer is halted (rendering is cancelled).

Methods to access sub texture maps of materials or texmaps

Prototype:

virtual BOOL IsMultiMtl()

Remarks:

Implemented by the Plug-In.

This method returns TRUE for materials or textures that select sub-materials based on submaterial number (for example a mesh faceMtlIndex).

The only materials for which this method should return TRUE are those that choose to use one of their sub-maps or sub-mtls based on the submaterial number. For the majority of materials and maps, they should return FALSE, and in that case all of the submaterials and maps are enumerated by MtlBase::Requirements().

Default Implementation:

{ return FALSE; }

Prototype:

void DeactivateMapsInTree();

Remarks:

Implemented by the System.

This method must be called on a sub-material or sub-map when it is removed, in case it or any of its sub-maps are active in the viewport.

Update / Reset / Validity

Prototype:

virtual void Update(TimeValue t, Interval& valid)=0;

Remarks:

Implemented by the Plug-In.

A material has a Shade() method, and a texture map has a EvalColor() method. These are called by the renderer for every pixel. This method is called before rendering begins to allow the plug-in to evaluate anything prior to the render so it can store this information. In this way this information does not need to be calculated over and over for every pixel when Shade() or EvalColor() is called. This allows texture and material evaluation to be more efficient. It is generally called once at the start of each frame, or during interactive playback when the time changes. It is not guaranteed to get called on every frame, because if you returned a validity interval that covers several frames, your parent material won't bother to call you if the current frame is still in that interval.

Parameters:

TimeValue t

The current time.

Interval& valid

The validity interval to update to reflect the validity interval of the material or texture at the time passed.

Prototype:

virtual void Reset()=0;

Remarks:

Implemented by the Plug-In.

This method is called to reset the material or texmap back to its default values.

Prototype:

virtual Interval Validity(TimeValue t)=0;

Remarks:

Implemented by the Plug-In.

This method is called to determine the validity interval of the material or texture.

Parameters:

TimeValue t

Specifies the time about which to compute the validity interval.

Return Value:

The validity interval of the item at the specified time.

User Interface Methods

Prototype:

virtual ParamDlg* CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp)=0;

Remarks:

Implemented by the Plug-In.

This method gets called when the material or texture is to be displayed in the material editor parameters area. The plug-in should allocate a new instance of a class derived from ParamDlg to manage the user interface.

Note: The following is a discussion of this CreateParamDlg() method, and the SetDlgThing() method, and the way they relate to the ParamMap2 system. A good example for this discussion is a texture map which typically has several rollouts, say its texmap parameters, a UVW coordinates rollout, and an Output rollout.

The normal way for a texmap to implement these other (common) rollouts is for the it to create a UVGen instance and a TextureOutput instance as 'sub-objects' in the map and then ask them to put up their rollouts when it is asked to do so by the Materials Editor (in CreateParamDlg()). The Materials Editor requires a ParamDlg pointer back from the CreateParamDlg() on which it calls methods to control the UI, such as time change updates or loading up a new texmap of the same class into the UI when the user switches them, so that the whole UI doesn't need to be rebuilt.

Prior to the ParamMap2 system, a texmap would implement its own ParamDlg subclass and would keep track of the UVGen and TextureOutput ParamDialogs and pass on any time change or SetThing() calls to them. ParamMap2 introduced its own ParamDlg subclass (Class IAutoMParamDlg) that you can ask it to build for you and have manage all interaction with the Materials Editor automatically. As before, this still needs to know about the other (sub-object) ParamDlgs, and so it has the ability to keep a list of 'secondary' ParamDlgs to which it passes on the SetTime()s and SetThing()s.

When the Materials Editor asks the texmap to CreateParamDlg(), the texmap asks its ClassDesc2 to build one of these (ClassDesc2::CreateParamDlgs()). If the texmap itself has multiple ParamBlock2s, CreateParamDlgs() builds one ParamDlg per pblock/rollout, makes the first of them a 'master' and adds the rest as secondary ParamDlgs. The texmap then asks the UVGen and TextureOutput objects to CreateParamDlg() for their rollouts and adds them to the master IAutoMParamDlg also.

Now consider the need for the SetDlgThing() method below. It is related to the SetThing() method that the Materials Editor calls on the 'master' ParamDlg to switch into the UI a texmap of the same class as that currently in the UI. Normally, the master IAutoParamDlg would propogate the SetThing() to its registered secondary ParamDlgs. In the case of multiple paramblock2s in the texmap, this would be correct, since the 'thing' in this case is the incoming texmap. But this doesn't work for the secondary UVGen and TextureOutput ParamDlgs; their 'things' are the UVGen and TextureOutput subobjects of the incoming map. So, IAutoParamDlg first calls SetDlgThing() on the incoming texmap so that it gets a chance to call the correct SetThing()s on the sub-object ParamDlgs with the appropriate incoming sub-objects. A clear example of this is in Gradient::SetDlgThing() in \MAXSDK\SAMPLES\MATERIALS\GRADIENT.CPP. It is called once for each secondary ParamDlg. For those ParamDlgs that have special SetThing() requirements, it does the appropriate sub-object SetThing() and returns TRUE. If it does no special handling for a particular ParamDlg, it returns FALSE, signalling to the IAutoMParamDlg that it should do the standard SetThing() propogation for that dialog.

The Render Effects dialog has a similar arangment to the Materials Editor for controlling Effect UI and so there is an IAutoEParamDlg that works exactly the same way as the IAuotMParamDlg.

Parameters:

HWND hwMtlEdit

The window handle of the materials editor.

IMtlParams *imp

The interface pointer for calling methods in 3ds max.

Return Value:

A pointer to the created instance of a class derived from ParamDlg.

Multiple Map Display in the Viewports

Prototype:

virtual BOOL SupportsMultiMapsInViewport();

Remarks:

This method is available in release 4.0 and later only.

Implemented by the Plug-In.

Returns TRUE if this material supports the display of multi-maps in the viewports (interactive renderer); FALSE if it doesn't.

Default Implementation:

{ return FALSE; }

Prototype:

virtual void SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb);

Remarks:

This method is available in release 4.0 and later only.

Implemented by the Plug-In.

This method is called to initalize the interactive renderer Material passed with the properties of this MtlBase.

If a MtlBase (material or texmap) wants to display multiple textures in the viewports, it implements

SupportsMultiMapsInViewport() to return TRUE, and implements SetupGfxMultiMaps to store the necessary information in the Material passed in, including the TextureInfo's for each texture.

The MtlMakerCallback passed in to SetupGfxMultiMaps provides functions to help in setting up the "Material" data structure. The function NumberTexturesSupported() lets you know the capabilities of the current hardware, so you can adapt accordingly. The function GetGfxTexInfoFromTexmap fills in the fields of a TextureInfo except the texHandle and texture ops.

The implementation of SetupGfxMultiMaps must create the "texHandle" for each of the textures described in its TextureInfo array. It typically does this by calling the submap's GetVPDisplayDIB() method, and then creates the texHandle by calling the callBack function MakeHandle(bmi). To avoid doing this calculation when not necessary it is best to save the texHandles along with their validity intervals. Then when SetupGfxMultiMaps is called, if valid texHandles are already in hand they can just be used without recomputing.

Parameters:

TimeValue t

The time at which to evaulate the material.

Material *mtl

Points to the interactive renderer material to update.

MtlMakerCallback &cb

This callback object is provided as a helper to fill in the Material properties above. See Class MtlMakerCallback.

Default Implementation:

{}

Loading and Saving Methods

Prototype:

IOResult Load(ILoad *iload);

Remarks:

Implemented by the System.

This method is called to load the material or texture from disk. The common MtlBase data must be loaded as well. See the code below.

Parameters:

ILoad *iload

An interface pointer for calling methods to load data. See Class ILoad.

Return Value:

See List of IOResults.

Sample Code:

IOResult Gradient::Load(ILoad *iload) {

 IOResult res;

 int id;

 while (IO_OK==(res=iload->OpenChunk())) {

  switch(id = iload->CurChunkID()) {

   case MTL_HDR_CHUNK:

    res = MtlBase::Load(iload);

    break;

   case MAPOFF_CHUNK+0:

   case MAPOFF_CHUNK+1:

   case MAPOFF_CHUNK+2:

    mapOn[id-MAPOFF_CHUNK] = 0;

    break;

   }

  iload->CloseChunk();

  if (res!=IO_OK)

   return res;

  }

 iload->RegisterPostLoadCallback(

  new ParamBlockPLCB(versions,NUM_OLDVERSIONS,&curVersion,this,1));

 return IO_OK;

 }

Prototype:

IOResult Save(ISave *isave);

Remarks:

Implemented by the System.

This method saves the plug-in's data to disk.. The common MtlBase data must be saved as well. The base class method must be called in a chunk at the beginning of every Mtl and Texmap.

Parameters:

ISave *isave

An interface pointer available for saving data. See Class ISave.

Return Value:

See List of IOResults.

Sample Code:

Note in the code below the base class method is called in a chunk before the rest of the plug-ins data is saved.

IOResult Gradient::Save(ISave *isave) {

 IOResult res;

 // Save common stuff

 isave->BeginChunk(MTL_HDR_CHUNK);

 res = MtlBase::Save(isave);

 if (res!=IO_OK) return res;

 isave->EndChunk();

 

 for (int i=0; i<NSUBTEX; i++) {

  if (mapOn[i]==0) {

   isave->BeginChunk(MAPOFF_CHUNK+i);

   isave->EndChunk();

   }

  }

 return IO_OK;

 } 

Enumerate Auxilliary Files Implementation

Prototype:

void EnumAuxFiles(NameEnumCallback& nameEnum, DWORD flags);

Remarks:

This method is available in release 2.0 and later only.

This is an implementation of the Animatable method. This default implementation simply recurses, skipping inactive subTexmaps if appropriate.

GBuffer (system) methods.

Prototype:

ULONG GetGBufID();

Remarks:

Implemented by the System.

Returns the G-buffer ID of this material.

Prototype:

void SetGBufID(ULONG id);

Remarks:

Implemented by the System.

Sets the G-buffer ID of this material.

Operators:

Prototype:

MtlBase& operator=(const MtlBase& m);

Remarks:

Implemented by the System.

Materials and Texmaps must use this operator to copy the common portion of themselves when cloning.

Postage Stamp Image Methods

The Material / Map Browser supports the display of small and large icon images for material and texture maps. The methods below deal with the creation, access and deletion of these images. The small size image is 32 pixels. The large size is 88 pixels.

Prototype:

PStamp* GetPStamp(int sz);

Remarks:

This method is available in release 2.0 and later only.

Implemented by the System.

Returns a pointer to the postage stamp image for the file.

Parameters:

int sz

One of the following values:

PS_SMALL for small (32x32) images.

PS_LARGE for large (88x88) images.

PS_TINY for tiny (24x24) images.

Prototype:

PStamp* CreatePStamp(int sz, BOOL Render = FALSE);

Remarks:

This method is available in release 2.0 and later only.

Implemented by the System.

Creates a postage stamp image and returns a pointer to it. If the postage stamp image already exists then it is simply returned.

Here's an example using this method to display a small material sample.

 

void DisplayMB(MtlBase *mb, HDC hdc, int x, int y) {

mb->CreatePStamp(0,TRUE); // create and render a small pstamp

PStamp *ps = mb->GetPStamp(0);

if (ps) {

int d = PSDIM(0);

int scanw = ByteWidth(d);

int nb = scanw*d;

UBYTE *workImg = new UBYTE[nb];

if (workImg==NULL)

return;

ps->GetImage(workImg);

Rect rect;

rect.left = x;

rect.top = y;

rect.right = x+d;

rect.bottom = y+d;

GetGPort()->DisplayMap(hdc, rect,0,0, workImg, scanw);

delete [] workImg;

}

}

Parameters:

int sz

One of the following values:

PS_SMALL for small (32x32) images.

PS_LARGE for large (88x88) images.

PS_TINY for tiny (24x24) images.

BOOL Render = FALSE

This parameter is available in release 4.0 and later only.

If set to true, the postage stamp bitmap will have the MtlBase rendered into it automatically. The bitmap can then be retrieved using PStamp::GetImage, for drawing in the UI.

Prototype:

void DiscardPStamp(int sz);

Remarks:

This method is available in release 2.0 and later only.

Implemented by the System.

Discards the postage stamp image.

Parameters:

int sz

One of the following values:

PS_SMALL for small (32x32) images.

PS_LARGE for large (88x88) images.

PS_TINY for tiny (24x24) images.

Internal Methods

Prototype:

int GetMeditObjType()

Remarks:

This method is used internally.

Prototype:

void SetMeditObjType(int t)

Remarks:

This method is used internally.

Prototype:

int GetMeditTiling()

Remarks:

This method is used internally.

Prototype:

void SetMeditTiling(int t)

Remarks:

This method is used internally.

Prototype:

BOOL TextureDisplayEnabled()

Remarks:

This method is used internally.

 

The following methods are for doing interactive texture display.

Prototype:

virtual BOOL SupportTexDisplay()

Remarks:

Implemented by the Plug-In.

Returns TRUE if this texture supports being used in the interactive renderer; otherwise FALSE. If the texture does return TRUE it is expected to implement the methods ActivateTexDisplay() and GetActiveTexHandle().

Default Implementation:

{ return FALSE; }

Prototype:

virtual void ActivateTexDisplay(BOOL onoff)

Remarks:

Implemented by the Plug-In.

This method is called when the usage of the texture the interactive renderer changes. This method must only be implemented if SupportTexDisplay() returns TRUE. This method does not cause the texture map to be drawn in the viewport but should be called with TRUE as the argument before this can occur. For viewport drawing of textures refer to Interface::ActivateTexture() and Interface::DeActivateTexture() instead.

Parameters:

BOOL onoff

TRUE if the texture is being used; FALSE if it is no longer being used.

Default Implementation:

{}

Prototype:

virtual DWORD GetActiveTexHandle(TimeValue t, TexHandleMaker& thmaker)

Remarks:

Implemented by the Plug-In.

This method is called to retrieve a texture handle to this texture map.

Parameters:

TimeValue t

The time to return the texture handle.

TexHandleMaker& thmaker

This class provides methods for creating a texture handle from a 3ds max bitmap and a Windows DIB. It also has a method to retrieve the required size of the texture map. See Class TexHandleMaker.

Return Value:

The texture handle.

Default Implementation:

{return 0;}

Prototype:

void IncrActive();

Remarks:

This method is used internally.

Prototype:

void DecrActive();

Remarks:

This method is used internally.

Prototype:

int Active();

Remarks:

This method is used internally.