当前位置: 首页 > news >正文

基础教程六(CEGUI和OGRE)

必备知识

本教程是在假设你已经拥有c++编程基础并能够成功建立和编译Ogre程序(如果你设置程序方面还存在问题,请参阅SettingUpAnApplication来获取详细信息)。 本教程建立在之前的初学者教程的基础上,并且假设你已经学习了它们。

[编辑]工程设置

下面的适用于下载源代码的用户:

    添加include文件夹: $(OGRE_HOME)/Dependencies/include,
$(OGRE_HOME)/Dependencies/include/CEGUI
添加lib库路径:     $(OGRE_HOME)/OgreMain/Dependencies/Lib/Debug

确信已经链接 'CEGUIBase' 和 'OgreGUIRender' 库,也就是说将下面一行添加进你的Makefile文件或g++命令行:

    -L/usr/local/lib -lCEGUIBase -lCEGUIOgreRenderer

下面的适用于SDK的用户:

   添加include文件夹:$(OGRE_HOME)/include/CEGUI

确信已经在debug配置的中添加 'CEGUIBase_d.lib' 和 'OgreGUIRenderer_d.lib' 库( 'CEGUIBase.lib' 和 'OgreGUIRenderer.lib' 在release配置中)。 在Visual C++中添加依赖,依次点击:项目 -> 属性 -> 配置属性 -> 链接。

CEGUIRender源程序现在是从Ogre CVS下载代码中的一部分,一个示例工程,因此你必须将包含OgreGUIRenderer头文件和lib文件的文件夹路径添加到属性配置中。

另外,下面两个目录是必需的。尽管你在你的安装路径中的文件夹找不到。将其作为约定它就会起作用:

    添加Include文件夹: $(OGRE_HOME)/Samples/Common/CEGUIRenderer/include
    添加 Lib 路径:      $(OGRE_HOME)/Samples/Common/CEGUIRenderer/lib

[编辑]介绍

Crazy Eddies GUI系统是一个为不具备或缺乏用户界面制作功能的图形API或引擎提供免费用户界面支持的开源的库。这个使用c++编写的库是针对那些想制作优秀的游戏却又没有GUI(图形用户界面)子系统的专业游戏开发者。

[编辑]开始

首先,你需要架构(skeleton)代码来创建具有CEGUI组件的Ogre程序。 注意:如果你使用,你必须在之前添加#define NOMINMAX。

   //mem probs without this next one
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "OgreCEGUIRenderer.h"
#include "OgreCEGUIResourceProvider.h"
//regular mem handler
#include  
#include "ExampleApplication.h"
  class GuiFrameListener : public ExampleFrameListener
{ 
private:
CEGUI::Renderer* mGUIRenderer;
public:
GuiFrameListener(RenderWindow* win, Camera* cam, CEGUI::Renderer* renderer)  : ExampleFrameListener(win, cam, false, false),
mGUIRenderer(renderer)
{
}
};

仅仅是一个不做任何动作的空帧监听器,但在你按下“Esc”之前会一直循环。

  class TutorialApplication : public ExampleApplication
{
private:
CEGUI::OgreCEGUIRenderer* mGUIRenderer;
CEGUI::System* mGUISystem;
CEGUI::Window* mEditorGuiSheet;

这些是包含所有CEGUI数据的数据成员。我喜欢显式的调用CEGUI成员,一但你开始对Ogre成员添加调用,这将会明确的说明它们是来自CEGUI。

  public:
TutorialApplication()  : mGUIRenderer(0),
mGUISystem(0),
mEditorGuiSheet(0)
{
}
~TutorialApplication() 
{
if(mEditorGuiSheet)
{
CEGUI::WindowManager::getSingleton().destroyWindow(mEditorGuiSheet);
}
if(mGUISystem)
{
delete mGUISystem;
mGUISystem = 0;
}
if(mGUIRenderer)
{
delete mGUIRenderer;
mGUIRenderer = 0;
}
}

下面是你可以设置任意Ogre场景的地方,使用你在前五章教程学到的方法。在这个Ogre场景中,你仍要为其添加一个独立的相机(camera)和视窗(viewport)。

