Basic Tutorial 6         The Ogre Startup Sequence
Print

Tutorial Introduction
Image In this tutorial you will learn how to write a simple Ogre application from scratch.

 

Any problems you encounter during working with this tutorial should be posted in the Help Forum(external link).

 

Prerequisites

  • This tutorial assumes you have knowledge of C++ programming and are able to set up and compile an Ogre application.
  • This tutorial also assumes that you have created a project using the Ogre Wiki Tutorial Framework, either manually, using CMake or the Ogre AppWizard - see Setting Up An Application for instructions.
  • This tutorial builds on the previous basic tutorials, and it assumes you have already worked through them.

 

You can find the code for this tutorial here. As you go through the tutorial you should be slowly adding code to your own project and watching the results as we build it.

Getting Started

The Initial Code

In this tutorial, we will be using a bare bones code base as a starting point.

Warning
Image

 
Before proceeding, make sure that you've got a project set up, and that it only has two files: a header and a cpp.
If you've used the Ogre Wiki Tutorial Framework, remove BaseApplication.h and BaseApplication.cpp from it.

 

BasicTutorial6 header
class BasicTutorial6
{
public:
    BasicTutorial6(void);
    virtual ~BasicTutorial6(void);
    bool go(void);
};
BasicTutorial6 implementation
#include "BasicTutorial6.h"
 
#include <OgreException.h>
 
//-------------------------------------------------------------------------------------
BasicTutorial6::BasicTutorial6(void)
{
}
//-------------------------------------------------------------------------------------
BasicTutorial6::~BasicTutorial6(void)
{
}
 
bool BasicTutorial6::go(void)
{
    return true;
}
 
 
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
 
#ifdef __cplusplus
extern "C" {
#endif
 
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
    int main(int argc, char *argv[])
#endif
    {
        // Create application object
        BasicTutorial6 app;
 
        try {
            app.go();
        } catch( Ogre::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
            std::cerr << "An exception has occured: " <<
                e.getFullDescription().c_str() << std::endl;
#endif
        }
 
        return 0;
    }
 
#ifdef __cplusplus
}
#endif

 
Be sure you can compile this code before continuing.
The code will do nothing at all - it will exit immediately after it's run.

Don't worry, though:
After having walked through this tutorial, we will arrive at a full featured Ogre application.

The Startup Process in a Nutshell

Once you understand what's going on under the hood, getting Ogre running is actually very easy to do. The example framework looks daunting at first since it tries to do a lot of things that may or may not be needed for your application. After finishing this tutorial, you will be able to pick and choose what exactly is needed for your application and you can build a class with exactly that. Before we dive into this, we'll first take a quick look at how the startup process works at a high level.

The basic Ogre life cycle looks like this:

  1. Create the Root object.
  2. Define the resources that Ogre will use.
  3. Choose and set up the RenderSystem (that is, DirectX, OpenGL, etc).
  4. Create the RenderWindow (the window which Ogre resides in).
  5. Initialise the resources that you are going to use.
  6. Create a scene using those resources.
  7. Set up any third party libraries and plugins.
  8. Create any number of frame listeners.
  9. Start the render loop.

 
We will be going through each one of these in depth in this tutorial.

Note that while you really should do steps 1-4 in order, steps 5 and 6 (initialising resources and creating the scene) can come much later in your startup process if you like.
You could initialise third party plugins and create frame listeners before steps 5 and 6 if you so choose, but you really shouldn't do them before finishing step 4.
Also, the frame listeners/third party libraries cannot access any game related resources (such as your cameras, entities, etc) until the resources are initialised and the scene has been created.
In short, you can do some of these steps out of order if you feel it will be better for your application, but we do not recommend doing so unless you are sure you understand the consequences of what you are doing.

Starting up Ogre

Creating the Root Object

The Root object is the core of the Ogre library, and must be created before you can do almost anything with the engine.

We need to add the following class members to our BasicTutorial6 class:

private:
    Ogre::Root* mRoot;
    Ogre::String mPluginsCfg;

Also add the following to the header includes:

#include <OgreRoot.h>

Then, adjust the constructor and the destructor to deal with them:

BasicTutorial6::BasicTutorial6(void)
    : mRoot(0),
    mPluginsCfg(Ogre::StringUtil::BLANK)
{
}
//-------------------------------------------------------------------------------------
BasicTutorial6::~BasicTutorial6(void)
{
    delete mRoot;
}

