void KeyboardUpCallback(unsigned char key, int x, int y)
{
	gKeys[key] = false;

	switch (key)
	{
		case 'p': { bPause = !bPause; 
					if (bPause)
						hud.SetDisplayString(1, "Paused - Hit \"p\" to Unpause", 0.3f, 0.55f);
					else
						hud.SetDisplayString(1, "", 0.0f, 0.0f);	
					getElapsedTime(); 
					break; }
	
		case 'f': { bForceMode = !bForceMode; break; }
	    case 'b': 
			{
				box = CreateBox(NxVec3(2,5-0.75,7), NxVec3(0.75,0.75,0.75), 1);
	  			sphere = CreateSphere(NxVec3(0,4-0.4,1), 0.4, 1);
	  			capsule = CreateCapsule(NxVec3(3,0-(1+0.5),8), 1, 1, 1);
		 		break; 
	  		  }	
		case 27 : { exit(0); break; }
		default : { break; }
	}
}
void UpdateTime()
{
	if(!gameOver)
	{
		hud.SetDisplayInt(29, minutes, 0.25f, 0.01f);	
		//code to manually place a 0 before any seond number lower than 10
		if(seconds < 10)
		{
			hud.SetDisplayString(31, "Playtime:      : 0", 0.10f, 0.01f);
			hud.SetDisplayInt(30, seconds, 0.31f, 0.01f);
		}
		else
		{
			hud.SetDisplayString(31, "Playtime:      :", 0.10f, 0.01f);
			hud.SetDisplayInt(30, seconds, 0.30f, 0.01f);
		}
	}
	else
	{
		hud.SetDisplayInt(29, minutes, -100.25f, 0.01f);	
		//code to manually place a 0 before any seond number lower than 10
		if(seconds < 10)
		{
			hud.SetDisplayString(31, "Playtime:      : 0", -100.10f, 0.01f);
			hud.SetDisplayInt(30, seconds, -100.31f, 0.01f);
		}
		else
		{
			hud.SetDisplayString(31, "Playtime:      :", -100.10f, 0.01f);
			hud.SetDisplayInt(30, seconds, -100.30f, 0.01f);
		}
	}
}
void KeyboardUpCallback(unsigned char key, int x, int y)
{
	gKeys[key] = false;

	switch (key)
	{
		case 'p': { bPause = !bPause; 
					if (bPause)
						hud.SetDisplayString(1, "Paused - Hit \"p\" to Unpause", 0.3f, 0.55f);
					else
						hud.SetDisplayString(1, "", 0.0f, 0.0f);	
					getElapsedTime(); 
					break; }
		case 'x': { bShadows = !bShadows; break; }
		case 'b': { bDebugWireframeMode = !bDebugWireframeMode; break; }
		case 'c': { 
					// Reset the box
					NxMat33 m;
					m.id();
					box1->setGlobalOrientation(m);
					box1->setGlobalPosition(NxVec3(5,3.5,0));
					box1->setLinearVelocity(NxVec3(0,0,0));
					box1->setAngularVelocity(NxVec3(0,0,0));

					ChangeKernel();
					break; 
				  }
		case 27 : { exit(0); break; }
		default : { break; }
	}
}
void ProcessInputs()
{
    UpdateWheelShapeUserData();

    ProcessForceKeys();

	if (bSetCurrentMotorTorque1)
	{
		bSetCurrentMotorTorque1 = false;
		wheel1->setMotorTorque(gCurrentMotorTorque1);
		// Set motor torque #1 in HUD
		char ds[512];
		sprintf(ds, "Left wheel torque: %d", gCurrentMotorTorque1);
		hud.SetDisplayString(2, ds, 0.015f, 0.92f);
	}

	if (bSetCurrentMotorTorque2)
	{
		bSetCurrentMotorTorque2 = false;
		wheel2->setMotorTorque(gCurrentMotorTorque2);
		// Set motor torque #2 in HUD
		char ds[512];
		sprintf(ds, "Right wheel torque: %d", gCurrentMotorTorque2);
		hud.SetDisplayString(3, ds, 0.015f, 0.87f);
	}

    // Show debug wireframes
    if (bDebugWireframeMode) 
	{
		if (gScene)
		{
			gDebugRenderer.renderData(*gScene->getDebugRenderable());
		}
    }
}
void KeyboardUpCallback(unsigned char key, int x, int y)
{
	gKeys[key] = false;

	switch (key)
	{
		case 'p': { bPause = !bPause; 
					if (bPause)
						hud.SetDisplayString(2, "Paused - Hit \"p\" to Unpause", 0.3f, 0.55f);
					else
						hud.SetDisplayString(2, "", 0.0f, 0.0f);	
					break; }
		case 'x': { bShadows = !bShadows; break; }
		case 'b': { bDebugWireframeMode = !bDebugWireframeMode; break; }		
		case 'f': { bForceMode = !bForceMode; break; }

		case 'o': 
		{     
			NxCloth** cloths = gScene->getCloths();
			for (NxU32 i = 0; i < gScene->getNbCloths(); i++) 
			{
				cloths[i]->setFlags(cloths[i]->getFlags() ^ NX_CLF_BENDING_ORTHO);
			}
			break;
		}

		case 'g': 
		{     
			NxCloth** cloths = gScene->getCloths();
			for (NxU32 i = 0; i < gScene->getNbCloths(); i++) 
			{
				cloths[i]->setFlags(cloths[i]->getFlags() ^ NX_CLF_GRAVITY);
			}
			break;
		}

		case 'y': 
		{
			NxCloth** cloths = gScene->getCloths();
			for (NxU32 i = 0; i < gScene->getNbCloths(); i++) 
			{
				cloths[i]->setFlags(cloths[i]->getFlags() ^ NX_CLF_BENDING);
			}	            
			break;
		}
		case ' ': 
		{
			NxActor* sphere = CreateSphere(gCameraPos, 1, 1);
			sphere->setLinearVelocity(gCameraForward * 20);
			break; 
		}
		case 27 : { exit(0); break; }
		default : { break; }
	}
}
void CheckLives()
{
	//game is in player displayer lives at top right
	hud.SetDisplayInt(4, lives, 0.86f, 0.93f);

	//levelnum
	hud.SetDisplayInt(8, currentLevel, 0.52f, 0.93f);

	//if game is over display final score
	if(gameOver)
	{
		ShowScores();
		hud.SetDisplayString(3, "", 0.0f, 0.0f);
		hud.SetDisplayString(0, "", 0.3f, 0.55f);
		hud.SetDisplayString(2, "    Game Over\nYour Score:\n\n\n -High Scores-\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nBackspace = Restart", 0.4f, 0.65f);
		hud.SetDisplayString(4, "", 0.3f, 0.55f);
	}

	//check if level is complete
	if(nextLevel)
	{
		hud.SetDisplayString(3, "", 0.0f, 0.0f);
		hud.SetDisplayString(0, "", 0.3f, 0.55f);
		hud.SetDisplayString(2, "Level Complete!\n\nPress Enter to Progress", 0.3f, 0.55f);
		hud.SetDisplayString(4, "", 0.3f, 0.55f);
	}
}
void ProcessInputs()
{
    UpdateWheelShapeUserData();

    ProcessForceKeys();

	if (bSetCurrentSteerAngle)
	{
		bSetCurrentSteerAngle = false;
        wheel1->setSteerAngle(gCurrentSteerAngle);
		// Add front wheel steer angle to HUD
		char ds[512];
		sprintf(ds, "Front Wheel Steer Angle: %d", (int)(gCurrentSteerAngle*180.0/NxPi));
		hud.SetDisplayString(2, ds, 0.015f, 0.92f);
	}

	if (bSetCurrentMotorTorque)
	{
		bSetCurrentMotorTorque = false;
        wheel2->setMotorTorque(gCurrentMotorTorque);
        wheel3->setMotorTorque(gCurrentMotorTorque);
		// Add rear wheel motor torque to HUD
		char ds[512];
		sprintf(ds, "Rear Wheel Motor Torque: %d", gCurrentMotorTorque);
		hud.SetDisplayString(3, ds, 0.015f, 0.87f);
	}

	if (bSetCurrentBrakeTorque)
	{
		bSetCurrentBrakeTorque = false;
		wheel2->setBrakeTorque(gCurrentBrakeTorque);
		wheel3->setBrakeTorque(gCurrentBrakeTorque);				
		// Add rear wheel brake torque to HUD
		char ds[512];
		sprintf(ds, "Rear Wheel Brake Torque: %d", gCurrentBrakeTorque);
		hud.SetDisplayString(4, ds, 0.015f, 0.82f);
	}


    // Show debug wireframes
    if (bDebugWireframeMode) 
	{
		if (gScene)
		{
			gDebugRenderer.renderData(*gScene->getDebugRenderable());
		}
    }
}
void ProcessInputs()
{
	DisableAKey('t');
    ProcessForceKeys();

	UpdateJointMotorTarget();

	if (bReconfigureD6Joint)
	{
		bReconfigureD6Joint = false;
		gJointType = (gJointType+1)%gNumJointConfigurations; 
		ReconfigureD6Joint();
	}

	if (bToggleLowerActorGravity)
	{
		char ds[512];

        bToggleLowerActorGravity = false;
        if (capsule2->readBodyFlag(NX_BF_DISABLE_GRAVITY))
            capsule2->clearBodyFlag(NX_BF_DISABLE_GRAVITY);   
        else
            capsule2->raiseBodyFlag(NX_BF_DISABLE_GRAVITY);

		// Set lower actor gravity in HUD
		sprintf(ds, "Lower Actor Gravity: %s", gOnOffString[!capsule2->readBodyFlag(NX_BF_DISABLE_GRAVITY)]);
		hud.SetDisplayString(11, ds, 0.015f, 0.47f);
    }

    // Show debug wireframes
	if (bDebugWireframeMode)
	{
		if (gScene)  gDebugRenderer.renderData(*gScene->getDebugRenderable());
	}
}
void KeyboardUpCallback(unsigned char key, int x, int y)
{
	gKeys[key] = false;

	switch (key)
	{
	    case '0': { gPerfRenderer.toggleEnable(); break; }
		case 'p': { bPause = !bPause; 
					if (bPause)
						hud.SetDisplayString(1, "Paused - Hit \"p\" to Unpause", 0.3f, 0.55f);
					else
						hud.SetDisplayString(1, "", 0.0f, 0.0f);	
					getElapsedTime(); 
					break; }
		case 'x': { bShadows = !bShadows; break; }
		case 'b': { bDebugWireframeMode = !bDebugWireframeMode; break; }		
		case 'f': { bForceMode = !bForceMode; break; }
		case 27 : { exit(0); break; }

		// Switch simulation threads mode
		case 't': {	ReleaseNx();
					gbThreadScheduler = gbThreadPolling = gbThreadSDKManage = gbNoThread = false;
					gbThreadScheduler = true;
					InitNx();
					break; }
		case 'y': {	ReleaseNx();
					gbThreadScheduler = gbThreadPolling = gbThreadSDKManage = gbNoThread = false;
					gbThreadPolling = true;
					InitNx();
					break; }
		case 'g': {	ReleaseNx();
					gbThreadScheduler = gbThreadPolling = gbThreadSDKManage = gbNoThread = false;
					gbThreadSDKManage = true;
					InitNx();
					break; }
		case 'h': {	ReleaseNx();
					gbThreadScheduler = gbThreadPolling = gbThreadSDKManage = gbNoThread = false;
					gbNoThread = true;
					InitNx();
					break; }
		default : { break; }
	}
}
void KeyboardUpCallback(unsigned char key, int x, int y)
{
	gKeys[key] = false;

	switch (key)
	{
		case 'p': { bPause = !bPause; 
					if (bPause)
						hud.SetDisplayString(1, "Paused - Hit \"p\" to Unpause", 0.3f, 0.55f);
					else
						hud.SetDisplayString(1, "", 0.0f, 0.0f);	
					getElapsedTime(); 
					break; }
		case 'x': { bShadows = !bShadows; break; }
		case 'b': { bDebugWireframeMode = !bDebugWireframeMode; break; }		
		case 'f': { bForceMode = !bForceMode; break; }
		case 27 : { exit(0); break; }
		default : { break; }
	}
}
void RenderCallback()
{
    // Clear buffers
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    ProcessCameraKeys();
	SetupCamera();

    if (gScene && !bPause)
	{
		GetPhysicsResults();
        ProcessInputs();
		StartPhysics();
	}

    // Display scene
 	RenderActors(bShadows);

	// Display kernel Info
	if (gForceField)
	{
		if (gForceField->getForceFieldKernel() == gCustomKernel)
		{
			hud.SetDisplayString(2, "Using CustomKernel", 0.14f, 0.92f);
		}
		else if (gForceField->getForceFieldKernel() == gLinearKernel)
		{
			hud.SetDisplayString(2, "Using LinearKernel", 0.14f, 0.92f);
		}
	}
	
	// Render the HUD
	hud.Render();

    glFlush();
    glutSwapBuffers();
}
void UnShowScores()
{
	int count = 9;
	for(int i = 0; i < 10; i++)
	{
		if(orderedScores[i] > 0)
		{			
			hud.SetDisplayInt(count, 0, -100.55f, 0.5f - ((float)i/40)); 
			char *display = &orderedNames[i][0];
			count++;
  			hud.SetDisplayString(count, "", -100.4f, 0.5f - ((float)i/40));
			count ++;
		}
	}
	count = 0;
}
///
/// Handle all single key presses. 
///
void KeyPress(unsigned char key, int x, int y)
{
	if (!gKeys[key]) // ensure the keypress is only executed once
	{
		switch (key)
		{
			/*
		case 'b': //toggle between different rendering modes
			if (rendering_mode == RENDER_SOLID)
				rendering_mode = RENDER_WIREFRAME;
			else if (rendering_mode == RENDER_WIREFRAME)
				rendering_mode = RENDER_BOTH;
			else if (rendering_mode == RENDER_BOTH)
				rendering_mode = RENDER_SOLID;
			break;
			*/
		case 'p':
			bPause = !bPause; 
			if (bPause)
			{
				hud.SetDisplayString(1, "Paused - Hit \"p\" to Unpause", 0.3f, 0.55f);
			}
			else
				hud.SetDisplayString(1, "", 0.3f, 0.55f);	
			getElapsedTime(); 
			break; 
			/*
		case 'r':
			SelectNextActor();
			break;
		case 'x': 
			bShadows = !bShadows; 
			break;
			*/
		case 27: //ESC
			exit(0);
			break;
		case 8:
				if(gameOver)
			{// Reset PhysX and View
				ResetGame();
				ResetPhysX();
				UnShowScores();
				hud.SetDisplayString(3, "Score:", 0.04f, 0.93);
				hud.SetDisplayString(2, "", 0.04f, 0.93);
				hud.SetDisplayString(0, "Lives:", 0.76f, 0.93f);
				//ResetCamera();
				gSelectedActor = 0;
				minutes = 0;
				seconds = 0;
			}
			break;
		case 13:
			if(nextLevel)
			{//progress level
		NextLevel();
		ResetPhysX();
		hud.SetDisplayString(3, "Score:", 0.04f, 0.93);
		hud.SetDisplayString(2, "", 0.04f, 0.93);
		hud.SetDisplayString(0, "Lives:", 0.76f, 0.93f);
		}
		break;
		default:
			break;
		}
	}

	gKeys[key] = true;
}
// Reconfigure joint, a.k.a., roll joint
void ReconfigureD6Joint()
{
	NxActor* a0 = capsule1;
	NxActor* a1 = capsule2;

    NxD6JointDesc d6Desc;

    // Reset actor #1
    NxMat33 orient;
    orient.id();
    a1->raiseBodyFlag(NX_BF_KINEMATIC);
    a1->setGlobalOrientation(orient);
    a1->setGlobalPosition(NxVec3(0,3,0));
    a1->clearBodyFlag(NX_BF_KINEMATIC);

    d6Desc.actor[0] = a0;
    d6Desc.actor[1] = a1;

    // Reset Anchor and Axis
    NxVec3 globalAnchor = NxVec3(0,5,0);
    NxVec3 globalAxis = NxVec3(0,1,0);

    d6Desc.setGlobalAnchor(globalAnchor);
    d6Desc.setGlobalAxis(globalAxis);

	switch (gJointType) 
	{
		case 0:  // Translation Limited Joint 
		{
			d6Desc.twistMotion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.swing1Motion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.swing2Motion = NX_D6JOINT_MOTION_LOCKED;

			d6Desc.xMotion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.yMotion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.zMotion = NX_D6JOINT_MOTION_LIMITED;

	        d6Desc.linearLimit.value = 0.8;
	        d6Desc.linearLimit.restitution = 0;
	        d6Desc.linearLimit.spring = 0;
	        d6Desc.linearLimit.damping = 0;
		}
		break;

		case 1:  // Translation Soft Limited Joint 
		{ 
			d6Desc.twistMotion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.swing1Motion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.swing2Motion = NX_D6JOINT_MOTION_LOCKED;

			d6Desc.xMotion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.yMotion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.zMotion = NX_D6JOINT_MOTION_LIMITED;

	        d6Desc.linearLimit.value = 0.8;
	        d6Desc.linearLimit.restitution = 0;
	        d6Desc.linearLimit.spring = 100;
	        d6Desc.linearLimit.damping = 0.1;
		}
		break;

		case 2:  // Rotation Limited Joint 
		{ 
			d6Desc.twistMotion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.swing1Motion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.swing2Motion = NX_D6JOINT_MOTION_LIMITED;

			d6Desc.xMotion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.yMotion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.zMotion = NX_D6JOINT_MOTION_LOCKED;

	        d6Desc.swing1Limit.value = 0.3*NxPi;
	        d6Desc.swing1Limit.restitution = 0;
	        d6Desc.swing1Limit.spring = 0;
	        d6Desc.swing1Limit.damping = 0;

	        d6Desc.swing2Limit.value = 0.3*NxPi;
	        d6Desc.swing2Limit.restitution = 0;
	        d6Desc.swing2Limit.spring = 0;
	        d6Desc.swing2Limit.damping = 0;

	        d6Desc.twistLimit.low.value = -0.05*NxPi;
	        d6Desc.twistLimit.low.restitution = 0;
	        d6Desc.twistLimit.low.spring = 0;
	        d6Desc.twistLimit.low.damping = 0;
			
			d6Desc.twistLimit.high.value = 0.05*NxPi;
	        d6Desc.twistLimit.high.restitution = 0;
	        d6Desc.twistLimit.high.spring = 0;
	        d6Desc.twistLimit.high.damping = 0;
		}
		break;

		case 3:  // Rotation Soft Limited Joint 
		{ 
			d6Desc.twistMotion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.swing1Motion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.swing2Motion = NX_D6JOINT_MOTION_LIMITED;

			d6Desc.xMotion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.yMotion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.zMotion = NX_D6JOINT_MOTION_LOCKED;

	        d6Desc.swing1Limit.value = 0.3*NxPi;
	        d6Desc.swing1Limit.restitution = 0;
	        d6Desc.swing1Limit.spring = 300;
	        d6Desc.swing1Limit.damping = 10;

	        d6Desc.swing2Limit.value = 0.3*NxPi;
	        d6Desc.swing2Limit.restitution = 0;
	        d6Desc.swing2Limit.spring = 300;
	        d6Desc.swing2Limit.damping = 10;

	        d6Desc.twistLimit.low.value = -0.05*NxPi;
	        d6Desc.twistLimit.low.restitution = 0;
	        d6Desc.twistLimit.low.spring = 300;
	        d6Desc.twistLimit.low.damping = 10;
			
			d6Desc.twistLimit.high.value = 0.05*NxPi;
	        d6Desc.twistLimit.high.restitution = 0;
		}
		break;

		case 4:  // Translation Motored Joint 
		{ 
			d6Desc.twistMotion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.swing1Motion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.swing2Motion = NX_D6JOINT_MOTION_LOCKED;

			d6Desc.xMotion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.yMotion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.zMotion = NX_D6JOINT_MOTION_LIMITED;

	        d6Desc.linearLimit.value = 1;
	        d6Desc.linearLimit.restitution = 0;
	        d6Desc.linearLimit.spring = 0;
	        d6Desc.linearLimit.damping = 0;

			d6Desc.zDrive.driveType = NX_D6JOINT_DRIVE_POSITION;
			d6Desc.zDrive.spring = 100;
			d6Desc.zDrive.damping = 0;
			d6Desc.drivePosition.set(0,5,1);

//			d6Desc.zDrive.driveType = NX_D6JOINT_DRIVE_VELOCITY;
//			d6Desc.zDrive.forceLimit = FLT_MAX;
//			d6Desc.driveLinearVelocity.set(0,0,5);
		}
		break;

		case 5:  // Rotation Motored Joint 
		{ 
			d6Desc.twistMotion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.swing1Motion = NX_D6JOINT_MOTION_LIMITED;
			d6Desc.swing2Motion = NX_D6JOINT_MOTION_LIMITED;

			d6Desc.xMotion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.yMotion = NX_D6JOINT_MOTION_LOCKED;
			d6Desc.zMotion = NX_D6JOINT_MOTION_LOCKED;

	        d6Desc.swing1Limit.value = 0.3*NxPi;
	        d6Desc.swing1Limit.restitution = 0;
	        d6Desc.swing1Limit.spring = 0;
	        d6Desc.swing1Limit.damping = 0;

	        d6Desc.swing2Limit.value = 0.3*NxPi;
	        d6Desc.swing2Limit.restitution = 0;
	        d6Desc.swing2Limit.spring = 0;
	        d6Desc.swing2Limit.damping = 0;

	        d6Desc.twistLimit.low.value = -0.05*NxPi;
	        d6Desc.twistLimit.low.restitution = 0;
	        d6Desc.twistLimit.low.spring = 0;
	        d6Desc.twistLimit.low.damping = 0;
			
			d6Desc.twistLimit.high.value = 0.05*NxPi;
	        d6Desc.twistLimit.high.restitution = 0;
	        d6Desc.twistLimit.high.spring = 0;
	        d6Desc.twistLimit.high.damping = 0;

			// Slerp Drive - Orientation Target
			d6Desc.flags = NX_D6JOINT_SLERP_DRIVE;
			d6Desc.slerpDrive.driveType = NX_D6JOINT_DRIVE_POSITION;
			d6Desc.slerpDrive.spring = 200;
			d6Desc.slerpDrive.damping = 0;
			NxQuat q;
			q.fromAngleAxis(90,NxVec3(0,1,0));
			d6Desc.driveOrientation = q;
		}
		break;

	};

	d6Desc.projectionMode = NX_JPM_NONE;

	// Set joint motion display values
	gJointMotion[3] = d6Desc.twistMotion;
	gJointMotion[4] = d6Desc.swing1Motion;
	gJointMotion[5] = d6Desc.swing2Motion;

	gJointMotion[0] = d6Desc.xMotion;
	gJointMotion[1] = d6Desc.yMotion;
	gJointMotion[2] = d6Desc.zMotion;

	char ds[512];

	// Set joint type in HUD
	sprintf(ds, "JOINT TYPE: %s", gJointTypeString[gJointType]);
	hud.SetDisplayString(2, ds, 0.015f, 0.92f);	

	// Set rotation motions in HUD
    sprintf(ds, "   Axis: %s", gJointMotionString[gJointMotion[3]]);
	hud.SetDisplayString(4, ds, 0.015f, 0.82f); 
    sprintf(ds, "   Normal: %s", gJointMotionString[gJointMotion[4]]);
	hud.SetDisplayString(5, ds, 0.015f, 0.77f); 
    sprintf(ds, "   Binormal: %s", gJointMotionString[gJointMotion[5]]);
	hud.SetDisplayString(6, ds, 0.015f, 0.72f); 

	// Set translation motions in HUD
    sprintf(ds, "   Axis: %s", gJointMotionString[gJointMotion[0]]);
	hud.SetDisplayString(8, ds, 0.015f, 0.62f); 
    sprintf(ds, "   Normal: %s", gJointMotionString[gJointMotion[1]]);
	hud.SetDisplayString(9, ds, 0.015f, 0.57f); 
    sprintf(ds, "   Binormal: %s", gJointMotionString[gJointMotion[2]]);
	hud.SetDisplayString(10, ds, 0.015f, 0.52f);

	d6Joint->loadFromDesc(d6Desc);
}
void KeyboardUpCallback(unsigned char key, int x, int y)
{
	gKeys[key] = false;

	switch (key)
	{
		case 'p': { bPause = !bPause; 
					if (bPause)
						hud.SetDisplayString(1, "Paused - Hit \"p\" to Unpause", 0.3f, 0.55f);
					else
						hud.SetDisplayString(1, "", 0.0f, 0.0f);	
					getElapsedTime(); 
					break; }
		case 'x': { bShadows = !bShadows; break; }
		case 'b': { bDebugWireframeMode = !bDebugWireframeMode; break; }		
		case 'f': { bForceMode = !bForceMode; break; }

	    // Left wheel
		case '1':
        { 
            gCurrentMotorTorque1 += 100;
 			bSetCurrentMotorTorque1 = true;
			break; 
        }

		case '2':
        { 
            gCurrentMotorTorque1 = 0;
 			bSetCurrentMotorTorque1 = true;
			break; 
        }

		case '3':
        { 
            gCurrentMotorTorque1 -= 100;
 			bSetCurrentMotorTorque1 = true;
            break; 
        }

	    // Right wheel
		case '8':
        { 
            gCurrentMotorTorque2 += 100;
 			bSetCurrentMotorTorque2 = true;
			break; 
        }

		case '9':
        { 
            gCurrentMotorTorque2 = 0;
 			bSetCurrentMotorTorque2 = true;
            break; 
        }

		case '0':
        { 
            gCurrentMotorTorque2 -= 100;
 			bSetCurrentMotorTorque2 = true;
            break; 
        }

		case 27 : { exit(0); break; }
		default : { break; }
	}
}