1 /* 使用OGRE默认的资源文件语法分析器得到所有的资源 */
2 mResourceCfg = "plugins_d.cfg";
3 Ogre::ConfigFile cf;
4 cf.load(mResourceCfg);
5
6 Ogre::ConfigFile::SectionInterator seci;
7 seci = cf.getSectionInterator();
8 Ogre::ConfigFile::SettingsMultiMap *settings;
9 Ogre::ConfigFile::SettingsMultiMap::Interator *i;
10 Ogre::String secName, typeName, archName;
11 while(seci.hasMoreElement())
12 {
13 secName = seci.peekNextKey();
14 settings = seci.getNext();
15 for(i=settings->begin(); i != settings->end(); ++i)
16 {
17 /* 隐藏了访问资源的细节,不论是文件夹还是ZIP文件,都是透明的 */
18 typeName = i->first;
19 archName = i->second;
20 /* 现在OGRE核心之一资源管理器,就能够直接取得需要的资源 */
21 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName,typeName,secName);
22 }
23 }
24
25
26 /* 你如果不想在你的程序运行前出现配置对话框,可以用Root方法直接写入配置文件 */
27 Ogre::RenderWindow *mWindow;
28 /* 这里有个细节问题,即或运算先判断前一个是否成立,如果成立后面一个不会继续判断 */
29 if(!(mRoot->restoreConfig() || mRoot->showConfigDialog()))
30 {
31 return false;
32 }
33 /* 你也可以用WIN32API自己创建一个用于渲染的窗口 */
34 mWindow = mRoot->initialise(true, "Game Render Window");
35
36 /* 一个游戏需要大量的资源文件,可是在某个时刻却只需要其中的一部分;前一部分已经做完,后部分马上完成;
37 * 不过在此之前,需要设置MipMap的等级,参考笔记中MipMap资料
38 */
39 Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
40 Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
41
42 /* 现在,完成了第一阶段-准备阶段,现在进入启动阶段-创建场景:
43 * 1. 创建场景管理器
44 * 2. 创建相机
45 * 3. 创建观察点
46 */
47 Ogre::SceneManager *mSceneMgr;
48 mSceneMgr = mRoot->createSceneManager("DefaultSceneManager");
49 Ogre::Camera *mCamera;
50 mCamera = mSceneMgr->createCamera("DefaultCamera");
51 mCamera->setPosition(Ogre::Vector3(0,0,80));
52 mCamera->lookAt(Ogre::Vector3(0,0,-300)); // why -300 ,not 0
53 mCamera->setNearClipDistance(5); // 如果相机与物体距离小于5个距离单元,就只能看到物体内部了。
54 Ogre::Viewport *mViewport;
55 /* 这里猜测一下设计上的思路:
56 * 相机、灯光等都被看做特殊的实体,所以应该由资源管理器管理;
57 * 而观察点并不是一个实体,比如照相的时候别人让你站在某个位置照相,那个位置是属于空间中的点;
58 * 在这里那个空间就是渲染窗口,所以观察点应该由渲染窗口添加和管理;
59 * 正是因为将相机也当做实体资源,而资源在OGRE中使用非常灵活,你可以多创建几个相机,摆放好位置,
60 * 当你想用哪个相机时直接指定那个相机的位置是观察点即可;
61 * 进一步思考:
62 * 如果我想将一个渲染窗口分开在不同位置分别观察某个场景,那么实现上应该再创建一个观察点,然后
63 * 每个观察点单独指定相机。
64 */
65 mViewport = mWindow->addViewport(mCamera);
66 /* 疑问:
67 * 为什么需要设置观察点的背景颜色呢?难道不是所有的颜色都是由灯光指定?
68 * 背景颜色的指定是不是相当于指定白天黑夜黄昏?
69 */
70 mViewport->setBackgroundColor(Ogre::ColourValue(0,0,0));
71 /* 疑问:
72 * 设置相机的纵横比,如果参数偏大,会是什么效果?
73 * 偏小呢?
74 */
75 mCamera->setAspectRatio(Ogre::Real(mViewport->getActualWidth()) / Ogre::Real(mViewport->getActualHeight()));
76
77 /* 现在,启动工作也完成了,只需要载入实体就可以看到丰富的场景效果了 */
78 /* 因为已经初始化过资源文件了,我们只需要直接指定资源名称就可以使用了 */
79 Ogre::Entity *ogreHead;
80 ogreHead = mSceneManager->createEntity("Head", "ogrehead.mesh");
81 Ogre::SceneNode *headNode;
82 /* OGRE中实体的名称都必须是惟一的,你可以通过两种方式访问到这些实体:
83 * 1. 实体句柄,其实是一个指针,比如headNode
84 * 2. 实体名称,比如headNode指向的场景节点的名称也是headNode
85 */
86 headNode = mSceneManager->getRootSeneNode()->createChildSceneNode("headNode");
87 headNode->setPosition(Ogre::Vector3(0,0,0));
88 headNode->attachObject(ogreHead);
89 /* 疑问:
90 * AmbientLight是环境光,Viewport背景光又是什么呢?
91 */
92 mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5,0.5,0.5));
93 Ogre::Light *light;
94 light = mSceneMgr->createLight("MainLight");
95 light->setPosition(Ogre::Vector3(20,100, 50));
96
97 /* 你现在可以得到这个场景的效果图了,不过却是一闪而过的;我希望计算机保持这个场景,
98 * 并且当我与之交互时,能够改变这个场景中的某个部分;那么你就需要一个循环等待的过程;
99 * 这个过程在OGRE中叫做渲染循环:
100 * OGRE提供了多种方式让你根据每个循环的特点选取其中一个,最简单的是:
101 * Ogre::Root::RenderOneFrame()
102 * 下面这段代码实现的功能是,一直等待用户关闭窗口,或者渲染一帧画面的时候出错了。
103 */
104 while(true)
105 {
106 Ogre::WindowEventUtilities::messagePump();
107 if(mWindow->isClosed())
108 {
109 return false;
110 }
111
112 if(!mRoot->RenderOneFrame())
113 {
114 return false;
115 }
116 }
117
118 /* OIS(Object Oriented Input System )是OGRE推荐使用的用户输入插件;
119 * 如果在进入渲染循环之前设置了OIS,那么我们的鼠标和键盘就能够在场景中得到响应;
120 * 这相当于为OGRE添加了一个中断系统
121 */
122 Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
123 OIS::ParamList pl;
124 size_t WindowHnd = 0;
125 std::ostringstream windowHndStr;
126
127 mWindow->getCustomAttribute("WINDOW", &windowHnd);
128 windowHndStr << windowHnd;
129 pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
130
131 mInputManager = OIS::InputManager::createInputSystem(pl);
132
133 mKeyboard = static_cast<OIS::Keyboard *>(mInputManager->createInputObject(OIS::OISKeyboard, false));
134 mMouse = static_cast<OIS::Keyboard *>(mInputManager->createInputObject(OIS::OISKeyboard, false));
135
136 /* 我们不仅要让渲染循环能够响应键盘上对场景的操作,还要在将渲染窗口关闭的时候同时停止OIS模块的运行,
137 * 之所以这么做是因为OIS是独立于OGRE的单独模块,写好后,在主程序中将其注册为窗口监听函数。
138 */
139 void Game::windowClosed(Ogre::RenderWindow *rw)
140 {
141 if(rw == mWindow)
142 {
143 if(mInputManager)
144 {
145 mInputManager->destroyInputObject(mKeyboard);
146 mInputManager->destroyInputObject(mMouse);
147
148 OIS::InputManager::destroyInputSystem(mInputManager);
149 mInputManager = 0;
150 }
151 }
152 }
153
154 Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);
155
156 /* 有了OIS作为内嵌的中断系统,我们可以编写帧监听函数,这些函数实际上相当于中断处理程序
157 * 首先要在Game类的保护区申明如下定义:
158 * virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);
159 * 在保护区表明该功能不能被继承,然而为何在保护区?
160 */
161 bool Game::frameRenderingQueued(const Ogre::FrameEvent &evt)
162 {
163 if(mWindow->isClosed())
164 {
165 return false;
166 }
167 mKeyboard->capture();
168 mMouse->capture();
169
170 if(mKeyboard->isKeyDown(OIS::KC_ESCAPE))
171 {
172 return false;
173 }
174
175 return true;
176 }
177 /* 中断程序写好后,需要注册才能使用 */
178 mRoot->addFrameListener(this);
179 mRoot->startRendering();
180
181
182