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