• Ogre启动过程&原理


    #include <Ogre.h>
    #include <OIS/OIS.h>
    #include <CEGUI/CEGUI.h>
    #include <OgreCEGUIRenderer.h>
    using namespace Ogre;
    class ExitListener : public FrameListener
    {
    public:
        ExitListener(OIS::Keyboard *keyboard)
            : mKeyboard(keyboard)
        {
        }
        bool frameStarted(const FrameEvent& evt)
        {
            mKeyboard->capture();
            return !mKeyboard->isKeyDown(OIS::KC_ESCAPE);
        }
    private:
        OIS::Keyboard *mKeyboard;
    };
    class Application
    {
    public:
        void go()
        {
            /************************************************************************
            1、创建Root对象。 
            2、定义Ogre将要使用的资源。 
            3、选择并设置渲染系统(即DirectX, OpenGL等)。 
            4、创建渲染窗口(Ogre所处的窗口)。 
            5、初始化你要使用的资源。 
            6、用这些资源来建立一个场景。 
            7、设置第三方库或插件。 
            8、创建一些帧监听器。 
            9、启动渲染循环 
            ************************************************************************/
            createRoot();
            defineResources();
            setupRenderSystem();
            createRenderWindow();
            initializeResourceGroups();
            setupScene();
            setupInputSystem();
            setupCEGUI();
            createFrameListener();
            startRenderLoop();
        }
        ~Application()
        {
            /************************************************************************
            最后一件事是,当程序终止时,我们要对所创建的所有对象进行清理。为止,我们
            将按照与创建时相反的顺序来删除或销毁这些对象。我们从OIS开始下手,它有一个
            专门的方法来销毁它的对象。添加如下代码: 
            ************************************************************************/
            mInputManager->destroyInputObject(mKeyboard);
            OIS::InputManager::destroyInputSystem(mInputManager);
            /************************************************************************
            现在我们来清理CEGUI,只要删除对象即可:
            ************************************************************************/
            delete mRenderer;
            delete mSystem;
            /************************************************************************
            最后,我们要删除Root和FrameListener对象。当删除Root对象时,我们创建的其它
            对象(SceneManager, the RenderWindow等)也会一并删除。 
            ************************************************************************/
            delete mListener;
            delete mRoot;
            /************************************************************************
            好了! 你现在可以编译并运行你的程序了,虽然你将只能看见一个黑屏,因为我们
            并没有往场景添加任何东西。如果在编译里遇到链接问题,确保CEGUIBase_d.lib
            和OgreGUIRenderer_d.lib添加到了链接器的输入里(这是debug模式的,如果是release
            模式,去掉_d)。现在你应该对Ogre的启动过程比较熟悉了,可以抛开示例框架而使
            用其它的了。
            ************************************************************************/
        }
    private:
        Root *mRoot;
        OIS::Keyboard *mKeyboard;
        OIS::InputManager *mInputManager;
        CEGUI::OgreCEGUIRenderer *mRenderer;
        CEGUI::System *mSystem;
        ExitListener *mListener;
        void createRoot()
        {
            /************************************************************************
            1、创建Root对象 
            Root的构造函数需要三个参数。第一个是插件配置文件的名称和路径。
            第二个是Ogre配置文件的路径(它告诉Ogre关于显卡、显示设置等信息)。
            最后一个是日志文件的名称和路径。因为我们不需要修改任何一个属性,所以用默认的。
            ************************************************************************/
            mRoot = new Root();
        }
        void defineResources()
        {
            /************************************************************************
            2、资源
            注意: 你最好在SDK的bin/release目录里找到resources.cfg,看看它的内容是很有帮助的。 
            下面我们要定义程序将要使用的资源,包括纹理、模型、脚本等等。请记住,你必须预先定
            义好你的资源,在Ogre能使用它们之前,你还必须对它进行初始化。在这一步里,我们来定义
            所有程序可能使用的资源。为止,我们把每一个资源所在的文件夹添加到ResourceGroupManager。
            ************************************************************************/
            String secName, typeName, archName;
            ConfigFile cf;
            cf.load("resources.cfg");
            /************************************************************************
            这里使用了一个Ogre的ConfigFile类来解析"resources.cfg"里的所有的资源,
            但并不是把它们装入到Ogre(你必须手工添加)。记住,你可以自由地使用你自己的
            文件格式和解析器,只需要用你自己的解析器来替换ConfigFile的。装入资源的方
            式并不十分重要,只要你能把资源添加到ResourceGroupManager。现在我们解析好
            了cfg文件,还需要把各部分添加到ResourceGroupManager中。以下代码启动一个循
            环: 
            ************************************************************************/
            ConfigFile::SectionIterator seci = cf.getSectionIterator();
            while (seci.hasMoreElements())
            {
                /************************************************************************
                每次循环里,我们再循环一次,提取它里面所有的内容:
                ************************************************************************/
                secName = seci.peekNextKey();
                ConfigFile::SettingsMultiMap *settings = seci.getNext();
                ConfigFile::SettingsMultiMap::iterator i;
                /************************************************************************
                添加部件名称(那一组资源的),资源类型(zip,文件夹等等),以及资源本身的文件
                名,给ResourceGroupManager: 
                ************************************************************************/
                for (i = settings->begin(); i != settings->end(); ++i)
                {
                    typeName = i->first;
                    archName = i->second;
                    ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
                }
            }
        }
        void setupRenderSystem()
        {
            /************************************************************************
            3、创建渲染系统 
            接下来,我们需要选择一个渲染系统(在Windows机器上通常是DirectX或者OpenGL),
            然后配置它。大多数Demo程序使用的是一个Ogre配置对话框,这是一个很好的一个东
            东。Ogre提供了一种保存用户设置的方法,意味着除了第一次需要设置外,以后都不
            需要了。并添加以下代码: 
            ************************************************************************/
            if (!mRoot->restoreConfig() && !mRoot->showConfigDialog())
                throw Exception(52, "User canceled the config dialog!", "Application::setupRenderSystem()");
            /************************************************************************
            在if语句里的第一部分,尝试恢复这个config文件。如果函数返回false,意味着文
            件不存在,则应该显示配置对话框,也就是if语句的第二部分。如果仍然返回false
            ,意味着用户取消了配置对话框(也就是他们想退出程序)。在这个例子里,抛出了一
            个异常,但实际上简单地返回false且关闭应用程序,这样可能更好。由于 restoreConfig
            和 showConfigDialog 也可能抛出异常,保存这些真正的异常可能更好。然而,这将
            增加了教程的不必要的复杂度,我在这里只使用了一个异常。 
            如果你在Ogre的启动过程中捕获了一个异常,最好在catch里删除这个ogre.cfg文件。
            因为他们在配置对话框里进行的设置可能导致了问题的发生,所以他们需要更改它。
            你也可以不使用它,关闭配置对话框可以节省开发时间,因为你不必每次程序运行时
            确认这些显示设置。
            如果你不打算使用Ogre的配置对话框,你需要手动地设置渲染系统。以下是一个基本
            的例子: 
            ************************************************************************/
            // Do not add this to the application
            RenderSystem *rs = mRoot->getRenderSystemByName("Direct3D9 Rendering Subsystem");
                                                  // or use "OpenGL Rendering Subsystem"
            mRoot->setRenderSystem(rs);
            rs->setConfigOption("Full Screen", "No");
            rs->setConfigOption("Video Mode", "1440 x 900 @ 32-bit colour");
        }
        void createRenderWindow()
        {
            /************************************************************************
            4、创建渲染窗口
            目前选择了一个渲染系统,还需要一个渲染Ogre的窗口。实际上有许多种方式来实现
            ,但这里只介绍两种。 
            ************************************************************************/
            mRoot->initialise(true, "Tutorial Render Window");
            /************************************************************************
            第一个参数表示是否让Ogre为你创建一个渲染窗口。否则,你可以自己创建一个渲
            染窗口,通过使用win32 API、wxWidgets或其它Windows/Linux的GUI系统。关于在
            Windows下的一个简单例子是这样: 
            ************************************************************************/
            //// Do not add this to the application
            //mRoot->initialise(false);
            //HWND hWnd = 0;  // Get the hWnd of the application!
            //NameValuePairList misc;
            //misc["externalWindowHandle"] = StringConverter::toString((int)hWnd);
            //RenderWindow *win = mRoot->createRenderWindow("Main RenderWindow", 800, 600, false, &misc);
            /************************************************************************
            在这里你仍然使用Root::initialise,第一个参数设置成了false。然后,你必须获
            取你希望Ogre渲染的窗口的句柄。你如何取得它,完全决定于你用来创建窗口的GUI
            工具箱(在Linux下我估计这有一点区别)。你拥有了它之后,你通过NameValuePairList
            handle把这个句柄赋予"externalWindowHandle"。Root::createRenderWindow方法被
            用来从你创建的窗口来创建RenderWindow对象。想了解更多,参考这个方法的API文
            档。
            ************************************************************************/
        }
        void initializeResourceGroups()
        {
            /************************************************************************
            5、初始化资源
            现在我们创建了Root对象、渲染系统、以及渲染窗口,继续。接下来是初始化将要使
            用的资源。从mesh到脚本,所有的东西,在某一时刻,我们只用到这些资源其中的一
            小部分。为了减少内存消耗,我们可以只加载正在使用的资源。为止,我们把资源分
            解成各种部分,只在运行时初始化它们。在本课里,不将详细介绍。其它的地方有一
            个专门介绍资源的教程。初始化资源之前,我们应该设置纹理mipmap的缺省值。添加
            如下代码: 
            ************************************************************************/
            TextureManager::getSingleton().setDefaultNumMipmaps(5);
            ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
        }
        void setupScene()
        {
            /************************************************************************
            6、创建场景
            你应该了解在把各种东西添加到场景之前,你要做三件事:创建场景管理器
            (SceneManager)、创建摄像机(Camera)、创建视口(Viewport)。在setupScene
            方法里添加如下代码:
            ************************************************************************/
            SceneManager *mgr = mRoot->createSceneManager(ST_GENERIC, "Default SceneManager");
            Camera *cam = mgr->createCamera("Camera");
            Viewport *vp = mRoot->getAutoCreatedWindow()->addViewport(cam);
            /************************************************************************
            如果需要的话,可以创建多个场景管理器、多个摄像机,但当真正打算使用摄像机
            把事物渲染到屏幕上时,请确保已经为它添加了视口中。为止,要借助RenderWindow
            类,它在“创建渲染窗口”一节里被建立。由于我们没有这个对象的指针,所以我们
            通过Root::getAutoCreatedWindow方法来获取它。 
            这三件事完了以后,你可以尽情地往你的场景里添加物体了。 
            ************************************************************************/
        }
        void setupInputSystem()
        {
            /************************************************************************
            7、设置第三方库
            OIS 
            虽然在OGRE里,OIS不是唯一的选择,但它是最好的之一。我来简单介绍一下OIS如何
            在程序里启动。若真想要使用这个库,请参考这个教程,以及OIS自身的文档。 
            设置无缓冲输入 
            OIS使用一个统一的InputManager,它比较难配置,但一旦正确地创建之后,非常好使
            用。实际上,它只是需要Ogre渲染窗口的句柄。幸好,由于我们使用的是自动创建的窗
            口,Ogre使之简化了。添加如下代码: 
            ************************************************************************/
            size_t windowHnd = 0;
            std::ostringstream windowHndStr;
            OIS::ParamList pl;
            RenderWindow *win = mRoot->getAutoCreatedWindow();
            win->getCustomAttribute("WINDOW", &windowHnd);
            windowHndStr << windowHnd;
            pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
            mInputManager = OIS::InputManager::createInputSystem(pl);
            /************************************************************************
            这样InputManager就建好了,但为了从键盘、鼠标、或是手柄中获得输入,你还必
            须创建这些对象:
            ************************************************************************/
            try
            {
                mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, false));
                //mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, false));
                //mJoy = static_cast<OIS::JoyStick*>(mInputManager->createInputObject(OIS::OISJoyStick, false));
            }
            catch (const OIS::Exception &e)
            {
                throw new Exception(42, e.eText, "Application::setupInputSystem");
            }
            /************************************************************************
            我把Mouse和Joystick对象注释掉了,因为这里我们不使用,但它们就是这样创建的。
            InputManager::createInputObject的第二个参数是指是否使用带缓冲输入(在以前的
            教程里介绍过)。把第二个参数设置成false,创建了一个无缓冲的输入对象,我们这
            里就使用这个。 
            ************************************************************************/
        }
        void setupCEGUI()
        {
            /************************************************************************
            CEGUI 
            CEGUI是直接整合到Ogre里的一个非常灵活的GUI库。在这里不使用CEGUI的任何功能
            ,但我还是来简单介绍一下它的设置。CEGUI需要RenderWindow和SceneManager以供
            渲染。 
            ************************************************************************/
            SceneManager *mgr = mRoot->getSceneManager("Default SceneManager");
            RenderWindow *win = mRoot->getAutoCreatedWindow();
            // CEGUI setup
            mRenderer = new CEGUI::OgreCEGUIRenderer(win, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mgr);
            mSystem = new CEGUI::System(mRenderer);
            /************************************************************************
            就这样,你就能使用CEGUI了。如果你程序中途你改变了SceneManager,你必须通知
            CEGUI应该渲染到一个新的SceneManager。
            为止,使用OgreCEGUIRenderer::setTargetSceneManager就行了。 
            ************************************************************************/
            // Other CEGUI setup here.
        }
        void createFrameListener()
        {
            /************************************************************************
            8、渲染循环以及最后的工作
            帧监听 
            在我们开始渲染循环,并让程序运行之前,我们还需要添加帧监听器。请注意我已经
            创建一个非常简单的帧监听器,名为ExitListener,它等待ESC键被按下,以退出程
            序。在你的程序里,我可能需要更多的帧监听器,来做更复杂的事情。看一下这个
            ExitListener,确保了解它的流程。
            ************************************************************************/
            mListener = new ExitListener(mKeyboard);
            mRoot->addFrameListener(mListener);
        }
        void startRenderLoop()
        {
            /************************************************************************
            9、渲染循环 
            最后我们要做的是启动Ogre的渲染循环。非常简单,添加如下代码: 
            ************************************************************************/
            mRoot->startRendering();
            /************************************************************************
            这样程序就开始渲染,直到FrameListener返回false。你也可以提取单个帧,并在
            每帧之间做一些事情。Root::renderOneFrame渲染一帧,如何任何一个FrameListener
            返回false,它也返回false: 
            ************************************************************************/
            //// Do not add this to the application
            //while (mRoot->renderOneFrame())
            //{
            //    // Do some things here, like sleep for x milliseconds or perform other actions.
            //}
            /************************************************************************
            然而,在我看来,你应该把所有while循环里的代码转移到FrameListener。我能想
            到的这种模式的唯一用处就是,中途睡眠某些毫秒,从而人为地降低帧率到某一个
            值。一般在FrameListener里不会这样做,因为它会与FrameEvent::timeSinceLastFrame
            变量搞混淆。 
            ************************************************************************/
        }
    };
    #if OGRE_PLATFORM == PLATFORM_WIN32 || 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
    {
        try
        {
            Application app;
            app.go();
        }
        catch(Exception& e)
        {
    #if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
            MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
    #else
            fprintf(stderr, "An exception has occurred: %s/n",
                e.getFullDescription().c_str());
    #endif
        }
        return 0;
    }
    

  • 相关阅读:
    洛谷 P1990 覆盖墙壁
    洛谷 P1033 自由落体
    洛谷 P2049 魔术棋子
    洛谷 P2183 巧克力
    poj_1743_Musical Theme(后缀数组)
    Codeforces Round #367 (Div. 2) D. Vasiliy's Multiset
    Codeforces Round #367 (Div. 2) C. Hard problem
    hdu_5831_Rikka with Parenthesis II(模拟)
    hdu_5826_physics(物理题)
    hdu_5821_Ball(贪心)
  • 原文地址:https://www.cnblogs.com/ainima/p/6331161.html
Copyright © 2020-2023  润新知