更进一步
在这篇文章中,我们将把CEGUI集成到应用程序中。
Rendering The UI
CEGUI 将它的 UI elements 画成四方形的Mesh形式画到"screen
space"中. CEGUI 通过"OgreGUIRenderer"与Ogre进行交互。
CEGUI Data Files
CEGUI中的文件有如下几个:
- Scheme. Definition of the different UI elements that are valid in a
particular "scheme", for example buttons, listboxes, and so on.
Found in .scheme files.
- Look-And-Feel. Definition of the way that each UI element is presented on
the display, including its behaviors and the textures used to render it.
Found in .looknfeel files.
- Layout. Defines the position, size, parenting hierarchy and other
properties used to display actual UI elements in a single unit: the UI
"sheet". Found in .layout files.
- Imageset. Defines the textures used in a scheme, and the UV coordinates
that are actually mapped to UI element quads on your screen. Found in
.imageset files.
- Font. Should be obvious; CEGUI needs to know where to find the
fonts you intend to use for your text, including the glyph definitions and
the font texture to use. Found in .font files.
In the gui.zip resource data file
accompanying the source for this article, you will find many examples of all of
these types of files. Look through each type of file and see what they contain
-- they are all just text XML files. This article uses the
"TaharezLookSkin" scheme.
Falagard Skinning System
There is also another part of CEGUI that works behind the
scenes, but starting with CEGUI 0.5.x (the version used in this article), is
core to its operation. The "Falagard" skinning system was devised as
a way to remove the need to create a separate code module (DLL) that was used
actually to assemble and render each different scheme and look-and-feel. As you
might expect (if you are a regular in the Ogre forums) the person (at least
mostly) responsible for its creation was Falagard (unless my information is
incorrect, of course). This method of UI skinning is a generalized, data-driven
way to render the UI elements without having to author special code to do it.
It relies on all of that data found in the look-and-feel and scheme files for
its operation -- verbosity of data is one of the prices you pay for
flexibility. ;)
先介绍到这里,下面让我们看一下代码。在这个版本中,原来的初始版本将显示我们这里创建的layout.
And Then, Now The Code
对于添加CEGUI需要的修改,会指出。首先在main.cpp添加附加的头文件
// needed to be able to create the CEGUI renderer interface
#include "OgreCEGUIRenderer.h"
// CEGUI includes
#include "CEGUISystem.h"
#include "CEGUIInputEvent.h"
#include "CEGUIWindow.h"
#include "CEGUIWindowManager.h"
#include "CEGUISchemeManager.h"
#include "CEGUIFontManager.h"
#include "elements/CEGUIFrameWindow.h"
Initializing CEGUI
main.cpp
// with a scene manager and window, we can create a the GUI renderer
CEGUI::OgreCEGUIRenderer* pGUIRenderer = new CEGUI::OgreCEGUIRenderer(
window, // the render window created earlier; CEGUI renders to this
Ogre::RENDER_QUEUE_OVERLAY, // CEGUI should render in this render queue
false, // put everything in the above render queue first, not last
3000, // this is actually unnecessary now in CEGUI -- max quads for the UI
sceneMgr // use this scene manager to manage the UI
);
// create the root CEGUI class
CEGUI::System* pSystem = new CEGUI::System(pGUIRenderer);
// tell us a lot about what is going on (see CEGUI.log in the working directory)
CEGUI::Logger::getSingleton().setLoggingLevel(CEGUI::Informative);
// use this CEGUI scheme definition (see CEGUI docs for more)
CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLookSkin.scheme", (CEGUI::utf8*)"GUI");
// show the CEGUI mouse cursor (defined in the look-n-feel)
pSystem->setDefaultMouseCursor((CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MouseArrow");
// use this font for text in the UI
CEGUI::FontManager::getSingleton().createFont("Tahoma-8.font", (CEGUI::utf8*)"GUI");
pSystem->setDefaultFont((CEGUI::utf8*)"Tahoma-8");
// load a layout from the XML layout file (you'll find this in resources/gui.zip), and
// put it in the GUI resource group
CEGUI::Window* pLayout = CEGUI::WindowManager::getSingleton().loadWindowLayout("katana.layout", "", "GUI");
// you need to tell CEGUI which layout to display. You can call this at any time to change the layout to
// another loaded layout (i.e. moving from screen to screen or to load your HUD layout). Note that this takes
// a CEGUI::Window instance -- you can use anything (any widget) that serves as a root window.
pSystem->setGUISheet(pLayout);
Input Support For
CEGUI
需要修改 InputHandler类以处理一个新增的参数:一个指向main.cpp中创建的CEGUI::System的指针:
input.cpp
// MouseListener
bool InputHandler::mouseMoved(const OIS::MouseEvent &evt) {
m_pSystem->injectMouseWheelChange(evt.state.Z.rel);
return m_pSystem->injectMouseMove(evt.state.X.rel, evt.state.Y.rel);
}
bool InputHandler::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) {
CEGUI::MouseButton button = CEGUI::NoButton;
if (btn == OIS::MB_Left)
button = CEGUI::LeftButton;
if (btn == OIS::MB_Middle)
button = CEGUI::MiddleButton;
if (btn == OIS::MB_Right)
button = CEGUI::RightButton;
return m_pSystem->injectMouseButtonDown(button);
}
bool InputHandler::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) {
CEGUI::MouseButton button = CEGUI::NoButton;
if (btn == OIS::MB_Left)
button = CEGUI::LeftButton;
if (btn == OIS::MB_Middle)
button = CEGUI::MiddleButton;
if (btn == OIS::MB_Right)
button = CEGUI::RightButton;
return m_pSystem->injectMouseButtonUp(button);
}
// KeyListener
bool InputHandler::keyPressed(const OIS::KeyEvent &evt) {
unsigned int ch = evt.text;
m_pSystem->injectKeyDown(evt.key);
return m_pSystem->injectChar(ch);
}
bool InputHandler::keyReleased(const OIS::KeyEvent &evt) {
if (evt.key == OIS::KC_ESCAPE)
m_simulation->requestStateChange(SHUTDOWN);
return m_pSystem->injectKeyUp(evt.key);
}
很显然的,输入系统通过inject…等命令,将自己挂进CEGUI中.
main.cpp
// since the input handler deals with pushing input to CEGUI, we need to give it a pointer
// to the CEGUI System instance to use
InputHandler *handler = new InputHandler(pSystem, sim, hWnd);
// put us into our "main menu" state
sim->requestStateChange(GUI);
同时,需要将状态转成GUI,如前面所述。在一个正常的应用程序中,你通常是先进入“主菜单”,而不是直接进入游戏。你还需要建立一个类来处理UI的动作,为简单起见,我们在main.cpp来处理:
// make an instance of our GUI sheet handler class
MainMenuDlg* pDlg = new MainMenuDlg(pSystem, pLayout, sim);
其定义见文件MainMenuDlg.h and .cpp:
MainMenuDlg.h
#pragma once
#include "CEGUIWindow.h"
namespace CEGUI
{
class System;
class Window;
}
class Simulation;
class MainMenuDlg
{
public:
MainMenuDlg(CEGUI::System* pSystem, CEGUI::Window* pSheet, Simulation* pSimulation);
~MainMenuDlg();
// CEGUI event handlers. You can name these whatever you like, so long as they have the proper
// signature: bool <method name>(const CEGUI::EventArgs &args)
bool Quit_OnClick(const CEGUI::EventArgs &args);
bool Options_OnClick(const CEGUI::EventArgs &args);
bool Launch_OnClick(const CEGUI::EventArgs &args);
private:
CEGUI::System* m_pSystem; // pointer to the CEGUI System instance
CEGUI::Window* m_pWindow; // pointer to the layout sheet window
Simulation* m_pSimulation; // pointer to the Simulation controller
};
MainMenuDlg.cpp
#include "MainMenuDlg.h"
#include "Simulation.h"
#include "CEGUISystem.h"
#include "CEGUIWindow.h"
#include "CEGUIWindowManager.h"
#include "elements/CEGUIPushButton.h"
MainMenuDlg::MainMenuDlg(CEGUI::System *pSystem, CEGUI::Window *pSheet, Simulation *pSimulation)
{
m_pSystem = pSystem;
m_pWindow = pSheet;
m_pSimulation = pSimulation;
// hook up the event handlers to the window elements
CEGUI::PushButton* pQuitButton = (CEGUI::PushButton *)CEGUI::WindowManager::getSingleton().getWindow("cmdQuit");
pQuitButton->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&MainMenuDlg::Quit_OnClick, this));
CEGUI::PushButton* pOptionsButton = (CEGUI::PushButton *)CEGUI::WindowManager::getSingleton().getWindow("cmdOptions");
pOptionsButton->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&MainMenuDlg::Options_OnClick, this));
CEGUI::PushButton* pLaunchButton = (CEGUI::PushButton *)CEGUI::WindowManager::getSingleton().getWindow("cmdInstantAction");
pLaunchButton->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&MainMenuDlg::Launch_OnClick, this));
}
MainMenuDlg::~MainMenuDlg()
{
}
bool MainMenuDlg::Quit_OnClick(const CEGUI::EventArgs &args)
{
m_pSimulation->requestStateChange(SHUTDOWN);
return true;
}
bool MainMenuDlg::Launch_OnClick(const CEGUI::EventArgs &args)
{
return true;
}
bool MainMenuDlg::Options_OnClick(const CEGUI::EventArgs &args)
{
return true;
}
两个主要的事情是 (a)
action handler methods 如何挂接 CEGUI events, and (b) “Quit”按钮告诉程序状态转换到Shutdown.
Conclusion
Enjoy!
Link:
OIS: http://sourceforge.net/projects/wgois