home *** CD-ROM | disk | FTP | other *** search
/ NEXT Generation 27 / NEXT27.iso / pc / demos / emperor / dx3.exe / SDK / SAMPLES / MISC / RMMAIN.CPP < prev    next >
C/C++ Source or Header  |  1996-08-28  |  36KB  |  1,000 lines

  1. /*
  2.  *  Copyright (C) 1995, 1996 Microsoft Corporation. All Rights Reserved.
  3.  *
  4.  *  File: rmmain.cpp
  5.  *
  6.  *  Each of the Direct3D retained mode (D3DRM) samples must be linked with
  7.  *  this file.  It contains the code which allows them to run in the Windows
  8.  *  environment.
  9.  *
  10.  *  A window is created using the rmmain.res which allows the user to select
  11.  *  the Direct3D driver to use and change the render options.
  12.  *
  13.  *  Individual samples are executed through two functions, BuildScene and
  14.  *  OverrideDefaults, as described in rmdemo.h.  Samples can also read
  15.  *  mouse input via ReadMouse.
  16.  */
  17.  
  18. #define INITGUID
  19.  
  20. #include <windows.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <malloc.h>
  24. #include <math.h>
  25. #include <direct.h>
  26. #include <d3drmwin.h>
  27. #include "rmdemo.h"             /* prototypes for functions to commumicate
  28.                                    with each sample */
  29. #include "rmmain.h"             /* defines constants used in rmmain.rc */
  30. #include "rmerror.h"            /* prototypes for error reporting: error.c */
  31.  
  32. #define MAX_DRIVERS 5           /* maximum D3D drivers we ever expect to find */
  33.  
  34. /* 
  35.  * GLOBAL VARIABLES
  36.  */
  37. LPDIRECT3DRM lpD3DRM;           /* Direct3DRM object */
  38. LPDIRECTDRAWCLIPPER lpDDClipper;/* DirectDrawClipper object */
  39.  
  40. struct _myglobs {
  41.     LPDIRECT3DRMDEVICE dev;     /* Direct3DRM device */
  42.     LPDIRECT3DRMVIEWPORT view;  /* Direct3DRM viewport through which we view
  43.                                    the scene */
  44.     LPDIRECT3DRMFRAME scene;    /* Master frame in which others are placed */
  45.     LPDIRECT3DRMFRAME camera;   /* Frame describing the users POV */
  46.  
  47.     GUID DriverGUID[MAX_DRIVERS];     /* GUIDs of the available D3D drivers */
  48.     char DriverName[MAX_DRIVERS][50]; /* names of the available D3D drivers */
  49.     int  NumDrivers;                  /* number of available D3D drivers */
  50.     int  CurrDriver;                  /* number of D3D driver currently
  51.                                          being used */
  52.  
  53.     D3DRMRENDERQUALITY RenderQuality;   /* current shade mode, fill mode and
  54.                                            lighting state */
  55.     D3DRMTEXTUREQUALITY TextureQuality; /* current texture interpolation */
  56.     BOOL bDithering;                    /* is dithering on? */
  57.     BOOL bAntialiasing;                 /* is antialiasing on? */
  58.  
  59.     BOOL bQuit;                 /* program is about to terminate */
  60.     BOOL bInitialized;          /* all D3DRM objects have been initialized */
  61.     BOOL bMinimized;            /* window is minimized */
  62.     BOOL bSingleStepMode;       /* render one frame at a time */
  63.     BOOL bDrawAFrame;           /* render on this pass of the main loop */
  64.     BOOL bNoTextures;           /* this sample doesn't use any textures */
  65.     BOOL bConstRenderQuality;   /* this sample is not constructed with
  66.                                    MeshBuilders and so the RenderQuality
  67.                                    cannot be changed */
  68.  
  69.     int BPP;                    /* bit depth of the current display mode */
  70.  
  71.     int mouse_buttons;          /* mouse button state */
  72.     int mouse_x;                /* mouse cursor x position */
  73.     int mouse_y;                /* mouse cursor y position */
  74. } myglobs;
  75.  
  76. /*
  77.  * PROTOTYPES
  78.  */
  79. static HWND InitApp(HINSTANCE, int);
  80. static void InitGlobals(void);
  81. long FAR PASCAL WindowProc(HWND, UINT, WPARAM, LPARAM);
  82. static BOOL CreateDevAndView(LPDIRECTDRAWCLIPPER lpDDClipper, int driver, int width, int height);
  83. static BOOL RenderLoop(void);
  84. static void CleanUpAndPostQuit(void);
  85. static BOOL SetRenderState(void);
  86. static BOOL EnumDevices(HWND win);
  87. extern "C" void ReadMouse(int*, int*, int*);
  88.  
  89. /****************************************************************************/
  90. /*                               WinMain                                    */
  91. /****************************************************************************/
  92. /*
  93.  * Initializes the application then enters a message loop which renders the
  94.  * scene until a quit message is received.
  95.  */
  96. int PASCAL
  97. WinMain (HINSTANCE this_inst, HINSTANCE prev_inst, LPSTR cmdline, int cmdshow)
  98. {
  99.     HWND    hwnd;
  100.     MSG     msg;
  101.     HACCEL  accel;
  102.     int     failcount = 0;  /* number of times RenderLoop has failed */
  103.  
  104.     prev_inst;
  105.     cmdline;
  106.  
  107.     /*
  108.      * Create the window and initialize all objects needed to begin rendering
  109.      */
  110.     if (!(hwnd = InitApp(this_inst, cmdshow)))
  111.         return 1;
  112.  
  113.     accel = LoadAccelerators(this_inst, "AppAccel");
  114.  
  115.     while (!myglobs.bQuit) {
  116.         /* 
  117.          * Monitor the message queue until there are no pressing
  118.          * messages
  119.          */
  120.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  121.             if (msg.message == WM_QUIT) {
  122.                 CleanUpAndPostQuit();
  123.                 break;
  124.             }
  125.             if (!TranslateAccelerator(msg.hwnd, accel, &msg)) {
  126.                 TranslateMessage(&msg);
  127.                 DispatchMessage(&msg);
  128.             }
  129.         }
  130.         if (myglobs.bQuit)
  131.             break;
  132.         /* 
  133.          * If the app is not minimized, not about to quit and D3DRM has
  134.          * been initialized, we can render
  135.          */
  136.         if (!myglobs.bMinimized && !myglobs.bQuit && myglobs.bInitialized) {
  137.             /*
  138.              * If were are not in single step mode or if we are and the
  139.              * bDrawAFrame flag is set, render one frame
  140.              */
  141.             if (!(myglobs.bSingleStepMode && !myglobs.bDrawAFrame)) {
  142.                 /* 
  143.                  * Attempt to render a frame, if it fails, take a note.  If
  144.                  * rendering fails more than twice, abort execution.
  145.                  */
  146.                 if (!RenderLoop())
  147.                     ++failcount;
  148.                 if (failcount > 2) {
  149.                     Msg("Rendering has failed too many times.  Aborting execution.\n");
  150.                     CleanUpAndPostQuit();
  151.                     break;
  152.                 }
  153.             }
  154.             /*
  155.              * Reset the bDrawAFrame flag if we are in single step mode
  156.              */
  157.             if (myglobs.bSingleStepMode)
  158.                 myglobs.bDrawAFrame = FALSE;
  159.         } else {
  160.             WaitMessage();
  161.         }
  162.     }
  163.     DestroyWindow(hwnd);
  164.     return msg.wParam;
  165. }
  166.  
  167. /****************************************************************************/
  168. /*                   Initialization and object creation                     */
  169. /****************************************************************************/
  170. /*
  171.  * InitApp
  172.  * Creates window and initializes all objects neccessary to begin rendering
  173.  */
  174. static HWND
  175. InitApp(HINSTANCE this_inst, int cmdshow)
  176. {
  177.     HWND win;
  178.     HDC hdc;
  179.     DWORD flags;
  180.     WNDCLASS wc;
  181.     Defaults defaults;
  182.     HRESULT rval;
  183.     RECT rc;
  184.  
  185.     /*
  186.      * set up and registers the window class
  187.      */
  188.     wc.style = CS_HREDRAW | CS_VREDRAW;
  189.     wc.lpfnWndProc = WindowProc;
  190.     wc.cbClsExtra = 0;
  191.     wc.cbWndExtra = sizeof(DWORD);
  192.     wc.hInstance = this_inst;
  193.     wc.hIcon = LoadIcon(this_inst, "AppIcon");
  194.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  195.     wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  196.     wc.lpszMenuName = "AppMenu";
  197.     wc.lpszClassName = "D3DRM Example";
  198.     if (!RegisterClass(&wc))
  199.         return FALSE;
  200.     /*
  201.      * Initialize the global variables and allow the sample code to override
  202.      * some of these default settings.
  203.      */
  204.     InitGlobals();
  205.     defaults.bNoTextures = myglobs.bNoTextures;
  206.     defaults.bConstRenderQuality = myglobs.bConstRenderQuality;
  207.     defaults.bResizingDisabled = FALSE;
  208.     lstrcpy(defaults.Name, "D3DRM Example");
  209.     OverrideDefaults(&defaults);
  210.     myglobs.bNoTextures = defaults.bNoTextures;
  211.     myglobs.bConstRenderQuality = defaults.bConstRenderQuality;
  212.     /*
  213.      * Create the window
  214.      */
  215.     if (defaults.bResizingDisabled)
  216.         flags =  WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
  217.                  WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
  218.     else
  219.         flags = WS_OVERLAPPEDWINDOW;
  220.     win =
  221.         CreateWindow
  222.         (   "D3DRM Example",            /* class */
  223.             defaults.Name,              /* caption */
  224.             flags,                      /* style */
  225.             CW_USEDEFAULT,              /* init. x pos */
  226.             CW_USEDEFAULT,              /* init. y pos */
  227.             300,                        /* init. x size */
  228.             300,                        /* init. y size */
  229.             NULL,                       /* parent window */
  230.             NULL,                       /* menu handle */
  231.             this_inst,                  /* program handle */
  232.             NULL                        /* create parms */
  233.         );
  234.     if (!win)
  235.         return FALSE;
  236.     /*
  237.      * Record the current display BPP
  238.      */
  239.     hdc = GetDC(win);
  240.     myglobs.BPP = GetDeviceCaps(hdc, BITSPIXEL);
  241.     ReleaseDC(win, hdc);
  242.     /*
  243.      * Enumerate the D3D drivers and select one
  244.      */
  245.     if (!EnumDevices(win))
  246.         return FALSE;
  247.     /*
  248.      * Create the D3DRM object and the D3DRM window object
  249.      */
  250.     rval = Direct3DRMCreate(&lpD3DRM);
  251.     if (rval != D3DRM_OK) {
  252.         Msg("Failed to create Direct3DRM.\n%s", D3DRMErrorToString(rval));
  253.         return FALSE;
  254.     }
  255.     /*
  256.      * Create the master scene frame and camera frame
  257.      */
  258.     rval = lpD3DRM->CreateFrame(NULL, &myglobs.scene);
  259.     if (rval != D3DRM_OK) {
  260.         Msg("Failed to create the master scene frame.\n%s", D3DRMErrorToString(rval));
  261.         return FALSE;
  262.     }
  263.     rval = lpD3DRM->CreateFrame(myglobs.scene, &myglobs.camera);
  264.     if (rval != D3DRM_OK) {
  265.         Msg("Failed to create the camera's frame.\n%s", D3DRMErrorToString(rval));
  266.         return FALSE;
  267.     }
  268.     rval = myglobs.camera->SetPosition(myglobs.scene, D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0));
  269.     if (rval != D3DRM_OK) {
  270.         Msg("Failed to position the camera in the frame.\n%s", D3DRMErrorToString(rval));
  271.         return FALSE;
  272.     }
  273.     /*
  274.      * Create a clipper and associate the window with it
  275.      */
  276.     rval = DirectDrawCreateClipper(0, &lpDDClipper, NULL);
  277.     if (rval != DD_OK) {
  278.         Msg("Failed to create DirectDrawClipper");
  279.         return FALSE;
  280.     }
  281.     rval = lpDDClipper->SetHWnd(0, win);
  282.     if (rval != DD_OK) {
  283.         Msg("Failed to set hwnd on the clipper");
  284.         return FALSE;
  285.     }
  286.     /*
  287.      * Created the D3DRM device with the selected D3D driver
  288.      */
  289.     GetClientRect(win, &rc);
  290.     if (!CreateDevAndView(lpDDClipper, myglobs.CurrDriver, rc.right, rc.bottom)) {
  291.         return FALSE;
  292.     }
  293.     /*
  294.      * Create the scene to be rendered by calling this sample's BuildScene
  295.      */
  296.     if (!BuildScene(myglobs.dev, myglobs.view, myglobs.scene, myglobs.camera))
  297.         return FALSE;
  298.     /*
  299.      * Now we are ready to render
  300.      */
  301.     myglobs.bInitialized = TRUE;
  302.     /*
  303.      * Display the window
  304.      */
  305.     ShowWindow(win, cmdshow);
  306.     UpdateWindow(win);
  307.  
  308.     return win;
  309. }
  310.  
  311. /*
  312.  * CreateDevAndView
  313.  * Create the D3DRM device and viewport with the given D3D driver and of the
  314.  * specified size.
  315.  */
  316. static BOOL
  317. CreateDevAndView(LPDIRECTDRAWCLIPPER lpDDClipper, int driver, int width, int height)
  318. {
  319.     HRESULT rval;
  320.  
  321.     if (!width || !height) {
  322.         Msg("Cannot create a D3DRM device with invalid window dimensions.");
  323.         return FALSE;
  324.     }
  325.     /*
  326.      * Create the D3DRM device from this window and using the specified D3D
  327.      * driver.
  328.      */
  329.     rval = lpD3DRM->CreateDeviceFromClipper(lpDDClipper, &myglobs.DriverGUID[driver],
  330.                                         width, height, &myglobs.dev);
  331.     if (rval != D3DRM_OK) {
  332.         Msg("Failed to create the D3DRM device from the clipper.\n%s",
  333.             D3DRMErrorToString(rval));
  334.         return FALSE;
  335.     }
  336.     /*
  337.      * Create the D3DRM viewport using the camera frame.  Set the background
  338.      * depth to a large number.  The width and height may be slightly
  339.      * adjusted, so get them from the device to be sure.
  340.      */
  341.     width = myglobs.dev->GetWidth();
  342.     height = myglobs.dev->GetHeight();
  343.     rval = lpD3DRM->CreateViewport(myglobs.dev, myglobs.camera, 0, 0, width,
  344.                                    height, &myglobs.view);
  345.     if (rval != D3DRM_OK) {
  346.         Msg("Failed to create the D3DRM viewport.\n%s",
  347.             D3DRMErrorToString(rval));
  348.         RELEASE(myglobs.dev);
  349.         return FALSE;
  350.     }
  351.     rval = myglobs.view->SetBack(D3DVAL(5000.0));
  352.     if (rval != D3DRM_OK) {
  353.         Msg("Failed to set the background depth of the D3DRM viewport.\n%s",
  354.             D3DRMErrorToString(rval));
  355.         RELEASE(myglobs.dev);
  356.         RELEASE(myglobs.view);
  357.         return FALSE;
  358.     }
  359.     /*
  360.      * Set the render quality, fill mode, lighting state and color shade info
  361.      */
  362.     if (!SetRenderState())
  363.         return FALSE;
  364.     return TRUE;
  365. }
  366.  
  367. /****************************************************************************/
  368. /*                         D3D Device Enumeration                           */
  369. /****************************************************************************/
  370. /*
  371.  * BPPToDDBD
  372.  * Converts bits per pixel to a DirectDraw bit depth flag
  373.  */
  374. static DWORD
  375. BPPToDDBD(int bpp)
  376. {
  377.     switch(bpp) {
  378.         case 1:
  379.             return DDBD_1;
  380.         case 2:
  381.             return DDBD_2;
  382.         case 4:
  383.             return DDBD_4;
  384.         case 8:
  385.             return DDBD_8;
  386.         case 16:
  387.             return DDBD_16;
  388.         case 24:
  389.             return DDBD_24;
  390.         case 32:
  391.             return DDBD_32;
  392.         default:
  393.             return 0;
  394.     }
  395. }
  396.  
  397. /*
  398.  * enumDeviceFunc
  399.  * Callback function which records each usable D3D driver's name and GUID
  400.  * Chooses a driver to begin with and sets *lpContext to this starting driver
  401.  */
  402. static HRESULT
  403. WINAPI enumDeviceFunc(LPGUID lpGuid, LPSTR lpDeviceDescription, LPSTR lpDeviceName,
  404.         LPD3DDEVICEDESC lpHWDesc, LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext)
  405. {
  406.     static BOOL hardware = FALSE; /* current start driver is hardware */
  407.     static BOOL mono = FALSE;     /* current start driver is mono light */
  408.     LPD3DDEVICEDESC lpDesc;
  409.     int *lpStartDriver = (int *)lpContext;
  410.     /*
  411.      * Decide which device description we should consult
  412.      */
  413.     lpDesc = lpHWDesc->dcmColorModel ? lpHWDesc : lpHELDesc;
  414.     /*
  415.      * If this driver cannot render in the current display bit depth skip
  416.      * it and continue with the enumeration.
  417.      */
  418.     if (!(lpDesc->dwDeviceRenderBitDepth & BPPToDDBD(myglobs.BPP)))
  419.         return D3DENUMRET_OK;
  420.     /*
  421.      * Record this driver's info
  422.      */
  423.     memcpy(&myglobs.DriverGUID[myglobs.NumDrivers], lpGuid, sizeof(GUID));
  424.     lstrcpy(&myglobs.DriverName[myglobs.NumDrivers][0], lpDeviceName);
  425.     /*
  426.      * Choose hardware over software, RGB lights over mono lights
  427.      */
  428.     if (*lpStartDriver == -1) {
  429.         /*
  430.          * this is the first valid driver
  431.          */
  432.         *lpStartDriver = myglobs.NumDrivers;
  433.         hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
  434.         mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
  435.     } else if (lpDesc == lpHWDesc && !hardware) {
  436.         /*
  437.          * this driver is hardware and start driver is not
  438.          */
  439.         *lpStartDriver = myglobs.NumDrivers;
  440.         hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
  441.         mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
  442.     } else if ((lpDesc == lpHWDesc && hardware ) || (lpDesc == lpHELDesc
  443.                                                      && !hardware)) {
  444.         if (lpDesc->dcmColorModel == D3DCOLOR_MONO && !mono) {
  445.             /*
  446.              * this driver and start driver are the same type and this
  447.              * driver is mono while start driver is not
  448.              */
  449.             *lpStartDriver = myglobs.NumDrivers;
  450.             hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
  451.             mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
  452.         }
  453.     }
  454.     myglobs.NumDrivers++;
  455.     if (myglobs.NumDrivers == MAX_DRIVERS)
  456.         return (D3DENUMRET_CANCEL);
  457.     return (D3DENUMRET_OK);
  458. }
  459.  
  460. /*
  461.  * EnumDevices
  462.  * Enumerate the available D3D drivers, add them to the file menu, and choose
  463.  * one to use.
  464.  */
  465. static BOOL
  466. EnumDevices(HWND win)
  467. {
  468.     LPDIRECTDRAW lpDD;
  469.     LPDIRECT3D lpD3D;
  470.     HRESULT rval;
  471.     HMENU hmenu;
  472.     int i;
  473.  
  474.     /*
  475.      * Create a DirectDraw object and query for the Direct3D interface to use
  476.      * to enumerate the drivers.
  477.      */
  478.     rval = DirectDrawCreate(NULL, &lpDD, NULL);
  479.     if (rval != DD_OK) {
  480.         Msg("Creation of DirectDraw HEL failed.\n%s", D3DRMErrorToString(rval));
  481.         return FALSE;
  482.     }
  483.     rval = lpDD->QueryInterface(IID_IDirect3D, (void**) &lpD3D);
  484.     if (rval != DD_OK) {
  485.         Msg("Creation of Direct3D interface failed.\n%s", D3DRMErrorToString(rval));
  486.         lpDD->Release();
  487.         return FALSE;
  488.     }
  489.     /*
  490.      * Enumerate the drivers, setting CurrDriver to -1 to initialize the
  491.      * driver selection code in enumDeviceFunc
  492.      */
  493.     myglobs.CurrDriver = -1;
  494.     rval = lpD3D->EnumDevices(enumDeviceFunc, &myglobs.CurrDriver);
  495.     if (rval != DD_OK) {
  496.         Msg("Enumeration of drivers failed.\n%s", D3DRMErrorToString(rval));
  497.         return FALSE;
  498.     }
  499.     /*
  500.      * Make sure we found at least one valid driver
  501.      */
  502.     if (myglobs.NumDrivers == 0) {
  503.         Msg("Could not find a D3D driver which is compatible with this display depth");
  504.         return FALSE;
  505.     }
  506.     lpD3D->Release();
  507.     lpDD->Release();
  508.     /*
  509.      * Add the driver names to the File menu
  510.      */
  511.     hmenu = GetSubMenu(GetMenu(win), 0);
  512.     for (i = 0; i < myglobs.NumDrivers; i++) {
  513.         InsertMenu(hmenu, 5 + i, MF_BYPOSITION | MF_STRING, MENU_FIRST_DRIVER + i,
  514.                    myglobs.DriverName[i]);
  515.     }
  516.     return TRUE;
  517. }
  518.  
  519. /****************************************************************************/
  520. /*                             Render Loop                                  */
  521. /****************************************************************************/
  522. /*
  523.  * Clear the viewport, render the next frame and update the window
  524.  */
  525. static BOOL
  526. RenderLoop()
  527. {
  528.     HRESULT rval;
  529.     /*
  530.      * Tick the scene
  531.      */
  532.     rval = myglobs.scene->Move(D3DVAL(1.0));
  533.     if (rval != D3DRM_OK) {
  534.         Msg("Moving scene failed.\n%s", D3DRMErrorToString(rval));
  535.         return FALSE;
  536.     }
  537.     /* 
  538.      * Clear the viewport
  539.      */
  540.     rval = myglobs.view->Clear();
  541.     if (rval != D3DRM_OK) {
  542.         Msg("Clearing viewport failed.\n%s", D3DRMErrorToString(rval));
  543.         return FALSE;
  544.     }
  545.     /*
  546.      * Render the scene to the viewport
  547.      */
  548.     rval = myglobs.view->Render(myglobs.scene);
  549.     if (rval != D3DRM_OK) {
  550.         Msg("Rendering scene failed.\n%s", D3DRMErrorToString(rval));
  551.         return FALSE;
  552.     }
  553.     /*
  554.      * Update the window
  555.      */
  556.     rval = myglobs.dev->Update();
  557.     if (rval != D3DRM_OK) {
  558.         Msg("Updating device failed.\n%s", D3DRMErrorToString(rval));
  559.         return FALSE;
  560.     }
  561.     return TRUE;
  562. }
  563.  
  564.  
  565. /****************************************************************************/
  566. /*                    Windows Message Handlers                              */
  567. /****************************************************************************/
  568. /*
  569.  * AppAbout
  570.  * About box message handler
  571.  */
  572. BOOL
  573. FAR PASCAL AppAbout(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lParam)
  574. {
  575.   switch (msg)
  576.   {
  577.     case WM_COMMAND:
  578.       if (LOWORD(wparam) == IDOK)
  579.         EndDialog(hwnd, TRUE);
  580.       break;
  581.  
  582.     case WM_INITDIALOG:
  583.       return TRUE;
  584.   }
  585.   return FALSE;
  586. }
  587.  
  588. /*
  589.  * WindowProc
  590.  * Main window message handler
  591.  */
  592. LONG FAR PASCAL WindowProc(HWND win, UINT msg, WPARAM wparam, LPARAM lparam)
  593. {
  594.     int i;
  595.     HRESULT rval;
  596.     RECT rc;
  597.  
  598.     switch (msg)    {
  599.         case WM_LBUTTONDOWN:
  600.         case WM_LBUTTONUP:
  601.         case WM_RBUTTONDOWN:
  602.         case WM_RBUTTONUP:
  603.         case WM_MOUSEMOVE:
  604.             /*
  605.              * Record the mouse state for ReadMouse
  606.              */
  607.             myglobs.mouse_buttons = wparam;
  608.             myglobs.mouse_x = LOWORD(lparam);
  609.             myglobs.mouse_y = HIWORD(lparam);
  610.             break;
  611.         case WM_INITMENUPOPUP:
  612.             /*
  613.              * Check and enable the appropriate menu items
  614.              */
  615.             CheckMenuItem((HMENU)wparam, MENU_STEP,(myglobs.bSingleStepMode) ? MF_CHECKED : MF_UNCHECKED);
  616.             EnableMenuItem((HMENU)wparam, MENU_GO,(myglobs.bSingleStepMode) ? MF_ENABLED : MF_GRAYED);
  617.             if (!myglobs.bConstRenderQuality) {
  618.                 CheckMenuItem((HMENU)wparam, MENU_LIGHTING, (myglobs.RenderQuality & D3DRMLIGHT_MASK) == D3DRMLIGHT_ON ? MF_CHECKED : MF_GRAYED);
  619.                 CheckMenuItem((HMENU)wparam, MENU_FLAT, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_FLAT ? MF_CHECKED : MF_UNCHECKED);
  620.                 CheckMenuItem((HMENU)wparam, MENU_GOURAUD, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_GOURAUD ? MF_CHECKED : MF_UNCHECKED);
  621.                 CheckMenuItem((HMENU)wparam, MENU_PHONG, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_PHONG ? MF_CHECKED : MF_UNCHECKED);
  622.                 EnableMenuItem((HMENU)wparam, MENU_PHONG, MF_GRAYED);
  623.                 CheckMenuItem((HMENU)wparam, MENU_POINT, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_POINTS ? MF_CHECKED : MF_UNCHECKED);
  624.                 CheckMenuItem((HMENU)wparam, MENU_WIREFRAME, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_WIREFRAME ? MF_CHECKED : MF_UNCHECKED);
  625.                 CheckMenuItem((HMENU)wparam, MENU_SOLID, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_SOLID ? MF_CHECKED : MF_UNCHECKED);
  626.             } else {
  627.                 EnableMenuItem((HMENU)wparam, MENU_LIGHTING, MF_GRAYED);
  628.                 EnableMenuItem((HMENU)wparam, MENU_FLAT, MF_GRAYED);
  629.                 EnableMenuItem((HMENU)wparam, MENU_GOURAUD, MF_GRAYED);
  630.                 EnableMenuItem((HMENU)wparam, MENU_PHONG, MF_GRAYED);
  631.                 EnableMenuItem((HMENU)wparam, MENU_POINT, MF_GRAYED);
  632.                 EnableMenuItem((HMENU)wparam, MENU_WIREFRAME, MF_GRAYED);
  633.                 EnableMenuItem((HMENU)wparam, MENU_SOLID, MF_GRAYED);
  634.             }
  635.             if (!myglobs.bNoTextures) {
  636.                 CheckMenuItem((HMENU)wparam, MENU_POINT_FILTER, (myglobs.TextureQuality == D3DRMTEXTURE_NEAREST) ? MF_CHECKED : MF_UNCHECKED);
  637.                 CheckMenuItem((HMENU)wparam, MENU_LINEAR_FILTER, (myglobs.TextureQuality == D3DRMTEXTURE_LINEAR) ? MF_CHECKED : MF_UNCHECKED);
  638.             } else {
  639.                 EnableMenuItem((HMENU)wparam, MENU_POINT_FILTER, MF_GRAYED);
  640.                 EnableMenuItem((HMENU)wparam, MENU_LINEAR_FILTER, MF_GRAYED);
  641.             }
  642.             CheckMenuItem((HMENU)wparam, MENU_DITHERING, (myglobs.bDithering) ? MF_CHECKED : MF_UNCHECKED);
  643.             CheckMenuItem((HMENU)wparam, MENU_ANTIALIAS, (myglobs.bAntialiasing) ? MF_CHECKED : MF_UNCHECKED);
  644.             EnableMenuItem((HMENU)wparam, MENU_ANTIALIAS, MF_GRAYED);
  645.             for (i = 0; i < myglobs.NumDrivers; i++) {
  646.                 CheckMenuItem((HMENU)wparam, MENU_FIRST_DRIVER + i,
  647.                        (i == myglobs.CurrDriver) ? MF_CHECKED : MF_UNCHECKED);
  648.             }
  649.             break;
  650.         case WM_COMMAND:
  651.             switch(LOWORD(wparam)) {
  652.                 case MENU_ABOUT:
  653.                     DialogBox((HINSTANCE)GetWindowLong(win, GWL_HINSTANCE),
  654.                               "AppAbout", win, (DLGPROC)AppAbout);
  655.                     break;
  656.                 case MENU_EXIT:
  657.                     CleanUpAndPostQuit();
  658.                     break;
  659.                 case MENU_STEP:
  660.                     /*
  661.                      * Begin single step more or draw a frame if in single
  662.                      * step mode
  663.                      */
  664.                     if (!myglobs.bSingleStepMode) {
  665.                         myglobs.bSingleStepMode = TRUE;
  666.                         myglobs.bDrawAFrame = TRUE;
  667.                     } else if (!myglobs.bDrawAFrame) {
  668.                         myglobs.bDrawAFrame = TRUE;
  669.                     }
  670.                     break;
  671.                 case MENU_GO:
  672.                     /*
  673.                      * Exit single step mode
  674.                      */
  675.                     myglobs.bSingleStepMode = FALSE;
  676.                     break;
  677.                 /*
  678.                  * Lighting toggle
  679.                  */
  680.                 case MENU_LIGHTING:
  681.                     myglobs.RenderQuality ^= D3DRMLIGHT_ON;
  682.                     SetRenderState();
  683.                     break;
  684.                 /*
  685.                  * Fill mode selection
  686.                  */
  687.                 case MENU_POINT:
  688.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_POINTS;
  689.                     SetRenderState();
  690.                     break;
  691.                 case MENU_WIREFRAME:
  692.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_WIREFRAME;
  693.                     SetRenderState();
  694.                     break;
  695.                 case MENU_SOLID:
  696.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_SOLID;
  697.                     SetRenderState();
  698.                     break;
  699.                 /*
  700.                  * Shade mode selection
  701.                  */
  702.                 case MENU_FLAT:
  703.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_FLAT;
  704.                     SetRenderState();
  705.                     break;
  706.                 case MENU_GOURAUD:
  707.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_GOURAUD;
  708.                     SetRenderState();
  709.                     break;
  710.                 case MENU_PHONG:
  711.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_PHONG;
  712.                     SetRenderState();
  713.                     break;
  714.  
  715.                 case MENU_DITHERING:
  716.                     myglobs.bDithering = !myglobs.bDithering;
  717.                     SetRenderState();
  718.                     break;
  719.                 case MENU_ANTIALIAS:
  720.                     myglobs.bAntialiasing = !myglobs.bAntialiasing;
  721.                     break;
  722.                 /*
  723.                  * Texture filter selection
  724.                  */
  725.                 case MENU_POINT_FILTER:
  726.                     if (myglobs.TextureQuality == D3DRMTEXTURE_NEAREST)
  727.                         break;
  728.                     myglobs.TextureQuality = D3DRMTEXTURE_NEAREST;
  729.                     SetRenderState();
  730.                     break;
  731.                 case MENU_LINEAR_FILTER:
  732.                     if (myglobs.TextureQuality == D3DRMTEXTURE_LINEAR)
  733.                         break;
  734.                     myglobs.TextureQuality = D3DRMTEXTURE_LINEAR;
  735.                     SetRenderState();
  736.                     break;
  737.                 }
  738.                 /*
  739.                  * Changing the D3D Driver
  740.                  */
  741.                 if (LOWORD(wparam) >= MENU_FIRST_DRIVER &&
  742.                     LOWORD(wparam) < MENU_FIRST_DRIVER + MAX_DRIVERS &&
  743.                     myglobs.CurrDriver != LOWORD(wparam) - MENU_FIRST_DRIVER){
  744.                         /*
  745.                          * Release the current viewport and device and create
  746.                          * the new one
  747.                          */
  748.                         RELEASE(myglobs.view);
  749.                         RELEASE(myglobs.dev);
  750.                         myglobs.CurrDriver = LOWORD(wparam)-MENU_FIRST_DRIVER;
  751.                         GetClientRect(win, &rc);
  752.                         if (!CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
  753.                                               rc.right, rc.bottom)) {
  754.                             CleanUpAndPostQuit();
  755.                         }
  756.                 }
  757.                 /*
  758.                  * Draw a frame in single step mode after ever command
  759.                  */
  760.                 myglobs.bDrawAFrame = TRUE;
  761.             break;
  762.     case WM_DESTROY:
  763.         CleanUpAndPostQuit();
  764.         break;
  765.     case WM_SIZE:
  766.         /*
  767.          * Handle resizing of the window
  768.          */
  769.         {
  770.         int width = LOWORD(lparam);
  771.         int height = HIWORD(lparam);
  772.         if (width && height) {
  773.             int view_width = myglobs.view->GetWidth();
  774.             int view_height = myglobs.view->GetHeight();
  775.             int dev_width = myglobs.dev->GetWidth();
  776.             int dev_height = myglobs.dev->GetHeight();
  777.             /*
  778.              * If the window hasn't changed size and we aren't returning from
  779.              * a minimize, there is nothing to do
  780.              */
  781.             if (view_width == width && view_height == height &&
  782.                 !myglobs.bMinimized)
  783.                 break;
  784.             if (width <= dev_width && height <= dev_height) {
  785.                 /*
  786.                  * If the window has shrunk, we can use the same device with a
  787.                  * new viewport
  788.                  */
  789.                 RELEASE(myglobs.view);
  790.                 rval = lpD3DRM->CreateViewport(myglobs.dev, myglobs.camera,
  791.                                                0, 0, width, height,
  792.                                                &myglobs.view);
  793.                 if (rval != D3DRM_OK) {
  794.                     Msg("Failed to resize the viewport.\n%s",
  795.                         D3DRMErrorToString(rval));
  796.                     CleanUpAndPostQuit();
  797.                     break;
  798.                 }
  799.                 rval = myglobs.view->SetBack(D3DVAL(5000.0));
  800.                 if (rval != D3DRM_OK) {
  801.                     Msg("Failed to set background depth after viewport resize.\n%s",
  802.                         D3DRMErrorToString(rval));
  803.                     CleanUpAndPostQuit();
  804.                     break;
  805.                 }
  806.             } else {
  807.                 /*
  808.                  * If the window got larger than the current device, create a
  809.                  * new device.
  810.                  */
  811.                 RELEASE(myglobs.view);
  812.                 RELEASE(myglobs.dev);
  813.                 if (!CreateDevAndView(lpDDClipper, myglobs.CurrDriver, width,
  814.                     height)) {
  815.                     CleanUpAndPostQuit();
  816.                     break;
  817.                 }
  818.             }
  819.             /*
  820.              * We must not longer be minimized
  821.              */
  822.             myglobs.bMinimized = FALSE;
  823.         } else {
  824.             /*
  825.              * This is a minimize message
  826.              */
  827.             myglobs.bMinimized = TRUE;
  828.         }
  829.         }
  830.         break;
  831.     case WM_ACTIVATE:
  832.         {
  833.         /*
  834.          * Create a Windows specific D3DRM window device to handle this
  835.          * message
  836.          */
  837.         LPDIRECT3DRMWINDEVICE windev;
  838.         if (!myglobs.dev)
  839.             break;
  840.         if (SUCCEEDED(myglobs.dev->QueryInterface(IID_IDirect3DRMWinDevice,
  841.             (void **) &windev)))  {
  842.                 if (FAILED(windev->HandleActivate(wparam)))
  843.                     Msg("Failed to handle WM_ACTIVATE.\n");
  844.                 windev->Release();
  845.         } else {
  846.             Msg("Failed to create Windows device to handle WM_ACTIVATE.\n");
  847.         }
  848.         }
  849.         break;
  850.     case WM_PAINT:
  851.         if (!myglobs.bInitialized || !myglobs.dev)
  852.             return DefWindowProc(win, msg, wparam, lparam);
  853.         /*
  854.          * Create a Windows specific D3DRM window device to handle this
  855.          * message
  856.          */
  857.         RECT r;
  858.         PAINTSTRUCT ps;
  859.         LPDIRECT3DRMWINDEVICE windev;
  860.  
  861.         if (GetUpdateRect(win, &r, FALSE)) {
  862.             BeginPaint(win, &ps);
  863.             if (SUCCEEDED(myglobs.dev->QueryInterface(IID_IDirect3DRMWinDevice,
  864.                 (void **) &windev))) {
  865.                 if (FAILED(windev->HandlePaint(ps.hdc)))
  866.                     Msg("Failed to handle WM_PAINT.\n");
  867.                 windev->Release();
  868.             } else {
  869.                 Msg("Failed to create Windows device to handle WM_PAINT.\n");
  870.             }
  871.             EndPaint(win, &ps);
  872.         }
  873.         break;
  874.     default:
  875.         return DefWindowProc(win, msg, wparam, lparam);
  876.     }
  877.     return 0L;
  878. }
  879.  
  880. /*
  881.  * SetRenderState
  882.  * Set the render quality, dither toggle and shade info if any of them has
  883.  * changed
  884.  */
  885. BOOL
  886. SetRenderState(void)
  887. {
  888.     HRESULT rval;
  889.     /*
  890.      * Set the render quality (light toggle, fill mode, shade mode)
  891.      */
  892.     if (myglobs.dev->GetQuality() != myglobs.RenderQuality) {
  893.         rval = myglobs.dev->SetQuality(myglobs.RenderQuality);
  894.         if (rval != D3DRM_OK) {
  895.             Msg("Setting the render quality failed.\n%s",
  896.                 D3DRMErrorToString(rval));
  897.             return FALSE;
  898.         }
  899.     }
  900.     /*
  901.      * Set dithering toggle
  902.      */
  903.     if (myglobs.dev->GetDither() != myglobs.bDithering) {
  904.         rval = myglobs.dev->SetDither(myglobs.bDithering);
  905.         if (rval != D3DRM_OK) {
  906.             Msg("Setting dither mode failed.\n%s", D3DRMErrorToString(rval));
  907.             return FALSE;
  908.         }
  909.     }
  910.     /*
  911.      * Set the texture quality (point or linear filtering)
  912.      */
  913.     if (myglobs.dev->GetTextureQuality() != myglobs.TextureQuality) {
  914.         rval = myglobs.dev->SetTextureQuality(myglobs.TextureQuality);
  915.         if (rval != D3DRM_OK) {
  916.             Msg("Setting texture quality failed.\n%s",
  917.                 D3DRMErrorToString(rval));
  918.             return FALSE;
  919.         }
  920.     }
  921.     /*
  922.      * Set shade info based on current bits per pixel
  923.      */
  924.     switch (myglobs.BPP) {
  925.         case 1:
  926.             if (FAILED(myglobs.dev->SetShades(4)))
  927.                 goto shades_error;
  928.             if (FAILED(lpD3DRM->SetDefaultTextureShades(4)))
  929.                 goto shades_error;
  930.             break;
  931.         case 16:
  932.             if (FAILED(myglobs.dev->SetShades(32)))
  933.                 goto shades_error;
  934.             if (FAILED(lpD3DRM->SetDefaultTextureColors(64)))
  935.                 goto shades_error;
  936.             if (FAILED(lpD3DRM->SetDefaultTextureShades(32)))
  937.                 goto shades_error;
  938.             break;
  939.         case 24:
  940.         case 32:
  941.             if (FAILED(myglobs.dev->SetShades(256)))
  942.                 goto shades_error;
  943.             if (FAILED(lpD3DRM->SetDefaultTextureColors(64)))
  944.                 goto shades_error;
  945.             if (FAILED(lpD3DRM->SetDefaultTextureShades(256)))
  946.                 goto shades_error;
  947.             break;
  948.     }
  949.     return TRUE;
  950. shades_error:
  951.     Msg("A failure occurred while setting color shade information.\n");
  952.     return FALSE;
  953. }
  954.  
  955. /****************************************************************************/
  956. /*                          Additional Functions                            */
  957. /****************************************************************************/
  958. /*
  959.  * ReadMouse
  960.  * Returns the mouse status for interaction with sample code
  961.  */
  962. void
  963. ReadMouse(int* b, int* x, int* y)
  964. {
  965.     *b = myglobs.mouse_buttons;
  966.     *x = myglobs.mouse_x;
  967.     *y = myglobs.mouse_y;
  968. }
  969.  
  970. /*
  971.  * InitGlobals
  972.  * Initialize the global variables
  973.  */
  974. void
  975. InitGlobals(void)
  976. {
  977.     lpD3DRM = NULL;
  978.     memset(&myglobs, 0, sizeof(myglobs));
  979.     myglobs.RenderQuality = D3DRMLIGHT_ON | D3DRMFILL_SOLID |
  980.                             D3DRMSHADE_GOURAUD;
  981.     myglobs.TextureQuality = D3DRMTEXTURE_NEAREST;
  982. }
  983.  
  984. /*
  985.  * CleanUpAndPostQuit
  986.  * Release all D3DRM objects, post a quit message and set the bQuit flag
  987.  */
  988. void
  989. CleanUpAndPostQuit(void)
  990. {
  991.     myglobs.bInitialized = FALSE;
  992.     RELEASE(myglobs.scene);
  993.     RELEASE(myglobs.camera);
  994.     RELEASE(myglobs.view);
  995.     RELEASE(myglobs.dev);
  996.     RELEASE(lpD3DRM);
  997.     RELEASE(lpDDClipper);
  998.     myglobs.bQuit = TRUE;
  999. }
  1000.