Skip to main content
Tutorial Introduction
Ogre Tutorial Head

This tutorial will not use the Ogre Wiki Tutorial Framework. Instead, we are going to show you how to get an application up and running without the help of the additional class. After this tutorial, you should have a basic understanding of most of the code that was hidden in the BaseApplication class.

The full source for this tutorial is here.

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

IMPORTANT: This framework is meant to be used with old releases of Ogre. For Ogre >= 1.10, rather use OgreBites::ApplicationContext.


Prerequisites

This tutorial assumes that you already know how to set up an Ogre project and compile it successfully. If you need help with this, then read Setting Up An Application. This tutorial is also part of the Basic Tutorials series and knowledge from the previous tutorials will be assumed.

If you have been using a project created for the tutorial framework, then make sure to remove the BaseApplication files. We will not be using them for this tutorial. For instance, if you're building with CMake, then you will need to remove the lines that include those files in your CMakeLists.txt. If you're using an IDE, then you should be able to remove the files from the project just by deleting them.

ogrehead_visual.png

Getting Started

We will start from scratch with this tutorial. This code should compile successfully and exit immediately.

TutorialApplication.h
Copy to clipboard
class TutorialApplication { public: TutorialApplication(); virtual ~TutorialApplication(); bool go(); };
TutorialApplication.cpp
Copy to clipboard
#include "TutorialApplication.h" #include <OgreException.h> TutorialApplication::TutorialApplication() { } TutorialApplication::~TutorialApplication() { } bool TutorialApplication::go() { return true; } // MAIN FUNCTION OMITTED

The Ogre Startup Process

We are going to give a brief overview of the Ogre startup process. In the previous tutorials, we have used the Ogre Wiki Tutorial Framework to take care of a large part of this process. In this tutorial, we will build an Ogre application from scratch. This will give you greater control over how your application runs. Remember that the tutorial framework is for teaching purposes only. Your own applications should not be organized like the framework.

The basic Ogre life cycle looks like this:

  1. Create the Ogre::Root object
  2. Define the resources that Ogre will use
  3. Choose and set up the RenderSystem (DirectX, OpenGL, etc)
  4. Create the RenderWindow
  5. Set up any third party libraries and plugins.
  6. Initialise resources
  7. Register listener classes
  8. Build a scene
  9. Start the render loop

This tutorial will cover each of these steps in some depth. This order is not absolutely necessary. The first four steps should be done in this order, but you can experiment with the rest if it suits your application's design better. Just make sure you understand the basics of the process before you begin making any drastic changes. For instance, you don't want to try and use a resource before it is initialised.

Creating the Root Object

In some ways, the Ogre::Root object will be our new BaseApplication framework. Everything that is done by the root object can be done manually. It allows us to initialize the core Ogre system with very little effort.

The first thing we'll do is add an Ogre::Root member to our class along with two Strings that will be used during setup. Add the following to the private section of the TutorialApplication header:

TutorialApplication.h
Copy to clipboard
Ogre::Root* mRoot; Ogre::String mResourcesCfg; Ogre::String mPluginsCfg;

We also need to include the header that provides Ogre::Root.

TutorialApplication.h
Copy to clipboard
#include <OgreRoot.h>

After that add the initialization and cleanup to the implementation file.

TutorialApplication.cpp
Copy to clipboard
TutorialApplication::TutorialApplication() : mRoot(0), mResourcesCfg(Ogre::StringUtil::BLANK), mPluginsCfg(Ogre::StringUtil::BLANK) { } TutorialApplication::~TutorialApplication() { delete mRoot; }

Now we will construct an instance of the root object, but first we need to define the strings that identify the resource and plugin configuration files. We use the preprocessor flag _DEBUG to make sure we are using the appropriate files for each build. The root object takes the plugin filename as its first parameter. Add the following to go:

Copy to clipboard
#ifdef _DEBUG mResourcesCfg = "resources_d.cfg"; mPluginsCfg = "plugins_d.cfg"; #else mResourcesCfg = "resources.cfg"; mPluginsCfg = "plugins.cfg"; #endif mRoot = new Ogre::Root(mPluginsCfg);

The constructor for Ogre::Root takes 3 parameters:

Parameter: Default Value:
Ogre::String pluginFileName "plugins.cfg"
Ogre::String configFileName "ogre.cfg"
Ogre::String logFileName "Ogre.log"
Unable to load the jQuery Sortable Tables feature.

