www.pudn.com > 3ds-load.rar > Camera.cpp


//***********************************************************************// 
//																		 // 
//		- "Talk to me like I'm a 3 year old!" Programming Lessons -		 // 
//                                                                       // 
//		$Author:		DigiBen		DigiBen@GameTutorials.com			 // 
//																		 // 
//		$Program:		Camera5	(strafing)								 // 
//																		 // 
//		$Description:	Demonstrates camera strafing right and left		 // 
//																		 // 
//		$Date:			1/1/02											 // 
//																		 // 
//***********************************************************************// 
 
 
//#include "main.h" 
#include  
#include  
#include 		// Header File For The Glaux Library 
//#include "vector.h" 
#define SCREEN_WIDTH 800								// We want our screen width 800 pixels 
#define SCREEN_HEIGHT 600								// We want our screen height 600 pixels 
#define SCREEN_DEPTH 16									// We want 16 bits per pixel 
 
#include "Camera.h" 
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * 
 
// This is how fast our camera moves (Sped up a bit due to normalizing our vectors) 
#define kSpeed	5.5f									 
 
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * 
 
 
/////////////////////////////////////// CROSS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
///// 
/////	This returns a perpendicular vector from 2 given vectors by taking the cross product. 
///// 
/////////////////////////////////////// CROSS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
												 
 
 
///////////////////////////////// CCAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
///// 
/////	This is the class constructor 
///// 
///////////////////////////////// CCAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
 
CCamera::CCamera() 
{ 
	CVector3 vZero = CVector3(0.0, 0.0, 0.0);		// Init a vVector to 0 0 0 for our position 
	CVector3 vView = CVector3(0.0, 1.0, 0.5);		// Init a starting view vVector (looking up and out the screen)  
	CVector3 vUp   = CVector3(0.0, 0.0, 1.0);		// Init a standard up vVector (Rarely ever changes) 
 
	m_vPosition	= vZero;					// Init the position to zero 
	m_vView		= vView;					// Init the view to a std starting view 
	m_vUpVector	= vUp;						// Init the UpVector 
} 
 
 
///////////////////////////////// POSITION CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
///// 
/////	This function sets the camera's position and view and up vVector. 
///// 
///////////////////////////////// POSITION CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
 
void CCamera::PositionCamera(float positionX, float positionY, float positionZ, 
				  		     float viewX,     float viewY,     float viewZ, 
							 float upVectorX, float upVectorY, float upVectorZ) 
{ 
	CVector3 vPosition	= CVector3(positionX, positionY, positionZ); 
	CVector3 vView		= CVector3(viewX, viewY, viewZ); 
	CVector3 vUpVector	= CVector3(upVectorX, upVectorY, upVectorZ); 
 
	// The code above just makes it cleaner to set the variables. 
	// Otherwise we would have to set each variable x y and z. 
 
	m_vPosition = vPosition;					// Assign the position 
	m_vView     = vView;						// Assign the view 
	m_vUpVector = vUpVector;					// Assign the up vector 
//	 
/*	char buf[128]; 
	wsprintf(buf,"Position:%d %d %d LookAt:%d %d %d",int(m_vPosition.x),int(m_vPosition.y),int(m_vPosition.z),int(m_vView.x),int(m_vView.y),int(m_vView.z)); 
	if(m_pText) 
		m_pText->EditItem(m_nTextID,0.0f,1.0f,0.0f,buf); 
		*/ 
} 
 
 
///////////////////////////////// SET VIEW BY MOUSE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
///// 
/////	This allows us to look around using the mouse, like in most first person games. 
///// 
///////////////////////////////// SET VIEW BY MOUSE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
 
