How to-list

Written by Oogst, last update on 25-05-2004, check the Oogst-site for more Oogst-stuff.

About this list

This is a list of how to do simple things in Ogre. It contains mainly simple code examples, which is something I myself really missed while learning the basics of Ogre. The explanations provided here are all kept brief. For more details on all the things mentioned, see:
-the official manual for the Ogre-basics and the script-definitions;
-the API for descriptions of all classes and functions in Ogre;
-the tutorials provided with Ogre;
-the search-function of the Ogre-forum.

Why I made this list

I made this list for four reasons:
-I am working on a group project at school and the rest of the team would like to be able to find code examples quickly;
-I really missed this kind of thing when learning Ogre myself and it would have saved me a lot of time;
-I keep forgetting function-names and this way I can look them up quickly;
-I wanted to do something in return for the fantastic engine the Ogre-team has provided and which I can use for free without any expectation from the creators of getting something back for it.

ExampleApplication

This list works from the ExampleApplication and supposes the user uses ExampleApplication and ExampleFrameListener. Some variables, like mSceneMgr, are only available with this name through ExampleApplication. If you are not using ExampleApplication, you will have to fill in the different variables yourself.

Furthermore, all examples use arbitrary names for variables and such; of course you should change these to what you find appropriate for your own application.

How to...

...set up an application using ExampleApplication
...put a 3D-model in the scene
...remove a 3D-model from the scene
...move, reposition, scale and rotate a SceneNode
...put a light in the scene
...set the ambient lighting
...control the camera
...add a billboard/sprite to the scene
...create a basic FrameListener using ExampleFrameListener
...control some object from your scene in a FrameListener
...get the time since the previous frame
...react to key-presses
...make sure key-presses are not reacted to too shortly after each other
...quit you application
...efficiently add and remove 3D-objects from the scene during run-time (like rockets being fired)
...show an Overlay (and hide it again)
...change the text in a TextArea
...show the mouse-cursor
...create a working button
...find out which button was pressed
...quit the application using an ActionListener
...get a different SceneManager
...efficiently get a list of all possible collisions
...find out to which of your own objects a MovableObject belongs
...exclude objects from collision detection

...set up an application using ExampleApplication

If you do not know how this works already, you MUST read more about it in Ogre’s tutorial-section: it is really important to understand this properly. In short it requires creating a class that is derived from ExampleApplication. This class can implement the functions createScene() and createFrameListener(). It will probably look something like this:

    #include "ExampleApplication.h"

    class MyClass: public ExampleApplication,
    {
    public:
      MyClass(void);
      ~MyClass(void);
    protected:
      void createScene(void);
      void createFrameListener(void);
    };

You will also need a .cpp-file that creates one instance of MyClass and runs it. In general it will look something like this (taken from the “Guide To Setting Up Application Project Files”-tutorial):

    #include "Ogre.h"
    #include "MyClass.h"

    #if OGRE_PLATFORM == 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
    {
      MyClass app;

      try
      {
        app.go();
      }
      catch( Exception& e )
      {
    #if OGRE_PLATFORM == 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;
    }

...put a 3D-model in the scene

A 3D-model is an Entity and it must be attached to a SceneNode to be placed in the scene. The SceneNode can be taken from the rootSceneNode in the SceneManager. Creating an Entity and SceneNode and attaching the Entity to the SceneNode will look something like this:

    Entity* thisEntity = mSceneMgr->createEntity("nameInTheScene", "FileName.mesh");
    SceneNode* thisSceneNode = static_cast<SceneNode*>(mSceneMgr->getRootSceneNode()->createChild());
    thisSceneNode->attachObject(thisEntity);

...remove a 3D-model from the scene

To remove a 3D-model, you must detach the Entity from its SceneNode, delete it and if needed destroy the SceneNode as well, which must be done using the SceneManager. If you have a SceneNode* called myNode you can completely destroy all its contents (both MovableObjects and child SceneNodes) and the node itself using the following code:

    while(myNode->numAttachedObjects() > 0)

    {
      MovableObject* thisObject = myNode->detachObject(static_cast<unsigned short>(0));
      delete thisObject;
    }
    myNode->removeAndDestroyAllChildren();
    mSceneMgr->getRootSceneNode()->removeAndDestroyChild(myNode->getName());

...move, reposition, scale and rotate a SceneNode

If you have a SceneNode with some MovableObjects, like Entities, Lights and Cameras, attached to it, you can move it using a lot of different functions, see the API for all of them. The following functions respectively move it, reposition it, scale it and rotate it over its X-, Y- and Z-axis:

    thisSceneNode->translate(10, 20, 30);
    thisSceneNode->setPosition(1.8, 20.1, 10.5);
    thisSceneNode->scale(0.5, 0.8, 1.3);
    thisSceneNode->pitch(45);
    thisSceneNode->yaw(90);
thisSceneNode->roll(180);

...put a light in the scene

To add a light to the scene, you must ask the SceneManager for one. You can then set its settings, of which some examples are given below:

    Light* myLight = mSceneMgr->createLight("nameOfTheLight");
    myLight->setType(Light::LT_POINT);
    myLight->setPosition(200, 300, 400);
    myLight->setDiffuseColour(1, 1, 0.7);
    myLight->setSpecularColour(1, 1, 0.7);

You can also attach a light to a SceneNode. The following code creates a SceneNode and attaches myLight to it:

    SceneNode* thisSceneNode = static_cast<SceneNode*>(mSceneMgr->getRootSceneNode()->createChild());
    thisSceneNode->attachObject(myLight);

...set the ambient lighting

The ambient lighting is controlled by the Scenemanager, so that is where you can set it:

    mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2));

