text: #ifndef __Dot3Bump_H__
  #define __Dot3Bump_H__
  
  #include "SdkSample.h"
  
  using namespace Ogre;
  using namespace OgreBites;
  
  class _OgreSampleClassExport Sample_Dot3Bump : public SdkSample
  {
  public:
  
  	Sample_Dot3Bump()
  		: mMoveLights (true)
  	{
  		mInfo["Title"] = "Bump Mapping";
  		mInfo["Description"] = "Shows how to use the dot product blending operation and normalization cube map "
  			"to achieve a bump mapping effect. Tangent space computations made through the guide of the tutorial "
  			"on bump mapping from http://users.ox.ac.uk/~univ1234 by paul.baker@univ.ox.ac.uk.";
  		mInfo["Thumbnail"] = "thumb_bump.png";
  		mInfo["Category"] = "Lighting";
  		mInfo["Help"] = "Left click and drag anywhere in the scene to look around. Let go again to show "
  			"cursor and access widgets. Use WASD keys to move.";
  	}
  
  	StringVector getRequiredPlugins()
  	{
  		StringVector names;
          if (!GpuProgramManager::getSingleton().isSyntaxSupported("glsles") && !GpuProgramManager::getSingleton().isSyntaxSupported("glsl"))
              names.push_back("Cg Program Manager");
  		return names;
  	}
  
  	void testCapabilities(const RenderSystemCapabilities* caps)
  	{
  		if (!caps->hasCapability(RSC_VERTEX_PROGRAM) || !(caps->hasCapability(RSC_FRAGMENT_PROGRAM)))
          {
  			OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your graphics card does not support vertex and fragment programs, "
  				"so you cannot run this sample. Sorry!", "Dot3BumpSample::testCapabilities");
          }
  
  		if (!GpuProgramManager::getSingleton().isSyntaxSupported("arbfp1") &&
  			!GpuProgramManager::getSingleton().isSyntaxSupported("ps_2_0") &&
  			!GpuProgramManager::getSingleton().isSyntaxSupported("ps_4_0") &&
              !GpuProgramManager::getSingleton().isSyntaxSupported("glsl")   &&
  			!GpuProgramManager::getSingleton().isSyntaxSupported("glsles"))
  		{
  			OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your card does not support the shader model needed for this sample, "
  				"so you cannot run this sample. Sorry!", "Dot3BumpSample::testCapabilities");
  		}
  	}
  
  	bool frameRenderingQueued(const FrameEvent& evt)
  	{
  		if (mMoveLights)
  		{
  			// rotate the light pivots
  			mLightPivot1->roll(Degree(evt.timeSinceLastFrame * 30));
  			mLightPivot2->roll(Degree(evt.timeSinceLastFrame * 10));
  		}
  
  		return SdkSample::frameRenderingQueued(evt);  // don't forget the parent class updates!
  	}
  
  	void itemSelected(SelectMenu* menu)
  	{
  		if (menu == mMeshMenu)
  		{
  			// change to the selected entity
  			mObjectNode->detachAllObjects();
  			mObjectNode->attachObject(mSceneMgr->getEntity(mMeshMenu->getSelectedItem()));
  
  			// remember which material is currently selected
  			int index = std::max<int>(0, mMaterialMenu->getSelectionIndex());
  
  			// update the material menu's options
  			mMaterialMenu->setItems(mPossibilities[mMeshMenu->getSelectedItem()]);
  
  			mMaterialMenu->selectItem(index);   // select the material with the saved index
  		}
  		else
  		{
  			// set the selected material for the active mesh
  			((Entity*)mObjectNode->getAttachedObject(0))->setMaterialName(menu->getSelectedItem());
  		}
  	}
  
  	void checkBoxToggled(CheckBox* box)
  	{
  		if (StringUtil::startsWith(box->getName(), "Light", false))
  		{
  			// get the light pivot that corresponds to this checkbox
  			SceneNode* pivot = box->getName() == "Light1" ? mLightPivot1 : mLightPivot2;
  			SceneNode::ObjectIterator it = pivot->getAttachedObjectIterator();
  
  			while (it.hasMoreElements())  // toggle visibility of light and billboard set
  			{
  				MovableObject* o = it.getNext();
  				o->setVisible(box->isChecked());
  			}
  
  		}
  		else if (box->getName() == "MoveLights")
  		{
  			mMoveLights = !mMoveLights;
  		}
  	}
  
  protected:
  
  	void setupContent()
  	{
  		// create our main node to attach our entities to
  		mObjectNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
  
  		setupModels();
  		setupLights();
  		setupControls();
  
  		mCamera->setPosition(0, 0, 500);
  
  #if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS
  		setDragLook(true);
  #endif
  	}
  
  
  
  	void loadResources()
  	{		
  #ifdef INCLUDE_RTSHADER_SYSTEM
  		Ogre::StringVector groupVector = Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
  		Ogre::StringVector::iterator itGroup = groupVector.begin();
  		Ogre::StringVector::iterator itGroupEnd = groupVector.end();
  		Ogre::String shaderCoreLibsPath;
  
  
  		for (; itGroup != itGroupEnd; ++itGroup)
  		{
  			Ogre::ResourceGroupManager::LocationList resLocationsList = Ogre::ResourceGroupManager::getSingleton().getResourceLocationList(*itGroup);
  			Ogre::ResourceGroupManager::LocationList::iterator it = resLocationsList.begin();
  			Ogre::ResourceGroupManager::LocationList::iterator itEnd = resLocationsList.end();
  			bool coreLibsFound = false;
  
  			// Find the location of the core shader libs
  			for (; it != itEnd; ++it)
  			{
  				if ((*it)->archive->getName().find("RTShaderLib") != Ogre::String::npos)
  				{
  					shaderCoreLibsPath = (*it)->archive->getName() + "/";	
  					coreLibsFound = true;
  					break;
  				}
  			}
  
  			// Core libs path found in the current group.
  			if (coreLibsFound) 
  				break; 
  		}
  			
  #endif
  	}
  
  	void unloadResources()
  	{
  
  	}
  
  	void setupModels()
  	{
  		StringVector matNames;
  
  		matNames.push_back("Examples/BumpMapping/MultiLight");
  		matNames.push_back("Examples/BumpMapping/MultiLightSpecular");
  		matNames.push_back("Examples/OffsetMapping/Specular");
  		matNames.push_back("Examples/ShowUV");
  		matNames.push_back("Examples/ShowNormals");
  		matNames.push_back("Examples/ShowTangents");
  
  #ifdef INCLUDE_RTSHADER_SYSTEM
  		matNames.push_back("RTSS/NormalMapping_SinglePass");
  		matNames.push_back("RTSS/NormalMapping_MultiPass");
  #endif
  
  	
  		mPossibilities["ogrehead.mesh"] = matNames;
  		mPossibilities["knot.mesh"] = matNames;
  
  		matNames.clear();
  		matNames.push_back("Examples/Athene/NormalMapped");
  		matNames.push_back("Examples/Athene/NormalMappedSpecular");
  		matNames.push_back("Examples/Athene/NormalMappedSpecular");
  		matNames.push_back("Examples/ShowUV");
  		matNames.push_back("Examples/ShowNormals");
  		matNames.push_back("Examples/ShowTangents");
  #ifdef INCLUDE_RTSHADER_SYSTEM
  		matNames.push_back("RTSS/Athene/NormalMapping_SinglePass");
  		matNames.push_back("RTSS/Athene/NormalMapping_MultiPass");
  #endif
  
  		mPossibilities["athene.mesh"] = matNames;
  
  		for (std::map<String, StringVector>::iterator it = mPossibilities.begin(); it != mPossibilities.end(); it++)
  		{
  			// load each mesh with non-default hardware buffer usage options
  			MeshPtr mesh = MeshManager::getSingleton().load(it->first, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
  				HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
  
              // build tangent vectors for our mesh
              unsigned short src, dest;
              if (!mesh->suggestTangentVectorBuildParams(VES_TANGENT, src, dest))
              {
                  mesh->buildTangentVectors(VES_TANGENT, src, dest);
  				// this version cleans mirrored and rotated UVs but requires quality models
  				// mesh->buildTangentVectors(VES_TANGENT, src, dest, true, true);
              }
  
  			// create an entity from the mesh and set the first available material
  			Entity* ent = mSceneMgr->createEntity(mesh->getName(), mesh->getName());
  			ent->setMaterialName(it->second.front());
  		}
  	}
  
  	void setupLights()
  	{
  		mSceneMgr->setAmbientLight(ColourValue::Black);   // disable ambient lighting
  
  		// create pivot nodes
  		mLightPivot1 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
  		mLightPivot2 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
  
  		Light* l;
  		BillboardSet* bbs;
  
  		// create white light
  		l = mSceneMgr->createLight();
  		l->setPosition(200, 0, 0);
  		l->setDiffuseColour(1, 1, 1);
  		l->setSpecularColour(1, 1, 1);
  		// create white flare
  		bbs = mSceneMgr->createBillboardSet();
  		bbs->setMaterialName("Examples/Flare");
  		bbs->createBillboard(200, 0, 0)->setColour(ColourValue::White);
  
  		mLightPivot1->attachObject(l);
  		mLightPivot1->attachObject(bbs);
  
  		// create red light
  		l = mSceneMgr->createLight();
  		l->setPosition(40, 200, 50);
  		l->setDiffuseColour(1, 0, 0);
  		l->setSpecularColour(1, 0.8, 0.8);
  		// create white flare
  		bbs = mSceneMgr->createBillboardSet();
  		bbs->setMaterialName("Examples/Flare");
  		bbs->createBillboard(50, 200, 50)->setColour(ColourValue::Red);
  
  		mLightPivot2->attachObject(l);
  		mLightPivot2->attachObject(bbs);
  	}
  
  	void setupControls()
  	{
  		mTrayMgr->showCursor();
  
  		// make room for the controls
  		mTrayMgr->showLogo(TL_TOPRIGHT);
  		mTrayMgr->showFrameStats(TL_TOPRIGHT);
  		mTrayMgr->toggleAdvancedFrameStats();
  
  		// create a menu to choose the model displayed
  		mMeshMenu = mTrayMgr->createLongSelectMenu(TL_BOTTOM, "Mesh", "Mesh", 370, 290, 10);
  		for (std::map<String, StringVector>::iterator it = mPossibilities.begin(); it != mPossibilities.end(); it++)
  			mMeshMenu->addItem(it->first);
  
  		// create a menu to choose the material used by the model
  		mMaterialMenu = mTrayMgr->createLongSelectMenu(TL_BOTTOM, "Material", "Material", 370, 290, 10);
  
  		// create checkboxes to toggle lights
  		mTrayMgr->createCheckBox(TL_TOPLEFT, "Light1", "Light A")->setChecked(true, false);
  		mTrayMgr->createCheckBox(TL_TOPLEFT, "Light2", "Light B")->setChecked(true, false);
  		mTrayMgr->createCheckBox(TL_TOPLEFT, "MoveLights", "Move Lights")->setChecked(true, false);
  
  		// a friendly reminder
  		StringVector names;
  		names.push_back("Help");
  		mTrayMgr->createParamsPanel(TL_TOPLEFT, "Help", 100, names)->setParamValue(0, "H/F1");
  
  		mMeshMenu->selectItem(0);  // select first mesh
  	}
  
  	void cleanupContent()
  	{
  		// clean up properly to avoid interfering with subsequent samples
  		for (std::map<String, StringVector>::iterator it = mPossibilities.begin(); it != mPossibilities.end(); it++)
  			MeshManager::getSingleton().unload(it->first);
  		mPossibilities.clear();
  	}
  
  	std::map<String, StringVector> mPossibilities;
  	SceneNode* mObjectNode;
  	SceneNode* mLightPivot1;
  	SceneNode* mLightPivot2;
  	bool mMoveLights;
  	SelectMenu* mMeshMenu;
  	SelectMenu* mMaterialMenu;
  };
  
  #endif
  