void CCamera::SetViewByMouse() 
{ 
	POINT mousePos;									// This is a window structure that holds an X and Y 
	int middleX = SCREEN_WIDTH  >> 1;				// This is a binary shift to get half the width 
	int middleY = SCREEN_HEIGHT >> 1;				// This is a binary shift to get half the height 
	float angleY = 0.0f;							// This is the direction for looking up or down 
	float angleZ = 0.0f;							// This will be the value we need to rotate around the Y axis (Left and Right) 
	static float currentRotX = 0.0f; 
	 
	// Get the mouse's current X,Y position 
	GetCursorPos(&mousePos);						 
	 
	// If our cursor is still in the middle, we never moved... so don't update the screen 
	if( (mousePos.x == middleX) && (mousePos.y == middleY) ) return; 
 
	// Set the mouse position to the middle of our window 
	SetCursorPos(middleX, middleY);							 
 
	// Get the direction the mouse moved in, but bring the number down to a reasonable amount 
	angleY = (float)( (middleX - mousePos.x) ) / 1000.0f;		 
	angleZ = (float)( (middleY - mousePos.y) ) / 1000.0f;		 
 
	// Here we keep track of the current rotation (for up and down) so that 
	// we can restrict the camera from doing a full 360 loop. 
	currentRotX -= angleZ;   
 
	// If the current rotation (in radians) is greater than 1.0, we want to cap it. 
//	if(currentRotX > 1.0f) 
//		currentRotX = 1.0f; 
	// Check if the rotation is below -1.0, if so we want to make sure it doesn't continue 
//	else if(currentRotX < -1.0f) 
//		currentRotX = -1.0f; 
	// Otherwise, we can rotate the view around our position 
//	else 
	{ 
		// To find the axis we need to rotate around for up and down 
		// movements, we need to get a perpendicular vector from the 
		// camera's view vector and up vector.  This will be the axis. 
		CVector3 vAxis = CrossProduct(m_vView - m_vPosition, m_vUpVector); 
		vAxis = Normalize(vAxis); 
 
		// Rotate around our perpendicular axis and along the y-axis 
		RotateView(angleZ, vAxis.x, vAxis.y, vAxis.z); 
		RotateView(angleY, 0, 1, 0); 
	} 
} 
 
 
///////////////////////////////// ROTATE VIEW \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
///// 
/////	This rotates the view around the position using an axis-angle rotation 
///// 
///////////////////////////////// ROTATE VIEW \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
 
void CCamera::RotateView(float angle, float x, float y, float z) 
{ 
	CVector3 vNewView; 
 
	// Get the view vector (The direction we are facing) 
	CVector3 vView = m_vView - m_vPosition;		 
 
	// Calculate the sine and cosine of the angle once 
	float cosTheta = (float)cos(angle); 
	float sinTheta = (float)sin(angle); 
 
	// Find the new x position for the new rotated point 
	vNewView.x  = (cosTheta + (1 - cosTheta) * x * x)		* vView.x; 
	vNewView.x += ((1 - cosTheta) * x * y - z * sinTheta)	* vView.y; 
	vNewView.x += ((1 - cosTheta) * x * z + y * sinTheta)	* vView.z; 
 
	// Find the new y position for the new rotated point 
	vNewView.y  = ((1 - cosTheta) * x * y + z * sinTheta)	* vView.x; 
	vNewView.y += (cosTheta + (1 - cosTheta) * y * y)		* vView.y; 
	vNewView.y += ((1 - cosTheta) * y * z - x * sinTheta)	* vView.z; 
 
	// Find the new z position for the new rotated point 
	vNewView.z  = ((1 - cosTheta) * x * z - y * sinTheta)	* vView.x; 
	vNewView.z += ((1 - cosTheta) * y * z + x * sinTheta)	* vView.y; 
	vNewView.z += (cosTheta + (1 - cosTheta) * z * z)		* vView.z; 
 
	// Now we just add the newly rotated vector to our position to set 
	// our new rotated view of our camera. 
	m_vView = m_vPosition + vNewView; 
} 
 
 
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * 
 
///////////////////////////////// STRAFE CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
///// 
/////	This strafes the camera left and right depending on the speed (-/+) 
///// 
///////////////////////////////// STRAFE CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
 
