History: MadMarx Tutorial 1
Source of version: 7
Copy to clipboard
!Foreword.
If you prefer tutorials that come with a framework => check the other wiki tutorial series.
If you prefer tutorials that go step by step without a framework => this page should be ok.
I assume you know C++. If not, this tutorial will probably be hard to understand !
This tutorial presents only a few elements of Ogre3D.
You can download the code and media for this tutorial at the bottom of this wiki page.
This little tutorial is an extract of a bigger project which contains more tutorials & helper classes.
This bigger project is avaible there :
https://sourceforge.net/projects/so3dtools/
Also, make sure you read these tutorials in order!
{maketoc}
!!Tutorial Description
In this program, we will just aim to show a window.
This is done in a few steps. Please note you don't need to understand all that to make a very good program.
These informations are provided in case you are interested to know how to do things from scratch.
STEP 1/ First, we will need to create the Ogre::Root object.
It is an object that must be created to use ogre correctly, and delete once we are finished using Ogre.
STEP 2/ Then we need to load plugins. It means that there are functions that are stored inside dynamic libraries.
These libraries are .dll or .so files. Most projects Ogre Project do not need all functions to be usable.
That way, only a subset of all function can be loaded. It also means you can create your own plugins if you want.
If you want to know more on the subject, you 'll need to dig into a C++ tutorial.
Anyway, for our use, we will need to load at least a 'RenderSystem' plugin, which means something to drive opengl or directx.
The basic plugins you are the most likely to use are the RenderSystems, the particle FX and the Cgprogram.
STEP 3/ Then, we can select from the loaded plugin the unique RenderSystem we want to use.
STEP 4/ When the RenderSystem is selected, we can initialise the Root. The root can be initialised only when a rendersystem has been selected.
STEP 5/ Then we can ask to the RenderSystem to create a window.
!!Before the main
These are some files that we need to include to use Ogre3D. Note that you can at the beginnings use directly "Ogre.h", to include lots of commonly used classes.
{CODE(wrap="1",colors="c++")}
¤#include "OGRE/OgreRoot.h"
#include "OGRE/OgreRenderSystem.h"
#include "OGRE/OgreRenderWindow.h"
#include "OGRE/OgreWindowEventUtilities.h"
{CODE}
I will use std::auto_ptr so I need to include 'memory'.
If you don't know std::auto_ptr, you should check some C++ tutorials/lesson on this matter.
{CODE(wrap="1",colors="c++")}
¤#include <memory>
{CODE}
I will check for std::exception. If you don't know what exception/try/catch means, you should learn C++ first.
{CODE(wrap="1",colors="c++")}
¤#include <exception>
{CODE}
!!In the main
!!!!Step 1
STEP 1/ First, we will need to create the Ogre::Root object.
It is an object that must be created to use ogre correctly, and delete once we are finished using Ogre.
This is the name of an optionnal textual configuration file for the rendersystem.
I won't use it.
{CODE(wrap="1",colors="c++")}
¤ Ogre::String lConfigFileName = "";
{CODE}
This is the name of an optionnal textual configuration file, which lists the available plugins.
I won't use it.
{CODE(wrap="1",colors="c++")}
¤ Ogre::String lPluginsFileName = "";
{CODE}
This is the name of the log file. A log file is a file in which you can write things during the program execution.
Ogre use it to display general informations about the rendersystem.
You are not obliged to generate one, and ogre can even transmit the log data to you own class if you want.
Here we only ask the root to create the file.
{CODE(wrap="1",colors="c++")}
¤ Ogre::String lLogFileName = "Tutorial_Ogre.LOG";
{CODE}
I create the root and I wrap it in an auto_ptr so that it will be automatically released.
Now I can even do "throw std::bad_alloc("bad alloc");", the program will release the root smoothly.
{CODE(wrap="1",colors="c++")}
¤ std::auto_ptr<Ogre::Root> lRoot(
new Ogre::Root(lConfigFileName, lPluginsFileName, lLogFileName));
{CODE}
!!!!Step 2
STEP 2/ Then we need to load plugins. It means that there are functions that are stored inside dynamic libraries.
These libraries are .dll or .so files. Most projects Ogre Project do not need all functions to be usable.
That way, only a subset of all function can be loaded. It also means you can create your own plugins if you want.
If you want to know more on the subject, you 'll need to dig into a C++ tutorial.
Anyway, for our use, we will need to load at least a 'RenderSystem' plugin, which means something to drive opengl or directx.
The basic plugins you are the most likely to use are the RenderSystems, the particle FX and the Cgprogram.
Ogre uses Ogre::String (which is a typedef) to represent strings.
Here I use a typedef. If you don't know what it means, you should learn C++ basics first.
Same if you don't know what std::vector is.
{CODE(wrap="1",colors="c++")}
¤ typedef std::vector<Ogre::String> Strings;
{CODE}
Here I list all the plugins I want to load.
I let those I don't want to use in comments.
Opengl rendersystem is supposed to work everywhere.
But in reality a rendersystem may fail on your computer.
It is likely do to bad/old graphic card driver/installation,
or too old directx version on windows (try update).
Often, when one rendersystem fail, the other at least kind-a-work.
I put them in a std::vector, because then I can factorise operations and calls (do a 'for').
{CODE(wrap="1",colors="c++")}
¤ Strings lPluginNames;
lPluginNames.push_back("RenderSystem_GL");
{CODE}
{CODE(wrap="1",colors="c++")}
¤ lPluginNames.push_back("Plugin_ParticleFX");
lPluginNames.push_back("Plugin_CgProgramManager");
{CODE}
{CODE(wrap="1",colors="c++")}
¤ lPluginNames.push_back("Plugin_OctreeSceneManager");
{CODE}
{CODE(wrap="1",colors="c++")}
¤ {
Strings::iterator lIter = lPluginNames.begin();
Strings::iterator lIterEnd = lPluginNames.end();
for(;lIter != lIterEnd; lIter++)
{
Ogre::String& lPluginName = (*lIter);
{CODE}
In debug mode, the plugins names are differents, they got a '_d' at the end.
So I add it. This is the main reason why I needed to put plugins names in a vector.
A macro or a function would have done the trick too...
{CODE(wrap="1",colors="c++")}
¤ bool lIsInDebugMode = OGRE_DEBUG_MODE;
if(lIsInDebugMode)
{
lPluginName.append("_d");
}
lRoot->loadPlugin(lPluginName);
}
}
{CODE}
!!!!Step 3
STEP 3/ Then, we can select from the loaded plugin the unique RenderSystem we want to use.
the root provide a method if you want to select
the rendersystem and its options visually (lRoot->showConfigDialog()).
in that case, you don't need to set the render system manually
{CODE(wrap="1",colors="c++")}
¤ const Ogre::RenderSystemList& lRenderSystemList = lRoot->getAvailableRenderers();
if( lRenderSystemList.size() == 0 )
{
Ogre::LogManager::getSingleton().logMessage("Sorry, no rendersystem was found.");
return 1;
}
Ogre::RenderSystem *lRenderSystem = lRenderSystemList[0];
lRoot->setRenderSystem(lRenderSystem);
{CODE}
!!!!Step 4
STEP 4/ When the RenderSystem is selected, we can initialise the Root. The root can be initialised only when a rendersystem has been selected.
I can create a window automatically, but I won't do it.
{CODE(wrap="1",colors="c++")}
¤ bool lCreateAWindowAutomatically = false;
{CODE}
name of the automatically generated window. empty for me.
{CODE(wrap="1",colors="c++")}
¤ Ogre::String lWindowTitle = "";
{CODE}
custom capabilities of the rendersystem. It's a feature for advanced use.
{CODE(wrap="1",colors="c++")}
¤ Ogre::String lCustomCapacities = "";
lRoot->initialise(lCreateAWindowAutomatically, lWindowTitle, lCustomCapacities);
{CODE}
!!!!Step 5
STEP 5/ Then we can ask to the RenderSystem to create a window.
{CODE(wrap="1",colors="c++")}
¤ Ogre::RenderWindow* lWindow = NULL;
{
Ogre::String lWindowTitle = "Hello Ogre World";
unsigned int lSizeX = 800;
unsigned int lSizeY = 600;
{CODE}
I don't want to use fullscreen during development.
{CODE(wrap="1",colors="c++")}
¤ bool lFullscreen = false;
{CODE}
This is just an example of parameters that we can put. Check the API for more details.
{CODE(wrap="1",colors="c++")}
¤ Ogre::NameValuePairList lParams;
{CODE}
fullscreen antialiasing. (check wikipedia if needed).
{CODE(wrap="1",colors="c++")}
¤ lParams["FSAA"] = "0";
{CODE}
vertical synchronisation will prevent some image-tearing, but also
will provide smooth framerate in windowed mode.(check wikipedia if needed).
{CODE(wrap="1",colors="c++")}
¤ lParams["vsync"] = "true";
lWindow = lRoot->createRenderWindow(lWindowTitle, lSizeX, lSizeY, lFullscreen, &lParams);
}
{CODE}
!!!!Step 6
I wait until the window is closed.
The "message pump" thing is something you will see in most GUI application.
It allow the binding of messages between the application and the OS.
These messages are most of the time : keystroke, mouse moved, ... or window closed.
If I don't do this, the message are never caught, and the window won't close.
{CODE(wrap="1",colors="c++")}
¤ while(!lWindow->isClosed())
{
Ogre::WindowEventUtilities::messagePump();
}
Ogre::LogManager::getSingleton().logMessage("end of the program");
{CODE}
!!!!Encapsulating errors in try catch
This try/catch will catch potential exception launched by ogre or by my program.
Ogre can launch 'Ogre::Exception' for example.
{CODE(wrap="1",colors="c++")}
¤ try
{
{CODE}
{CODE(wrap="1",colors="c++")}
¤ }catch(Ogre::Exception &e)
{
std::cout<<"!!!!Ogre::Exception!!!!"<<e.what()<<std::endl;
}catch(std::exception &e)
{
std::cout<<"!!!!std::exception!!!!"<<e.what()<<std::endl;
}
{CODE}
! main.cpp
{CODE(wrap="1",colors="c++")}
//
// Copyright (c) 2007-2010, 'Madmarx' from the ogre3D forums (ogre3D.org).
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of its author nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ------------------------------------------------------------------------------//
// ------------------------------------------------------------------------------//
// In this program, we will just aim to show a window.
// This is done in a few steps. Please note you don't need to understand all that to make a very good program.
// These informations are provided in case you are interested to know how to do things from scratch.
// STEP 1/ First, we will need to create the Ogre::Root object.
// It is an object that must be created to use ogre correctly, and delete once we are finished using Ogre.
// STEP 2/ Then we need to load plugins. It means that there are functions that are stored inside dynamic libraries.
// These libraries are .dll or .so files. Most projects Ogre Project do not need all functions to be usable.
// That way, only a subset of all function can be loaded. It also means you can create your own plugins if you want.
// If you want to know more on the subject, you 'll need to dig into a C++ tutorial.
// Anyway, for our use, we will need to load at least a 'RenderSystem' plugin, which means something to drive opengl or directx.
// The basic plugins you are the most likely to use are the RenderSystems, the particle FX and the Cgprogram.
// STEP 3/ Then, we can select from the loaded plugin the unique RenderSystem we want to use.
// STEP 4/ When the RenderSystem is selected, we can initialise the Root. The root can be initialised only when a rendersystem has been selected.
// STEP 5/ Then we can ask to the RenderSystem to create a window.
// These are some files that we need to include to use Ogre3D. Note that you can at the beginnings use directly "Ogre.h", to include lots of commonly used classes.
#include "OGRE/OgreRoot.h"
#include "OGRE/OgreRenderSystem.h"
#include "OGRE/OgreRenderWindow.h"
#include "OGRE/OgreWindowEventUtilities.h"
// I will use std::auto_ptr so I need to include 'memory'.
// If you don't know std::auto_ptr, you should check some C++ tutorials/lesson on this matter.
#include <memory>
// I will check for std::exception. If you don't know what exception/try/catch means, you should learn C++ first.
#include <exception>
int main()
{
// This try/catch will catch potential exception launched by ogre or by my program.
// Ogre can launch 'Ogre::Exception' for example.
try
{
// STEP 1/ First, we will need to create the Ogre::Root object.
// It is an object that must be created to use ogre correctly, and delete once we are finished using Ogre.
// This is the name of an optionnal textual configuration file for the rendersystem.
// I won't use it.
Ogre::String lConfigFileName = "";
// This is the name of an optionnal textual configuration file, which lists the available plugins.
// I won't use it.
Ogre::String lPluginsFileName = "";
// This is the name of the log file. A log file is a file in which you can write things during the program execution.
// Ogre use it to display general informations about the rendersystem.
// You are not obliged to generate one, and ogre can even transmit the log data to you own class if you want.
// Here we only ask the root to create the file.
Ogre::String lLogFileName = "Tutorial_Ogre.LOG";
// I create the root and I wrap it in an auto_ptr so that it will be automatically released.
// Now I can even do "throw std::bad_alloc("bad alloc");", the program will release the root smoothly.
std::auto_ptr<Ogre::Root> lRoot(
new Ogre::Root(lConfigFileName, lPluginsFileName, lLogFileName));
// STEP 2/ Then we need to load plugins. It means that there are functions that are stored inside dynamic libraries.
// These libraries are .dll or .so files. Most projects Ogre Project do not need all functions to be usable.
// That way, only a subset of all function can be loaded. It also means you can create your own plugins if you want.
// If you want to know more on the subject, you 'll need to dig into a C++ tutorial.
// Anyway, for our use, we will need to load at least a 'RenderSystem' plugin, which means something to drive opengl or directx.
// The basic plugins you are the most likely to use are the RenderSystems, the particle FX and the Cgprogram.
{
// Ogre uses Ogre::String (which is a typedef) to represent strings.
// Here I use a typedef. If you don't know what it means, you should learn C++ basics first.
// Same if you don't know what std::vector is.
typedef std::vector<Ogre::String> Strings;
// Here I list all the plugins I want to load.
// I let those I don't want to use in comments.
// Opengl rendersystem is supposed to work everywhere.
// But in reality a rendersystem may fail on your computer.
// It is likely do to bad/old graphic card driver/installation,
// or too old directx version on windows (try update).
// Often, when one rendersystem fail, the other at least kind-a-work.
// I put them in a std::vector, because then I can factorise operations and calls (do a 'for').
Strings lPluginNames;
lPluginNames.push_back("RenderSystem_GL");
//lPluginNames.push_back("RenderSystem_Direct3D9");
lPluginNames.push_back("Plugin_ParticleFX");
lPluginNames.push_back("Plugin_CgProgramManager");
//lPluginNames.push_back("Plugin_PCZSceneManager");
//lPluginNames.push_back("Plugin_OctreeZone");
lPluginNames.push_back("Plugin_OctreeSceneManager");
//lPluginNames.push_back("Plugin_BSPSceneManager");
{
Strings::iterator lIter = lPluginNames.begin();
Strings::iterator lIterEnd = lPluginNames.end();
for(;lIter != lIterEnd; lIter++)
{
Ogre::String& lPluginName = (*lIter);
// In debug mode, the plugins names are differents, they got a '_d' at the end.
// So I add it. This is the main reason why I needed to put plugins names in a vector.
// A macro or a function would have done the trick too...
bool lIsInDebugMode = OGRE_DEBUG_MODE;
if(lIsInDebugMode)
{
lPluginName.append("_d");
}
lRoot->loadPlugin(lPluginName);
}
}
}
// STEP 3/ Then, we can select from the loaded plugin the unique RenderSystem we want to use.
{
// the root provide a method if you want to select
// the rendersystem and its options visually (lRoot->showConfigDialog()).
// in that case, you don't need to set the render system manually
const Ogre::RenderSystemList& lRenderSystemList = lRoot->getAvailableRenderers();
if( lRenderSystemList.size() == 0 )
{
Ogre::LogManager::getSingleton().logMessage("Sorry, no rendersystem was found.");
return 1;
}
Ogre::RenderSystem *lRenderSystem = lRenderSystemList[0];
lRoot->setRenderSystem(lRenderSystem);
}
// STEP 4/ When the RenderSystem is selected, we can initialise the Root. The root can be initialised only when a rendersystem has been selected.
{
// I can create a window automatically, but I won't do it.
bool lCreateAWindowAutomatically = false;
// name of the automatically generated window. empty for me.
Ogre::String lWindowTitle = "";
// custom capabilities of the rendersystem. It's a feature for advanced use.
Ogre::String lCustomCapacities = "";
lRoot->initialise(lCreateAWindowAutomatically, lWindowTitle, lCustomCapacities);
}
// STEP 5/ Then we can ask to the RenderSystem to create a window.
Ogre::RenderWindow* lWindow = NULL;
{
Ogre::String lWindowTitle = "Hello Ogre World";
unsigned int lSizeX = 800;
unsigned int lSizeY = 600;
//I don't want to use fullscreen during development.
bool lFullscreen = false;
// This is just an example of parameters that we can put. Check the API for more details.
Ogre::NameValuePairList lParams;
// fullscreen antialiasing. (check wikipedia if needed).
lParams["FSAA"] = "0";
// vertical synchronisation will prevent some image-tearing, but also
// will provide smooth framerate in windowed mode.(check wikipedia if needed).
lParams["vsync"] = "true";
lWindow = lRoot->createRenderWindow(lWindowTitle, lSizeX, lSizeY, lFullscreen, &lParams);
}
// I wait until the window is closed.
// The "message pump" thing is something you will see in most GUI application.
// It allow the binding of messages between the application and the OS.
// These messages are most of the time : keystroke, mouse moved, ... or window closed.
// If I don't do this, the message are never caught, and the window won't close.
while(!lWindow->isClosed())
{
Ogre::WindowEventUtilities::messagePump();
}
Ogre::LogManager::getSingleton().logMessage("end of the program");
}catch(Ogre::Exception &e)
{
std::cout<<"!!!!Ogre::Exception!!!!"<<e.what()<<std::endl;
}catch(std::exception &e)
{
std::cout<<"!!!!std::exception!!!!"<<e.what()<<std::endl;
}
return 0;
}
{CODE}