#include "GraphicsSystem.h"
#include "StereoRenderingGameState.h"
#include "OgreSceneManager.h"
#include "OgreCamera.h"
#include "OgreRoot.h"
#include "OgreWindow.h"
#include "Compositor/OgreCompositorManager2.h"
#include "Compositor/OgreCompositorManager2.h"
#include "Compositor/OgreCompositorWorkspace.h"
#include "Compositor/OgreCompositorShadowNode.h"
#include "Compositor/OgreCompositorChannel.h"
#include "Compositor/Pass/PassClear/OgreCompositorPassClear.h"
#include "Compositor/Pass/PassScene/OgreCompositorPassScene.h"
#include "Compositor/Pass/PassQuad/OgreCompositorPassQuad.h"
#include "Compositor/Pass/PassQuad/OgreCompositorPassQuadDef.h"
#include "OgreDepthBuffer.h"
//Declares WinMain / main
#include "MainEntryPointHelper.h"
#include "System/MainEntryPoints.h"
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMainApp( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR strCmdLine, INT nCmdShow )
#else
int mainApp( int argc, const char *argv[] )
#endif
{
return Demo::MainEntryPoints::mainAppSingleThreaded( DEMO_MAIN_ENTRY_PARAMS );
}
namespace Demo
{
class StereoGraphicsSystem : public GraphicsSystem
{
Ogre::SceneNode *mCamerasNode;
Ogre::Camera *mEyeCameras[2];
Ogre::CompositorWorkspace *mEyeWorkspaces[2];
//-------------------------------------------------------------------------------
virtual void createCamera(void)
{
//Use one node to control both cameras
mCamerasNode = mSceneManager->getRootSceneNode( Ogre::SCENE_DYNAMIC )->
createChildSceneNode( Ogre::SCENE_DYNAMIC );
mCamerasNode->setName( "Cameras Node" );
mCamerasNode->setPosition( 0, 5, 15 );
mEyeCameras[0] = mSceneManager->createCamera( "Left Eye" );
mEyeCameras[1] = mSceneManager->createCamera( "Right Eye" );
const Ogre::Real eyeDistance = 0.5f;
const Ogre::Real eyeFocusDistance = 0.45f;
Ogre::Vector4 eyeFrustumExtents[2];
for( int i=0; i<2; ++i )
{
const Ogre::Vector3 camPos( eyeDistance * (i * 2 - 1), 0, 0 );
mEyeCameras[i]->setPosition( camPos );
Ogre::Vector3 lookAt( eyeFocusDistance * (i * 2 - 1), -5, -15 );
//Ogre::Vector3 lookAt( 0, 0, 0 );
// Look back along -Z
mEyeCameras[i]->lookAt( lookAt );
mEyeCameras[i]->setNearClipDistance( 0.2f );
mEyeCameras[i]->setFarClipDistance( 1000.0f );
mEyeCameras[i]->setAutoAspectRatio( true );
//By default cameras are attached to the Root Scene Node.
mEyeCameras[i]->detachFromParent();
mCamerasNode->attachObject( mEyeCameras[i] );
mEyeCameras[i]->getFrustumExtents(eyeFrustumExtents[i].x, eyeFrustumExtents[i].y, eyeFrustumExtents[i].w, eyeFrustumExtents[i].z, Ogre::FET_TAN_HALF_ANGLES);
}
mCamera = mEyeCameras[0];
//Create a camera for culling data
Ogre::Camera* mCullCamera = mSceneManager->createCamera("CameraCull");
Ogre::Vector4 cameraCullFrustumExtents;
cameraCullFrustumExtents.x = std::min(eyeFrustumExtents[0].x, -eyeFrustumExtents[1].y);
cameraCullFrustumExtents.y = -cameraCullFrustumExtents.x;
cameraCullFrustumExtents.z = std::max(eyeFrustumExtents[0].z, eyeFrustumExtents[1].z);
cameraCullFrustumExtents.w = std::min(eyeFrustumExtents[0].w, eyeFrustumExtents[1].w);
float mCullCameraOffset = (mEyeCameras[1]->getPosition().x - mEyeCameras[0]->getPosition().x) * 0.5f / cameraCullFrustumExtents.y;
mCullCamera->setPosition(0.0, 0.0, mCullCameraOffset);
mCullCamera->setNearClipDistance( 0.2f + mCullCameraOffset);
mCullCamera->setFarClipDistance(1000.0f);
mCullCamera->detachFromParent();
mCamerasNode->getParentSceneNode()->attachObject(mCullCamera);
mCullCamera->setFrustumExtents(cameraCullFrustumExtents.x, cameraCullFrustumExtents.y, cameraCullFrustumExtents.w, cameraCullFrustumExtents.z, Ogre::FET_TAN_HALF_ANGLES);
}
virtual Ogre::CompositorWorkspace* setupCompositor()
{
Ogre::CompositorManager2 *compositorManager = mRoot->getCompositorManager2();
//MAIN RENDER NODE DEFINITION
Ogre::CompositorNodeDef *renderNodeDef = compositorManager->addNodeDefinition("MainEngineRenderingNodeStereo");
renderNodeDef->addTextureSourceName("renderwindow", 0, Ogre::TextureDefinitionBase::TEXTURE_INPUT);
renderNodeDef->setNumLocalTextureDefinitions(1);
Ogre::TextureDefinitionBase::TextureDefinition *renderTex = renderNodeDef->addTextureDefinition("renderAux");
renderTex->textureFlags = Ogre::TextureFlags::RenderToTexture;
renderTex->format = Ogre::PFG_RGBA16_FLOAT;
renderTex->msaa = 1u;
Ogre::RenderTargetViewDef *rtv = renderNodeDef->addRenderTextureView("renderAux");
Ogre::RenderTargetViewEntry attachment;
attachment.textureName = "renderAux";
rtv->colourAttachments.push_back(attachment);
rtv->depthBufferId = Ogre::DepthBuffer::POOL_DEFAULT;
renderNodeDef->setNumTargetPass(3);
{
{
Ogre::CompositorTargetDef *targetDef = renderNodeDef->addTargetPass("renderAux");
targetDef->setNumPasses(1);
//SINGLE PASS STEREO PASS (or left eye when no available)
Ogre::CompositorPassSceneDef* mPassSceneDef = static_cast<Ogre::CompositorPassSceneDef*>(targetDef->addPass(Ogre::PASS_SCENE));
mPassSceneDef->mCameraName = "Left Eye";
mPassSceneDef->mCullCameraName = "CameraCull";
mPassSceneDef->setAllClearColours(Ogre::ColourValue::Black);
mPassSceneDef->setAllLoadActions(Ogre::LoadAction::Clear);
mPassSceneDef->mProfilingId = "LEFT_STEREO_SCENE_PASS";
mPassSceneDef->mVpLeft = 0.0f;
mPassSceneDef->mVpTop = 0.0f;
mPassSceneDef->mVpWidth = 0.5f;
mPassSceneDef->mVpHeight = 1.0f;
{ //Right eye
Ogre::CompositorTargetDef *targetDefRight = renderNodeDef->addTargetPass("renderAux");
targetDef->setNumPasses(1);
//RIGHT EYE
Ogre::CompositorPassSceneDef* mPassSceneDefRight = static_cast<Ogre::CompositorPassSceneDef*>(targetDefRight->addPass(Ogre::PASS_SCENE));
mPassSceneDefRight->mCameraName = "Right Eye";
mPassSceneDefRight->mCullCameraName = "CameraCull";
mPassSceneDefRight->mReuseCullData = true;
mPassSceneDefRight->mProfilingId = "RIGHT_STEREO_SCENE_PASS";
mPassSceneDefRight->mIdentifier = 25001;
mPassSceneDefRight->setAllStoreActions(Ogre::StoreAction::Store);
mPassSceneDefRight->mVpLeft = 0.5f;
mPassSceneDefRight->mVpTop = 0.0f;
mPassSceneDefRight->mVpWidth = 0.5f;
mPassSceneDefRight->mVpHeight = 1.0f;
}
}
//POST PROCESS
{
Ogre::CompositorTargetDef *targetDef = renderNodeDef->addTargetPass("renderwindow");
targetDef->setNumPasses(1);
//QUAD
Ogre::CompositorPassQuadDef *passQuadDef = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
passQuadDef->setAllLoadActions(Ogre::LoadAction::DontCare);
passQuadDef->mMaterialName = "Ogre/Copy/4xFP32";
passQuadDef->addQuadTextureSource(0, "renderAux");
passQuadDef->mProfilingId = "STEREO_FINAL_PROCESSING_QUAD_PASS";
}
}
//MAIN WORKSPACE DEFINITION
Ogre::CompositorWorkspaceDef *workspaceDef = compositorManager->addWorkspaceDefinition("StereoRenderingWorkspace2");
workspaceDef->connectExternal(0, "MainEngineRenderingNodeStereo", 0);
const Ogre::IdString workspaceName( "StereoRenderingWorkspace2" );
mEyeWorkspaces[0] = compositorManager->addWorkspace( mSceneManager,
mRenderWindow->getTexture(),
mEyeCameras[0], workspaceName,
true, -1, (Ogre::UavBufferPackedVec*)0,
(Ogre::ResourceLayoutMap*)0,
(Ogre::ResourceAccessMap*)0 );
Ogre::uint32 forwardPlusParams[8];
forwardPlusParams[0] = 4; //width
forwardPlusParams[1] = 4; //height
forwardPlusParams[2] = 24; //numSlices
forwardPlusParams[3] = 20; //lightsPerCell
forwardPlusParams[4] = 0; //decalsPerCell
forwardPlusParams[5] = 5; //cubemapProbesPerCel
forwardPlusParams[6] = 5; //minDistance
forwardPlusParams[7] = 500; //maxDistance
mSceneManager->setForwardClustered(true, forwardPlusParams[0], forwardPlusParams[1], forwardPlusParams[2],
forwardPlusParams[3], forwardPlusParams[4], forwardPlusParams[5], forwardPlusParams[6], forwardPlusParams[7]);
return mEyeWorkspaces[0];
}
public:
StereoGraphicsSystem( GameState *gameState ) :
GraphicsSystem( gameState )
{
}
};
void MainEntryPoints::createSystems( GameState **outGraphicsGameState,
GraphicsSystem **outGraphicsSystem,
GameState **outLogicGameState,
LogicSystem **outLogicSystem )
{
StereoRenderingGameState *gfxGameState = new StereoRenderingGameState(
"This tutorial demonstrates the most basic rendering loop: Variable framerate.\n"
"Variable framerate means the application adapts to the current frame rendering\n"
"performance and boosts or decreases the movement speed of objects to maintain\n"
"the appearance that objects are moving at a constant velocity.\n"
"When framerate is low, it looks 'frame skippy'; when framerate is high,\n"
"it looks very smooth.\n"
"Note: If you can't exceed 60 FPS, it's probably because of VSync being turned on.\n"
"\n"
"Despite what it seems, this is the most basic form of updating, and a horrible way\n"
"to update your objects if you want to do any kind of serious game development.\n"
"Keep going through the Tutorials for superior methods of updating the rendering loop.\n"
"\n"
"Note: The cube is black because there is no lighting. We are not focusing on that." );
GraphicsSystem *graphicsSystem = new StereoGraphicsSystem( gfxGameState );
gfxGameState->_notifyGraphicsSystem( graphicsSystem );
*outGraphicsGameState = gfxGameState;
*outGraphicsSystem = graphicsSystem;
}
void MainEntryPoints::destroySystems( GameState *graphicsGameState,
GraphicsSystem *graphicsSystem,
GameState *logicGameState,
LogicSystem *logicSystem )
{
delete graphicsSystem;
delete graphicsGameState;
}
const char* MainEntryPoints::getWindowTitle(void)
{
return "Stereo Rendering Sample";
}
}