3DS MAX PLUGINs 程序逻辑

品雪 pinxue@hotmail.com http://pinxue.yeah.net

1999.10.2.


基本思想:3dsmax sdk是一组库及相应的头文件,其中包含了3ds max的大部分核心代码,利用库中的函数就可与系统内核通信。

3dsmax 的plugins(插件)就是一种动态链接库,每个插件都包含有若干个类及对象和公用函数。有一组公用函数及几个类的对象是提供给系统挂接和管理插件用的,另外一些类则实现插件本身的功能(如造型或修改)。

插件中的每种活动都是由相应如的类对象来完成的,如系统获取插件中定义的类的描述、插件对象创建时的鼠标交互响应、用户对插件对象参数的修改等都有相应的类,系统会调用指定的公用函数取得这些对象的地址,并在适当的时候激活它们。这就是3ds max 的回调机制。


/****3ds max 系统管理插件的接口部分****/

//定义插件对象的32位类ID。
#define SPHERE_C_CLASSID1 8239283498
#define SPHERE_C_CLASSID2 8239283498

//插件描述类对象
SphereClassDesc sphereDesc; ]
ClassDesc* GetSphereDesc() { return &sphereDesc;}

//系统管理所需方法
//这几个方法都是dllexport型的
LibVersion() {return VERSION_3DSMAX;}
LibNumberClasses() {return 1;}
LibClassDesc() {return GetSphereDesc();}
LibDescription() {return _T("Sphere Object. Call 1-800-plig-in");}

//插件描述类,成员为供系统管理用的方法
class SphereClassDesc: public ClassDesc{
public:

int      IsPublic()   {return 1;} //true可由用户选取,false由其它插件调用不与用户打交道。
void *     Create(BOOL loading=FALSE){return new SphereObject;}
const TCHAR * ClassName()  { return _T("Sphere_c");}
SClass_ID   SuperClassID(){ return GEOMOBJECT_CLASS_ID;}
Class_ID    ClassID()   { return CLASS_ID(SPHERE_C_CLASSID1,SPHERE_C_CLASS_ID2); }
const TCHAR*  Category()   { return _T("How To");}

}


/****3ds max用户启用插件生成物体时的接口部分****/

//创建时期的用户鼠标交互接口
//由一个CreateMouseCallBack衍生类的对象定义
class SphereObjCreateCallBack: public CreateMouseCallBack{
IPoint2 sp0; SphereObject *ob; Point3 p0;
public:
//开发者定义的创建时期的用户交互方法
int proc(ViewExp *vpt,int msg,int point , int flags, IPoints2 m, Matrix3 &mat);
void SetObj(SphereObject *obj){ ob=obj;}
}

//创建时对用户鼠标交互活动的响应代码
int SphereObjCreateCallBack::proc(ViewExp *vpt,int msg,int point , int flags, IPoints2 m, Matrix3 &mat)
{ float r;Point3 p1,center;
if(msg==MOUSE_POINT || msg==MOUSE_MOVE){
switch (point){
case 0:... break;
case 1:... break;
}
else if(msg==MOUSE_ABORT){ return CREATE_ABORT;}
return TRUE;
}

//定义创物体创建时的回调类对象。
static SphereObjCreateCallBack sphereCreateCB;

//在插件所创建的物体的类中定义获取创建回调函数地址的方法。
CreateMouseCallBack* SphereObject::GetCreateMouseCallBack()
{
sphereCreateCB.SetObj(this);
return &sphereCreateCB;
}


//创建时期对用户修改物体参数的响应
//在用户编辑实体参数(创建时或修改时)系统将调用BeginEditParams(),该方法负责为面添加并注册滚转页
//在编辑完成时系统将会调用EndEditParams()。

//BeginEditParams用来在用户进入参数编辑框时
void SphereObject::BeginEditParams(IObjParam*ip,ULONG flags,Animatable *prev){
SimpleObject::BeginEditParams(ip,flags,prev);
this->ip=ip;
if(pmapCreate&&pmapParam){
pmapCreate->SetParamBlock(this);
pmapTypeIn->SetParamBlock(this);
pmapParam->SetParamBlock(pblock);
}else {
if (flags&GEGIN_EDIT_CREATE){
pmapCreate=CreateCPParamMap(descCreate,CREATEDESC_LENGTH,this,ip,hInstance,MAKEINTRESOURCE(IDD_SPHEREPARAM1),_T("Creation Method"),0);
pmapTypeIn=CreateCPParamMap(descTypeIn,TYPEINDESC_LENGTH,this,ip,hInstace,MAKEINTRESOURCE(IDD_SPHEREPARAM3),_T("Keyboard Entry"),APPENDROOL_CLOSED);
}
pmapParam=CreateCPParamMap(descParam,PARAMDESC_LENGTH,pblock,ip,hInstace,MAKEINTRESOURCE(IDD_SPHEREPARAM2),_T("Parameters"),0);
}
if(pmapTypeIn){
pmapTypeIn->SetUserDlgProc(new SphereTypeInDlgProc(this));
}
}

void SphereObject::EndEditParams(IObjParam *ip,ULONG flags,Animatable *next){
SimpleObject::EndEditParams(ip,flags,next);
this->ip=NULL;
if(flags&END_EDIT_REMOVEUI){
if(pmapCreate) DestroyCPParamMap(pmapCreate);
if(pmapTypeIn)DestroyCPParamMap(pmapTypeIn);
DestroyCPParamMap(pmapParam);
pmapParam=NULL;
pmapTypeIn=NULL;
pmapCreate=NULL;
}
pblock->GetValue(PB_SEGS,ip->GetTime(),dlgSegments,FOREVER);
pblock->GetValue(PB_SMOOTH,ip->GetTime(),dlgSmooth,FOREVER);
}

class SphereTypeInDlgProc: public ParamMapUserDlgProc{
public:
SphereObject *so;
SphereTypeInDlgProc(SphereObject *s){so=s;}
BOOL DlgProc(TimeValue t,IParamMap*map,HWIND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
void DeleteThis(){delete this;}
};

BOOL SphereTypeInDlgProc::DlgProc(TimeValue,IParamMap *map,HWIND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg){
case WM_COMMAND:
switch(LOWORD(wParam)){
case IDC_TI_CREATE:{
if(so->crtRadius==0.0) return TRUE;
if(so->TestAFlag(A_OBJ_CREATING)){
so->pblock->SetValue(PB_RADIUS,0,so->crtRadius);
}
Matrix3 tm(l);
tm.SetTrans(so->crtPos);
so->ip->NonMouseCreate(tm);
return TRUE;
}
break;
}
return FALUSE;
}