And then, in BasicTutorial6::go, we create a new Ogre::Root:

bool BasicTutorial6::go(void)
{
#ifdef _DEBUG
    mPluginsCfg = "plugins_d.cfg";
#else
    mPluginsCfg = "plugins.cfg";
#endif
 
    // construct Ogre::Root
    mRoot = new Ogre::Root(mPluginsCfg);
 
    return true;
}

The Ogre::Root's constructor takes 3 parameters:

parameter (Ogre::String) default value description
pluginFileName "plugins.cfg" the name and location of the plugins config file
configFileName "ogre.cfg" the name and location of the ogre config file
(which tells ogre things like the Video card, visual settings, etc)
logFileName "Ogre.log" name and location of the log file that Ogre will write to

We could leave the default values, but in order to make this application work against the precompiled Ogre SDK, where the name of the plugins configuration file differs between debug and release modes, we need to pass our mPluginsCfg parameter to the constructor, so that the name of the configuration file is 'plugins_d.cfg' when running in debug mode.

Go ahead and compile and run your application. :-)
It still looks like it does nothing, but if you open 'Ogre.log' you'll see that Ogre was fired up, initialised and then shut down.
You should also see that it parsed and installed the Ogre plugins listed in the specified plugins file ('plugins.cfg' for Release mode, 'plugins_d.cfg' for Debug mode).

Resources

Note: This section will make a lot more sense if you open "resources.cfg" and take a look at it before continuing; you can find it in the bin/release folder of your SDK. If you're in Debug mode, the file is called resources_d.cfg, and can be found in bin/debug.

The next thing we have to do is define the resources that the application uses.
This includes the textures, models, scripts, and so on.

We will not be going over all there is to know about resources in this tutorial. For now, just keep in mind that you must first define all the resources that you might use during the application, then initialise the specific resources you need before Ogre can use them. In this step, we define all the resources that our application might possibly use.

To do this, we have to add each folder in which resources reside to the ResourceGroupManager.

Add the following class member to our BasicTutorial6 class:

Ogre::String mResourcesCfg;

Then put it in the initialiser list in the constructor, just like we did with 'mPluginsCfg':

BasicTutorial6::BasicTutorial6(void)
	: mRoot(0),
	mResourcesCfg(Ogre::StringUtil::BLANK),
	mPluginsCfg(Ogre::StringUtil::BLANK)

 
We need to include Ogre::ConfigFile to make use of the Ogre config parser utility class.
Put the following at the top of 'BasicTutorial6.cpp':

#include <OgreConfigFile.h>

Now we need to add mResourcesCfg to the debug/release logic at the start of our 'go' function:

bool BasicTutorial6::go(void)
{
#ifdef _DEBUG
    mResourcesCfg = "resources_d.cfg";
    mPluginsCfg = "plugins_d.cfg";
#else
    mResourcesCfg = "resources.cfg";
    mPluginsCfg = "plugins.cfg";
#endif

Like the name of the plugins file, the name of the resources configuration file differs between Debug and Release modes.

Now we're ready to parse some Ogre resources.

Add the following code to BasicTutorial6::go:

// set up resources
// Load resource paths from config file
Ogre::ConfigFile cf;
cf.load(mResourcesCfg);

This uses Ogre's ConfigFile class to parse all of the resources from "resources.cfg", but it does not load them into Ogre (you have to do that manually). Keep in mind that in your own application, you are free to use your own parser and config file formats if you like; just replace Ogre's ConfigFile parser with your own. The method for loading resources doesn't really matter as long as you add the resources to the ResourceGroupManager.

Resources are divided into several sections. Now that we have parsed the config file, we need to add the sections to the ResourceGroupManager. The following code loops through the parsed config file and adds each entry to the ResourceGroupManager by means of its addResourceLocation() function. We will create three strings to extract information from resources.cfg:

  • secName is the name of each section: Essential, Popular, General
  • typeName is the type of the resource being defined: FileSystem (folder) or Zip file
  • archName is an absolute path to the resource

We will use two loops: a while loop for each section, and a for loop to iterate through it and get its resources.

// Go through all sections & settings in the file
Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
 
Ogre::String secName, typeName, archName;
while (seci.hasMoreElements())
{
    secName = seci.peekNextKey();
    Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
    Ogre::ConfigFile::SettingsMultiMap::iterator i;
    for (i = settings->begin(); i != settings->end(); ++i)
    {
        typeName = i->first;
        archName = i->second;
        Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
            archName, typeName, secName);
    }
}

