www.pudn.com > Fog_D3D.zip > win_main.cpp


// Done by TheTutor -- 1/19/04 
 
/*	 
	Fog is typically used for two reasons in a app.  The first is pretty obvious, the look of  
	the scene calls for fog %)  The second reason is that by using fog an application can speed 
	up it's rendering time by fogging out geometry, thus not considering it for rendering. 
	 
	Within, we are going to take a beginners peek at fog in a D3D 9.0 application.  First, lets 
	break down the parameters that control fog: 
	 
		Color -- The color of the fog 
		Type -- Either pixel or vertex 
		Start/Stop -- For fog with a linear falloff, this specifies the beginning of the fog 
					  and the end of the fog 
		Density -- For fog with an exponential falloff, this specifies how thick the fog is 
		Falloff -- Either linear, exponential, or exponential squared 
		Range -- Either using the distance from the camera to the object or the object's z-value 
				 when figuring out the fog calculations 
				  
	What we are going to do is write some wrapper functions that allow us to set all of these 
	parameters except for range.  This is because distance based fog calculations are not supported 
	on any current cards for pixel fog and in general they are more expensive than z-value based 
	fog calculations. 
	 
	**NOTE** It is important when doing fog to remember not all forms of fog are supported on 
			 every video card.  Be sure to check for failed fog function calls.  
	 
	Lets get to the code...	 
*/ 
 
#include  
#include  
#include  
#include "d3d_obj.h" 
#include "vector.h" 
 
#pragma comment(lib, "d3d9.lib") 
#pragma comment(lib, "d3dx9.lib") 
 
#define class_name "GT_D3DFog" 
 
// Width and height of the window (specifically the client rect) 
const int kWinWid = 640; 
const int kWinHgt = 480; 
 
const int kFogColor = ARGB(255, 100, 100, 200); // Light blue color of fog 
const int kMaxVerts = 512; // Maximum number of vertices in our vertex pool 
 
// Globals 
SVertex gVertPool[kMaxVerts] = {0}; // A giant array of vertices we can use for whatever we want 
 
bool LockFrameRate(int frame_rate = 60); // Locks the frame rate 
void CenterCursor(HWND hwnd); // Centers the cursor in the window 
void DrawCube(const CPos &cen, float size, int color); // Draws a cube centered at world pos "cen" 
 
