Basic Ogre Framework

From Ogre Wiki

Jump to: navigation, search

Contents

Introduction

Once upon a time a young programmer started discovering the great world of Ogre. He went through the first tutorials and was happy that everything worked without lots of code as there was the ExampleApplication.h that made the Ogre beginner's life rather easy. But, suddenly he read somewhere that the way it is done in this example application, isn't the way it is meant to be done (at least not in more advanced applications). So he started searching on the wiki and in the forums and piece-by-piece, he put together his own BasicOgreFramework.

This magic piece of code was capable of starting Ogre, loading the basic resources, reacting to standard keyboard and mouse input by moving the camera, making screen shots as well as showing the standard Ogre overlays with the logo and the FPS counter. From this day on, he always used this Framework when he needed a simple base for a test case or whatever.

As many people have the same problem (as he recognized by following most of the forum threads), he finally decided to put his solution in this great wiki, as his solution was much more complete than the other versions already available. However, he decided not to explain the code that much as it is self-explanatory for everyone that read the first Ogre tutorials.

Image:Forum icon question2.gif However: If you have any problems, please post in the forum thread for this article.
Basic Ogre Framework
Basic Ogre Framework

Update 2010/01/11: The framework was update to work with Ogre 1.7

Note: Not quite true, DebugOverlay has been removed in 1.7 and thus showing it results in a segfault. --Svenstaro 18:40, 17 February 2010 (UTC)

An example that runs out-of-the-box (without any compiling) can be downloaded here from my webspace. Of course it comes with the source, the needed media as well as with a Microsoft VisualStudio solution file.
If this file shouldn't be available anymore (due to a possible restructuring of my website), just send me a PM in the forum.


Architecture

Well, the architecture is rather simple: There is one class, called OgreFramework, that does most of the magic. Just add it to your project. Then you need a second class that is the real application. It calls several functions from the OgreFramework class and also implements the main loop. If you want, you can also make it handle additional input to extend the input handling already implemented.

Note: Don't be scared by the code that looks probably quite a lot to a beginner. However, it is quite easy to understand.


OgreFramework.hpp

That is the header for our OgreFramework class. It contains all the Ogre related variables:

  • Ogre Root
  • Camera
  • RenderWindow
  • Viewport
  • SceneManager
  • Log
  • Timer
  • Input stuff
  • ...

It also has the input handler function (e.g. keyPressed() or mouseMoved() ), that are used to capture some keys for basic camera movement. Apart from that, there are some other members such as a counter for the number of screenshots done while running the application or a variable indicating whether the application is to be shut down.

//|||||||||||||||||||||||||||||||||||||||||||||||

#ifndef OGRE_FRAMEWORK_HPP
#define OGRE_FRAMEWORK_HPP

//|||||||||||||||||||||||||||||||||||||||||||||||

#include <OgreCamera.h>
#include <OgreEntity.h>
#include <OgreLogManager.h>
#include <OgreOverlay.h>
#include <OgreOverlayElement.h>
#include <OgreOverlayManager.h>
#include <OgreRoot.h>
#include <OgreViewport.h>
#include <OgreSceneManager.h>
#include <OgreRenderWindow.h>
#include <OgreConfigFile.h>

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

//|||||||||||||||||||||||||||||||||||||||||||||||

class OgreFramework : public Ogre::Singleton<OgreFramework>, OIS::KeyListener, OIS::MouseListener
{
public:
	OgreFramework();
	~OgreFramework();

	bool initOgre(Ogre::String wndTitle, OIS::KeyListener *pKeyListener = 0, OIS::MouseListener *pMouseListener = 0);
	void updateOgre(double timeSinceLastFrame);
	void updateStats();
	void moveCamera();
	void getInput();

	bool isOgreToBeShutDown()const{return m_bShutDownOgre;}

	bool keyPressed(const OIS::KeyEvent &keyEventRef);
	bool keyReleased(const OIS::KeyEvent &keyEventRef);

	bool mouseMoved(const OIS::MouseEvent &evt);
	bool mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id); 
	bool mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id);
	
	Ogre::Root*				m_pRoot;
	Ogre::SceneManager*			m_pSceneMgr;
	Ogre::RenderWindow*			m_pRenderWnd;
	Ogre::Camera*				m_pCamera;
	Ogre::Viewport*				m_pViewport;
	Ogre::Log*				m_pLog;
	Ogre::Timer*				m_pTimer;
	
	OIS::InputManager*			m_pInputMgr;
	OIS::Keyboard*				m_pKeyboard;
	OIS::Mouse*				m_pMouse;

