//-----------------------------------------------------------------------------
// Name: ogl_fps_controls.cpp
// Author: Kevin Harris (kevin@codesampler.com)
// Last Modified: 02/01/05
// Description: This sample demonstrates how to collect user input and
// build a custom view matrix for First Person Shooter style
// controls.
//
// Control Keys: Up - View moves forward
// Down - View moves backward
// Left - View strafes left
// Right - View strafes Right
// Left Mouse - Perform looking
// Mouse - Look about the scene
// Home - View moves up
// End - View moves down
//-----------------------------------------------------------------------------
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "resource.h"
#include "geometry.h"
#include "matrix4x4f.h"
#include "vector3f.h"
//-----------------------------------------------------------------------------
// GLOBALS
//-----------------------------------------------------------------------------
HWND g_hWnd = NULL;
HDC g_hDC = NULL;
HGLRC g_hRC = NULL;
POINT g_ptLastMousePosit;
POINT g_ptCurrentMousePosit;
bool g_bMousing = false;
float g_fMoveSpeed = 25.0f;
float g_fElapsedTime;
double g_dCurTime;
double g_dLastTime;
vector3f g_vEye(5.0f, 5.0f, 5.0f); // Eye Position
vector3f g_vLook(-0.5f, -0.5f, -0.5f); // Look Vector
vector3f g_vUp(0.0f, 1.0f, 0.0f); // Up Vector
vector3f g_vRight(1.0f, 0.0f, 0.0f); // Right Vector
struct Vertex
{
// GL_C4UB_V3F
unsigned char r, g, b, a;
float x, y, z;
};
Vertex g_lineVertices[] =
{
{ 255, 0, 0, 255, 0.0f, 0.0f, 0.0f }, // X轴红色
{ 255, 0, 0, 255, 5.0f, 0.0f, 0.0f },
{ 0, 255, 0, 255, 0.0f, 0.0f, 0.0f }, // Y轴绿色
{ 0, 255, 0, 255, 0.0f, 5.0f, 0.0f },
{ 0, 0, 255, 255, 0.0f, 0.0f, 0.0f }, // Z轴蓝色
{ 0, 0, 255, 255, 0.0f, 0.0f, 5.0f }
};
//-----------------------------------------------------------------------------
// PROTOTYPES
//-----------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow);
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void init(void);
void render(void);
void shutDown(void);
void getRealTimeUserInput(void);
void updateViewMatrix(void);
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
WNDCLASSEX winClass;
MSG uMsg;
memset(&uMsg,0,sizeof(uMsg));
winClass.lpszClassName = "MY_WINDOWS_CLASS";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
winClass.lpfnWndProc = WindowProc;
winClass.hInstance = hInstance;
winClass.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_OPENGL_ICON);
winClass.hIconSm = LoadIcon(hInstance, (LPCTSTR)IDI_OPENGL_ICON);
winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
if( !RegisterClassEx(&winClass) )
return E_FAIL;
g_hWnd = CreateWindowEx( NULL, "MY_WINDOWS_CLASS",
"OpenGL - First Person Shooter Controls",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, 640, 480, NULL, NULL, hInstance, NULL );
if( g_hWnd == NULL )
return E_FAIL;
ShowWindow( g_hWnd, nCmdShow );
UpdateWindow( g_hWnd );
init();
while( uMsg.message != WM_QUIT )
{
if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &uMsg );
DispatchMessage( &uMsg );
}
else
{
g_dCurTime = timeGetTime();
g_fElapsedTime = (float)((g_dCurTime - g_dLastTime) * 0.001);
g_dLastTime = g_dCurTime;
render();
}
}
shutDown();
UnregisterClass( "MY_WINDOWS_CLASS", winClass.hInstance );
return uMsg.wParam;
}
//-----------------------------------------------------------------------------
// Name: WindowProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc( HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam )
{
switch( msg )
{
case WM_KEYDOWN:
{
switch( wParam )
{
case VK_ESCAPE:
PostQuitMessage(0);
break;
}
}
break;
case WM_LBUTTONDOWN:
{
g_bMousing = true;
}
break;
case WM_LBUTTONUP:
{
g_bMousing = false;
}
break;
case WM_SIZE:
{
int nWidth = LOWORD(lParam);
int nHeight = HIWORD(lParam);
glViewport(0, 0, nWidth, nHeight);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0, (GLdouble)nWidth / (GLdouble)nHeight, 0.1, 100.0);
}
break;
case WM_CLOSE:
{
PostQuitMessage(0);
}
case WM_DESTROY:
{
PostQuitMessage(0);
}
break;
default:
{
return DefWindowProc( hWnd, msg, wParam, lParam );
}
break;
}
return 0;
}
//-----------------------------------------------------------------------------
// Name: getRealTimeUserInput()
// Desc:
//-----------------------------------------------------------------------------
void getRealTimeUserInput( void )
{
//
// Get mouse input...
//
POINT mousePosit;
GetCursorPos( &mousePosit );
ScreenToClient( g_hWnd, &mousePosit );
g_ptCurrentMousePosit.x = mousePosit.x;
g_ptCurrentMousePosit.y = mousePosit.y;
matrix4x4f matRotation;
if( g_bMousing )
{
int nXDiff = (g_ptCurrentMousePosit.x - g_ptLastMousePosit.x);
int nYDiff = (g_ptCurrentMousePosit.y - g_ptLastMousePosit.y);
if( nYDiff != 0 )
{
matRotation.rotate( -(float)nYDiff / 3.0f, g_vRight );
matRotation.transformVector( &g_vLook );
matRotation.transformVector( &g_vUp );
}
if( nXDiff != 0 )
{
matRotation.rotate( -(float)nXDiff / 3.0f, vector3f(0.0f, 1.0f, 0.0f) );
matRotation.transformVector( &g_vLook );
matRotation.transformVector( &g_vUp );
}
}
g_ptLastMousePosit.x = g_ptCurrentMousePosit.x;
g_ptLastMousePosit.y = g_ptCurrentMousePosit.y;
//
// Get keyboard input...
//
unsigned char keys[256];
GetKeyboardState( keys );
vector3f tmpLook = g_vLook;
vector3f tmpRight = g_vRight;
// Up Arrow Key - View moves forward
if( keys[VK_UP] & 0x80 )
g_vEye -= tmpLook*-g_fMoveSpeed*g_fElapsedTime;
// Down Arrow Key - View moves backward
if( keys[VK_DOWN] & 0x80 )
g_vEye += (tmpLook*-g_fMoveSpeed)*g_fElapsedTime;
// Left Arrow Key - View side-steps or strafes to the left
if( keys[VK_LEFT] & 0x80 )
g_vEye -= (tmpRight*g_fMoveSpeed)*g_fElapsedTime;
// Right Arrow Key - View side-steps or strafes to the right
if( keys[VK_RIGHT] & 0x80 )
g_vEye += (tmpRight*g_fMoveSpeed)*g_fElapsedTime;
// Home Key - View elevates up
if( keys[VK_HOME] & 0x80 )
g_vEye.y += g_fMoveSpeed*g_fElapsedTime;
// End Key - View elevates down
if( keys[VK_END] & 0x80 )
g_vEye.y -= g_fMoveSpeed*g_fElapsedTime;
}
//-----------------------------------------------------------------------------
// Name: init()
// Desc:
//-----------------------------------------------------------------------------
void init( void )
{
GLuint PixelFormat;
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW |PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 16;
pfd.cDepthBits = 16;
g_hDC = GetDC( g_hWnd );
PixelFormat = ChoosePixelFormat( g_hDC, &pfd );
SetPixelFormat( g_hDC, PixelFormat, &pfd);
g_hRC = wglCreateContext( g_hDC );
wglMakeCurrent( g_hDC, g_hRC );
glClearColor( 0.35f, 0.53f, 0.7f, 1.0f );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0f, 640.0f / 480.0f, 0.1f, 100.0f);
}
//-----------------------------------------------------------------------------
// Name: shutDown()
// Desc:
//-----------------------------------------------------------------------------
void shutDown( void )
{
if( g_hRC != NULL )
{
wglMakeCurrent( NULL, NULL );
wglDeleteContext( g_hRC );
g_hRC = NULL;
}
if( g_hDC != NULL )
{
ReleaseDC( g_hWnd, g_hDC );
g_hDC = NULL;
}
}
//-----------------------------------------------------------------------------
// Name : updateViewMatrix()
// Desc : Builds a view matrix suitable for OpenGL.
//
// Here's what the final view matrix should look like:
//
// | rx ry rz -(r.e) |
// | ux uy uz -(u.e) |
// | -lx -ly -lz (l.e) |
// | 0 0 0 1 |
//
// Where r = Right vector
// u = Up vector
// l = Look vector
// e = Eye position in world space
// . = Dot-product operation
//
//-----------------------------------------------------------------------------
void updateViewMatrix( void )
{
matrix4x4f view;
view.identity();
g_vLook.normalize();
g_vRight = crossProduct(g_vLook, g_vUp);
g_vRight.normalize();
g_vUp = crossProduct(g_vRight, g_vLook);
g_vUp.normalize();
view.m[0] = g_vRight.x;
view.m[1] = g_vUp.x;
view.m[2] = -g_vLook.x;
view.m[3] = 0.0f;
view.m[4] = g_vRight.y;
view.m[5] = g_vUp.y;
view.m[6] = -g_vLook.y;
view.m[7] = 0.0f;
view.m[8] = g_vRight.z;
view.m[9] = g_vUp.z;
view.m[10] = -g_vLook.z;
view.m[11] = 0.0f;
view.m[12] = -dotProduct(g_vRight, g_vEye);
view.m[13] = -dotProduct(g_vUp, g_vEye);
view.m[14] = dotProduct(g_vLook, g_vEye);
view.m[15] = 1.0f;
glMultMatrixf( view.m );
}
//-----------------------------------------------------------------------------
// Name: render()
// Desc:
//-----------------------------------------------------------------------------
void render( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
getRealTimeUserInput();
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
updateViewMatrix();
glColor3f( 1.0f, 1.0f, 1.0f );
renderWireTeapot( 2.0f );
glInterleavedArrays( GL_C4UB_V3F, 0, g_lineVertices );
glDrawArrays( GL_LINES, 0, 6 );
SwapBuffers( g_hDC );
}