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 | \*----------------------------*/