Class descriptors provide 3ds Max with information about each plug-ins that is implemented in a DLL, and allows 3ds Max to instantiate them. A plug-in will implement its own class descriptor by deriving from ClassDesc2 which in turn derives from ClassDesc.
A ClassDesc2 class descriptor contains a a table of ParamBlockDesc2s for all the parameter blocks used in the plug-in, and a number of methods for accessing block descriptors, UI management, auto param block2 construction, and access to any ParamMap2s.
3ds Max queries the DLL for the number of class descriptors contained in the plug-in using LibNumberClasses() and will retrieve them using LibClassDesc(). For more information see Required DLL Functions.
Here is an example of a plug-ins class descriptor:
class WidgetClassDesc : public ClassDesc2 { public: int IsPublic() { return TRUE; } void* Create(BOOL loading = FALSE) { return new Widget(); } const TCHAR* ClassName() { return GetResourceString(IDS_CLASS_NAME); } SClass_ID SuperClassID() { return GEOMOBJECT_CLASS_ID; } Class_ID ClassID() { return Widget_CLASS_ID; } const TCHAR* Category() { return GetResourceString(IDS_CATEGORY); } // returns fixed parsable name (scripter-visible name) const TCHAR* InternalName() { return _T("Widget"); } // returns owning module handle HINSTANCE HInstance() { return hInstance; } };
The ClassDesc::IsPublic() member function returns a boolean value to indicate whether the plug-in should be exposed to the user through the 3ds Max user interface. If the plug-in can be selected by the user, as is usually the case, return TRUE otherwise return FALSE. The following code example demonstrates how a plug-in that is only intended for 3ds Max Design might prevent itself from being display in non-Design versions of 3ds Max.
int IsPublic() { return GetProductID() == k3dsMaxDesign ? 1 : 0; }
3ds Max calls the ClassDesc::Create() member function when it needs a pointer to a new instance of the plug-in class. For example, if 3ds Max is loading a file from disk containing a previously used plug-in (procedural object, modifier, controller, etc.), it will call the plug-in's ClassDesc::Create() member function. The plug-in responds by allocating a new instance of its plug-in class. Typically this would be done using the new operator.
The optional parameter passed to ClassDesc::Create() is a flag indicating if the class being created is going to be loaded from a disk file. If the flag is TRUE, the plug-in may not have to perform any initialization of the object because the loading process will take care of it. See the section on Loading and Saving Plug-in Data for more information.
Some plug-ins allow the system to manage the creation process so their implementation of this member function simply returns NULL. This indicates to the system that it should invoke the default object creation process.
The ClassDesc::ClassName() member function returns the potentially localized name of the class. This name appears in the button for the plug-in in the 3ds Max user interface. This name is also used by MAXScript as a name for the class. However, since the name returned by this method may be a localized name, scripts written in one locale may not work correctly in other locales.
In general, your plug-in should implement ClassDesc::UseOnlyInternalNameForMAXScriptExposure() and return true, in which case only the non-localized name returned by InternalName() is used by MAXScript as the name of the class. If UseOnlyInternalNameForMAXScriptExposure() is not implemented, or returns false, both the ClassName and InternalName are used as names for the class.
The ClassDesc::SuperClassID() member function returns a system-defined constant describing the class that this plug-in class was derived from. For example, the Bend modifier returns OSM_CLASS_ID. This super class ID is used by all object space modifiers. Some other example super class IDs are: CAMERA_CLASS_ID, LIGHT_CLASS_ID, SHAPE_CLASS_ID, HELPER_CLASS_ID, and SYSTEM_CLASS_ID. Consult the C++ Reference's "Related Pages > Lists and Functions > List of Super Class IDs" for the entire list of available super class IDs.
The ClassDesc::ClassID() member function must return the unique ID for the plug-in object. A program is provided with the SDK called Generating Class IDs to generate these IDs, to avoid conflicts with existing plug-ins. It is very important you use this program to create the class ids for your plug-ins.
Note: If you use one of the source code examples to create your plug-in, you MUST change the existing Class_ID. If you don't, you'll get a conflict. If two class IDs conflict, the system will only load the first one it finds (and will post a message when it attempts to load the second one noting that there is a Class_ID conflict).
A Class_ID consists of two unsigned 32-bit quantities. The constructor assigns a value to each of these, for example Class_ID( 0xA1C864D1, 0xE7AA2BE5). See theClass_ID documentation for reference information.
Note: sample code plug-ins used in 3ds Max use 0 as the second 32-bit quantity of the Class_ID. Only the built-in classes (those that ship with 3ds Max) should have the second 32 bits equal to 0 . All plug-in developers should use both 32 bit quantities.
The ClassDesc::Category() category is selected in the bottom-most drop down list in the create branch of the command panel. If this is set to be an existing category (i.e. "Standard Primitives", "Particle Systems", etc.) then the plug-in will appear in that category. Developers should not add to the categories provided by 3ds Max (see the note below). If the category doesn't yet exist then it is created. If the plug-in does not need to appear in the list, it may simply return an empty string as in \_T(""). ClassDesc::Category() is also used for modifiers to classify them in the button sets dialog.
The ClassDesc::InternalName() returns a fixed, parsable internal name for the plug-in.
By default, Plug-in names exposed to MAXScript are generated using both the strings from ClassName() and InternalName(). You can change this behavior by returning true from ClassDesc::UseOnlyInternalNameForMAXScriptExposure(), in which case the plug-in exposes only its InternalName(). We recommend that new plugins implement this method and return true.