/*=========================================================================== * * D3DApp.CPP - Dave Humphrey (uesp@m0use.net), 30 October 2000 * *=========================================================================*/ /* Include Files */ #include "d3dapp.h" #undef __FUNC__ #define __FUNC__ "CD3DApp::CD3DApp()" /*=========================================================================== * * Class CD3DApp Constructor * *=========================================================================*/ CD3DApp::CD3DApp() { QuitMain = FALSE; Initialized = FALSE; Minimized = FALSE; ResizingDisabled = FALSE; Dithering = FALSE; DisplayFrameRate = TRUE; InSurfaceMode = FALSE; AntiAlias = TRUE; Activated = TRUE; AllowMovement = TRUE; AllowSelectObject = TRUE; CallBackOnSelectObject = TRUE; HasSelectedObject = FALSE; FollowSurface = TRUE; BitsPerPixel = 0; CameraHeight = D3DVAL(50.0); RenderQuality = D3DRMLIGHT_ON | D3DRMFILL_SOLID | D3DRMSHADE_GOURAUD; TextureQuality = D3DRMTEXTURE_NEAREST; MovementSpeed = D3DVAL(5.0); RotationSpeed = D3DVAL(3.0); FrameRate = D3DVAL(0.0); ViewBackLength = D3DVAL(50000.0); pAcceleratorName = NULL; pIconName = NULL; pWindowCaption = NULL; pMenuName = NULL; pClassName = NULL; pCurrentSurfaceMode = NULL; /* Initialize handles to NULL */ hMainWindow = NULL; hInstance = NULL; hAccelerator = NULL; /* Initialize the counter variables */ UsePerformanceCounter = QueryPerformanceFrequency(&PerformanceFreq); LastRenderTick = 0; LastRenderCounter.QuadPart = 0; /* Callback functions */ pWindowProc = NULL; pOnSelectObjectCallBack = NULL; pBuildScene = NULL; /* Direct3D objects */ pSelectedFace = NULL; pSelectedVisual = NULL; pDirect3D = NULL; pDDClipper = NULL; pDevice = NULL; pView = NULL; pScene = NULL; pCamera = NULL; /* Exclusive mode specific variables */ #if D3D_EXCLUSIVE_MODE pPrimarySurface = NULL; pDirectDraw = NULL; pBackSurface = NULL; pDirectDraw1 = NULL; #endif } /*=========================================================================== * End of Class CD3DApp Constructor *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::Destroy()" /*=========================================================================== * * Class CD3DApp Destructor * *=========================================================================*/ void CD3DApp::Destroy() { /* Unallocate memory */ DestroyPointer(pAcceleratorName); DestroyPointer(pIconName); DestroyPointer(pMenuName); DestroyPointer(pClassName); DestroyPointer(pWindowCaption); /* Release D3D objects as required */ RELEASE(pSelectedFace); RELEASE(pSelectedVisual); RELEASE(pScene); RELEASE(pCamera); RELEASE(pView); RELEASE(pDevice); RELEASE(pDirect3D); RELEASE(pDDClipper); /* Exclusive mode specific variables */ #if D3D_EXCLUSIVE_MODE RELEASE(pBackSurface); RELEASE(pDDSurface); RELEASE(pDirectDraw); #endif /* Reset the global Direct3D object */ SetD3DRM(NULL); QuitMain = TRUE; Initialized = FALSE; Minimized = FALSE; HasSelectedObject = FALSE; InSurfaceMode = FALSE; LastRenderTick = 0; LastRenderCounter.QuadPart = 0; FrameRate = D3DVAL(0.0); pWindowProc = NULL; pBuildScene = NULL; pCurrentSurfaceMode = NULL; hMainWindow = NULL; hInstance = NULL; /* Accelerator tables loaded with LoadAccelerators() are freed * auotmatically when the program terminates. */ hAccelerator = NULL; } /*=========================================================================== * End of Class CD3DApp Destructor *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::CreateCameraFrame()" /*=========================================================================== * * Class CD3DApp Method - boolean CreateCamereaFrame (void); * * Creates the camera frame which will be the viewport of the user into the * 3D world. Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::CreateCameraFrame (void) { HRESULT Result; /* Assert valid objects */ ASSERT(pDirect3D != NULL); /* Need a valid Direct3D and scene objects */ ASSERT(pScene != NULL); ASSERT(pCamera == NULL); /* Don't want to recreate a valid camera */ /* Create the camera frame */ Result = pDirect3D->CreateFrame(pScene, &pCamera); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to create the camera frame!"); return (FALSE); } /* Set the initial position the camera in the frame */ Result = pCamera->SetPosition(pScene, D3DVAL(0.0), D3DVAL(2.0), D3DVAL(0.0)); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to position the camera in the scene!"); return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::CreateCameraFrame() *=========================================================================*/ /* Exclusive mode specific mode */ #if D3D_EXCLUSIVE_MODE #undef __FUNC__ #define __FUNC__ "CD3DApp::CreateD3DExclusiveMode()" /*=========================================================================== * * Class CD3DApp Method - boolean CreateD3DExclusiveMode (void); * * Creates and initializes exclusive mode. Only valid if the macro * D3D_EXCLUSIVE_MODE is defined as TRUE. Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::CreateD3DExclusiveMode (void) { HRESULT Result; /* Assert valid objects */ ASSERT(pDirectDraw == NULL); /* Don't recreate over a valid object */ ASSERT(hMainWindow != NULL); /* Need a window handle for the application */ /* Create the DirectDraw object */ Result = CreateDirectDrawObject(&pDirectDraw); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to create the DirectDraw object!"); return (FALSE); } /* Set the DirectDraw coorperation to exclusive and fullscreen */ Result = pDirectDraw->SetCooperativeLevel(hMainWindow, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to initialize the DirectDraw object!"); return (FALSE); } /* Change to the desired display mode */ /* TODO: This should allow for some mode selection including auto-selection */ Result = pDirectDraw->SetDisplayMode(640, 480, 16, 0, 0); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to set the DirectDraw display mode!"); return (FALSE); } /* Create the exclusive mode primary/back surfaces */ return (CreateExModeSurfaces()); } /*=========================================================================== * End of Class Method CD3DApp::CreateD3DExclusiveMode() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::CreateExModeSurfaces()" /*=========================================================================== * * Class CD3DApp Method - boolean CreateExModeSurfaces (void); * * Creates and initializes primary and back buffer surfaces required for * page flipping in exclusive mode. Only valid if the macro * D3D_EXCLUSIVE_MODE is defined as TRUE. Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::CreateExModeSurfaces (void) { HRESULT Result; ddscaps_t ddSurfaceCaps; ddsdesc_t ddSurfaceDesc; /* Assert valid objects */ ASSERT(pDirectDraw != NULL); /* Need a valid DirectDraw object */ ASSERT(pPrimarySurcace == NULL); /* Don't recreate over valid objects */ ASSERT(pBackSurface == NULL); /* Setup the primary surface description */ memset(&ddSurfaceDesc, 0, sizeof(ddSurfaceDesc)); ddSurfaceDesc.dwSize = sizeof(ddSurfaceDesc); ddSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; ddSurfaceDesc.dwWidth = 640; ddSurfaceDesc.dwHeight = 480; ddSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddSurfaceDesc.dwBackBufferCount = 1; Result = pDirectDraw->CreateSurface(&ddSurfaceDesc, &pPrimarySurface, NULL); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to create the DirectDraw primary surface!"); return (FALSE); } /* Get the back buffer surface for later use */ ddSurfaceCaps.dwCaps = DDSCAPS_BACKBUFFER; Result = pPrimarySurface->GetAttachedSurface(&ddSurfaceCaps, &pBackSurface); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to get the back buffer surface!"); return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::CreateExModeSurfaces() *=========================================================================*/ #endif /* End of if D3D_EXCLUSIVE_MODE */ #undef __FUNC__ #define __FUNC__ "CD3DApp::CreateDevice()" /*=========================================================================== * * Class CD3DApp Method - boolean CreateDevice (void); * * Creates the Direct3D device from the current Direct3D object and the * given width/height of the window (if not in exclusive mode). Returns * FALSE on any error. * *=========================================================================*/ boolean CD3DApp::CreateDevice (void) { /* Assert valid objects */ ASSERT(hMainWindow != NULL); /* Create the D3DRM device depending on whether exclusive mode is used */ #if D3D_EXCLUSIVE_MODE return (CreateDevice(0, 0)); #else RECT WindowRect; boolean Result; /* Get the size of the application window */ Result = GetClientRect(hMainWindow, &WindowRect); if (!Result) { SET_WIN_ERROR2("Failed to retrieve the size of the window!"); return (FALSE); } return (CreateDevice(WindowRect.right, WindowRect.bottom)); #endif } /*=========================================================================== * End of Class Method CD3DApp::CreateDevice() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::CreateDevice()" /*=========================================================================== * * Class CD3DApp Method - boolean CreateDevice (Width, Height); * * Creates the Direct3D device from the current Direct3D object and the * given width/height (if not in exclusive mode). Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::CreateDevice (const int Width, const int Height) { HRESULT Result; /* Assert valid objects */ ASSERT(pDirect3D != NULL); /* Need a valid Direct3D object */ ASSERT(pDevice == NULL); /* Don't want to recreate a valid object */ /* Create the D3DRM device from this window and using the 'best' driver * depending on whether exclusive mode is requested. */ #if D3D_EXCLUSIVE_MODE Result = pDirect3D->CreateDeviceFromSurface(NULL, pDirectDraw, pBackSurface, &pDevice); #else /* Ensure a valid window size */ if (Width == 0 || Height == 0) { SET_D3D_ERROR2(D3DRMERR_BADVALUE, "Received an invalid 0 width or height!"); return (FALSE); } /* Create the device from the current clipper object */ Result = pDirect3D->CreateDeviceFromClipper(pDDClipper, NULL, Width, Height, &pDevice); #endif /* Ensure the creation of the device was successfull */ if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to find a valid Direct3D device!"); return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::CreateDevice() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::CreateDDClipper()" /*=========================================================================== * * Class CD3DApp Method - boolean CreateDDClipper (void); * * Creates the DirectDraw clipper object and attaches it to the main window. * Only valid if not in exclusive mode. Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::CreateDDClipper (void) { HRESULT Result; /* Assert valid objects */ ASSERT(pDirect3D != NULL); /* Need a valid Direct3D object */ ASSERT(pDDClipper == NULL); /* Don't want to recreate a valid object */ /* Create the clipper object */ Result = DirectDrawCreateClipper(0, &pDDClipper, NULL); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to create the DirectDraw clipper!"); return (FALSE); } /* Associate the clipper to the main window */ Result = pDDClipper->SetHWnd(0, hMainWindow); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to associate the main window with the DirectDraw clipper!"); return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::CreateDDClipper() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::CreateMainWindow()" /*=========================================================================== * * Class CD3DApp Method - boolean CreateMainWindow (void); * * Creates the application window and returns TRUE on success. Does not * update or show the window. * *=========================================================================*/ boolean CD3DApp::CreateMainWindow (void) { WNDCLASS WindowClass; DWORD Flags; /* Check object states */ ASSERT(hMainWindow == NULL); ASSERT(hInstance != NULL); /* Setup the window class structure */ WindowClass.style = CS_HREDRAW | CS_VREDRAW; WindowClass.lpfnWndProc = pWindowProc; WindowClass.cbClsExtra = 0; WindowClass.cbWndExtra = sizeof(DWORD); WindowClass.hInstance = hInstance; WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW); WindowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); WindowClass.lpszMenuName = pMenuName; WindowClass.lpszClassName = pClassName; /* Set the window icon resource, if any */ if (pIconName == NULL) WindowClass.hIcon = NULL; else WindowClass.hIcon = LoadIcon(hInstance, pIconName); /* Attempt to register the class */ if (!RegisterClass(&WindowClass)) { SET_WIN_ERROR2("Failed to register the window class!"); return (FALSE); } /* Set the window flags based on resizing options */ if (ResizingDisabled) Flags = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; else Flags = WS_OVERLAPPEDWINDOW; /* Attempt to create the window */ hMainWindow = CreateWindow (pClassName, pWindowCaption, Flags, CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, NULL, NULL, hInstance, NULL); /* Ensure the window was successfully created */ if (hMainWindow == NULL) { SET_WIN_ERROR2("Failed to create the window!"); return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::CreateMainWindow() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::CreateSceneFrame()" /*=========================================================================== * * Class CD3DApp Method - boolean CreateSceneFrame (void); * * Creates the scene frame which will be the root frame for future 3D objects. * Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::CreateSceneFrame (void) { HRESULT Result; /* Assert valid objects */ ASSERT(pDirect3D != NULL); /* Need a valid Direct3D object */ ASSERT(pScene == NULL); /* Don't want to recreate a valid scene */ /* Create the master scene frame */ Result = pDirect3D->CreateFrame(NULL, &pScene); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to create the master scene frame!"); return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::CreateSceneFrame() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::CreateView()" /*=========================================================================== * * Class CD3DApp Method - boolean CreateView (void); * * Creates the Direct3D viewpoty from the current device. Returns FALSE on * any error. * *=========================================================================*/ boolean CD3DApp::CreateView (void) { HRESULT Result; /* Assert valid objects */ ASSERT(pDirect3D != NULL); /* Need a valid Direct3D and other objects */ ASSERT(pCamera != NULL); ASSERT(pDevice != NULL); ASSERT(pView == NULL); /* Don't reinitialize the view object */ /* Create the Direct3D viewport using the camera frame and the width * and height of the device */ Result = pDirect3D->CreateViewport(pDevice, pCamera, 0, 0, pDevice->GetWidth(), pDevice->GetHeight(), &pView); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to create a valid Direct3D view!"); Initialized = FALSE; return (FALSE); } /* Set the back render plane of the view */ Result = pView->SetBack(ViewBackLength); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to set the Direct3D back render length!"); return (FALSE); } /* Set the render quality, fill mode, lighting state and color shade info */ Result = SetRenderState(); if (!Result) return (FALSE); /* Return success */ return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::CreateView() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::D3DInitialization()" /*=========================================================================== * * Class CD3DApp Method - boolean D3DInitialization (void); * * Standard intialization function. Performs all the initialization * needed to get the app running. * *=========================================================================*/ boolean CD3DApp::D3DInitialization (void) { boolean Result; /* Check objects for valid states */ ASSERT(pDirect3D == NULL); /* We don't want to re-initialize over valid objects */ /* Create the Direct3D, Scene, and Camera objects */ Result = CreateDirect3DObject(&pDirect3D); if (Result) Result = CreateSceneFrame(); if (Result) Result = CreateCameraFrame(); /* Perform Exclusive mode specific initialization */ #if (D3D_EXCLUSIVE_MODE) if (Result) Result = CreateD3DExclusiveMode(); #else /* Clipper is only required if not in exclusive mode */ if (Result) Result = CreateDDClipper(); #endif /* Create the Direct3D device and view */ if (Result) Result = CreateDevice(); if (Result) Result = CreateView(); return (Result); } /*=========================================================================== * End of Class Method CD3DApp::D3DInitialization() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::D3DWinMain()" /*=========================================================================== * * Class CD3DApp Method - int D3DWinMain (ThisInstance, PrevInstance, * CommandLine, CommandShow); * * A standard windows entry point for D3D applications. Just call from * your own WinMain() to use. Returns non-zero on failure. * *=========================================================================*/ int CD3DApp::D3DWinMain (HINSTANCE ThisInstance, HINSTANCE PrevInstance, LPSTR CommandLine, int CommandShow) { boolean Result; MSG Message; int FailCount = 0; /* Initialize the applicate and create the main window */ Result = Initialize(ThisInstance, CommandShow); /* Ensure the user has been notified of any error */ if (!Result) { if (!ErrorHandler.HaveNotifiedUser()) ErrorHandler.Notify(); return(1); } /* Main application event loop */ while (!QuitMain) { /* Check the message queue until no immediate messages remain */ while (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) { /* Are we quitting? */ if (Message.message == WM_QUIT) { TerminateApp(); break; } /* Check the accelerator table, if any */ if (hAccelerator == NULL) continue; if (!TranslateAccelerator(Message.hwnd, hAccelerator, &Message)) { TranslateMessage(&Message); DispatchMessage(&Message); } } /* End of while peeking messages */ /* Do we need to quit yet? */ if (QuitMain) break; /* Render a scene if the application state is valid */ if (CanRenderScene()) { /* Attempt to render a frame, notifying the user of any errors */ if (!Render()) { FailCount++; if (!ErrorHandler.HaveNotifiedUser()) ErrorHandler.Notify(); } /* Abort if rendering fails more than twice */ if (FailCount > 2) { SET_EXT_ERROR2(ERR_CUSTOM, "Rendering has failed too many times...Aborting execution!"); ErrorHandler.Notify(); TerminateApp(); break; } } /* End of if rendering... */ else WaitMessage(); } /* End of while (!QuitMain)... */ /* Destroy the main window and exit */ DestroyWindow(hMainWindow); return (Message.wParam); } /*=========================================================================== * End of Class Method CD3DApp::D3DWinMain(); *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::DoFollowSurface()" /*=========================================================================== * * Class CD3DApp Method - boolean DoFollowSurface (void); * * Attempt to get the camera to follow the surface. Returns FALSE on any * error. * *=========================================================================*/ boolean CD3DApp::DoFollowSurface (void) { HRESULT Result; D3DVECTOR CameraVector; D3DVECTOR SurfacePoint; /* Ignore if not following the surface currently */ if (!FollowSurface) return (TRUE); /* Ensure valid objects */ ASSERT(pCamera != NULL); ASSERT(pScene != NULL); /* Attempt to retrieve the camera position */ Result = pCamera->GetPosition(pScene, &CameraVector); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to retrieve the camera position!"); return (FALSE); } /* Attempt to find the surface point above/below the camera */ Result = FindSurface(pScene, CameraVector, SurfacePoint); if (!Result) return (FALSE); /* Move the camera up slightly */ CameraVector.y = SurfacePoint.y + (float) CameraHeight; Result = pCamera->SetPosition(pScene, CameraVector.x, CameraVector.y, CameraVector.z); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to set the camera position!"); return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::DoFollowSurface() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::DrawFrameRate()" /*=========================================================================== * * Class CD3DApp Method - boolean DrawFrameRate (void); * * Displays the frame rate in the main window. Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::DrawFrameRate (void) { boolean Result; HDC hDC; char FrameRateBuffer[64]; int BufferSize; int PrevBKMode; /* Ignore if we aren't displaying the frame rate currently */ if (!DisplayFrameRate) return (TRUE); /* Get the device context for the display */ hDC = GetDisplayDC(); if (hDC == NULL) return (FALSE); /* Set the background mode */ PrevBKMode = SetBkMode(hDC, TRANSPARENT); /* Create a frame rate string and output to DC */ BufferSize = sprintf (FrameRateBuffer, "%.1f fps", FrameRate); TextOut(hDC, 10, 30, FrameRateBuffer, BufferSize); SetBkMode(hDC, PrevBKMode); /* Release the display device context */ Result = ReleaseDisplayDC(hDC); return (Result); } /*=========================================================================== * End of Class CD3DApp::DrawFrameRate() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::GetDirectDraw()" /*=========================================================================== * * Class CD3DApp Method - CDirectDraw* GetDirectDraw (void); * * Returns the current DirectDraw object for the application. If the app is * not initialization or not in exclusive mode, NULL will be returned. * *=========================================================================*/ CDirectDraw* CD3DApp::GetDirectDraw (void) { #if (D3D_EXCLUSIVE_MODE) ASSERT(pDirectDraw != NULL); return (pDirectDraw); #else return (NULL); #endif } /*=========================================================================== * End of Class Method CD3DApp::GetDirectDraw() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::GetPrimarySurface()" /*=========================================================================== * * Class CD3DApp Method - CDDSurface* GetPrimarySurface (void); * * Returns the current Primary Surface for the application. If the app is * not initialization or not in exclusive mode, NULL will be returned. * *=========================================================================*/ CDDSurface* CD3DApp::GetPrimarySurface (void) { #if (D3D_EXCLUSIVE_MODE) ASSERT(pPrimarySurface != NULL); return (pPrimarySurface); #else return (NULL); #endif } /*=========================================================================== * End of Class Method CD3DApp::GetPrimarySurface() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::FindSurface()" /*=========================================================================== * * Class CD3DApp Method - boolean FindSurface (pRefFrame, SourcePoint, DestPoint); * * Attempt to find a surface directly above/below the given point in the * main frame. Returns TRUE on success or FALSE on any error. * *=========================================================================*/ boolean CD3DApp::FindSurface (CD3DFrame* pRefFrame, const d3dvector_t& SourcePoint, d3dvector_t& DestPoint) { CD3DPickedArray2* pPickedArray; CD3DVisual* pVisual; CD3DFrameArray* pFrameArray; d3dpickdesc2_t PickDesc; d3dray_t Ray; HRESULT Result; /* Ensure valid input */ ASSERT(pRefFrame != NULL); /* Chose the down direction from the source point */ Ray.dvDir = D3DVECTOR(0.0, -1.0, 0.0); Ray.dvPos = SourcePoint; /* Find the surface */ Result = pRefFrame->RayPick(NULL, &Ray, D3DRMRAYPICK_IGNOREFURTHERPRIMITIVES | D3DRMRAYPICK_INTERPOLATENORMAL, &pPickedArray); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to RayPick the reference frame!"); return (FALSE); } /* Nothing found, try in the up direction */ if (pPickedArray->GetSize() == 0) { RELEASE(pPickedArray); Ray.dvPos.y += (float) 10000.0; /* Find the surface */ Result = pRefFrame->RayPick(NULL, &Ray, D3DRMRAYPICK_IGNOREFURTHERPRIMITIVES | D3DRMRAYPICK_INTERPOLATENORMAL, &pPickedArray); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to RayPick the reference frame!"); return (FALSE); } /* Ensure something was found */ if (pPickedArray->GetSize() == 0) { SystemLog.Printf ("Failed to find any surfaces at point (%.0f, %.0f, %.0f)!", SourcePoint.x, SourcePoint.y, SourcePoint.z); RELEASE(pPickedArray); return (FALSE); } } /* Attempt to retreive the first object in the pick array */ Result = pPickedArray->GetPick(0, &pVisual, &pFrameArray, &PickDesc); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to get the first object in PickedArray!"); RELEASE(pPickedArray); return (FALSE); } /* Save the found destination point on the surface */ DestPoint = PickDesc.dvPosition; /* Release objects and return success*/ RELEASE(pVisual); RELEASE(pFrameArray); RELEASE(pPickedArray); return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::FindSurface() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::GetDisplayDC()" /*=========================================================================== * * Class CD3DApp Method - hDC GetDisplayDC (void); * * Attempt to retrieve the main display Device Context. Returns NULL on * any error. * *=========================================================================*/ HDC CD3DApp::GetDisplayDC (void) { HDC hDC; /* Get the device context for the display */ #if (D3D_EXCLUSIVE_MODE) HRESULT Result; /* Ensure a valid primary surface */ ASSERT(pBackSurface != NULL); Result = pBackSurface->GetDC(&hDC); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to retrieve the device context for the primary surface!"); return (NULL); } #else /* Ensure a valid window handle */ ASSERT(hMainWindow != NULL); hDC = GetDC(hMainWindow); if (hDC == NULL) { SET_WIN_ERROR2("Failed to retrieve the device context for the main window!"); return (NULL); } #endif return (hDC); } /*=========================================================================== * End of Class CD3DApp::GetDisplayDC() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::GetElapsedRenderTime()" /*=========================================================================== * * Class CD3DApp Method - float GetElapsedRenderTime (void); * * Retrieves the time, in seconds, since the last render. On any error, such * as an invalid last render time, returns 0. * *=========================================================================*/ float CD3DApp::GetElapsedRenderTime (void) { boolean Result; float ElapsedTime; /* Use the high precision counter */ if (UsePerformanceCounter) { LARGE_INTEGER CurrentCount; LARGE_INTEGER CounterDiff; Result = QueryPerformanceCounter(&CurrentCount); if (Result) { CounterDiff.QuadPart = CurrentCount.QuadPart - LastRenderCounter.QuadPart; if (LastRenderCounter.QuadPart == 0 || CounterDiff.QuadPart <= 0) { LastRenderCounter = CurrentCount; return ((float)0.0); } ElapsedTime = (float) ((double)CounterDiff.QuadPart/(double)PerformanceFreq.QuadPart); LastRenderCounter = CurrentCount; return (ElapsedTime); } } /* Have to use the regular clock timer */ clock_t CurrentTick = clock(); clock_t TickDiff = clock() - CurrentTick; if (LastRenderTick == 0 || TickDiff <= 0) { LastRenderTick = CurrentTick; return ((float)0.0); } ElapsedTime = (float)((float)TickDiff/(float)CLOCKS_PER_SEC); LastRenderTick = CurrentTick; return (ElapsedTime); } /*=========================================================================== * End of Class Method CD3DApp::GetElapsedRenderTime() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::GetPositionInFrontOfCamera()" /*=========================================================================== * * Class CD3DApp Method - boolean GetPositionInFrontOfCamera (Vector, pRefFrame); * * Attempt to retrieve a vector to a position in front of the current * camera relative to the given reference frame. Returns FALSE on any * error. * *=========================================================================*/ boolean CD3DApp::GetPositionInFrontOfCamera (d3dvector_t& Vector, LPDIRECT3DRMFRAME2 pRefFrame) { HRESULT Result; D3DVECTOR Up; D3DVECTOR Direction; /* Ensure valid objects */ ASSERT(pCamera != NULL); ASSERT(pRefFrame != NULL); /* Retreive the camera's position relative to the scene */ Result = pCamera->GetPosition(pRefFrame, &Vector); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to get camera position!"); return (FALSE); } /* Get the camera's orientation */ Result = pCamera->GetOrientation(pRefFrame, &Direction, &Up); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to get camera orientation!"); return (FALSE); } /* Adjust the vector to place it in front of the camera */ Direction.x = -Direction.x; Vector += Direction * MovementSpeed; return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::GetPositionInFrontOfCamera() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::HandleMessages()" /*=========================================================================== * * Class CD3DApp Method - boolean HandleMessages (Result, hWindow, Message, wParam, lParam); * * Handles any general window messages. Call from your WindowProc() * procedure. Returns FALSE if the message was not handled. * *=========================================================================*/ boolean CD3DApp::HandleMessages (LRESULT& Result, HWND hWindow, UINT Message, WPARAM wParam, LPARAM lParam) { boolean bResult; /* Ignore if not initialized. The default window procedure * should be called. */ if (!IsInitialized()) return (FALSE); /* Let any active surface mode object handle the message first */ if (IsInSurfaceMode()) { if (pCurrentSurfaceMode->IsActive()) { bResult = pCurrentSurfaceMode->HandleMessages(Result, hWindow, Message, wParam, lParam); if (bResult) return (TRUE); } } switch (Message) { case WM_KEYUP: if (!IsInSurfaceMode()) return OnKeyUp(Result, wParam); break; case WM_KEYDOWN: if (!IsInSurfaceMode()) return OnKeyDown(Result, wParam); break; case WM_LBUTTONDOWN: if (!IsInSurfaceMode()) return OnLButtonDown(Result, wParam, LOWORD(lParam), HIWORD(lParam)); break; case WM_DESTROY: TerminateApp(); return (TRUE); case WM_SIZE: /* Handle resizing of the window */ return OnSize(Result, LOWORD(lParam), HIWORD(lParam)); case WM_ACTIVATE: /* Create a Windows specific D3DRM window device to handle this message */ return OnActivate(Result, wParam); case WM_PAINT: return OnPaint(Result, hWindow); case WM_DISPLAYCHANGE: return OnDisplayChange(Result, hWindow); default: return (FALSE); } return (FALSE); } /*=========================================================================== * End of Class Method CD3DApp::HandleMessage() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::Initialize()" /*=========================================================================== * * Class CD3DApp Method - boolean Initialize (ThisInstance, CommandShow); * * Standard intialization function. Performs all the initialization * needed to get the app running. Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::Initialize (HINSTANCE ThisInstance, int CommandShow) { boolean Result; /* Ignore if already initialized */ if (IsInitialized()) return (TRUE); hInstance = ThisInstance; /* Create the application window and initialize Direct3D */ Result = CreateMainWindow(); if (Result) Result = UpdateBitsPerPixel(); if (Result) Result = D3DInitialization(); /* Build the intial scene as specified by the user, if valid */ if (Result && pBuildScene != NULL) { Result = pBuildScene(); } /* Abort if any of the previous actions resulted in failure */ if (!Result) return (FALSE); /* Load the acceleration table, if any. It appears that if * accelerators aren't loaded, the application locks-up. */ if (pAcceleratorName != NULL) { hAccelerator = LoadAccelerators(hInstance, pAcceleratorName); if (hAccelerator == NULL) { SET_WIN_ERROR3("Failed to load the accelerator table '%s'!", pAcceleratorName); return (FALSE); } } /* Display and update the main window */ ShowWindow(hMainWindow, CommandShow); Result = UpdateWindow(hMainWindow); if (!Result) { SET_WIN_ERROR2("Failed show and update the main application window!"); return (FALSE); } /* Return Success */ Initialized = TRUE; return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::Initialize() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::MoveScene()" /*=========================================================================== * * Class CD3DApp Method - boolean MoveScene (void); * * Moves the scene 'tick' according to the time elasped since the last * render. Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::MoveScene (void) { HRESULT Result; float ElaspedTime; /* Ensure a valid scene object */ if (pScene == NULL) { SET_EXT_ERROR(ERR_NULL); return (FALSE); } /* Compute the time correction factor and frame rate */ ElaspedTime = GetElapsedRenderTime(); if (ElaspedTime != 0.0) FrameRate = D3DVAL(1.0/ElaspedTime); else FrameRate = D3DVAL(0.0); /* Apply the tick to the scene */ Result = pScene->Move(ElaspedTime); if (FAILED(Result)) { SET_D3D_ERROR3(Result, "Failed to move the scene by %.3f sec!", ElaspedTime); return (FALSE); } /* Get the camera to follow the surface if required */ Result = DoFollowSurface(); //if (!Result) return (FALSE); return (TRUE); } /*=========================================================================== * End of Class CD3DApp::MoveScene() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::OnActivate()" /*=========================================================================== * * Class CD3DApp Event - boolean OnActivate (lResult, wParam); * * Called when the main window is activated. Create a Windows specific * D3DRM window device to handle this message. Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::OnActivate (LRESULT& lResult, WPARAM wParam) { CD3DWinDevice* pWinDev; HRESULT Result; /* Ensure a valid Direct3D device */ ASSERT(pDevice != NULL); /* Toggle the activated flag */ if (LOWORD(wParam) == WA_INACTIVE) Activated = FALSE; else Activated = TRUE; /* Attempt to get the window device from the device */ Result = pDevice->QueryInterface(IID_IDirect3DRMWinDevice, (void **) &pWinDev); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to create Direct3D windows device to handle WM_ACTIVATE event!"); return (FALSE); } /* Handle the activate message */ Result = pWinDev->HandleActivate(wParam); if (FAILED(Result)) SET_EXT_ERROR2(ERR_CUSTOM, "Failed to handle the WM_ACTIVATE event!"); RELEASE(pWinDev); /* Ensure the display is updated on a activate */ if (Activated) Render(); /* Set the Windows return value and return success */ lResult = 0; return (TRUE); } /*=========================================================================== * End of Class Event CD3DApp::OnActivate() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::OnDisplayRange()" /*=========================================================================== * * Class CD3DApp Event - boolean OnDisplayChange (lResult, hWindow); * * Handles any display change messages. Creates a temporary DirectDraw and * surface to see if the display change was created by an application requesting * exclusive mode. If so, just ignore it. Otherwise update the device and * view appropiately. Returns TRUE if the event was properly handled. * *=========================================================================*/ boolean CD3DApp::OnDisplayChange (LRESULT& lResult, HWND hWindow) { CDirectDraw* pDDraw = NULL; CDDSurface* pDDSurface = NULL; ddsdesc_t ddSurfaceDesc; HRESULT Result; /* We should ignore this if in exclusive mode */ #if D3D_EXCLUSIVE_MODE lResult = 0; return (TRUE); #endif /* Create a temporary DirectDraw object to see if this display change was * due to another app requesting exclusive mode. */ Result = CreateDirectDrawObject(&pDDraw); if (!Result) return (FALSE); Result = pDDraw->SetCooperativeLevel(hWindow, DDSCL_NORMAL | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ); if (FAILED(Result)) { RELEASE(pDDraw); return (FALSE); } /* Set the temporary surface attributes and create the surface */ memset(&ddSurfaceDesc, 0, sizeof(ddSurfaceDesc)); ddSurfaceDesc.dwSize = sizeof(ddSurfaceDesc); ddSurfaceDesc.dwFlags = DDSD_CAPS; ddSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; Result = pDDraw->CreateSurface(&ddSurfaceDesc, &pDDSurface, NULL); /* An exclusive mode generated WM_DISPLAYCHANGE, ignore it */ if (Result == DDERR_NOEXCLUSIVEMODE) { RELEASE(pDDraw); return (FALSE); } /* Release the temporary Surface and DirectDraw objects */ if (SUCCEEDED(Result)) RELEASE(pDDSurface); RELEASE(pDDraw); Initialized = FALSE; /* Create a new device and view */ Result = CreateDevice(); if (Result) Result = CreateView(); /* On failure we must terminate the application */ if (!Result) { TerminateApp(); return (TRUE); } Initialized = TRUE; lResult = 0; return (TRUE); } /*=========================================================================== * End of Class Event CD3DApp::OnDisplayChange() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::OnKeyDown()" /*=========================================================================== * * Class CD3DApp Event - boolean OnKeyDown (lResult, KeyDown); * * Called when a key is pressed * *=========================================================================*/ boolean CD3DApp::OnKeyDown (LRESULT& lResult, int KeyCode) { D3DVECTOR Direction; D3DVECTOR Up; D3DVECTOR Right; /* Ensure valid objects */ ASSERT(pCamera != NULL); /* Compute valid directions of the camera frame */ pCamera->GetOrientation(pScene, &Direction, &Up); D3DRMVectorCrossProduct(&Right, &Up, &Direction); Direction = Normalize(Direction)*MovementSpeed; Up.x /= D3DVAL(4.0); Up.y /= D3DVAL(4.0); Up.z /= D3DVAL(4.0); Right.x /= D3DVAL(4.0); Right.y /= D3DVAL(4.0); Right.z /= D3DVAL(4.0); lResult = 0; switch (KeyCode) { case 'q': case 'Q': TerminateApp(); return (TRUE); case VK_LEFT: case VK_NUMPAD4: if (!AllowMovement) break; pCamera->SetRotation(pScene, 0, 1, 0, -RotationSpeed); return (TRUE); case VK_NUMPAD6: case VK_RIGHT: if (!AllowMovement) break; pCamera->SetRotation(pScene, 0, 1, 0, RotationSpeed); return (TRUE); case VK_NUMPAD8: case VK_UP: if (!AllowMovement) break; pCamera->SetVelocity(pScene, Direction.x, 0.0, Direction.z, FALSE); return (TRUE); case VK_NUMPAD2: case VK_DOWN: if (!AllowMovement) break; pCamera->SetVelocity(pScene, -Direction.x, 0.0, -Direction.z, FALSE); return (TRUE); case VK_PRIOR: case VK_NUMPAD9: if (!AllowMovement) break; pCamera->SetRotation(pScene, Right.x, 0, Right.z, (float) (RotationSpeed/10.0)); return (TRUE); case VK_NEXT: case VK_NUMPAD3: if (!AllowMovement) break; pCamera->SetRotation(pScene, Right.x, 0, Right.z, (float) (-RotationSpeed/10.0)); return (TRUE); } /* Event was not handled */ return (FALSE); } /*=========================================================================== * End of Class Event CD3DApp::OnKeyDown() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::OnKeyUp()" /*=========================================================================== * * Class CD3DApp Event - boolean OnKeyUp (lResult, KeyCode); * * Called when a key is pressed. Returns TRUE if the event was handled. * *=========================================================================*/ boolean CD3DApp::OnKeyUp (LRESULT& lResult, int KeyCode) { lResult = 0; switch (KeyCode) { case VK_PRIOR: case VK_NEXT: case VK_NUMPAD4: case VK_NUMPAD6: case VK_NUMPAD9: case VK_NUMPAD3: case VK_RIGHT: case VK_LEFT: if (!AllowMovement) break; pCamera->SetRotation(pScene, D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0)); return (TRUE); case VK_NUMPAD8: case VK_NUMPAD2: case VK_UP: case VK_DOWN: if (!AllowMovement) break; pCamera->SetVelocity(pScene, D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0), FALSE); return (TRUE); } /* Event was not handled */ return (FALSE); } /*=========================================================================== * End of Class Event CD3DApp::OnKeyUp() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::OnLButtonDown()" /*=========================================================================== * * Class CD3DApp Event - LRESULT OnLMouseDown (lResult, KeyFlags, XPos, YPos); * * Called when the Left-mouse down is pressed in the main window. * Returns TRUE if the event was handled. * *=========================================================================*/ boolean CD3DApp::OnLButtonDown (LRESULT& lResult, int KeyFlags, int XPos, int YPos) { /* Attempt to select objects in the window */ PickObjects(pView, XPos, YPos); lResult = 0; return (TRUE); } /*=========================================================================== * End of Class Event CD3DApp::OnLButtonDown() *=========================================================================*/ /*=========================================================================== * * Class CD3DApp Event - LRESULT OnPaint (lResult, hWindow); * * Called when the main window is needs to be repainted. Create a Windows * specific D3DRM window device to handle this message. * *=========================================================================*/ boolean CD3DApp::OnPaint (LRESULT& lResult, HWND hWindow) { RECT WindowRect; PAINTSTRUCT PaintStruct; CD3DWinDevice* pWinDev = NULL; BOOL bResult; HRESULT Result; /* Ignore if we aren't initialized yet */ if (!IsInitialized()) return (FALSE); /* Ensure valid objects */ ASSERT(pDevice != NULL); /* Get the area we need to update */ bResult = GetUpdateRect(hWindow, &WindowRect, FALSE); if (!bResult) return (FALSE); /* Start the window painting */ BeginPaint(hWindow, &PaintStruct); /* Attempt to get a windows device from the D3D device */ Result = pDevice->QueryInterface(IID_IDirect3DRMWinDevice, (void **) &pWinDev); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to create Windows device to handle WM_PAINT!"); return (FALSE); } /* Handle the paint event */ Result = pWinDev->HandlePaint(PaintStruct.hdc); if (FAILED(Result)) SET_EXT_ERROR2(ERR_CUSTOM, "Failed to handle WM_PAINT message!"); /* Terminate painting */ RELEASE(pWinDev); EndPaint(hWindow, &PaintStruct); lResult = 0; return (TRUE); } /*=========================================================================== * End of Class Event CD3DApp::OnPaint() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::OnSize()" /*=========================================================================== * * Class CD3DApp EVent - boolean OnSize (lResult, Width, Height); * * Protected event which occurs when the user attempts to resize the * window. Returns TRUE if the event was handled. * *=========================================================================*/ boolean CD3DApp::OnSize (LRESULT& lResult, int Width, int Height) { boolean Result; /* Should ignore this in exclusive mode */ #if (D3D_EXCLUSIVE_MODE) lResult = 0; return (TRUE); #endif /* Ensure valid objects */ ASSERT(pView != NULL); ASSERT(pDevice != NULL); /* Check for a minimized message */ if (Width == 0 || Height == 0) { Minimized = TRUE; ResetLastRender(); lResult = 0; return (TRUE); } /* Release the current view and device objects */ Initialized = FALSE; RELEASE(pView); RELEASE(pDevice); /* Create a new device and view for the window */ Result = CreateDevice(Width, Height); if (Result) Result = CreateView(); /* Must terminate application on error */ if (!Result) { ErrorHandler.Notify(); TerminateApp(); lResult = 0; return (TRUE); } /* Reset appropriate states */ Initialized = TRUE; Minimized = FALSE; ResetLastRender(); /* Return success */ lResult = 0; return (TRUE); } /*=========================================================================== * End of Class Event CD3DApp::OnSize() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::PickObjects()" /*=========================================================================== * * Class CD3DApp Method - boolean PickObjects (pViewport, XPos, YPos); * * Attempt to pick objects in the given viewport at the specific coordinates. * Returns TRUE if any object was picked. Attempt to select the object and * display info depending on the application state. * *=========================================================================*/ boolean CD3DApp::PickObjects (CD3DView* pViewport, const int XPos, const int YPos) { CD3DPickedArray* pPickedArray; CD3DVisual* pVisual; CD3DFrameArray* pFrameArray; CD3DFaceArray* pFaceArray; CD3DFace* pFace; CD3DMeshBuilder* pMesh; d3dpickdesc_t PickDesc; HRESULT Result; /* Ignore if we aren't allowing object selection currently */ if (!AllowSelectObject) return (FALSE); /* Ensure valid input */ ASSERT(pViewport != NULL); /* Attempt to find objects in scene */ Result = pViewport->Pick(XPos, YPos, &pPickedArray); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Error picking object in viewport!"); return (FALSE); } /* Nothing found */ if (pPickedArray->GetSize() == 0) { RELEASE(pPickedArray); return (FALSE); } /* Select the first pick object in the array */ Result = pPickedArray->GetPick(0, &pVisual, &pFrameArray, &PickDesc); if (pVisual == NULL || FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to get the first picked object in the array!"); RELEASE(pPickedArray); return (FALSE); } /* Attempt to get the mesh builder from the visual object */ Result = pVisual->QueryInterface(IID_CD3DMeshBuilder, (void **) &pMesh); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to retrieve the mesh builder from the visual object!"); RELEASE(pPickedArray); RELEASE(pVisual); return (FALSE); } /* Attempt to get the face array from the object */ Result = pMesh->GetFaces(&pFaceArray); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to retrieve the face array from the mesh builder!"); RELEASE(pMesh); RELEASE(pPickedArray); RELEASE(pVisual); return (FALSE); } /* Ensure a valid face index (so, I'm paranoid) */ ASSERT(pFaceArray->GetSize() > PickDesc.ulFaceIdx); /* Get the face object */ Result = pFaceArray->GetElement(PickDesc.ulFaceIdx, &pFace); if (FAILED(Result)) { SET_D3D_ERROR3(Result, "Failed to retrieve the face %d from the face array !", PickDesc.ulFaceIdx); RELEASE(pFaceArray); RELEASE(pMesh); RELEASE(pPickedArray); RELEASE(pVisual); return (FALSE); } /* Select the object if required */ SelectObject(pVisual, pFace, PickDesc); /* Unallocate objects */ RELEASE(pFrameArray); RELEASE(pPickedArray); RELEASE(pFaceArray); RELEASE(pMesh); return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::PickObjects() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::ReleaseDisplayDC()" /*=========================================================================== * * Class CD3DApp Method - boolean ReleaseDisplayDC (void); * * Releases a device context previously obtained with GetDisplayDC(). * Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::ReleaseDisplayDC (HDC hDC) { /* Release the device context for the display */ #if (D3D_EXCLUSIVE_MODE) HRESULT Result; /* Ensure a valid primary surface */ ASSERT(pBackSurface != NULL); Result = pBackSurface->ReleaseDC(&hDC); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to release the device context for the back surface!"); return (FALSE); } #else boolean Result; /* Ensure a valid window handle */ ASSERT(hMainWindow != NULL); Result = ReleaseDC(hMainWindow, hDC); if (Result != 1) { SET_WIN_ERROR2("Failed to release the device context for the main window!"); return (FALSE); } #endif return (TRUE); } /*=========================================================================== * End of Class CD3DApp::ReleaseDisplayDC() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::RemoveSurfaceMode()" /*=========================================================================== * * Class CD3DApp Method - void RemoveSurfaceMode (void); * * Removes any current surface mode object. * *=========================================================================*/ void CD3DApp::RemoveSurfaceMode (void) { /* Ensure there is a surface mode to remove */ if (pCurrentSurfaceMode == NULL) return; InSurfaceMode = FALSE; pCurrentSurfaceMode->Destroy(); pCurrentSurfaceMode = NULL; Render(); } /*=========================================================================== * End of Class Method CD3DApp::RemoveSurfaceMode() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::Render()" /*=========================================================================== * * Class CD3DApp Method - boolean Render (void); * * Updates the window with one frame. Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::Render (void) { HRESULT Result; /* Ensure we should be rendering the scene currently */ if (!CanRenderScene()) return (TRUE); /* Tick the scene, applying time correction to the movement */ Result = MoveScene(); if (!Result) return (FALSE); /* Clear the viewport */ Result = pView->Clear(); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to clear viewport!"); return FALSE; } /* Render the scene to the viewport */ Result = pView->Render(pScene); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to render scene!"); return (FALSE); } /* Update the entire view */ pView->ForceUpdate(pView->GetX(), pView->GetY(), pView->GetX()+pView->GetWidth(), pView->GetY() + pView->GetHeight()); Result = pDevice->Update(); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to update device after render!"); return (FALSE); } /* Display the frame rate if required */ Result = DrawFrameRate(); /* Flip surfaces only if we are in exclusive mode */ #if (D3D_EXCLUSIVE_MODE) ASSERT(pDDSurface != NULL); /* Flip the primary/back buffers */ Result = pDDSurface->Flip(NULL, DDFLIP_WAIT); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to flip the primary and back surfaces!"); return (FALSE); } #endif return (TRUE); } /*=========================================================================== * End of Class CD3DApp::Render() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::SelectObject()" /*=========================================================================== * * Class CD3DApp Method - boolean SelectObject (pVisual, pFace, PickDesc); * * Attempt to set the currently selected object. Returns TRUE on success * or FALSE on any error. * *=========================================================================*/ boolean CD3DApp::SelectObject (CD3DVisual* pVisual, CD3DFace* pFace, d3dpickdesc_t& PickDesc) { int Result; /* Ensure valid objects */ ASSERT(pVisual != NULL); ASSERT(pFace != NULL); /* Unselect the current objects, if any */ UnSelectObject(); /* Are we allowed to select objects? */ if (!AllowSelectObject) return (FALSE); /* Copy the object pointers/values */ pSelectedVisual = pVisual; pSelectedFace = pFace; SelectedPickDesc = PickDesc; HasSelectedObject = TRUE; /* Record and change the color of the selected face */ OldSelectedFaceColor = pSelectedFace->GetColor(); pSelectedFace->SetColorRGB(D3DVAL(1.0), D3DVAL(0.1), D3DVAL(0.1)); /* Call the display plane callback function if required, updating the * output display beforehand. */ if (pOnSelectObjectCallBack != NULL && CallBackOnSelectObject) { Result = Render(); if (!Result) return (FALSE); pOnSelectObjectCallBack (pVisual->GetAppData(), SelectedPickDesc.ulFaceIdx); } return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::SelectObject() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::SetFillMode()" /*=========================================================================== * * Class CD3DApp Method - boolean SetFillMode (FillMode); * * Changes the rendering quality fill mode (point, wireframe, or solid). * Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::SetFillMode(d3dfillmode_t FillMode) { d3dfillmode_t OldFillMode = (d3dfillmode_t) (RenderQuality & D3DRMFILL_MASK); HRESULT Result; /* Ensure a valid device object */ ASSERT(pDevice != NULL); /* Extract the render quality information */ RenderQuality = (RenderQuality & ~D3DRMFILL_MASK) | FillMode; Result = pDevice->SetQuality(RenderQuality); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to set the render quality while changing the fill mode!"); return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::SetFillMode() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::SetRenderState()" /*=========================================================================== * * Class CD3DApp Method - boolean SetRenderState (void); * * Sets the render state (quality, dithering, texture BPP, etc...). * Returns the D3D return code. * *=========================================================================*/ boolean CD3DApp::SetRenderState (void) { HRESULT Result; /* Ensure valid objects */ ASSERT(pDirect3D != NULL); ASSERT(pDevice != NULL); /* Set the render quality (light toggle, fill mode, shade mode) */ if (pDevice->GetQuality() != RenderQuality) { Result = pDevice->SetQuality(RenderQuality); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to set the Direct3D device quality!"); return (FALSE); } } /* Set dithering toggle */ if (pDevice->GetDither() != Dithering) { Result = pDevice->SetDither(Dithering); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to change the dithering mode of the Direct3D device!"); return (FALSE); } } /* Set the texture quality (point or linear filtering) */ if (pDevice->GetTextureQuality() != TextureQuality) { Result = pDevice->SetTextureQuality(TextureQuality); if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to change the texture quality of the Direct3D device!"); return (FALSE); } } /* Set shade info based on current bits per pixel */ switch (BitsPerPixel) { case 1: Result = pDevice->SetShades(4); if (FAILED(Result)) break; Result = pDirect3D->SetDefaultTextureShades(4); break; case 16: Result = pDevice->SetShades(32); if (FAILED(Result)) break; Result = pDirect3D->SetDefaultTextureColors(64); if (FAILED(Result)) break; Result = pDirect3D->SetDefaultTextureShades(32); break; case 24: case 32: Result = pDevice->SetShades(256); if (FAILED(Result)) break; Result = pDirect3D->SetDefaultTextureColors(64); if (FAILED(Result)) break; Result = pDirect3D->SetDefaultTextureShades(256); break; } /* Check for errors */ if (FAILED(Result)) { SET_D3D_ERROR2(Result, "Failed to change the texture shades/colors of the Direct3D device!"); return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::SetRenderState() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::SetSurfaceMode()" /*=========================================================================== * * Class CD3DApp Method - boolean SetSurfaceMode (pSurfaceMode); * * Sets the current surface mode. Destroys the previous mode, if any and * returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::SetSurfaceMode (CDDSurfaceMode* pSurfaceMode) { boolean Result; /* Ensure valid input */ ASSERT(pSurfaceMode != NULL); /* Remove the previous surface mode, if any */ RemoveSurfaceMode(); /* Initialize the new surface mode */ Result = pSurfaceMode->InitSurfaceMode(hMainWindow, this); if (!Result) return (FALSE); /* Set the surface mode to be the active component */ pSurfaceMode->SetActive(); InSurfaceMode = TRUE; pCurrentSurfaceMode = pSurfaceMode; pSurfaceMode->Update(); return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::SetSurfaceMofe() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::TerminateApp()" /*=========================================================================== * * Class CD3DApp Method - void TerminateApp (void); * * Destroys all the D3D objects. * *=========================================================================*/ void CD3DApp::TerminateApp (void) { Initialized = FALSE; QuitMain = TRUE; /* Destroy exclusive mode specific objects */ #if (D3D_EXCLUSIVE_MODE) RELEASE(pBackSurface); RELEASE(pPrimarySurface); RELEASE(pDirectDraw); #endif RELEASE(pSelectedFace); RELEASE(pSelectedVisual); RELEASE(pScene); RELEASE(pCamera); RELEASE(pView); RELEASE(pDevice); RELEASE(pDirect3D); RELEASE(pDDClipper); } /*=========================================================================== * End of Class Method CD3DApp::TerminateApp() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::UnSelectObject()" /*=========================================================================== * * Class CD3DApp Method - void UnSelectObject (void); * * Unselects any currently selected objects. * *=========================================================================*/ void CD3DApp::UnSelectObject (void) { /* Delete the currently selected item objects, if any */ if (HasSelectedObject) { /* Ensure valid objects */ ASSERT(pSelectedFace != NULL); ASSERT(pSelectedVisual != NULL); /* Reset the selected face color */ pSelectedFace->SetColor(OldSelectedFaceColor); /* Delete the selected objects */ RELEASE(pSelectedVisual); RELEASE(pSelectedFace); /* Reset the description of the selected object */ SelectedPickDesc.lGroupIdx = 0; SelectedPickDesc.ulFaceIdx = 0; HasSelectedObject = FALSE; } } /*=========================================================================== * End of Class Method CD3DApp::UnSelectObject() *=========================================================================*/ #undef __FUNC__ #define __FUNC__ "CD3DApp::UpdateBitsPerPixel()" /*=========================================================================== * * Class CD3DApp Method - boolean UpdateBitsPerPixel (void); * * Updates the BitsPerPixel member variable from the current settings * of the main application window. Returns FALSE on any error. * *=========================================================================*/ boolean CD3DApp::UpdateBitsPerPixel (void) { HDC hDC; /* Attempt to get a Device Context from the main window */ hDC = GetDC(hMainWindow); if (hDC == NULL) { SET_WIN_ERROR2("Failed to retrieve a device context for the main window!"); return (FALSE); } /* Record the BPP from the device capabilities */ BitsPerPixel = GetDeviceCaps(hDC, BITSPIXEL); /* Release the Device Context and return success */ ReleaseDC(hMainWindow, hDC); return (TRUE); } /*=========================================================================== * End of Class Method CD3DApp::UpdateBitsPerPixel() *=========================================================================*/