Basic tutorial 9 (Ogre startup sequence)

Source: Internet
Author: User
Introduction

In this lesson, you will learn how to start ogre without the sample framework. After learning, you will create your own ogre application without using exampleapplication or exampleframelistener.

You can find the code for this lesson here. When you take this course, you should add code to your project one by one, compile and observe the results.

Start preparation

Initial code
   #include    #include    #include    #include       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()       {           createRoot();           defineResources();           setupRenderSystem();           createRenderWindow();           initializeResourceGroups();           setupScene();           setupInputSystem();           setupCEGUI();           createFrameListener();           startRenderLoop();       }          ~Application()       {       }      private:       Root *mRoot;       OIS::Keyboard *mKeyboard;       OIS::InputManager *mInputManager;       CEGUI::OgreCEGUIRenderer *mRenderer;       CEGUI::System *mSystem;       ExitListener *mListener;          void createRoot()       {       }              void defineResources()       {       }              void setupRenderSystem()       {       }              void createRenderWindow()       {       }          void initializeResourceGroups()       {       }          void setupScene()       {       }          void setupInputSystem()       {       }          void setupCEGUI()       {       }          void createFrameListener()       {       }          void startRenderLoop()       {       }   };      #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;   }

Starting from scratch

Before getting started, let's take a look at how the startup process works at a higher level:

  1. Create a root object.
  2. Defines the resources to be used by ogre.
  3. Select and set the rendering system (DirectX, OpenGL, and so on ).
  4. Create a rendering window (the window in which ogre is located ).
  5. Initialize the resources you want to use.
  6. Use these resources to create a scenario.
  7. Set third-party libraries or plug-ins.
  8. Create some frame listeners.
  9. Start rendering cycle

This section describes these steps one by one. Note that steps 1-4 must be performed in strict order, while steps 5 (initialize resources) and 6 (Create scenarios) can be placed at a later point, if you like. But I do not recommend this unless you really know the order of your work.

Start ogre

Create a root object

This is simple. The root object is the core of the Ogre library. Before you use this engine to do other things, you must first create it. Find the application: createroot method and add the following code:

           mRoot = new Root();

The root constructor requires three parameters. The first is the name and path of the plug-in configuration file. The second is the path of the Ogre configuration file (it tells the Ogre about the graphics card, display settings, and other information ). The last one is the name and path of the log file. Because we do not need to modify any attribute, we can use the default one.

Resources

Note:: It is helpful to find resources. cfg in the bin/release directory of the SDK.

Next we will define the resources that the program will use, including textures, models, scripts, and so on. Remember, you must pre-define your resources and initialize them before Ogre can use them. In this step, we define the resources that all programs may use. So far, we add the folder where each resource is located to resourcegroupmanager. Find the defineresources method and add the following code:

   String secName, typeName, archName;   ConfigFile cf;   cf.load("resources.cfg");

Here, an ogre configfile class is used to parse all resources in "resources. cfg", but not to load them into ogre (you must manually add them ). Remember, you can use your own file format and parser freely. You only need to replace configfile with your own parser. Loading resources is not very important, as long as you can add resources to resourcegroupmanager. Now that we have parsed the cfg file, we also need to add each part to resourcegroupmanager. Run the following code to start a loop:

       ConfigFile::SectionIterator seci = cf.getSectionIterator();      while (seci.hasMoreElements())      {

In each loop, we recycle it once and extract all the content in it:

            secName = seci.peekNextKey();          ConfigFile::SettingsMultiMap *settings = seci.getNext();          ConfigFile::SettingsMultiMap::iterator i;

Finally, we add the part name (the group of resources), the resource type (ZIP, folder, etc.), and the resource file name to resourcegroupmanager:

          for (i = settings->begin(); i != settings->end(); ++i)          {              typeName = i->first;              archName = i->second;              ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);          }      }

This method adds all resources from the config file, but it only tells the Ogre where they are. But if you want to use them, you must initialize them. We will introduce it in the "initialize resources" section later.

Create a rendering system

Next, we need to select a rendering system (usually DirectX or OpenGL on a Windows machine) and configure it. Most demo programs use an ogre configuration dialog box, which is a good example. Ogre provides a method to save user settings, meaning that you do not need to set the settings for the first time. Find the setuprendersystem method and add the following code:

      if (!mRoot->restoreConfig() && !mRoot->showConfigDialog())          throw Exception(52, "User canceled the config dialog!", "Application::setupRenderSystem()");

In the first part of the IF statement, we try to restore the config file. If the function returns false, indicating that the file does not exist, the configuration dialog box is displayed, that is, the second part of the IF statement. If false is returned, the configuration dialog box is canceled (that is, they want to exit the program ). In this example, we throw an exception, but in fact it is better to simply return false and close the application. Because restoreconfig and showconfigdialog may also throw exceptions, it may be better to save these real exceptions. However, this will increase the unnecessary complexity of the tutorial. Here I only use one exception.

