将KlayGE嵌入到MFC

说明:

1、KlayGE是一款国人开发的开源游戏引擎(),以下都是以KlayGE3.8.0而言,并且假定您已经可以编译该引擎(具体可以参看readme.html,有一点需要提醒由于KlayGE使用了动态运行时库,所以boost都会使用动态库版本,例如boost::signals, boost::filesystem等,运行时不要忘了相关dll文件)并且可以运行给定的demo。

2、KlayGE和Ogre都是相当优秀的开源游戏引擎,个人感觉Ogre设计上更为灵活,这是其最值得学习的地方;而KlayGE则在技巧和技术上有更多可以学习的地方(他的设计也是相当优秀的,至少是我辈望尘莫及的),例如boost库的大量使用(尤其是boost::signals和boost::python),强大的字体系统(与Ogre的字体系统对比一下就知道了),与python的结合等。

3、MFC只是提供了一个GUI框架,还可以有更多的选择,wx,qt,甚至是.net Framework等。

4、本文并没有完美的实现嵌入,至少KlayGE自带的GUI系统嵌入后就无法正常使用了。并且由于KlayGE没有开放单独绘制一桢这样的函数,所以直接关闭程序会有内存泄漏和异常。以后再研究研究,试着把相关功能提取一下,做成和Ogre一样的,那样就可以在OnIdle()和OnPaint()时渲染一桢,在OnDestory()时清理资源。

~~~~~~~~~~~~~~~~~~~~~哥不是分界线,是寂寞~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

KlayGE本身并没有为嵌入MFC做过考虑(这似乎也是正常的),但是假如我们要做一款编辑器或是其他什么东东,需要用到这方面的功能。KlayGE源代码的修改是必须的。

KlayGE工程,window。hpp/cpp,class Window 这个类就是一个窗口,KlayGE会在构造函数的时候CreateWindow,而我们所要做的就是创建另一个构造函数,传入一个HWND,这个构造函数不会CreateWindow。如下:

Window::Window(HWND hWnd, const std::string& strName) { Convert(wname_, strName); wnd_ = hWnd; m_bIsExternal = true; RECT rect; GetWindowRect(wnd_, &rect); left_ = rect.left; top_ = rect.top; width_ = rect.right - rect.left; height_ = rect.bottom - rect.top; } Window::~Window() { if (wnd_ != NULL && !m_bIsExternal) { ::DestroyWindow(wnd_); wnd_ = NULL; } }

这里多添了一个成员变量m_bIsExternal,如果是外部传入的窗口句柄,那么window在析构的时候就不销毁窗口。

Window的创建是在App3D.hpp/cpp中App3DFramework类的构造函数中进行的,建立一个3D程序必须继承这个类。同理我们需要添加一个传入HWND的构造函数。

App3DFramework::App3DFramework(HWND hWnd, const std::string& strName, RenderSettings const & settings) : name_(strName), settings_(settings), fps_(0), accumulate_time_(0), num_frames_(0) { Context::Instance().AppInstance(*this); main_wnd_ = this->MakeWindow(hWnd, strName); settings_.left = main_wnd_->Left(); settings_.top = main_wnd_->Top(); settings_.width = main_wnd_->Width(); settings_.height = main_wnd_->Height(); } WindowPtr App3DFramework::MakeWindow(HWND hWnd, const std::string &strName) { return MakeSharedPtr<Window>(hWnd, strName); }

这样我们的准备工作就完成了。接下来就是建立一个MFC程序(单文档或多文档均可),选择一个Demo插入到工程中,在合适的位置初始化(我个人喜欢把Demo的头文件包含在CXXXXApp.h中,并在BOOL CXXXXApp::InitInstance()中的ShowWindow之前初始化,因为这个时候View肯定已经创建完成了。别忘了using namespace KlayGE;),最后删除原Demo中的main函数。

// 调度在命令行中指定的命令。如果 // 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。 if (!ProcessShellCommand(cmdInfo)) return FALSE; ResLoader::Instance().AddPath("./media/Common"); ResLoader::Instance().AddPath("./media/Cartoon"); RenderSettings settings = Context::Instance().LoadCfg("KlayGE.cfg"); CMainFrame* pMainFrm = (CMainFrame*)m_pMainWnd; Cartoon app(pMainFrm->GetActiveView()->GetSafeHwnd(), "卡通渲染", settings); app.Create(); app.Run(); // 唯一的一个窗口已初始化,因此显示它并对其进行更新 m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow();

ResLoader开始,注意这里的资源位置要正确,并且KlayGE的Demo中使用的都是。kui 。kfx这样加密成二进制的文件。把对应的xml文件(如 。uiml 。fxml)插入到工程中vs会自动编译的。

好了,一切就绪,编译……………………等等,怎么出现一大堆错误?

原来是windef.h中的min max宏定义和std::min std::max冲突了,在有冲突的头文件开头加入#undef min和#undef max(我加在mathhelper.hpp和elementformat.hpp中)就好了。

ok, enjoy yourself!

KlayGEMFC

版权声明:本文为博主原创文章,遵循版权协议,转载请附上原文出处链接和本声明。
本文链接:
德国时时彩 极速快乐8 幸运飞艇官网 秒速时时彩 235棋牌 北京幸运28 天津11选5 澳洲幸运10开奖结果 快乐赛车 幸运飞艇官网