// WinProc 
LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); 
 
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow) 
{ 
    HWND hwnd; 
	MSG msg; 
    WNDCLASSEX wndclassex = {0}; 
 
	// Init fields we care about 
	wndclassex.cbSize = sizeof(WNDCLASSEX); // Always set to size of WNDCLASSEX 
    wndclassex.style = CS_HREDRAW | CS_VREDRAW; 
    wndclassex.lpfnWndProc = WinProc; 
    wndclassex.hInstance = hinstance; 
    wndclassex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 
	wndclassex.lpszClassName = class_name; 
	wndclassex.hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW), 
											IMAGE_CURSOR, 0, 0, LR_SHARED); 
 
    RegisterClassEx(&wndclassex); 
 
	RECT rect = { 0, 0, kWinWid, kWinHgt }; // Desired window client rect 
	 
	DWORD winStyleEx = WS_EX_APPWINDOW; 
	DWORD winStyle = WS_CAPTION | WS_SYSMENU; // Window style 
 
	// Adjust window rect so it gives us our desired client rect when we  
	// create the window 
	AdjustWindowRectEx(&rect, winStyle, false, winStyleEx); 
 
    hwnd = CreateWindowEx(winStyleEx, // Window extended style 
					      class_name, 
						  "www.GameTutorials.com -- D3D Camera", 
						  winStyle, // Window style 
						  CW_USEDEFAULT, 
						  CW_USEDEFAULT, 
						  rect.right - rect.left, 
						  rect.bottom - rect.top, 
						  NULL, 
						  NULL, 
						  hinstance, 
						  NULL); 
 
	// Init our global 3D object 
	if(g3D->init(hwnd) == false) 
		return EXIT_FAILURE; // There's been an error, lets get out of this joint 
 
	// Get the client rect and make sure our client is the size we want 
	GetClientRect(hwnd, &rect); 
	assert(rect.right == kWinWid && rect.bottom == kWinHgt); 
 
	// We set up our projection matrix once because it will never change 
	g3D->setProjMatrix(); 
	 
	// If we can't set the fog parameters, exit the app  
	if(!g3D->setFogStatus(true) || !g3D->setFogColor(kFogColor) ||  
	   !g3D->setPixelFogMode(D3DFOG_LINEAR) || !g3D->setFogStart(1.0f) || 
	   !g3D->setFogEnd(10.0f)) 
		return EXIT_FAILURE; 
		 
	ShowCursor(FALSE); // Hide cursor 
	ShowWindow(hwnd, ishow); 
	UpdateWindow(hwnd); 
	 
    while(1) 
	{ 
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) 
		{ 
			if(msg.message == WM_QUIT) 
				break; 
			 
			TranslateMessage(&msg); 
			DispatchMessage(&msg); 
		} 
		else if(LockFrameRate()) 
		{ 
			static float angle = 0; // Angle of rotation 
			D3DXMATRIX wMat; // World matrix  
			 
			// Using our camera will set up the view of our 3D world 
			g3D->setViewMatrix(gCamera); 
			 
			g3D->begin(); // Begin drawing 
			g3D->clear(kFogColor); // Clear the screen to the fog color 
			 
			// Rotate around the Y-axis			 
			g3D->setWorldMatrix(0, D3DXMatrixRotationY(&wMat, DEG2RAD(++angle))); 
			 
			// Draw 4 cubes 
			DrawCube(CPos(2,0,0), 0.5f, ARGB(255, 255, 0, 0)); 
			DrawCube(CPos(-2,0,0), 0.5f, ARGB(255, 255, 0, 0)); 
			DrawCube(CPos(0,0,2), 0.5f, ARGB(255, 255, 0, 0)); 
			DrawCube(CPos(0,0,-2), 0.5f, ARGB(255, 255, 0, 0)); 
			 
			g3D->end(); // Finish drawing 
			 
			// Always center the cursor 
			CenterCursor(hwnd); 
		} 
	 
	} // end of while(1) 
 
	ShowCursor(TRUE); // Reshow cursor 
	UnregisterClass(class_name,hinstance); // Free up WNDCLASSEX 
	    return EXIT_SUCCESS; // Application was a success 
} 
 
// WinProc 
LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) 
{ 
	switch(message) 
    { 
		case WM_CREATE:	 
			CenterCursor(hwnd); // Make sure we start with the mouse centered 
				return 0; 
     
		case WM_KEYDOWN: // If we get a key down message, do stuff 
 
			switch(wparam) 
			{ 
				case VK_ESCAPE: 
					SendMessage(hwnd, WM_CLOSE, 0, 0); // Close window if user hits ESC 
						break; 
 
				case VK_UP: // If they push up, move forward (Camera's +Z) 
					gCamera->move(CCamera::eForward); 
						break; 
 
				case VK_DOWN: // If they push down, move backward (Camera's -Z) 
					gCamera->move(CCamera::eBack); 
						break; 
 
				case VK_RIGHT: // If they push right, move right (Camera's +X) 
					gCamera->move(CCamera::eRight); 
						break; 
 
				case VK_LEFT: // If they push left, move left (Camera's -X) 
					gCamera->move(CCamera::eLeft); 
						break; 
						 
				case 'R': 
					gCamera->reset(); // Recenter the camera 
						break; 
			} 
			 
			return 0; 
			 
		// If they move the mouse 
		case WM_MOUSEMOVE: 
		{ 
			static float pitchAmt = 0.0f; // Amount camera has pitched up/down in degrees 
			const float kDegInc = 1.25f; // Amount to rotate in degrees 
			const int kCushion = 20; // "Cushion" amount from the center 
									// of the window the user must move the mouse 
								   // before we rotate their view  
		 
			// First we will get the (x,y) of the mouse 
			int xPos = LOWORD(lparam); 
			int yPos = HIWORD(lparam); 
 
			if(xPos < (kWinWid / 2 - kCushion)) // If they move the mouse left 
				gCamera->rotateY(DEG2RAD(-kDegInc));  
			else if(xPos > (kWinWid / 2 + kCushion)) // If they move the mouse right 
				gCamera->rotateY(DEG2RAD(kDegInc)); 
 
			if(yPos < (kWinHgt / 2 - kCushion)) // If they move the mouse up 
			{ 
				// If they haven't pitched up 88°, go ahead and pitch them up 
				if(pitchAmt < 88) 
				{ 
					gCamera->pitch(DEG2RAD(kDegInc)); 
					pitchAmt += kDegInc; 
				} 
			} 
			else if(yPos > (kWinHgt / 2 + kCushion)) // If they move the mouse down 
			{ 
				// If they haven't pitched down 88°, go ahead and pitch them down 
				if(pitchAmt > -88) 
				{ 
					gCamera->pitch(DEG2RAD(-kDegInc)); 
					pitchAmt -= kDegInc; 
				} 
			} 
		     
		    return 0; 
		}	 
 
		case WM_DESTROY: 
			PostQuitMessage(0); 
				return 0; 
    } 
 
    return DefWindowProc(hwnd, message, wparam, lparam); 
} 
 