We have overriden the default value for the plugin config file so that it will switch to the debug version when built in debug mode using a precompiled Ogre SDK.

Compile and run your application. It still looks like it does nothing, but if you look in your 'bin' directory, you'll find a new 'Ogre.log' file that should have recorded a large amount of information about Ogre starting up and loading plugins. We haven't gone anywhere yet, but the motor is humming...

Setting Up Resources

We are now going to set up our applications resources. You should open up your project's 'resources.cfg' file. If you're using the SDK, then this will be in your 'bin/release' or 'bin/debug' directory. If you built Ogre from source, then most likely this file will be in the 'bin' directory right next to your executable.

The 'resources.cfg' file lets Ogre know where it should look for potential resources. Ogre does not initialize all of these resources during this step. We will do that later. Looking at the file, we can see it is essentially a list of directories. Here is the file that is being used to write these tutorials:

Copy to clipboard
# Resources required by the sample browser and most samples. [Essential] Zip=../media/packs/SdkTrays.zip # Resource locations to be added to the default path [General] FileSystem=../media FileSystem=../media/materials/scripts FileSystem=../media/materials/textures FileSystem=../media/models

One important thing to note is that Ogre will not automatically search sub-directories. From the example, you can see that including '../media' did not prevent us from having to include '../media/materials/scripts'.

For the next step, we need to include Ogre::ConfigFile.

TutorialApplication.cpp
Copy to clipboard
#include <OgreConfigFile.h>

We already set up the resources string when we created the root object. Now we will create a Ogre::ConfigFile object and use it to parse our cfg file. Add the following to go after we create the root object:

Copy to clipboard
Ogre::ConfigFile cf; cf.load(mResourcesCfg);

You are free to use your own config file formats and parser. To do this, simply replace Ogre's ConfigFile parser with your own.

If you look back to your 'resources.cfg' file, you will see that they are divided into sections like [Essential]. Now that we have the information loaded from the cfg file, we have to add these sections and their list of locations to the ResourceGroupManager.

The first thing we will do is define two strings we will use to gather information from the parsed config file.

Copy to clipboard
Ogre::String name, locType;

The name parameter is the path to the resources (i.e. "../media"). The locType parameter defines what kind of location this is (i.e. Filesystem, Zip, etc.)
To get started, we will ask for a SectionIterator. This will allow us to iterate through all of the sections discovered by the parser.

Copy to clipboard
Ogre::ConfigFile::SectionIterator secIt = cf.getSectionIterator();

We will now iterate through all of the results.

Copy to clipboard
while (secIt.hasMoreElements()) {

Now, inside of this loop we are going to ask for another iterator that will let us iterate through the items in each section.

Copy to clipboard
^ Ogre::ConfigFile::SettingsMultiMap* settings = secIt.getNext(); Ogre::ConfigFile::SettingsMultiMap::iterator it;

Each section is returned as a SettingsMultiMap. This is Ogre's implementation of a multimap which contains pairs of settings. The "multi" part means it can contain multiple elements all with the same key. This is what we want here, because the key is the location type, and many of our locations will have the same type. We also set up an iterator to read through these pairs.

Now we will start another loop to scan through each item with this iterator.

Copy to clipboard
^ for (it = settings->begin(); it != settings->end(); ++it) {

We will now unpack each pair. The first object will be a string representing the location type of this resource, and the second argument will be the path.

Copy to clipboard
^ locType = it->first; name = it->second;

Finally, we will use these two strings to add this location to our ResourceGroupManager using the addResourceLocation method.

Copy to clipboard
^ Ogre::ResourceGroupManager::getSingleton().addResourceLocation(name, locType); } }

Keep in mind that this only lets Ogre know where to look for the resources. We still have to initialize the particular resources we actually need later in the tutorial.

Compile and run your application. It still isn't doing much, but now your 'Ogre.log' should contain information about adding the resource locations.

Configuring the RenderSystem

The next thing we will do is choose which RenderSystem to use. DirectX or OpenGL will be the most popular options, but they are not the only choices and you can even add additional systems. The demo applications that come with Ogre all use the config dialog to allow the user to make choices about their render settings. We will use this same approach. In your own applications, you might want to incorporate this into a settings menu that can also handle other things like keybindings.