void CCamera::StrafeCamera(float speed) 
{ 
	// Strafing is quite simple if you understand what the cross product is. 
	// If you have 2 vectors (say the up vVector and the view vVector) you can 
	// use the cross product formula to get a vVector that is 90 degrees from the 2 vectors. 
	// For a better explanation on how this works, check out the OpenGL "Normals" tutorial at our site. 
	// In our new Update() function, we set the strafing vector (m_vStrafe).  Due 
	// to the fact that we need this vector for many things including the strafing 
	// movement and camera rotation (up and down), we just calculate it once. 
	// 
	// Like our MoveCamera() function, we add the strafing vector to our current position  
	// and view.  It's as simple as that.  It has already been calculated in Update(). 
	 
	// Add the strafe vector to our position 
	m_vPosition.x += m_vStrafe.x * speed; 
	m_vPosition.z += m_vStrafe.z * speed; 
 
	// Add the strafe vector to our view 
	m_vView.x += m_vStrafe.x * speed; 
	m_vView.z += m_vStrafe.z * speed; 
//	m_pPortal->CheckCollision(); 
} 
 
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * 
 
 
///////////////////////////////// MOVE CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
///// 
/////	This will move the camera forward or backward depending on the speed 
///// 
///////////////////////////////// MOVE CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
 
void CCamera::MoveCamera(float speed) 
{ 
	// Get the current view vector (the direction we are looking) 
	CVector3 vVector = m_vView - m_vPosition; 
 
 
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * 
 
	// I snuck this change in here!  We now normalize our view vector when 
	// moving throughout the world.  This is a MUST that needs to be done. 
	// That way you don't move faster than you strafe, since the strafe vector 
	// is normalized too. 
	vVector = Normalize(vVector); 
	 
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * 
 
 
	m_vPosition.x += vVector.x * speed;		// Add our acceleration to our position's X 
	m_vPosition.z += vVector.z * speed;		// Add our acceleration to our position's Z 
	m_vView.x += vVector.x * speed;			// Add our acceleration to our view's X 
	m_vView.z += vVector.z * speed;			// Add our acceleration to our view's Z 
//	m_pPortal->CheckCollision(); 
} 
 
 
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * 
 
// The next 3 functions were added to our camera class.  The less code in  
// Main.cpp the better. 
 
//////////////////////////// CHECK FOR MOVEMENT \\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
///// 
/////	This function handles the input faster than in the WinProc() 
///// 
//////////////////////////// CHECK FOR MOVEMENT \\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
 
void CCamera::CheckForMovement() 
{ 
	// Check if we hit the Up arrow or the 'w' key 
	if(GetKeyState(VK_UP) & 0x80 || GetKeyState('W') & 0x80) {				 
 
		// Move our camera forward by a positive SPEED 
		MoveCamera(kSpeed);				 
	} 
 
	// Check if we hit the Down arrow or the 's' key 
	if(GetKeyState(VK_DOWN) & 0x80 || GetKeyState('S') & 0x80) {			 
 
		// Move our camera backward by a negative SPEED 
		MoveCamera(-kSpeed);				 
	} 
 
	// Check if we hit the Left arrow or the 'a' key 
	if(GetKeyState(VK_LEFT) & 0x80 || GetKeyState('A') & 0x80) {			 
 
		// Strafe the camera left 
		StrafeCamera(-kSpeed); 
	} 
 
	// Check if we hit the Right arrow or the 'd' key 
	if(GetKeyState(VK_RIGHT) & 0x80 || GetKeyState('D') & 0x80) {			 
 
		// Strafe the camera right 
		StrafeCamera(kSpeed); 
	}	 
} 
 
 
///////////////////////////////// UPDATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
///// 
/////	This updates the camera's view and strafe vector 
///// 
///////////////////////////////// UPDATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
extern char g_strText[10][255]; 
void CCamera::Update()  
{ 
	// Below we calculate the strafe vector every time we update 
	// the camera.  This is because many functions use it so we might 
	// as well calculate it only once.   
//	char buf[128]; 
	wsprintf(g_strText[1],"Position:%d %d %d LookAt:%d %d %d",int(m_vPosition.x),int(m_vPosition.y),int(m_vPosition.z),int(m_vView.x),int(m_vView.y),int(m_vView.z)); 
//	if(m_pText) 
//		m_pText->EditItem(m_nTextID,0.0f,1.0f,0.0f,buf); 
	 
	// Initialize a variable for the cross product result 
	CVector3 vCross = CrossProduct(m_vView - m_vPosition, m_vUpVector); 
 
	// Normalize the strafe vector 
	m_vStrafe = Normalize(vCross); 
 
	// Move the camera's view by the mouse 
	SetViewByMouse(); 
 
	// This checks to see if the keyboard was pressed 
	CheckForMovement(); 
} 
 
 
///////////////////////////////// LOOK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
///// 
/////	This updates the camera according to the  
///// 
///////////////////////////////// LOOK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* 
 
