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