...control the camera

The standard camera in ExampleApplication is called mCamera and is available in the class that is derived from ExampleApplication. The following code changes its position, changes the point it looks at, creates a SceneNode and attaches the camera to it:

    mCamera->setPosition(0, 130, -400);
    mCamera->lookAt(0, 40, 0);
    SceneNode* thisSceneNode = static_cast<SceneNode*>(mSceneMgr->getRootSceneNode()->createChild());
    thisSceneNode->attachObject(mCamera);

...add a billboard/sprite to the scene

A Billboard is a square polygon that is always pointed at the camera. It is also known as a sprite. To make one, you must first make a BillboardSet. Then the billboard can be added to it on a given position. The BillboardSet is a MovableObject en should therefore be added to a SceneNode. The whole procedure is as follows:

    SceneNode* myNode = static_cast(mSceneMgr->getRootSceneNode()->createChild());
    BillboardSet* mySet = mSceneMgr->createBillboardSet("mySet");
    Billboard* myBillboard = mySet->createBillboard(Vector3(100, 0, 200));
    myNode->attachObject(mySet);

...create a basic FrameListener using ExampleFrameListener

A FrameListener gives you the opportunity to do something at the start and the end of every frame. You must first create a class that is derived from ExampleFrameListener and in this class you can implement frameStarted() and frameEnded(). This will look something like this:

    #include "ExampleFrameListener.h"

    class myFrameListener: public ExampleFrameListener
    {
    public:
      myFrameListener(RenderWindow* win, Camera* cam);
      ~myFrameListener(void);
      bool frameStarted(const FrameEvent& evt);
      bool frameEnded(const FrameEvent& evt);
    };

The constructor should call its parent-constructor, which will look something like this:

    myFrameListener::myFrameListener(RenderWindow* win, Camera* cam): ExampleFrameListener(win, cam){}

You must also register your FrameListener to the Root. This can be done in the createFrameListener()-function of the class that is derived from ExampleApplication. You can register as many FrameListeners to the root as you want. It will look something like this:

    void createFrameListener(void)
    {
      MyFrameListener listener = new MyFrameListener(mWindow, mCamera);
      mRoot->addFrameListener(listener);
    }

...control some object from your scene in a FrameListener

If you want to control some object you have in your scene in a FrameListener, the FrameListener must have access to it. An easy way to do this, is by providing a pointer to it in the constructor of the FrameListener. Its constructor will now look something like this:

    myFrameListener(RenderWindow* win, Camera* cam, Car* car);

...get the time since the previous frame

In the functions frameEnded() and frameStarted() of a FrameListener you can get the time in seconds (this is a float) in the following way:

    bool frameStarted(const FrameEvent& evt)
    {
      float time = evt.timeSinceLastFrame;
      return true;
    }

You can now for instance multiply the speed per second with this float in order to get the movement since the last frame. This will make the pace of the game framerate-independent.

...react to key-presses

