text: /*
  -----------------------------------------------------------------------------
  This source file is part of OGRE
      (Object-oriented Graphics Rendering Engine)
  For the latest info, see http://www.ogre3d.org/
  
  Copyright (c) 2000-2014 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
  same license as the rest of the engine.
  -----------------------------------------------------------------------------
  */
  
  /**
      @file 
          Shadows.cpp
      @brief
          Shows a few ways to use Ogre's shadowing techniques
  */
  
  #include "SdkSample.h"
  #include "OgreBillboard.h"
  #include "OgreMovablePlane.h"
  #include "OgrePredefinedControllers.h"
  
  using namespace Ogre;
  using namespace OgreBites;
  
  
  
  // 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");
  
  /** This class 'wibbles' the light and billboard */
  class LightWibbler : public ControllerValue<Real>
  {
  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;
  
  
  class _OgreSampleClassExport Sample_Shadows : public SdkSample
  {
  protected:
      Entity* mAthene;
      AnimationState* mAnimState;
      Entity* pPlaneEnt;
      vector<Entity*>::type pColumns;
      Light* mLight;
      Light* mSunLight;
      SceneNode* mLightNode;
      AnimationState* mLightAnimationState;
      ColourValue mMinLightColour;
      ColourValue mMaxLightColour;
      Real mMinFlareSize;
      Real mMaxFlareSize;
      Controller<Real>* mController;
  
      enum ShadowProjection
      {
          UNIFORM,
          UNIFORM_FOCUSED,
          LISPSM,
          PLANE_OPTIMAL
      };
  
      enum ShadowMaterial
      {
          MAT_STANDARD,
          MAT_DEPTH_FLOAT,
          MAT_DEPTH_FLOAT_PCF
      };
      
      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:
  
      bool frameEnded(const FrameEvent& evt)
      {
          if (mAnimState)
                  mAnimState->addTime(evt.timeSinceLastFrame);
          return SdkSample::frameEnded(evt);
      }
  
      Sample_Shadows()
          : mAnimState(0)
          , mLightNode(0)
          , mLightAnimationState(0)
          , mMinLightColour(0.2, 0.1, 0.0)
          , mMaxLightColour(0.5, 0.3, 0.1)
          , mMinFlareSize(40)
          , mMaxFlareSize(80)
          , mController(0)
          , mPlane(0)
      {
          mInfo["Title"] = "Shadows";
          mInfo["Description"] = "A demonstration of ogre's various shadowing techniques.";
          mInfo["Thumbnail"] = "thumb_shadows.png";
          mInfo["Category"] = "Lighting";
  
      }
  
  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;
      //  }
      //}
      
      // Just override the mandatory create scene method
      void setupContent(void)
      {
          // Need to detect D3D or GL for best depth shadowmapping
          mIsOpenGL = Root::getSingleton().getRenderSystem()->getName().find("GL") != String::npos;
  
          // do this first so we generate edge lists
          if (mRoot->getRenderSystem()->getCapabilities()->hasCapability(RSC_HWSTENCIL))
          {
              mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE);
              mCurrentShadowTechnique = SHADOWTYPE_STENCIL_MODULATIVE;
          }
          else
          {
              mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);
              mCurrentShadowTechnique = SHADOWTYPE_TEXTURE_MODULATIVE;
          }
          // 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);
  
          Vector3 pos(1500,1750,1300);
          mSceneMgr->getRootSceneNode()->createChildSceneNode(pos)->attachObject(mSunLight);
          mSunLight->setSpotlightRange(Degree(30), Degree(50));
          mSunLight->setDirection(-pos.normalisedCopy());
          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));
          mController = 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)
                  {
                      StringStream 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));
          //mSceneMgr->setShowDebugShadows(true);
  
          setupGUI();
  #if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS
          setDragLook(true);
  #endif
      }
  
      virtual void setupView()
      {
          SdkSample::setupView();
  
          // incase infinite far distance is not supported
          mCamera->setFarClipDistance(100000);
  
          mCameraNode->setPosition(250, 20, 400);
          mCameraNode->lookAt(Vector3(0, 10, 0), Node::TS_WORLD);
      }
      
      virtual void cleanupContent()
      {
          ControllerManager::getSingleton().destroyController(mController);
  
          MeshManager::getSingleton().remove("Myplane", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
  
          pColumns.clear();
      }
  
      /// 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;
          };
  
      }
  
      SelectMenu* mTechniqueMenu;
      SelectMenu* mLightingMenu;
      SelectMenu* mProjectionMenu;
      SelectMenu* mMaterialMenu;
      
      Slider* mFixedBiasSlider;
      Slider* mSlopedBiasSlider;
      Slider* mClampSlider;
  
      void setupGUI()
      {
          mTechniqueMenu = mTrayMgr->createLongSelectMenu(
              TL_TOPLEFT, "TechniqueSelectMenu", "Technique", 300, 200, 5);
          mTechniqueMenu->addItem("Stencil");
          mTechniqueMenu->addItem("Texture");
          if(mCurrentShadowTechnique & SHADOWDETAILTYPE_STENCIL)
              mTechniqueMenu->selectItem("Stencil", false);
          else
              mTechniqueMenu->selectItem("Texture", false);
  
          mLightingMenu = mTrayMgr->createLongSelectMenu(
              TL_TOPLEFT, "LightingSelectMenu", "Lighting", 300, 200, 5);
          mLightingMenu->addItem("Additive");
          mLightingMenu->addItem("Modulative");
          if(mCurrentShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE)
              mLightingMenu->selectItem("Additive", false);
          else
              mLightingMenu->selectItem("Modulative", false);
          
          //These values are synchronized with ShadowProjection enum
          mProjectionMenu = mTrayMgr->createLongSelectMenu(
              TL_TOPLEFT, "ProjectionSelectMenu", "Projection", 300, 200, 5);
          mProjectionMenu->addItem("Uniform");
          mProjectionMenu->addItem("Uniform Focused");
          mProjectionMenu->addItem("LiSPSM");
          mProjectionMenu->addItem("Plane Optimal");
          
          mMaterialMenu = mTrayMgr->createLongSelectMenu(
              TL_TOPLEFT, "MaterialSelectMenu", "Material", 300, 200, 5);
          mMaterialMenu->addItem("Standard");
          mMaterialMenu->addItem("Depth Shadowmap");
          mMaterialMenu->addItem("Depth Shadowmap (PCF)");
          
          mFixedBiasSlider = mTrayMgr->createThickSlider(TL_NONE, "FixedBiasSlider", "Fixed Bias", 256, 80, 0, 0.02, 100);
          mFixedBiasSlider->setValue(0.0009, false);
          mFixedBiasSlider->hide();
  
          mSlopedBiasSlider = mTrayMgr->createThickSlider(TL_NONE, "SlopedBiasSlider", "Sloped Bias", 256, 80, 0, 0.2, 100);
          mSlopedBiasSlider->setValue(0.0008, false);
          mSlopedBiasSlider->hide();
  
          mClampSlider = mTrayMgr->createThickSlider(TL_NONE, "SlopeClampSlider", "Slope Clamp", 256, 80, 0, 2, 100);
          mClampSlider->setValue(0.2, false);
          mClampSlider->hide();
  
          updateGUI(mCurrentShadowTechnique);
          mTrayMgr->showCursor();
      }
  
      void updateGUI(ShadowTechnique newTech)
      {
          bool isTextureBased = (newTech & SHADOWDETAILTYPE_TEXTURE) != 0;
  
          if (isTextureBased) 
          {
              mProjectionMenu->show();
              mTrayMgr->moveWidgetToTray(mProjectionMenu, TL_TOPLEFT);
              mMaterialMenu->show();
              mTrayMgr->moveWidgetToTray(mMaterialMenu, TL_TOPLEFT);
          }
          else 
          {
              mProjectionMenu->hide();
              mTrayMgr->removeWidgetFromTray(mProjectionMenu);
              mMaterialMenu->hide();
              mTrayMgr->removeWidgetFromTray(mMaterialMenu);
          }
      }
  
      void itemSelected(SelectMenu* menu)
      {
          if (menu == mTechniqueMenu) handleShadowTypeChanged();
          else if (menu == mLightingMenu) handleShadowTypeChanged();
          else if (menu == mProjectionMenu) handleProjectionChanged();
          else if (menu == mMaterialMenu) handleMaterialChanged();
      }
  
  
      void handleShadowTypeChanged()
      {
          bool isStencil = mTechniqueMenu->getSelectionIndex() == 0;
          bool isAdditive = mLightingMenu->getSelectionIndex() == 0;
          ShadowTechnique newTech = mCurrentShadowTechnique;
  
          if (isStencil)
          {
              newTech = static_cast<ShadowTechnique>(
                  (newTech & ~SHADOWDETAILTYPE_TEXTURE) | SHADOWDETAILTYPE_STENCIL);
              resetMaterials();
          }
          else
          {
              newTech = static_cast<ShadowTechnique>(
                  (newTech & ~SHADOWDETAILTYPE_STENCIL) | SHADOWDETAILTYPE_TEXTURE);
          }
          
          if (isAdditive)
          {
              newTech = static_cast<ShadowTechnique>(
                  (newTech & ~SHADOWDETAILTYPE_MODULATIVE) | SHADOWDETAILTYPE_ADDITIVE);
          }
          else
          {
              newTech = static_cast<ShadowTechnique>(
                  (newTech & ~SHADOWDETAILTYPE_ADDITIVE) | SHADOWDETAILTYPE_MODULATIVE);
          }
  
          changeShadowTechnique(newTech);
      }
  
      void handleProjectionChanged()
      {
          ShadowProjection proj = (ShadowProjection)mProjectionMenu->getSelectionIndex();
          
          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 && mCustomRockwallFparams)
              {
                  // set
                  setDefaultDepthShadowParams();
              }
  
          }
      }
  
      void updateDepthShadowParams()
      {
          mCustomRockwallFparams->setNamedConstant("fixedDepthBias", 
              mFixedBiasSlider->getValue());
          mCustomRockwallFparams->setNamedConstant("gradientScaleBias",
              mSlopedBiasSlider->getValue());
          mCustomRockwallFparams->setNamedConstant("gradientClamp",
              mClampSlider->getValue());
  
          mCustomAtheneFparams->setNamedConstant("fixedDepthBias", 
              mFixedBiasSlider->getValue());
          mCustomAtheneFparams->setNamedConstant("gradientScaleBias",
              mSlopedBiasSlider->getValue());
          mCustomAtheneFparams->setNamedConstant("gradientClamp",
              mClampSlider->getValue());
      }
  
      void setDefaultDepthShadowParams()
      {
          switch(mCurrentProjection)
          {
          case UNIFORM:
          case UNIFORM_FOCUSED:
          case PLANE_OPTIMAL:
              mFixedBiasSlider->setValue(0.0f, false);
              mSlopedBiasSlider->setValue(0.0f, false);
              break;
          case LISPSM:
              mFixedBiasSlider->setValue(0.009f, false);
              mSlopedBiasSlider->setValue(0.04f, false);
              break;
          };
  
          updateDepthShadowParams();
  
      }
  
      void sliderMoved(Slider* slider)
      {
          if (mCustomRockwallVparams && mCustomRockwallFparams)
          {
              updateDepthShadowParams();
          }
      }
  
      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 (vector<Entity*>::type::iterator i = pColumns.begin();
              i != pColumns.end(); ++i)
          {
              (*i)->setMaterialName(BASIC_ROCKWALL_MATERIAL);
          }
  
          mCustomRockwallVparams.reset();
          mCustomRockwallFparams.reset();
          mCustomAtheneVparams.reset();
          mCustomAtheneFparams.reset();
  
      }
      
      void handleMaterialChanged()
      {
          bool showSliders = false;   
          ShadowMaterial mat = (ShadowMaterial)mMaterialMenu->getSelectionIndex();
          MaterialPtr themat;
          if (mat != mCurrentMaterial)
          {
              switch(mat)
              {
              case MAT_STANDARD:
                  mSceneMgr->setShadowTexturePixelFormat(PF_X8R8G8B8);
                  mSceneMgr->setShadowTextureCasterMaterial(MaterialPtr());
                  mSceneMgr->setShadowTextureReceiverMaterial(MaterialPtr());
                  mSceneMgr->setShadowTextureSelfShadow(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);
                  }
                  themat = MaterialManager::getSingleton().getByName(CUSTOM_CASTER_MATERIAL);
                  mSceneMgr->setShadowTextureCasterMaterial(themat);
                  themat = MaterialManager::getSingleton().getByName(CUSTOM_ATHENE_MATERIAL);
                  mSceneMgr->setShadowTextureReceiverMaterial(themat);
                  mSceneMgr->setShadowTextureSelfShadow(true);    
                  // Sort out base materials
                  pPlaneEnt->setMaterialName(CUSTOM_ROCKWALL_MATERIAL);
                  mAthene->setMaterialName(CUSTOM_ATHENE_MATERIAL);
                  for (vector<Entity*>::type::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();
                  showSliders = 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);
                  }
                  themat = MaterialManager::getSingleton().getByName(CUSTOM_CASTER_MATERIAL);
                  mSceneMgr->setShadowTextureCasterMaterial(themat);
                  themat = MaterialManager::getSingleton().getByName(CUSTOM_RECEIVER_MATERIAL + "/PCF");
                  mSceneMgr->setShadowTextureReceiverMaterial(themat);
                  mSceneMgr->setShadowTextureSelfShadow(true);    
                  // Sort out base materials
                  pPlaneEnt->setMaterialName(CUSTOM_ROCKWALL_MATERIAL + "/PCF");
                  mAthene->setMaterialName(CUSTOM_ATHENE_MATERIAL + "/PCF");
                  for (vector<Entity*>::type::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();
                  showSliders = true;
  
                  // set the current params
                  setDefaultDepthShadowParams();
                  break;
              };
              mCurrentMaterial = mat;
  
              if (showSliders)
              {
                  mFixedBiasSlider->show();
                  mTrayMgr->moveWidgetToTray(mFixedBiasSlider, TL_TOPRIGHT);
                  mSlopedBiasSlider->show();
                  mTrayMgr->moveWidgetToTray(mSlopedBiasSlider, TL_TOPRIGHT);
                  mClampSlider->show();   
                  mTrayMgr->moveWidgetToTray(mClampSlider, TL_TOPRIGHT);          
              }
              else
              {
                  mFixedBiasSlider->hide();
                  mTrayMgr->removeWidgetFromTray(mFixedBiasSlider);
                  mSlopedBiasSlider->hide();
                  mTrayMgr->removeWidgetFromTray(mSlopedBiasSlider);
                  mClampSlider->hide();       
                  mTrayMgr->removeWidgetFromTray(mClampSlider);       
              }
              //updateTipForCombo(cbo);
              //rebindDebugShadowOverlays();
          }
      }
  };
  