/*
-----------------------------------------------------------------------------
Filename:    TutorialApplication.cpp
-----------------------------------------------------------------------------

This source file is part of the
   ___                 __    __ _ _    _ 
  /___\__ _ _ __ ___  / / /\ \ (_) | _(_)
 //  // _` | '__/ _ \ \ \/  \/ / | |/ / |
/ \_// (_| | | |  __/  \  /\  /| |   <| |
\___/ \__, |_|  \___|   \/  \/ |_|_|\_\_|
      |___/                              
      Tutorial Framework
      http://www.ogre3d.org/tikiwiki/
-----------------------------------------------------------------------------
*/
#include "TutorialApplication.h"

using namespace Ogre;

//-------------------------------------------------------------------------------------
TutorialApplication::TutorialApplication(void)
{
	// Set constants
	m_fRotateSpeed = 0.002;     // The rotate constant
	m_fRotateDecel = 0.001;     // The rotate deceleration constant
	m_fZoomSpeed = 2;			// The zoom constant
	m_fZoomDecel = 2;			// The zoom deceleration
	m_fMaxZoom = 10;
	m_fMinZoom = 100;
	
	// Connect to the glove depending on the platform
	m_pGlove = NULL;
	ConnectGlove();

}

//-------------------------------------------------------------------------------------
void TutorialApplication::ConnectGlove(void)
{
	#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
	int iPort = 0;
	m_pGlove = fdOpen("USB0");
	if (!m_pGlove)
		m_pGlove = fdOpen("COM0");
	//while (!m_pGlove && iPort < 10)
	//{
	//	std::stringstream out;
	//	out<<"COM"<<iPort;
	//	char tempChr[50];
	//	strncpy(tempChr, out.str().c_str(),strlen(out.str().c_str())+1);

	//	m_pGlove = fdOpen(tempChr);				
	//	iPort++;
	//}
	#elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE
		m_pGlove = fdOpen(""); // connect to first glove available
	#else // Linux
		m_pGlove = fdOpen("/dev/usb/hiddev0");
		if (!m_pGlove)
			m_pGlove = fdOpen("/dev/dev/ttyS0");
	#endif

	// try to automatically load the calibration file
	if (m_pGlove)
	{
		char cSerial[50];
		fdGetSerialNumber(m_pGlove, cSerial);
		std::string sFileName(cSerial);
		sFileName += ".fd";
		if (fdLoadCalibration(m_pGlove, sFileName.c_str()))
			int a = 3;
	}
}

//-------------------------------------------------------------------------------------
TutorialApplication::~TutorialApplication(void)
{
	fdClose(m_pGlove);
}

//-------------------------------------------------------------------------------------
void TutorialApplication::createScene(void)
{
    //ogre
	Ogre::Entity *handEnt;//*handEntL, *handEntR;
	if (m_pGlove && fdGetGloveHand(m_pGlove) == FD_HAND_RIGHT)
		handEnt = m_pSceneMgr->createEntity("Hand", "5DTRHand.mesh");
	else
		handEnt = m_pSceneMgr->createEntity("Hand", "5DTLHand.mesh");
		
	// generate tangent vectors for normal mapping
	//unsigned short src, dest;
	//if (!handEnt->getMesh()->suggestTangentVectorBuildParams(VES_TANGENT, src,dest))
	//	handEnt->getMesh()->buildTangentVectors(VES_TANGENT, src,dest);
	
	Ogre::SceneNode* HandNode = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("HandNode",Ogre::Vector3(0,20,0));
	HandNode->setScale(Ogre::Vector3(10,10,10));
	HandNode->attachObject(handEnt);
	
	setupCamera();

    // Set ambient light
    m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5 ));
	//mSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
 
    // Create a light
    Ogre::Light* light = m_pSceneMgr->createLight("MainLight");
	light->setDiffuseColour(Ogre::ColourValue::White);
	light->setSpecularColour(Ogre::ColourValue::White);
    light->setPosition(20,80,50);
	//light->setPosition(40,160,100);

}