The first thing we will do is create a RenderWindow instance. Add the following to go right after our resource code:

Copy to clipboard
Ogre::RenderWindow* mWindow;

The BaseApplication class from the tutorial framework always shows the config dialog. We can do a little better than this. We can make it so that the dialog will only be shown if there is no 'ogre.cfg' file present. This way we can set the options once and speed up our startup time. In your own applications, you would want to add a little to this method, because you want your user to be able to reset these settings if they need to without manually deleting 'ogre.cfg'.

Copy to clipboard
if(!(mRoot->restoreConfig() || mRoot->showConfigDialog())) return false;

The first call in the if statement tries to restore our configuration from an existing cfg file. If that fails, then we show the config dialog. The || statement will do what is called "short-circuit evaluation". The showConfigDialog call will only be executed if the restoreConfig call fails. The if statement will only return false if both of these calls return false.

You could also choose to throw an exception instead of just returning false and exiting the application. If you do throw an exception, then you should try to delete any 'ogre.cfg' file that exists in the catch block, because it is possible the settings the user chose are causing the problem.

It is also possible to manually set up the RenderSystem. This would be helpful if you were designing your own settings menu. Here is a simple example of setting up a Direct3D9 RenderSystem:

Copy to clipboard
// Do not add this to your project RenderSystem* rs = mRoot->getRenderSystemByName("Direct3D9 Rendering Subsystem"); mRoot->setRenderSystem(rs); rs->setConfigOption("Full Screen", "No"); rs->setConfigOption("Video Mode", "800 x 600 @ 32-bit colour");

The method Root::getAvailableRenderers will let your know what is currently available on your system. Once you have a pointer to the RenderSystem, you can use RenderSystem::getConfigOptions to see what options it provides.

Creating a RenderWindow

Now we will initialise a window for our application to be rendered in. This is another thing that we can ask the Root object to take care of. First, add the RenderWindow include to your project.

Copy to clipboard
#include "OgreRenderWindow.h"

Then add the following to go right after our configuration code:

Copy to clipboard
mWindow = mRoot->initialise(true, "TutorialApplication Render Window");

This call initialises the RenderSystem we chose in the previous step. The first parameter determines whether or not Ogre will create a RenderWindow for us.

We could also create a window using the win32 API, wxWidgets, or any other windowing system. Here is a quick example of how to do this under Windows:

Copy to clipboard
// Do not add this to your project mRoot->initialise(false); HWND hWnd = 0; // Retrieve the HWND for the window we want to render in. // This step depends entirely on the windowing system you are using. NameValuePairList misc; misc["externalWindowHandle"] = StringConverter::toString((int)hWnd); RenderWindow* win = mRoot->createRenderWindow("Main RenderWindow", 800, 600, false, &misc);

You can see that we still need to call Root::initialise, but the first parameter is set to false. We then call Root::createRenderWindow to directly assign our render window using the information we've gathered.

Initialising Resources

In a very large application, we may have thousands of resources. This can include meshes, textures, and scripts. However, at any given time, we will probably only be using a small subset of those resources. To help manage memory use, we will try to only initialise resources when we need them. For further reading on this topic, you can read Resources and ResourceManagers.

Before we initialise our resources, let's set the default number of mipmaps to be used. These are the lower resolution versions of textures used to produce different "level of detail" (LOD) for a texture, depending on how far it is away from the Camera. Continue adding to go.

Copy to clipboard
Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);

Now we'll call a single method from the ResourceGroupManager singleton that will initialise all of the resources found by Ogre.

Copy to clipboard
Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

That's it.

Creating a SceneManager

As we described in the early tutorials, we need a SceneManager to...manage the scene. First, add this include to your class:

Copy to clipboard
#include <OgreSceneManager.h>

Then we need a SceneManager data member.

Copy to clipboard
Ogre::SceneManager* mSceneMgr;

Now we ask the Root object to create the manager for us in go.

Copy to clipboard
mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC);

The Ogre namespace defines a series of SceneManager types that all start with "ST_". We've chosen the default, generic manager.

Creating the Camera

Now we will add a Camera to our project. Include the Camera class.

Copy to clipboard
#include <OgreCamera.h>

Add a Camera member.

Copy to clipboard
Ogre::Camera* mCamera;

And set it up in the go method.