I also recommend that you delete the ogre. cfg file in catch if you catch an exception during ogre startup. They need to change it because their settings in the configuration dialog box may cause problems. You can also disable it. Closing the configuration dialog box can save development time, because you do not have to confirm these display settings every time you run the program.

If you do not want to use the Ogre configuration dialog box, you need to manually set the rendering system. The following is a basic example:

// Do not add these to the program: rendersystem * rs = mroot-> getrendersystembyname ("Direct3D9 rendering subsystem"); mroot-> setrendersystem (RS ); RS-> setconfigoption ("full screen", "no"); RS-> setconfigoption ("video mode", "800x600 @ 32-bit color ");

You can use root: getavailablerenderers to understand which rendering systems are available for your program. Once you get a rendering system, you can use rendersystem: getconfigoptions to check which options can be provided to users. With these two methods, you can create your own configuration dialog box.

Create rendering window

Currently, we have selected a rendering system. We also need a window for rendering ogre. There are actually many ways to implement it, but here we only introduce two.

If you want ogre to create a rendering window for you, this is quite easy. Find the createrenderwindow method and write it as follows:

      mRoot->initialise(true, "Tutorial Render Window");

The first parameter indicates whether to allow ogre to create a rendering window for you. Otherwise, you can create a rendering window by using Win32 API, wxWidgets, or other Windows/Linux GUI systems. A simple example in Windows is as follows:

// Do not add these to the program mroot-> initialise (false); hwnd = 0; // get the hwnd of the application! Namevaluepairlist MISC; MISC ["external?whandle"] = stringconverter: tostring (INT) hwnd); renderwindow * win = mroot-> createrenderwindow ("Main renderwindow", 800,600, false, & MISC );

Here you still use root: initialise. The first parameter is set to false. Then, you must obtain the handle of the window you want the ogre to render. How you obtain it depends entirely on the GUI toolbox you use to create a window (which is different in Linux ). After you have it, you can use namevaluepairlist handle to assign this handle to "external?whandle ". Root: The createrenderwindow method is used to create the renderwindow object from the window you created. For more information, see the API documentation for this method.

Initialize Resources

Now we have created a root object, a rendering system, and a rendering window. Next we will initialize the resources we will use. From mesh to script, we only use a small part of these resources at a certain time. To reduce memory consumption, we can only load resources in use. So far, we break down resources into various parts and initialize them only at runtime. We will not detail this lesson. There is a tutorial dedicated to introducing resources elsewhere. Before Initializing Resources, we should set the default value of texture mipmap. Find the initializeresourcegroups method and add the following code:

      TextureManager::getSingleton().setDefaultNumMipmaps(5);      ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

In this way, the program has all initialized resource groups for use.

Scenario

You should understand three things you need to do before adding various things to a scenario: Create a scenario Manager (scenemanager), create a camera (CAMERA), and create a viewport ). Add the following code in the setupscene method:

      SceneManager *mgr = mRoot->createSceneManager(ST_GENERIC, "Default SceneManager");      Camera *cam = mgr->createCamera("Camera");      Viewport *vp = mRoot->getAutoCreatedWindow()->addViewport(cam);

If you need it, you can create multiple scenario managers and multiple cameras, but when you really want to use the camera to render things to the screen, make sure that you have added the viewport for it. So far, you need to use the renderwindow class, which is created in the "Create rendering window" section. Because we do not have a pointer to this object, we can get it through the root: getautocreatedwindow method.

After these three things are complete, you can add objects to your scenario as much as possible.

Set third-party Libraries

Ois

Although in ogre, OIS is not the only choice, it is one of the best. Let me briefly introduce how OIS is started in a program. If you really want to use this library, please refer to this tutorial and the OIS documentation.

Set no buffer input

Ois uses a unified inputmanager, which is difficult to configure, but it is easy to use once it is created correctly. In fact, it only requires the handle of the Ogre rendering window. Fortunately, because we use an automatic window, ogre simplifies it. Find the setupinputsystem method and add the following code:

      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, false);

