Ogre三维框架基础篇(六)

准备CEGUI

没有配置好CEGUI可以回到上一篇文章中重新配置。配置成功后将TutorialApplication初始化。

TutorialApplication.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "BaseApplication.h"
#include <CEGUI/CEGUI.h>
#include <CEGUI/RendererModules/Ogre/Renderer.h> //from 0.8 it's just Ogre/Renderer.h

class TutorialApplication : public BaseApplication
{
public:
TutorialApplication(void);
virtual ~TutorialApplication(void);

protected:
CEGUI::OgreRenderer* mRenderer;
virtual void createScene(void);
virtual void createFrameListener(void);

// Ogre::FrameListener
virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);

// OIS::KeyListener
virtual bool keyPressed( const OIS::KeyEvent &arg );
virtual bool keyReleased( const OIS::KeyEvent &arg );
// OIS::MouseListener
virtual bool mouseMoved( const OIS::MouseEvent &arg );
virtual bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id );
virtual bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id );

bool quit(const CEGUI::EventArgs &e);
};

TutorialApplication.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include "TutorialApplication.h"

//-------------------------------------------------------------------------------------
TutorialApplication::TutorialApplication(void)
{
}
//-------------------------------------------------------------------------------------
TutorialApplication::~TutorialApplication(void)
{
}

//-------------------------------------------------------------------------------------
void TutorialApplication::createScene(void)
{

}

void TutorialApplication::createFrameListener(void)
{

}
//-------------------------------------------------------------------------------------
bool TutorialApplication::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
return true;
}
//-------------------------------------------------------------------------------------
bool TutorialApplication::keyPressed( const OIS::KeyEvent &arg )
{
return true;
}
//-------------------------------------------------------------------------------------
bool TutorialApplication::keyReleased( const OIS::KeyEvent &arg )
{
return true;
}


//-------------------------------------------------------------------------------------
bool TutorialApplication::mouseMoved( const OIS::MouseEvent &arg )
{
return true;
}
//-------------------------------------------------------------------------------------
bool TutorialApplication::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
return true;
}
//-------------------------------------------------------------------------------------
bool TutorialApplication::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
return true;
}

//-------------------------------------------------------------------------------------
bool TutorialApplication::quit(const CEGUI::EventArgs &e)
{
return true;
}

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char *argv[])
#endif
{
// Create application object
TutorialApplication app;

try {
app.go();
} catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "An exception has occured: " <<
e.getFullDescription().c_str() << std::endl;
#endif
}

return 0;
}

#ifdef __cplusplus
}
#endif

初始化CEGUI

createScene()方法中加入

1
2
3
4
5
6
7
8
9
10
11
12
13
//CEGUI的主要渲染器,bootstrapSystem()方法会初始化CEGUI中重要的几个管理器,如OgreRenderer,System,OgreResourceProvider,OgreImageCodec
mRenderer = &CEGUI::OgreRenderer::bootstrapSystem();
//读取资源文件
CEGUI::ImageManager::setImagesetDefaultResourceGroup("Imagesets");
CEGUI::Font::setDefaultResourceGroup("Fonts");
CEGUI::Scheme::setDefaultResourceGroup("Schemes");
CEGUI::WidgetLookManager::setDefaultResourceGroup("LookNFeel");
CEGUI::WindowManager::setDefaultResourceGroup("Layouts");

//选择UI皮肤
CEGUI::SchemeManager::getSingleton().createFromFile("TaharezLook.scheme");
//设置鼠标
CEGUI::System::getSingleton().getDefaultGUIContext().getMouseCursor().setDefaultImage("TaharezLook/MouseArrow");

移除SDKTrays

通过重写createFrameListener()frameRenderingQueued()移除SDKTrays。(Ogre的logo部分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void TutorialApplication::createFrameListener(void)
{
Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
OIS::ParamList pl;
size_t windowHnd = 0;
std::ostringstream windowHndStr;

mWindow->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr << windowHnd;
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

mInputManager = OIS::InputManager::createInputSystem( pl );

mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, true ));
mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, true ));

mMouse->setEventCallback(this);
mKeyboard->setEventCallback(this);

//Set initial mouse clipping size
windowResized(mWindow);

//Register as a Window listener
Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);

mRoot->addFrameListener(this);
}
//-------------------------------------------------------------------------------------
bool TutorialApplication::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
if(mWindow->isClosed())
return false;

if(mShutDown)
return false;

//Need to capture/update each device
mKeyboard->capture();
mMouse->capture();

//Need to inject timestamps to CEGUI System.
CEGUI::System::getSingleton().injectTimePulse(evt.timeSinceLastFrame);

return true;
}

注入输入事件——键盘和鼠标

