home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / misc / rmmain.cpp < prev    next >
C/C++ Source or Header  |  1997-07-14  |  38KB  |  1,089 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 HRESULT CreateDevAndView(LPDIRECTDRAWCLIPPER lpDDClipper, int driver, int width, int height);
  83. static BOOL RenderLoop(void);
  84. static void CleanUpAndPostQuit(void);
  85. static HRESULT 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 (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver, rc.right, rc.bottom)) {
  291.     myglobs.CurrDriver = 0;
  292.     if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver, rc.right, rc.bottom)) {
  293.         Msg("Failed to create the D3DRM device.\n%s", D3DRMErrorToString(rval));
  294.         return FALSE;
  295.     }
  296.     }
  297.     /*
  298.      * Create the scene to be rendered by calling this sample's BuildScene
  299.      */
  300.     if (!BuildScene(myglobs.dev, myglobs.view, myglobs.scene, myglobs.camera))
  301.         return FALSE;
  302.     /*
  303.      * Display the window
  304.      */
  305.     ShowWindow(win, cmdshow);
  306.     UpdateWindow(win);
  307.     /*
  308.      * Now we are ready to render
  309.      */
  310.     myglobs.bInitialized = TRUE;
  311.  
  312.     return win;
  313. }
  314.  
  315. /*
  316.  * CreateDevAndView
  317.  * Create the D3DRM device and viewport with the given D3D driver and of the
  318.  * specified size.
  319.  */
  320. static HRESULT
  321. CreateDevAndView(LPDIRECTDRAWCLIPPER lpDDClipper, int driver, int width, int height)
  322. {
  323.     HRESULT rval;
  324.  
  325.     if (!width || !height)
  326.         return D3DRMERR_BADVALUE;
  327.     /*
  328.      * Create the D3DRM device from this window and using the specified D3D
  329.      * driver.
  330.      */
  331.     rval = lpD3DRM->CreateDeviceFromClipper(lpDDClipper, &myglobs.DriverGUID[driver],
  332.                                         width, height, &myglobs.dev);
  333.     if (rval != D3DRM_OK)
  334.         return rval;
  335.     /*
  336.      * Create the D3DRM viewport using the camera frame.  Set the background
  337.      * depth to a large number.  The width and height may be slightly
  338.      * adjusted, so get them from the device to be sure.
  339.      */
  340.     width = myglobs.dev->GetWidth();
  341.     height = myglobs.dev->GetHeight();
  342.     rval = lpD3DRM->CreateViewport(myglobs.dev, myglobs.camera, 0, 0, width,
  343.                                    height, &myglobs.view);
  344.     if (rval != D3DRM_OK) {
  345.     myglobs.bInitialized = FALSE;
  346.         RELEASE(myglobs.dev);
  347.         return rval;
  348.     }
  349.     rval = myglobs.view->SetBack(D3DVAL(5000.0));
  350.     if (rval != D3DRM_OK) {
  351.     myglobs.bInitialized = FALSE;
  352.         RELEASE(myglobs.dev);
  353.         RELEASE(myglobs.view);
  354.         return rval;
  355.     }
  356.     /*
  357.      * Set the render quality, fill mode, lighting state and color shade info
  358.      */
  359.     if (rval = SetRenderState()) {
  360.     myglobs.bInitialized = FALSE;
  361.         RELEASE(myglobs.dev);
  362.         RELEASE(myglobs.view);
  363.         return rval;
  364.     }
  365.  
  366.     return D3DRM_OK;
  367. }
  368.  
  369. /****************************************************************************/
  370. /*                         D3D Device Enumeration                           */
  371. /****************************************************************************/
  372. /*
  373.  * BPPToDDBD
  374.  * Converts bits per pixel to a DirectDraw bit depth flag
  375.  */
  376. static DWORD
  377. BPPToDDBD(int bpp)
  378. {
  379.     switch(bpp) {
  380.         case 1:
  381.             return DDBD_1;
  382.         case 2:
  383.             return DDBD_2;
  384.         case 4:
  385.             return DDBD_4;
  386.         case 8:
  387.             return DDBD_8;
  388.         case 16:
  389.             return DDBD_16;
  390.         case 24:
  391.             return DDBD_24;
  392.         case 32:
  393.             return DDBD_32;
  394.         default:
  395.             return 0;
  396.     }
  397. }
  398.  
  399. /*
  400.  * enumDeviceFunc
  401.  * Callback function which records each usable D3D driver's name and GUID
  402.  * Chooses a driver to begin with and sets *lpContext to this starting driver
  403.  */
  404. static HRESULT
  405. WINAPI enumDeviceFunc(LPGUID lpGuid, LPSTR lpDeviceDescription, LPSTR lpDeviceName,
  406.         LPD3DDEVICEDESC lpHWDesc, LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext)
  407. {
  408.     static BOOL hardware = FALSE; /* current start driver is hardware */
  409.     static BOOL mono = FALSE;     /* current start driver is mono light */
  410.     LPD3DDEVICEDESC lpDesc;
  411.     int *lpStartDriver = (int *)lpContext;
  412.     /*
  413.      * Decide which device description we should consult
  414.      */
  415.     lpDesc = lpHWDesc->dcmColorModel ? lpHWDesc : lpHELDesc;
  416.     /*
  417.      * If this driver cannot render in the current display bit depth skip
  418.      * it and continue with the enumeration.
  419.      */
  420.     if (!(lpDesc->dwDeviceRenderBitDepth & BPPToDDBD(myglobs.BPP)))
  421.         return D3DENUMRET_OK;
  422.     /*
  423.      * Record this driver's info
  424.      */
  425.     memcpy(&myglobs.DriverGUID[myglobs.NumDrivers], lpGuid, sizeof(GUID));
  426.     lstrcpy(&myglobs.DriverName[myglobs.NumDrivers][0], lpDeviceName);
  427.     /*
  428.      * Choose hardware over software, RGB lights over mono lights
  429.      */
  430.     if (*lpStartDriver == -1) {
  431.         /*
  432.          * this is the first valid driver
  433.          */
  434.         *lpStartDriver = myglobs.NumDrivers;
  435.         hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
  436.         mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
  437.     } else if (lpDesc == lpHWDesc && !hardware) {
  438.         /*
  439.          * this driver is hardware and start driver is not
  440.          */
  441.         *lpStartDriver = myglobs.NumDrivers;
  442.         hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
  443.         mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
  444.     } else if ((lpDesc == lpHWDesc && hardware ) || (lpDesc == lpHELDesc
  445.                                                      && !hardware)) {
  446.         if (lpDesc->dcmColorModel == D3DCOLOR_MONO && !mono) {
  447.             /*
  448.              * this driver and start driver are the same type and this
  449.              * driver is mono while start driver is not
  450.              */
  451.             *lpStartDriver = myglobs.NumDrivers;
  452.             hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
  453.             mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
  454.         }
  455.     }
  456.     myglobs.NumDrivers++;
  457.     if (myglobs.NumDrivers == MAX_DRIVERS)
  458.         return (D3DENUMRET_CANCEL);
  459.     return (D3DENUMRET_OK);
  460. }
  461.  
  462. /*
  463.  * EnumDevices
  464.  * Enumerate the available D3D drivers, add them to the file menu, and choose
  465.  * one to use.
  466.  */
  467. static BOOL
  468. EnumDevices(HWND win)
  469. {
  470.     LPDIRECTDRAW lpDD;
  471.     LPDIRECT3D lpD3D;
  472.     HRESULT rval;
  473.     HMENU hmenu;
  474.     int i;
  475.  
  476.     /*
  477.      * Create a DirectDraw object and query for the Direct3D interface to use
  478.      * to enumerate the drivers.
  479.      */
  480.     rval = DirectDrawCreate(NULL, &lpDD, NULL);
  481.     if (rval != DD_OK) {
  482.         Msg("Creation of DirectDraw HEL failed.\n%s", D3DRMErrorToString(rval));
  483.         return FALSE;
  484.     }
  485.     rval = lpDD->QueryInterface(IID_IDirect3D, (void**) &lpD3D);
  486.     if (rval != DD_OK) {
  487.         Msg("Creation of Direct3D interface failed.\n%s", D3DRMErrorToString(rval));
  488.         lpDD->Release();
  489.         return FALSE;
  490.     }
  491.     /*
  492.      * Enumerate the drivers, setting CurrDriver to -1 to initialize the
  493.      * driver selection code in enumDeviceFunc
  494.      */
  495.     myglobs.CurrDriver = -1;
  496.     rval = lpD3D->EnumDevices(enumDeviceFunc, &myglobs.CurrDriver);
  497.     if (rval != DD_OK) {
  498.         Msg("Enumeration of drivers failed.\n%s", D3DRMErrorToString(rval));
  499.         return FALSE;
  500.     }
  501.     /*
  502.      * Make sure we found at least one valid driver
  503.      */
  504.     if (myglobs.NumDrivers == 0) {
  505.         Msg("Could not find a D3D driver which is compatible with this display depth");
  506.         return FALSE;
  507.     }
  508.     lpD3D->Release();
  509.     lpDD->Release();
  510.     /*
  511.      * Add the driver names to the File menu
  512.      */
  513.     hmenu = GetSubMenu(GetMenu(win), 0);
  514.     for (i = 0; i < myglobs.NumDrivers; i++) {
  515.         InsertMenu(hmenu, 5 + i, MF_BYPOSITION | MF_STRING, MENU_FIRST_DRIVER + i,
  516.                    myglobs.DriverName[i]);
  517.     }
  518.     return TRUE;
  519. }
  520.  
  521. /****************************************************************************/
  522. /*                             Render Loop                                  */
  523. /****************************************************************************/
  524. /*
  525.  * Clear the viewport, render the next frame and update the window
  526.  */
  527. static BOOL
  528. RenderLoop()
  529. {
  530.     HRESULT rval;
  531.     /*
  532.      * Tick the scene
  533.      */
  534.     rval = myglobs.scene->Move(D3DVAL(1.0));
  535.     if (rval != D3DRM_OK) {
  536.         Msg("Moving scene failed.\n%s", D3DRMErrorToString(rval));
  537.         return FALSE;
  538.     }
  539.     /* 
  540.      * Clear the viewport
  541.      */
  542.     rval = myglobs.view->Clear();
  543.     if (rval != D3DRM_OK) {
  544.         Msg("Clearing viewport failed.\n%s", D3DRMErrorToString(rval));
  545.         return FALSE;
  546.     }
  547.     /*
  548.      * Render the scene to the viewport
  549.      */
  550.     rval = myglobs.view->Render(myglobs.scene);
  551.     if (rval != D3DRM_OK) {
  552.         Msg("Rendering scene failed.\n%s", D3DRMErrorToString(rval));
  553.         return FALSE;
  554.     }
  555.     /*
  556.      * Update the window
  557.      */
  558.     rval = myglobs.dev->Update();
  559.     if (rval != D3DRM_OK) {
  560.         Msg("Updating device failed.\n%s", D3DRMErrorToString(rval));
  561.         return FALSE;
  562.     }
  563.     return TRUE;
  564. }
  565.  
  566.  
  567. /****************************************************************************/
  568. /*                    Windows Message Handlers                              */
  569. /****************************************************************************/
  570. /*
  571.  * AppAbout
  572.  * About box message handler
  573.  */
  574. BOOL
  575. FAR PASCAL AppAbout(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lParam)
  576. {
  577.   switch (msg)
  578.   {
  579.     case WM_COMMAND:
  580.       if (LOWORD(wparam) == IDOK)
  581.         EndDialog(hwnd, TRUE);
  582.       break;
  583.  
  584.     case WM_INITDIALOG:
  585.       return TRUE;
  586.   }
  587.   return FALSE;
  588. }
  589.  
  590. /*
  591.  * WindowProc
  592.  * Main window message handler
  593.  */
  594. LONG FAR PASCAL WindowProc(HWND win, UINT msg, WPARAM wparam, LPARAM lparam)
  595. {
  596.     int i;
  597.     HRESULT rval;
  598.     RECT rc;
  599.  
  600.     if (!myglobs.bInitialized) {
  601.         return DefWindowProc(win, msg, wparam, lparam);
  602.     }
  603.  
  604.     switch (msg)    {
  605.         case WM_LBUTTONDOWN:
  606.         case WM_LBUTTONUP:
  607.         case WM_RBUTTONDOWN:
  608.         case WM_RBUTTONUP:
  609.         case WM_MOUSEMOVE:
  610.             /*
  611.              * Record the mouse state for ReadMouse
  612.              */
  613.             myglobs.mouse_buttons = wparam;
  614.             myglobs.mouse_x = LOWORD(lparam);
  615.             myglobs.mouse_y = HIWORD(lparam);
  616.             break;
  617.         case WM_INITMENUPOPUP:
  618.             /*
  619.              * Check and enable the appropriate menu items
  620.              */
  621.             CheckMenuItem((HMENU)wparam, MENU_STEP,(myglobs.bSingleStepMode) ? MF_CHECKED : MF_UNCHECKED);
  622.             EnableMenuItem((HMENU)wparam, MENU_GO,(myglobs.bSingleStepMode) ? MF_ENABLED : MF_GRAYED);
  623.             if (!myglobs.bConstRenderQuality) {
  624.                 CheckMenuItem((HMENU)wparam, MENU_LIGHTING, (myglobs.RenderQuality & D3DRMLIGHT_MASK) == D3DRMLIGHT_ON ? MF_CHECKED : MF_GRAYED);
  625.                 CheckMenuItem((HMENU)wparam, MENU_FLAT, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_FLAT ? MF_CHECKED : MF_UNCHECKED);
  626.                 CheckMenuItem((HMENU)wparam, MENU_GOURAUD, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_GOURAUD ? MF_CHECKED : MF_UNCHECKED);
  627.                 CheckMenuItem((HMENU)wparam, MENU_PHONG, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_PHONG ? MF_CHECKED : MF_UNCHECKED);
  628.                 EnableMenuItem((HMENU)wparam, MENU_PHONG, MF_GRAYED);
  629.                 CheckMenuItem((HMENU)wparam, MENU_POINT, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_POINTS ? MF_CHECKED : MF_UNCHECKED);
  630.                 CheckMenuItem((HMENU)wparam, MENU_WIREFRAME, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_WIREFRAME ? MF_CHECKED : MF_UNCHECKED);
  631.                 CheckMenuItem((HMENU)wparam, MENU_SOLID, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_SOLID ? MF_CHECKED : MF_UNCHECKED);
  632.             } else {
  633.                 EnableMenuItem((HMENU)wparam, MENU_LIGHTING, MF_GRAYED);
  634.                 EnableMenuItem((HMENU)wparam, MENU_FLAT, MF_GRAYED);
  635.                 EnableMenuItem((HMENU)wparam, MENU_GOURAUD, MF_GRAYED);
  636.                 EnableMenuItem((HMENU)wparam, MENU_PHONG, MF_GRAYED);
  637.                 EnableMenuItem((HMENU)wparam, MENU_POINT, MF_GRAYED);
  638.                 EnableMenuItem((HMENU)wparam, MENU_WIREFRAME, MF_GRAYED);
  639.                 EnableMenuItem((HMENU)wparam, MENU_SOLID, MF_GRAYED);
  640.             }
  641.             if (!myglobs.bNoTextures) {
  642.                 CheckMenuItem((HMENU)wparam, MENU_POINT_FILTER, (myglobs.TextureQuality == D3DRMTEXTURE_NEAREST) ? MF_CHECKED : MF_UNCHECKED);
  643.                 CheckMenuItem((HMENU)wparam, MENU_LINEAR_FILTER, (myglobs.TextureQuality == D3DRMTEXTURE_LINEAR) ? MF_CHECKED : MF_UNCHECKED);
  644.             } else {
  645.                 EnableMenuItem((HMENU)wparam, MENU_POINT_FILTER, MF_GRAYED);
  646.                 EnableMenuItem((HMENU)wparam, MENU_LINEAR_FILTER, MF_GRAYED);
  647.             }
  648.             CheckMenuItem((HMENU)wparam, MENU_DITHERING, (myglobs.bDithering) ? MF_CHECKED : MF_UNCHECKED);
  649.             CheckMenuItem((HMENU)wparam, MENU_ANTIALIAS, (myglobs.bAntialiasing) ? MF_CHECKED : MF_UNCHECKED);
  650.             EnableMenuItem((HMENU)wparam, MENU_ANTIALIAS, MF_GRAYED);
  651.             for (i = 0; i < myglobs.NumDrivers; i++) {
  652.                 CheckMenuItem((HMENU)wparam, MENU_FIRST_DRIVER + i,
  653.                        (i == myglobs.CurrDriver) ? MF_CHECKED : MF_UNCHECKED);
  654.             }
  655.             break;
  656.         case WM_COMMAND:
  657.             switch(LOWORD(wparam)) {
  658.                 case MENU_ABOUT:
  659.                     DialogBox((HINSTANCE)GetWindowLong(win, GWL_HINSTANCE),
  660.                               "AppAbout", win, (DLGPROC)AppAbout);
  661.                     break;
  662.                 case MENU_EXIT:
  663.                     CleanUpAndPostQuit();
  664.                     break;
  665.                 case MENU_STEP:
  666.                     /*
  667.                      * Begin single step more or draw a frame if in single
  668.                      * step mode
  669.                      */
  670.                     if (!myglobs.bSingleStepMode) {
  671.                         myglobs.bSingleStepMode = TRUE;
  672.                         myglobs.bDrawAFrame = TRUE;
  673.                     } else if (!myglobs.bDrawAFrame) {
  674.                         myglobs.bDrawAFrame = TRUE;
  675.                     }
  676.                     break;
  677.                 case MENU_GO:
  678.                     /*
  679.                      * Exit single step mode
  680.                      */
  681.                     myglobs.bSingleStepMode = FALSE;
  682.                     break;
  683.                 /*
  684.                  * Lighting toggle
  685.                  */
  686.                 case MENU_LIGHTING:
  687.                     myglobs.RenderQuality ^= D3DRMLIGHT_ON;
  688.                     SetRenderState();
  689.                     break;
  690.                 /*
  691.                  * Fill mode selection
  692.                  */
  693.                 case MENU_POINT:
  694.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_POINTS;
  695.                     SetRenderState();
  696.                     break;
  697.                 case MENU_WIREFRAME:
  698.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_WIREFRAME;
  699.                     SetRenderState();
  700.                     break;
  701.                 case MENU_SOLID:
  702.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_SOLID;
  703.                     SetRenderState();
  704.                     break;
  705.                 /*
  706.                  * Shade mode selection
  707.                  */
  708.                 case MENU_FLAT:
  709.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_FLAT;
  710.                     SetRenderState();
  711.                     break;
  712.                 case MENU_GOURAUD:
  713.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_GOURAUD;
  714.                     SetRenderState();
  715.                     break;
  716.                 case MENU_PHONG:
  717.                     myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_PHONG;
  718.                     SetRenderState();
  719.                     break;
  720.  
  721.                 case MENU_DITHERING:
  722.                     myglobs.bDithering = !myglobs.bDithering;
  723.                     SetRenderState();
  724.                     break;
  725.                 case MENU_ANTIALIAS:
  726.                     myglobs.bAntialiasing = !myglobs.bAntialiasing;
  727.                     break;
  728.                 /*
  729.                  * Texture filter selection
  730.                  */
  731.                 case MENU_POINT_FILTER:
  732.                     if (myglobs.TextureQuality == D3DRMTEXTURE_NEAREST)
  733.                         break;
  734.                     myglobs.TextureQuality = D3DRMTEXTURE_NEAREST;
  735.                     SetRenderState();
  736.                     break;
  737.                 case MENU_LINEAR_FILTER:
  738.                     if (myglobs.TextureQuality == D3DRMTEXTURE_LINEAR)
  739.                         break;
  740.                     myglobs.TextureQuality = D3DRMTEXTURE_LINEAR;
  741.                     SetRenderState();
  742.                     break;
  743.                 }
  744.                 /*
  745.                  * Changing the D3D Driver
  746.                  */
  747.                 if (LOWORD(wparam) >= MENU_FIRST_DRIVER &&
  748.                     LOWORD(wparam) < MENU_FIRST_DRIVER + MAX_DRIVERS &&
  749.                     myglobs.CurrDriver != LOWORD(wparam) - MENU_FIRST_DRIVER)
  750.         {
  751.                     /*
  752.                      * Release the current viewport and device and create
  753.                      * the new one
  754.                      */
  755.             int LastDriver = myglobs.CurrDriver;
  756.             myglobs.bInitialized = FALSE;
  757.                     RELEASE(myglobs.view);
  758.                     RELEASE(myglobs.dev);
  759.                     myglobs.CurrDriver = LOWORD(wparam)-MENU_FIRST_DRIVER;
  760.                     GetClientRect(win, &rc);
  761.                     if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
  762.                         rc.right, rc.bottom))
  763.             {
  764.             myglobs.CurrDriver = LastDriver;
  765.             if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
  766.                             rc.right, rc.bottom))
  767.             {
  768.                 Msg("Failed to create the D3DRM device.\n%s", D3DRMErrorToString(rval));
  769.                 CleanUpAndPostQuit();
  770.             }
  771.             else
  772.             {
  773.                 Msg("There was not enough video memory available to use the 3D accelerated hardware device.\nRestoring old software device.");
  774.                 myglobs.bInitialized = TRUE;
  775.             }
  776.                     }
  777.             else
  778.             {
  779.             myglobs.bInitialized = TRUE;
  780.             }
  781.                 }
  782.                 /*
  783.                  * Draw a frame in single step mode after ever command
  784.                  */
  785.                 myglobs.bDrawAFrame = TRUE;
  786.             break;
  787.     case WM_DESTROY:
  788.         CleanUpAndPostQuit();
  789.         break;
  790.     case WM_SIZE:
  791.         /*
  792.          * Handle resizing of the window
  793.          */
  794.         {
  795.         int width = LOWORD(lparam);
  796.         int height = HIWORD(lparam);
  797.         if (width && height && myglobs.view && myglobs.dev) {
  798.             int view_width = myglobs.view->GetWidth();
  799.             int view_height = myglobs.view->GetHeight();
  800.             int dev_width = myglobs.dev->GetWidth();
  801.             int dev_height = myglobs.dev->GetHeight();
  802.             /*
  803.              * If the window hasn't changed size and we aren't returning from
  804.              * a minimize, there is nothing to do
  805.              */
  806.             if (view_width == width && view_height == height &&
  807.                 !myglobs.bMinimized)
  808.                 break;
  809.             if (width <= dev_width && height <= dev_height) {
  810.                 /*
  811.                  * If the window has shrunk, we can use the same device with a
  812.                  * new viewport
  813.                  */
  814.                 myglobs.bInitialized = FALSE;
  815.                 RELEASE(myglobs.view);
  816.                 rval = lpD3DRM->CreateViewport(myglobs.dev, myglobs.camera,
  817.                                                0, 0, width, height,
  818.                                                &myglobs.view);
  819.                 if (rval != D3DRM_OK) {
  820.                     Msg("Failed to resize the viewport.\n%s",
  821.                         D3DRMErrorToString(rval));
  822.                     CleanUpAndPostQuit();
  823.                     break;
  824.                 }
  825.                 rval = myglobs.view->SetBack(D3DVAL(5000.0));
  826.                 if (rval != D3DRM_OK) {
  827.                     Msg("Failed to set background depth after viewport resize.\n%s",
  828.                         D3DRMErrorToString(rval));
  829.                     CleanUpAndPostQuit();
  830.                     break;
  831.                 }
  832.         myglobs.bInitialized = TRUE;
  833.             } else {
  834.                 /*
  835.                  * If the window got larger than the current device, create a
  836.                  * new device.
  837.                  */
  838.         myglobs.bInitialized = FALSE;
  839.                 RELEASE(myglobs.view);
  840.                 RELEASE(myglobs.dev);
  841.                 if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
  842.                         width, height))
  843.         {
  844.             myglobs.CurrDriver = 0;
  845.             if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
  846.                         width, height))
  847.             {
  848.             Msg("Failed to create the D3DRM device.\n%s", D3DRMErrorToString(rval));
  849.             CleanUpAndPostQuit();
  850.             }
  851.             else
  852.             {
  853.             Msg("There was not enough video memory available to use the 3D accelerated hardware device.\nUsing software rendering instead.");
  854.             myglobs.bInitialized = TRUE;
  855.             }
  856.                 }
  857.         else
  858.         {
  859.             myglobs.bInitialized = TRUE;
  860.         }
  861.         myglobs.bInitialized = TRUE;
  862.             }
  863.             /*
  864.              * We must not longer be minimized
  865.              */
  866.             myglobs.bMinimized = FALSE;
  867.         } else {
  868.             /*
  869.              * This is a minimize message
  870.              */
  871.             myglobs.bMinimized = TRUE;
  872.         }
  873.         }
  874.         myglobs.bDrawAFrame = TRUE;
  875.         break;
  876.     case WM_ACTIVATE:
  877.         {
  878.         /*
  879.          * Create a Windows specific D3DRM window device to handle this
  880.          * message
  881.          */
  882.         LPDIRECT3DRMWINDEVICE windev;
  883.         if (!myglobs.dev)
  884.             break;
  885.         if (SUCCEEDED(myglobs.dev->QueryInterface(IID_IDirect3DRMWinDevice,
  886.             (void **) &windev)))  {
  887.                 if (FAILED(windev->HandleActivate(wparam)))
  888.                     Msg("Failed to handle WM_ACTIVATE.\n");
  889.                 windev->Release();
  890.         } else {
  891.             Msg("Failed to create Windows device to handle WM_ACTIVATE.\n");
  892.         }
  893.         }
  894.         break;
  895.     case WM_PAINT:
  896.         if (!myglobs.bInitialized || !myglobs.dev)
  897.             return DefWindowProc(win, msg, wparam, lparam);
  898.         /*
  899.          * Create a Windows specific D3DRM window device to handle this
  900.          * message
  901.          */
  902.         RECT r;
  903.         PAINTSTRUCT ps;
  904.         LPDIRECT3DRMWINDEVICE windev;
  905.  
  906.         if (GetUpdateRect(win, &r, FALSE)) {
  907.             BeginPaint(win, &ps);
  908.             if (SUCCEEDED(myglobs.dev->QueryInterface(IID_IDirect3DRMWinDevice,
  909.                 (void **) &windev))) {
  910.                 if (FAILED(windev->HandlePaint(ps.hdc)))
  911.                     Msg("Failed to handle WM_PAINT.\n");
  912.                 windev->Release();
  913.             } else {
  914.                 Msg("Failed to create Windows device to handle WM_PAINT.\n");
  915.             }
  916.             EndPaint(win, &ps);
  917.         }
  918.         break;
  919.     case WM_DISPLAYCHANGE:
  920.     {
  921.         /*
  922.          * If this display change message was generated because another application
  923.          * has gone exclusive, ignore it.
  924.          */
  925.         LPDIRECTDRAW lpDD;
  926.         LPDIRECTDRAWSURFACE lpDDS;
  927.         DDSURFACEDESC ddsd;
  928.         HRESULT err;
  929.  
  930.         if (DirectDrawCreate(NULL, &lpDD, NULL))
  931.         break;
  932.         err = lpDD->SetCooperativeLevel(win, DDSCL_NORMAL);
  933.         if (err) {
  934.         lpDD->Release();
  935.         break;
  936.         }
  937.         memset(&ddsd, 0, sizeof(ddsd));
  938.         ddsd.dwSize = sizeof(ddsd);
  939.         ddsd.dwFlags = DDSD_CAPS;
  940.         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  941.         err = lpDD->CreateSurface(&ddsd, &lpDDS, NULL);
  942.         if (err == DDERR_NOEXCLUSIVEMODE) {
  943.         // This exclusive mode generated WM_DISPLAYCHANGE, ignoring
  944.         lpDD->Release();
  945.         break;
  946.         }
  947.         if (!err)
  948.         lpDDS->Release();
  949.         lpDD->Release();        
  950.     }
  951.     GetClientRect(win, &rc);
  952.     myglobs.bInitialized = FALSE;
  953.         if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
  954.                     rc.right, rc.bottom)) {
  955.         myglobs.CurrDriver = 0;
  956.         if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
  957.                     rc.right, rc.bottom))
  958.         {
  959.         Msg("Failed to create the D3DRM device.\n%s", D3DRMErrorToString(rval));
  960.         CleanUpAndPostQuit();
  961.         }
  962.         else
  963.         {
  964.         // Don't bother the user with an error message here
  965.         //Msg("There was not enough video memory available to use the 3D accelerated hardware device.\nUsing software rendering instead.");
  966.         myglobs.bInitialized = TRUE;
  967.         }
  968.         }
  969.     else
  970.     {
  971.         myglobs.bInitialized = TRUE;
  972.     }
  973.     break;
  974.     default:
  975.         return DefWindowProc(win, msg, wparam, lparam);
  976.     }
  977.     return 0L;
  978. }
  979.  
  980. /*
  981.  * SetRenderState
  982.  * Set the render quality, dither toggle and shade info if any of them has
  983.  * changed
  984.  */
  985. HRESULT
  986. SetRenderState(void)
  987. {
  988.     HRESULT rval;
  989.     /*
  990.      * Set the render quality (light toggle, fill mode, shade mode)
  991.      */
  992.     if (myglobs.dev->GetQuality() != myglobs.RenderQuality) {
  993.         rval = myglobs.dev->SetQuality(myglobs.RenderQuality);
  994.         if (rval != D3DRM_OK)
  995.         return rval;
  996.     }
  997.     /*
  998.      * Set dithering toggle
  999.      */
  1000.     if (myglobs.dev->GetDither() != myglobs.bDithering) {
  1001.         rval = myglobs.dev->SetDither(myglobs.bDithering);
  1002.         if (rval != D3DRM_OK) 
  1003.         return rval;
  1004.     }
  1005.     /*
  1006.      * Set the texture quality (point or linear filtering)
  1007.      */
  1008.     if (myglobs.dev->GetTextureQuality() != myglobs.TextureQuality) {
  1009.         rval = myglobs.dev->SetTextureQuality(myglobs.TextureQuality);
  1010.         if (rval != D3DRM_OK) 
  1011.         return rval;
  1012.     }
  1013.     /*
  1014.      * Set shade info based on current bits per pixel
  1015.      */
  1016.     switch (myglobs.BPP) {
  1017.     case 1:
  1018.         if (rval = myglobs.dev->SetShades(4))
  1019.             return rval;
  1020.         if (rval = lpD3DRM->SetDefaultTextureShades(4))
  1021.             return rval;
  1022.         break;
  1023.     case 16:
  1024.         if (rval = myglobs.dev->SetShades(32))
  1025.             return rval;
  1026.         if (rval = lpD3DRM->SetDefaultTextureColors(64))
  1027.             return rval;
  1028.         if (rval = lpD3DRM->SetDefaultTextureShades(32))
  1029.             return rval;
  1030.         break;
  1031.     case 24:
  1032.     case 32:
  1033.         if (rval = myglobs.dev->SetShades(256))
  1034.             return rval;
  1035.         if (rval = lpD3DRM->SetDefaultTextureColors(64))
  1036.             return rval;
  1037.         if (rval = lpD3DRM->SetDefaultTextureShades(256))
  1038.             return rval;
  1039.         break;
  1040.     }
  1041.     return D3DRM_OK;
  1042. }
  1043.  
  1044. /****************************************************************************/
  1045. /*                          Additional Functions                            */
  1046. /****************************************************************************/
  1047. /*
  1048.  * ReadMouse
  1049.  * Returns the mouse status for interaction with sample code
  1050.  */
  1051. void
  1052. ReadMouse(int* b, int* x, int* y)
  1053. {
  1054.     *b = myglobs.mouse_buttons;
  1055.     *x = myglobs.mouse_x;
  1056.     *y = myglobs.mouse_y;
  1057. }
  1058.  
  1059. /*
  1060.  * InitGlobals
  1061.  * Initialize the global variables
  1062.  */
  1063. void
  1064. InitGlobals(void)
  1065. {
  1066.     lpD3DRM = NULL;
  1067.     memset(&myglobs, 0, sizeof(myglobs));
  1068.     myglobs.RenderQuality = D3DRMLIGHT_ON | D3DRMFILL_SOLID |
  1069.                             D3DRMSHADE_GOURAUD;
  1070.     myglobs.TextureQuality = D3DRMTEXTURE_NEAREST;
  1071. }
  1072.  
  1073. /*
  1074.  * CleanUpAndPostQuit
  1075.  * Release all D3DRM objects, post a quit message and set the bQuit flag
  1076.  */
  1077. void
  1078. CleanUpAndPostQuit(void)
  1079. {
  1080.     myglobs.bInitialized = FALSE;
  1081.     RELEASE(myglobs.scene);
  1082.     RELEASE(myglobs.camera);
  1083.     RELEASE(myglobs.view);
  1084.     RELEASE(myglobs.dev);
  1085.     RELEASE(lpD3DRM);
  1086.     RELEASE(lpDDClipper);
  1087.     myglobs.bQuit = TRUE;
  1088. }
  1089.