private:
	OgreFramework(const OgreFramework&);
	OgreFramework& operator= (const OgreFramework&);

	Ogre::Overlay*				m_pDebugOverlay;
	Ogre::Overlay*				m_pInfoOverlay;
	int					m_iNumScreenShots;

	bool					m_bShutDownOgre;
	
	Ogre::Vector3				m_TranslateVector;
	Ogre::Real				m_MoveSpeed; 
	Ogre::Degree				m_RotateSpeed; 
	float					m_MoveScale; 
	Ogre::Degree				m_RotScale;
};

//|||||||||||||||||||||||||||||||||||||||||||||||

#endif 

//|||||||||||||||||||||||||||||||||||||||||||||||

OgreFramework.cpp

The following code parts form together the OgreFramework.cpp. I'll give some information on the functions:

  • First line: Needed for the Singleton
  • OgreFramework(): It just sets some default values for the variables
#include "OgreFramework.hpp"

using namespace Ogre; 

template<> OgreFramework* Ogre::Singleton<OgreFramework>::ms_Singleton = 0;

OgreFramework::OgreFramework()
{
	m_MoveSpeed			= 0.1f;
	m_RotateSpeed		        = 0.3f;

	m_bShutDownOgre		        = false;
	m_iNumScreenShots	        = 0;

	m_pRoot				= 0;
	m_pSceneMgr			= 0;
	m_pRenderWnd		        = 0;
	m_pCamera			= 0;
	m_pViewport			= 0;
	m_pLog				= 0;
	m_pTimer			= 0;

	m_pInputMgr			= 0;
	m_pKeyboard			= 0;
	m_pMouse			= 0;

	m_pDebugOverlay		        = 0;
	m_pInfoOverlay		        = 0;
}
  • initOgre():
  1. instantiates the log manager class
  2. creates a new Ogre root
  3. creates the scene manager and set some ambient light
  4. creates the camera and sets its position and clip planes
  5. creates the viewport and sets the background color
  6. creates the input devices
  7. loads the resources
  8. creates the timer
  9. creates the debug overlay
  10. sets the render window active
bool OgreFramework::initOgre(Ogre::String wndTitle, OIS::KeyListener *pKeyListener, OIS::MouseListener *pMouseListener)
{
	Ogre::LogManager* logMgr = new Ogre::LogManager();
	
	m_pLog = Ogre::LogManager::getSingleton().createLog("OgreLogfile.log", true, true, false);
	m_pLog->setDebugOutputEnabled(true);
	
	m_pRoot = new Ogre::Root();

	if(!m_pRoot->showConfigDialog())
		return false;
	m_pRenderWnd = m_pRoot->initialise(true, wndTitle);

	m_pSceneMgr = m_pRoot->createSceneManager(ST_GENERIC, "SceneManager");
	m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.7f, 0.7f, 0.7f));
	
	m_pCamera = m_pSceneMgr->createCamera("Camera");
	m_pCamera->setPosition(Vector3(0, 60, 60));
	m_pCamera->lookAt(Vector3(0, 0, 0));
	m_pCamera->setNearClipDistance(1);

	m_pViewport = m_pRenderWnd->addViewport(m_pCamera);
	m_pViewport->setBackgroundColour(ColourValue(0.8f, 0.7f, 0.6f, 1.0f));

	m_pCamera->setAspectRatio(Real(m_pViewport->getActualWidth()) / Real(m_pViewport->getActualHeight()));
	
	m_pViewport->setCamera(m_pCamera);

	unsigned long hWnd = 0;
        OIS::ParamList paramList;
        m_pRenderWnd->getCustomAttribute("WINDOW", &hWnd);

	paramList.insert(OIS::ParamList::value_type("WINDOW", Ogre::StringConverter::toString(hWnd)));

	m_pInputMgr = OIS::InputManager::createInputSystem(paramList);

        m_pKeyboard = static_cast<OIS::Keyboard*>(m_pInputMgr->createInputObject(OIS::OISKeyboard, true));
	m_pMouse = static_cast<OIS::Mouse*>(m_pInputMgr->createInputObject(OIS::OISMouse, true));
    
	m_pMouse->getMouseState().height = m_pRenderWnd->getHeight();
	m_pMouse->getMouseState().width	 = m_pRenderWnd->getWidth();

	if(pKeyListener == 0)
		m_pKeyboard->setEventCallback(this);
	else
		m_pKeyboard->setEventCallback(pKeyListener);

	if(pMouseListener == 0)
		m_pMouse->setEventCallback(this);
	else
		m_pMouse->setEventCallback(pMouseListener);

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

	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
        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);
            }
        }
	Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

	m_pTimer = new Ogre::Timer();
	m_pTimer->reset();
	
	m_pDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
	m_pDebugOverlay->show();

	m_pRenderWnd->setActive(true);

	return true;
}
  • ~OgreFramework(): Just clears up the whole thing
