Converting Objects to Compatible Types

3ds Max objects aren't always in a form suitable for a particular type of modifier. Consider the case of a 3ds Max user putting a volume select modifier on a procedural sphere in order to select some vertices within it. A procedural sphere is not defined by vertices and faces. Rather it is defined by it procedural definition, i.e. its radius, segment count, hemisphere setting, etc. But a user can put a volume select modifier on a sphere. The way this is handled is that 3ds Max asks the object if it can be converted to a triangle mesh object (which has vertices and faces). If the sphere responds yes, then 3ds Max asks the sphere to convert itself to one. Then, once the objects is in the form of the triangle mesh, the modifier may alter it. There are two methods that procedural objects implement to allow this to happen. These are Object::CanConvertToType() and Object::ConvertToType().

The code executed by the procedural sphere implementation of Object::CanConvertToType() is as follows:

int SphereObject::CanConvertToType(Class_ID obtype)
{
   if (obtype==patchObjectClassID || obtype==defObjectClassID ||
      obtype==triObjectClassID || obtype==EDITABLE_SURF_CLASS_ID)
   {
     return 1;
   }
   else
   {
     return  SimpleObject::CanConvertToType(obtype);
   }
}
 
int  SimpleObject::CanConvertToType(Class_ID obtype)
{
   if (obtype==defObjectClassID || obtype==mapObjectClassID ||
      obtype==triObjectClassID || obtype==patchObjectClassID)
   {
     return 1;
   } 
   return Object::CanConvertToType(obtype);
}
 
int Object::CanConvertToType(Class_ID obtype)
{
   return obtype==ClassID();
}
 

Note that the sphere returns TRUE when asked if it can convert itself to a patch object, a deformable object (a generic object with points that can be modified), a triangle mesh object, and an editable surf object (NURBS object). In other cases it calls the base class method from SimpleObject. If SimpleObject doesn't recognize the type it calls its base class method from Object. The Object implementation returns nonzero if the object is asked to convert to itself, otherwise zero.

When 3ds Max needs to actually have the object convert itself to the type required by the modifier it calls ConvertToType() on the object as passes the needed Class_ID. Below is the code from the procedural sphere's implementation.

Object* SphereObject::ConvertToType(TimeValue t, Class_ID obtype)
{
   if (obtype == patchObjectClassID)
   {
     Interval valid = FOREVER;
     float radius;
     int smooth, genUVs;
     pblock->GetValue(PB_RADIUS,t,radius,valid);
     pblock->GetValue(PB_SMOOTH,t,smooth,valid); 
     pblock->GetValue(PB_GENUVS,t,genUVs,valid);
     PatchObject *ob = new PatchObject();
     BuildSpherePatch(ob->patch,radius,smooth,genUVs);
     ob->SetChannelValidity(TOPO_CHAN_NUM,valid);
     ob->SetChannelValidity(GEOM_CHAN_NUM,valid);
     ob->UnlockObject();
     return ob;
   }
   elseif (obtype == EDITABLE_SURF_CLASS_ID)
   {
     Interval valid = FOREVER;
     float radius, hemi;
     int recenter, genUVs;
     pblock->GetValue(PB_RADIUS,t,radius,valid);
     pblock->GetValue(PB_HEMI,t,hemi,valid); 
     pblock->GetValue(PB_RECENTER, t,recenter,valid);
     pblock->GetValue(PB_GENUVS,t,genUVs,valid);
     Object *ob = BuildNURBSSphere(radius, hemi, recenter,genUVs);
     ob->SetChannelValidity(TOPO_CHAN_NUM,valid);
     ob->SetChannelValidity(GEOM_CHAN_NUM,valid);
     ob->UnlockObject();
     return ob;
   }
   else
   {
     return  SimpleObject::ConvertToType(t,obtype);
   }
}

The cases handled above cover converting to a patch or NURBS representation. The other cases are handled by the base classes.

In summary, an object must implement two methods to allow a modifier to operate upon it. These are Object::CanConvertToType() and Object::ConvertToType().