OGRE Wiki
Support and community documentation for Ogre3D
Ogre Forums
ogre3d.org
Log in
Username:
Password:
CapsLock is on.
Remember me (for 1 year)
Log in
Home
Tutorials
Tutorials Home
Basic Tutorials
Intermediate Tutorials
Mad Marx Tutorials
In Depth Tutorials
Older Tutorials
External Tutorials
Cookbook
Cookbook Home
CodeBank
Snippets
Experiences
Ogre Articles
Libraries
Libraries Home
Alternative Languages
Assembling A Toolset
Development Tools
OGRE Libraries
List of Libraries
Tools
Tools Home
DCC Tools
DCC Tutorials
DCC Articles
DCC Resources
Assembling a production pipeline
Development
Development Home
Roadmap
Building Ogre
Installing the Ogre SDK
Setting Up An Application
Ogre Wiki Tutorial Framework
Frequently Asked Questions
Google Summer Of Code
Help Requested
Ogre Core Articles
Community
Community Home
Projects Using Ogre
Recommended Reading
Contractors
Wiki
Immediate Wiki Tasklist
Wiki Ideas
Wiki Guidelines
Article Writing Guidelines
Wiki Styles
Wiki Page Tracker
Ogre Wiki Help
Ogre Wiki Help Overview
Help - Basic Syntax
Help - Images
Help - Pages and Structures
Help - Wiki Plugins
Toolbox
Freetags
Categories
List Pages
Structures
Trackers
Statistics
Rankings
List Galleries
Ogre Lexicon
Comments
History: Basic Tutorial 6
View page
Source of version: 137
(current)
{TRANSCLUDE(page="tutbox")}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 ((BasicTutorial6SourceCurrent|here)).{TRANSCLUDE} %tutorialhelp% {DIV(class="achtung")}__IMPORTANT:__ This framework is meant to be used with old releases of Ogre. For Ogre >= 1.10, rather use [https://ogrecave.github.io/ogre/api/latest/setup.html#skeleton|OgreBites::ApplicationContext].{DIV} !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. {img fileId="2297" rel="box[g]"} {maketoc} !Getting Started We will start from scratch with this tutorial. This code should compile successfully and exit immediately. {CODE(caption="TutorialApplication.h" wrap="1", colors="c++")} class TutorialApplication { public: TutorialApplication(); virtual ~TutorialApplication(); bool go(); }; {CODE} {CODE(caption="TutorialApplication.cpp" wrap="1", colors="c++")} #include "TutorialApplication.h" #include <OgreException.h> TutorialApplication::TutorialApplication() { } TutorialApplication::~TutorialApplication() { } bool TutorialApplication::go() { return true; } // MAIN FUNCTION OMITTED {CODE} !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: # Create the Ogre::Root object # Define the resources that Ogre will use # Choose and set up the RenderSystem (DirectX, OpenGL, etc) # Create the RenderWindow # Set up any third party libraries and plugins. # Initialise resources # Register listener classes # Build a scene # 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: {CODE(caption="TutorialApplication.h" wrap="1", colors="c++")} Ogre::Root* mRoot; Ogre::String mResourcesCfg; Ogre::String mPluginsCfg; {CODE} We also need to include the header that provides Ogre::Root. {CODE(caption="TutorialApplication.h" wrap="1", colors="c++")} #include <OgreRoot.h> {CODE} After that add the initialization and cleanup to the implementation file. {CODE(caption="TutorialApplication.cpp" wrap="1", colors="c++")} TutorialApplication::TutorialApplication() : mRoot(0), mResourcesCfg(Ogre::StringUtil::BLANK), mPluginsCfg(Ogre::StringUtil::BLANK) { } TutorialApplication::~TutorialApplication() { delete mRoot; } {CODE} 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 {MONO()}_DEBUG{MONO} 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 {MONO()}go{MONO}: {CODE(wrap="1", colors="c++")} #ifdef _DEBUG mResourcesCfg = "resources_d.cfg"; mPluginsCfg = "plugins_d.cfg"; #else mResourcesCfg = "resources.cfg"; mPluginsCfg = "plugins.cfg"; #endif mRoot = new Ogre::Root(mPluginsCfg); {CODE} The constructor for {MONO()}Ogre::Root{MONO} takes 3 parameters: {FANCYTABLE()} Parameter: | Default Value: {MONO()}Ogre::String pluginFileName{MONO} | "plugins.cfg" {MONO()}Ogre::String configFileName{MONO} | "ogre.cfg" {MONO()}Ogre::String logFileName{MONO} | "Ogre.log"{FANCYTABLE} 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: {CODE(wrap="1" colors="ini")} # 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 {CODE} 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. {CODE(caption="TutorialApplication.cpp" wrap="1", colors="c++")} #include <OgreConfigFile.h> {CODE} 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 {MONO()}go{MONO} after we create the root object: {CODE(wrap="1", colors="c++")} Ogre::ConfigFile cf; cf.load(mResourcesCfg); {CODE} 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 [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_resource_group_manager.html|ResourceGroupManager]. The first thing we will do is define two strings we will use to gather information from the parsed config file. {CODE(wrap="1" colors="c++")} Ogre::String name, locType; {CODE} The {MONO()}name{MONO} parameter is the path to the resources (i.e. "../media"). The {MONO()}locType{MONO} 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. {CODE(wrap="1" colors="c++")} Ogre::ConfigFile::SectionIterator secIt = cf.getSectionIterator(); {CODE} We will now iterate through all of the results. {CODE(wrap="1" colors="c++")} while (secIt.hasMoreElements()) { {CODE} Now, inside of this loop we are going to ask for another iterator that will let us iterate through the items in each section. {CODE(wrap="1" colors="c++")} ^ Ogre::ConfigFile::SettingsMultiMap* settings = secIt.getNext(); Ogre::ConfigFile::SettingsMultiMap::iterator it; {CODE} Each section is returned as a SettingsMultiMap. This is Ogre's implementation of a [http://www.cplusplus.com/reference/map/multimap/|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. {CODE(wrap="1" colors="c++")} ^ for (it = settings->begin(); it != settings->end(); ++it) { {CODE} 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. {CODE(wrap="1" colors="c++")} ^ locType = it->first; name = it->second; {CODE} Finally, we will use these two strings to add this location to our ResourceGroupManager using the {MONO()}addResourceLocation{MONO} method. {CODE(wrap="1" colors="c++")} ^ Ogre::ResourceGroupManager::getSingleton().addResourceLocation(name, locType); } } {CODE} 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 {MONO()}go{MONO} right after our resource code: {CODE(wrap="1", colors="c++")} Ogre::RenderWindow* mWindow; {CODE} 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'. {CODE(wrap="1", colors="c++")} if(!(mRoot->restoreConfig() || mRoot->showConfigDialog())) return false; {CODE} 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 ~124~~124~ statement will do what is called "short-circuit evaluation". The {MONO()}showConfigDialog{MONO} call will only be executed if the {MONO()}restoreConfig{MONO} 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: {CODE(wrap="1", colors="c++")} // 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"); {CODE} The method {MONO()}Root::getAvailableRenderers{MONO} will let your know what is currently available on your system. Once you have a pointer to the RenderSystem, you can use {MONO()}RenderSystem::getConfigOptions{MONO} 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. {CODE(wrap="1", colors="c++")} #include "OgreRenderWindow.h" {CODE} Then add the following to {MONO()}go{MONO} right after our configuration code: {CODE(wrap="1", colors="c++")} mWindow = mRoot->initialise(true, "TutorialApplication Render Window"); {CODE} 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: {CODE(wrap="1", colors="c++")} // 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); {CODE} You can see that we still need to call {MONO()}Root::initialise{MONO}, but the first parameter is set to false. We then call {MONO()}Root::createRenderWindow{MONO} 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 ((Mipmapping|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 {MONO()}go{MONO}. {CODE(wrap="1", colors="c++")} Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5); {CODE} Now we'll call a single method from the ResourceGroupManager singleton that will initialise all of the resources found by Ogre. {CODE(wrap="1", colors="c++")} Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); {CODE} 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: {CODE(wrap="1", colors="c++")} #include <OgreSceneManager.h> {CODE} Then we need a SceneManager data member. {CODE(wrap="1", colors="c++")} Ogre::SceneManager* mSceneMgr; {CODE} Now we ask the Root object to create the manager for us in {MONO()}go{MONO}. {CODE(wrap="1", colors="c++")} mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC); {CODE} 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. {CODE(wrap="1", colors="c++")} #include <OgreCamera.h> {CODE} Add a Camera member. {CODE(wrap="1", colors="c++")} Ogre::Camera* mCamera; {CODE} And set it up in the {MONO()}go{MONO} method. {CODE(wrap="1", colors="c++")} mCamera = mSceneMgr->createCamera("MainCam"); mCamera->setPosition(0, 0, 80); mCamera->lookAt(0, 0, -300)); mCamera->setNearClipDistance(5); {CODE} 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. {CODE(wrap="1", colors="c++")} #include "OgreViewport.h" {CODE} Now we will declare the viewport and create it in the {MONO()}go{MONO} method. {CODE(wrap="1", colors="c++")} Ogre::Viewport* vp = mWindow->addViewport(mCamera); vp->setBackgroundColour(Ogre::ColourValue(0,0,0)); mCamera->setAspectRatio( Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight())); {CODE} 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. {CODE(wrap="1", colors="c++")} #include <OgreEntity.h> {CODE} Now we'll add an Ogre head, some ambient light, and a point light to our scene. {CODE(wrap="1", colors="c++")} 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); {CODE} 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 {MONO()}Root::renderOneFrame{MONO} in a while loop. We briefly looked at this function in ((Basic Tutorial 4)). {CODE(wrap="1", colors="c++")} bool Root::renderOneFrame(void) { if(!_fireFrameStarted()) return false; if(!_updateAllRenderTargets()) return false; return _fireFrameEnded(); } {CODE} Now we need to set up our render loop. First, include this header: {CODE(wrap="1", colors="c++")} #include <OgreWindowEventUtilities.h> {CODE} Now we will add the following to the end of {MONO()}go{MONO}: {CODE(wrap="1", colors="c++")} while(true) { Ogre::WindowEventUtilities::messagePump(); if(mWindow->isClosed()) return false; if(!mRoot->renderOneFrame()) return false; } {CODE} This will loop infinitely until the window is closed or the {MONO()}renderOneFrame{MONO} method returns false. The {MONO()}messagePump{MONO} 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 [http://code.joyridelabs.de/ois_api/annotated.html|OIS documentation]. Let's include the OIS headers in TutorialApplication.h. {CODE(wrap="1", colors="c++")} #include <OISEvents.h> #include <OISInputManager.h> #include <OISKeyboard.h> #include <OISMouse.h> {CODE} Now add the following data members to your class. {CODE(wrap="1", colors="c++")} OIS::InputManager* mInputManager; OIS::Mouse* mMouse; OIS::Keyboard* mKeyboard; {CODE} 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: {CODE(wrap="1", colors="c++")} 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 ); {CODE} 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: {CODE(wrap="1", colors="c++")} mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, false )); mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, false )); {CODE} We are passing '''false''' to the createInputObject function because we want mouse and keyboard unbuffered. %note% __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 {MONO()}WindowEventListener{MONO}. First, put this line in your list of includes in {MONO()}BasicTutorial6.h{MONO}: {CODE(wrap="1", colors="c++")} #include <OgreWindowEventUtilities.h> {CODE} Then we need to change our class declaration to derive from {MONO()}WindowEventListener{MONO}: {CODE(wrap="1", colors="c++")} class BasicTutorial6 : public Ogre::WindowEventListener {CODE} We want to override {MONO()}WindowEventListener::windowResized{MONO} and {MONO()}WindowEventListener::windowClosed{MONO}, so put this in the protected section of the BasicTutorial6 class declaration: {CODE(wrap="1", colors="c++")} // Ogre::WindowEventListener virtual void windowResized(Ogre::RenderWindow* rw); virtual void windowClosed(Ogre::RenderWindow* rw); {CODE} Now, open BasicTutorial6.cpp and add the following to it: {CODE(wrap="1", colors="c++")} //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; } } } {CODE} {MONO()}windowResized{MONO} is called whenever the window is resized, and makes sure that the OIS mouse state is synchronised with the actual size of the window. {MONO()}windowClosed{MONO} 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 {MONO()}BasicTutorial6::go{MONO}: {CODE(wrap="1", colors="c++")} //Set initial mouse clipping size windowResized(mWindow); //Register as a Window listener Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); {CODE} There's one more thing we need to do. Find the BasicTutorial6 destructor and make it look like this: {CODE(wrap="1", colors="c++")} //Remove ourself as a Window listener Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this); windowClosed(mWindow); delete mRoot; {CODE} !Setting Up the Framelistener No matter if you are using buffered or unbuffered input, every frame you must call the {MONO()}capture{MONO} 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: {CODE(wrap="1", colors="c++")} class BasicTutorial6 : public Ogre::WindowEventListener, public Ogre::FrameListener {CODE} Then add this function declaration to the protected section of the class declaration: {CODE(wrap="1", colors="c++")} // Ogre::FrameListener virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt); {CODE} And then, in BasicTutorial6.cpp, add this function definition: {CODE(wrap="1", colors="c++")} 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; } {CODE} !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: {CODE(wrap="1", colors="c++")} mRoot->addFrameListener(this); {CODE} 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 {MONO()}frameRenderingQueued(){MONO} 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 {MONO()}frameRenderingQueued(){MONO} function. {CODE(wrap="1", colors="c++")} mRoot->startRendering(); {CODE} 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. !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 {CODE(wrap="1", colors="c++")} #ifdef _DEBUG mResourcesCfg = "resources_d.cfg"; mPluginsCfg = "plugins_d.cfg"; #else mResourcesCfg = "resources.cfg"; mPluginsCfg = "plugins.cfg"; #endif {CODE} to {CODE(wrap="1", colors="c++")} #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 {CODE} !!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: {CODE(wrap="1", colors="c++")} #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{CODE} * In createRoot(), change {CODE(wrap="1", colors="c++")} mRoot = new Root();{CODE} to {CODE(wrap="1", colors="c++")} #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE mRoot = new Root(macBundlePath() + "/Contents/Resources/plugins.cfg"); #else mRoot = new Root(); #endif{CODE} * In defineResources(), change {CODE(wrap="1", colors="c++")} cf.load("resources.cfg");{CODE} to {CODE(wrap="1", colors="c++")} #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE cf.load(macBundlePath() + "/Contents/Resources/resources.cfg"); #else cf.load("resources.cfg"); #endif{CODE} * Also in defineResources(), change {CODE(wrap="1", colors="c++")} Ogre::ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName);{CODE} to {CODE(wrap="1", colors="c++")} #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE Ogre::ResourceGroupManager::getSingleton().addResourceLocation( String(macBundlePath() + "/" + archName), typeName, secName); #else Ogre::ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName); #endif{CODE} !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 ((BasicTutorial6SourceCurrent|here)). !Next ((Basic Tutorial 7)) --- Alias: (alias(Basic_Tutorial_6))
Search by Tags
Search Wiki by Freetags
Latest Changes
Minimal Ogre Collision
Artifex Terra
OpenMB
Advanced Mogre Framework
MogreSocks
Critter AI
Mogre Add-ons
MOGRE
Mogre MyGUI wrapper
MOGRE Editable Terrain Manager
...more
Search
Find
Advanced
Search Help
Online Users
50 online users