CEGUI不会自己处理输入,它不读取鼠标的移动和键盘的输入。相反地,它依赖用户把按键鼠标事件注入到系统,换句话说必须要人为的将其放到事件响应的方法中。CEGUI一般以缓冲模式注入到系统中。

注入键盘响应事件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//-------------------------------------------------------------------------------------
bool TutorialApplication::keyPressed( const OIS::KeyEvent &arg )
{
//UI上下文
CEGUI::GUIContext& context = CEGUI::System::getSingleton().getDefaultGUIContext();
//注入按键按下的事件
context.injectKeyDown((CEGUI::Key::Scan)arg.key);
//注入获取按下Unicode的事件
context.injectChar((CEGUI::Key::Scan)arg.text);
return true;
}
//-------------------------------------------------------------------------------------
bool TutorialApplication::keyReleased( const OIS::KeyEvent &arg )
{
//注入按键松开的事件
CEGUI::System::getSingleton().getDefaultGUIContext().injectKeyUp((CEGUI::Key::Scan)arg.key);
return true;
}

注入鼠标响应事件中

鼠标主要有三个响应类型,左键,中键以及右键,所以添加一个根据OIS反馈鼠标的响应类型的函数,把OIS的按钮ID转换为CEGUI的按钮ID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CEGUI::MouseButton convertButton(OIS::MouseButtonID buttonID)
{
switch (buttonID)
{
case OIS::MB_Left:
return CEGUI::LeftButton;

case OIS::MB_Right:
return CEGUI::RightButton;

case OIS::MB_Middle:
return CEGUI::MiddleButton;

default:
return CEGUI::LeftButton;
}
}

鼠标移动,按下和松开的响应事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//-------------------------------------------------------------------------------------
bool TutorialApplication::mouseMoved( const OIS::MouseEvent &arg )
{
CEGUI::System &sys = CEGUI::System::getSingleton();
//参数分别为x,y的移动距离
sys.getDefaultGUIContext().injectMouseMove(arg.state.X.rel, arg.state.Y.rel);
// 滚轮
if (arg.state.Z.rel)
//滚轮滚过的角度
sys.getDefaultGUIContext().injectMouseWheelChange(arg.state.Z.rel / 120.0f);
return true;
}
//-------------------------------------------------------------------------------------
bool TutorialApplication::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
//注入鼠标按下的事件,参数为鼠标的响应类型
CEGUI::System::getSingleton().getDefaultGUIContext().injectMouseButtonDown(convertButton(id));
return true;
}
//-------------------------------------------------------------------------------------
bool TutorialApplication::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
//注入鼠标松开的事件,参数为鼠标的响应类型
CEGUI::System::getSingleton().getDefaultGUIContext().injectMouseButtonUp(convertButton(id));
return true;
}

窗口、表单、组件(Windows, Sheets, and Widgets)

介绍

CEGUI与其它多数GUI系统有所不同。在CEGUI里,所有能显示出来的东西都是CEGUI::Window类的一个子类,而且一个window可以有任意数量的子window。这样会导致一些奇怪的事情发生。你能在一个按钮里面放置另外一个按钮,虽然实际上不会这么干。我提这些的原因是,当你正寻找放在应用程序里的某个特殊的小部件时,它们都被称作Windows,而且可以通过访问Windows的函数来访问。
CEGUI最常用的用法是,你不必在代码里创建每一个单独的对象。而你可以通过一个像CEGUI Layout Editor这样的编辑器,来为你的程序创建一个GUI布局。根据你的喜好,放置你的窗口、按钮以及其它部件到屏幕上之后,编辑器会把布局保存到一个文本文件里。你就可以之后加载这个布局到GUI sheet里面(它也是CEGUI::Window的一个子类)。
最后,要知道CEGUI包含大量的小部件供你的程序使用。我们在这里不去涉及,所以如果你决定使用CEGUI,最好还是去它们的网站了解更多的信息。

载入表单

在CEGUI里载入一个表单(sheet)是非常容易的事。WindowManager类提供了一个”loadWindowLayout”函数来加载表单,并把它放入CEGUI::Window对象。然后你可以通过CEGUI::System::setGUISheet来显示它。

1
2
3
// 本次示例程序中不需要添加
CEGUI::Window *guiRoot = CEGUI::WindowManager::getSingleton().loadLayoutFromFile("TextDemo.layout");
CEGUI::System::getSingleton().getDefaultGUIContext().setRootWindow(guiRoot);

手动创建部件

