/*
这个例子显示了如何载入引擎一个Quake3地图模型,新建一个场景节点来优化渲染速度以及如何创建一个用户视角的摄像机。
我们像前一个例子halloworld那样开始。
包含鬼火的头文件,并且和一些附加文件以便于我们使用控制台来询问用户要使用哪一中驱动类型。
*/
#include <irrlicht.h>
#include <iostream>
/*
就像在helloworld例子中提到的那样,在鬼火引擎中,每个事物都可以在命名空间'irr'下找到。
为了拜托irr::这个前缀,我们告诉编译器我们要从现在开始使用这个命名空间,并且不必写明'irr::'。
还有5个子命名空间分别是'core'、 'scene'、 'video'、'io' 和 'gui'。
和helloworld例子中不同的是,我们不使用'using namespace',因为这样才能看到所使用的变量在那个命名空间被找到。
可是如果你喜欢,我们也可以像之前的例子那样包含命名空间。
代码就想你所想的那样。
*/
using namespace irr;
/*
在这里我们为了要使用Irrlicht.DLL文件,我们同样需要链接到Irrlicht.lib。
我们可以用项目设置来完成这个工作,但这里我们为了简单使用表示链接库。
*/
#pragma comment(lib, "Irrlicht.lib")
/*
好了,我们可以开始了。
同样我们使用main()函数来开始,不使用winmain(),因为这样可以写的比较短。
*/
int main()
{
/*
就像helloworld例子那样,我们用createDebice()来建立一个鬼火设备。
区别在于我们要求用户去选择他们要用什么样的硬件加速。
软件设备在载入大型Quake3地图时太过缓慢,可是只是为了有趣,我们也给出这样的选择。
*/
// 询问用户所希望的设备
video::E_DRIVER_TYPE driverType;
printf("Please select the driver you want for this example:\n"\
" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
" (d) Software Renderer\n (e) Burning's Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");
char i;
std::cin >> i;
switch(i)
{
case 'a': driverType = video::EDT_DIRECT3D9;break;
case 'b': driverType = video::EDT_DIRECT3D8;break;
case 'c': driverType = video::EDT_OPENGL; break;
case 'd': driverType = video::EDT_SOFTWARE; break;
case 'e': driverType = video::EDT_BURNINGSVIDEO;break;
case 'f': driverType = video::EDT_NULL; break;
default: return 1;
}
// 创建新设备,若创建失败则退出。
IrrlichtDevice *device =
createDevice(driverType, core::dimension2d<s32>(640, 480));
if (device == 0)
return 1; //不能创建所选择的设备
/*
或的视频驱动和场景管理器的指针,以便于我们下面的程序写的简短些。
*/
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
/*
为了显示Quake3地图,我们首先需要载入它。
Quake3地图位于.pk3文件中,相对于zip文件不包含任何其他东西。
所以我们将.pk3文件加入我们的文件系统中。
加载后,我们可以从直接存储在硬盘上的文件档案中读取它。
*/
device->getFileSystem()->addZipFileArchive("http://www.cnblogs.com/media/map-20kdm2.pk3");
/*
getFileSystem()
纯虚函数
返回文件系统
addZipFileArchive()
纯虚函数
参数解释:
1 文件名:要加入文件系统的档案的文件名。
2 可忽视情况:若设为真,在档案中的文件可以在拼写不全((⊙_⊙?)writing all letters in the right case)的情况下进行读写。(默认为true)
3 可忽视路径:若设为真,被加入的文件档案可以在不拼写全部路径的情况下进行读写。(默认为true)
*/
/*
现在我们可以调用getMesh()来载入网格。
我们需要获得一个动画网格的指针。
就像你知道的,Quake3地图不是真正的动画,他们只是一团静态的几何图形并附上了材质。
因此,这个动画网格只有一帧,所以我们获取这个所谓动画的第一帧,也就是我们的0,
并用addOctTreeSceneNode()为他创建一个八元树场景节点。
八元树可以实现较优化的场景,只绘制目前可是的部分。
可以用AnimatedMeshSceneNode来替换八元树,它总是不加选择的绘制所有几何网格。
你可以自己尝试用addAnimatedMeshSceneNode来替换addOctTreeSceneNode,然后比较一下视频驱动绘制出的基元。
(getPrimitiveCountDrawed()函数在IVideoDriver类中)
这里要说明:用八元树来优化场景之作用于有大量几何形状的大型场景。
*/
scene::IAnimatedMesh* mesh = smgr->getMesh("20kdm2.bsp");
scene::ISceneNode* node = 0;
if (mesh)
node = smgr->addOctTreeSceneNode(mesh->getMesh(0), 0, -1, 128);
/*
纯虚函数
参数解释:
1 网格:网格中包含了八元树中所要创建的所有图形。
2 父节点:八元树的父节点。
3 id号:节点的id号。可以用来识别节点。
4 细分等级:指定最小多边形所含有的八元树节点。
如果节点含有的多变型的个数少于该值,侧不再细分。
5 网格加载失败时加载:如果参数1为0则加载此场景节点。
*/
/*
因为坐标与模型并不匹配,所以我们可以把坐标进行一些转换。
*/
if (node)
node->setPosition(core::vector3df(-1300,-144,-1249));
/*
现在我们只需要一个摄像机去观察这个Quake3地图。
并且我们希望创建一个用户可控制的摄像机。
在鬼火引擎中有很多不同效用的摄像机。
例如:maya摄像机就是模仿maya中的摄像机,可以用鼠标左键进行算转,中间进行缩放,右键进行移动。
这种摄像机可以用函数addCameraSceneNodeMaya()创建。
但为了简便期间,我们这里希望创建一个与第一人称射击游戏中类似的摄像机(FPS)。
*/
smgr->addCameraSceneNodeFPS();
/*
光标在这里没有作用,所以我们隐藏它。
*/
device->getCursorControl()->setVisible(false);
/*
我们已经做好了万全的准备~冲啊……可以绘制了。
我们还需要指定我们当前每秒帧数然后绘制出基元显示出来。
'if (device->isWindowActive())'这行程序是可选的
,为了防止任务切换到其他程序的时候显示出光标的位置,在这里我们加上这句。
(?切换活动窗口而导致引擎渲染桢速率显示不正确)
*/
int lastFPS = -1;
while(device->run())
if (device->isWindowActive())
{
driver->beginScene(true, true, video::SColor(0,200,200,200));
smgr->drawAll();
driver->endScene();
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Irrlicht Engine - Quake 3 Map example [";
str += driver->getName();
str += "] FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
/*
不能写成while()
{
if(!device->isWindowActive())break;
balabala......
}
这样切换窗口就会导致关闭!
貌似可以等价于while()
{
if(!device->isWindowActive())continue;
balabala......
}
*/
/*
最后,删除设备~
*/
device->drop();
return 0;
}