Introduction

Once upon a time, a young programmer eager to explore the world of 3D graphics, started wandering around looking for a powerful magician to help him. For a long time he crossed the country from one side to another and back again, until he finally gave up and sat down at side of a old, rugged road. He was sad, really sad...and disappointed that he hasn't been able to reach his wonderful dream.

While he was sitting there in the grass, quarreling with himself, a rather ugly, green Ogre came along the street. He was in a very good mood, whistling a song with a big grin on his face, reaching from one cheek to the other. That's when he saw the poor young programmer boy. Sincerely appalled, he asked what in the world made him so sad and the boy told him his whole story. But instead of becoming also sad and grieve when hearing this sorrowful story, the Ogre grinned even more and said:

Quote:
"Boy, this must be your lucky day. You just met the perfect guy! I'm not as nice as the magician you dreamed of helping you, but I am way more powerful. I can render you anything and teach you all the secrets of 3D graphics! Boy, come on! Is no good waiting here when you have a whole new world in front of you!"

That said, the little programmer boy jumped up and flung his arms around the Ogre's neck and almost kissed him, but suddenly realized that...well...kissing an Ogre is not how you should behave...

By the time, the Ogre taught the young boy everything he knew, starting with the first basic tutorials and later even leaving the devil ExampleApplication.h beyond him. But at some point, this wasn't enough anymore. He wanted more:

  • A game state system
  • a graphical user interface
  • different input modes
  • scene loading and
  • manual material manipulation.


Hopefully he stared up to the Ogres face almost waiting for it telling him, that this is more than he can tell him, but the Ogre only grinned and said:

Quote:
"I know the perfect secret book for you. It will totally fulfill all your wishes...It's called: The Advanced Ogre Framework!"


And not only has he qualified himself for this kind of advanced knowledge, but also you are ready to be introduced in these magic circles. Just read on...

An example that runs out-of-the-box (without any compiling) can be downloaded from my AdvancedOgreFramework BitBucket Hg repository. Of course it comes with the source, the needed media as well as with a Microsoft VisualStudio solution file.

help If you should encounter any problems while reading, please post in the forum thread for this article.

Note: An older version of the framework made by a forum user for Ogre 1.7.1 and CEGUI 0.7.1 can be found here.

Advanced Ogre Framework - Menu state
Advanced Ogre Framework - Menu state
Advanced Ogre Framework - Game state
Advanced Ogre Framework - Game state


Architecture

Well, the architecture may seem awfully complex, but it isn't that hard to get through it. I will try to explain most of it and with a little bit of patience, everyone should make their way through it.

The whole project consists of 17 header and source files, but: Don't be scared by this huge number! One of these files is the main.cpp, which is as always neither big nor complex and two others won't even be posted here as they are just the two files from the RapidXML DotSceneLoader. That makes 14 more to cope with.

Another pair is the basic Ogre initialization part, similar to the BasicOgreFramework.hpp / .cpp, with almost nothing new in it and of course another pair called DemoApp.hpp / .cpp being the central organization point with just a few lines of code.

The biggest and most complex part is the remaining 10 files that form together the application state system. But since htere are three different application states in this demo framework, many code parts are redundant and just copied from one state to the other. So the actual amount a "unique code lines to understand" isn't that high!



Application state system

For the application state system, I basically used a variation of the approach shown here, however with some minor changes. Generally, the whole system works like this:

For each application state we want to use in our program, we create an own class inheriting AppState.hpp. So each application state has the same basic functions like enter, exit, pause, resume and update as well its own Camera and SceneManager.

The second important part of this system is the AppStateManager.hpp. Its task is to manage all the game states and connect them. To do so, the manager has a stack of active states and always executes the one on top of this stack. At any time, you can then put another state on the stack that is then used until it is popped from the stack. In this case, the manager resumes executing the state that was below the one just removed. As soon as there aren't any active states left, the manager closes the whole application.

main.cpp

Let's start with the simplest: the main.cpp. Nothing surprising here.

All that is done is to create an instance of our DemoApp class and call its startDemo() function. That's it.

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

#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
{
	DemoApp demo;
	try	
	{
		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;
}

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



DotSceneLoader

As mentioned above, I won't show this code here, as it is already on the RapidXML DotSceneLoader page. I just copied these two files from there:

  • DotSceneLoader.hpp
  • DotSceneLoader.cpp

In order to make them work you also need to include rapidxml.hpp (more information of the DotSceneLoader page).



AdvancedOgreFramework.hpp

This OgreFramework class is the equivalent to the equally named one of the Basic Ogre Framework. It has the needed functions to power up Ogre and offers the standard behavior such as making screenshots and toggling and filling the Ogre Debug Overlays. It contains most of the Ogre related variables:

  • Root
  • RenderWindow
  • Viewport
  • Log
  • Timer
  • InputManager / Keyboard / Mouse
  • SDKTrays Manager


It also offers functions to handle input, but that is almost not used here, as each application state needs a different input behavior and therefore this is directly modeled in the application states. However, everything common for the whole application can be put here.

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

#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>

#include <SdkTrays.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);

	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::RenderWindow*			m_pRenderWnd;
	Ogre::Viewport*				m_pViewport;
	Ogre::Log*				m_pLog;
	Ogre::Timer*				m_pTimer;

	OIS::InputManager*			m_pInputMgr;
	OIS::Keyboard*				m_pKeyboard;
	OIS::Mouse*				m_pMouse;

        OgreBites::SdkTrayManager*	        m_pTrayMgr;

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

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

#endif

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



AdvancedOgreFramework.cpp

  • First line: Singleton is initialized
  • OgreFramework(): Constructor
//|||||||||||||||||||||||||||||||||||||||||||||||

#include "AdvancedOgreFramework.hpp"

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

using namespace Ogre;

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

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

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

OgreFramework::OgreFramework()
{
    m_pRoot			= 0;
    m_pRenderWnd		= 0;
    m_pViewport			= 0;
    m_pLog			= 0;
    m_pTimer			= 0;

    m_pInputMgr			= 0;
    m_pKeyboard			= 0;
    m_pMouse			= 0;
    m_pTrayMgr			= 0;
}

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

  • ~OgreFramework(): Destructor, clearing up
OgreFramework::~OgreFramework()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Shutdown OGRE...");
    if(m_pTrayMgr)              delete m_pTrayMgr;
    if(m_pInputMgr)		OIS::InputManager::destroyInputSystem(m_pInputMgr);
    if(m_pRoot)			delete m_pRoot;
}

  • initOgre(): Powers up Ogre with the following steps:
  1. create the log manager
  2. create the Root
  3. create the RenderWindow and the Viewport
  4. power up OIS
  5. if there was no MouseListener or KeyboardListener passed as a parameter, use the ones from this class, otherwise the passed ones (however you still can use both, by calling the OgreFramework class input functions when you handle input elsewhere)
  6. load resources
  7. start Timer
  8. set up the SDKTrayManager
  9. create and show the debug overlay


