3DS Max plugin 编程五,第一行代码
来源:互联网 发布:什么是web软件开发 编辑:程序博客网 时间:2024/06/06 05:27
这个篇章结束,我们能自己写一个*.dle插件,这个插件的最后结果很简单,弹出一个对话框,如下图:
从图中的对话框内容可以看出,我们这个对话框是在DoExport()中被Max引擎给调用到了。文章中,我们会从一个空的工程开始一点一点加入代码,直到最后上面的结果,整个过程能让我们实践一个插件的开发过程,当然,只是万里长征的第一步。
整个工程最后的文件清单如下:
1,dllmain.h, dllmain.cpp
2,exporterdesc.h, exporterdesc.cpp
3,resource.h
4,OgreExporter.h, OgreExporter.cpp
5,exporter.def
4里面用到Ogre开头的名称,是因为我们后续可以导出成Ogre识别的XML格式,这个格式可以在Ogre DTD文档中看到,对大家都比较方便。最后我们也可以用Ogre知道我们导出的有没有问题。
现在就让我们开始:
准备、用VC新建win32 project,创建一个DLL, 记住勾选empty project,我们会在写插件的过程中不停的手工加入需要的文件。
1、在新项目中添加new item,类型选择.cpp,加入第一个文件,dllmain.h,内容如下:
#ifndef DLLMAIN_H#define DLLMAIN_H#include <windows.h>#include "resource.h"#include "max.h"extern HINSTANCE hInstance;extern TCHAR *GetString(int id);#endif
这个头文件主要是包含了resource.h, windows.h, max.h 3个重要的头文件,准备做为一个基础给其他的C++文件包含用。
2、新加入dllmain.cpp,相关的代码如下,建议这个文件可以作为以后的模板文件,Copy-Paste代码的方式在这里完全是有意义的。
#include "dllmain.h"#include "exporterdesc.h"HINSTANCE hInstance;static ExporterDesc gExporterDescInst;BOOL WINAPI DllMain (HINSTANCE hInst, ULONG ulReason, LPVOID lpvReserved){ hInstance = hInst; switch(ulReason) { case DLL_PROCESS_ATTACH: if (FAILED(CoInitialize(NULL))) return FALSE; break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: break; } return(TRUE);}//------------------------------------------------__declspec( dllexport ) const TCHAR *LibDescription() { return _T("ogre exporter"); }__declspec( dllexport ) int LibNumberClasses() { return 1; }__declspec( dllexport ) ClassDesc *LibClassDesc(int i) { switch(i) { case 0: return &gExporterDescInst; break; default: return 0; break; }}__declspec( dllexport ) ULONG LibVersion() { return VERSION_3DSMAX; }__declspec( dllexport ) ULONG CanAutoDefer(){ return 1;}//------------------------------------------------TCHAR *GetString(int id){ static TCHAR buf[256]; if (hInstance) return LoadString(hInstance, id, buf, sizeof(buf)) ? buf : NULL; return NULL;}
需要特别注意的是,LibClassDesc()这个DLL入口实现,可以返回一个ClassDesc的指针,这里通常我们会在插件编写中让它返回一个全局的静态变量。
3、新加入文件,这次是.DEF文件。
LIBRARY "exporter"EXPORTS LibDescription @1 LibNumberClasses @2 LibClassDesc @3 LibVersion @4SECTIONS.data READ WRITE
这个文件定义了整个插件能导出的方法名称。
4、dllmain中引出了一个exporterdesc.h,所以我们新加入文件,名称即exporterdesc.h,文件中内容如下:
#include "iparamb2.h"class ExporterDesc : public ClassDesc2{public: ExporterDesc(); virtual ~ExporterDesc(); int IsPublic(); void * Create(BOOL loading = FALSE); const TCHAR * ClassName(); SClass_ID SuperClassID(); Class_ID ClassID(); const TCHAR* Category();};
这个类必须继承自ClassDesc2(或者ClassDesc,ClassDesc2是前者的继承类),并实现上述的接口。在Max启动的过程中,扫描到我们的插件的时候,DllMain()是重要的入口,因为是动态链接库强制的。而这里的Create(),则是Max引擎强制的,会被Max引擎用来创建插件主体的一个实例。
5、实现上面类的是exporterdesc.cpp中,我们要实现这些方法,如下:
#include "dllmain.h"#include "exporterdesc.h"#include "OgreExporter.h"ExporterDesc::ExporterDesc(){}ExporterDesc::~ExporterDesc(){}int ExporterDesc::IsPublic(){ return true;}const TCHAR* ExporterDesc::Category(){ return GetString(IDS_STRCATEGORY);}Class_ID ExporterDesc::ClassID(){ return Class_ID(0x73bd1636, 0x22f05f49);}const TCHAR* ExporterDesc::ClassName(){ return GetString(IDS_STRCLASSNAME);}void* ExporterDesc::Create(BOOL loading){ OgreExporter* pExporter = new OgreExporter(hInstance); return pExporter;}SClass_ID ExporterDesc::SuperClassID(){ return SCENE_EXPORT_CLASS_ID;}
我们的Create()方法创建了一个OgreExporter实例。所以,我们需要来加入OgreMaxExport这个类。这个类也是导出插件的真正主体。前面一切的一切都是因为Max引擎或者说是SDK需要我们那么做,为了让Max引擎能跟我们的插件做配合才做的工作。而这个被创建的OgreExporter才是我们真正的主角。
6、新加入OgreExporter.h文件,内容如下:
#ifndef OGREEXPORTER_H#define OGREEXPORTER_H#include <windows.h>#include "resource.h"#include "max.h"#include "impexp.h"#include "dllmain.h"class OgreExporter : public SceneExport{public:OgreExporter(HINSTANCE hInst) : m_hInstance(hInst) { }virtual ~OgreExporter ();public: virtual int ExtCount(); virtual const MCHAR* Ext(int n); virtual const MCHAR* LongDesc(); virtual const MCHAR* ShortDesc(); virtual const MCHAR* AuthorName(); virtual const MCHAR* CopyrightMessage(); virtual const MCHAR* OtherMessage1(); virtual const MCHAR* OtherMessage2(); virtual unsigned int Version(); virtual void ShowAbout(HWND hWnd); virtual int DoExport(const MCHAR* name,ExpInterface* ei,Interface* i,BOOL suppressPrompts=FALSE, DWORD options=0);private:HINSTANCE m_hInstance;};#endif
对于导出插件来讲(3DS Max中,导出插件是其中一个类型),我们需要继承SceneExport,
并实现基类的几个函数,列表如下:
virtual int ExtCount();virtual const MCHAR* Ext(int n);
virtual const MCHAR* LongDesc();
virtual const MCHAR* ShortDesc();
virtual const MCHAR* AuthorName();
virtual const MCHAR* CopyrightMessage();
virtual const MCHAR* OtherMessage1();
virtual const MCHAR* OtherMessage2();
virtual unsigned int Version();
virtual void ShowAbout(HWND hWnd);
virtual int DoExport(const MCHAR* name,ExpInterface* ei,Interface* i,BOOL suppressPrompts=FALSE, DWORD options=0);
在SDK中,可以看到这些方法SDK有标准[Pure Virtual],也就是“纯虚函数”,所以,有这个标注的方法就必须自己来实现实体。
7,实现的文件是新加入的文件,OgreExpoter.cpp。
#include "OgreExporter.h"OgreExporter::~OgreExporter(){}int OgreExporter::DoExport(const MCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options){ MessageBox (NULL, "DoExport called by Max engine", "Max plug-in", MB_OK); return 1;}const MCHAR* OgreExporter::AuthorName(){ return GetString(IDS_STRAUTHORNAME);}const MCHAR* OgreExporter::CopyrightMessage(){ return GetString(IDS_STRCOPYRIGHT);}const MCHAR* OgreExporter::Ext(int n){ switch (n) { case 0:return _T("xml");break; default:return _T(""); }}int OgreExporter::ExtCount(){ return 1;}const MCHAR* OgreExporter::LongDesc(){ return GetString(IDS_STRLONGDESC); }const MCHAR* OgreExporter::OtherMessage1(){ return GetString(IDS_STROTHER1);}const MCHAR* OgreExporter::OtherMessage2(){ return GetString(IDS_STROTHER2);}const MCHAR* OgreExporter::ShortDesc(){ return GetString(IDS_STRSHORTDESC); }void OgreExporter::ShowAbout(HWND hWnd){ }unsigned int OgreExporter::Version(){ return 100;}
如我在前面的文章中(http://blog.csdn.net/tinyhum/article/details/6918540)提过的,上述的Ext方法会被Max引擎迭代用来找到该插件支持的后缀,DoExport则是真正的主体,在用户选好导出的文件名字并按下保存后就会被Max引擎呼叫到,想做什么事情,主要在这里做文章。
弹出的对话框我们是直接调用Win32的MessageBox()来进行的,你也可以在VC中自己制作好Dialog模板来进行调用。我们的GetString()利用了VC的resource view来进行字符串调用。
上述7个文件,还不能编译成功整个工程,如果要编译过,你必须在工程中加入resource,并把GetString()用到的那些ID全部实现。
编译的过程中,项目的属性页上,头文件包含目录必须有max sdk的include路径;链接目录上,必须有max sdk的lib路径;输入的库文件中,需要有comctl32.lib core.lib geom.lib gfx.lib helpsys.lib maxutil.lib mesh.lib paramblk2.lib这些库,特别是最后一个库是我们目前一定需要的(ClassDesc2存在的库)。
- 3DS Max plugin 编程五,第一行代码
- 3DS Max Plugin 编程一,开始
- 3DS Max plugin 编程三,utility
- 3DS Max plugin 编程四,配置Hybrid
- 3DS Max plugin 编程八,导出单个物体
- 3DS Max Plugin 编程二,CryEngine的Max插件安装
- 3ds Max 2009 Plugin + vs 2008
- 3DS Max plugin 编程六,使用上SDK的库
- 3DS Max plugin 编程七,简单了解Ogre的XML格式内容(DTD)
- 3ds Max 2009 Plugin + vs 2008(转载)
- 3DS Max Lighting
- 3DS MAX
- 3ds max快捷键
- 3ds max经验
- 3ds max 扫盲
- 3ds Max 2017
- 《第一行代码3》
- 《第一行代码》读书笔记(五)----广播
- Design Pattern
- 黑马程序员-SqlHelper.cs
- 数独的生成和破解算法分析
- struts2的运行环境认识
- SAP PA标准教程概览
- 3DS Max plugin 编程五,第一行代码
- 代码的同步和异步执行
- 记事狗3.0去版权方法
- 无前缀码的Kraft不等式 一种理解
- struts2 的基本常用配置详解
- iperf 测试wifi速率rx偏低解决方案.
- ASIHTTPRequest官方文档(一)
- PL/SQL程序设计_基本语法
- 学习资料1