OgreFramework::~OgreFramework()
{
	if(m_pInputMgr)
		OIS::InputManager::destroyInputSystem(m_pInputMgr);

	delete m_pRoot;
}
  • keyPressed(): Implements the basic keyboard input handling
  1. leave the application when escape is pressed
  2. make a screenshot when print is hit
  3. change polygon mode when M is hit
  4. toggle the overlay when O is pressed
bool OgreFramework::keyPressed(const OIS::KeyEvent &keyEventRef)
{
	if(m_pKeyboard->isKeyDown(OIS::KC_ESCAPE))
	{
			m_bShutDownOgre = true;
			return true;
	}

	if(m_pKeyboard->isKeyDown(OIS::KC_SYSRQ))
	{
		m_pRenderWnd->writeContentsToTimestampedFile("BOF_Screenshot_", ".png");
		return true;
	}

	if(m_pKeyboard->isKeyDown(OIS::KC_M))
	{
		static int mode = 0;
		
		if(mode == 2)
		{
			m_pCamera->setPolygonMode(PM_SOLID);
			mode = 0;
		}
		else if(mode == 0)
		{
			 m_pCamera->setPolygonMode(PM_WIREFRAME);
			 mode = 1;
		}
		else if(mode == 1)
		{
			m_pCamera->setPolygonMode(PM_POINTS);
			mode = 2;
		}
	}

	if(m_pKeyboard->isKeyDown(OIS::KC_O))
	{
		if(m_pDebugOverlay)
		{
			if(!m_pDebugOverlay->isVisible())
				m_pDebugOverlay->show();
			else
				m_pDebugOverlay->hide();
		}
	}

	return true;
}
  • keyReleased(): Doesn't do anything. It just has to be in there due to the class being inherited from the OIS::MouseListener and OIS::KeyboardListener.
bool OgreFramework::keyReleased(const OIS::KeyEvent &keyEventRef)
{
	return true;
}
  • mouseMoved(): This function gets called when the mouse is move and then changes the camera's orientation.
bool OgreFramework::mouseMoved(const OIS::MouseEvent &evt)
{
	m_pCamera->yaw(Degree(evt.state.X.rel * -0.1f));
	m_pCamera->pitch(Degree(evt.state.Y.rel * -0.1f));
	
	return true;
}
  • mousePressed(): Doesn't do anything. It just has to be in there due to the class being inherited from the OIS::MouseListener and OIS::KeyboardListener
  • mouseReleased(): Same here as above.
bool OgreFramework::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
	return true;
}

bool OgreFramework::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
	return true;
}
  • updateOgre(): The function will be called by our own demo class in the main loop (so for every frame). It calculates the move and rotation scale in order to take into account the time passed since the last frame. It also calls getInput() and moveCamera() as well as updateStats().
void OgreFramework::updateOgre(double timeSinceLastFrame)
{
	m_MoveScale = m_MoveSpeed   * (float)timeSinceLastFrame;
	m_RotScale  = m_RotateSpeed * (float)timeSinceLastFrame;
		
	m_TranslateVector = Vector3::ZERO;

	getInput();
	moveCamera();

	updateStats();
}
  • updateStats(): This function simply updates the overlay with the newest information on the FPS or the triangle count.