This function we have now filled in adds all of the resources from the config file, but it only tells Ogre where they are.
Before you can use any of them you have to either initialise the group that you want to use, or you must initialise them all.
We will discuss this further in the "Initialising Resources" section.

If you compile and run now, you can see in 'Ogre.log' that Ogre created resource groups and parsed the resources.

Remember to construct mRoot BEFORE adding the resource code, otherwise the compile will fail. -Maythe

 

Creating the RenderSystem

Next we need to choose the RenderSystem (usually either DirectX or OpenGL on a Windows machine) and then configure it. Most of the demo applications use the Ogre config dialog, which is a perfectly reasonable way to set up your application. Ogre also offers a way to restore the configuration that a user has already set, meaning you will never have to configure it after the first time.

First, we need to add a new class member to our BasicTutorial6 class to hold our Ogre::RenderWindow:

Ogre::RenderWindow* mWindow;

 
Then, add the following code to BasicTutorial6::go:

// configure
// Show the configuration dialog and initialise the system
if(!(mRoot->restoreConfig() || mRoot->showConfigDialog()))
{
    return false;
}

In the first part of the if statement, we attempt to restore the config file. If that function returns false, it means that the file does not exist so we should show the config dialog, which is the second portion of the if statement. If that also returns false, it means the user canceled out of the config dialog (meaning they want to exit the program).

In this example we're merely returning false, and thus exiting the program. We could also throw an exception. If you use this technique in practice, I would recommend that if you catch an exception during Ogre's startup, you delete the ogre.cfg file in the catch block; it's possible that the settings the user has chosen in the config dialog have caused a problem and need to be changed.

While you're debugging, turning off the config dialog can help cut down on development time by a small amount, as you won't have to confirm the graphics settings every time you run the program.

Your application may also manually set up the RenderSystem if you choose to use something other than Ogre's config dialog. A basic example of this would be as follows:

// 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", "800 x 600 @ 32-bit colour");

You can use Root::getAvailableRenderers() to find out which RenderSystems are available for your application to use.
Once you have retrieved a RenderSystem, you can use the RenderSystem::getConfigOptions to see what options are available for the user.
By combining these two function calls, you can create your own config dialog for your application.

Creating a RenderWindow

Now that we have chosen the RenderSystem, we need a window to render Ogre in.
There are actually a lot of options for how to do this, but we will really only cover a couple.

If you want Ogre to create a render window for you, then this is very easy to do.
Add the following code to BasicTutorial6::go:

mWindow = mRoot->initialise(true, "BasicTutorial6 Render Window");

This call initialises the RenderSystem we set in the previous section.
The first parameter is whether or not Ogre should create a RenderWindow for you.

Alternatively, you can create a render window yourself using the win32 API, wxWidgets, or one of the many other Windows or Linux GUI systems.
A quick example of how to do this under Windows would look something like this:

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

Note that you still have to call Root::initialise, but the first parameter is set to false.
Then, you must get the HWND of the window you want to render Ogre in.
How you get this will be determined entirely by the GUI toolkit you use to create the window (and under Linux I would imagine this would be a bit different as well).
After you have this, you use the NameValuePairList to assign the handle to "externalWindowHandle".
The Root::createRenderWindow function can then be used to create the RenderWindow class from the window you have already created.
Consult the API documentation on this function for more information.

Initialising Resources

Now we have our Root, RenderSystem and RenderWindow objects created and ready to go. The only thing left to do before we create our scene is initialise the resources we are about to use.

In a very large game or application, we may have hundreds or even thousands of resources for our game to use - everything from meshes to textures to scripts. However, we will probably be using only a small subset of these resources at any given time.

To keep down memory requirements, we can load only the resources that our application is using. We do this by dividing the resources into sections and only initialising them as we go. We will not be covering that in this tutorial, however. See Resources and ResourceManagers for a full tutorial devoted to resources.

Before we initialise the resources, we should also set the default number of mipmaps that textures use; we must set it before we initialise the resources for it to have any effect.

Add the following code to BasicTutorial6::go:

// Set default mipmap level (note: some APIs ignore this)
Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
// initialise all resource groups
Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

The application now has all resource groups initialised and ready to be used.

Creating a Scene

There are three things that must be done before you start adding things to a scene:

  1. Creating the SceneManager.
  2. Creating the Camera.
  3. Creating the Viewport.

 