void CCamera::Look() 
{ 
	// Give openGL our camera position, then camera view, then camera up vector 
	gluLookAt(m_vPosition.x, m_vPosition.y, m_vPosition.z,	 
			  m_vView.x,	 m_vView.y,     m_vView.z,	 
			  m_vUpVector.x, m_vUpVector.y, m_vUpVector.z); 
} 
 
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * 
 
 
///////////////////////////////////////////////////////////////////////////////// 
// 
// * QUICK NOTES *  
// 
// This file should now be close to complete.  Now that we have all the basic camera  
// functionality you can use this file in your projects and not have to cut and paste code. 
// I created a camera.h for this purpose as well. 
// 
// We added strafing to this file.  3 other functions were added to our camera class 
// so that it would clean up main.cpp a bit more.  In Camera.h you will find some 
// new changes as well, which include the move of our camera data to private.  We now 
// will use data access functions to get camera data. 
// 
// Here are the notes from main.cpp about the concept and application: 
// 
// This tutorial was taken from the Camera4 tutorial.  This is our last camera tutorial. 
// We might create a bezier curve camera tutorial though in the future.  This tutorial 
// shows how to strafe the camera right or left.  This might seem easy when you think to 
// attempt it, but if you don't know your linear algebra it can be tricky.  Strafing the 
// camera is moving the camera 90 degrees left or right from the current view.  In other 
// words, it's as if you were side stepping while you look forward.  This is used in most 
// first person shooters games, and comes in handy when peering around corners or running 
// past a hallway while firing off some rounds.  It's also a great way to move diagonal 
// while doing a shootout at close ranges to avoid being hit. 
// 
// Since we understand what strafing is and what it does, let me actually explain how it works. 
// We know that we want to walk in the direction that is 90 degrees from the view vVector (with 
// the view vVector being m_vView - m_vPosition).  So how do we then get the vVector that is 90 
// degrees from our view vVector?  If you know what the cross product is, you can easily see how 
// this would be done.  The cross product is a mathematical formula that takes 2 vectors and 
// returns the vVector 90 degrees from those 2 vectors.  This is how you find the normal to a plane. 
// Well, we have a view vVector, but what would the other vVector be?  Does the up vVector come to mind? 
// That's it!  We want to take the cross product between the up vVector and the view vVector.  This 
// will return the vVector (or direction) that we want to strafe in.  In games like Descent, the 
// up vVector will change because you can go upside down and spin in crazy directions.  The cross 
// product will ensure that we will always strafe correctly no matter what orientation the camera is in. 
// Once we have the strafe vVector, we need to add it to the position and view points. 
// Here are the controls for this tutorial: 
// 
// w, s, UP_ARROW, DOWN_ARROW - Move the camera forward and backward 
// a, d, RIGHT_ARROW, LEFT_ARROW - Strafe the camera left and right 
// Mouse movement - Moves the view for first person mode 
// ESCAPE - Quits the program 
// 
// You may notice that we don't use all the methods in the camera class.  I decided to leave 
// them in there because since this is the last camera tutorial it would be nice to just use 
// this in your projects without having to cut and paste code.  That's also why I finally 
// added a camera.h so you don't have the camera class in main.h. 
//  
// Enjoy! 
//  
// 
// Ben Humphrey (DigiBen) 
// Game Programmer 
// DigiBen@GameTutorials.com 
// Co-Web Host of www.GameTutorials.com 
// 
//