In the functions frameEnded() and frameStarted() of a FrameListener you can react to key-presses by first ordering Ogre to capture them and then checking which key is being pressed. You only have to capture the InputDevice once per frame. This will look something like this:

    mInputDevice->capture();
    if (mInputDevice->isKeyDown(Ogre::KC_DOWN))
    {
      //react however you like
    }
    if (mInputDevice->isKeyDown(Ogre::KC_UP))
    {
      //react however you like
    }

...make sure key-presses are not reacted to too shortly after each other

If you implement reactions to key-presses in the above way, they will happen each frame. If you want them to happen, for instance, at most twice per second, you can achieve this by setting a timer. This timer must be kept in the class itself and not in the function in order to be able to access it through different calls of the function. Implementing this will look something like this:

    class myFrameListener: public ExampleFrameListener
    {
    protected:
      float buttonTimer;
    public:
      myFrameListener(RenderWindow* win, Camera* cam): ExampleFrameListener(win, cam)
      {
        buttonTimer = 0;
      }	
      bool frameStarted(const FrameEvent& evt)
      {
        float time = evt.timeSinceLastFrame;
        buttonTimer -= time;
        mInputDevice->capture();
        if (mInputDevice->isKeyDown(Ogre::KC_DOWN) && buttonTimer <= 0)
        {
          buttonTimer = 0.5;
          //react however you like
        }
        return true;
      }
    };

...quit you application

You can quit you application in the frameStarted() or frameEnded()-function of the FrameListener by returning false. If you want to tie this to pressing the escape-button on the keyboard, this will look as follows:

    bool frameStarted(const FrameEvent& evt)
    {
      mInputDevice->capture();
      if (mInputDevice->isKeyDown(Ogre::KC_ESCAPE))
        return false;
      return true;
    }

...efficiently add and remove 3D-objects from the scene during run-time (like rockets being fired)

In the createScene()-function you can load meshes from a file, but this is too slow to do if new objects must be added in run-time (though in a very simple application you will not see the difference in speed). To add objects faster, you can load a lot of meshes in the createScene()-function and then take them from a stack in run-time. After the objects are not used anymore, you can put them back on the stack for later use. A good example of the usefulness of this is a canon that fires rockets: these must be created when fired and removed when exploded.

In order to always have access to this stack of rockets, you can make it a global variable (outside any class) or access it through a singleton. The latter is much nicer, but takes more code so I will not do so in this example. So you keep a stack of Entities somewhere:

    stack rocketEntities;

In createScene() you fill this stack with a lot of rockets. Each Entity is set invisible for now and must have a unique name, which is achieved using the sprintf()-function. All in all it looks like this:

    for (unsigned int t = 0; t < 100; t++)
    {
      char tmp[20];
      sprintf(tmp, "rocket_%d", t);
      Entity* newRocketEntity = mSceneMgr->createEntity(tmp, "Rocket.mesh");
      newRocketEntity->setVisible(false);
      rocketEntities.push(newRocketEntity);
    }

Now when creating a new Rocket we can take a mesh from rocketEntities. In this example I do so in the constructor of the Rocket and put it pack in the destructor of the Rocket. In order to get the Entity back from the SceneNode in the destructor, I store its name in rocketEntityName. I also position the rocket correctly in the constructor. To make this all work, the SceneManager must be available throughout your program, in this case this is achieved by having it be a global variable (outside any class). I also handle creation and destruction of the SceneNode in the constructor and destructor. The Rocket-class will now look like this:

    class Rocket
    {
    protected:
      SceneNode* rocketNode;
      string rocketEntityName;
    public:
      Rocket(const Vector3& position, const Quaternion& direction)
      {
        rocketNode = static_cast<SceneNode*>(sceneMgr->getRootSceneNode()->createChild());
        Entity* rocketEntity = rocketEntities.top();
        rocketEntities.pop();
        rocketEntity->setVisible(true);
        rocketEntityName = rocketEntity->getName();
        rocketNode->attachObject(rocketEntity);
        rocketNode->setOrientation(direction);
        rocketNode->setPosition(position);
      }
      ~Rocket()
      {
        Entity* rocketEntity = static_cast<Entity*>(rocketNode->detachObject(rocketEntityName));
        rocketEntity->setVisible(false);
        rocketEntities.push(rocketEntity);
        sceneMgr->getRootSceneNode()->removeAndDestroyChild(rocketNode->getName());
      }
    };