Note: After running this function you still won't see anything on the screen as there is no Camera and no SceneManager. Those are members of the individual application states!

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_pViewport = m_pRenderWnd->addViewport(0);
    m_pViewport->setBackgroundColour(ColourValue(0.5f, 0.5f, 0.5f, 1.0f));

    m_pViewport->setCamera(0);

    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_pTrayMgr = new OgreBites::SdkTrayManager("AOFTrayMgr", m_pRenderWnd, m_pMouse, 0);

    m_pTimer = new Ogre::Timer();
    m_pTimer->reset();

    m_pRenderWnd->setActive(true);

    return true;
}

  • keyPressed(): Handles to buffered input, common for the whole application
  • keyReleased(): same as above
  • mouseMoved(): same as above
  • mousePressed(): same as above
  • mouseReleased(): same as above
bool OgreFramework::keyPressed(const OIS::KeyEvent &keyEventRef)
{
    if(m_pKeyboard->isKeyDown(OIS::KC_SYSRQ))
    {
        m_pRenderWnd->writeContentsToTimestampedFile("AOF_Screenshot_", ".jpg");
        return true;
    }

    if(m_pKeyboard->isKeyDown(OIS::KC_O))
    {
        if(m_pTrayMgr->isLogoVisible())
        {
            m_pTrayMgr->hideFrameStats();
            m_pTrayMgr->hideLogo();
        }
        else
        {
            m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
            m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);
        }
    }

    return true;
}

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

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

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

bool OgreFramework::mouseMoved(const OIS::MouseEvent &evt)
{
    return true;
}

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

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(): Is called once per frame by the AppStateManager to update everything directly related to Ogre, in our case...nothing. In this application all updates are taken care of by the application states, but if there would be some central Ogre update task, the would go in here.
void OgreFramework::updateOgre(double timeSinceLastFrame)
{
}


...page... Wiki page pagination has not been enabled.