void OgreFramework::updateStats() 
{ 
	static String currFps	= "Current FPS: "; 
        static String avgFps	= "Average FPS: "; 
        static String bestFps	= "Best FPS: "; 
        static String worstFps	= "Worst FPS: "; 
        static String tris		= "Triangle Count: "; 
        static String batches	= "Batch Count: "; 
 
        OverlayElement* guiAvg	= OverlayManager::getSingleton().getOverlayElement("Core/AverageFps"); 
        OverlayElement* guiCurr	= OverlayManager::getSingleton().getOverlayElement("Core/CurrFps"); 
        OverlayElement* guiBest	= OverlayManager::getSingleton().getOverlayElement("Core/BestFps"); 
        OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps"); 

	const RenderTarget::FrameStats& stats = m_pRenderWnd->getStatistics(); 
        guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS)); 
        guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS)); 
        guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS) 
            +" "+StringConverter::toString(stats.bestFrameTime)+" ms"); 
        guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS) 
            +" "+StringConverter::toString(stats.worstFrameTime)+" ms"); 

        OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris"); 
        guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount)); 

	OverlayElement* guiBatches = OverlayManager::getSingleton().getOverlayElement("Core/NumBatches"); 
        guiBatches->setCaption(batches + StringConverter::toString(stats.batchCount)); 

	OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText"); 
	guiDbg->setCaption("");
}
  • moveCamera(): This function changes the position of the camera accordingly to the vector m_TranslateVector that is changed by the keyboard input. If shift is pressed, it will move ten times faster than without.
void OgreFramework::moveCamera()
{
	if(m_pKeyboard->isKeyDown(OIS::KC_LSHIFT)) 
		m_pCamera->moveRelative(m_TranslateVector);
	else
		m_pCamera->moveRelative(m_TranslateVector / 10);
}
  • getInput(): This function changes the camera translation vector m_TranslateVector accordingly to the keyboard input.
void OgreFramework::getInput()
{
	if(m_pKeyboard->isKeyDown(OIS::KC_A))
		m_TranslateVector.x = -m_MoveScale;
	
	if(m_pKeyboard->isKeyDown(OIS::KC_D))
		m_TranslateVector.x = m_MoveScale;
	
	if(m_pKeyboard->isKeyDown(OIS::KC_W))
		m_TranslateVector.z = -m_MoveScale;
	
	if(m_pKeyboard->isKeyDown(OIS::KC_S))
		m_TranslateVector.z = m_MoveScale;
}

Creating your demo class

All that is missing now is your own demo class that only needs some content. It might look like this:

  • some functions to start, setup and run the Demo
  • a pointer to an OgreFramework instance
  • an entity and a scene node
  • a boolean variable to show whether the demo should be shut down

Note: By inheriting from OIS::KeyListener and passing our demo class as a parameter to the initOgre() method, we can extend the input handling from the OgreFramework class by reacting to the inputs events in the keyPressed() and keyReleased() functions. The keyPressed() and keyReleased() function of OgreFramework are not called by OIS in this case, so we must call them from keyPressed() and keyReleased() in the DemoApp instead.

//|||||||||||||||||||||||||||||||||||||||||||||||

#ifndef OGRE_DEMO_HPP
#define OGRE_DEMO_HPP

//|||||||||||||||||||||||||||||||||||||||||||||||

#include "OgreFramework.hpp"

//|||||||||||||||||||||||||||||||||||||||||||||||

class DemoApp : public OIS::KeyListener
{
public:
	DemoApp();
	~DemoApp();

	void startDemo();
	
	bool keyPressed(const OIS::KeyEvent &keyEventRef);
	bool keyReleased(const OIS::KeyEvent &keyEventRef);

private:
        void setupDemoScene();
	void runDemo();

	Ogre::SceneNode*			m_pCubeNode;
	Ogre::Entity*				m_pCubeEntity;

	bool					m_bShutdown;
};

//|||||||||||||||||||||||||||||||||||||||||||||||

#endif 

//|||||||||||||||||||||||||||||||||||||||||||||||

Implemeting your demo class

This is what your demo class implementation could look like:

  • DempApp(): Constructor
  • ~DemoApp(): Destructor
  • startDemo():
  1. creates a new OgreFramework
  2. set the shutdown indicator to false (why would we want to shut it down right now?)
  3. calls setupDemo() and runDemo()
  • setupDemoScene(): puts some content in our scene
  1. adds a skyBox
  2. creates a light
  3. adds a simple cube mesh
  • runDemo(): the main loop of our application
  1. leaves the application if m_Shutdown is false or if the OgreFramework wants us to shut down for some reason
  2. calculates the time passed since the last frame
  3. orders the input devices for the keyboard and the mouse to look for new input events
  4. calls the updateOgre() function
  5. renders one frame
  6. if the render window is not active (does not have the focus), the application sleeps for a second
  • keyPressed(): you can define here own input handling stuff, as e.g. move the cube in our scene
  • keyReleased(): same as above