If you use this construction, you should be aware of the fact that this crashes if no rockets are left. You can solve this by checking whether the stack of Entities is empty and if it is, load new meshes to add to the stack.

...show an Overlay (and hide it again)

To show and hide an Overlay, you must first get a pointer to it using the OverlayManager, which is a singleton. If you have an Overlay that is defined in a .overlay-script with the name “myOverlay” you can get it, show it and hide it again using the following code:

    Overlay* thisOverlay = static_cast<Overlay*>(OverlayManager::getSingleton().getByName("myOverlay"));
    thisOverlay->show();
    thisOverlay->hide();

...change the text in a TextArea

You can change all parameters of Containers and Elements in the GUI in runtime. In order to do so, you must first get a pointer to the Element or Container you want and, if needed for what you want to do, cast it to the type it is. Getting a pointer to a TextArea that is defined in a .overlay-script as “myTextArea” and changing its caption will look something like this:

    GuiElement* thisTextArea = GuiManager::getSingleton().getGuiElement("myTextArea");
    thisTextArea->setCaption(“blaat”);

In this case no casting was needed, as every GuiElement has a caption. If you want to set a setting that is specific for one type of GuiElement, you will have to cast it to that type. Changing the font-name of a TextArea will look something like this:

    TextAreaGuiElement* thisTextArea = static_cast<TextAreaGuiElement*>(GuiManager::getSingleton().getGuiElement("myTextArea"));
    thisTextArea->setFontName(“RealCoolFont”);

...show the mouse-cursor

If you want to show the mouse-cursor on the screen, you have to do two things: set it to be shown and tell a FrameListener to track it. Telling it to be shown can be done as follows:

    GuiContainer* cursor = OverlayManager::getSingleton().getCursorGui();
    cursor->setMaterialName("Cursor/default");
    cursor->setDimensions(32.0/640.0, 32.0/480.0);
    cursor->show();

Telling a FrameListener to track it should be done in its parents’ constructor by setting its last boolean-parameter to true. The constructor will now look something like this:

    myFrameListener::myFrameListener(RenderWindow* win, Camera* cam): ExampleFrameListener(win, cam, false, true){}

Beware though that after doing this, this specific FrameListener will not react to button-presses anymore as the capture()- and isKeyPressed()-functions of mInputDevice now do not work properly anymore. A different FrameListener should be made to handle keyboard input now.

...create a working button

You can define a button in an Overlay-script using something like the following syntax, where it is important to set all these materials:

    container Button(myButton)
    {
      metrics_mode relative
      horz_align left
      vert_align top
      top 0.1
      left 0.1
      width 0.18
      height 0.1
      material NCG/GuiSession/RedMaterial
      button_down_material NCG/GuiSession/RedMaterial
      button_up_material NCG/GuiSession/RedMaterial
      button_hilite_down_material NCG/GuiSession/RedMaterial
      button_hilite_up_material NCG/GuiSession/RedMaterial
      button_disabled_material NCG/GuiSession/RedMaterial
    }

Buttons are not standard in Ogre and therefore you must make sure they are found by the compiler in the folder ogrenew\PlugIns\GuiElements\Include. Now you can include it:

    #include “OgreButtonGuiElement.h”

To make the button work, an ActionListener must be registered to it, which can be done as follows:

    ActionTarget* thisButton = static_cast<ButtonGuiElement*>(GuiManager::getSingleton().getGuiElement("myButton"));
    thisButton->addActionListener(this);

This examples supposes ‘this’ is an ActionListener, which is not true by default. Of cource any ActionListener will do, it does not have to be ‘this’. You can make a class an ActionListener by deriving it from ActionListener and implementing actionPerformed(). This will look something like this:

    
    class Listener: public ActionListener
    {
    public:
      void actionPerformed(ActionEvent *e);
    };

...find out which button was pressed

If you register one ActionListener to several buttons, they will all call the same function actionPerformed(). You can find out which button was actually being pressed by comparing its name with the name in the ActionEvent e. This will look something like this:

    #include 

    void actionPerformed(ActionEvent *e)
    {
      std::string action = e->getActionCommand();
      if (action == "myButton")
      {
        //handle the button-press
      }
    }

...quit the application using an ActionListener