Before carrying on, let's add some more includes to the top of our BasicTutorial6.cpp file:

#include <OgreCamera.h>
#include <OgreViewport.h>
#include <OgreSceneManager.h>
#include <OgreRenderWindow.h>

 

Creating a SceneManager

First, add a new private data member to the BasicTutorial6 class:

Ogre::SceneManager* mSceneMgr;

And then add the following code to BasicTutorial6::go:

// Create the SceneManager, in this case a generic one
mSceneMgr = mRoot->createSceneManager("DefaultSceneManager");

 

Creating the Camera

First, add a new private data member to the BasicTutorial6 class:

Ogre::Camera* mCamera;

And then add the following code to BasicTutorial6::go:

// Create the camera
mCamera = mSceneMgr->createCamera("PlayerCam");
 
// Position it at 80 in Z direction
mCamera->setPosition(Ogre::Vector3(0,0,80));
// Look back along -Z
mCamera->lookAt(Ogre::Vector3(0,0,-300));
mCamera->setNearClipDistance(5);

 

Adding a Viewport

// Create one viewport, entire window
Ogre::Viewport* vp = mWindow->addViewport(mCamera);
vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
 
// Alter the camera aspect ratio to match the viewport
mCamera->setAspectRatio(
    Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));

You can create as many SceneManagers and Cameras as you like, but when you actually want to render something on the screen using a Camera, you have to add a Viewport for it.

Creating scenes

Let's add something to our scene, now that we've taken care of the basics.

Find the BasicTutorial6::go function and add the following code:

Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh");
 
Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
headNode->attachObject(ogreHead);
 
// Set ambient light
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
 
// Create a light
Ogre::Light* l = mSceneMgr->createLight("MainLight");
l->setPosition(20,80,50);

We need to include OgreEntity for the code to compile error-free, so add this line to the top of 'BasicTutorial6.cpp':

#include <OgreEntity.h>

 

Render Loop - take one

In order to admire our work so far, we need to render our scene.

Ogre::Root features several methods to kick off a render loop, the most simple of which is Ogre::Root::renderOneFrame().
That basically loops until a function in the loop returns false.

Here's what it looks like when it's called in Root::startRendering():

void Root::startRendering(void)
{
    assert(mActiveRenderer != 0);
 
    mActiveRenderer->_initRenderTargets();
 
    // Clear event times
    clearEventTimes();
 
    // Infinite loop, until broken out of by frame listeners
    // or break out by calling queueEndRendering()
    mQueuedEnd = false;
 
    while( !mQueuedEnd )
    {
        //Pump messages in all registered RenderWindow windows
        WindowEventUtilities::messagePump();
 
        if (!renderOneFrame())
            break;
    }
}

We will not go into the gritty details of that function, only point out the renderOneFrame() function.

We briefly looked at this function in Basic Tutorial 4, but let's cover it again:

bool Root::renderOneFrame(void)
{
    if(!_fireFrameStarted())
        return false;
 
        if (!_updateAllRenderTargets())
            return false;
 
    return _fireFrameEnded();
}

Besides updating all render targets, it calls the frame event functions, and if either of those returns false, it will cause the render loop to exit.

Since we're not using any FrameListeners just yet, we need an alternative render loop.

Add this line to the list of includes at the top of our BasicTutorial6.cpp file:

#include <OgreWindowEventUtilities.h>

Put this in the BasicTutorial6::go function:

while(true)
{
    // Pump window messages for nice behaviour
    Ogre::WindowEventUtilities::messagePump();
 
    if(mWindow->isClosed())
    {
        return false;
    }
 
    // Render a frame
    if(!mRoot->renderOneFrame()) return false;
}

It loops over and over, until the window is closed, or the renderOneFrame() function returns false.

Compile and run your application. :-)
You should see a window with an Ogre head in it.
You need to click the close button to exit the application, because we haven't implemented any input functionality yet.

Image

OIS

Though not the only option for input in Ogre, OIS is one of the best.

We will briefly cover how to start up OIS in your application. For the actual uses of the library, you should check the various tutorials on this site (which use it extensively) and the OIS documentation itself.

Put the following includes in BasicTutorial6.h:

#include <OISEvents.h>
#include <OISInputManager.h>
#include <OISKeyboard.h>
#include <OISMouse.h>

Add the following data members to the BasicTutorial6 class:

// OIS Input devices
OIS::InputManager* mInputManager;
OIS::Mouse*    mMouse;
OIS::Keyboard* mKeyboard;

Then we need to add OIS to our project settings:

Include Directory $(OGRE_HOME)/include/OIS
Input Library OIS_d.lib/OIS.lib

The library directory should already be set up.

Make sure you can compile the project after adding OIS to it.

Firing up OIS

OIS uses a general InputManager which is a touch difficult to set up, but easy to use once you have created it properly. OIS does not integrate into Ogre; it's a standalone library, which means that you will need to provide it with some information at the beginning for it to work properly. In practice it really only needs the window handle in which Ogre is rendering. Thankfully, since we have used the automatically created window, Ogre makes this easy for us.

Go to the BasicTutorial6::go function and add this code to it, before our render loop:

Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
OIS::ParamList pl;
size_t windowHnd = 0;
std::ostringstream windowHndStr;
 
mWindow->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr << windowHnd;
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
 
mInputManager = OIS::InputManager::createInputSystem( pl );

This sets up the InputManager for use, but to actually use OIS to get input for the Keyboard, Mouse, or Joystick of your choice, you'll need to create those objects:

mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, false ));
mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, false ));

We are passing 'false' to the createInputObject function because we want mouse and keyboard unbuffered.
Info Note: If you wish to use buffered input (meaning you get event callbacks to mouseMoved, mousePressed, keyReleased, and so on), then you must set the second parameter to createInputObject to be true.

Shutting down OIS

OIS is a bit tricky to shut down properly.
The most failsafe way to do this is by using a WindowEventListener.

First, put this line in your list of includes in BasicTutorial6.h:

#include <OgreWindowEventUtilities.h>

Then we need to change our class declaration to derive from WindowEventListener:

class BasicTutorial6 : public Ogre::WindowEventListener

We want to override WindowEventListener::windowResized and WindowEventListener::windowClosed, so put this in the protected section of the BasicTutorial6 class declaration:

// Ogre::WindowEventListener
virtual void windowResized(Ogre::RenderWindow* rw);
virtual void windowClosed(Ogre::RenderWindow* rw);

Now, open BasicTutorial6.cpp and add the following to it:

//Adjust mouse clipping area
void BasicTutorial6::windowResized(Ogre::RenderWindow* rw)
{
    unsigned int width, height, depth;
    int left, top;
    rw->getMetrics(width, height, depth, left, top);
 
    const OIS::MouseState &ms = mMouse->getMouseState();
    ms.width = width;
    ms.height = height;
}
 
//Unattach OIS before window shutdown (very important under Linux)
void BasicTutorial6::windowClosed(Ogre::RenderWindow* rw)
{
    //Only close for window that created OIS (the main window in these demos)
    if( rw == mWindow )
    {
        if( mInputManager )
        {
            mInputManager->destroyInputObject( mMouse );
            mInputManager->destroyInputObject( mKeyboard );
 
            OIS::InputManager::destroyInputSystem(mInputManager);
            mInputManager = 0;
        }
    }
}

windowResized is called whenever the window is resized, and makes sure that the OIS mouse state is synchronised with the actual size of the window.
windowClosed destroys OIS when the window is closed.

To make our application act as a WindowEventListener, we need to register it as one.
So add these lines to BasicTutorial6::go:

//Set initial mouse clipping size
windowResized(mWindow);
 
//Register as a Window listener
Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);

 
There's one more thing we need to do.
Find the BasicTutorial6 destructor and make it look like this:

//Remove ourself as a Window listener
Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this);
windowClosed(mWindow);
delete mRoot;

 

Setting Up the Framelistener

No matter if you are using buffered or unbuffered input, every frame you must call the capture method on all Keyboard, Mouse, and Joystick objects you use.

For unbuffered input, this is all you need to do.
Every frame you can call the various Keyboard and Mouse functions to query for the state of these objects.

So, we need to make our BasicTutorial6 class become a FrameListener. :-)

Change the class declaration to look like this:

class BasicTutorial6 : public Ogre::WindowEventListener, public Ogre::FrameListener

Then add this function declaration to the protected section of the class declaration:

// Ogre::FrameListener
virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);

And then, in BasicTutorial6.cpp, add this function definition:

bool BasicTutorial6::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
    if(mWindow->isClosed())
        return false;
 
    //Need to capture/update each device
    mKeyboard->capture();
    mMouse->capture();
 
    if(mKeyboard->isKeyDown(OIS::KC_ESCAPE))
        return false;
 
    return true;
}

 