  protected:
void createScene(void)
{
// Set ambient light
mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

下面是创建CEGUI日志的地方,一般都设置为Informative模式的。其具有四种模式:Standard, Errors, Informative 和 Insane。

          // Set up GUI system
mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow,  
Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mSceneMgr);
mGUISystem = new CEGUI::System(mGUIRenderer);   
CEGUI::Logger::getSingleton().setLoggingLevel(CEGUI::Informative);

创建一个新的CEGUI系统,使用“TaharezLook”来设置图(sheme)与鼠标指针,使用“BlueHighway-12”来设置字体。

           CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLookSkin.scheme");
mGUISystem->setDefaultMouseCursor((CEGUI::utf8*)"TaharezLook",(CEGUI::utf8*)"MouseArrow");
CEGUI::MouseCursor::getSingleton().setImage("TaharezLook","MouseMoveCursor");
mGUISystem->setDefaultFont((CEGUI::utf8*)"BlueHighway-12");
mEditorGuiSheet=CEGUI::WindowManager::getSingleton().createWindow((CEGUI::utf8*)"DefaultWindow",
(CEGUI::utf8*)"Sheet");  
mGUISystem->setGUISheet(mEditorGuiSheet);
}

调用自定义的帧监听器,这样我们可以在需要时访问“mGUIRender”。

  void createFrameListener(void)
{
mFrameListener = new GuiFrameListener(mWindow, mCamera, mGUIRenderer);
mRoot->addFrameListener(mFrameListener);
}
};

下面是主函数也是程序的主循环,在本教程并不需要你修改这段代码。

   #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
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( 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
fprintf(stderr, "An exception has occured: %s/n",e.getFullDescription().c_str());
#endif
}
return 0;
}

完成后,编译程序能得到一个空的窗口。请关掉程序,继续我们的学习。 注意:如果实际操作中出现问题,你可以在应用程序所在文件夹中找到“CEGUI.log”文件分析查找错误

[编辑]CEGUI是如何工作的

本质上CEGUI是通过向窗口添加第二个场景,这个场景是在Ogre的基本渲染队列完成后才渲染的。这个场景仅仅是由一系列3D矩形对象组成的。(也就是两个多边形沿着其边压制到一起)。渲染矩阵是为消除矩形的突兀与歪斜而根据他们的位置建立的。使用这些矩形,添加材质和响应就构成了用户界面(GUI)。一般情况下这是很不错的,因为一个3D的用户界面将会自动的缩放其元素来适应屏幕,并且使用硬件材质过滤。其将会比C++标准的2D用户界面更加快速和漂亮。

  “So in one sentence: CEGUI renders a 2D gui using 3D methods and hardware so you don't have to.”——zeroskill

[编辑]添加退出按钮

首先,我们需要为应用程序添加下面的头文件。本例中是“Push Button”

   #include 

我们要在场景底部添加退出按钮。

   CEGUI::PushButton* quitButton = (CEGUI::PushButton*)CEGUI::WindowManager::getSingleton().createWindow
("TaharezLook/Button", (CEGUI::utf8*)"Quit");
mEditorGuiSheet->addChildWindow(quitButton);
quitButton->setPosition(CEGUI::Point(0.35f, 0.45f));
quitButton->setSize(CEGUI::Size(0.3f, 0.1f));
quitButton->setText("Quit");

完成后执行程序,一个漂亮的按钮将会出现在屏幕中。但请注意,程序此时仍然不做任何事情,因为我们并没有为其添加响应时间。

如果你编译时遇到了setPosition()和setSize()的调用错误: 'CEGUI::Window::setPosition' : cannot convert parameter 1 from 'CEGUI::Vector2' to 'const CEGUI::UVector2 &'

将setPosition()和setSize()所在行分别用下面的代码替换:

 quitButton->setPosition(CEGUI::UVector2(cegui_reldim(0.35f), cegui_reldim( 0.45f)) );
quitButton->setSize(CEGUI::UVector2(cegui_reldim(0.35f), cegui_reldim( 0.1f)) );

[编辑]响应事件

将下面函数添加到TutorialApplication的public:中

  void setupEventHandlers(void)
{
CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
wmgr.getWindow((CEGUI::utf8*)"Quit")->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber
(&TutorialApplication::handleQuit, this));
}
bool handleQuit(const CEGUI::EventArgs& e)
{
static_cast(mFrameListener)->requestShutdown();
return true;
}