// Locks the frame rate at "frame_rate" 
// Returns true when it's okay to draw, false otherwise 
bool LockFrameRate(int frame_rate) 
{ 
	static float lastTime = 0.0f; 
	 
	// Get current time in seconds (milliseconds * .001 = seconds) 
	float currentTime = GetTickCount() * 0.001f;  
 
	// Get the elapsed time by subtracting the current time from the last time 
	// If the desired frame rate amount of seconds has passed -- return true (ie Blit()) 
	if((currentTime - lastTime) > (1.0f / frame_rate)) 
	{ 
		// Reset the last time 
		lastTime = currentTime;	 
			return true; 
	} 
 
	return false; 
} 
 
// Centers the mouse in the window 
void CenterCursor(HWND hwnd) 
{ 
	// This is the center of the client area of our window 
	POINT pt = { kWinWid / 2, kWinHgt / 2 }; 
	 
	// Get these coordinates in screen coordinates (the coordinate system the entire monitor uses) 
	ClientToScreen(hwnd, &pt); 
	SetCursorPos(pt.x, pt.y); // Set our cursor to the middle of our window 
} 
 
// Draws a red/blue cube to the screen, centered at "cen" with "size" dimensions 
void DrawCube(const CPos &cen, float size, int color) 
{ 
	// This handy dandy little algorithm will construct the 
	// 8 verts we need for a cube. 
	for(int i = 0; i < 8; ++i) 
	{ 
		gVertPool[i].color = color; 
		 
		gVertPool[i].x = (i & 1) ? (cen.x - size) : (cen.x + size); 
		gVertPool[i].y = (i & 2) ? (cen.y - size) : (cen.y + size); 
		gVertPool[i].z = (i & 4) ? (cen.z + size) : (cen.z - size);	 
	} 
	 
	// Indexes for our cube 
	WORD indexList[36] = { 0, 2, 3, 
						   3, 1, 0, 
						   7, 6, 4, 
						   4, 5, 7, 
						   4, 6, 2,  
						   2, 0, 4, 
						   1, 3, 7, 
						   7, 5, 1, 
						   4, 0, 1, 
						   1, 5, 4, 
						   2, 6, 7, 
						   7, 3, 2 }; 
	 
	g3D->render(gVertPool, 8, indexList, 36); // Draw the cube 
} 
 
// This still foggy? 
 
/* 
	Adding fog to an application is not too difficult.  However, be aware that not all cards 
	support all fog modes so if something isn't working, check the hardware capabilites (you can use 
	IDirect3DDevice9::GetDeviceCaps() for this) first. 
	 
	If this is still foggy be sure to ask the forums found at:  www.GameTutorials.com	 
*/ 
 
/*----------------------------*\ 
|  TheTutor                    | 
|  thetutor@gametutorials.com  | 
|  © 2000-2004 GameTutorials   | 
\*----------------------------*/