//-------------------------------------------------------------------------------------
void TutorialApplication::setupCamera()
{
	// create a pivot at roughly the character's shoulder
	m_pCameraPivot = m_pCamera->getSceneManager()->getRootSceneNode()->createChildSceneNode();
	m_pCameraPivot->setPosition(m_pSceneMgr->getSceneNode("HandNode")->getPosition()+Ogre::Vector3(12,0,0));

	// this is where the camera should be soon, and it spins around the pivot
	m_pCameraGoal = m_pCameraPivot->createChildSceneNode(Vector3(0, 0, 30));

	// this is where the camera actually is
	m_pCameraNode = m_pCamera->getSceneManager()->getRootSceneNode()->createChildSceneNode();
	m_pCameraNode->setPosition(m_pCameraPivot->getPosition() + m_pCameraGoal->getPosition());

	m_pCameraPivot->setFixedYawAxis(true);
	m_pCameraGoal->setFixedYawAxis(true);
	m_pCameraNode->setFixedYawAxis(true);

	// our model is quite small, so reduce the clipping planes
	m_pCamera->setNearClipDistance(0.1);
	m_pCamera->setFarClipDistance(100);
	m_pCameraNode->attachObject(m_pCamera);

	m_fPivotPitch = 0;

	if (m_pGlove && fdGetGloveHand(m_pGlove) == FD_HAND_RIGHT)
		updateCameraGoal(135, -45, 10);
	else
		updateCameraGoal(45, -45, 10);
}

//-------------------------------------------------------------------------------------
// Execute while waiting for the GPU to flip the buffers
bool TutorialApplication::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	if (!BaseApplication::frameRenderingQueued(evt))
		return false;

	UpdateCam(evt.timeSinceLastFrame);

	//if (Light* light = mSceneMgr->getLight("MainLight"))
	//{
	//	light->setPosition(m_Camera->getDerivedPosition() + m_Camera->getDerivedUp() * 20.0);
	//	light->setDirection(m_Camera->getDerivedDirection());
	//}

	static float time = 0;
	static float activitytime = 0;
	
	time += evt.timeSinceLastFrame;
	activitytime += evt.timeSinceLastFrame;

	// if no activity for 1 second: reset glove
	if (m_pGlove && activitytime>1 && !fdNewData(m_pGlove))
	{
		fdClose(m_pGlove);
		m_pGlove = 0;
		activitytime = -10; // allow 10 seconds to load glove
	}
	else if (m_pGlove && fdNewData(m_pGlove))
		activitytime = 0;


	if (m_pGlove)
	{
		if (fdGetGloveType(m_pGlove)==FD_GLOVE14U || 
			fdGetGloveType(m_pGlove) == FD_GLOVE14UW ||
			fdGetGloveType(m_pGlove) == FD_GLOVE14U_USB)
				Update14SensorGlove();
		else
			Update5SensorGlove();
	}
	else if (time>1) // check for connection each second
	{
		time = 0;
		ConnectGlove();

		if (m_pGlove)
		{
			m_pSceneMgr->destroyEntity("Hand");
			if (fdGetGloveHand(m_pGlove) == FD_HAND_RIGHT)
				m_pSceneMgr->createEntity("Hand", "5DTRHand.mesh");
			else
				m_pSceneMgr->createEntity("Hand", "5DTLHand.mesh");

			m_pSceneMgr->getSceneNode("HandNode")->attachObject(m_pSceneMgr->getEntity("Hand"));
		}
	}
	return true;
}