重写 GuiFrameListener 类来响应键盘和鼠标输入

  class GuiFrameListener : public ExampleFrameListener, public MouseMotionListener, public MouseListener
{
private:
CEGUI::Renderer* mGUIRenderer;
bool mShutdownRequested;
public:
// NB using buffered input
GuiFrameListener(RenderWindow* win, Camera* cam, CEGUI::Renderer* renderer)  : ExampleFrameListener(win, cam, true, true), 
mGUIRenderer(renderer),
mShutdownRequested(false)
{
mEventProcessor->addMouseMotionListener(this);
mEventProcessor->addMouseListener(this);
mEventProcessor->addKeyListener(this);
}
// Tell the frame listener to exit at the end of the next frame
void requestShutdown(void)
{
mShutdownRequested = true;
}
bool frameEnded(const FrameEvent& evt)
{
if (mShutdownRequested)
return false;
else
return ExampleFrameListener::frameEnded(evt);
}
     void mouseMoved (MouseEvent *e)
{
CEGUI::System::getSingleton().injectMouseMove(
e->getRelX() * mGUIRenderer->getWidth(), 
e->getRelY() * mGUIRenderer->getHeight());
e->consume();
}
void mouseDragged (MouseEvent *e) 
{ 
mouseMoved(e);
}
void mousePressed (MouseEvent *e)
{
CEGUI::System::getSingleton().injectMouseButtonDown(
convertOgreButtonToCegui(e->getButtonID()));
e->consume();
}
void mouseReleased (MouseEvent *e)
{
CEGUI::System::getSingleton().injectMouseButtonUp(
convertOgreButtonToCegui(e->getButtonID()));
e->consume();
}
     void mouseClicked(MouseEvent* e) {}
void mouseEntered(MouseEvent* e) {}
void mouseExited(MouseEvent* e) {}
void keyPressed(KeyEvent* e)
{
if(e->getKey() == KC_ESCAPE)
{
mShutdownRequested = true;
e->consume();
return;
}
CEGUI::System::getSingleton().injectKeyDown(e->getKey());
CEGUI::System::getSingleton().injectChar(e->getKeyChar());
e->consume();
}
void keyReleased(KeyEvent* e)
{
CEGUI::System::getSingleton().injectKeyUp(e->getKey());
e->consume();
}
void keyClicked(KeyEvent* e) 
{
// Do nothing
e->consume();
}
};

Ogre 1.4.0

如果你使用的是Ogre 1.4.0 你将会要使用OIS。在Ogre3d中使用OIS的更多细节,请参阅使用OIS并且再看一看基础教程5:

  class GuiFrameListener : public ExampleFrameListener, public OIS::MouseListener, public OIS::KeyListener
{
private:
CEGUI::Renderer* mGUIRenderer;
bool mShutdownRequested;
public:
// NB using buffered input
GuiFrameListener(RenderWindow* win, Camera* cam, CEGUI::Renderer* renderer)  : ExampleFrameListener(win, cam, true, true), 
mGUIRenderer(renderer),
mShutdownRequested(false)
{
mMouse->setEventCallback( this );
mKeyboard->setEventCallback( this );
}
// Tell the frame listener to exit at the end of the next frame
void requestShutdown(void)
{
mShutdownRequested = true;
}
bool frameEnded(const FrameEvent& evt)
{
if (mShutdownRequested)
return false;
else
return ExampleFrameListener::frameEnded(evt);
}
bool mouseMoved( const OIS::MouseEvent &e ) 
{
using namespace OIS;
CEGUI::System::getSingleton().injectMouseMove(e.state.X.rel,e.state.Y.rel);
return true;
}
bool mousePressed (const OIS::MouseEvent &e, OIS::MouseButtonID id)
{
CEGUI::System::getSingleton().injectMouseButtonDown(convertOgreButtonToCegui(id));
return true;
}
bool mouseReleased( const OIS::MouseEvent &e, OIS::MouseButtonID id )
{
CEGUI::System::getSingleton().injectMouseButtonUp(convertOgreButtonToCegui(id));
return true;
}
bool keyPressed( const OIS::KeyEvent &e )
{
if(e.key == OIS::KC_ESCAPE)
{
mShutdownRequested = true;
return true;
}
CEGUI::System::getSingleton().injectKeyDown(e.key);
CEGUI::System::getSingleton().injectChar(e.text);
return true;
}
bool keyReleased( const OIS::KeyEvent &e )
{
CEGUI::System::getSingleton().injectKeyUp(e.key);
return true;
}
};

