This tutorial aims to show how to quickly get started with Ogre3D 1.7 running on Mac OS X.

0. Getting Ogre3D
This is how I got up and running with a compiled and up-to-date version of Ogre.

  1. If you don’t have Mercurial installed, get it and install it from http://mercurial.selenic.com/
  2. Download the latest stable branch using hg clone http://bitbucket.org/sinbad/ogre/ -u v1-7
  3. Ensure you have the latest build of freetype, boost and freeimage using:
    sudo port install freetype +universal boost +universal freeimage +universal
  4. Generate the XCode files using:
    cmake -G Xcode -D CMAKE_XCODE_ATTRIBUTE_GCC_VERSION=4.0 .
    This uses GCC 4.0 in order to work around a compiler issue.
  5. Open the newly generated OGRE.xcodeproj and build it.

1. Getting started
The very bare bones basics to get OGRE running.

  1. Open XCode and create a new Cocoa Application.
  2. Once done drag the Ogre.framework and RenderSystem_GL.dylib into the project’s frameworks group.
  3. To make the app self contained. Add a new Copy Files Build Phase that copies into Frameworks, and add the Ogre.framework to it.
  4. Add a new Copy Files Build Phase that copies into Plugins, and add the RenderSystem_GL.dylib to it.
  5. Remove the window from the nib file and references in the app delegate, we don’t need it for now.
  6. Rename the default app delegate class to be a .mm file so that it compiles ObjC++.
  7. Enter this basic code outline for initalising Ogre:

    #import "OgreTutorial1AppDelegate.h"
    #import <Ogre/Ogre.h>
 
    using namespace Ogre;
 
    @implementation OgreTutorial1AppDelegate
 
    - (void)applicationDidFinishLaunching:(NSNotification *)notification
    {
        std::string mResourcePath = [[[NSBundle mainBundle] resourcePath]
            cStringUsingEncoding:NSUTF8StringEncoding];
 
        // Create a new root object with the correct paths
        Root *mRoot = new Root(mResourcePath + "/plugins.cfg", mResourcePath + "/ogre.cfg",
            mResourcePath + "/ogre.log");
        mRoot->setRenderSystem(mRoot->getAvailableRenderers().front());
 
        // Show a configure box and exit if user clicked cancel
        if(!mRoot->showConfigDialog())
            return;
 
        // Initialise
        RenderWindow *mWindow = mRoot->initialise(true);
        SceneManager *mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "My scene manager");
 
        // Create the camera, node & attach camera
        Camera *mCamera = mSceneMgr->createCamera("My camera");
        SceneNode *camNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
        camNode->attachObject(mCamera);
        mWindow->addViewport(mCamera);
    }
 
    @end
  1. Lastly create a new empty file called plugins.cfg. This is the configure file that tells OGRE what plugins to load. Enter “Plugin=RenderSystem_GL” in the blank file. And make sure it is included in the Copy Bundle Resources build phase.
  2. Enjoy the results:

  1. Download it here: OgreTutorial1.zip.

2. Adding resources and entities

A black screen is not very exciting. Ogre can do much more, we provide a start by adding some simple resources and creating something to look at.

  1. First add the resources to the project for the knot: knot.material knot.mesh and MtlPlat2.jpg These are the material defenition file, the 3D mesh and the texture for the entity we will create. Make sure all three resources are included in the Copy Bundle Resources build phase. These are included in the download.
  2. Next we add the code to load the resources, after initalising the Root object.

    // Add resource locations -- looking at folders recursively
    ResourceGroupManager::getSingleton().addResourceLocation(mResourcePath,
        std::string("FileSystem"), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, false);
    ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
  1. Lastly we create a light and an Ogre entity out of the knot at (0,0,-500).
    // Create a light
    mSceneMgr->setAmbientLight(ColourValue(0, 0, 0));
    mSceneMgr->createLight("MainLight");
 
    // Add a object, give it it's own node
    SceneNode *objectNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    Entity *knot = mSceneMgr->createEntity("knot", "knot.mesh");
    objectNode->attachObject(knot);
    objectNode->setPosition(Vector3(0, 0, -500));
  1. Looking better:

  1. Download it here: OgreTutorial2.zip.

3. Animation
At the moment the 3D view only redraws as you resize the window. To make it move, we add a timer that causes some animation and updates the window.

  1. Add a timer to fire calling renderFrame every 50th of a second:

    // create a timer that causes OGRE to render at 50fps
    [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(renderFrame)
        userInfo:NULL repeats:YES];
  1. Add the method renderFrame that renders a single frame and updates the object.
    - (void)renderFrame
    {
        Ogre::Root::getSingleton().renderOneFrame();
        objectNode->rotate(Vector3(0, 1, 0), Radian(0.01));
    }
  1. Download it here: OgreTutorial3.zip.

4. In your own nib file
Ogre can fit seamlessly in your own interface, inbetween all sorts of controls with multiple views. I needed to apply this patch to Ogre to make this work.

  1. Open up the MainMenu.nib file again, and create a new window, filling it with a custom view that stretches with the window. Make sure the window is set to be visible on launch.
  2. Create a new class OgreView by subclassing NSView and set the class of the new view you created to OgreView. Throw in some other interface bits for fun.

  1. Add an ogreView outlet to the `OgreController` class in Interface Builder connecting it up to the newly created view. Also add the outlet to the OgreController.h file.
  2. You will need to import the Ogre/OgreOSXView.h header file to reference the `OgreView` class.
  3. Replace this code that automatically creates windows
// Show a configure box and exit if user clicked cancel
if(!mRoot->showConfigDialog())
    return;
 
// Initialise
RenderWindow* mWindow = mRoot->initialise(true);

…with this code that uses an OgreView we pass in ourselves.

// Initialise without an automatically created window
mRoot->initialise(false);
 
// Ask for a new window passing in the ogreView in our nib file
NameValuePairList misc;
misc["externalWindowHandle"] = StringConverter::toString((size_t)ogreView);
mRoot->createRenderWindow("ogre window", 0, 0, false, &misc);
RenderWindow *mWindow = [ogreView ogreWindow];
  1. Have some fun with the interface. Hook up the components with bindings to control different aspects of the scene.
  2. Add the timer to other run loops to get animation whilst using controls.
NSTimer *renderTimer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self
    selector:@selector(renderFrame) userInfo:NULL repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:renderTimer forMode:NSEventTrackingRunLoopMode];
  1. Download it here: OgreTutorial4.zip.