//-------------------------------------------------------------------------------------
void TutorialApplication::buttonHit(OgreBites::Button* b)
{

	bool bIs14SensorGlove = false;
	if (fdGetGloveType(m_pGlove)==FD_GLOVE14U || 
		fdGetGloveType(m_pGlove) == FD_GLOVE14UW ||
		fdGetGloveType(m_pGlove) == FD_GLOVE14U_USB)
	{
		bIs14SensorGlove = true;
	}

	if (b->getName() == "btnReset")
	{
		fdResetCalibration(m_pGlove);
	}
	else if (b->getName() == "btnFingersOpen")
	{
		unsigned short pLower[20];
		unsigned short pUpper[20];
		fdGetCalibrationAll(m_pGlove, pUpper, pLower);

		fdSetCalibration(m_pGlove, FD_THUMBINDEX, pUpper[FD_THUMBINDEX], fdGetSensorRaw(m_pGlove,FD_THUMBINDEX));
		fdSetCalibration(m_pGlove, FD_INDEXMIDDLE, pUpper[FD_INDEXMIDDLE], fdGetSensorRaw(m_pGlove,FD_INDEXMIDDLE));
		fdSetCalibration(m_pGlove, FD_MIDDLERING, pUpper[FD_MIDDLERING], fdGetSensorRaw(m_pGlove,FD_MIDDLERING));
		fdSetCalibration(m_pGlove, FD_RINGLITTLE, pUpper[FD_RINGLITTLE], fdGetSensorRaw(m_pGlove,FD_RINGLITTLE));

	}
	else if (b->getName() == "btnFingersClosed")
	{
		unsigned short pLower[20];
		unsigned short pUpper[20];
		fdGetCalibrationAll(m_pGlove, pUpper, pLower);

		fdSetCalibration(m_pGlove, FD_THUMBINDEX, fdGetSensorRaw(m_pGlove,FD_THUMBINDEX), pLower[FD_THUMBINDEX]);
		fdSetCalibration(m_pGlove, FD_INDEXMIDDLE, fdGetSensorRaw(m_pGlove,FD_INDEXMIDDLE), pLower[FD_INDEXMIDDLE]);
		fdSetCalibration(m_pGlove, FD_MIDDLERING, fdGetSensorRaw(m_pGlove,FD_MIDDLERING), pLower[FD_MIDDLERING]);
		fdSetCalibration(m_pGlove, FD_RINGLITTLE, fdGetSensorRaw(m_pGlove,FD_RINGLITTLE), pLower[FD_RINGLITTLE]);
	}
	else if (b->getName() == "btnHandOpen")
	{
		unsigned short pCurrentData[20];
		unsigned short pLower[20];
		unsigned short pUpper[20];
		fdGetSensorRawAll(m_pGlove, pCurrentData);
		fdGetCalibrationAll(m_pGlove, pUpper, pLower);
		
		if (!bIs14SensorGlove)
			fdSetCalibrationAll(m_pGlove, pUpper, pCurrentData);
		else
		{
			for (int i = 0; i<20; i++)
				if (i!=FD_THUMBINDEX && i != FD_INDEXMIDDLE && i != FD_MIDDLERING && i != FD_RINGLITTLE)
					fdSetCalibration(m_pGlove, i, pUpper[i], pCurrentData[i]);
		}
	}
	else if (b->getName() == "btnFist")
	{
		unsigned short pCurrentData[20];
		unsigned short pLower[20];
		unsigned short pUpper[20];
		fdGetSensorRawAll(m_pGlove, pCurrentData);
		fdGetCalibrationAll(m_pGlove, pUpper, pLower);
		
		if (!bIs14SensorGlove)
			fdSetCalibrationAll(m_pGlove, pCurrentData, pLower);
		else
		{
			for (int i = 0; i<20; i++)
				if (i!=FD_THUMBINDEX && i != FD_INDEXMIDDLE && i != FD_MIDDLERING && i != FD_RINGLITTLE)
					fdSetCalibration(m_pGlove, i, pCurrentData[i], pLower[i]);
		}

	}
	else if (b->getName() == "btnSaveCalibration")
	{
		m_pTrayCalibration->hideAll();
		char cSerial[50];
		fdGetSerialNumber(m_pGlove, cSerial);
		std::string sFileName(cSerial);
		sFileName += ".fd";
		fdSaveCalibration(m_pGlove,sFileName.c_str());
	}
	else if (b->getName() == "btnCancel")
	{
		m_pTrayCalibration->hideAll();
	}
	BaseApplication::buttonHit(b);

}