Quiting an application can be done in the frameStarted()- and frameEnded()-functions of a FrameListener, not in the actionPerformed()-function. So how do we get there? For this we can introduce a simple FrameListener that does nothing more than quit if asked to. This FrameListener will look something like this (from the Gui-demo provided with Ogre):

    #include “ExampleFrameListener.h”

    class QuitListener: public ExampleFrameListener
    {
    public:
      QuitListener(RenderWindow* win, Camera* cam): ExampleFrameListener(win, cam, false, false)
      {
        quit = false;
      }
      bool frameStarted(const FrameEvent& evt)
      {
        if (quit)
          return false;
        return true;
      }
      void scheduleQuit(void)
      {
      quit = true;
      }
    protected:
      bool quit;
    };

Now if your ActionListener has a pointer to this QuitListener, it can simply schedule a quit by calling scheduleQuit() and the QuitListener will perform it before the next frame starts.

...get a different SceneManager

The SceneManager is chosen automatically using an identifier that tells what kind of scene it is. This is done in ExampleApplication, so to change this, you will have to change ExampleApplication itself. Normally, ExampleApplication contains the following piece of code:

    virtual void chooseSceneManager(void)
    {
      // Get the SceneManager, in this case a generic one
      mSceneMgr = mRoot->getSceneManager(ST_GENERIC);
    }

You can change ST_GENERIC to any of the following identifiers to get a SceneManager that is appropriate for your specific scene: ST_GENERIC ST_EXTERIOR_CLOSE ST_EXTERIOR_FAR ST_EXTERIOR_REAL_FAR ST_INTERIOR

...efficiently get a list of all possible collisions

Ogre can provide you with a list of all objects that are possible colliding. Objects that are close but not in a collision might be in this list as well, so you will have to make sure which one is a collision yourself afterwards. You can ask for this list of collisions using an IntersectionSceneQuery, which you can get using the following code:

    IntersectionSceneQuery* intersectionQuery = sceneMgr->createIntersectionQuery();

Now you can ask it for a list of all possible collisions:

    IntersectionSceneQueryResult& queryResult = intersectionQuery->execute();

If you intend to get this list several times before updating your scene, there is no need to have Ogre calculate it again over and over. You can get back the same list again without a new calculation using the following line:

    IntersectionSceneQueryResult& queryResult = intersectionQuery->getLastResults();

After use, you can store the IntersectionSceneQuery for later use or remove it. If you remove it, you must tell the SceneManager to do so using the following code:

    mSceneMgr->destroyQuery(intersectionQuery);

The IntersectionSceneQueryResult is a list of pairs of MovableObjects. An example of its use is getting the name of the first of the two colliding objects:

    queryResult.movables2movables.begin()->first->getName();

See the Ogre-API for more details on the types of the results.

...find out to which of your own objects a MovableObject belongs

The list of colliding objects IntersectionSceneQuery delivers is of MovableObjects, but in general you will want to relate this to some custom object in your own scene. To do so, you can attach a pointer to your own object to a MovableObject and get this pointer back later on. If you have an Entity (which is a MovableObject) and a custom object (like myRocket here below), you can attach your custom object to the Entity as follows:

    Entity* myEntity = sceneMgr->createEntity("myEntity”, "Rocket.mesh");
    Rocket* myRocket = new Rocket();
    myEntity->setUserObject(myRocket);

Now you can get a pointer to myRocket back from the Entity using the following code:

    myEntity->getUserobject();

To make this work, your own custom class must be derived from UserDefinedObject. This also allows you to find out what kind of class the returned object is, so that you can cast it back. The definition for Rocket could now look something like this:

    class Rocket: public UserDefinedObject
    {
    public:
      const string& getTypeName(void)
      {
        const string& typeName = "Rocket";
        return typeName;
      }
    };

Now after having detected which MovableObjects are involved in a collision, you can also find out which of your own objects are involved in this collision.

...exclude objects from collision detection

You can exclude certain objects from collision detection by using flags. You can add a flag to any MovableObject, for instance 100 in the following example:

    Entity* ground = mSceneMgr->createEntity("ground", "Ground.mesh");
    ground->setQueryFlags(100);

Now you can tell your IntersectionSceneQuery to exclude objects with this flag from its list of intersections by setting its mask. This will look like this:

    IntersectionSceneQuery* intersectionQuery = sceneMgr->createIntersectionQuery();
    intersectionQuery->setQueryMask(~100);