基礎教程六(CEGUI和OGRE)

來源:互聯網
上載者:User
必備知識

本教程是在假設你已經擁有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編程的樂趣:)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.