//-------------------------------------------------------------------------------------
// OIS::KeyListener
bool TutorialApplication::keyPressed( const OIS::KeyEvent& evt )
{
	static std::string curMaterial = "basic1";

	BaseApplication::keyPressed(evt);
	if (m_pTrayMgr->isDialogVisible()) return true;   // don't process any more keys if dialog is up
   
	switch (evt.key)
    {
		//case OIS::KC_R:
		//	if (pGlove)
		//	{
		//		fdClose(pGlove);
		//		pGlove = 0;
		//	}
		//	break;
		case OIS::KC_F1:
			m_pTrayMgr->showOkDialog("5DT 3D Glove Demo", "This program is meant for demo and education purposes regarding the 5DT Data Glove series. The source is freely available on www.5dt.com\n\nKeys:\n\nMouse: Rotate\nScroll: Zoom\nESC: Exit\nC: Calibrate\nF: Toggle Framerate Display\nT: Toggle Texture Filter Mode\nE: Toggle Polygon Render Mode");
			break;
		case OIS::KC_C:
			{
				if (m_pTrayCalibration->isCursorVisible())
				{
					m_pTrayCalibration->hideAll();
				}
				else
				{				
					m_pTrayCalibration->destroyAllWidgets();
					
					m_pTrayCalibration->createLabel(OgreBites::TL_CENTER, "lblCalibration", "Glove Calibration",200);
					m_pTrayCalibration->createSeparator(OgreBites::TL_CENTER, "sepCalibration");
				
					// add calibration buttons according to the glove connected
					if (m_pGlove)
					{
						if (fdGetGloveType(m_pGlove)==FD_GLOVE14U || 
							fdGetGloveType(m_pGlove) == FD_GLOVE14UW ||
							fdGetGloveType(m_pGlove) == FD_GLOVE14U_USB)
						{	
							m_pTrayCalibration->createButton(OgreBites::TL_CENTER, "btnReset", "Reset");
							m_pTrayCalibration->createButton(OgreBites::TL_CENTER, "btnHandOpen", "Hand Open");
							m_pTrayCalibration->createButton(OgreBites::TL_CENTER, "btnFist", "Fist");
							m_pTrayCalibration->createButton(OgreBites::TL_CENTER, "btnFingersOpen", "Spread Fingers");
							m_pTrayCalibration->createButton(OgreBites::TL_CENTER, "btnFingersClosed", "Flat Hand");
						}
						else
						{
							m_pTrayCalibration->createButton(OgreBites::TL_CENTER, "btnReset", "Reset");
							m_pTrayCalibration->createButton(OgreBites::TL_CENTER, "btnHandOpen", "Hand Open");
							m_pTrayCalibration->createButton(OgreBites::TL_CENTER, "btnFist", "Fist");							
						}
						m_pTrayCalibration->createSeparator(OgreBites::TL_CENTER, "sepCalibration2");
						m_pTrayCalibration->createButton(OgreBites::TL_CENTER, "btnSaveCalibration", "Save to File");
					}
					else
					{
						m_pTrayCalibration->createLabel(OgreBites::TL_CENTER, "lblNoGloveConnected", "No Glove connected");
					}
					m_pTrayCalibration->createButton(OgreBites::TL_CENTER, "btnCancel", "Cancel");
					m_pTrayCalibration->showAll();
				}
			}
		//case OIS::KC_M:
		//	{
		//		if (mSceneMgr->getEntity("Hand")->getSubEntity(0)->getMaterialName() == "basic1")
		//			mSceneMgr->getEntity("Hand")->setMaterialName("basic");
		//		else
		//			mSceneMgr->getEntity("Hand")->setMaterialName("basic1");

		//	}

		case OIS::KC_S:
			{
				char cSerial[50];
				fdGetSerialNumber(m_pGlove, cSerial);
				std::string sFileName(cSerial);
				sFileName += ".fd";
				fdSaveCalibration(m_pGlove,sFileName.c_str());
			}
		default:
			break;
    }
    return true;
}

//-------------------------------------------------------------------------------------
bool TutorialApplication::keyReleased( const OIS::KeyEvent& evt )
{
	BaseApplication::keyReleased(evt);

    return true;
}