In this way, the inputmanager is created, but to obtain input from the keyboard, mouse, or handle, you must also create these objects:

      try      {          mKeyboard = static_cast(mInputManager->createInputObject(OIS::OISKeyboard, false));          //mMouse = static_cast(mInputManager->createInputObject(OIS::OISMouse, false));          //mJoy = static_cast(mInputManager->createInputObject(OIS::OISJoyStick, false));      }      catch (const OIS::Exception &e)      {          throw Exception(42, e.eText, "Application::setupInputSystem");      }

I commented out the mouse and joystick objects, because we do not use them here, but they are created in this way. Inputmanager: The second parameter of createinputobject indicates whether to use a buffer input (introduced in previous tutorials ). Set the second parameter to false and create an input object without buffering. We will use this here.

Create frame listener

Whether or not you use a buffered input, you must call the capture method of the keyboard, mouse, or handle object between each frame. This is already done in the starting code of this lesson. For unbuffered input, you only need to do this. Between each frame, you can call various methods of the mouse and keyboard to query the status of these objects. For buffered input, we need to do something a little bit.

To use buffered input, you need to add a class to process the input. There are two things to do: one is to implement the appropriate listening interface, and the other is to register the class you created as the callback of this event. In the previous course, you can find an example with a buffer country input. The following is the code of this class:

// Add it to the project class bufferedinputhandler: Public ois: keylistener, public ois: mouselistener, public ois: joysticklistener {public: bufferedinputhandler (OIS :: keyboard * keyboard = 0, ois: mouse * mouse = 0, ois: joystick * joystick = 0) {If (keyboard) keyboard-> seteventcallback (this );
       if (mouse)           mouse->setEventCallback(this);
       if (joystick)           joystick->setEventCallback(this);   }
   // KeyListener   virtual bool keyPressed(const OIS::KeyEvent &arg) { return true; }   virtual bool keyReleased(const OIS::KeyEvent &arg) { return true; }
   // MouseListener   virtual bool mouseMoved(const OIS::MouseEvent &arg) { return true; }   virtual bool mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { return true; }   virtual bool mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { return true; }
   // JoystickListener   virtual bool buttonPressed(const OIS::JoyStickEvent &arg, int button) { return true; }   virtual bool buttonReleased(const OIS::JoyStickEvent &arg, int button) { return true; }   virtual bool axisMoved(const OIS::JoyStickEvent &arg, int axis) { return true; }

};

I recommend that you only implement the listener functions you actually need.

Intractable Diseases with buffered Input

If you do not get the input buffer in the program as you want, you need to check the following:

  1. When you call the inputmanager: createinputobject () function to create an input device, do you want to set the second parameter (enable input buffer) to true?
  2. Have you set a seteventcallback () function for each input buffer object?
  3. Is there any other class that calls the seteventcallback () function? (Note: OIS only allows an event to be called back to an object. You cannot call back an event to two classes for processing .)

If you have checked these three problems and still encountered errors, please post your questions to the ogre help Forum.

Cegui

Cegui is a flexible GUI library that is directly integrated into ogre. Although we do not use any cegui functions in this lesson, I will briefly introduce its settings. Cegui requires renderwindow and scenemanager for rendering.

      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);

In this way, you can use cegui. If you change the scenemanager in the middle of your program, you must notify the cegui to render it to a new scenemanager. So far, use ogreceguirenderer: settargetscenemanager.

Rendering loop and final work

Frame monitoring

Before we start rendering the loop and let the program run, we need to add a frame listener. Note that I have created a simple frame listener named exitlistener, which waits for the ESC key to be pressed to exit the program. In your program, I may need more frame listeners for more complex tasks. Take a look at this exitlistener to make sure you understand its process. Then add the following code to the createframelistener method:

      mListener = new ExitListener(mKeyboard);      mRoot->addFrameListener(mListener);

Rendering cycle

The last thing we need to do is to start the rendering loop of ogre. Very simple. Find the startrenderloop method and add the following code:

      mRoot->startRendering();

In this way, the program starts rendering until framelistener returns false. You can also extract a single frame and do something between each frame. Root: renderoneframe renders a frame. If any framelistener returns false, it also returns false:

// Do not add this section to the project while (mroot-> renderoneframe () {// do some things here, like sleep for X milliseconds or perform other actions .}

However, in my opinion, you should transfer all the code in the while loop to framelistener. The only use of this model that I can think of is to sleep for some milliseconds in the middle, thus artificially reducing the frame rate to a certain value. This is generally not done in framelistener, because it will be confused with the frameevent: timesincelastframe variable.

Clear

The last thing is that when the program is terminated, we need to clear all the created objects. So far, we will delete or destroy these objects in the reverse order of creation. We started with OIS and it has a special method to destroy its objects. Find ~ And add the following code:

      mInputManager->destroyInputObject(mKeyboard);      OIS::InputManager::destroyInputSystem(mInputManager);

Now let's clear the cegui, as long as you delete the object:

      delete mRenderer;      delete mSystem;

Finally, we need to delete the root and framelistener objects. When the root object is deleted, other created objects (such as scenemanager and the renderwindow) will also be deleted.

      delete mListener;      delete mRoot;

Okay! Now you can compile and run your program. Although you can only see one black screen, we didn't add anything to the scenario. If a link problem occurs during compilation, make sure that ceguibase_d.lib and ogreguirenderer_d.lib are added to the input of the linker (this is in debug mode. If it is in release mode, remove _ D ). Now you should be familiar with the Ogre startup process. You can leave the sample framework behind and use other methods. However, to simplify the process, the subsequent courses will still use the sample framework.

If you are interested in other parts of the sample framework, please refer to more in-depth articles.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.