一个可以响应的退出按钮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//创建CEGUI窗口
//-----------------------------------------------
//获取窗口管理器
CEGUI::WindowManager &wmgr = CEGUI::WindowManager::getSingleton();
//创建一个默认窗口(DefaultWindow),名字为"CEGUIDemo/Sheet"
CEGUI::Window *sheet = wmgr.createWindow("DefaultWindow", "CEGUIDemo/Sheet");
//创建按钮(样式在TaharezLook文件的Button节点中),名称为"CEGUIDemo/QuitButton"
CEGUI::Window *quit = wmgr.createWindow("TaharezLook/Button", "CEGUIDemo/QuitButton");
//设置文字
quit->setText("Quit");
//设置大小
quit->setSize(CEGUI::USize(CEGUI::UDim(0.15, 0), CEGUI::UDim(0.05, 0)));
//为按钮绑定事件,参数分别为:点击响应,响应的事件
quit->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&TutorialApplication::quit, this));
//将按钮放置在默认窗口上
sheet->addChild(quit);
//设置默认窗口为全局窗口
CEGUI::System::getSingleton().getDefaultGUIContext().setRootWindow(sheet);

quit()方法

1
2
3
4
5
6
7
//-------------------------------------------------------------------------------------
bool TutorialApplication::quit(const CEGUI::EventArgs &e)
{
//关闭窗口
mShutDown = true;
return true;
}

渲染到纹理

用CEGUI创建一个纹理窗口的渲染器。这可以让我们能够创建一个可以直接渲染到CEGUI部件的视口。

创建场景

首先创建一个能让我们看见的场景(createScene()方法中)

1
2
3
4
5
6
//创建模型
mSceneMgr->setAmbientLight(Ogre::ColourValue(1, 1, 1));
mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);
Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh");
Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Ogre::Vector3(0, 0, -300));
headNode->attachObject(ogreHead);

创建纹理

RenderSystem对象提供了一种渲染到纹理的功能。我们用RenderSystem::createRenderTexture函数创建一个纹理。在这个程序里,我们创建一个512 x 512的纹理

1
2
3
4
5
6
7
8
9
10
Ogre::TexturePtr tex = mRoot->getTextureManager()->createManual(
"RTT",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D,
512,
512,
0,
Ogre::PF_R8G8B8,
Ogre::TU_RENDERTARGET);
Ogre::RenderTexture *rtex = tex->getBuffer()->getRenderTarget();

创建视口

接下来创建一个摄像机和一个视口,以便察看创建的场景。注意,要关闭Overlays,否则你会看见CEGUI与Ogre在小窗口里面重叠在一起。

1
2
3
4
5
6
7
8
9
10
   Ogre::Camera *cam = mSceneMgr->createCamera("RTTCam");
cam->setPosition(100, -100, -400);
cam->lookAt(0, 0, -300);
//在材质上添加一个视口
Ogre::Viewport *v = rtex->addViewport(cam);
//关掉透视
v->setOverlaysEnabled(false);
v->setClearEveryFrame(true);
v->setBackgroundColour(Ogre::ColourValue::Black);
CEGUI::Texture &guiTex = mRenderer->createTexture("textname", tex);

创建图像部件

1
2
3
4
5
6
7
8
9
10
11
//CEGUI的图像
//图像显示区域的大小
const CEGUI::Rectf rect(CEGUI::Vector2f(0.0f, 0.0f), guiTex.getOriginalDataSize());
//创建图像部件
CEGUI::BasicImage* image = (CEGUI::BasicImage*)( &CEGUI::ImageManager::getSingleton().create("BasicImage", "RTTImage"));
//设置部件的材质
image->setTexture(&guiTex);
//设置区域
image->setArea(rect);
//设置缩放
image->setAutoScaled(CEGUI::ASM_Both);

显示图像

1
2
3
4
5
6
7
8
9
10
11
//添加窗口显示图像
CEGUI::Window *si = CEGUI::WindowManager::getSingleton().createWindow("TaharezLook/StaticImage", "RTTWindow");
//si->setSize(CEGUI::UVector2(CEGUI::UDim(0.5f, 0),
si->setSize(CEGUI::USize(CEGUI::UDim(0.5f, 0),
CEGUI::UDim(0.4f, 0)));
si->setPosition(CEGUI::UVector2(CEGUI::UDim(0.5f, 0),
CEGUI::UDim(0.0f, 0)));
//设置要显示的图像
si->setProperty("Image", "RTTImage");
//将窗口添加到表单中
sheet->addChild(si);

运行结果

Ogre+CEGUI

结语

CEGUI具有强大的功能,同时也能够简单上手,给我们开发Ogre提供了很大的便利。


参考文章:Ogre基础教程7

文章作者: cpacm
文章链接: http://www.cpacm.net/2015/02/17/Ogre三维框架基础篇(六)/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 cpacm
打赏
  • 微信
  • 支付宝

评论