//-------------------------------------------------------------------------------------
// OIS::MouseListener
bool TutorialApplication::mouseMoved( const OIS::MouseEvent& evt )
{
	//BaseApplication::mouseMoved( evt );
	if (m_pTrayMgr->injectMouseMove(evt)) return true;
	if (m_pTrayCalibration->injectMouseMove(evt)) return true;
	if (m_pTrayCalibration->isCursorVisible()) return true;

	updateCameraGoal(-0.10f * evt.state.X.rel, -0.10f * evt.state.Y.rel, -0.001f * evt.state.Z.rel);
	return true;

}

//-------------------------------------------------------------------------------------
void TutorialApplication::updateCameraGoal(Real deltaYaw, Real deltaPitch, Real deltaZoom)
{
	m_pCameraPivot->yaw(Degree(deltaYaw), Node::TS_WORLD);

	// bound the pitch
	if (!(m_fPivotPitch + deltaPitch > 55 && deltaPitch > 0) &&
		!(m_fPivotPitch + deltaPitch < -60 && deltaPitch < 0))
	{
		m_pCameraPivot->pitch(Degree(deltaPitch), Node::TS_LOCAL);
		m_fPivotPitch += deltaPitch;
	}
		
	Real dist = m_pCameraGoal->_getDerivedPosition().distance(m_pCameraPivot->_getDerivedPosition());
	Real distChange = deltaZoom * dist;

	// bound the zoom
	if (!(dist + distChange < 8 && distChange < 0) &&
		!(dist + distChange > 55 && distChange > 0))
	{
		m_pCameraGoal->translate(0, 0, distChange, Node::TS_LOCAL);
	}
}

//-------------------------------------------------------------------------------------
bool TutorialApplication::mousePressed( const OIS::MouseEvent& evt, OIS::MouseButtonID id )
{
	BaseApplication::mousePressed( evt, id );
	return true;
}

//-------------------------------------------------------------------------------------
bool TutorialApplication::mouseReleased( const OIS::MouseEvent& evt, OIS::MouseButtonID id )
{
	BaseApplication::mouseReleased( evt, id );
	return true;
}

//-------------------------------------------------------------------------------------
void TutorialApplication::UpdateCam(Real deltaTime)
{
	// move the camera smoothly to the goal
	Vector3 goalOffset = m_pCameraGoal->_getDerivedPosition() - m_pCameraNode->getPosition();
	m_pCameraNode->translate(goalOffset * deltaTime * 9.0f);
	// always look at the pivot
	m_pCameraNode->lookAt(m_pCameraPivot->_getDerivedPosition(), Node::TS_WORLD);
}

//-------------------------------------------------------------------------------------
void TutorialApplication::Update5SensorGlove()
{
	Ogre::Skeleton* skel = m_pSceneMgr->getEntity("Hand")->getSkeleton();
	
	Ogre::Bone* mBone;

	// Thumb
	float fThumb = 90*fdGetSensorScaled(m_pGlove,FD_THUMBFAR)-10;
	
	mBone = skel->getBone("Thumb.1");
    mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fThumb/3));

	mBone = skel->getBone("Thumb.2");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fThumb/2.5));

	mBone = skel->getBone("Thumb.3");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fThumb/2));

	// Index finger
	float fIndexFinger = 90*fdGetSensorScaled(m_pGlove,FD_INDEXFAR);
	
	mBone = skel->getBone("Index.1");
    mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fIndexFinger+20));

	mBone = skel->getBone("Index.2");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fIndexFinger));

	mBone = skel->getBone("Index.3");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fIndexFinger));

	float fMiddleFinger = 90*fdGetSensorScaled(m_pGlove,FD_MIDDLEFAR);

	mBone = skel->getBone("Middle.1");
    mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fMiddleFinger+20));

	mBone = skel->getBone("Middle.2");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fMiddleFinger));

	mBone = skel->getBone("Middle.3");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fMiddleFinger));

	float fRingFinger = 90*fdGetSensorScaled(m_pGlove,FD_RINGFAR);
	
	mBone = skel->getBone("Ring.1");
    mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fRingFinger+20));

	mBone = skel->getBone("Ring.2");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fRingFinger));

	mBone = skel->getBone("Ring.3");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fRingFinger));

	float fLittleFinger = 90*fdGetSensorScaled(m_pGlove,FD_LITTLEFAR);
	
	mBone = skel->getBone("Little.1");
    mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fLittleFinger+20));

	mBone = skel->getBone("Little.2");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fLittleFinger));

	mBone = skel->getBone("Little.3");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fLittleFinger));
}

