/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2006 Torus Knot Software Ltd Also see acknowledgements in Readme.html You may use this sample code for anything you like, it is not covered by the LGPL like the rest of the engine. ----------------------------------------------------------------------------- */ /** \file Shadows.cpp \brief Shows a few ways to use Ogre's shadowing techniques */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "OgreCEGUIRenderer.h" #include "OgreCEGUIResourceProvider.h" #include "ExampleApplication.h" /* #include "OgreNoMemoryMacros.h" #include #include #include "OgreMemoryMacros.h" */ /* #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 #include "OgreNoMemoryMacros.h" #include #endi*/ Entity* mAthene; AnimationState* mAnimState = 0; Entity* pPlaneEnt; std::vector pColumns; Light* mLight; Light* mSunLight; SceneNode* mLightNode = 0; AnimationState* mLightAnimationState = 0; ColourValue mMinLightColour(0.2, 0.1, 0.0); ColourValue mMaxLightColour(0.5, 0.3, 0.1); Real mMinFlareSize = 40; Real mMaxFlareSize = 80; // New depth shadowmapping String CUSTOM_ROCKWALL_MATERIAL("Ogre/DepthShadowmap/Receiver/RockWall"); String CUSTOM_CASTER_MATERIAL("Ogre/DepthShadowmap/Caster/Float"); String CUSTOM_RECEIVER_MATERIAL("Ogre/DepthShadowmap/Receiver/Float"); String CUSTOM_ATHENE_MATERIAL("Ogre/DepthShadowmap/Receiver/Athene"); String BASIC_ROCKWALL_MATERIAL("Examples/Rockwall"); String BASIC_ATHENE_MATERIAL("Examples/Athene/NormalMapped"); OverlayElement* mShadowTechniqueInfo; OverlayElement* mMaterialInfo; OverlayElement* mInfo; /** This class 'wibbles' the light and billboard */ class LightWibbler : public ControllerValue { protected: Light* mLight; Billboard* mBillboard; ColourValue mColourRange; ColourValue mMinColour; Real mMinSize; Real mSizeRange; Real intensity; public: LightWibbler(Light* light, Billboard* billboard, const ColourValue& minColour, const ColourValue& maxColour, Real minSize, Real maxSize) { mLight = light; mBillboard = billboard; mMinColour = minColour; mColourRange.r = maxColour.r - minColour.r; mColourRange.g = maxColour.g - minColour.g; mColourRange.b = maxColour.b - minColour.b; mMinSize = minSize; mSizeRange = maxSize - minSize; } virtual Real getValue (void) const { return intensity; } virtual void setValue (Real value) { intensity = value; ColourValue newColour; // Attenuate the brightness of the light newColour.r = mMinColour.r + (mColourRange.r * intensity); newColour.g = mMinColour.g + (mColourRange.g * intensity); newColour.b = mMinColour.b + (mColourRange.b * intensity); mLight->setDiffuseColour(newColour); mBillboard->setColour(newColour); // set billboard size Real newSize = mMinSize + (intensity * mSizeRange); mBillboard->setDimensions(newSize, newSize); } }; Real timeDelay = 0; #define KEY_PRESSED(_key,_timeDelay, _macro) \ { \ if (mKeyboard->isKeyDown(_key) && timeDelay <= 0) \ { \ timeDelay = _timeDelay; \ _macro ; \ } \ } //--------------------------------------------------------------------------- class GaussianListener: public Ogre::CompositorInstance::Listener { protected: int mVpWidth, mVpHeight; // Array params - have to pack in groups of 4 since this is how Cg generates them // also prevents dependent texture read problems if ops don't require swizzle float mBloomTexWeights[15][4]; float mBloomTexOffsetsHorz[15][4]; float mBloomTexOffsetsVert[15][4]; public: GaussianListener() {} virtual ~GaussianListener() {} void notifyViewportSize(int width, int height) { mVpWidth = width; mVpHeight = height; // Calculate gaussian texture offsets & weights float deviation = 3.0f; float texelSize = 1.0f / (float)std::min(mVpWidth, mVpHeight); // central sample, no offset mBloomTexOffsetsHorz[0][0] = 0.0f; mBloomTexOffsetsHorz[0][1] = 0.0f; mBloomTexOffsetsVert[0][0] = 0.0f; mBloomTexOffsetsVert[0][1] = 0.0f; mBloomTexWeights[0][0] = mBloomTexWeights[0][1] = mBloomTexWeights[0][2] = Ogre::Math::gaussianDistribution(0, 0, deviation); mBloomTexWeights[0][3] = 1.0f; // 'pre' samples for(int i = 1; i < 8; ++i) { mBloomTexWeights[i][0] = mBloomTexWeights[i][1] = mBloomTexWeights[i][2] = Ogre::Math::gaussianDistribution(i, 0, deviation); mBloomTexWeights[i][3] = 1.0f; mBloomTexOffsetsHorz[i][0] = i * texelSize; mBloomTexOffsetsHorz[i][1] = 0.0f; mBloomTexOffsetsVert[i][0] = 0.0f; mBloomTexOffsetsVert[i][1] = i * texelSize; } // 'post' samples for(int i = 8; i < 15; ++i) { mBloomTexWeights[i][0] = mBloomTexWeights[i][1] = mBloomTexWeights[i][2] = mBloomTexWeights[i - 7][0]; mBloomTexWeights[i][3] = 1.0f; mBloomTexOffsetsHorz[i][0] = -mBloomTexOffsetsHorz[i - 7][0]; mBloomTexOffsetsHorz[i][1] = 0.0f; mBloomTexOffsetsVert[i][0] = 0.0f; mBloomTexOffsetsVert[i][1] = -mBloomTexOffsetsVert[i - 7][1]; } } virtual void notifyMaterialSetup(Ogre::uint32 pass_id, Ogre::MaterialPtr &mat) { // Prepare the fragment params offsets switch(pass_id) { case 701: // blur horz { // horizontal bloom mat->load(); Ogre::GpuProgramParametersSharedPtr fparams = mat->getBestTechnique()->getPass(0)->getFragmentProgramParameters(); const Ogre::String& progName = mat->getBestTechnique()->getPass(0)->getFragmentProgramName(); // A bit hacky - Cg & HLSL index arrays via [0], GLSL does not fparams->setNamedConstant("sampleOffsets", mBloomTexOffsetsHorz[0], 15); fparams->setNamedConstant("sampleWeights", mBloomTexWeights[0], 15); break; } case 700: // blur vert { // vertical bloom mat->load(); Ogre::GpuProgramParametersSharedPtr fparams = mat->getTechnique(0)->getPass(0)->getFragmentProgramParameters(); const Ogre::String& progName = mat->getBestTechnique()->getPass(0)->getFragmentProgramName(); fparams->setNamedConstant("sampleOffsets", mBloomTexOffsetsVert[0], 15); fparams->setNamedConstant("sampleWeights", mBloomTexWeights[0], 15); break; } } } virtual void notifyMaterialRender(Ogre::uint32 pass_id, Ogre::MaterialPtr &mat) { } }; GaussianListener gaussianListener; class ShadowsListener : public ExampleFrameListener, public OIS::MouseListener, public OIS::KeyListener { protected: SceneManager* mSceneMgr; Viewport *mShadowVp; CompositorInstance* mShadowCompositor; bool mShutdownRequested; CEGUI::Window* mRootGuiPanel; bool mLMBDown; bool mRMBDown; bool mProcessMovement; bool mUpdateMovement; bool mMoveFwd; bool mMoveBck; bool mMoveLeft; bool mMoveRight; CEGUI::Point mLastMousePosition; bool mLastMousePositionSet; float mAvgFrameTime; Camera* mTexCam; //----------------------------------------------------------------// CEGUI::MouseButton convertOISMouseButtonToCegui(int buttonID) { switch (buttonID) { case 0: return CEGUI::LeftButton; case 1: return CEGUI::RightButton; case 2: return CEGUI::MiddleButton; case 3: return CEGUI::X1Button; default: return CEGUI::LeftButton; } } public: ShadowsListener(RenderWindow* win, Camera* cam, SceneManager* sm) : ExampleFrameListener(win, cam, true, true) , mSceneMgr(sm) , mShadowVp(0) , mShadowCompositor(0) , mShutdownRequested(false) , mLMBDown(false) , mRMBDown(false) , mProcessMovement(false) , mUpdateMovement(false) , mMoveFwd(false) , mMoveBck(false) , mMoveLeft(false) , mMoveRight(false) , mLastMousePositionSet(false) , mAvgFrameTime(0.1f) { mMouse->setEventCallback(this); mKeyboard->setEventCallback(this); mRootGuiPanel = CEGUI::WindowManager::getSingleton().getWindow("Shadows"); mMoveSpeed = 10.0f; // Set up a debug panel to display the shadow MaterialPtr debugMat = MaterialManager::getSingleton().create( "Ogre/DebugShadowMap0", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); TexturePtr shadowTex = mSceneMgr->getShadowTexture(0); TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(shadowTex->getName()); t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); debugMat = MaterialManager::getSingleton().create( "Ogre/DebugShadowMap1", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); shadowTex = mSceneMgr->getShadowTexture(1); t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(shadowTex->getName()); t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); /* Uncomment this to display the shadow textures OverlayContainer* debugPanel = (OverlayContainer*) (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/DebugShadowPanel0")); debugPanel->_setPosition(0.8, 0); debugPanel->_setDimensions(0.2, 0.2); debugPanel->setMaterialName("Ogre/DebugShadowMap0"); Overlay* debugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay"); debugOverlay->add2D(debugPanel); debugPanel = (OverlayContainer*) (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/DebugShadowPanel1")); debugPanel->_setPosition(0.8, 0.2); debugPanel->_setDimensions(0.2, 0.2); debugPanel->setMaterialName("Ogre/DebugShadowMap1"); debugOverlay->add2D(debugPanel); */ } bool frameStarted(const FrameEvent& evt) { CEGUI::System::getSingleton().injectTimePulse(evt.timeSinceLastFrame); mMouse->capture(); mKeyboard->capture(); if (mShutdownRequested) return false; else { // update movement process if(mProcessMovement || mUpdateMovement) { mTranslateVector.x += mMoveLeft ? mAvgFrameTime * -mMoveSpeed : 0; mTranslateVector.x += mMoveRight ? mAvgFrameTime * mMoveSpeed : 0; mTranslateVector.z += mMoveFwd ? mAvgFrameTime * -mMoveSpeed : 0; mTranslateVector.z += mMoveBck ? mAvgFrameTime * mMoveSpeed : 0; mCamera->yaw(mRotX); mCamera->pitch(mRotY); mCamera->moveRelative(mTranslateVector); mUpdateMovement = false; mRotX = 0; mRotY = 0; mTranslateVector = Ogre::Vector3::ZERO; } } return true; } bool frameEnded(const FrameEvent& evt) { if (mAnimState) mAnimState->addTime(evt.timeSinceLastFrame); if (mShutdownRequested) return false; else return ExampleFrameListener::frameEnded(evt); } //----------------------------------------------------------------// bool mouseMoved( const OIS::MouseEvent &arg ) { CEGUI::System::getSingleton().injectMouseMove( arg.state.X.rel, arg.state.Y.rel ); return true; } //----------------------------------------------------------------// bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) { CEGUI::System::getSingleton().injectMouseButtonDown(convertOISMouseButtonToCegui(id)); return true; } //----------------------------------------------------------------// bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) { CEGUI::System::getSingleton().injectMouseButtonUp(convertOISMouseButtonToCegui(id)); return true; } //----------------------------------------------------------------// bool keyPressed( const OIS::KeyEvent &arg ) { if( arg.key == OIS::KC_ESCAPE ) mShutdownRequested = true; if (arg.key == OIS::KC_SYSRQ) mWindow->writeContentsToTimestampedFile("screenshot", ".jpg"); CEGUI::System::getSingleton().injectKeyDown( arg.key ); CEGUI::System::getSingleton().injectChar( arg.text ); return true; } //----------------------------------------------------------------// bool keyReleased( const OIS::KeyEvent &arg ) { CEGUI::System::getSingleton().injectKeyUp( arg.key ); return true; } //-------------------------------------------------------------------------- bool handleMouseMove(const CEGUI::EventArgs& e) { const CEGUI::MouseEventArgs& me = static_cast(e); if( mLMBDown && !mRMBDown) { // rotate camera mRotX += Degree(-me.moveDelta.d_x * mAvgFrameTime * 3.0); mRotY += Degree(-me.moveDelta.d_y * mAvgFrameTime * 3.0); CEGUI::MouseCursor::getSingleton().setPosition( mLastMousePosition ); mUpdateMovement = true; } else { if( mRMBDown && !mLMBDown) { // translate camera mTranslateVector.x += me.moveDelta.d_x * mAvgFrameTime * mMoveSpeed; mTranslateVector.y += -me.moveDelta.d_y * mAvgFrameTime * mMoveSpeed; //mTranslateVector.z = 0; CEGUI::MouseCursor::getSingleton().setPosition( mLastMousePosition ); mUpdateMovement = true; } else { if( mRMBDown && mLMBDown) { mTranslateVector.z += (me.moveDelta.d_x + me.moveDelta.d_y) * mAvgFrameTime * mMoveSpeed; CEGUI::MouseCursor::getSingleton().setPosition( mLastMousePosition ); mUpdateMovement = true; } } } return true; } //-------------------------------------------------------------------------- bool handleMouseButtonUp(const CEGUI::EventArgs& e) { const CEGUI::MouseEventArgs& me = static_cast(e); //Window* wndw = ((const WindowEventArgs&)e).window; if( me.button == CEGUI::LeftButton ) { mLMBDown = false; } if( me.button == CEGUI::RightButton ) { mRMBDown = false; } if( !mLMBDown && !mRMBDown ) { CEGUI::MouseCursor::getSingleton().show(); if(mLastMousePositionSet) { CEGUI::MouseCursor::getSingleton().setPosition( mLastMousePosition ); mLastMousePositionSet = false; } mRootGuiPanel->releaseInput(); } return true; } //-------------------------------------------------------------------------- bool handleMouseButtonDown(const CEGUI::EventArgs& e) { const CEGUI::MouseEventArgs& me = static_cast(e); //Window* wndw = ((const WindowEventArgs&)e).window; if( me.button == CEGUI::LeftButton ) { mLMBDown = true; } if( me.button == CEGUI::RightButton ) { mRMBDown = true; } if( mLMBDown || mRMBDown ) { CEGUI::MouseCursor::getSingleton().hide(); if (!mLastMousePositionSet) { mLastMousePosition = CEGUI::MouseCursor::getSingleton().getPosition(); mLastMousePositionSet = true; } mRootGuiPanel->captureInput(); } return true; } //-------------------------------------------------------------------------- bool handleMouseWheelEvent(const CEGUI::EventArgs& e) { const CEGUI::MouseEventArgs& me = static_cast(e); mTranslateVector.z += me.wheelChange * -5.0; mUpdateMovement = true; return true; } //-------------------------------------------------------------------------- void checkMovementKeys(CEGUI::Key::Scan scancode, bool state ) { switch ( scancode ) { case CEGUI::Key::A: mMoveLeft = state; break; case CEGUI::Key::D: mMoveRight = state; break; case CEGUI::Key::S: mMoveBck = state; break; case CEGUI::Key::W: mMoveFwd = state; break; default: break; } mProcessMovement = mMoveLeft || mMoveRight || mMoveFwd || mMoveBck; } //-------------------------------------------------------------------------- bool handleKeyDownEvent(const CEGUI::EventArgs& e) { const CEGUI::KeyEventArgs& ke = static_cast(e); checkMovementKeys(ke.scancode , true); return true; } //-------------------------------------------------------------------------- bool handleKeyUpEvent(const CEGUI::EventArgs& e) { const CEGUI::KeyEventArgs& ke = static_cast(e); checkMovementKeys(ke.scancode, false ); return true; } }; class ShadowsApplication : public ExampleApplication { protected: enum ShadowProjection { UNIFORM, UNIFORM_FOCUSED, LISPSM, PLANE_OPTIMAL }; enum ShadowMaterial { MAT_STANDARD, MAT_DEPTH_FLOAT, MAT_DEPTH_FLOAT_PCF }; CEGUI::OgreCEGUIRenderer* mGUIRenderer; CEGUI::System* mGUISystem; CEGUI::Window* mDescWindow; CEGUI::Scrollbar* mFixedBias; CEGUI::Scrollbar* mGradientBias; CEGUI::Scrollbar* mGradientClamp; CEGUI::Window* mDepthShadowTweak; CEGUI::Window* mFixedBiasText; CEGUI::Window* mGradientBiasText; CEGUI::Window* mGradientClampText; ShadowTechnique mCurrentShadowTechnique; ShadowProjection mCurrentProjection; ShadowMaterial mCurrentMaterial; GpuProgramParametersSharedPtr mCustomRockwallVparams; GpuProgramParametersSharedPtr mCustomRockwallFparams; GpuProgramParametersSharedPtr mCustomAtheneVparams; GpuProgramParametersSharedPtr mCustomAtheneFparams; ShadowCameraSetupPtr mCurrentShadowCameraSetup; /// Plane that defines plane-optimal shadow mapping basis MovablePlane* mPlane; // transient pointer to LiSPSM setup if present LiSPSMShadowCameraSetup* mLiSPSMSetup; bool mIsOpenGL; public: ShadowsApplication() : mGUIRenderer(0), mGUISystem(0), mPlane(0) { } ~ShadowsApplication() { mDescWindow = 0; if(mGUISystem) { delete mGUISystem; mGUISystem = 0; } if(mGUIRenderer) { delete mGUIRenderer; mGUIRenderer = 0; } delete mPlane; } protected: // Override this to ensure FPU mode bool configure(void) { // Show the configuration dialog and initialise the system // You can skip this and use root.restoreConfig() to load configuration // settings if you were sure there are valid ones saved in ogre.cfg if(mRoot->showConfigDialog()) { // Custom option - to use PlaneOptimalShadowCameraSetup we must have // double-precision. Thus, set the D3D floating point mode if present, // no matter what was chosen ConfigOptionMap& optMap = mRoot->getRenderSystem()->getConfigOptions(); ConfigOptionMap::iterator i = optMap.find("Floating-point mode"); if (i != optMap.end()) { if (i->second.currentValue != "Consistent") { i->second.currentValue = "Consistent"; LogManager::getSingleton().logMessage("Demo_Shadows: overriding " "D3D floating point mode to 'Consistent' to ensure precision " "for plane-optimal camera setup option"); } } // If returned true, user clicked OK so initialise // Here we choose to let the system create a default rendering window by passing 'true' mWindow = mRoot->initialise(true); return true; } else { return false; } } void generalSceneSetup() { // do this first so we generate edge lists mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE); mCurrentShadowTechnique = SHADOWTYPE_STENCIL_ADDITIVE; // Set ambient light off mSceneMgr->setAmbientLight(ColourValue(0.0, 0.0, 0.0)); // Fixed light, dim mSunLight = mSceneMgr->createLight("SunLight"); mSunLight->setType(Light::LT_SPOTLIGHT); mSunLight->setPosition(1500,1750,1300); mSunLight->setSpotlightRange(Degree(30), Degree(50)); Vector3 dir; dir = -mSunLight->getPosition(); dir.normalise(); mSunLight->setDirection(dir); mSunLight->setDiffuseColour(0.35, 0.35, 0.38); mSunLight->setSpecularColour(0.9, 0.9, 1); // Point light, movable, reddish mLight = mSceneMgr->createLight("Light2"); mLight->setDiffuseColour(mMinLightColour); mLight->setSpecularColour(1, 1, 1); mLight->setAttenuation(8000,1,0.0005,0); // Create light node mLightNode = mSceneMgr->getRootSceneNode()->createChildSceneNode( "MovingLightNode"); mLightNode->attachObject(mLight); // create billboard set BillboardSet* bbs = mSceneMgr->createBillboardSet("lightbbs", 1); bbs->setMaterialName("Examples/Flare"); Billboard* bb = bbs->createBillboard(0,0,0,mMinLightColour); // attach mLightNode->attachObject(bbs); // create controller, after this is will get updated on its own ControllerFunctionRealPtr func = ControllerFunctionRealPtr( new WaveformControllerFunction(Ogre::WFT_SINE, 0.75, 0.5)); ControllerManager& contMgr = ControllerManager::getSingleton(); ControllerValueRealPtr val = ControllerValueRealPtr( new LightWibbler(mLight, bb, mMinLightColour, mMaxLightColour, mMinFlareSize, mMaxFlareSize)); Controller* controller = contMgr.createController( contMgr.getFrameTimeSource(), val, func); //mLight->setPosition(Vector3(300,250,-300)); mLightNode->setPosition(Vector3(300,1750,-700)); // Create a track for the light Animation* anim = mSceneMgr->createAnimation("LightTrack", 20); // Spline it for nice curves anim->setInterpolationMode(Animation::IM_SPLINE); // Create a track to animate the camera's node NodeAnimationTrack* track = anim->createNodeTrack(0, mLightNode); // Setup keyframes TransformKeyFrame* key = track->createNodeKeyFrame(0); // A startposition key->setTranslate(Vector3(300,750,-700)); key = track->createNodeKeyFrame(2);//B key->setTranslate(Vector3(150,800,-250)); key = track->createNodeKeyFrame(4);//C key->setTranslate(Vector3(-150,850,-100)); key = track->createNodeKeyFrame(6);//D key->setTranslate(Vector3(-400,700,-200)); key = track->createNodeKeyFrame(8);//E key->setTranslate(Vector3(-200,700,-400)); key = track->createNodeKeyFrame(10);//F key->setTranslate(Vector3(-100,850,-200)); key = track->createNodeKeyFrame(12);//G key->setTranslate(Vector3(-100,575,180)); key = track->createNodeKeyFrame(14);//H key->setTranslate(Vector3(0,750,300)); key = track->createNodeKeyFrame(16);//I key->setTranslate(Vector3(100,850,100)); key = track->createNodeKeyFrame(18);//J key->setTranslate(Vector3(250,800,0)); key = track->createNodeKeyFrame(20);//K == A key->setTranslate(Vector3(300,750,-700)); // Create a new animation state to track this mAnimState = mSceneMgr->createAnimationState("LightTrack"); mAnimState->setEnabled(true); // Make light node look at origin, this is for when we // change the moving light to a spotlight mLightNode->setAutoTracking(true, mSceneMgr->getRootSceneNode()); // Prepare athene mesh for normalmapping MeshPtr pAthene = MeshManager::getSingleton().load("athene.mesh", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); unsigned short src, dest; if (!pAthene->suggestTangentVectorBuildParams(VES_TANGENT, src, dest)) { pAthene->buildTangentVectors(VES_TANGENT, src, dest); } SceneNode* node; node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); mAthene = mSceneMgr->createEntity( "athene", "athene.mesh" ); mAthene->setMaterialName(BASIC_ATHENE_MATERIAL); node->attachObject( mAthene ); node->translate(0,-27, 0); node->yaw(Degree(90)); Entity* pEnt; // Columns for (int x = -2; x <= 2; ++x) { for (int z = -2; z <= 2; ++z) { if (x != 0 || z != 0) { StringUtil::StrStreamType str; str << "col" << x << "_" << z; node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); pEnt = mSceneMgr->createEntity( str.str(), "column.mesh" ); pEnt->setMaterialName(BASIC_ROCKWALL_MATERIAL); pColumns.push_back(pEnt); node->attachObject( pEnt ); node->translate(x*300,0, z*300); } } } // Skybox mSceneMgr->setSkyBox(true, "Examples/StormySkyBox"); // Floor plane (use POSM plane def) mPlane = new MovablePlane("*mPlane"); mPlane->normal = Vector3::UNIT_Y; mPlane->d = 107; MeshManager::getSingleton().createPlane("Myplane", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, *mPlane, 1500,1500,50,50,true,1,5,5,Vector3::UNIT_Z); pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" ); pPlaneEnt->setMaterialName(BASIC_ROCKWALL_MATERIAL); pPlaneEnt->setCastShadows(false); mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt); if (mRoot->getRenderSystem()->getCapabilities()->hasCapability(RSC_HWRENDER_TO_TEXTURE)) { // In D3D, use a 1024x1024 shadow texture mSceneMgr->setShadowTextureSettings(1024, 2); } else { // Use 512x512 texture in GL since we can't go higher than the window res mSceneMgr->setShadowTextureSettings(512, 2); } mSceneMgr->setShadowColour(ColourValue(0.5, 0.5, 0.5)); // incase infinite far distance is not supported mCamera->setFarClipDistance(100000); //mSceneMgr->setShowDebugShadows(true); mCamera->setPosition(250, 20, 400); mCamera->lookAt(0, 10, 0); } // Just override the mandatory create scene method void createScene(void) { // Need to detect D3D or GL for best depth shadowmapping if (Root::getSingleton().getRenderSystem()->getName().find("GL") != String::npos) { mIsOpenGL = true; } else { mIsOpenGL = false; } // set up general scene (this defaults to additive stencils) generalSceneSetup(); setupGUI(); } /// Change basic shadow technique void changeShadowTechnique(ShadowTechnique newTech) { mSceneMgr->setShadowTechnique(newTech); // Below is for projection //configureShadowCameras(mCurrentShadowTechnique, newTech); configureLights(newTech); // Advanced modes - materials / compositors //configureCompositors(mCurrentShadowTechnique, newTech); //configureTextures(mCurrentShadowTechnique, newTech); //configureShadowCasterReceiverMaterials(mCurrentShadowTechnique, newTech); updateGUI(newTech); mCurrentShadowTechnique = newTech; } void configureLights(ShadowTechnique newTech) { Vector3 dir; switch (newTech) { case SHADOWTYPE_STENCIL_ADDITIVE: // Fixed light, dim mSunLight->setCastShadows(true); // Point light, movable, reddish mLight->setType(Light::LT_POINT); mLight->setCastShadows(true); mLight->setDiffuseColour(mMinLightColour); mLight->setSpecularColour(1, 1, 1); mLight->setAttenuation(8000,1,0.0005,0); break; case SHADOWTYPE_STENCIL_MODULATIVE: // Multiple lights cause obvious silhouette edges in modulative mode // So turn off shadows on the direct light // Fixed light, dim mSunLight->setCastShadows(false); // Point light, movable, reddish mLight->setType(Light::LT_POINT); mLight->setCastShadows(true); mLight->setDiffuseColour(mMinLightColour); mLight->setSpecularColour(1, 1, 1); mLight->setAttenuation(8000,1,0.0005,0); break; case SHADOWTYPE_TEXTURE_MODULATIVE: case SHADOWTYPE_TEXTURE_ADDITIVE: // Fixed light, dim mSunLight->setCastShadows(true); // Change moving light to spotlight // Point light, movable, reddish mLight->setType(Light::LT_SPOTLIGHT); mLight->setDirection(Vector3::NEGATIVE_UNIT_Z); mLight->setCastShadows(true); mLight->setDiffuseColour(mMinLightColour); mLight->setSpecularColour(1, 1, 1); mLight->setAttenuation(8000,1,0.0005,0); mLight->setSpotlightRange(Degree(80),Degree(90)); break; default: break; }; } void setupGUI() { // setup GUI system mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mSceneMgr); mGUISystem = new CEGUI::System(mGUIRenderer); CEGUI::Logger::getSingleton().setLoggingLevel(CEGUI::Informative); // load scheme and set up defaults CEGUI::SchemeManager::getSingleton().loadScheme( (CEGUI::utf8*)"TaharezLookSkin.scheme"); mGUISystem->setDefaultMouseCursor( (CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MouseArrow"); mGUISystem->setDefaultFont((CEGUI::utf8*)"BlueHighway-12"); CEGUI::Window* sheet = CEGUI::WindowManager::getSingleton().loadWindowLayout( (CEGUI::utf8*)"shadows.layout"); mGUISystem->setGUISheet(sheet); // Tooltips aren't big enough, do our own //mGUISystem->setDefaultTooltip("TaharezLook/Tooltip"); CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton(); // Get description window mDescWindow = wmgr.getWindow("Shadows/Desc"); CEGUI::Window *wnd = wmgr.getWindow("Shadows/Stencil"); wnd->subscribeEvent(CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseEnter, this)); wnd->subscribeEvent(CEGUI::Window::EventMouseLeaves, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseLeave, this)); wnd = wmgr.getWindow("Shadows/Texture"); wnd->subscribeEvent(CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseEnter, this)); wnd->subscribeEvent(CEGUI::Window::EventMouseLeaves, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseLeave, this)); wnd = wmgr.getWindow("Shadows/Additive"); wnd->subscribeEvent(CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseEnter, this)); wnd->subscribeEvent(CEGUI::Window::EventMouseLeaves, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseLeave, this)); wnd = wmgr.getWindow("Shadows/Modulative"); wnd->subscribeEvent(CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseEnter, this)); wnd->subscribeEvent(CEGUI::Window::EventMouseLeaves, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseLeave, this)); // Combo doesn't raise enter / exit itself, have to grab subcomponents? CEGUI::Combobox* cbo = static_cast(wmgr.getWindow("Shadows/Projection")); cbo->subscribeEvent(CEGUI::Combobox::EventListSelectionAccepted, CEGUI::Event::Subscriber(&ShadowsApplication::handleProjectionChanged, this)); cbo->getEditbox()->subscribeEvent(CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseEnterCombo, this)); cbo->getEditbox()->subscribeEvent(CEGUI::Window::EventMouseLeaves, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseLeave, this)); cbo->getDropList()->subscribeEvent(CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseEnterCombo, this)); cbo->getDropList()->subscribeEvent(CEGUI::Window::EventMouseLeaves, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseLeave, this)); cbo->getPushButton()->subscribeEvent(CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseEnterCombo, this)); cbo->getPushButton()->subscribeEvent(CEGUI::Window::EventMouseLeaves, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseLeave, this)); // Populate projection // Get a select image to be used for highlighting items in listbox when mouse moves over them const CEGUI::Image* selectImage = &CEGUI::ImagesetManager::getSingleton().getImageset("TaharezLook")->getImage("MultiListSelectionBrush"); CEGUI::ListboxTextItem* li = new CEGUI::ListboxTextItem("Uniform", UNIFORM); li->setSelectionBrushImage(selectImage); li->setTooltipText("Uniform: Shadows are rendered and projected using a uniform " "frustum for the whole light coverage. Simple and lowest quality."); cbo->addItem(li); cbo->setItemSelectState(li, true); cbo->setText("Uniform"); mCurrentProjection = UNIFORM; li = new CEGUI::ListboxTextItem("Uniform Focused", UNIFORM_FOCUSED); li->setSelectionBrushImage(selectImage); li->setTooltipText("Uniform Focused: As Uniform except that the frustum is " "focused on the visible area of the camera. Better quality than Uniform " "at the expense of some 'swimming'."); cbo->addItem(li); li = new CEGUI::ListboxTextItem("LiSPSM", LISPSM); li->setSelectionBrushImage(selectImage); li->setTooltipText("LiSPSM: The frustum is distorted to take into account " "the perspective of the camera, and focused on the visible area. " "Good quality & flexibility."); cbo->addItem(li); li = new CEGUI::ListboxTextItem("Plane Optimal", PLANE_OPTIMAL); li->setSelectionBrushImage(selectImage); li->setTooltipText("Plane Optimal: The frustum is optimised to project " "shadows onto a plane of interest. Best possible quality for the " "plane, less good for other receiver angles."); cbo->addItem(li); cbo = static_cast(wmgr.getWindow("Shadows/Material")); cbo->getEditbox()->subscribeEvent(CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseEnterCombo, this)); cbo->getEditbox()->subscribeEvent(CEGUI::Window::EventMouseLeaves, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseLeave, this)); cbo->getDropList()->subscribeEvent(CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseEnterCombo, this)); cbo->getDropList()->subscribeEvent(CEGUI::Window::EventMouseLeaves, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseLeave, this)); cbo->getPushButton()->subscribeEvent(CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseEnterCombo, this)); cbo->getPushButton()->subscribeEvent(CEGUI::Window::EventMouseLeaves, CEGUI::Event::Subscriber(&ShadowsApplication::handleMouseLeave, this)); cbo->subscribeEvent(CEGUI::Combobox::EventListSelectionAccepted, CEGUI::Event::Subscriber(&ShadowsApplication::handleMaterialChanged, this)); li = new CEGUI::ListboxTextItem("Standard", MAT_STANDARD); li->setSelectionBrushImage(selectImage); li->setTooltipText("Standard Material: Shadows are rendered into a simple RGB texture " " and are received only by objects that are not themselves shadow casters " " (no self-shadowing)"); cbo->addItem(li); cbo->setItemSelectState(li, true); cbo->setText("Standard"); mCurrentMaterial = MAT_STANDARD; // Only add depth shadowmapping if supported if (GpuProgramManager::getSingleton().isSyntaxSupported("ps_2_0") || GpuProgramManager::getSingleton().isSyntaxSupported("glsl")) { li = new CEGUI::ListboxTextItem("Depth Shadowmap", MAT_DEPTH_FLOAT); li->setSelectionBrushImage(selectImage); li->setTooltipText("Depth Shadowmap: Shadow caster depth is rendered into a " " floating point texture and a depth comparison is performed on receivers " " (self-shadowing allowed). Requires floating point textures and shader support."); cbo->addItem(li); li = new CEGUI::ListboxTextItem("Depth Shadowmap (PCF)", MAT_DEPTH_FLOAT_PCF); li->setSelectionBrushImage(selectImage); li->setTooltipText("Depth Shadowmap (PCF): Shadow caster depth is rendered into a " " floating point texture and a depth comparison is performed on receivers " " (self-shadowing allowed), with a percentage closest filter. Requires " "floating point textures and shader support."); cbo->addItem(li); } CEGUI::RadioButton* radio = static_cast( wmgr.getWindow("Shadows/Stencil")); radio->setSelected(true); radio->subscribeEvent(CEGUI::RadioButton::EventSelectStateChanged, CEGUI::Event::Subscriber(&ShadowsApplication::handleShadowTypeChanged, this)); radio = static_cast(wmgr.getWindow("Shadows/Texture")); radio->subscribeEvent(CEGUI::RadioButton::EventSelectStateChanged, CEGUI::Event::Subscriber(&ShadowsApplication::handleShadowTypeChanged, this)); radio = static_cast(wmgr.getWindow("Shadows/Modulative")); radio->subscribeEvent(CEGUI::RadioButton::EventSelectStateChanged, CEGUI::Event::Subscriber(&ShadowsApplication::handleShadowTypeChanged, this)); radio = static_cast(wmgr.getWindow("Shadows/Additive")); radio->setSelected(true); radio->subscribeEvent(CEGUI::RadioButton::EventSelectStateChanged, CEGUI::Event::Subscriber(&ShadowsApplication::handleShadowTypeChanged, this)); mFixedBias = static_cast(wmgr.getWindow("Shadows/DepthShadowTweakGroup/FixedBias")); mFixedBias->setScrollPosition(0.002f); mFixedBias->subscribeEvent(CEGUI::Scrollbar::EventScrollPositionChanged, CEGUI::Event::Subscriber(&ShadowsApplication::handleParamsChanged, this)); mGradientBias = static_cast(wmgr.getWindow("Shadows/DepthShadowTweakGroup/SlopeBias")); mGradientBias->setScrollPosition(0.0008f); mGradientBias->subscribeEvent(CEGUI::Scrollbar::EventScrollPositionChanged, CEGUI::Event::Subscriber(&ShadowsApplication::handleParamsChanged, this)); mGradientClamp = static_cast(wmgr.getWindow("Shadows/DepthShadowTweakGroup/SlopeClamp")); mGradientClamp->setScrollPosition(0.02f); mGradientClamp->subscribeEvent(CEGUI::Scrollbar::EventScrollPositionChanged, CEGUI::Event::Subscriber(&ShadowsApplication::handleParamsChanged, this)); mDepthShadowTweak = wmgr.getWindow("Shadows/DepthShadowTweakGroup"); mDepthShadowTweak->setVisible(false); mFixedBiasText = wmgr.getWindow("Shadows/DepthShadowTweakGroup/FixedBiasText"); mGradientBiasText = wmgr.getWindow("Shadows/DepthShadowTweakGroup/SlopeBiasText"); mGradientClampText = wmgr.getWindow("Shadows/DepthShadowTweakGroup/SlopeClampText"); updateGUI(mCurrentShadowTechnique); } void updateGUI(ShadowTechnique newTech) { bool isTextureBased = (newTech & SHADOWDETAILTYPE_TEXTURE) != 0; // Stencil based technique, turn off the texture-specific options CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton(); CEGUI::Window* win = wmgr.getWindow("Shadows/Projection"); win->setEnabled(isTextureBased); win = wmgr.getWindow("Shadows/Material"); win->setEnabled(isTextureBased); } /// callback when mouse enters a described field (non-combo) bool handleMouseEnter(const CEGUI::EventArgs& e) { const CEGUI::WindowEventArgs& winargs = static_cast(e); mDescWindow->setText(winargs.window->getTooltipText()); return true; } /// callback when mouse leaves a described field bool handleMouseLeave(const CEGUI::EventArgs& e) { //if (mDescWindow) // mDescWindow->setText(""); return true; } void updateTipForCombo(CEGUI::Combobox* cbo) { CEGUI::String text = cbo->getTooltipText(); text.append(" "); if (cbo->getSelectedItem()) text.append(cbo->getSelectedItem()->getTooltipText()); mDescWindow->setText(text); } /// callback when mouse enters a described field (combo) bool handleMouseEnterCombo(const CEGUI::EventArgs& e) { const CEGUI::WindowEventArgs& winargs = static_cast(e); // get tooltip from parent combo (events raised on contained components) CEGUI::Combobox* cbo = static_cast(winargs.window->getParent()); updateTipForCombo(cbo); return true; } // Callback when a shadow type combo changed bool handleShadowTypeChanged(const CEGUI::EventArgs& e) { // Only trigger change on selected const CEGUI::WindowEventArgs& we = static_cast(e); CEGUI::RadioButton* radio = static_cast(we.window); if (radio->isSelected()) { ShadowTechnique newTech = mCurrentShadowTechnique; switch (radio->getID()) { case 1: // stencil newTech = static_cast( (newTech & ~SHADOWDETAILTYPE_TEXTURE) | SHADOWDETAILTYPE_STENCIL); resetMaterials(); break; case 2: // texture newTech = static_cast( (newTech & ~SHADOWDETAILTYPE_STENCIL) | SHADOWDETAILTYPE_TEXTURE); break; case 3: // additive newTech = static_cast( (newTech & ~SHADOWDETAILTYPE_MODULATIVE) | SHADOWDETAILTYPE_ADDITIVE); break; case 4: // modulative newTech = static_cast( (newTech & ~SHADOWDETAILTYPE_ADDITIVE) | SHADOWDETAILTYPE_MODULATIVE); break; } changeShadowTechnique(newTech); } return true; } bool handleProjectionChanged(const CEGUI::EventArgs& e) { const CEGUI::WindowEventArgs& winargs = static_cast(e); CEGUI::Combobox* cbo = static_cast(winargs.window); if (cbo->getSelectedItem()) { ShadowProjection proj = (ShadowProjection)cbo->getSelectedItem()->getID(); if (proj != mCurrentProjection) { switch(proj) { case UNIFORM: mCurrentShadowCameraSetup = ShadowCameraSetupPtr(new DefaultShadowCameraSetup()); break; case UNIFORM_FOCUSED: mCurrentShadowCameraSetup = ShadowCameraSetupPtr(new FocusedShadowCameraSetup()); break; case LISPSM: { mLiSPSMSetup = new LiSPSMShadowCameraSetup(); //mLiSPSMSetup->setUseAggressiveFocusRegion(false); mCurrentShadowCameraSetup = ShadowCameraSetupPtr(mLiSPSMSetup); } break; case PLANE_OPTIMAL: mCurrentShadowCameraSetup = ShadowCameraSetupPtr(new PlaneOptimalShadowCameraSetup(mPlane)); break; }; mCurrentProjection = proj; mSceneMgr->setShadowCameraSetup(mCurrentShadowCameraSetup); updateTipForCombo(cbo); if (!mCustomRockwallVparams.isNull() && !mCustomRockwallFparams.isNull()) { // set setDefaultDepthShadowParams(); } } } return true; } void updateDepthShadowParams() { mCustomRockwallFparams->setNamedConstant("fixedDepthBias", mFixedBias->getScrollPosition()); mCustomRockwallFparams->setNamedConstant("gradientScaleBias", mGradientBias->getScrollPosition()); mCustomRockwallFparams->setNamedConstant("gradientClamp", mGradientClamp->getScrollPosition()); mCustomAtheneFparams->setNamedConstant("fixedDepthBias", mFixedBias->getScrollPosition()); mCustomAtheneFparams->setNamedConstant("gradientScaleBias", mGradientBias->getScrollPosition()); mCustomAtheneFparams->setNamedConstant("gradientClamp", mGradientClamp->getScrollPosition()); mFixedBiasText->setText(StringConverter::toString( mFixedBias->getScrollPosition(), 4, 5, '0', std::ios::fixed)); mGradientBiasText->setText(StringConverter::toString( mGradientBias->getScrollPosition(), 4, 5, '0', std::ios::fixed)); mGradientClampText->setText(StringConverter::toString( mGradientClamp->getScrollPosition(), 4, 5, '0', std::ios::fixed)); } void setDefaultDepthShadowParams() { switch(mCurrentProjection) { case UNIFORM: case UNIFORM_FOCUSED: case PLANE_OPTIMAL: mFixedBias->setScrollPosition(0.0f); mGradientBias->setScrollPosition(0.0f); break; case LISPSM: mFixedBias->setScrollPosition(0.009f); mGradientBias->setScrollPosition(0.04f); break; }; updateDepthShadowParams(); } bool handleParamsChanged(const CEGUI::EventArgs& e) { if (!mCustomRockwallVparams.isNull() && !mCustomRockwallFparams.isNull()) { updateDepthShadowParams(); } return true; } void rebindDebugShadowOverlays() { MaterialPtr debugMat = MaterialManager::getSingleton().getByName("Ogre/DebugShadowMap0"); TexturePtr shadowTex = mSceneMgr->getShadowTexture(0); debugMat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(shadowTex->getName()); debugMat = MaterialManager::getSingleton().getByName("Ogre/DebugShadowMap1"); shadowTex = mSceneMgr->getShadowTexture(1); debugMat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(shadowTex->getName()); } void resetMaterials() { // Sort out base materials pPlaneEnt->setMaterialName(BASIC_ROCKWALL_MATERIAL); mAthene->setMaterialName(BASIC_ATHENE_MATERIAL); for (std::vector::iterator i = pColumns.begin(); i != pColumns.end(); ++i) { (*i)->setMaterialName(BASIC_ROCKWALL_MATERIAL); } mCustomRockwallVparams.setNull(); mCustomRockwallFparams.setNull(); mCustomAtheneVparams.setNull(); mCustomAtheneFparams.setNull(); } bool handleMaterialChanged(const CEGUI::EventArgs& e) { const CEGUI::WindowEventArgs& winargs = static_cast(e); CEGUI::Combobox* cbo = static_cast(winargs.window); if (cbo->getSelectedItem()) { ShadowMaterial mat = (ShadowMaterial)cbo->getSelectedItem()->getID(); MaterialPtr themat; if (mat != mCurrentMaterial) { switch(mat) { case MAT_STANDARD: mSceneMgr->setShadowTexturePixelFormat(PF_L8); mSceneMgr->setShadowTextureCasterMaterial(StringUtil::BLANK); mSceneMgr->setShadowTextureReceiverMaterial(StringUtil::BLANK); mSceneMgr->setShadowTextureSelfShadow(false); mDepthShadowTweak->setVisible(false); resetMaterials(); break; case MAT_DEPTH_FLOAT: if (mIsOpenGL) { // GL performs much better if you pick half-float format mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT16_R); } else { // D3D is the opposite - if you ask for PF_FLOAT16_R you // get an integer format instead! You can ask for PF_FLOAT16_GR // but the precision doesn't work well mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R); } mSceneMgr->setShadowTextureCasterMaterial(CUSTOM_CASTER_MATERIAL); mSceneMgr->setShadowTextureReceiverMaterial(CUSTOM_RECEIVER_MATERIAL); mSceneMgr->setShadowTextureSelfShadow(true); // Sort out base materials pPlaneEnt->setMaterialName(CUSTOM_ROCKWALL_MATERIAL); mAthene->setMaterialName(CUSTOM_ATHENE_MATERIAL); for (std::vector::iterator i = pColumns.begin(); i != pColumns.end(); ++i) { (*i)->setMaterialName(CUSTOM_ROCKWALL_MATERIAL); } themat = MaterialManager::getSingleton().getByName(CUSTOM_ROCKWALL_MATERIAL); mCustomRockwallVparams = themat->getTechnique(0)->getPass(1)->getShadowReceiverVertexProgramParameters(); mCustomRockwallFparams = themat->getTechnique(0)->getPass(1)->getShadowReceiverFragmentProgramParameters(); themat = MaterialManager::getSingleton().getByName(CUSTOM_ATHENE_MATERIAL); mCustomAtheneVparams = themat->getTechnique(0)->getPass(1)->getShadowReceiverVertexProgramParameters(); mCustomAtheneFparams = themat->getTechnique(0)->getPass(1)->getShadowReceiverFragmentProgramParameters(); mDepthShadowTweak->setVisible(true); // set the current params setDefaultDepthShadowParams(); break; case MAT_DEPTH_FLOAT_PCF: if (mIsOpenGL) { // GL performs much better if you pick half-float format mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT16_R); } else { // D3D is the opposite - if you ask for PF_FLOAT16_R you // get an integer format instead! You can ask for PF_FLOAT16_GR // but the precision doesn't work well mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R); } mSceneMgr->setShadowTextureCasterMaterial(CUSTOM_CASTER_MATERIAL); mSceneMgr->setShadowTextureReceiverMaterial(CUSTOM_RECEIVER_MATERIAL + "/PCF"); mSceneMgr->setShadowTextureSelfShadow(true); // Sort out base materials pPlaneEnt->setMaterialName(CUSTOM_ROCKWALL_MATERIAL + "/PCF"); mAthene->setMaterialName(CUSTOM_ATHENE_MATERIAL + "/PCF"); for (std::vector::iterator i = pColumns.begin(); i != pColumns.end(); ++i) { (*i)->setMaterialName(CUSTOM_ROCKWALL_MATERIAL + "/PCF"); } themat = MaterialManager::getSingleton().getByName(CUSTOM_ROCKWALL_MATERIAL + "/PCF"); mCustomRockwallVparams = themat->getTechnique(0)->getPass(1)->getShadowReceiverVertexProgramParameters(); mCustomRockwallFparams = themat->getTechnique(0)->getPass(1)->getShadowReceiverFragmentProgramParameters(); themat = MaterialManager::getSingleton().getByName(CUSTOM_ATHENE_MATERIAL + "/PCF"); mCustomAtheneVparams = themat->getTechnique(0)->getPass(1)->getShadowReceiverVertexProgramParameters(); mCustomAtheneFparams = themat->getTechnique(0)->getPass(1)->getShadowReceiverFragmentProgramParameters(); mDepthShadowTweak->setVisible(true); // set the current params setDefaultDepthShadowParams(); break; }; mCurrentMaterial = mat; updateTipForCombo(cbo); rebindDebugShadowOverlays(); } } return true; } // Create new frame listener void createFrameListener(void) { ShadowsListener* shadowListener = new ShadowsListener(mWindow, mCamera, mSceneMgr); mFrameListener = shadowListener; mFrameListener->showDebugOverlay(true); mRoot->addFrameListener(mFrameListener); // Hook up Root sheet (handles main input) CEGUI::Window* wnd = CEGUI::WindowManager::getSingleton().getWindow("Shadows"); wnd->subscribeEvent(CEGUI::Window::EventMouseMove, CEGUI::Event::Subscriber(&ShadowsListener::handleMouseMove, shadowListener)); wnd->subscribeEvent(CEGUI::Window::EventMouseButtonUp, CEGUI::Event::Subscriber(&ShadowsListener::handleMouseButtonUp, shadowListener)); wnd->subscribeEvent(CEGUI::Window::EventMouseButtonDown, CEGUI::Event::Subscriber(&ShadowsListener::handleMouseButtonDown, shadowListener)); wnd->subscribeEvent(CEGUI::Window::EventMouseWheel, CEGUI::Event::Subscriber(&ShadowsListener::handleMouseWheelEvent, shadowListener)); wnd->subscribeEvent(CEGUI::Window::EventKeyDown, CEGUI::Event::Subscriber(&ShadowsListener::handleKeyDownEvent, shadowListener )); wnd->subscribeEvent(CEGUI::Window::EventKeyUp, CEGUI::Event::Subscriber(&ShadowsListener::handleKeyUpEvent, shadowListener )); } public: void go(void) { if (!setup()) return; mRoot->startRendering(); } }; #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 #define WIN32_LEAN_AND_MEAN #include "windows.h" #endif #ifdef __cplusplus extern "C" { #endif #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT ) #else int main(int argc, char *argv[]) #endif { // Create application object ShadowsApplication app; try { app.go(); } catch( Ogre::Exception& e ) { #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL); #else std::cerr << "An exception has occured: " << e.getFullDescription().c_str() << std::endl; #endif } return 0; } #ifdef __cplusplus } #endif