Skip to main content
History: Basic Ogre Framework
View published page
Source of version: 36
(current)
{DIV(class="achtung")}__IMPORTANT:__ This framework is meant to be used with old releases of Ogre. For new projects, rather use [https://ogrecave.github.io/ogre/api/1.10/setup.html#skeleton|OgreBites::ApplicationContext].{DIV} {maketoc} !!Introduction Once upon a time a young programmer started discovering the great world of Ogre. He went through the ((Basic Tutorials|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|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 ((Tutorials|Ogre tutorials)). {DIV(class="Layout_box13")}%help% However: If you have any problems, please post in the [http://www.ogre3d.org/forums/viewtopic.php?f=5&t=48491|forum thread for this article].{DIV} {IMG(fileId="1692",thumb="y",rel="box[g]",width="150",align="right",stylebox="border",desc="Basic Ogre Framework",title="Basic Ogre Framework",alt="BasicOgreFramework.jpg")}{IMG} {DIV(class="Bloody_box1")} An example that runs __out-of-the-box__ (without any compiling) can be downloaded from my [https://bitbucket.org/spacegaier/basicogreframework/overview|__BasicOgreFramework BitBucket Hg repository__]. Of course it comes with the source, the needed media as well as with a Microsoft ((-VisualStudio|VisualStudio)) solution file. {DIV} !!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% __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 {DIV(class="Spacegaier_box1")} 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. {DIV} {CODE(wrap="1", colors="c++")}//||||||||||||||||||||||||||||||||||||||||||||||| #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 <OgreFrameListener.h> #include <OISEvents.h> #include <OISInputManager.h> #include <OISKeyboard.h> #include <OISMouse.h> #include <SdkTrays.h> //||||||||||||||||||||||||||||||||||||||||||||||| class OgreFramework : public Ogre::Singleton<OgreFramework>, OIS::KeyListener, OIS::MouseListener, OgreBites::SdkTrayListener { public: OgreFramework(); ~OgreFramework(); bool initOgre(Ogre::String wndTitle, OIS::KeyListener *pKeyListener = 0, OIS::MouseListener *pMouseListener = 0); void updateOgre(double timeSinceLastFrame); 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&); OgreBites::SdkTrayManager* m_pTrayMgr; Ogre::FrameEvent m_FrameEvent; 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 //|||||||||||||||||||||||||||||||||||||||||||||||{CODE} !!OgreFramework.cpp The following code parts form together the OgreFramework.cpp. I'll give some information on the functions: {DIV(class="Spacegaier_box1")} * __First line__: Needed for the [[Singleton]] * __OgreFramework()__: It just sets some default values for the variables {DIV} {CODE(wrap="1", colors="c++")}#include "OgreFramework.hpp" #include <OgreTextureManager.h> using namespace Ogre; template<> OgreFramework* Ogre::Singleton<OgreFramework>::msSingleton = 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_pTrayMgr = 0; m_FrameEvent = Ogre::FrameEvent(); }{CODE} {DIV(class="Spacegaier_box1")} * __initOgre()__: # instantiates the log manager class # creates a new Ogre root # creates the scene manager and set some ambient light # creates the camera and sets its position and clip planes # creates the viewport and sets the background color # creates the input devices # loads the resources # creates the timer # creates the debug overlay # sets the render window active {DIV} {CODE(wrap="1", colors="c++")}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); size_t 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_pTrayMgr = new OgreBites::SdkTrayManager("TrayMgr", m_pRenderWnd, m_pMouse, this); m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT); m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT); m_pTrayMgr->hideCursor(); m_pRenderWnd->setActive(true); return true; }{CODE} {DIV(class="Spacegaier_box1")} * __~OgreFramework()__: Just clears up the whole thing {DIV} {CODE(wrap="1", colors="c++")} OgreFramework::~OgreFramework() { if(m_pInputMgr) OIS::InputManager::destroyInputSystem(m_pInputMgr); if(m_pTrayMgr) delete m_pTrayMgr; if(m_pRoot) delete m_pRoot; }{CODE} {DIV(class="Spacegaier_box1")} * __keyPressed()__: Implements the basic keyboard input handling # leave the application when ''escape'' is pressed # make a screenshot when ''print'' is hit # change polygon mode when 'M' is hit # toggle the frame stats and logo when 'O' is pressed {DIV} {CODE(wrap="1", colors="c++")} 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_pTrayMgr->isLogoVisible()) { m_pTrayMgr->hideLogo(); m_pTrayMgr->hideFrameStats(); } else { m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT); m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT); } } return true; }{CODE} {DIV(class="Spacegaier_box1")} * __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''. {DIV} {CODE(wrap="1", colors="c++")} bool OgreFramework::keyReleased(const OIS::KeyEvent &keyEventRef) { return true; }{CODE} {DIV(class="Spacegaier_box1")} * __mouseMoved()__: This function gets called when the mouse is move and then changes the camera's orientation. {DIV} {CODE(wrap="1", colors="c++")}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; }{CODE} {DIV(class="Spacegaier_box1")} * __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. {DIV} {CODE(wrap="1", colors="c++")}bool OgreFramework::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id) { return true; } bool OgreFramework::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id) { return true; }{CODE} {DIV(class="Spacegaier_box1")} * __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 inject an update event into the SdkTrayManager. {DIV} {CODE(wrap="1", colors="c++")}void OgreFramework::updateOgre(double timeSinceLastFrame) { m_MoveScale = m_MoveSpeed * (float)timeSinceLastFrame; m_RotScale = m_RotateSpeed * (float)timeSinceLastFrame; m_TranslateVector = Vector3::ZERO; getInput(); moveCamera(); m_FrameEvent.timeSinceLastFrame = timeSinceLastFrame; m_pTrayMgr->frameRenderingQueued(m_FrameEvent); }{CODE} {DIV(class="Spacegaier_box1")} * __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. {DIV} {CODE(wrap="1", colors="c++")}void OgreFramework::moveCamera() { if(m_pKeyboard->isKeyDown(OIS::KC_LSHIFT)) m_pCamera->moveRelative(m_TranslateVector); else m_pCamera->moveRelative(m_TranslateVector / 10); }{CODE} {DIV(class="Spacegaier_box1")} * __getInput()__: This function changes the camera translation vector m_TranslateVector accordingly to the keyboard input. {DIV} {CODE(wrap="1", colors="c++")}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; }{CODE} ...page... {maketoc} !!Creating your demo class {DIV(class="Spacegaier_box1")} 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. {DIV} {CODE(wrap="1", colors="c++")}//||||||||||||||||||||||||||||||||||||||||||||||| #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_pOgreHeadNode; Ogre::Entity* m_pOgreHeadEntity; bool m_bShutdown; }; //||||||||||||||||||||||||||||||||||||||||||||||| #endif //|||||||||||||||||||||||||||||||||||||||||||||||{CODE} !!Implementing your demo class {DIV(class="Spacegaier_box1")} This is what your demo class implementation could look like: * __DempApp()__: Constructor * __~DemoApp()__: Destructor * __startDemo()__: # creates a new ''OgreFramework'' # set the shutdown indicator to false (why would we want to shut it down right now?) # calls ''setupDemo()'' and ''runDemo()'' * __setupDemoScene()__: puts some content in our scene # adds a skyBox # creates a light # adds a simple cube mesh * __runDemo()__: the main loop of our application # leaves the application if m_Shutdown is false or if the ''OgreFramework'' wants us to shut down for some reason # calculates the time passed since the last frame # orders the input devices for the keyboard and the mouse to look for new input events # calls the ''updateOgre()'' function # renders one frame # 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 {DIV} {CODE(wrap="1", colors="c++")}DemoApp::DemoApp() { m_pOgreHeadNode = 0; m_pOgreHeadEntity = 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_pOgreHeadEntity = OgreFramework::getSingletonPtr()->m_pSceneMgr->createEntity("OgreHeadEntity", "ogrehead.mesh"); m_pOgreHeadNode = OgreFramework::getSingletonPtr()->m_pSceneMgr->getRootSceneNode()->createChildSceneNode("OgreHeadNode"); m_pOgreHeadNode->attachObject(m_pOgreHeadEntity); } //||||||||||||||||||||||||||||||||||||||||||||||| 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; Ogre::WindowEventUtilities::messagePump(); 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 { #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 Sleep(1000); #else sleep(1); #endif } } 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; } //||||||||||||||||||||||||||||||||||||||||||||||| {CODE} !!The very last thing: main.cpp {DIV(class="Spacegaier_box1")} * 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 {DIV} {CODE(wrap="1", colors="c++")}//||||||||||||||||||||||||||||||||||||||||||||||| #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; } //|||||||||||||||||||||||||||||||||||||||||||||||{CODE} !!Notes __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: {CODE(wrap="1", colors="c++")}#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{CODE} __3.__ In [http://www.ogre3d.org/forums/viewtopic.php?f=5&t=48491&start=75#p354360|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... --- Alias: (alias(Example Framework Demystified)) Alias: (alias(Basic_Ogre_Framework))
Search by Tags
Search Wiki by Freetags
Latest Changes
Compiled API Reference
Overlay Editor
Introduction - JaJDoo Shader Guide - Basics
RT Shader System
RapidXML Dotscene Loader
One Function Ogre
One Function Ogre
...more
Search
Find
Online Users
156 online users
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