Final Touches

Before we're ready to compile and run our application, we need to register our application as a FrameListener.
And we don't need a custom render loop either.

Find BasicTutorial6::go and remove the while loop.
Then add this to it:

mRoot->addFrameListener(this);
 
mRoot->startRendering();

The first line of code adds the BasicTutorial6 instance to mRoot as a FrameListener, meaning that it will receive frame events.
If we don't register our class as a FrameListener with the Root object, the frameRenderingQueued() function will never be called.

The second line of code starts the rendering loop. We don't really need any special handling of the loop since we can perform our per-frame tasks in the frameRenderingQueued() function.

Compile and run! :-D
You should see the familiar Ogre head in an Ogre RenderWindow, and you should be able to exit the application by pressing the Escape key.

Mac OS X

Cocoa version

The new way to set up the current wiki tutorial framework for xcode in Mac OS X is much shorter and easy to understand.
Make sure your project is created as a cocoa application and changed the extension to .mm from .cpp and copy both resources and plugins cfg to your copy resource phase in your xcode target
Now change the following from

#ifdef _DEBUG
    mResourcesCfg = "resources_d.cfg";
    mPluginsCfg = "plugins_d.cfg";
#else
    mResourcesCfg = "resources.cfg";
    mPluginsCfg = "plugins.cfg";
#endif

to

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
	std::string mResourcePath = [[[NSBundle mainBundle] resourcePath] cStringUsingEncoding:NSUTF8StringEncoding];
#endif
#ifdef _DEBUG
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
    mResourcesCfg = mResourcePath + "/resources_d.cfg";
    mPluginsCfg = mResourcePath + "/plugins_d.cfg";
#else
    mResourcesCfg = "resources_d.cfg";
    mPluginsCfg = "plugins_d.cfg";
#endif
#else
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
    mResourcesCfg = mResourcePath + "/resources.cfg";
    mPluginsCfg = mResourcePath + "/plugins.cfg";
#else
    mResourcesCfg = "resources.cfg";
    mPluginsCfg = "plugins.cfg";
#endif

 

Carbon version

Since Mac OS X uses app bundles, a concept radically different from what is used on Windows and Linux, the code described above is going to crash on Mac OS X.

  • Add the following function:
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
 #include <CoreFoundation/CoreFoundation.h>
 
 // This function will locate the path to our application on OS X,
 // unlike windows you cannot rely on the current working directory
 // for locating your configuration files and resources.
 std::string macBundlePath()
 {
     char path[1024];
     CFBundleRef mainBundle = CFBundleGetMainBundle();
     assert(mainBundle);
 
     CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);
     assert(mainBundleURL);
 
     CFStringRef cfStringRef = CFURLCopyFileSystemPath( mainBundleURL, kCFURLPOSIXPathStyle);
     assert(cfStringRef);
 
     CFStringGetCString(cfStringRef, path, 1024, kCFStringEncodingASCII);
 
     CFRelease(mainBundleURL);
     CFRelease(cfStringRef);
 
     return std::string(path);
 }
 #endif
  • In createRoot(), change
mRoot = new Root();

to

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
     mRoot = new Root(macBundlePath() + "/Contents/Resources/plugins.cfg");
 #else
     mRoot = new Root();
 #endif
  • In defineResources(), change
cf.load("resources.cfg");

to

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
     cf.load(macBundlePath() + "/Contents/Resources/resources.cfg");	
 #else
     cf.load("resources.cfg");		
 #endif
  • Also in defineResources(), change
Ogre::ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName);

to

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
     Ogre::ResourceGroupManager::getSingleton().addResourceLocation( String(macBundlePath() + "/" + archName), typeName, secName);
 #else
     Ogre::ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName);
 #endif

 
Proceed to Basic Tutorial 7 CEGUI and Ogre


Alias: Basic_Tutorial_6


Contributors to this page: Maythe7 points  , shjohnsonpi16 points  , peters181 points  , pencilcheck91 points  , Latin1598 points  , Jaevko only 132 points  , jacmoe133512 points  , Harkathmaker244 points  , chisser98423 points  and breakpointer158 points  .
Page last modified on Monday 23 of January, 2012 03:46:34 UTC by Maythe7 points .


The content on this page is licensed under the terms of the Creative Commons Attribution-ShareAlike License.
As an exception, any source code contributed within the content is released into the Public Domain.