Table of contents

    AppState.hpp

    In this file, two classes are defined:

    • AppStateListener and
    • AppState


    The first class will later be inherited by the application state manager, but has to be defined here due to design reasons.

    • AppStateListener(): Constructor
    • ~AppStateListener(): Destructor
    • manageGameState(): Function to later add a new state to the manager
    • changeAppState(): Exits the current app state and starts the one specified as the parameter
    • pushAppState(): Puts a new app state on the active state stack that will then be excecuted
    • popGameState(): Removes the top active state from the stack, which results in returning to the one below
    • shutdown(): Well, guess what happens here...
    • popAllAndPushAppState(): Removes all current app states from the stack and moves to the given new state


    The second class is the app state blueprint from which each actual application state will inherit:

    • some functions to enter, exit, pause, resume and update the state
    • some functions to call other states (orders the manager to start them)
    • a pointer to the manager (which is also a AppStateListener)
    • own Camera and SceneManager


    The last part of this file is a big #define statement. It defines the macro DECLARE_APPSTATE_CLASS via that you can later create the game states.

    Note: The backslashes there are very important as they tell the compiler to take those lines as one big one. Otherwise you would get compiler errors...

    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #ifndef APP_STATE_HPP
    #define APP_STATE_HPP
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #include "AdvancedOgreFramework.hpp"
    
    class AppState;
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    class AppStateListener
    {
    public:
    	AppStateListener(){};
    	virtual ~AppStateListener(){};
    
    	virtual void manageAppState(Ogre::String stateName, AppState* state) = 0;
    
    	virtual AppState*	findByName(Ogre::String stateName) = 0;
    	virtual void		changeAppState(AppState *state) = 0;
    	virtual bool		pushAppState(AppState* state) = 0;
    	virtual void		popAppState() = 0;
    	virtual void		pauseAppState() = 0;
    	virtual void		shutdown() = 0;
            virtual void            popAllAndPushAppState(AppState* state) = 0;
    };
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    class AppState : public OIS::KeyListener, public OIS::MouseListener, public OgreBites::SdkTrayListener
    {
    public:
    	static void create(AppStateListener* parent, const Ogre::String name){};
    
    	void destroy(){delete this;}
    
    	virtual void enter() = 0;
    	virtual void exit() = 0;
    	virtual bool pause(){return true;}
    	virtual void resume(){};
    	virtual void update(double timeSinceLastFrame) = 0;
    
    protected:
    	AppState(){};
    
    	AppState*	findByName(Ogre::String stateName){return m_pParent->findByName(stateName);}
    	void		changeAppState(AppState* state){m_pParent->changeAppState(state);}
    	bool		pushAppState(AppState* state){return m_pParent->pushAppState(state);}
    	void		popAppState(){m_pParent->popAppState();}
    	void		shutdown(){m_pParent->shutdown();}
            void            popAllAndPushAppState(AppState* state){m_pParent->popAllAndPushAppState(state);}
    
    	AppStateListener*	m_pParent;
    
    	Ogre::Camera*		m_pCamera;
    	Ogre::SceneManager*	m_pSceneMgr;
            Ogre::FrameEvent        m_FrameEvent;
    };
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #define DECLARE_APPSTATE_CLASS(T)					\
    static void create(AppStateListener* parent, const Ogre::String name)	\
    {									\
    	T* myAppState = new T();					\
    	myAppState->m_pParent = parent;					\
    	parent->manageAppState(name, myAppState);			\
    }
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #endif
    
    //|||||||||||||||||||||||||||||||||||||||||||||||



    AppStateManager.hpp

    The class AppStateManager inherits from the class AppStateListener shown above and mainly implements its abstract methods. Furthermore it contains:

    • a std::vector for all existing states (m_States)
    • a std::vector for the active states, so the stack of those states currently is use (m_ActiveStateStack)

    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #ifndef APP_STATE_MANAGER_HPP
    #define APP_STATE_MANAGER_HPP
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #include "AppState.hpp"
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    class AppStateManager : public AppStateListener
    {
    public:
    	typedef struct
    	{
    		Ogre::String name;
    		AppState* state;
    	} state_info;
    
    	AppStateManager();
    	~AppStateManager();
    
    	void manageAppState(Ogre::String stateName, AppState* state);
    
    	AppState* findByName(Ogre::String stateName);
    
    	void start(AppState* state);
    	void changeAppState(AppState* state);
    	bool pushAppState(AppState* state);
    	void popAppState();
    	void pauseAppState();
    	void shutdown();
            void popAllAndPushAppState(AppState* state);
    
    protected:
    	void init(AppState *state);
    
    	std::vector<AppState*>		m_ActiveStateStack;
    	std::vector<state_info>		m_States;
    	bool				m_bShutdown;
    };
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #endif
    
    //|||||||||||||||||||||||||||||||||||||||||||||||



    AppStateManager.cpp

    • AppStateManager(): Constructor, just setting the shutdown indicator
    • ~AppStateManager(): Destructor, exiting all active application states and emptying the std::vectors

    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #include "AppStateManager.hpp"
    
    #include <OgreWindowEventUtilities.h>
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    AppStateManager::AppStateManager()
    {
    	m_bShutdown = false;
    }
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    AppStateManager::~AppStateManager()
    {
    	state_info si;
    
            while(!m_ActiveStateStack.empty())
    	{
    		m_ActiveStateStack.back()->exit();
    		m_ActiveStateStack.pop_back();
    	}
    
    	while(!m_States.empty())
    	{
    		si = m_States.back();
                    si.state->destroy();
                    m_States.pop_back();
    	}
    }

    • manageAppState(): Called from within the state creation macro and sets some information of the new state, as well as pushing it on the active states stack
    void AppStateManager::manageAppState(Ogre::String stateName, AppState* state)
    {
    	try
    	{
    		state_info new_state_info;
    		new_state_info.name = stateName;
    		new_state_info.state = state;
    		m_States.push_back(new_state_info);		
    	}
    	catch(std::exception& e)
    	{
    		delete state;
    		throw Ogre::Exception(Ogre::Exception::ERR_INTERNAL_ERROR, "Error while trying to manage a new AppState\n" + Ogre::String(e.what()), "AppStateManager.cpp (39)");
    	}
    }

    • findByName(): Returns a pointer to the state with the respective name
    AppState* AppStateManager::findByName(Ogre::String stateName)
    {
    	std::vector<state_info>::iterator itr;
    
    	for(itr=m_States.begin();itr!=m_States.end();itr++)
    	{
    		if(itr->name==stateName)
    			return itr->state;
    	}
    
    	return 0;
    }

    • start(): Main loop of the application that does the following steps:
    1. change to the state specified
    2. start loop
    3. capture keyboard and mouse input
    4. update the current state (the top most of the stack)
    5. call the OgreFramework class to update and render
    void AppStateManager::start(AppState* state)
    {
    	changeAppState(state);
    
    	int timeSinceLastFrame = 1;
    	int startTime = 0;
    
    	while(!m_bShutdown)
    	{
    		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();
    
    			m_ActiveStateStack.back()->update(timeSinceLastFrame);
    
    			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");
    }

    • changeAppState(): Exits the current state (if there is any) and starts the new specified one
    void AppStateManager::changeAppState(AppState* state)
    {
    	if(!m_ActiveStateStack.empty())
    	{
    		m_ActiveStateStack.back()->exit();
    		m_ActiveStateStack.pop_back();
    	}
    
    	m_ActiveStateStack.push_back(state);
    	init(state);
    	m_ActiveStateStack.back()->enter();
    }

    • pushAppState(): Puts an new state on the top of the stack and starts it
    bool AppStateManager::pushAppState(AppState* state)
    {
    	if(!m_ActiveStateStack.empty())
    	{
    		if(!m_ActiveStateStack.back()->pause())
    			return false;
    	}
    
    	m_ActiveStateStack.push_back(state);
    	init(state);
    	m_ActiveStateStack.back()->enter();
    
    	return true;
    }

    • popAppState(): Removes the top most state and resumes the one below if there is one, otherwise shutdown the application
    void AppStateManager::popAppState()
    {
    	if(!m_ActiveStateStack.empty())
    	{
    		m_ActiveStateStack.back()->exit();
    		m_ActiveStateStack.pop_back();
    	}
    
    	if(!m_ActiveStateStack.empty())
    	{
    		init(m_ActiveStateStack.back());
    		m_ActiveStateStack.back()->resume();
    	}
        else
    		shutdown();
    }

    • popAllAndPushAppState(): Exits all existing app state on the stack and enters the given new state
    void AppStateManager::popAllAndPushAppState(AppState* state)
    {
        while(!m_ActiveStateStack.empty())
        {
            m_ActiveStateStack.back()->exit();
            m_ActiveStateStack.pop_back();
        }
    
        pushAppState(state);
    }

    • pauseAppState(): Pauses the current app state and resumes the one in the stack below
    void AppStateManager::pauseAppState()
    {
    	if(!m_ActiveStateStack.empty())
    	{
    		m_ActiveStateStack.back()->pause();
    	}
    
    	if(m_ActiveStateStack.size() > 2)
    	{
    		init(m_ActiveStateStack.at(m_ActiveStateStack.size() - 2));
    		m_ActiveStateStack.at(m_ActiveStateStack.size() - 2)->resume();
    	}
    }

    • shutdown(): Exits the application
    void AppStateManager::shutdown()
    {
    	m_bShutdown = true;
    }

    • init(): Initializes a new state and links the input and SDKTrays callback on it, as well as resetting the Ogre statistics (FPS, triangle count, batch count, ...)
    void AppStateManager::init(AppState* state)
    {
        OgreFramework::getSingletonPtr()->m_pKeyboard->setEventCallback(state);
    	OgreFramework::getSingletonPtr()->m_pMouse->setEventCallback(state);
        OgreFramework::getSingletonPtr()->m_pTrayMgr->setListener(state);
    
    	OgreFramework::getSingletonPtr()->m_pRenderWnd->resetStatistics();
    }



    The MenuState class is one of the actual AppState class implementations. By inheriting from AppState it is assured that it will have the same common functions enter(), exit(), pause(), resume() and update().

    • DECLARE_APPSTATE_CLASS(MenuState): This line calls the macro defined in AppState.hpp, making this class a valid application state

    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #ifndef MENU_STATE_HPP
    #define MENU_STATE_HPP
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #include "AppState.hpp"
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    class MenuState : public AppState
    {
    public:
        MenuState();
    
    	DECLARE_APPSTATE_CLASS(MenuState)
    
    	void enter();
    	void createScene();
    	void exit();
    
    	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);
    
    	void buttonHit(OgreBites::Button* button);
    
    	void update(double timeSinceLastFrame);
    
    private:
    	bool m_bQuit;
    };
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #endif
    
    //|||||||||||||||||||||||||||||||||||||||||||||||



    • enter(): Always called when starting this state and does the following steps:
    1. create SceneManager
    2. create a Camera
    3. set input callbacks
    4. build GUI
    5. call createScene() to fill the scene with content
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    #include "MenuState.hpp"
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    using namespace Ogre;
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    MenuState::MenuState()
    {
        m_bQuit         = false;
        m_FrameEvent    = Ogre::FrameEvent();
    }
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    void MenuState::enter()
    {
        OgreFramework::getSingletonPtr()->m_pLog->logMessage("Entering MenuState...");
    
        m_pSceneMgr = OgreFramework::getSingletonPtr()->m_pRoot->createSceneManager(ST_GENERIC, "MenuSceneMgr");
        m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.7f, 0.7f, 0.7f));
    
        m_pCamera = m_pSceneMgr->createCamera("MenuCam");
        m_pCamera->setPosition(Vector3(0, 25, -50));
        m_pCamera->lookAt(Vector3(0, 0, 0));
        m_pCamera->setNearClipDistance(1);
    
        m_pCamera->setAspectRatio(Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualWidth()) /
            Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualHeight()));
    
        OgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);
    
        OgreFramework::getSingletonPtr()->m_pTrayMgr->destroyAllWidgets();
        OgreFramework::getSingletonPtr()->m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
        OgreFramework::getSingletonPtr()->m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);
        OgreFramework::getSingletonPtr()->m_pTrayMgr->showCursor();
        OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_CENTER, "EnterBtn", "Enter GameState", 250);
        OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_CENTER, "ExitBtn", "Exit AdvancedOgreFramework", 250);
        OgreFramework::getSingletonPtr()->m_pTrayMgr->createLabel(OgreBites::TL_TOP, "MenuLbl", "Menu mode", 250);
    
        createScene();
    }

    • createScene(): Fill the scene with content (no content in the MenuState here)
    • exit(): Destroys the Camera and the SceneManager as well as the GUI elements
    void MenuState::createScene()
    {
    }
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    void MenuState::exit()
    {
        OgreFramework::getSingletonPtr()->m_pLog->logMessage("Leaving MenuState...");
    
        m_pSceneMgr->destroyCamera(m_pCamera);
        if(m_pSceneMgr)
            OgreFramework::getSingletonPtr()->m_pRoot->destroySceneManager(m_pSceneMgr);
    
        OgreFramework::getSingletonPtr()->m_pTrayMgr->clearAllTrays();
        OgreFramework::getSingletonPtr()->m_pTrayMgr->destroyAllWidgets();
        OgreFramework::getSingletonPtr()->m_pTrayMgr->setListener(0);
    }

    Input handling functions:

    • keyPressed(): Quits on Escape and forwards the unhandled input to the OgreFramework class
    • keyReleased(): Only forwards to the OgreFramework class
    • mouseMoved(): Injects the mouse movements to the GUI
    • mousePressed(): Injects the mouse clicks to the GUI
    • mouseReleased(): Injects the mouse clicks to the GUI
    bool MenuState::keyPressed(const OIS::KeyEvent &keyEventRef)
    {
        if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_ESCAPE))
        {
            m_bQuit = true;
            return true;
        }
    
        OgreFramework::getSingletonPtr()->keyPressed(keyEventRef);
        return true;
    }
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    bool MenuState::keyReleased(const OIS::KeyEvent &keyEventRef)
    {
        OgreFramework::getSingletonPtr()->keyReleased(keyEventRef);
        return true;
    }
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    bool MenuState::mouseMoved(const OIS::MouseEvent &evt)
    {
        if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseMove(evt)) return true;
        return true;
    }
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    bool MenuState::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
    {
        if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseDown(evt, id)) return true;
        return true;
    }
    
    //|||||||||||||||||||||||||||||||||||||||||||||||
    
    bool MenuState::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
    {
        if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseUp(evt, id)) return true;
        return true;
    }

    • update(): Updates the GUI and checks whether the state is to be quit.
    void MenuState::update(double timeSinceLastFrame)
    {
        m_FrameEvent.timeSinceLastFrame = timeSinceLastFrame;
        OgreFramework::getSingletonPtr()->m_pTrayMgr->frameRenderingQueued(m_FrameEvent);
    
        if(m_bQuit == true)
        {
            shutdown();
            return;
        }
    }

    • buttonHit(): Callback function that gets triggered when a button is hit.
    void MenuState::buttonHit(OgreBites::Button *button)
    {
        if(button->getName() == "ExitBtn")
            m_bQuit = true;
        else if(button->getName() == "EnterBtn")
            changeAppState(findByName("GameState"));
    }



    ...page... Wiki page pagination has not been enabled.

    Table of contents



      GameState.hpp

      The second actual implemented application state, also inheriting from AppState. It is similar to the MenuState.hpp but with a bit more going on on the screen and itnernally.

      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      #ifndef GAME_STATE_HPP
      #define GAME_STATE_HPP
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      #include "AppState.hpp"
      
      #include "DotSceneLoader.hpp"
      
      #include <OgreSubEntity.h>
      #include <OgreMaterialManager.h>
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      enum QueryFlags
      {
          OGRE_HEAD_MASK	= 1<<0,
          CUBE_MASK		= 1<<1
      };
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      class GameState : public AppState
      {
      public:
      	GameState();
      
      	DECLARE_APPSTATE_CLASS(GameState)
      
      	void enter();
      	void createScene();
      	void exit();
      	bool pause();
      	void resume();
      
      	void moveCamera();
      	void getInput();
              void buildGUI();
      
      	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);
      
      	void onLeftPressed(const OIS::MouseEvent &evt);
              void itemSelected(OgreBites::SelectMenu* menu);
      
      	void update(double timeSinceLastFrame);
      
      private:
      	Ogre::SceneNode*		m_pOgreHeadNode;
      	Ogre::Entity*			m_pOgreHeadEntity;
      	Ogre::MaterialPtr		m_pOgreHeadMat;
      	Ogre::MaterialPtr		m_pOgreHeadMatHigh;
      
          OgreBites::ParamsPanel*		m_pDetailsPanel;
      	bool				m_bQuit;
      
      	Ogre::Vector3			m_TranslateVector;
      	Ogre::Real			m_MoveSpeed;
      	Ogre::Degree			m_RotateSpeed;
      	float				m_MoveScale;
      	Ogre::Degree			m_RotScale;
      
      	Ogre::RaySceneQuery*		m_pRSQ;
      	Ogre::SceneNode*		m_pCurrentObject;
      	Ogre::Entity*			m_pCurrentEntity;
      	bool				m_bLMouseDown, m_bRMouseDown;
      	bool				m_bSettingsMode;
      };
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      #endif
      
      //|||||||||||||||||||||||||||||||||||||||||||||||



      GameState.cpp

      • GameState(): Constructor
      • enter(): Basic setup of the scene and the GUI
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      #include "GameState.hpp"
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      using namespace Ogre;
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      GameState::GameState()
      {
          m_MoveSpeed		= 0.1f;
          m_RotateSpeed	= 0.3f;
      
          m_bLMouseDown       = false;
          m_bRMouseDown       = false;
          m_bQuit             = false;
          m_bSettingsMode     = false;
      
          m_pDetailsPanel	= 0;
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      void GameState::enter()
      {
          OgreFramework::getSingletonPtr()->m_pLog->logMessage("Entering GameState...");
      
          m_pSceneMgr = OgreFramework::getSingletonPtr()->m_pRoot->createSceneManager(ST_GENERIC, "GameSceneMgr");
          m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.7f, 0.7f, 0.7f));
      
          m_pRSQ = m_pSceneMgr->createRayQuery(Ray());
          m_pRSQ->setQueryMask(OGRE_HEAD_MASK);
      
          m_pCamera = m_pSceneMgr->createCamera("GameCamera");
          m_pCamera->setPosition(Vector3(5, 60, 60));
          m_pCamera->lookAt(Vector3(5, 20, 0));
          m_pCamera->setNearClipDistance(5);
      
          m_pCamera->setAspectRatio(Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualWidth()) /
              Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualHeight()));
      
          OgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);
          m_pCurrentObject = 0;
      
          buildGUI();
      
          createScene();
      }

      • pause(): Called by the app state manager when the game state is to be paused
      • resume(): Called by the app state manager when the game state is to be resumed and rebuilds the GUI and sets the camera active
      bool GameState::pause()
      {
          OgreFramework::getSingletonPtr()->m_pLog->logMessage("Pausing GameState...");
      
          return true;
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      void GameState::resume()
      {
          OgreFramework::getSingletonPtr()->m_pLog->logMessage("Resuming GameState...");
      
          buildGUI();
      
          OgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);
          m_bQuit = false;
      }

      • exit(): Similar to the pause() function, but also destroys the Camera, the SceneManager and the RaySceneQuery
      void GameState::exit()
      {
          OgreFramework::getSingletonPtr()->m_pLog->logMessage("Leaving GameState...");
      
          m_pSceneMgr->destroyCamera(m_pCamera);
          m_pSceneMgr->destroyQuery(m_pRSQ);
          if(m_pSceneMgr)
              OgreFramework::getSingletonPtr()->m_pRoot->destroySceneManager(m_pSceneMgr);
      }

      • createScene(): Fills the scene with content:
      1. create a Light
      2. instantiate the DotSceneLoader
      3. load a DotScene (CubeScene.xml) from the ResourceGroup General
      4. retrieve the Entities from the DotScene and set the QueryMaskFlag (so that they can't be selected with the mouse)
      5. put the OgerHead into the scene and also set a QueryMaskFlag, so that it actually can be selected with the mouse
      6. get the current material from the head, clone it and change the cloned one to red
      void GameState::createScene()
      {
          m_pSceneMgr->createLight("Light")->setPosition(75,75,75);
      
          DotSceneLoader* pDotSceneLoader = new DotSceneLoader();
          pDotSceneLoader->parseDotScene("CubeScene.xml", "General", m_pSceneMgr, m_pSceneMgr->getRootSceneNode());
          delete pDotSceneLoader;
      
          m_pSceneMgr->getEntity("Cube01")->setQueryFlags(CUBE_MASK);
          m_pSceneMgr->getEntity("Cube02")->setQueryFlags(CUBE_MASK);
          m_pSceneMgr->getEntity("Cube03")->setQueryFlags(CUBE_MASK);
      
          m_pOgreHeadEntity = m_pSceneMgr->createEntity("Cube", "ogrehead.mesh");
          m_pOgreHeadEntity->setQueryFlags(OGRE_HEAD_MASK);
          m_pOgreHeadNode = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("CubeNode");
          m_pOgreHeadNode->attachObject(m_pOgreHeadEntity);
          m_pOgreHeadNode->setPosition(Vector3(0, 0, -25));
      
          m_pOgreHeadMat = m_pOgreHeadEntity->getSubEntity(1)->getMaterial();
          m_pOgreHeadMatHigh = m_pOgreHeadMat->clone("OgreHeadMatHigh");
          m_pOgreHeadMatHigh->getTechnique(0)->getPass(0)->setAmbient(1, 0, 0);
          m_pOgreHeadMatHigh->getTechnique(0)->getPass(0)->setDiffuse(1, 0, 0, 0);
      }

      • keyPressed(): Handles the buffered input:
      1. if we are in settings mode (can be toggled via [Tab]) then all the key hits have to be injected as they should be processed by the GUI
      2. check for [Escape], [Tab] to switch input modes and [Return] / [Enter] when we are in chat mode in order to send the typed in text to the message box
      3. if we a) are not in the chat mode or b) we are in chat mode, but [O] was not pressed, we can pass the unhandled input to the OgreFramework class (without this check, e.g. typing in an [O] in chat mode would also be passed to the OgreFramework resulting in also toggling the Overlays for each typed [O])
      • keyReleased(): Just passes the input on to the OgreFramework class
      bool GameState::keyPressed(const OIS::KeyEvent &keyEventRef)
      {
          if(m_bSettingsMode == true)
          {
              if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_S))
              {
                  OgreBites::SelectMenu* pMenu = (OgreBites::SelectMenu*)OgreFramework::getSingletonPtr()->m_pTrayMgr->getWidget("ChatModeSelMenu");
                  if(pMenu->getSelectionIndex() + 1 < (int)pMenu->getNumItems())
                      pMenu->selectItem(pMenu->getSelectionIndex() + 1);
              }
      
              if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_W))
              {
                  OgreBites::SelectMenu* pMenu = (OgreBites::SelectMenu*)OgreFramework::getSingletonPtr()->m_pTrayMgr->getWidget("ChatModeSelMenu");
                  if(pMenu->getSelectionIndex() - 1 >= 0)
                      pMenu->selectItem(pMenu->getSelectionIndex() - 1);
              }
          }
      
          if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_ESCAPE))
          {
              pushAppState(findByName("PauseState"));
              return true;
          }
      
          if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_I))
          {
              if(m_pDetailsPanel->getTrayLocation() == OgreBites::TL_NONE)
              {
                  OgreFramework::getSingletonPtr()->m_pTrayMgr->moveWidgetToTray(m_pDetailsPanel, OgreBites::TL_TOPLEFT, 0);
                  m_pDetailsPanel->show();
              }
              else
              {
                  OgreFramework::getSingletonPtr()->m_pTrayMgr->removeWidgetFromTray(m_pDetailsPanel);
                  m_pDetailsPanel->hide();
              }
          }
      
          if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_TAB))
          {
              m_bSettingsMode = !m_bSettingsMode;
              return true;
          }
      
          if(m_bSettingsMode && OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_RETURN) ||
              OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_NUMPADENTER))
          {
          }
      
          if(!m_bSettingsMode || (m_bSettingsMode && !OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_O)))
              OgreFramework::getSingletonPtr()->keyPressed(keyEventRef);
      
          return true;
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      bool GameState::keyReleased(const OIS::KeyEvent &keyEventRef)
      {
          OgreFramework::getSingletonPtr()->keyPressed(keyEventRef);
          return true;
      }

      • mouseMoved(): Handle the mouse movement:
      1. inject the movement to the GUI
      2. if the right mouse button is pressed, manipulate the camera
      • mousePressed(): Checks which button was pressed and sets the internal bool values as well as injecting the left click to the GUI and calls the function onLeftPressed() for object selection with the mouse
      • mouseReleased(): The same as above, but for the key release
      bool GameState::mouseMoved(const OIS::MouseEvent &evt)
      {
          if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseMove(evt)) return true;
      
          if(m_bRMouseDown)
          {
              m_pCamera->yaw(Degree(evt.state.X.rel * -0.1f));
              m_pCamera->pitch(Degree(evt.state.Y.rel * -0.1f));
          }
      
          return true;
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      bool GameState::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
      {
          if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseDown(evt, id)) return true;
      
          if(id == OIS::MB_Left)
          {
              onLeftPressed(evt);
              m_bLMouseDown = true;
          }
          else if(id == OIS::MB_Right)
          {
              m_bRMouseDown = true;
          }
      
          return true;
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      bool GameState::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
      {
          if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseUp(evt, id)) return true;
      
          if(id == OIS::MB_Left)
          {
              m_bLMouseDown = false;
          }
          else if(id == OIS::MB_Right)
          {
              m_bRMouseDown = false;
          }
      
          return true;
      }

      • onLeftPressed(): Object selection:
      1. if there is a selected object (which would be stored in m_pCurrentObject) hide its bounding box now and set another material for the Ogre head (the Ogre head is the only selectable object in our scene due to the QueryMask)
      2. get the position of our mouse cursor
      3. create a Ray from the camera to this position and check for hits
      4. iterate over all hits
      5. if we hit a movable object, show its bounding box and store it into m_pCurrentObject as well as applying a different material to it
      void GameState::onLeftPressed(const OIS::MouseEvent &evt)
      {
          if(m_pCurrentObject)
          {
              m_pCurrentObject->showBoundingBox(false);
              m_pCurrentEntity->getSubEntity(1)->setMaterial(m_pOgreHeadMat);
          }
      
          Ogre::Ray mouseRay = m_pCamera->getCameraToViewportRay(OgreFramework::getSingletonPtr()->m_pMouse->getMouseState().X.abs / float(evt.state.width),
              OgreFramework::getSingletonPtr()->m_pMouse->getMouseState().Y.abs / float(evt.state.height));
          m_pRSQ->setRay(mouseRay);
          m_pRSQ->setSortByDistance(true);
      
          Ogre::RaySceneQueryResult &result = m_pRSQ->execute();
          Ogre::RaySceneQueryResult::iterator itr;
      
          for(itr = result.begin(); itr != result.end(); itr++)
          {
              if(itr->movable)
              {
                  OgreFramework::getSingletonPtr()->m_pLog->logMessage("MovableName: " + itr->movable->getName());
                  m_pCurrentObject = m_pSceneMgr->getEntity(itr->movable->getName())->getParentSceneNode();
                  OgreFramework::getSingletonPtr()->m_pLog->logMessage("ObjName " + m_pCurrentObject->getName());
                  m_pCurrentObject->showBoundingBox(true);
                  m_pCurrentEntity = m_pSceneMgr->getEntity(itr->movable->getName());
                  m_pCurrentEntity->getSubEntity(1)->setMaterial(m_pOgreHeadMatHigh);
                  break;
              }
          }
      }

      • moveCamera(): Translate the camera by the vector assembled in getInput() (10 times faster if Shift is pressed)
      void GameState::moveCamera()
      {
          if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_LSHIFT))
              m_pCamera->moveRelative(m_TranslateVector);
          m_pCamera->moveRelative(m_TranslateVector / 10);
      }

      • getInput(): If we are not in chat mode, we want to move the camera via the keys, so in this case assemble a translation vector that is then applied to the camera in moveCamera()
      void GameState::getInput()
      {
          if(m_bSettingsMode == false)
          {
              if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_A))
                  m_TranslateVector.x = -m_MoveScale;
      
              if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_D))
                  m_TranslateVector.x = m_MoveScale;
      
              if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_W))
                  m_TranslateVector.z = -m_MoveScale;
      
              if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_S))
                  m_TranslateVector.z = m_MoveScale;
      
              if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_Q))
                  m_TranslateVector.y = -m_MoveScale;
      
              if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_E))
                  m_TranslateVector.y = m_MoveScale;
      
              //camera roll
              if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_Z))
                  m_pCamera->roll(Angle(-m_MoveScale));
      
              if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_X))
                  m_pCamera->roll(Angle(m_MoveScale));
      
              //reset roll
              if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_C))
                  m_pCamera->roll(-(m_pCamera->getRealOrientation().getRoll()));
          }
      }

      • update(): Update the whole state:
      1. update the GUI
      2. leave and remove this state from the active state stack if requested
      3. update the information in the details panel
      4. determine the move scale depending on the time passed since the last frame
      5. reset the translation vector for the camera
      6. get the unbuffered input and move the camera
      void GameState::update(double timeSinceLastFrame)
      {
          m_FrameEvent.timeSinceLastFrame = timeSinceLastFrame;
          OgreFramework::getSingletonPtr()->m_pTrayMgr->frameRenderingQueued(m_FrameEvent);
      
          if(m_bQuit == true)
          {
              popAppState();
              return;
          }
      
          if(!OgreFramework::getSingletonPtr()->m_pTrayMgr->isDialogVisible())
          {
              if(m_pDetailsPanel->isVisible())
              {
                  m_pDetailsPanel->setParamValue(0, Ogre::StringConverter::toString(m_pCamera->getDerivedPosition().x));
                  m_pDetailsPanel->setParamValue(1, Ogre::StringConverter::toString(m_pCamera->getDerivedPosition().y));
                  m_pDetailsPanel->setParamValue(2, Ogre::StringConverter::toString(m_pCamera->getDerivedPosition().z));
                  m_pDetailsPanel->setParamValue(3, Ogre::StringConverter::toString(m_pCamera->getDerivedOrientation().w));
                  m_pDetailsPanel->setParamValue(4, Ogre::StringConverter::toString(m_pCamera->getDerivedOrientation().x));
                  m_pDetailsPanel->setParamValue(5, Ogre::StringConverter::toString(m_pCamera->getDerivedOrientation().y));
                  m_pDetailsPanel->setParamValue(6, Ogre::StringConverter::toString(m_pCamera->getDerivedOrientation().z));
                  if(m_bSettingsMode)
                      m_pDetailsPanel->setParamValue(7, "Buffered Input");
                  else
                      m_pDetailsPanel->setParamValue(7, "Un-Buffered Input");
              }
          }
      
          m_MoveScale = m_MoveSpeed   * timeSinceLastFrame;
          m_RotScale  = m_RotateSpeed * timeSinceLastFrame;
      
          m_TranslateVector = Vector3::ZERO;
      
          getInput();
          moveCamera();
      }

      • buildGUI(): Inserts all needed GUI elements in the SDKTrayManager
      void GameState::buildGUI()
      {
          OgreFramework::getSingletonPtr()->m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
          OgreFramework::getSingletonPtr()->m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);
          OgreFramework::getSingletonPtr()->m_pTrayMgr->createLabel(OgreBites::TL_TOP, "GameLbl", "Game mode", 250);
          OgreFramework::getSingletonPtr()->m_pTrayMgr->showCursor();
      
          Ogre::StringVector items;
          items.push_back("cam.pX");
          items.push_back("cam.pY");
          items.push_back("cam.pZ");
          items.push_back("cam.oW");
          items.push_back("cam.oX");
          items.push_back("cam.oY");
          items.push_back("cam.oZ");
          items.push_back("Mode");
      
          m_pDetailsPanel = OgreFramework::getSingletonPtr()->m_pTrayMgr->createParamsPanel(OgreBites::TL_TOPLEFT, "DetailsPanel", 200, items);
          m_pDetailsPanel->show();
      
          Ogre::String infoText = "[TAB] - Switch input mode\n\n[W] - Forward / Mode up\n[S] - Backwards/ Mode down\n[A] - Left\n";
          infoText.append("[D] - Right\n\nPress [SHIFT] to move faster\n\n[O] - Toggle FPS / logo\n");
          infoText.append("[Print] - Take screenshot\n\n[ESC] - Exit");
          OgreFramework::getSingletonPtr()->m_pTrayMgr->createTextBox(OgreBites::TL_RIGHT, "InfoPanel", infoText, 300, 220);
      
          Ogre::StringVector chatModes;
          chatModes.push_back("Solid mode");
          chatModes.push_back("Wireframe mode");
          chatModes.push_back("Point mode");
          OgreFramework::getSingletonPtr()->m_pTrayMgr->createLongSelectMenu(OgreBites::TL_TOPRIGHT, "ChatModeSelMenu", "ChatMode", 200, 3, chatModes);
      }

      • itemSelected(): Callback function triggered when a selection menu changes. As a result of changing the polygon mode of the camera
      void GameState::itemSelected(OgreBites::SelectMenu* menu)
      {
          switch(menu->getSelectionIndex())
          {
          case 0:
              m_pCamera->setPolygonMode(Ogre::PM_SOLID);break;
          case 1:
              m_pCamera->setPolygonMode(Ogre::PM_WIREFRAME);break;
          case 2:
              m_pCamera->setPolygonMode(Ogre::PM_POINTS);break;
          }
      }



      PauseState.hpp

      The PauseState class is one of the actual AppState class implementations. By inheriting from AppState it is assured that will have the same common functions enter(), exit(), pause(), resume() and update().

      • DECLARE_APPSTATE_CLASS(PauseState): This line calls the macro defined in AppState.hpp, making this class a valid application state

      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      #ifndef PAUSE_STATE_HPP
      #define PAUSE_STATE_HPP
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      #include "AppState.hpp"
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      class PauseState : public AppState
      {
      public:
          PauseState();
      
          DECLARE_APPSTATE_CLASS(PauseState)
      
          void enter();
          void createScene();
          void exit();
      
          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);
      
          void buttonHit(OgreBites::Button* button);
          void yesNoDialogClosed(const Ogre::DisplayString& question, bool yesHit);
      
          void update(double timeSinceLastFrame);
      
      private:
          bool m_bQuit;
          bool m_bQuestionActive;
      };
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      #endif
      
      //|||||||||||||||||||||||||||||||||||||||||||||||



      PauseState.cpp

      • constructor(): Initializing values
      • enter(): Setup the basic values and building the GUI
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      #include "PauseState.hpp"
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      using namespace Ogre;
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      PauseState::PauseState()
      {
          m_bQuit             = false;
          m_bQuestionActive   = false;
          m_FrameEvent        = Ogre::FrameEvent();
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      void PauseState::enter()
      {
          OgreFramework::getSingletonPtr()->m_pLog->logMessage("Entering PauseState...");
      
          m_pSceneMgr = OgreFramework::getSingletonPtr()->m_pRoot->createSceneManager(ST_GENERIC, "PauseSceneMgr");
          m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.7f, 0.7f, 0.7f));
      
          m_pCamera = m_pSceneMgr->createCamera("PauseCam");
          m_pCamera->setPosition(Vector3(0, 25, -50));
          m_pCamera->lookAt(Vector3(0, 0, 0));
          m_pCamera->setNearClipDistance(1);
      
          m_pCamera->setAspectRatio(Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualWidth()) /
              Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualHeight()));
      
          OgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);
      
          OgreFramework::getSingletonPtr()->m_pTrayMgr->destroyAllWidgets();
          OgreFramework::getSingletonPtr()->m_pTrayMgr->showCursor();
          OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_CENTER, "BackToGameBtn", "Return to GameState", 250);
          OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_CENTER, "BackToMenuBtn", "Return to Menu", 250);
          OgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_CENTER, "ExitBtn", "Exit AdvancedOgreFramework", 250);
          OgreFramework::getSingletonPtr()->m_pTrayMgr->createLabel(OgreBites::TL_TOP, "PauseLbl", "Pause mode", 250);
      
          m_bQuit = false;
      
          createScene();
      }

      • createScene(): Would fill the scene here, but we only have GUI elements
      • exit(): Pretty much self-explanatory
      void PauseState::createScene()
      {
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      void PauseState::exit()
      {
          OgreFramework::getSingletonPtr()->m_pLog->logMessage("Leaving PauseState...");
      
          m_pSceneMgr->destroyCamera(m_pCamera);
          if(m_pSceneMgr)
              OgreFramework::getSingletonPtr()->m_pRoot->destroySceneManager(m_pSceneMgr);
      
          OgreFramework::getSingletonPtr()->m_pTrayMgr->clearAllTrays();
          OgreFramework::getSingletonPtr()->m_pTrayMgr->destroyAllWidgets();
          OgreFramework::getSingletonPtr()->m_pTrayMgr->setListener(0);
      }

      • keyPressed(): Check if we want to leave and pass all other events on to the OgreFramework
      • keyReleased(): Pass all other events on to the OgreFramework
      • mouseMoved(): Pass events to the SDKTrayManager
      • mousePressed(): Pass events to the SDKTrayManager
      • mouseReleased(): Pass events to the SDKTrayManager
      bool PauseState::keyPressed(const OIS::KeyEvent &keyEventRef)
      {
          if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_ESCAPE) && !m_bQuestionActive)
          {
              m_bQuit = true;
              return true;
          }
      
          OgreFramework::getSingletonPtr()->keyPressed(keyEventRef);
      
          return true;
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      bool PauseState::keyReleased(const OIS::KeyEvent &keyEventRef)
      {
          OgreFramework::getSingletonPtr()->keyReleased(keyEventRef);
      
          return true;
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      bool PauseState::mouseMoved(const OIS::MouseEvent &evt)
      {
          if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseMove(evt)) return true;
          return true;
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      bool PauseState::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
      {
          if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseDown(evt, id)) return true;
          return true;
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      bool PauseState::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
      {
          if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseUp(evt, id)) return true;
          return true;
      }

      • update(): Update the state, so first note the GUI, then check for leave condition
      • buttonHit(): Triggered when a button is hit. Then reacts by changing app states or showing a GUI dialog
      • yesNoDialogClosed(): Shows a popup dialog to confirm that the user wants to leave
      void PauseState::update(double timeSinceLastFrame)
      {
          m_FrameEvent.timeSinceLastFrame = timeSinceLastFrame;
          OgreFramework::getSingletonPtr()->m_pTrayMgr->frameRenderingQueued(m_FrameEvent);
      
          if(m_bQuit == true)
          {
              popAppState();
              return;
          }
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      void PauseState::buttonHit(OgreBites::Button *button)
      {
          if(button->getName() == "ExitBtn")
          {
              OgreFramework::getSingletonPtr()->m_pTrayMgr->showYesNoDialog("Sure?", "Really leave?");
              m_bQuestionActive = true;
          }
          else if(button->getName() == "BackToGameBtn")
          {
              popAllAndPushAppState(findByName("GameState"));
              m_bQuit = true;
          }
          else if(button->getName() == "BackToMenuBtn")
              popAllAndPushAppState(findByName("MenuState"));
      }
      
      //|||||||||||||||||||||||||||||||||||||||||||||||
      
      void PauseState::yesNoDialogClosed(const Ogre::DisplayString& question, bool yesHit)
      {
          if(yesHit == true)
              shutdown();
          else
              OgreFramework::getSingletonPtr()->m_pTrayMgr->closeDialog();
      
          m_bQuestionActive = false;
      }



      ...page... Wiki page pagination has not been enabled.

      Table of contents

        DemoApp.hpp

        The DemoApp class is the central application organizing location. It only has two member variables:

        • the application state manager
        • an indicator of whether the application is to be shut down or not

        //|||||||||||||||||||||||||||||||||||||||||||||||
        
        #ifndef OGRE_DEMO_HPP
        #define OGRE_DEMO_HPP
        
        //|||||||||||||||||||||||||||||||||||||||||||||||
        
        #include "AdvancedOgreFramework.hpp"
        #include "AppStateManager.hpp"
        
        //|||||||||||||||||||||||||||||||||||||||||||||||
        
        class DemoApp
        {
        public:
        	DemoApp();
        	~DemoApp();
        
        	void startDemo();
        
        private:
        	AppStateManager*	m_pAppStateManager;
        };
        
        //|||||||||||||||||||||||||||||||||||||||||||||||
        
        #endif
        
        //|||||||||||||||||||||||||||||||||||||||||||||||



        DemoApp.cpp

        The central application file, managing everything:

        • DemoApp(): Constructor
        • ~DemoApp(): Destructor
        • startDemo(): Starts the application:
        1. fires up the OgreFramework
        2. initializes Ogre (via the OgreFramework)
        3. create an AppStateManager instance
        4. creates the application states (MenuState, GameState and PauseState)
        5. orders the AppStateManager to start its main loop function
        //|||||||||||||||||||||||||||||||||||||||||||||||
        
        #include "DemoApp.hpp"
        
        #include "MenuState.hpp"
        #include "GameState.hpp"
        #include "PauseState.hpp"
        
        //|||||||||||||||||||||||||||||||||||||||||||||||
        
        DemoApp::DemoApp()
        {
        	m_pAppStateManager = 0;
        }
        
        //|||||||||||||||||||||||||||||||||||||||||||||||
        
        DemoApp::~DemoApp()
        {
        	delete m_pAppStateManager;
                delete OgreFramework::getSingletonPtr();
        }
        
        //|||||||||||||||||||||||||||||||||||||||||||||||
        
        void DemoApp::startDemo()
        {
        	new OgreFramework();
        	if(!OgreFramework::getSingletonPtr()->initOgre("AdvancedOgreFramework", 0, 0))
        		return;
        
        	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Demo initialized!");
        
        	m_pAppStateManager = new AppStateManager();
        
        	MenuState::create(m_pAppStateManager, "MenuState");
        	GameState::create(m_pAppStateManager, "GameState");
                PauseState::create(m_pAppStateManager, "PauseState");
        
        	m_pAppStateManager->start(m_pAppStateManager->findByName("MenuState"));
        }
        
        //|||||||||||||||||||||||||||||||||||||||||||||||



        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:

        #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. In this forum post you will find a list of all needed changes in order to get this running with XCode on Mac.

        Conclusion

        Fatigued but happy, the little young programmer boy closed the secret book, feeling his head humming due to all the new great knowledge. However, with a satisfied smile on his face, he promised his teacher - the friendly Ogre - to test all these new valuable insights the next day after catching a big load of sleep...


        Alias: Advanced_Ogre_Framework

        <HR>
        Creative Commons Copyright -- Some rights reserved.


        THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.

        BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.

        1. Definitions

        • "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.
        • "Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License.
        • "Licensor" means the individual or entity that offers the Work under the terms of this License.
        • "Original Author" means the individual or entity who created the Work.
        • "Work" means the copyrightable work of authorship offered under the terms of this License.
        • "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
        • "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike.

        2. Fair Use Rights

        Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws.

        3. License Grant

        Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:

        • to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;
        • to create and reproduce Derivative Works;
        • to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;
        • to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works.
        • For the avoidance of doubt, where the work is a musical composition:
          • Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work.
          • Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights society or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions).
          • Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).


        The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved.

        4. Restrictions

        The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:

        • You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by clause 4(c), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by clause 4(c), as requested.
        • You may distribute, publicly display, publicly perform, or publicly digitally perform a Derivative Work only under the terms of this License, a later version of this License with the same License Elements as this License, or a Creative Commons iCommons license that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy of, or the Uniform Resource Identifier for, this License or other license specified in the previous sentence with every copy or phonorecord of each Derivative Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Derivative Works that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder, and You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Derivative Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Derivative Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Derivative Work itself to be made subject to the terms of this License.
        • If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit.

        5. Representations, Warranties and Disclaimer

        UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.

        6. Limitation on Liability.

        EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

        7. Termination

        • This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
        • Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.

        8. Miscellaneous

        • Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
        • Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
        • If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
        • No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
        • This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.