Editing Material and Texture Parameters

This section discusses the manner in which plug-in texture and materials manage their user interface in 3ds Max. This is only a concern of developers creating plug-in materials or textures.

The way materials and texture maps handle their user interface is different than the way other plug-ins handle their UI in the command panel of 3ds Max. For materials and textures, a developer derives a class from ParamDlg and implements its methods.

A method of MtlBase named CreateParamDlg() is called by the system when the material or texture is to be displayed in the material editor parameters area. This method is expected to create a new instance of a class derived from ParamDlg. The system then maintains the ParamDlg pointer. When the system needs to delete the memory associated with this instance it calls the method ParamDlg::DeleteThis().

Within the instance of the class derived from ParamDlg a developer can store any data needed to handle the user interface (for example, spinner control handles, window handles, etc.). The class will also need to have a pointer to the 'thing' that is being edited. This 'thing' is either a texture or the material.

As the user works with different materials in the materials editor, these materials have to put up their user interfaces. For example, if the user is editing a Standard material in one sample window, then selects another Standard material in another sample window, the user interface changes to reflect the new material settings. The user interface does not 'flash' however -- in other words the entire rollup page is not deleted and replaced. Rather the fields are simply updated to reflect the new values. What the system is doing is effectively 'passing off' the user interface from one material to another. Two methods of ParamDlg allow this to happen. These are SetThing() and GetThing().

When a system calls SetThing() it passes a pointer to a ReferenceTarget. This is the item that is being edited. So normally a developer would implement this method to store the item being edited (the 'thing') and update the user interface controls to reflect the state of the new 'thing'.

When the system calls GetThing(), the plug-in returns the 'thing' that is currently being edited.

As an example, consider the following code from the Checker texture map. Checker derives a class from ParamDlg and uses data members to store the data needed for its operation. A portion of this code is shown below:

classCheckerDlg: public ParamDlg
{
   public:
     HWND hwmedit; // window handle of the materials editor dialog
     IMtlParams *ip;
     Checker *theTex; // current Checker being edited.
     HWND hPanel; // Rollup pane
      ISpinnerControl *blurSpin;
     IColorSwatch *cs[2];
     TimeValue curTime;
     ParamDlg *uvGenDlg;
     int isActive;
     ...

Note that CheckerDlg has a data member that is a pointer to an instance of Checker (theTex). This is where it stores the 'thing', i.e. the current Checker being edited. Shown below are Checker's implementations of GetThing() and SetThing().

ReferenceTarget* GetThing() { return ( ReferenceTarget *)theTex; }

When the system calls GetThing(), Checker just returns the pointer to the item that is currently being edited.

voidCheckerDlg::SetThing( ReferenceTarget *m)
{
   assert (m->ClassID()==checkerClassID);
   assert (m->SuperClassID()==TEXMAP_CLASS_ID);
 
   if (theTex) theTex->paramDlg = NULL;
 
   theTex = (Checker *)m;
   uvGenDlg->SetThing(theTex->uvGen);
 
   if (theTex)
     theTex->paramDlg = this;
   LoadDialog(TRUE);
}

When the system calls SetThing(), Checker store the pointer to the item that is currently being edited into theTex. The Checker class itself maintains a pointer to the instance of ParamDlg that is handling the user interface. Note that Checker stores the this pointer (theTex->paramDlg = this;).

Also note that CheckerDlg maintains a pointer to a UVGen (UVGenDlg). UVGen is a class developers use to encapsulate the user interface for UV coordinates. This pointer is initialized in the CheckerDlg constructor as follows:

uvGenDlg = theTex->uvGen->CreateParamDlg(hwmedit, imp);

In the CheckerDlg implementation of SetThing() it also calls the SetThing() method on the uvGenDlg. This allows the UVGen to update its user interface in the dialog. These are the controls in the 'Coordinate' and 'Noise' rollups.