Publishing Mixin Interface on Arbitrary Classes
 
 
 

Publishing Mixin Interface on Arbitrary Classes

You can publish FnPub mixin interfaces on any class, not just Animatable subclasses. To do this, you inherit from, IObject, a new virtual base class in the FnPub system. This provides an API for querying and iterating FPMixinInterfaces that the class wishes to publish, similar to Animatable::GetInterface(). The API that the publishing class must implement is as follows:

class IObject
{
   public:
     // object/class name
     virtual TCHAR* GetName()=0;
 
     // iterate over all interfaces...
     virtualint NumInterfaces()=0; 
     virtual FPInterface* GetInterface(inti)=0;
 
     // get ID'd interface
     virtual FPInterface* GetInterface(Interface_ID id)=0;
 
     // IObject ref management (can be implemented by dynamically-
     // allocated IObjects for ref-count based lifetime control)
      virtualvoid Acquire() { }; 
     virtualvoid Release() { };
};

There is a corresponding new ParamType2 type code, TYPE_IOBJECT, that allows instances of these classes to be passed and returned in FPInterface methods, providing a simple form of user-defined type, in the sense that these instance collections are passed as interfaces rather than pointers (similar to COM). MAXScript has been extended to provide wrapper value classes for IObjects and so this mechanism provides a light-weight alternative to the MAXScript SDK facilities for adding new wrapper value classes to the scripter.

MAXScript also calls the Acquire() and Release() methods on IObjects as it creates and collects these wrappers, so that IObject objects can keep track of MAXScript's extant references to them. For example:

class IFoo1 : public  FPMixinInterface
{
   virtualvoid Frabulate(Point3 p)=0;
   //...
};
 
class IFoo2 : public  FPMixinInterface
{
   //...
};
 
class Foo : public IObject, publicIFoo1, publicIFoo2
{
   // Foo methods
   //...
 
   // IObject methods
   TCHAR* GetName() { return_T("Foo"); }
   intNumInterfaces() { return 2; }
 
   FPInterface* GetInterface(inti)
   {
     if (i == 0) return (IFoo1*)this;
     if (i == 1) return (IFoo2*)this;
   }
 
   FPInterface* GetInterface(Interface_ID id)
   {
     if (id == FOO_INTERFACE_1) return (IFoo1*)this;
     if (id == FOO_INTERFACE_2) return (IFoo2*)this;
   }
   // IFoo1 methods
   voidFrabulate(Point3 p) { ... }
   //...
   // IFoo2 methods
   //...
};

Instances of Foo can be passed as parameters and results in FnPub interface descriptors and function maps by declaring them as TYPE_IOBJECT values, and they will get cast to IObject* automatically. For example, in a plug-in that uses the Foo class, a method in one of its FPInterfaces might want to return a Foo instance. The method might be defined as:

Foo* GetFoo(INode* object)
{
   Foo* x = newFoo (...);
   //...
   returnx;
}

Since Foo is not a supported base ParamType2 type but is derived from IObject, the return value of the above method can be declared using TYPE_IOBJECT in the FUNCTION_MAP as:

FN_1(my_getFoo, TYPE_IOBJECT, GetFoo, TYPE_INODE);

and in the descriptor constructor as:

my_getFoo, _T("getFoo"), 0, TYPE_IOBJECT, 0, 1,
     _T("object"), 0, TYPE_INODE,

In MAXScript, calling getFoo() would return an IObject value that has two interface properties, ifoo1 and ifoo2, and these in turn would expose their methods as properties:

f = getFoo $
f.ifoo1.frabulate [10,0,0] --call the IFoo1 frabulate method