home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / misc / rmfull.cpp < prev    next >
C/C++ Source or Header  |  1997-07-14  |  36KB  |  1,165 lines

  1. /*
  2.  *  Copyright (C) 1995, 1996 Microsoft Corporation. All Rights Reserved.
  3.  *
  4.  *  File: rmfull.cpp
  5.  *
  6.  *  Each of the Direct3D retained mode (D3DRM) samples may be linked with
  7.  *  this file.  It contains the code which allows them to run in the Windows
  8.  *  environment as a window or fullscreen.  It is a modified version of
  9.  *  d3dmain.cpp.  Comparing these two files is instructive.
  10.  *
  11.  *  A window is created using rmfull.res which allows the user to select the
  12.  *  Direct3D driver to use and change the render options.  The D3DApp
  13.  *  collection of functions is used to initialize DirectDraw, Direct3D and
  14.  *  keep surfaces and D3D devices available for rendering.
  15.  *
  16.  *  Frame rate and a screen mode information buffer is Blt'ed to the screen
  17.  *  by functions in rmstats.cpp.
  18.  *
  19.  *  Individual samples are executed through two functions, BuildScene and
  20.  *  OverrideDefaults, as described in rmdemo.h.  Samples can also read
  21.  *  mouse input via ReadMouse.
  22.  */
  23.  
  24. #include "rmfull.h"
  25. #include <stdarg.h>
  26.  
  27. /*
  28.  * GLOBAL VARIABLES
  29.  */
  30. D3DAppInfo* d3dapp;        /* Pointer to read only collection of DD and D3D
  31.                    objects maintained by D3DApp */
  32. rmfullglobals myglobs;        /* collection of global variables */
  33. LPDIRECT3DRM lpD3DRM;        /* Direct3DRM object */
  34.  
  35. /*
  36.  *  INTERNAL FUNCTION PROTOTYPES
  37.  */
  38. static BOOL AppInit(HINSTANCE hInstance, LPSTR lpCmdLine);
  39. static BOOL CreateD3DApp(LPSTR lpCmdLine);
  40. static BOOL BeforeDeviceDestroyed(LPVOID lpContext);
  41. static BOOL AfterDeviceCreated(int w, int h, LPDIRECT3DVIEWPORT* lpViewport,
  42.                    LPVOID lpContext);
  43. void CleanUpAndPostQuit(void);
  44. static void InitGlobals(void);
  45. static BOOL AppPause(BOOL f);
  46. void ReportD3DAppError(void);
  47. static BOOL RenderLoop(void);
  48. static BOOL RestoreSurfaces();
  49. long FAR PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam,
  50.                LPARAM lParam );
  51. extern "C" void ReadMouse(int*, int*, int*);
  52. extern "C" char* D3DRMErrorToString(HRESULT error);
  53. BOOL CreateD3DRM(HWND win);
  54. BOOL SetRenderState(void);
  55.  
  56. /****************************************************************************/
  57. /*                            WinMain                                       */
  58. /****************************************************************************/
  59. /*
  60.  * Initializes the application then enters a message loop which calls sample's
  61.  * RenderScene until a quit message is received.
  62.  */
  63. int PASCAL
  64. WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
  65.     int nCmdShow)
  66. {
  67.     int failcount = 0; /* number of times RenderLoop has failed */
  68.     MSG    msg;
  69.     HACCEL hAccelApp;
  70.  
  71.     hPrevInstance;
  72.     /*
  73.      * Create the window and initialize all objects needed to begin rendering
  74.      */
  75.     if(!AppInit(hInstance, lpCmdLine))
  76.         return FALSE;
  77.     hAccelApp = LoadAccelerators(hInstance, "AppAccel");
  78.  
  79.     while (!myglobs.bQuit) {
  80.     /* 
  81.      * Monitor the message queue until there are no pressing
  82.      * messages
  83.      */
  84.         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  85.             if (msg.message == WM_QUIT) {
  86.         CleanUpAndPostQuit();
  87.                 break;
  88.         }
  89.             if (!myglobs.hWndMain || !TranslateAccelerator(myglobs.hWndMain,
  90.                                hAccelApp, &msg)) {
  91.                 TranslateMessage(&msg); 
  92.                 DispatchMessage(&msg);
  93.             }
  94.     /* 
  95.      * If the app is not minimized, not about to quit, not paused, either the
  96.      * active fullscreen app or in a window and D3D has been initialized,
  97.      * we can render
  98.      */
  99.         } else if (d3dapp->bRenderingIsOK && !d3dapp->bMinimized
  100.            && !d3dapp->bPaused && !myglobs.bQuit 
  101.            && (d3dapp->bAppActive || !d3dapp->bFullscreen)) {
  102.         /*
  103.          * If were are not in single step mode or if we are and the
  104.          * bDrawAFrame flag is set, render one frame
  105.          */
  106.             if (!(myglobs.bSingleStepMode && !myglobs.bDrawAFrame)) {
  107.         /* 
  108.          * Attempt to render a frame, if it fails, take a note.  If
  109.          * rendering fails more than twice, abort execution.
  110.          */
  111.         if (!RenderLoop()) {
  112.             ++failcount;
  113.             if (failcount == 3) {
  114.             Msg("Rendering has failed too many times.  Aborting execution.\n");
  115.             CleanUpAndPostQuit();
  116.             break;
  117.             }
  118.         }
  119.         }
  120.         /*
  121.          * Reset the bDrawAFrame flag if we are in single step mode
  122.          */
  123.             if (myglobs.bSingleStepMode)
  124.                 myglobs.bDrawAFrame = FALSE;
  125.         } else {
  126.         WaitMessage();
  127.     }
  128.     }
  129.     DestroyWindow(myglobs.hWndMain);
  130.     return msg.wParam;
  131. }
  132.  
  133. /****************************************************************************/
  134. /*             D3DApp Initialization and callback functions                 */
  135. /****************************************************************************/
  136. /*
  137.  * AppInit
  138.  * Creates the window and initializes all objects necessary to begin rendering
  139.  */
  140. static BOOL
  141. AppInit(HINSTANCE hInstance, LPSTR lpCmdLine)
  142. {
  143.     WNDCLASS wc;
  144.     HMENU hmenu;
  145.     DWORD flags;
  146.     int i;
  147.     Defaults defaults;
  148.  
  149.     /*
  150.      * Register the window class
  151.      */
  152.     wc.style = CS_HREDRAW | CS_VREDRAW;
  153.     wc.lpfnWndProc = WindowProc;
  154.     wc.cbClsExtra = 0;
  155.     wc.cbWndExtra = 0;
  156.     wc.hInstance = hInstance;
  157.     wc.hIcon = LoadIcon( hInstance, "AppIcon");
  158.     wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  159.     wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  160.     wc.lpszMenuName = "AppMenu";
  161.     wc.lpszClassName = "Example";
  162.     if (!RegisterClass(&wc))
  163.         return FALSE;
  164.     /*
  165.      * Initialize the global variables and allow the sample code to override
  166.      * some of these default settings.
  167.      */
  168.     InitGlobals();
  169.     myglobs.hInstApp = hInstance;
  170.     defaults.bNoTextures = myglobs.bNoTextures;
  171.     defaults.bConstRenderQuality = myglobs.bConstRenderQuality;
  172.     defaults.bResizingDisabled = FALSE;
  173.     lstrcpy(defaults.Name, "D3DRM Example");
  174.     OverrideDefaults(&defaults);
  175.     myglobs.bNoTextures = defaults.bNoTextures;
  176.     myglobs.bConstRenderQuality = defaults.bConstRenderQuality;
  177.     myglobs.lpCmdLine = lpCmdLine;
  178.  
  179.     /*
  180.      * Enumerate the DD drivers
  181.      */
  182.     if (!D3DAppEnumerateDDDevices(&myglobs.NumDDDrivers, &myglobs.DDDriver[0])) {
  183.     ReportD3DAppError();
  184.     return FALSE;
  185.     }
  186.     /*
  187.      * Choose the last device enumerated which will probably be secondary 3d hardware.
  188.      */
  189.     myglobs.CurrDDDriver = myglobs.NumDDDrivers - 1;
  190.  
  191.     /*
  192.      * Create the window
  193.      */
  194.     if (defaults.bResizingDisabled)
  195.     flags =  WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
  196.          WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
  197.     else
  198.     flags = WS_OVERLAPPEDWINDOW;
  199.     /*
  200.      * Create a window with some default settings that may change
  201.      */
  202.     myglobs.hWndMain = CreateWindowEx(
  203.           WS_EX_APPWINDOW,
  204.      "Example",
  205.      defaults.Name,
  206.      flags,
  207.          CW_USEDEFAULT, CW_USEDEFAULT,
  208.      START_WIN_SIZE, START_WIN_SIZE,
  209.          NULL,                    /* parent window */
  210.      NULL,                    /* menu handle */
  211.      hInstance,                /* program handle */
  212.      NULL);                    /* create parms */    
  213.     if (!myglobs.hWndMain){
  214.         Msg("CreateWindowEx failed");
  215.         return FALSE;
  216.     }
  217.     /*
  218.      * Display the window
  219.      */
  220.     ShowWindow(myglobs.hWndMain, SW_SHOWNORMAL);
  221.     UpdateWindow(myglobs.hWndMain);
  222.     /*
  223.      * Add the list of DD drivers D3DApp found to the file menu
  224.      */
  225.     hmenu = GetSubMenu(GetMenu(myglobs.hWndMain), 0);
  226.     for (i = 0; i < myglobs.NumDDDrivers; i++) {
  227.         InsertMenu(hmenu,  6 + i, MF_BYPOSITION | MF_STRING,
  228.            MENU_FIRST_DDDRIVER + i, myglobs.DDDriver[i].Name);
  229.     }
  230.     /* 
  231.      * Create the D3DRM object which are initialized only when the program
  232.      * starts
  233.      */
  234.     if (!CreateD3DRM(myglobs.hWndMain))
  235.         return FALSE;
  236.     /*
  237.      * Call D3DApp to initialize all DD and D3D objects necessary to render.
  238.      * D3DApp will call the device creation callback which will initialize the
  239.      * viewport and the sample's execute buffers.
  240.      */
  241.     if (!CreateD3DApp(lpCmdLine))
  242.     return FALSE;
  243.     /*
  244.      * Create the scene to be rendered by calling this sample's BuildScene
  245.      */
  246.     if (!BuildScene(myglobs.dev, myglobs.view, myglobs.scene, myglobs.camera))
  247.     return FALSE;
  248.  
  249.     return TRUE;
  250. }
  251.  
  252. /*
  253.  * CreateD3DRM
  254.  * Create main D3DRM objects which are only initialized once.
  255.  */
  256. BOOL
  257. CreateD3DRM(HWND win)
  258. {
  259.     HRESULT rval;
  260.  
  261.     /*
  262.      * Create the D3DRM object
  263.      */
  264.     rval = Direct3DRMCreate(&lpD3DRM);
  265.     if (rval != D3DRM_OK) {
  266.     Msg("Failed to create Direct3DRM.\n%s", D3DAppErrorToString(rval));
  267.     return FALSE;
  268.     }
  269.     /*
  270.      * Create the master scene frame and camera frame
  271.      */
  272.     rval = lpD3DRM->CreateFrame(NULL, &myglobs.scene);
  273.     if (rval != D3DRM_OK) {
  274.     Msg("Failed to create the master scene frame.\n%s", D3DAppErrorToString(rval));
  275.     return FALSE;
  276.     }
  277.     rval = lpD3DRM->CreateFrame(myglobs.scene, &myglobs.camera);
  278.     if (rval != D3DRM_OK) {
  279.     Msg("Failed to create the camera's frame.\n%s", D3DAppErrorToString(rval));
  280.     return FALSE;
  281.     }
  282.     rval = myglobs.camera->SetPosition(myglobs.scene, D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0));
  283.     if (rval != D3DRM_OK) {
  284.     Msg("Failed to position the camera in the frame.\n%s", D3DAppErrorToString(rval));
  285.     return FALSE;
  286.     }
  287.     return TRUE;
  288. }
  289.  
  290. /*
  291.  * CreateD3DApp
  292.  * Create all DirectDraw and Direct3D objects necessary to begin rendering.
  293.  * Add the list of D3D drivers to the file menu.
  294.  */
  295. static BOOL
  296. CreateD3DApp(LPSTR lpCmdLine)
  297. {
  298.     HMENU hmenu;
  299.     int i;
  300.     LPSTR option;
  301.     BOOL bOnlySystemMemory, bOnlyEmulation;
  302.     DWORD flags;
  303.  
  304.     /*
  305.      * Parse the command line in seach of one of the following options:
  306.      *     systemmemory  All surfaces should be created in system memory.
  307.      *                   Hardware DD and D3D devices are disabled, but
  308.      *                   debugging during the Win16 lock becomes possible.
  309.      *     emulation     Do not use hardware DD or D3D devices.
  310.      */
  311.     bOnlySystemMemory = FALSE;
  312.     bOnlyEmulation = FALSE;
  313.     option = strtok(lpCmdLine, " -");
  314.     while(option != NULL )   {
  315.         if (!lstrcmp(option, "systemmemory")) {
  316.             bOnlySystemMemory = TRUE;
  317.         } else if (!lstrcmp(option, "emulation")) {
  318.         bOnlyEmulation = TRUE;
  319.     } else {
  320.             Msg("Invalid command line options given.\nLegal options: -systemmemory, -emulation\n");
  321.             return FALSE;
  322.         }
  323.         option = strtok(NULL, " -");
  324.     }
  325.     /*
  326.      * Set the flags to pass to the D3DApp creation based on command line
  327.      */
  328.     flags = ((bOnlySystemMemory) ? D3DAPP_ONLYSYSTEMMEMORY : 0) | 
  329.         ((bOnlyEmulation) ? (D3DAPP_ONLYD3DEMULATION |
  330.                  D3DAPP_ONLYDDEMULATION) : 0);
  331.     /*
  332.      * Create all the DirectDraw and D3D objects neccesary to render.  The
  333.      * AfterDeviceCreated callback function is called by D3DApp to create the
  334.      * viewport and the example's execute buffers.
  335.      */
  336.     if (!D3DAppCreateFromHWND(flags, myglobs.hWndMain, 
  337.                   myglobs.DDDriver[myglobs.CurrDDDriver].bIsPrimary ? NULL : &myglobs.DDDriver[myglobs.CurrDDDriver].Guid,
  338.                   AfterDeviceCreated, NULL, BeforeDeviceDestroyed, NULL, &d3dapp)) {
  339.     ReportD3DAppError();
  340.     return FALSE;
  341.     }
  342.     /*
  343.      * Add the the list of display modes D3DApp found to the mode menu
  344.      */
  345.     hmenu = GetSubMenu(GetMenu(myglobs.hWndMain), 2);
  346.     for (i = 0; i < d3dapp->NumModes; i++) {
  347.         char ach[80];
  348.         wsprintf(ach,"%dx%dx%d", d3dapp->Mode[i].w, d3dapp->Mode[i].h,
  349.          d3dapp->Mode[i].bpp);
  350.         AppendMenu(hmenu, MF_STRING, MENU_FIRST_MODE+i, ach);
  351.     }
  352.     /*
  353.      * Add the list of D3D drivers D3DApp foudn to the file menu
  354.      */
  355.     hmenu = GetSubMenu(GetMenu(myglobs.hWndMain), 0);
  356.     for (i = 0; i < d3dapp->NumDrivers; i++) {
  357.         InsertMenu(hmenu, 7 + myglobs.NumDDDrivers + i, MF_BYPOSITION | MF_STRING,
  358.            MENU_FIRST_DRIVER + i, d3dapp->Driver[i].Name);
  359.     }
  360.  
  361.     return TRUE;
  362. }
  363.  
  364. /*
  365.  * DestroyD3DApp
  366.  *
  367.  * Destroy D3DApp and changes to menu
  368.  */
  369. static void
  370. DestroyD3DApp(void)
  371. {
  372.     HMENU hmenu;
  373.     int i;
  374.  
  375.     /*
  376.      * Remove the list of display modes
  377.      */
  378.     hmenu = GetSubMenu(GetMenu(myglobs.hWndMain), 4);
  379.     for (i = 0; i < d3dapp->NumModes; i++) {
  380.         DeleteMenu(hmenu, MENU_FIRST_MODE + i, MF_BYCOMMAND);
  381.     }
  382.     /*
  383.      * Remove the list of D3D drivers
  384.      */
  385.     hmenu = GetSubMenu(GetMenu(myglobs.hWndMain), 0);
  386.     for (i = 0; i < d3dapp->NumDrivers; i++) {
  387.         DeleteMenu(hmenu, MENU_FIRST_DRIVER + i, MF_BYCOMMAND);
  388.     }
  389.     RELEASE(myglobs.lpInfoBuffer);
  390.     RELEASE(myglobs.lpFrameRateBuffer);
  391.     D3DAppDestroy();
  392. }
  393.  
  394. /*
  395.  * AfterDeviceCreated
  396.  * D3DApp will call this function immediately after the D3D device has been
  397.  * created (or re-created).  D3DApp expects the D3D viewport to be created and
  398.  * returned.  In this case, we will return NULL because we only have a D3DRM
  399.  * viewport.  This is fine as long as we don't use any of the D3D viewport
  400.  * functionality of D3DApp.
  401.  */
  402. static BOOL
  403. AfterDeviceCreated(int w, int h, LPDIRECT3DVIEWPORT* lplpViewport, LPVOID lpContext)
  404. {
  405.     HRESULT rval;
  406.  
  407.     rval = lpD3DRM->CreateDeviceFromD3D(d3dapp->lpD3D, d3dapp->lpD3DDevice,
  408.                     &myglobs.dev);
  409.     if (rval != D3DRM_OK) {
  410.         Msg("Creation of D3DRM device failed.\n%s", D3DAppErrorToString(rval));
  411.         return FALSE;
  412.     }
  413.     /*
  414.      * Create the D3DRM viewport using the camera frame.  Set the background
  415.      * depth to a large number.  The width and height may be slightly
  416.      * adjusted, so get them from the device to be sure.
  417.      */
  418.     w = myglobs.dev->GetWidth();
  419.     h = myglobs.dev->GetHeight();
  420.     rval = lpD3DRM->CreateViewport(myglobs.dev, myglobs.camera, 0, 0, w,
  421.                    h, &myglobs.view);
  422.     if (rval != D3DRM_OK) {
  423.     Msg("Failed to create the D3DRM viewport.\n%s",
  424.         D3DAppErrorToString(rval));
  425.     RELEASE(myglobs.dev);
  426.     return FALSE;
  427.     }
  428.     rval = myglobs.view->SetBack(D3DVAL(5000.0));
  429.     if (rval != D3DRM_OK) {
  430.     Msg("Failed to set the background depth of the D3DRM viewport.\n%s",
  431.         D3DAppErrorToString(rval));
  432.     RELEASE(myglobs.dev);
  433.     RELEASE(myglobs.view);
  434.     return FALSE;
  435.     }
  436.     /*
  437.      * Set the render quality, fill mode, lighting state and color shade info
  438.      */
  439.     if (!SetRenderState())
  440.     return FALSE;
  441.  
  442.     /*
  443.      * Return NULL for the viewport
  444.      */
  445.     *lplpViewport = NULL;
  446.     /*
  447.      * Create and initialize the surfaces containing the frame rate and
  448.      * window information
  449.      */
  450.     InitFontAndTextBuffers();
  451.  
  452.     return TRUE;
  453. }
  454.  
  455. /*
  456.  * BeforeDeviceDestroyed
  457.  * D3DApp will call this function before the current D3D device is destroyed
  458.  * to give the app the opportunity to destroy objects it has created with the
  459.  * DD or D3D objects.
  460.  */
  461. static BOOL
  462. BeforeDeviceDestroyed(LPVOID lpContext)
  463. {
  464.     RELEASE(myglobs.view);
  465.     RELEASE(myglobs.dev);
  466.     return TRUE;
  467. }
  468.  
  469. /****************************************************************************/
  470. /*                            Rendering loop                                */
  471. /****************************************************************************/
  472. /*
  473.  * RenderLoop
  474.  * Render the next frame and update the window
  475.  */
  476. static BOOL
  477. RenderLoop()
  478. {
  479.     D3DRECT extents[D3DAPP_MAXCLEARRECTS];
  480.     int count;
  481.     HRESULT rval;
  482.     static BOOL b = FALSE; // Clear the second buffer on also
  483.  
  484.     /*
  485.      * If all the DD and D3D objects have been initialized we can render
  486.      */
  487.     if (d3dapp->bRenderingIsOK) {
  488.     /*
  489.      * Restore any lost surfaces
  490.      */
  491.         if (!RestoreSurfaces()) {
  492.         /*
  493.          * Restoring surfaces sometimes fails because the surfaces cannot
  494.          * yet be restored.  If this is the case, the error will show up
  495.          * somewhere else and we should return success here to prevent
  496.          * unnecessary error's being reported.
  497.          */
  498.         return TRUE;
  499.     }
  500.     /*
  501.      * Force an update of the entire client window if the resized flag is set
  502.      */
  503.     if (myglobs.bResized || b)
  504.         myglobs.view->ForceUpdate(0, 0, d3dapp->szClient.cx, d3dapp->szClient.cy);
  505.     /*
  506.      * Use b to makesure the second buffer is cleared also
  507.      */
  508.     if (b)
  509.         b = FALSE;
  510.     if (myglobs.bResized)
  511.         b = TRUE;
  512.  
  513.     /*
  514.      * Calculate the frame rate
  515.      */
  516.         if (!CalculateFrameRate())
  517.         return FALSE;
  518.  
  519.     /*
  520.      * Tick the scene
  521.      */
  522.     rval = myglobs.scene->Move(D3DVAL(1.0));
  523.     if (rval != D3DRM_OK) {
  524.         Msg("Moving scene failed.\n%s", D3DAppErrorToString(rval));
  525.         return FALSE;
  526.     }
  527.     /* 
  528.      * Clear the viewport
  529.      */
  530.     rval = myglobs.view->Clear();
  531.     if (rval != D3DRM_OK) {
  532.         Msg("Clearing viewport failed.\n%s", D3DAppErrorToString(rval));
  533.         return FALSE;
  534.     }
  535.     /*
  536.      * Render the scene to the viewport
  537.      */
  538.     rval = myglobs.view->Render(myglobs.scene);
  539.     if (rval != D3DRM_OK) {
  540.         Msg("Rendering scene failed.\n%s", D3DAppErrorToString(rval));
  541.         return FALSE;
  542.     }
  543.     /*
  544.      * Blt the frame rate and window stat text to the back buffer
  545.      */
  546.     count = 0;
  547.         if (!DisplayFrameRate(&count, &extents[0]))
  548.         return FALSE;
  549.     for (;count;--count)
  550.         myglobs.view->ForceUpdate(extents[count-1].x1, extents[count-1].y1,
  551.                       extents[count-1].x2, extents[count-1].y2);
  552.     /*
  553.      * Update the window
  554.      */
  555.     rval = myglobs.dev->Update();
  556.     if (rval != D3DRM_OK) {
  557.         Msg("Updating device failed.\n%s", D3DAppErrorToString(rval));
  558.         return FALSE;
  559.     }
  560.     /*
  561.      * Blt or flip the back buffer to the front buffer.  If this fails,
  562.      * don't report an error.
  563.      */
  564.     D3DAppShowBackBuffer(myglobs.bResized ? D3DAPP_SHOWALL : NULL);
  565.  
  566.     /*
  567.      * Reset the resize flag
  568.      */
  569.         myglobs.bResized = FALSE;
  570.     }
  571.     return TRUE;
  572. }
  573.  
  574. /*
  575.  * AppPause
  576.  * Pause and unpause the application
  577.  */
  578. static BOOL
  579. AppPause(BOOL f)
  580. {
  581.     /*
  582.      * Flip to the GDI surface and halt rendering
  583.      */
  584.     if (!D3DAppPause(f))
  585.     return FALSE;
  586.     /*
  587.      * When returning from a pause, reset the frame rate count
  588.      */
  589.     if (!f) {
  590.         ResetFrameRate();
  591.     myglobs.bResized = TRUE;
  592.     }
  593.     return TRUE;
  594. }
  595.  
  596. /*
  597.  * RestoreSurfaces
  598.  * Restores any lost surfaces.  Returns TRUE if all surfaces are not lost and
  599.  * FALSE if one or more surfaces is lost and can not be restored at the
  600.  * moment.
  601.  */
  602. static BOOL
  603. RestoreSurfaces()
  604. {
  605.     HRESULT d3drval;
  606.  
  607.     /*
  608.      * Have D3DApp check all the surfaces it's in charge of
  609.      */
  610.     if (!D3DAppCheckForLostSurfaces()) {
  611.             return FALSE;
  612.     }
  613.     /*
  614.      * Check frame rate and info surfaces and re-write them if they
  615.      * were lost.
  616.      */
  617.     if (myglobs.lpFrameRateBuffer->IsLost() == DDERR_SURFACELOST) {
  618.         d3drval = myglobs.lpFrameRateBuffer->Restore();
  619.         if (d3drval != DD_OK) {
  620.             return FALSE;
  621.         }
  622.     if (!WriteFrameRateBuffer(0.0f, 0))
  623.         return FALSE;
  624.     }
  625.     if (myglobs.lpInfoBuffer->IsLost() == DDERR_SURFACELOST) {
  626.         d3drval = myglobs.lpInfoBuffer->Restore();
  627.         if (d3drval != DD_OK) {
  628.             return FALSE;
  629.         }
  630.     if (!WriteInfoBuffer())
  631.         return FALSE;
  632.     }
  633.     return TRUE;
  634. }
  635.  
  636.  
  637. /*************************************************************************
  638.   Windows message handlers
  639.  *************************************************************************/
  640. /*
  641.  * AppAbout
  642.  * About box message handler
  643.  */
  644. BOOL
  645. FAR PASCAL AppAbout(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  646. {
  647.   switch (msg)
  648.   {
  649.     case WM_COMMAND:
  650.       if (LOWORD(wParam) == IDOK)
  651.         EndDialog(hwnd, TRUE);
  652.       break;
  653.  
  654.     case WM_INITDIALOG:
  655.       return TRUE;
  656.   }
  657.   return FALSE;
  658. }
  659.  
  660. /*
  661.  * WindowProc
  662.  * Main window message handler.
  663.  */
  664. long
  665. FAR PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam,
  666.                LPARAM lParam )
  667. {
  668.     int i;
  669.     BOOL bStop;
  670.     LRESULT lresult;
  671.  
  672.     /*
  673.      * Give D3DApp an opportunity to process any messages it MUST see in order
  674.      * to perform it's function.
  675.      */
  676.     if (!D3DAppWindowProc(&bStop, &lresult, hWnd, message, wParam, lParam)) {
  677.     ReportD3DAppError();
  678.     CleanUpAndPostQuit();
  679.     return 0;
  680.     }
  681.     /* 
  682.      * If bStop is set by D3DApp, the app should not process the message but
  683.      * return lresult.
  684.      */
  685.     if (bStop)
  686.     return lresult;
  687.  
  688.     if (!d3dapp || !d3dapp->bRenderingIsOK) {
  689.     return DefWindowProc(hWnd, message, wParam, lParam);
  690.     }
  691.  
  692.     switch( message ) {
  693.     case WM_LBUTTONDOWN:
  694.     case WM_LBUTTONUP:
  695.     case WM_RBUTTONDOWN:
  696.     case WM_RBUTTONUP:
  697.     case WM_MOUSEMOVE:
  698.         /*
  699.          * Record the mouse state for ReadMouse
  700.          */
  701.         myglobs.mouse_buttons = wParam;
  702.         myglobs.mouse_x = LOWORD(lParam);
  703.         myglobs.mouse_y = HIWORD(lParam);
  704.         break;
  705.         case WM_ENTERMENULOOP:
  706.             AppPause(TRUE);
  707.             break;
  708.         case WM_EXITMENULOOP:
  709.             AppPause(FALSE);
  710.             break;
  711.         case WM_DESTROY:
  712.             myglobs.hWndMain = NULL;
  713.             CleanUpAndPostQuit();
  714.             break;
  715.         case WM_INITMENUPOPUP:
  716.         /*
  717.              * Check and enable the appropriate menu items
  718.          */
  719.             CheckMenuItem((HMENU)wParam, MENU_STEP, (myglobs.bSingleStepMode) ? MF_CHECKED : MF_UNCHECKED);
  720.             EnableMenuItem((HMENU)wParam, MENU_GO, (myglobs.bSingleStepMode) ? MF_ENABLED : MF_GRAYED);
  721.         EnableMenuItem((HMENU)wParam, MENU_PHONG, MF_GRAYED);
  722.         if (!myglobs.bConstRenderQuality) {
  723.         CheckMenuItem((HMENU)wParam, MENU_LIGHTING, (myglobs.RenderQuality & D3DRMLIGHT_MASK) == D3DRMLIGHT_ON ? MF_CHECKED : MF_GRAYED);
  724.         CheckMenuItem((HMENU)wParam, MENU_FLAT, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_FLAT ? MF_CHECKED : MF_UNCHECKED);
  725.         CheckMenuItem((HMENU)wParam, MENU_GOURAUD, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_GOURAUD ? MF_CHECKED : MF_UNCHECKED);
  726.         CheckMenuItem((HMENU)wParam, MENU_PHONG, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_PHONG ? MF_CHECKED : MF_UNCHECKED);
  727.         EnableMenuItem((HMENU)wParam, MENU_PHONG, MF_GRAYED);
  728.         CheckMenuItem((HMENU)wParam, MENU_POINT, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_POINTS ? MF_CHECKED : MF_UNCHECKED);
  729.         CheckMenuItem((HMENU)wParam, MENU_WIREFRAME, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_WIREFRAME ? MF_CHECKED : MF_UNCHECKED);
  730.         CheckMenuItem((HMENU)wParam, MENU_SOLID, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_SOLID ? MF_CHECKED : MF_UNCHECKED);
  731.         } else {
  732.         EnableMenuItem((HMENU)wParam, MENU_LIGHTING, MF_GRAYED);
  733.         EnableMenuItem((HMENU)wParam, MENU_FLAT, MF_GRAYED);
  734.         EnableMenuItem((HMENU)wParam, MENU_GOURAUD, MF_GRAYED);
  735.         EnableMenuItem((HMENU)wParam, MENU_PHONG, MF_GRAYED);
  736.         EnableMenuItem((HMENU)wParam, MENU_POINT, MF_GRAYED);
  737.         EnableMenuItem((HMENU)wParam, MENU_WIREFRAME, MF_GRAYED);
  738.         EnableMenuItem((HMENU)wParam, MENU_SOLID, MF_GRAYED);
  739.         }
  740.             if (!myglobs.bNoTextures && d3dapp->ThisDriver.bDoesTextures) {
  741.         CheckMenuItem((HMENU)wParam, MENU_POINT_FILTER, (myglobs.TextureQuality == D3DRMTEXTURE_NEAREST) ? MF_CHECKED : MF_UNCHECKED);
  742.         CheckMenuItem((HMENU)wParam, MENU_LINEAR_FILTER, (myglobs.TextureQuality == D3DRMTEXTURE_LINEAR) ? MF_CHECKED : MF_UNCHECKED);
  743.         } else {
  744.         EnableMenuItem((HMENU)wParam, MENU_POINT_FILTER, MF_GRAYED);
  745.         EnableMenuItem((HMENU)wParam, MENU_LINEAR_FILTER, MF_GRAYED);
  746.         }
  747.             CheckMenuItem((HMENU)wParam, MENU_DITHERING, (myglobs.bDithering) ? MF_CHECKED : MF_UNCHECKED);
  748.             CheckMenuItem((HMENU)wParam, MENU_ANTIALIAS, (myglobs.bAntialiasing) ? MF_CHECKED : MF_UNCHECKED);
  749.             EnableMenuItem((HMENU)wParam, MENU_ANTIALIAS, MF_GRAYED);
  750.         if (d3dapp->bIsPrimary) {
  751.         CheckMenuItem((HMENU)wParam, MENU_FULLSCREEN, d3dapp->bFullscreen ? MF_CHECKED : MF_UNCHECKED);
  752.         EnableMenuItem((HMENU)wParam, MENU_FULLSCREEN, d3dapp->bFullscreen && !d3dapp->ThisDriver.bCanDoWindow ? MF_GRAYED : MF_ENABLED);
  753.         EnableMenuItem((HMENU)wParam, MENU_NEXT_MODE, (!d3dapp->bFullscreen) ? MF_GRAYED : MF_ENABLED);
  754.         EnableMenuItem((HMENU)wParam, MENU_PREVIOUS_MODE, (!d3dapp->bFullscreen) ? MF_GRAYED : MF_ENABLED);
  755.         } else {
  756.         EnableMenuItem((HMENU)wParam, MENU_FULLSCREEN, MF_GRAYED);
  757.         EnableMenuItem((HMENU)wParam, MENU_NEXT_MODE, MF_GRAYED);
  758.         EnableMenuItem((HMENU)wParam, MENU_PREVIOUS_MODE, MF_GRAYED);
  759.         }
  760.         for (i = 0; i < d3dapp->NumModes; i++) {
  761.         CheckMenuItem((HMENU)wParam, MENU_FIRST_MODE + i, (i == d3dapp->CurrMode) ? MF_CHECKED : MF_UNCHECKED);
  762.         EnableMenuItem((HMENU)wParam, MENU_FIRST_MODE + i, (d3dapp->Mode[i].bThisDriverCanDo) ? MF_ENABLED : MF_GRAYED);
  763.         }
  764.             for (i = 0; i < d3dapp->NumDrivers; i++) {
  765.                 CheckMenuItem((HMENU)wParam, MENU_FIRST_DRIVER + i, (i == d3dapp->CurrDriver) ? MF_CHECKED : MF_UNCHECKED);
  766.             }
  767.             break;
  768.         case WM_COMMAND:
  769.             switch(LOWORD(wParam)) {
  770.                 case MENU_ABOUT:
  771.                     AppPause(TRUE);
  772.                     DialogBox(myglobs.hInstApp, "AppAbout", myglobs.hWndMain, (DLGPROC)AppAbout);
  773.                     AppPause(FALSE);
  774.                     break;
  775.                 case MENU_EXIT:
  776.                 CleanUpAndPostQuit();
  777.                 break;
  778.                 case MENU_STEP:
  779.             /*
  780.              * Begin single step more or draw a frame if in single
  781.              * step mode
  782.              */
  783.                     if (!myglobs.bSingleStepMode) {
  784.                         myglobs.bSingleStepMode = TRUE;
  785.                         myglobs.bDrawAFrame = TRUE;
  786.                     } else if (!myglobs.bDrawAFrame) {
  787.                         myglobs.bDrawAFrame = TRUE;
  788.                     }
  789.                     break;
  790.                 case MENU_GO:
  791.             /*
  792.              * Exit single step mode
  793.              */
  794.                     if (myglobs.bSingleStepMode) {
  795.                         myglobs.bSingleStepMode = FALSE;
  796.                         ResetFrameRate();
  797.                     }
  798.                     break;
  799.                 case MENU_STATS:
  800.             /*
  801.              * Toggle output of frame rate and window info
  802.              */
  803.                     if ((myglobs.bShowFrameRate) && (myglobs.bShowInfo)) {
  804.                         myglobs.bShowFrameRate = FALSE;
  805.                         myglobs.bShowInfo = FALSE;
  806.                         break;
  807.                     }
  808.                     if ((!myglobs.bShowFrameRate) && (!myglobs.bShowInfo)) {
  809.                         myglobs.bShowFrameRate = TRUE;
  810.                         break;
  811.                     }
  812.                     myglobs.bShowInfo = TRUE;
  813.                     break;
  814.             case MENU_FULLSCREEN:
  815.             if (d3dapp->bFullscreen) {
  816.             /*
  817.              * Return to a windowed mode.  Let D3DApp decide which
  818.              * D3D driver to use in case this one cannot render to
  819.              * the Windows display depth
  820.              */
  821.             if (!D3DAppWindow(D3DAPP_YOUDECIDE, D3DAPP_YOUDECIDE)) {
  822.                 ReportD3DAppError();
  823.                 CleanUpAndPostQuit();
  824.                 break;
  825.             }
  826.             } else {
  827.             /*
  828.              * Enter the current fullscreen mode.  D3DApp may
  829.              * resort to another mode if this driver cannot do
  830.              * the currently selected mode.
  831.              */
  832.             if (!D3DAppFullscreen(d3dapp->CurrMode)) {
  833.                 ReportD3DAppError();
  834.                 CleanUpAndPostQuit();
  835.                 break;
  836.             }
  837.             }
  838.                     break;
  839.         /*
  840.          * Lighting toggle
  841.          */
  842.         case MENU_LIGHTING:
  843.             myglobs.RenderQuality ^= D3DRMLIGHT_ON;
  844.             SetRenderState();
  845.             break;
  846.         /*
  847.          * Fill mode selection
  848.          */
  849.         case MENU_POINT:
  850.             myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_POINTS;
  851.             SetRenderState();
  852.             break;
  853.         case MENU_WIREFRAME:
  854.             myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_WIREFRAME;
  855.             SetRenderState();
  856.             break;
  857.         case MENU_SOLID:
  858.             myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_SOLID;
  859.             SetRenderState();
  860.             break;
  861.         /*
  862.          * Shade mode selection
  863.          */
  864.         case MENU_FLAT:
  865.             myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_FLAT;
  866.             SetRenderState();
  867.             break;
  868.         case MENU_GOURAUD:
  869.             myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_GOURAUD;
  870.             SetRenderState();
  871.             break;
  872.         case MENU_PHONG:
  873.             myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_PHONG;
  874.             SetRenderState();
  875.             break;
  876.  
  877.         case MENU_DITHERING:
  878.             myglobs.bDithering = !myglobs.bDithering;
  879.             SetRenderState();
  880.             break;
  881.         case MENU_ANTIALIAS:
  882.             myglobs.bAntialiasing = !myglobs.bAntialiasing;
  883.             SetRenderState();
  884.             break;
  885.         /*
  886.          * Texture filter selection
  887.          */
  888.         case MENU_POINT_FILTER:
  889.             if (myglobs.TextureQuality == D3DRMTEXTURE_NEAREST)
  890.             break;
  891.             myglobs.TextureQuality = D3DRMTEXTURE_NEAREST;
  892.             SetRenderState();
  893.             break;
  894.         case MENU_LINEAR_FILTER:
  895.             if (myglobs.TextureQuality == D3DRMTEXTURE_LINEAR)
  896.             break;
  897.             myglobs.TextureQuality = D3DRMTEXTURE_LINEAR;
  898.             SetRenderState();
  899.             break;
  900.         case MENU_NEXT_MODE:
  901.             /*
  902.              * Enter the next usable fullscreen mode
  903.              */
  904.             i = d3dapp->CurrMode;
  905.             do {
  906.             ++i;
  907.             if (i >= d3dapp->NumModes)
  908.                 i = 0;
  909.             if (!d3dapp->Mode[i].bThisDriverCanDo)
  910.                 continue;
  911.             else {
  912.                 if (!D3DAppFullscreen(i)) {
  913.                 ReportD3DAppError();
  914.                 CleanUpAndPostQuit();
  915.                 }
  916.                 break;
  917.             }
  918.             } while(i != d3dapp->CurrMode);
  919.             break;
  920.         case MENU_PREVIOUS_MODE:
  921.             /*
  922.              * Enter the previous usable fullscreen mode
  923.              */
  924.             i = d3dapp->CurrMode;
  925.             do {
  926.             --i;
  927.             if (i < 0)
  928.                 i = d3dapp->NumModes - 1;
  929.             if (!d3dapp->Mode[i].bThisDriverCanDo)
  930.                 continue;
  931.             else {
  932.                 if (!D3DAppFullscreen(i)) {
  933.                 ReportD3DAppError();
  934.                 CleanUpAndPostQuit();
  935.                 }
  936.                 break;
  937.             }
  938.             } while(i != d3dapp->CurrMode);
  939.                     break;
  940.             }
  941.             if (   LOWORD(wParam) >= MENU_FIRST_DRIVER
  942.         && LOWORD(wParam) < MENU_FIRST_DRIVER + D3DAPP_MAXD3DDRIVERS
  943.         && d3dapp->CurrDriver != LOWORD(wParam) - MENU_FIRST_DRIVER) {
  944.         /*
  945.          * Change the D3D driver
  946.          */
  947.         if (!D3DAppChangeDriver(LOWORD(wParam) - MENU_FIRST_DRIVER,
  948.                     NULL)) {
  949.             ReportD3DAppError();
  950.             CleanUpAndPostQuit();
  951.         }
  952.             }
  953.             if (   LOWORD(wParam) >= MENU_FIRST_MODE
  954.         && LOWORD(wParam) < MENU_FIRST_MODE+100) {
  955.         /*
  956.          * Switch to the selected fullscreen mode
  957.          */
  958.         if (!D3DAppFullscreen(LOWORD(wParam) - MENU_FIRST_MODE)) {
  959.             ReportD3DAppError();
  960.             CleanUpAndPostQuit();
  961.         }
  962.             }
  963.             if (   LOWORD(wParam) >= MENU_FIRST_DDDRIVER
  964.         && LOWORD(wParam) < MENU_FIRST_DDDRIVER + D3DAPP_MAXDDDRIVERS
  965.         && myglobs.CurrDDDriver != LOWORD(wParam) - MENU_FIRST_DDDRIVER) {
  966.         /*
  967.          * Change the DD driver
  968.          */
  969.         DestroyD3DApp();
  970.         myglobs.CurrDDDriver = LOWORD(wParam) - MENU_FIRST_DDDRIVER;
  971.         SetWindowPos(myglobs.hWndMain, HWND_NOTOPMOST, 0, 0, START_WIN_SIZE, START_WIN_SIZE, SWP_NOMOVE | SWP_SHOWWINDOW);
  972.         if (!CreateD3DApp(myglobs.lpCmdLine))
  973.             return FALSE;
  974.             }
  975.         /*
  976.          * Whenever we receive a command in single step mode, draw a frame
  977.          */
  978.         if (myglobs.bSingleStepMode)
  979.         myglobs.bDrawAFrame = TRUE;
  980.             return 0L;
  981.     }
  982.     return DefWindowProc(hWnd, message, wParam, lParam);
  983. }
  984.  
  985. /****************************************************************************/
  986. /*                          Additional Functions                            */
  987. /****************************************************************************/
  988. /*
  989.  * ReadMouse
  990.  * Returns the mouse status for interaction with sample code
  991.  */
  992. void
  993. ReadMouse(int* b, int* x, int* y)
  994. {
  995.     *b = myglobs.mouse_buttons;
  996.     *x = myglobs.mouse_x;
  997.     *y = myglobs.mouse_y;
  998. }
  999.  
  1000. /*
  1001.  * SetRenderState
  1002.  * Set the render quality, dither toggle and shade info if any of them has
  1003.  * changed
  1004.  */
  1005. BOOL
  1006. SetRenderState(void)
  1007. {
  1008.     HRESULT rval;
  1009.     /*
  1010.      * Set the number of buffers so D3DRM can keep track of extents properly
  1011.      */
  1012.     rval = myglobs.dev->SetBufferCount(d3dapp->bFullscreen &&
  1013.                        d3dapp->bBackBufferInVideo ? 2 : 1);
  1014.     if (rval != D3DRM_OK) {
  1015.     Msg("Setting the buffer count failed.\n%s", D3DAppErrorToString(rval));
  1016.     return FALSE;
  1017.     }
  1018.     /*
  1019.      * Set the render quality (light toggle, fill mode, shade mode)
  1020.      */
  1021.     if (myglobs.dev->GetQuality() != myglobs.RenderQuality) {
  1022.     rval = myglobs.dev->SetQuality(myglobs.RenderQuality);
  1023.     if (rval != D3DRM_OK) {
  1024.         Msg("Setting the render quality failed.\n%s",
  1025.         D3DAppErrorToString(rval));
  1026.         return FALSE;
  1027.     }
  1028.     }
  1029.     /*
  1030.      * Set dithering toggle
  1031.      */
  1032.     if (myglobs.dev->GetDither() != myglobs.bDithering) {
  1033.     rval = myglobs.dev->SetDither(myglobs.bDithering);
  1034.     if (rval != D3DRM_OK) {
  1035.         Msg("Setting dither mode failed.\n%s", D3DAppErrorToString(rval));
  1036.         return FALSE;
  1037.     }
  1038.     }
  1039.     /*
  1040.      * Set the texture quality (point or linear filtering)
  1041.      */
  1042.     if (myglobs.dev->GetTextureQuality() != myglobs.TextureQuality) {
  1043.     rval = myglobs.dev->SetTextureQuality(myglobs.TextureQuality);
  1044.     if (rval != D3DRM_OK) {
  1045.         Msg("Setting texture quality failed.\n%s",
  1046.         D3DAppErrorToString(rval));
  1047.         return FALSE;
  1048.     }
  1049.     }
  1050.     /*
  1051.      * Set shade info based on current bits per pixel
  1052.      */
  1053.     switch (d3dapp->ThisMode.bpp) {
  1054.     case 1:
  1055.         if (FAILED(myglobs.dev->SetShades(4)))
  1056.         goto shades_error;
  1057.         if (FAILED(lpD3DRM->SetDefaultTextureShades(4)))
  1058.         goto shades_error;
  1059.         break;
  1060.     case 16:
  1061.         if (FAILED(myglobs.dev->SetShades(32)))
  1062.         goto shades_error;
  1063.         if (FAILED(lpD3DRM->SetDefaultTextureColors(64)))
  1064.         goto shades_error;
  1065.         if (FAILED(lpD3DRM->SetDefaultTextureShades(32)))
  1066.         goto shades_error;
  1067.         break;
  1068.     case 24:
  1069.     case 32:
  1070.         if (FAILED(myglobs.dev->SetShades(256)))
  1071.         goto shades_error;
  1072.         if (FAILED(lpD3DRM->SetDefaultTextureColors(64)))
  1073.         goto shades_error;
  1074.         if (FAILED(lpD3DRM->SetDefaultTextureShades(256)))
  1075.         goto shades_error;
  1076.         break;
  1077.     }
  1078.     return TRUE;
  1079. shades_error:
  1080.     Msg("A failure occurred while setting color shade information.\n");
  1081.     return FALSE;
  1082. }
  1083.  
  1084. /****************************************************************************/
  1085. /*          Initialization, error reporting and release functions.          */
  1086. /****************************************************************************/
  1087. /*
  1088.  * InitGlobals
  1089.  * Called once at program initialization to initialize global variables.
  1090.  */
  1091. static void
  1092. InitGlobals(void)
  1093. {
  1094.     d3dapp = NULL;
  1095.     memset(&myglobs, 0, sizeof(myglobs));
  1096.     myglobs.bShowFrameRate = TRUE;
  1097.     myglobs.bShowInfo = TRUE;
  1098.     myglobs.RenderQuality = D3DRMLIGHT_ON | D3DRMFILL_SOLID |
  1099.                 D3DRMSHADE_GOURAUD;
  1100.     myglobs.TextureQuality = D3DRMTEXTURE_NEAREST;
  1101. }
  1102.  
  1103. /*
  1104.  * CleanUpAndPostQuit
  1105.  * Release all D3D objects, post a quit message and set the bQuit flag
  1106.  */
  1107. void
  1108. CleanUpAndPostQuit(void)
  1109. {
  1110.     if (myglobs.bQuit)
  1111.     return;
  1112.     if (!D3DAppDestroy())
  1113.     ReportD3DAppError();
  1114.     RELEASE(myglobs.scene);
  1115.     RELEASE(myglobs.camera);
  1116.     RELEASE(lpD3DRM);
  1117.     myglobs.bQuit = TRUE;
  1118.     PostQuitMessage( 0 );
  1119. }
  1120.  
  1121. /*
  1122.  * ReportD3DAppError
  1123.  * Reports an error during a d3d app call.
  1124.  */
  1125. void
  1126. ReportD3DAppError(void)
  1127. {
  1128.     Msg("%s", D3DAppLastErrorString());
  1129. }
  1130.  
  1131. /* Msg
  1132.  * Message output for error notification.
  1133.  */
  1134. void __cdecl
  1135. Msg( LPSTR fmt, ... )
  1136. {
  1137.     char buff[256];
  1138.     va_list args;
  1139.     
  1140.     va_start(args, fmt);
  1141.     wvsprintf(buff, fmt, args);
  1142.     va_end(args);
  1143.     
  1144.     lstrcat(buff, "\r\n");
  1145.     AppPause(TRUE);
  1146.     if (d3dapp && d3dapp->bFullscreen)
  1147.     SetWindowPos(myglobs.hWndMain, HWND_NOTOPMOST, 0, 0, 0, 0,
  1148.              SWP_NOSIZE | SWP_NOMOVE);
  1149.     MessageBox( NULL, buff, "D3D Example Message", MB_OK );
  1150.     if (d3dapp && d3dapp->bFullscreen)
  1151.     SetWindowPos(myglobs.hWndMain, HWND_TOPMOST, 0, 0, 0, 0,
  1152.              SWP_NOSIZE | SWP_NOMOVE);
  1153.     AppPause(FALSE);
  1154. }
  1155.  
  1156. /*
  1157.  * D3DRMErrorToString
  1158.  * Allows the samples to return error strings.
  1159.  */
  1160. char*
  1161. D3DRMErrorToString(HRESULT error)
  1162. {
  1163.     return D3DAppErrorToString(error);
  1164. }
  1165.