*.dlu插件就是一个utility,这个插件通常在rollup栏的utility中加入一个自身选项,我们可以通过双击这个选项,让rollup的栏目上添加上一个我们自己的项目,通常会覆盖掉一个原先的项目。这个项目被点击的时候,能在rollup下面出现utility的相关功能,不同的utility会实现不同的需求。
在SDK中,我们可以编译SceneManager这个utility来看相关的功能。下面是对相关代码的注释,这些点是初学的时候的关键点。
1, dlu后缀名决定了max能知道该插件内部使用的肯定是属于UtilityObj,因此,代码中的SMananger继承这个类。
void SManager::BeginEditParams(Interface *ip,IUtil *iu) { this->iu = iu; this->ip = ip; hPanel = ip->AddRollupPage( hInstance, MAKEINTRESOURCE(IDD_SM_PANEL), // panel的句柄,在Windows里用resource制作 SManagerDlgProc, // panel的消息处理入口,有max调用 GetString(IDS_PARAMS), // string,显示在rollup上,作为这个单位的抬头 0); }
3,上面的消息处理入口方法
static INT_PTR CALLBACK SManagerDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: MM.Init(hWnd); break; case WM_DESTROY: MM.Destroy(hWnd); break; case WM_ENABLE: if(MM.hMapper!=NULL) EnableWindow(MM.hMapper,(BOOL) wParam); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_LAUNCH: //这个是LaunchManager这个按键的ID if(MM.hMapper==NULL) MM.hMapper = CreateDialog( hInstance, MAKEINTRESOURCE(IDD_SM_FLOATER), //是一个对话框,在windows中制作好 GetCOREInterface()->GetMAXHWnd(), //GetMAXHWnd()得到max的窗口句柄 MMDlgProc); //Dialog的回调函数入口 break; } break; default: return FALSE; } return TRUE; }
4, 按下按键后弹出的对话框的消息处理出口
static INT_PTR CALLBACK MMDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg){ case WM_INITDIALOG: MM.RefreshScanner(hWnd); break; case WM_DESTROY: MM.biDB.SetSize(0); MM.mtDB.SetSize(0); MM.txDB.SetSize(0); // kill variables MM.totalRAM=0; MM.vertcount=0; MM.facecount=0; MM.UV1count=MM.UV2count=0; break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_SAVE:{ OPENFILENAME ofn; TCHAR filename[255] = _T(""); memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(OPENFILENAME); // No OFN_ENABLEHOOK ofn.hwndOwner = hWnd; ofn.hInstance = hInstance; ofn.lpstrFile = filename; ofn.nMaxFile = sizeof(filename) / sizeof(TCHAR); ofn.lpstrFilter = _T("Text File\0*.txt\0"); ofn.nFilterIndex = 1; ofn.lpstrTitle = _T("Choose Output"); ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = MM.ip->GetDir(APP_SCENE_DIR); ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; ofn.FlagsEx = OFN_EX_NOPLACESBAR; if (GetSaveFileName(&ofn)) { if(_tcsicmp(filename + _tcslen(filename) - 4, ".txt")) strcat(filename,".txt"); FILE *stream; stream = fopen(filename,"wt"); HWND outHwnd = GetDlgItem(hWnd,IDC_OUT); if (stream) { for(int x=0; x<(SendMessage(outHwnd,LB_GETCOUNT,0,0));x++) { char q[255]; SendMessage(outHwnd,LB_GETTEXT,x,(WPARAM)q); fprintf(stream,"%s\n",q); } fclose(stream); } } break;} case IDC_CLOSE: MM.hMapper=NULL; EndDialog(hWnd,1); break; case IDC_CLEAR: SendMessage(GetDlgItem(hWnd,IDC_OUT),LB_RESETCONTENT,0,0); InvalidateRect(GetDlgItem(hWnd,IDC_OUT),NULL,TRUE); break; case IDC_GENERATE: // kill variables MM.totalRAM=0; MM.vertcount=0; MM.facecount=0; MM.UV1count=MM.UV2count=0; MM.biDB.SetSize(0); MM.mtDB.SetSize(0); MM.txDB.SetSize(0); MM.SetStatus(""); MM.Output("--- START OF REPORT ---"); MM.Output(""); MM.Output(""); if(MM.m1==1) MM.DoObjects(); if(MM.m2==1) MM.DoUVW(); if(MM.m3==1) MM.DoMaps(); if(MM.m4==1) MM.DoDups(); if(MM.m5==1) MM.DoLights(); MM.Output(""); MM.Output("Total Memory Usage: %.2fMB",(float)MM.totalRAM/1024.0f); MM.Output("");MM.Output("--- END OF REPORT ---");MM.Output("");MM.Output(""); MM.SetStatus(""); break; case ID_ALL: MM.m1=MM.m2=MM.m3=MM.m4=MM.m5=1;MM.RefreshScanner(hWnd); break; case ID_NONE: MM.m1=MM.m2=MM.m3=MM.m4=MM.m5=0;MM.RefreshScanner(hWnd); break; case ID_1:{ if(MM.m1==1){MM.m1=0;} else {MM.m1=1;}MM.RefreshScanner(hWnd); break;} case ID_2:{ if(MM.m2==1){MM.m2=0;} else {MM.m2=1;}MM.RefreshScanner(hWnd); break;} case ID_3:{ if(MM.m3==1){MM.m3=0;} else {MM.m3=1;}MM.RefreshScanner(hWnd); break;} case ID_4:{ if(MM.m4==1){MM.m4=0;} else {MM.m4=1;}MM.RefreshScanner(hWnd); break;} case ID_5:{ if(MM.m5==1){MM.m5=0;} else {MM.m5=1;}MM.RefreshScanner(hWnd); break;} } break; case WM_SIZE:{ MoveWindow(GetDlgItem(hWnd,IDC_OUT), 0, 0, LOWORD(lParam), HIWORD(lParam)-22,TRUE); Rect rw; GetWindowRect(GetDlgItem(hWnd,IDC_OUT),&rw); MoveWindow(GetDlgItem(hWnd,IDC_STATUS), 0, rw.h()+1, LOWORD(lParam), 20,TRUE); break;} case WM_CLOSE: MM.hMapper=NULL; EndDialog(hWnd,1); break; } return FALSE; }
上面的方法,大多数是Windows编程的代码,MM起头的字样是内部的处理数据的实例。跟max内部数据打交道的地方,会在后续记录。这里只记录入手max plugin的时候的切入点。