在网上有很多有关Ogre嵌入MFC的文章,(我看了几乎所有的有关的文章,下载了几乎所有的所谓的源代码),不过总结起来其实都基本是一个版本的,不知道转载的人没有看懂,有没有亲自编译过,那些教程写的不是很清楚,或者那些就足够一个高手看懂了,但是对一个C++新手而言貌似有点深了,致使很多人照着做却出现很多错误,浪费了很多时间。为了让更多的人更快的学会如何将Ogre嵌入MFC框架之中,便写了这篇教程。废话不多说,直接上教程:
以下内容是结合网上找的例程进行整理的,主要参考下面链接中文章:但有少许改动以使本程序适合VS2010及Ogre1.8版本,
特别说明:以下文章所述内容可在Win7 -32位系统,XP系统,均可通过正常运行。
原文地址:http://blog.csdn.net/tulun/article/details/5486828
第一步:建立一个名为OgreMFC的单文档应用程序
点击确定后出现下面界面:
点击下一步:
然后按图上所标示部分进行选择,完成后点击下一步:
其实可以在上一步就点击完成,哈哈。我只是想说明后面都保持的默认值。出现的界面是下面这个样子的,
接下来就是打开头文件OgreMFCView.h粘入以下代码
// OgreMFCView.h : COgreMFCView 类的接口
//
#pragma once
//添加的代码
#include "ogre.h"
#include "OgreConfigFile.h"
using namespace Ogre;
class COgreMFCView : public CView
{
protected: // 仅从序列化创建
COgreMFCView();
DECLARE_DYNCREATE(COgreMFCView)
// 属性
public:
COgreMFCDoc* GetDocument() const;
// 操作
public:
// 重写
public:
virtual void OnDraw(CDC* pDC); // 重写以绘制该视图
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
void setupResources();//添加的代码
// 实现
public:
virtual ~COgreMFCView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// 生成的消息映射函数
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
private:
CPoint m_mouseLast;
Root* mRoot;
RenderWindow* mWindow;
SceneManager* mSceneMgr;
Camera* mCamera;//添加的代码
public:
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
};
#ifndef _DEBUG // OgreMFCView.cpp 中的调试版本
inline COgreMFCDoc* COgreMFCView::GetDocument() const
{ return reinterpret_cast<COgreMFCDoc*>(m_pDocument); }
#endif
然后打开
OgreMFCView.cpp粘入以下代码:
// OgreMFCView.cpp : COgreMFCView 类的实现
//
#include "stdafx.h"
#include "OgreMFC.h"
#include "OgreMFCDoc.h"
#include "OgreMFCView.h"
#define OGRE_DEBUG_MEMORY_MANAGER 1
//#ifdef _DEBUG
//#define new DEBUG_NEW
//#endif
// COgreMFCView
IMPLEMENT_DYNCREATE(COgreMFCView, CView)
BEGIN_MESSAGE_MAP(COgreMFCView, CView)
// 标准打印命令
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_TIMER()
ON_WM_CREATE()
ON_WM_DESTROY()
END_MESSAGE_MAP()
// COgreMFCView 构造/析构
COgreMFCView::COgreMFCView()
{
// TODO: 在此处添加构造代码
mRoot = 0;
}
COgreMFCView::~COgreMFCView()
{
delete mRoot;
}
BOOL COgreMFCView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return CView::PreCreateWindow(cs);
}
void COgreMFCView::setupResources()
{
// Load resource paths from config file
ConfigFile cf;
cf.load("resources.cfg");
// Go through all sections & settings in the file
ConfigFile::SectionIterator seci = cf.getSectionIterator();
String secName, typeName, archName;
while (seci.hasMoreElements())
{
secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;
for (i = settings->begin(); i != settings->end(); ++i)
{
typeName = i->first;
archName = i->second;
ResourceGroupManager::getSingleton().addResourceLocation(
archName, typeName, secName);
}
}
}
// COgreMFCView 绘制
void COgreMFCView::OnDraw(CDC*/*pDC*/)
{
static bool once =true;
COgreMFCDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
if(once)
{
mRoot = new Root();
setupResources();
RenderSystemList rl = Root::getSingleton().getAvailableRenderers();
//D3D9RenderSystem
RenderSystem* rsys = NULL;
RenderSystemList::iterator it = rl.begin();
while( it != rl.end() )
{
if( -1 != ( *it )->getName().find("Direct3D9" ) )
{
rsys = (RenderSystem*)( *it );
break;
}
it++;
}
//mRoot->showConfigDialog();
rsys->initConfigOptions();
//rsys->setConfigOption("Colour Depth", "32" );
rsys->setConfigOption("Anti aliasing", "None" );
rsys->setConfigOption("Floating-point mode", "Fastest" );
rsys->setConfigOption( "Full Screen","No" );
rsys->setConfigOption("Rendering Device","NVIDIA GeForce FX 5700VE");
rsys->setConfigOption( "VSync","No" );
//rsys->setConfigOption( "Video Mode", "800 x 600 @ 32-bit colour" );
rsys->setConfigOption( "Video Mode","640 x 480" );
//rsys->setConfigOption( "Display Frequency", "60" );
// 起用
mRoot->setRenderSystem( rsys );
mRoot->initialise( false );
NameValuePairList miscParams;
unsigned int h = (unsigned int)this->GetSafeHwnd();
miscParams["externalWindowHandle"] = StringConverter::toString(h);
mWindow = NULL;
mWindow = mRoot->createRenderWindow( "View", 640, 480,false, &miscParams );
once = false;
mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "ExampleSMInstance");
// Create the camera
mCamera = mSceneMgr->createCamera("PlayerCam");
// Position it at 500 in Z direction
mCamera->setPosition(Vector3(0,0,500));
// Look back along -Z
mCamera->lookAt(Vector3(0,0,-300));
mCamera->setNearClipDistance(5);
// Create one viewport, entire window
Viewport* vp = mWindow->addViewport(mCamera);
vp->setBackgroundColour(ColourValue(0,0,0));
// Alter the camera aspect ratio to match the viewport
mCamera->setAspectRatio(
Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
//createScene();
// Set ambient light
mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
// Create a skydome
mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);
// Create a light
Light* l = mSceneMgr->createLight("MainLight");
// Accept default settings: point light, white diffuse, just set position
// NB I could attach the light to a SceneNode if I wanted it to move automatically with
// other objects, but I don't
l->setPosition(20,80,50);
Entity *ent;
// Define a floor plane mesh
Plane p;
p.normal = Vector3::UNIT_Y;
p.d = 200;
MeshManager::getSingleton().createPlane("FloorPlane",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
p,2000,2000,1,1,true,1,5,5,Vector3::UNIT_Z);
// Create an entity (the floor)
ent = mSceneMgr->createEntity("floor","FloorPlane");
ent->setMaterialName("Examples/RustySteel");
mSceneMgr->getRootSceneNode()->attachObject(ent);
ent = mSceneMgr->createEntity("head","ogrehead.mesh");
// Attach to child of root node, better for culling (otherwise bounds are the combination of the 2)
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
mWindow->update();
}
else
{
//mRoot->startRendering();
mWindow->update();
//drawScene();
}
}
// COgreMFCView 打印
BOOL COgreMFCView::OnPreparePrinting(CPrintInfo* pInfo)
{
// 默认准备
return DoPreparePrinting(pInfo);
}
void COgreMFCView::OnBeginPrinting(CDC*/*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加额外的打印前进行的初始化过程
}
void COgreMFCView::OnEndPrinting(CDC*/*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加打印后进行的清除过程
}
// COgreMFCView 诊断
#ifdef _DEBUG
void COgreMFCView::AssertValid()const
{
CView::AssertValid();
}
void COgreMFCView::Dump(CDumpContext& dc)const
{
CView::Dump(dc);
}
COgreMFCDoc* COgreMFCView::GetDocument() const// 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(COgreMFCDoc)));
return (COgreMFCDoc*)m_pDocument;
}
#endif //_DEBUG
// COgreMFCView 消息处理程序
BOOL COgreMFCView::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
//return CView::OnEraseBkgnd(pDC);
return true;
}
void COgreMFCView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_mouseLast = point;
CView::OnLButtonDown(nFlags, point);
}
void COgreMFCView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(nFlags & MK_LBUTTON)
{
CPoint mouseDiff = point - m_mouseLast;
m_mouseLast = point;
mCamera->yaw(Degree(mouseDiff.x) * 0.2);
mCamera->pitch(Degree(mouseDiff.y) * 0.2);
}
CView::OnMouseMove(nFlags, point);
}
void COgreMFCView::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
Invalidate();
CView::OnTimer(nIDEvent);
}
int COgreMFCView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
SetTimer(1, 30, NULL);
return 0;
}
void COgreMFCView::OnDestroy()
{
CView::OnDestroy();
// TODO: Add your message handler code here
KillTimer(1);
}
好了,现在代码部分已经好了,下面就要开始配置工程的属性了:
参照
http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Setting+Up+An+Application+-+Visual+Studio
进行配置,配置完成后;按F7编译一下试试:很不幸运我出了一个错误:
进行配置,配置完成后;按F7编译一下试试:很不幸运我出了一个错误:
看看错误的说明: 8 IntelliSense: #error 指令: Please use the /MD switch for _AFXDLL builds
怎么办呢,改变一下吧就:项目属性打开——C\C++——代码生成——运行时库——多线程 DLL (/MD)
再编译一下:
郁闷至极又报错:错误 8 error C1083: 无法打开编译器生成的文件:“Debug\OgreMFCView.obj”: Permission denied
怎么解决呢:网上有人说直接删除debug下所有文件重新编译一下,开始竟然还删除不掉,只能强力删除了,然后重新编译。
哈哈,编译成功后直接运行出现效果如下所示:
补充说明一点,其中我还在此过程中做了如下改动:
1、在项目属性页——C\C++——预处理器——预处理器定义——_AFXDLL。(添加的)
2、如果你在编译时出现了Assertain failed ,那么
看一下ogre.log 文件,发现是FileNotFind,问题解决了,只需要把62行的 cf.load("resources.cfg"); 改成cf.load("resources_d.cfg");即可(Debug下)
3、如果第二步不好使,那么请到你的
把OgreSDK_vc10_v1-8-0/bin/debug中的resources_d.cfg跟plugins_d.cfg文件重命名为resources.cfg和plugins.cfg
按道理来讲,应该不会再有编译错误了。