Copy to clipboard
mCamera = mSceneMgr->createCamera("MainCam"); mCamera->setPosition(0, 0, 80); mCamera->lookAt(0, 0, -300)); mCamera->setNearClipDistance(5);

Other than needing to ask the SceneManager to create the Camera, this should all be familiar from past tutorials.

Adding a Viewport

The last thing we need before setting up our scene is a viewport. Include the class.

Copy to clipboard
#include "OgreViewport.h"

Now we will declare the viewport and create it in the go method.

Copy to clipboard
Ogre::Viewport* vp = mWindow->addViewport(mCamera); vp->setBackgroundColour(Ogre::ColourValue(0,0,0)); mCamera->setAspectRatio( Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));

This should also be familiar from past tutorials. We need a viewport to actually see a camera's viewpoint rendered on the screen.

Setting Up the Scene

We're ready to add something to our scene! None of this should be new to you by now. Make sure to include the Entity class.

Copy to clipboard
#include <OgreEntity.h>

Now we'll add an Ogre head, some ambient light, and a point light to our scene.

Copy to clipboard
Ogre::Entity* ogreEntity = mSceneMgr->createEntity("ogrehead.mesh"); Ogre::SceneNode* ogreNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); ogreNode->attachObject(ogreEntity); mSceneMgr->setAmbientLight(Ogre::ColourValue(.5, .5, .5)); Ogre::Light* light = mSceneMgr->createLight("MainLight"); light->setPosition(20, 80, 50);

That does it for our basic scene.

An Initial Rendering Loop

We still have to get the rendering started somehow. The first thing we will try is calling Root::renderOneFrame in a while loop. We briefly looked at this function in Basic Tutorial 4.

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

Now we need to set up our render loop. First, include this header:

Copy to clipboard
#include <OgreWindowEventUtilities.h>

Now we will add the following to the end of go:

Copy to clipboard
while(true) { Ogre::WindowEventUtilities::messagePump(); if(mWindow->isClosed()) return false; if(!mRoot->renderOneFrame()) return false; }

This will loop infinitely until the window is closed or the renderOneFrame method returns false. The messagePump call basically updates the RenderWindow.

Compile and run your application. You should see the familiar Ogre head rendered in your window. You have to exit by pressing the close button on the window. We will add back input in the next section.

The Object-Oriented Input System (OIS)

One good option for adding input to Ogre is the Object-Oriented Input System. We will now provide an introduction to initialising OIS to work with Ogre. For more information, reference the OIS documentation.

Let's include the OIS headers in TutorialApplication.h.

Copy to clipboard
#include <OISEvents.h> #include <OISInputManager.h> #include <OISKeyboard.h> #include <OISMouse.h>

Now add the following data members to your class.

Copy to clipboard
OIS::InputManager* mInputManager; OIS::Mouse* mMouse; OIS::Keyboard* mKeyboard;

Also, remember to include the OIS library in your project. If you're using the CMake script from the tutorial framework, then it is already attempting to find OIS and including everything. If you're working with an IDE, then you'll need to add these settings to your project:

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

Compile and run your application. Make sure adding OIS hasn't caused any problems.

Initialising 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:

Copy to clipboard
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:

Copy to clipboard
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

Note: This is very important when building on linux.

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:

Copy to clipboard
#include <OgreWindowEventUtilities.h>

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

Copy to clipboard
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:

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

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

Copy to clipboard
//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:

Copy to clipboard
//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:

Copy to clipboard
//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:

Copy to clipboard
class BasicTutorial6 : public Ogre::WindowEventListener, public Ogre::FrameListener

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

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

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

Copy to clipboard
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; }

Registering Our FrameListener

Before we're ready to compile and run our application, we need to register our application as a FrameListener.
We don't need a custom render loop either. Find BasicTutorial6::go and remove the while loop. Then add this to it:

Copy to clipboard
mRoot->addFrameListener(this);

This line 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.

Replacing Our Custom Render Loop

This 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.

Copy to clipboard
mRoot->startRendering();

Compile and run! ๐Ÿ˜€
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.

Notes About 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

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

to

Copy to clipboard
#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:
Copy to clipboard
#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
Copy to clipboard
mRoot = new Root();

to

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

to

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

to

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

Conclusion

Now you should have a basic understanding of how to create your own simple Ogre application.

Full Source

The full source for this tutorial is here.

Next

Basic Tutorial 7


Alias: Basic_Tutorial_6