//-------------------------------------------------------------------------------------
void TutorialApplication::Update14SensorGlove()
{
	Ogre::Skeleton* skel = m_pSceneMgr->getEntity("Hand")->getSkeleton();
	Ogre::Bone* mBone;

	// Middle finger
	float fMiddleFingerNear = 90*fdGetSensorScaled(m_pGlove,FD_MIDDLENEAR)-10;

	mBone = skel->getBone("Middle.1");
    mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fMiddleFingerNear));

	float fMiddleFingerFar = 90*fdGetSensorScaled(m_pGlove,FD_MIDDLEFAR)-10;

	mBone = skel->getBone("Middle.2");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fMiddleFingerFar));

	mBone = skel->getBone("Middle.3");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fMiddleFingerFar));

	// Ring finger
	float fRingFingerNear = 90*fdGetSensorScaled(m_pGlove,FD_RINGNEAR)-10;
	float fMiddleRing = 15*fdGetSensorScaled(m_pGlove,FD_MIDDLERING)-10;

	mBone = skel->getBone("Ring.1");
    mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fRingFingerNear));
	mBone->roll(Ogre::Degree(-fMiddleRing));

	float fRingFingerFar = 90*fdGetSensorScaled(m_pGlove,FD_RINGFAR)-10;

	mBone = skel->getBone("Ring.2");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fRingFingerFar));

	mBone = skel->getBone("Ring.3");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fRingFingerFar));

	//Thumb
	float fThumbNear = 90*fdGetSensorScaled(m_pGlove,FD_THUMBNEAR)-10;
	float fTumbIndex = 30*fdGetSensorScaled(m_pGlove,FD_THUMBINDEX)-30;
	mBone = skel->getBone("Thumb.1");
    mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fThumbNear/3));
	mBone->roll(Ogre::Degree(fTumbIndex));

	float fThumbFar = 90*fdGetSensorScaled(m_pGlove,FD_THUMBFAR)-10;
	mBone = skel->getBone("Thumb.2");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fThumbFar/2.5));

	mBone = skel->getBone("Thumb.3");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fThumbFar/2));
	
	// Index finger
	float fIndexFingerNear = 90*fdGetSensorScaled(m_pGlove,FD_INDEXNEAR)-10;
	float fIndexFingerMiddle = 24*fdGetSensorScaled(m_pGlove,FD_INDEXMIDDLE)-12;
	
	mBone = skel->getBone("Index.1");
    mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fIndexFingerNear));
	mBone->roll(Ogre::Degree(fIndexFingerMiddle));

	float fIndexFingerFar = 90*fdGetSensorScaled(m_pGlove,FD_INDEXFAR)-10;

	mBone = skel->getBone("Index.2");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fIndexFingerFar));

	mBone = skel->getBone("Index.3");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fIndexFingerFar));

	// Little finger
	float fLittleFingerNear = 90*fdGetSensorScaled(m_pGlove,FD_LITTLENEAR)-10;
	float fRingLittle = 30*fdGetSensorScaled(m_pGlove,FD_RINGLITTLE)-15;

	mBone = skel->getBone("Little.1");
    mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fLittleFingerNear));
	mBone->roll(Ogre::Degree(-fRingLittle - fMiddleRing));

	float fLittleFingerFar = 90*fdGetSensorScaled(m_pGlove,FD_LITTLEFAR)-10;

	mBone = skel->getBone("Little.2");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fLittleFingerFar));

	mBone = skel->getBone("Little.3");
	mBone->setManuallyControlled(true);
	mBone->reset();
	mBone->pitch(Ogre::Degree(-fLittleFingerFar));
}

//-------------------------------------------------------------------------------------
void TutorialApplication::createCamera(void)
{
	m_pCamera = m_pSceneMgr->createCamera("PlayerCam");
	m_pCamera->setNearClipDistance(5);
	m_pCamera->setFixedYawAxis(true);

}

#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
        TutorialApplication 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
