Sure, no problem. The full sample code is below - its fairly simple. Its really the same kind of thing that you would do for any other OGRE sample application. The only new thing is the following:
This is basically what you would need to do with OpenGL, so I just abstracted it for OGRE with the English spelling. Stereo is not automatic, so the application should be able to easily disable or enable it. The other nice thing about choosing the buffer is that if the eyes are swapped in the application, you can unswap them by switching between the left and right buffers for all the stereo viewports. And to switch to 2D, you simply only draw to the back buffer.
Anyway - the full code is below, so let me know if you have any questions or problems. There maybe some code that is commented out and feel free to play with the stereo settings.
Code: Select all
#include "Ogre/Ogre.h"
#include "OIS/OISEvents.h"
#include "OIS/OISInputManager.h"
#include "OIS/OISKeyboard.h"
#include "OIS/OISMouse.h"
class AnimationFrameListener : public Ogre::FrameListener
{
public:
AnimationFrameListener(Ogre::Entity* sinbadEntity, bool* isSinbadRunning)
{
// Cache the application state
m_isSinbadRunning = isSinbadRunning;
// Get the running animiations for the base of Sinbad and the top of Sinbad
m_sinbadRunBaseAnimationState = sinbadEntity->getAnimationState("RunBase");
m_sinbadRunTopAnimationState = sinbadEntity->getAnimationState("RunTop");
}
bool frameStarted(const Ogre::FrameEvent& evt)
{
// If Sinbad is running, enable the animation
m_sinbadRunBaseAnimationState->setEnabled(*m_isSinbadRunning);
m_sinbadRunTopAnimationState->setEnabled(*m_isSinbadRunning);
if (*m_isSinbadRunning)
{
// If Sinbad is running, reset the animation if necessary
if (m_sinbadRunBaseAnimationState->hasEnded())
m_sinbadRunBaseAnimationState->setTimePosition(0.0f);
if (m_sinbadRunTopAnimationState->hasEnded())
m_sinbadRunTopAnimationState->setTimePosition(0.0f);
}
else
{
// If Sinbad is not running, reset the animation
m_sinbadRunBaseAnimationState->setTimePosition(0.0f);
m_sinbadRunTopAnimationState->setTimePosition(0.0f);
}
m_sinbadRunBaseAnimationState->addTime(evt.timeSinceLastFrame);
m_sinbadRunTopAnimationState->addTime(evt.timeSinceLastFrame);
return true;
}
bool* m_isSinbadRunning;
Ogre::AnimationState* m_sinbadRunBaseAnimationState;
Ogre::AnimationState* m_sinbadRunTopAnimationState;
};
class OISFrameListener : public Ogre::FrameListener
{
public:
OISFrameListener(Ogre::RenderWindow* window, Ogre::SceneNode* sinbadNode, bool* isStereoEnabled, bool* isSinbadRunning)
{
// Cache the objects
m_window = window;
m_sinbadNode = sinbadNode;
m_isStereoEnabled = isStereoEnabled;
m_isSinbadRunning = isSinbadRunning;
// Reset the timer, rotation, and set the speeds
m_timer.reset();
m_sinbadRotation = Ogre::Radian(0);
m_sinbadRunningSpeed = 50.0f;
m_cameraSpeed = 200.0f;
// Get the OGRE window handle
size_t windowHnd = 0;
m_window->getCustomAttribute("WINDOW", &windowHnd);
// Convert the OGRE window handle to a string
std::stringstream windowHndStr;
windowHndStr << windowHnd;
// Create an OIS input manager from the OGRE window handle string
OIS::ParamList paramList;
paramList.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
m_inputManager = OIS::InputManager::createInputSystem(paramList);
// Create the OIS keyboard and mouse unbuffered input objects
m_keyboard = static_cast<OIS::Keyboard*>(m_inputManager->createInputObject(OIS::OISKeyboard, false));
m_mouse = static_cast<OIS::Mouse*>(m_inputManager->createInputObject(OIS::OISMouse, false));
}
~OISFrameListener()
{
// Cleanup the OIS keyboard, mouse, and input manager
m_inputManager->destroyInputObject(m_keyboard);
m_inputManager->destroyInputObject(m_mouse);
OIS::InputManager::destroyInputSystem(m_inputManager);
}
bool frameStarted(const Ogre::FrameEvent& evt)
{
// Capture keyboard and mouse input
m_keyboard->capture();
m_mouse->capture();
// Quit the application
if (m_keyboard->isKeyDown(OIS::KC_ESCAPE))
return false;
// Toggle fullscreen
if (m_keyboard->isKeyDown(OIS::KC_F) && m_timer.getMilliseconds() > 250)
{
bool isFullScreen = m_window->isFullScreen();
m_window->setFullscreen(!isFullScreen, 1920, 1080);
m_timer.reset();
}
// If stereo is enabled, swap left and right color buffers
if (m_keyboard->isKeyDown(OIS::KC_M) && m_timer.getMilliseconds() > 250)
{
if (m_window->isStereoEnabled())
{
for (unsigned short i = 0; i < m_window->getNumViewports(); i++)
{
Ogre::Viewport* viewport = m_window->getViewport(i);
if (Ogre::CBT_BACK_LEFT == viewport->getDrawBuffer())
viewport->setDrawBuffer(Ogre::CBT_BACK_RIGHT);
else if (Ogre::CBT_BACK_RIGHT == viewport->getDrawBuffer())
viewport->setDrawBuffer(Ogre::CBT_BACK_LEFT);
}
}
m_timer.reset();
}
// Enable / disable stereo
if (m_keyboard->isKeyDown(OIS::KC_Z) && m_timer.getMilliseconds() > 250)
{
*m_isStereoEnabled = !(*m_isStereoEnabled);
for (unsigned short i = 0; i < m_window->getNumViewports(); i++)
{
Ogre::Viewport* viewport = m_window->getViewport(i);
if (0 == i && Ogre::CBT_BACK == viewport->getDrawBuffer())
viewport->setDrawBuffer(Ogre::CBT_BACK_LEFT);
else if (1 == i && Ogre::CBT_BACK == viewport->getDrawBuffer())
viewport->setDrawBuffer(Ogre::CBT_BACK_RIGHT);
else
viewport->setDrawBuffer(Ogre::CBT_BACK);
}
m_timer.reset();
}
// Move Sinbad around the scene
Ogre::Vector3 sinbadTranslate(0, 0, 0);
if (m_keyboard->isKeyDown(OIS::KC_UP))
{
m_sinbadRotation = Ogre::Radian(Ogre::Math::PI);
sinbadTranslate += Ogre::Vector3(0, 0, -1);
}
if (m_keyboard->isKeyDown(OIS::KC_DOWN))
{
m_sinbadRotation = Ogre::Radian(0);
sinbadTranslate += Ogre::Vector3(0, 0, 1);
}
if (m_keyboard->isKeyDown(OIS::KC_LEFT))
{
m_sinbadRotation = Ogre::Radian(-Ogre::Math::HALF_PI);
sinbadTranslate += Ogre::Vector3(-1, 0, 0);
}
if (m_keyboard->isKeyDown(OIS::KC_RIGHT))
{
m_sinbadRotation = Ogre::Radian(Ogre::Math::HALF_PI);
sinbadTranslate += Ogre::Vector3(1, 0, 0);
}
*m_isSinbadRunning = !sinbadTranslate.isZeroLength();
m_sinbadNode->translate(sinbadTranslate * evt.timeSinceLastFrame * m_sinbadRunningSpeed);
m_sinbadNode->resetOrientation();
m_sinbadNode->yaw(Ogre::Radian(m_sinbadRotation));
// Move the camera around the scene
Ogre::Vector3 cameraTranslate(0, 0, 0);
if (m_keyboard->isKeyDown(OIS::KC_W))
cameraTranslate += Ogre::Vector3(0, 0, -1);
if (m_keyboard->isKeyDown(OIS::KC_S))
cameraTranslate += Ogre::Vector3(0, 0, 1);
if (m_keyboard->isKeyDown(OIS::KC_A))
cameraTranslate += Ogre::Vector3(-1, 0, 0);
if (m_keyboard->isKeyDown(OIS::KC_D))
cameraTranslate += Ogre::Vector3(1, 0, 0);
if (m_keyboard->isKeyDown(OIS::KC_PGDOWN))
cameraTranslate += Ogre::Vector3(0, -1, 0);
if (m_keyboard->isKeyDown(OIS::KC_PGUP))
cameraTranslate += Ogre::Vector3(0, 1, 0);
// Rotate the camera using the mouse
float rotX = m_mouse->getMouseState().X.rel * evt.timeSinceLastFrame * -1;
float rotY = m_mouse->getMouseState().Y.rel * evt.timeSinceLastFrame * -1;
for (unsigned short i = 0; i < m_window->getNumViewports(); i++)
{
Ogre::Camera* camera = m_window->getViewport(i)->getCamera();
camera->yaw(Ogre::Radian(rotX));
camera->pitch(Ogre::Radian(rotY));
camera->moveRelative(cameraTranslate * evt.timeSinceLastFrame * m_cameraSpeed);
}
return true;
}
bool* m_isStereoEnabled;
bool* m_isSinbadRunning;
float m_sinbadRunningSpeed;
float m_cameraSpeed;
OIS::InputManager* m_inputManager;
OIS::Keyboard* m_keyboard;
OIS::Mouse* m_mouse;
Ogre::Radian m_sinbadRotation;
Ogre::RenderWindow* m_window;
Ogre::SceneNode* m_sinbadNode;
Ogre::Timer m_timer;
};
void loadResources(const Ogre::String& configFilename)
{
// Add all the resources in the resource configuration file
Ogre::ConfigFile configFile;
configFile.load(configFilename);
Ogre::ConfigFile::SectionIterator sectionIter = configFile.getSectionIterator();
Ogre::String secName, typeName, archName;
while (sectionIter.hasMoreElements())
{
secName = sectionIter.peekNextKey();
Ogre::ConfigFile::SettingsMultiMap* settings = sectionIter.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);
}
}
// Index all added resources
Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}
void createScene(Ogre::SceneManager* sceneManager, Ogre::Entity*& sinbadEntity, Ogre::SceneNode*& sinbadNode)
{
// Create a plane for the floor, attach a material, and add it to the scene
//Ogre::Plane plane(Ogre::Vector3::UNIT_Y, -50);
Ogre::Plane plane(Ogre::Vector3::UNIT_Y, -15);
Ogre::MeshManager::getSingleton().createPlane("Floor", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1500, 1500, 200, 200, true, 1, 5, 5, Ogre::Vector3::UNIT_Z);
Ogre::Entity* floorEntity = sceneManager->createEntity("FloorEntity", "Floor");
floorEntity->setMaterialName("Examples/BeachStones");
sceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(floorEntity);
// Create a directional light
Ogre::Light* light = sceneManager->createLight("Light");
light->setType(Ogre::Light::LT_DIRECTIONAL);
light->setDiffuseColour(Ogre::ColourValue(1.0f, 1.0f, 1.0f));
light->setDirection(Ogre::Vector3(1, -1, 0));
// Create an instance of the Sinbad mesh and add it to the scene
sinbadEntity = sceneManager->createEntity("Sinbad", "Sinbad.mesh");
sinbadNode = sceneManager->getRootSceneNode()->createChildSceneNode("SinbadNode");
//sinbadNode->setPosition(Ogre::Vector3(0.0f, 5.0f, 0.0f));
sinbadNode->setPosition(Ogre::Vector3(0.0f, 0.0f, 0.0f));
sinbadNode->setScale(Ogre::Vector3(3.0f, 3.0f, 3.0f));
sinbadNode->attachObject(sinbadEntity);
// Add shadows to the scene
sceneManager->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
}
void createViewport
(
Ogre::RenderWindow* window,
Ogre::SceneManager* sceneManager,
const Ogre::String& name,
const Ogre::Real focalLength,
const Ogre::Vector2 frustumOffset,
int zOrder,
Ogre::ColourBufferType colourBuffer,
Ogre::Viewport*& viewport
)
{
// Create a camera and position it in the scene
Ogre::Camera* camera = sceneManager->createCamera(name);
camera->setPosition(0 + frustumOffset.x, 0, 100);
camera->lookAt(0, 0, 0);
camera->moveRelative(Ogre::Vector3(0, 25.0f, 30.0f));
camera->pitch(Ogre::Radian(Ogre::Degree(-60.0f)));
camera->setNearClipDistance(5.0f);
// Create a viewport, set the background color to black, and set the aspect ratio
viewport = window->addViewport(camera, zOrder);
viewport->setBackgroundColour(Ogre::ColourValue(0.0f, 0.0f, 0.0f, 1.0f));
camera->setAspectRatio(Ogre::Real(viewport->getActualWidth()) / Ogre::Real(viewport->getActualHeight()));
// Set the color buffer type that will be used during rendering
viewport->setDrawBuffer(colourBuffer);
}
int main(void)
{
// Create an instance of OGRE root
Ogre::Root* root = new Ogre::Root("plugins_d.cfg");
// Show the configuration dialog, but if it doesn't work close the app
if (!root->showConfigDialog())
return -1;
// Create a render window and verify that stereo is enabled
Ogre::RenderWindow* window = root->initialise(true, "zSpace Example");
bool isStereoEnabled = window->isStereoEnabled();
// Load the resources for the scene
loadResources("resources_d.cfg");
// Create the scene manager and the scene
Ogre::SceneManager* sceneManager = root->createSceneManager(Ogre::ST_GENERIC);
Ogre::Entity* sinbadEntity = NULL;
Ogre::SceneNode* sinbadNode = NULL;
createScene(sceneManager, sinbadEntity, sinbadNode);
// Create the cameras and viewports
Ogre::Real focalLength = 10.0f;
Ogre::Vector2 frustumOffset(-3.0f, 0.0f);
Ogre::Viewport* leftViewport = NULL;
createViewport(window, sceneManager, "LeftCamera", focalLength, frustumOffset, 0, Ogre::CBT_BACK_LEFT, leftViewport);
frustumOffset.x = 3.0f;
Ogre::Viewport* rightViewport = NULL;
createViewport(window, sceneManager, "RightCamera", focalLength, frustumOffset, 1, Ogre::CBT_BACK_RIGHT, rightViewport);
bool isSinbadRunning = false;
Ogre::FrameListener* animationFrameListener = new AnimationFrameListener(sinbadEntity, &isSinbadRunning);
root->addFrameListener(animationFrameListener);
Ogre::FrameListener* oisFrameListener = new OISFrameListener(window, sinbadNode, &isStereoEnabled, &isSinbadRunning);
root->addFrameListener(oisFrameListener);
// Start OGRE rendering
root->startRendering();
root->removeFrameListener(animationFrameListener);
delete animationFrameListener;
root->removeFrameListener(oisFrameListener);
delete oisFrameListener;
// Delete the root object
delete root;
return 0;
}