在include语句后GuiFrameListener声明前添加下面代码

  CEGUI::MouseButton convertOgreButtonToCegui(int buttonID)
{
switch (buttonID)
{
case MouseEvent::BUTTON0_MASK:
return CEGUI::LeftButton;
case MouseEvent::BUTTON1_MASK:
return CEGUI::RightButton;
case MouseEvent::BUTTON2_MASK:
return CEGUI::MiddleButton;
case MouseEvent::BUTTON3_MASK:
return CEGUI::X1Button;
default:
return CEGUI::LeftButton;
}
}

Ogre 1.4.0

  CEGUI::MouseButton convertOgreButtonToCegui(int buttonID)
{
using namespace OIS; 
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;
}
}

将下面语句添加到创建场景方法(createscene)的末尾。

  setupEventHandlers();

现在你可以编译并执行程序了。实现效果是点击按钮后退出。

[编辑]加载设置(Layout)

CEGUI使用XML格式来加载图形用户界面样式设置。复制下面xml代码到记事本,并将其以“Tutoral Gui.xml”命名另存在“/media/gui”文件夹下。

    

Ogre 1.4.0

    

( 补充说明:在复制上面的.xml代码保存时,请手动删除行前的空格.否则会编译出错. editBy自由骑士笃志2008-04-25 )

现在将程序中下列代码段注释掉

  mEditorGuiSheet= CEGUI::WindowManager::getSingleton().createWindow((CEGUI::utf8*)"DefaultWindow", (CEGUI::utf8*)"Sheet"); 
mGUISystem->setGUISheet(mEditorGuiSheet);
CEGUI::PushButton* quitButton = (CEGUI::PushButton*)CEGUI::WindowManager::getSingleton().createWindow
("TaharezLook/Button",  (CEGUI::utf8*)"Quit");
mEditorGuiSheet->addChildWindow(quitButton);
quitButton->setPosition(CEGUI::Point(0.35f, 0.45f));
quitButton->setSize(CEGUI::Size(0.3f, 0.1f));
quitButton->setText("Quit");

在同样位置添加下列代码

  mEditorGuiSheet = CEGUI::WindowManager::getSingleton().loadWindowLayout((CEGUI::utf8*)"Tutorial Gui.xml");
mGUISystem->setGUISheet(mEditorGuiSheet);
CEGUI::PushButton* quitButton=(CEGUI::PushButton*)CEGUI:: 
WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Quit");

最后一行多余的,因为我们没有在之后使用指针,但是其说明了如何通过加载文件来进行访问。 注意:我们在创建xml文件时要根据实际窗口进行设计。

完成后编译并执行,程序在外观上并没有变化。

[编辑]尝试

•视线相交和选取Ogre mesh—当鼠标没有从GUI元素上移过。 •定义一个在GUI根菜单上的鼠标点击动作。当你鼠标点击一个不在根窗口中的GUI元素时,它将会响应你的鼠标点击。如果你的鼠标并没有从一个 GUI元素上滑过(也就是说当你的鼠标指针还在我们的3D场景中)则根窗口响应鼠标点击。 •将鼠标点击转换到世界坐标系和视线相交((Camera::getCamera)到ViewportRay(mouseX, mouseY))

  // Start a new ray query
Ogre::Ray cameraRay = root::getSingleton( ).
getCamera( )->getCameraToViewportRay( mouseX, mouseY );
Ogre::RaySceneQuery *raySceneQuery = root::getSingleton( ).
getSceneManager( )->createRayQuery( cameraRay );
   raySceneQuery->execute( );