DemoApp::DemoApp()
{
	m_pCubeNode		= 0;
	m_pCubeEntity		= 0;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

DemoApp::~DemoApp()
{
       delete OgreFramework::getSingletonPtr();
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void DemoApp::startDemo()
{
	new OgreFramework();
	if(!OgreFramework::getSingletonPtr()->initOgre("DemoApp v1.0", this, 0))
		return;

	m_bShutdown = false;

	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Demo initialized!");
	
	setupDemoScene();
	runDemo();
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void DemoApp::setupDemoScene()
{
	OgreFramework::getSingletonPtr()->m_pSceneMgr->setSkyBox(true, "Examples/SpaceSkyBox");

	OgreFramework::getSingletonPtr()->m_pSceneMgr->createLight("Light")->setPosition(75,75,75);

	m_pCubeEntity = OgreFramework::getSingletonPtr()->m_pSceneMgr->createEntity("Cube", "ogrehead.mesh");
	m_pCubeNode = OgreFramework::getSingletonPtr()->m_pSceneMgr->getRootSceneNode()->createChildSceneNode("CubeNode");
	m_pCubeNode->attachObject(m_pCubeEntity);
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void DemoApp::runDemo()
{
	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Start main loop...");
	
	double timeSinceLastFrame = 0;
	double startTime = 0;
	
      OgreFramework::getSingletonPtr()->m_pRenderWnd->resetStatistics();

	while(!m_bShutdown && !OgreFramework::getSingletonPtr()->isOgreToBeShutDown()) 
	{
		if(OgreFramework::getSingletonPtr()->m_pRenderWnd->isClosed())m_bShutdown = true;

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
		Ogre::WindowEventUtilities::messagePump();
#endif	
		if(OgreFramework::getSingletonPtr()->m_pRenderWnd->isActive())
		{
			startTime = OgreFramework::getSingletonPtr()->m_pTimer->getMillisecondsCPU();
					
			OgreFramework::getSingletonPtr()->m_pKeyboard->capture();
			OgreFramework::getSingletonPtr()->m_pMouse->capture();

			OgreFramework::getSingletonPtr()->updateOgre(timeSinceLastFrame);
			OgreFramework::getSingletonPtr()->m_pRoot->renderOneFrame();
		
			timeSinceLastFrame = OgreFramework::getSingletonPtr()->m_pTimer->getMillisecondsCPU() - startTime;
		}
		else
		{
			Sleep(1000);
		}
	}

	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Main loop quit");
	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Shutdown OGRE...");
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool DemoApp::keyPressed(const OIS::KeyEvent &keyEventRef)
{
	OgreFramework::getSingletonPtr()->keyPressed(keyEventRef);
	
	if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_F))
	{
		 //do something
	}

	return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool DemoApp::keyReleased(const OIS::KeyEvent &keyEventRef)
{
	OgreFramework::getSingletonPtr()->keyReleased(keyEventRef);
	
	return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

The very last thing: main.cpp

  • first of all: you don't have to understand this!
  • the only important parts are the two lines where an instance of our DemoApp is created and the startDemo() function is called
//|||||||||||||||||||||||||||||||||||||||||||||||

#include "DemoApp.hpp"

//|||||||||||||||||||||||||||||||||||||||||||||||

#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
      {
		DemoApp demo;
		demo.startDemo();
      }
	catch(std::exception& e)
      {
#if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
        MessageBoxA(NULL, e.what(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
        fprintf(stderr, "An exception has occurred: %s\n", e.what());
#endif
      }

    return 0;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

Note

1. If you want to, you can declare all the Ogre members in the OgreFramework class (Root, Camera, RenderWindow, SceneManager, ...) private and implement getter methods for them. This is mostly a matter of code style and one's preferences. You could also totally remove most of them as they are also singletons (e.g. Ogre::Root, Ogre::Log) and retrieve them via the singleton functions. It's up to you!

2. If Ogre::WindowEventUtilities::messagePump() doesn't work for you, try this instead:

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
{
   MSG msg;
   while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
   {
       if (msg.message == WM_QUIT)
          m_bShutdown = true;
       else
       {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
       }
   }
}
#endif

3. On Mac, the Sleep() function is written with a lower-case S at the beginning, so you either have to change this or (if you want both in your code) use this instead:

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
   Sleep(1000);
#elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE
   sleep(1000);
#endif

4. In this forum post you will find a list of all needed changes in order to get this running with XCode on Mac.

Conclusion

So that's it! It's not that much magic as it looks like. In fact it's no magic at all... just one possible way to have a simple and clean framework to use as a starting point.

Of course, you may alter and modify it to your needs. The young Ogre programmer from the top of the page wishes you good luck...

Personal tools
administration