Ogre::RaySceneQueryResult result = raySceneQuery->getLastResults( );
Ogre::MovableObject *closestObject = NULL;
real closestDistance = LONG_MAX;
std::list< Ogre::RaySceneQueryResultEntry >::iterator rayIterator;
   for ( rayIterator = result.begin( );
rayIterator != result.end( );
rayIterator++ ) {
if ( ( *rayIterator ).movable->getUserObject( ) != NULL ) 
{
if ( ( *rayIterator ).distance < closestDistance ) 
{
closestObject = ( *rayIterator ).movable;
closestDistance = ( *rayIterator ).distance;
}
}
}
   // No object clicked
if ( closestObject == NULL ) {   
clickedObject = NULL;                                  ---- clickedObject is a class scoped variable
} else {
clickedObject = static_cast< object* >( closestObject->getUserObject( ) );
}
raySceneQuery->clearResults( );
root::getSingleton( ).getSceneManager( )->destroyQuery( raySceneQuery )

[编辑]如何在两个GUI(用户界面)之间转换(使用透明度)

例如:如果你有一个登陆界面,在成功登陆后,进入了你的用户主界面。你将会想在这两个界面间切换。 •第一步,加载登陆用户界面。

    //First loading with this
mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, false, 3000,mSceneMgr);
mGUISystem = new CEGUI::System(mGUIRenderer);
CEGUI::Logger::getSingleton().setLoggingLevel(CEGUI::Informative);
CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"WindowsLook.scheme");
mGUISystem->setDefaultMouseCursor((CEGUI::utf8*)"WindowsLook", (CEGUI::utf8*)"MouseArrow");
CEGUI::Font *f = CEGUI::FontManager::getSingleton().createFont("Commonwealth-10.font");
mGUISystem->setDefaultFont(f);
//End "first loading with this"
   //Load a XML file
mEditorGuiSheet = CEGUI::WindowManager::getSingleton().loadWindowLayout((CEGUI::utf8*)"Presentation.xml");
mGUISystem->setGUISheet(mEditorGuiSheet);

•第二步,如果你想删除并重建一个GUI,你需要做到以下:

   if(mEditorGuiSheet)
CEGUI::WindowManager::getSingleton().destroyWindow(mEditorGuiSheet);

•最后一步,加载其他的GUI

   mEditorGuiSheet = CEGUI::WindowManager::getSingleton().loadWindowLayout((CEGUI::utf8*)"Futura.xml");
mGUISystem->setGUISheet(mEditorGuiSheet);

重做第二步和最后一步来加载其他GUI。

[编辑]结论

这个教程为你展示了在Ogre3D下使用CEGUI的一些基本方法,你可以感受下使用CUEGUI编程的乐趣:)

http://www.xdnf.cn/news/814555.html

相关文章:

  • 【转】威胁建模的12种方法
  • salt returner mysql_saltstack实战2--远程执行之返回(returner)
  • PyFlipper:一款功能强大的Flipper Zero命令行接口封装器
  • Chrome+ProxySwitchySharp+Putty
  • GSM模块的调试(一)
  • jQueryMobile 秘籍(四)
  • 汇编语言--DOSBox 0.74的安装与简单使用
  • CAP原则--Eureka对比Zookeeper
  • 常用的时间同步服务器地址
  • 电信DNS劫持事件
  • 12个方法去创造你人生中的第二次机会
  • Cygwin完全下载指南
  • Linux环境配置
  • Linux介绍与操作系统安装
  • 电力系统潮流计算(牛顿-拉夫逊法、高斯-赛德尔法、快速解耦法)【6节点 9节点 14节点 26节点 30节点 57节点】(Matlab代码实现)
  • sfdisk 中文手册
  • 各种颜色代码大全(Html、android)
  • Css display 属性详解
  • 什么是IT服务台?
  • Customer类定义
  • 制作一个简单HTML公司官网网页设计(HTML+CSS)
  • Mysql中 distinct 和 group by 哪个效率高?
  • Softice入门
  • 有关在matlab中对信号采样及频谱的一些解释;复数的频谱,高分辨率谱,高密度谱的一些理解
  • 启动程序因找不到sqlite3.dll文件出现错误提示
  • typedef用法
  • html中引入视频的方法
  • Linux内存调试工具初探-MEMWATCH
  • GitHub和码云上,7个 h5 页面制作工具推荐
  • 11.20 《第二家园》上线内测