home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / directx2 / sdk / samples / misc / ddcalls.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-28  |  33.8 KB  |  949 lines

  1. /*
  2.  *  Copyright (C) 1995, 1996 Microsoft Corporation. All Rights Reserved.
  3.  *
  4.  *  File: ddcalls.c
  5.  *
  6.  *  Manages DirectDraw objects needed for rendering.  Part of D3DApp.
  7.  *
  8.  *  D3DApp is a collection of helper functions for Direct3D applications.
  9.  *  D3DApp consists of the following files:
  10.  *      d3dapp.h    Main D3DApp header to be included by application
  11.  *      d3dappi.h   Internal header
  12.  *      d3dapp.c    D3DApp functions seen by application.
  13.  *      ddcalls.c   All calls to DirectDraw objects except textures
  14.  *      d3dcalls.c  All calls to Direct3D objects except textures
  15.  *      texture.c   Texture loading and managing texture list
  16.  *      misc.c      Miscellaneous calls
  17.  */
  18.  
  19. #include "d3dappi.h"
  20.  
  21. /***************************************************************************/
  22. /*                         Direct Draw Creation                            */
  23. /***************************************************************************/
  24. /*
  25.  * D3DAppIDDEnumCallback
  26.  * Callback function used during enumeration of DirectDraw drivers.
  27.  * During enumeration, if a 3D capable hardware device is found, it is 
  28.  * created and *(LPDIRECTDRAW*)lpContext is set to it.  Otherwise, does
  29.  * nothing.
  30.  */
  31. BOOL FAR PASCAL D3DAppIDDEnumCallback(GUID FAR* lpGUID, LPSTR lpDriverDesc,
  32.                                       LPSTR lpDriverName, LPVOID lpContext)
  33. {
  34.     LPDIRECTDRAW lpDD;
  35.     DDCAPS DriverCaps, HELCaps;
  36.  
  37.     /*
  38.      * A NULL GUID* indicates the DirectDraw HEL which we are not interested
  39.      * in at the moment.
  40.      */
  41.     if (lpGUID) {
  42.         /*
  43.          * Create the DirectDraw device using this driver.  If it fails,
  44.          * just move on to the next driver.
  45.          */
  46.         if (FAILED(DirectDrawCreate(lpGUID, &lpDD, NULL))) {
  47.             return DDENUMRET_OK;
  48.         }
  49.         /*
  50.          * Get the capabilities of this DirectDraw driver.  If it fails,
  51.          * just move on to the next driver.
  52.          */
  53.         memset(&DriverCaps, 0, sizeof(DDCAPS));
  54.         DriverCaps.dwSize = sizeof(DDCAPS);
  55.         memset(&HELCaps, 0, sizeof(DDCAPS));
  56.         HELCaps.dwSize = sizeof(DDCAPS);
  57.         if (FAILED(lpDD->lpVtbl->GetCaps(lpDD, &DriverCaps, &HELCaps))) {
  58.             lpDD->lpVtbl->Release(lpDD);
  59.             return DDENUMRET_OK;
  60.         }
  61.         if (DriverCaps.dwCaps & DDCAPS_3D) {
  62.             /*
  63.              * We have found a 3d hardware device.  Return the DD object
  64.              * and stop enumeration.
  65.              */
  66.             d3dappi.bIsPrimary = FALSE;
  67.             *(LPDIRECTDRAW*)lpContext = lpDD;
  68.             return DDENUMRET_CANCEL;
  69.         }       
  70.         lpDD->lpVtbl->Release(lpDD);
  71.     }
  72.     return DDENUMRET_OK;
  73. }
  74.  
  75. /*
  76.  * D3DAppICreateDD
  77.  * Creates the DirectDraw device and saves the current palette. If a 3D 
  78.  * capable DD driver is available, use it as the DD device, otherwise, use
  79.  * the HEL.  It is assumed that a 3D capable DD hardware driver is not the
  80.  * primary device and hence cannot operate in a window (ie it's a fullscreen
  81.  * only device displaying on a second monitor).  Valid flags:
  82.  *     D3DAPP_ONLYDDEMULATION    Always use the DirectDraw HEL
  83.  */
  84. BOOL
  85. D3DAppICreateDD(DWORD flags)
  86. {
  87.     HDC hdc;
  88.     int i;
  89.     LPDIRECTDRAW lpDD = NULL;
  90.  
  91.     /*
  92.      * If we aren't forced to use the DirectDraw HEL, search for a 3D capable
  93.      * DirectDraw hardware driver and create it.
  94.      */
  95.     if (!(flags & D3DAPP_ONLYDDEMULATION)) {
  96.         LastError = DirectDrawEnumerate(D3DAppIDDEnumCallback, &lpDD);
  97.         if (LastError != DD_OK) {
  98.             D3DAppISetErrorString("DirectDrawEnumerate failed.\n%s",
  99.                                   D3DAppErrorToString(LastError));
  100.             return FALSE;
  101.         }
  102.     }
  103.     if (!lpDD) {
  104.         /*
  105.          * If we haven't created a hardware DD device by now, resort to HEL
  106.          */
  107.         d3dappi.bIsPrimary = TRUE;
  108.         LastError = DirectDrawCreate(NULL, &d3dappi.lpDD, NULL);
  109.         if (LastError != DD_OK) {
  110.             D3DAppISetErrorString("DirectDrawCreate failed.\n%s",
  111.                                   D3DAppErrorToString(LastError));
  112.             return FALSE;
  113.         }
  114.     } else {
  115.         d3dappi.lpDD = lpDD;
  116.     }
  117.     /*
  118.      * Save the original palette for when we are paused.  Just in case we
  119.      * start in a fullscreen mode, put them in ppe.
  120.      */
  121.     hdc = GetDC(NULL);
  122.     GetSystemPaletteEntries(hdc, 0, (1 << 8),
  123.                             (LPPALETTEENTRY)(&Originalppe[0]));
  124.     for (i = 0; i < 256; i++)
  125.         ppe[i] = Originalppe[i];
  126.     ReleaseDC(NULL, hdc);
  127.     return TRUE;
  128. }
  129.  
  130. /***************************************************************************/
  131. /*                   Enumerating the display modes                         */
  132. /***************************************************************************/
  133. /*
  134.  * EnumDisplayModesCallback
  135.  * Callback to save the display mode information.
  136.  */
  137. static HRESULT
  138. CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC pddsd, LPVOID lpContext)
  139. {
  140.     /*
  141.      * Very large resolutions cause problems on some hardware.  They are also
  142.      * not very useful for real-time rendering.  We have chosen to disable
  143.      * them by not reporting them as available.
  144.      */
  145.     if (pddsd->dwWidth > 1024 || pddsd->dwHeight > 768)
  146.         return DDENUMRET_OK;
  147.     /*
  148.      * Save this mode at the end of the mode array and increment mode count
  149.      */
  150.     d3dappi.Mode[d3dappi.NumModes].w = pddsd->dwWidth;
  151.     d3dappi.Mode[d3dappi.NumModes].h = pddsd->dwHeight;
  152.     d3dappi.Mode[d3dappi.NumModes].bpp = pddsd->ddpfPixelFormat.dwRGBBitCount;
  153.     d3dappi.Mode[d3dappi.NumModes].bThisDriverCanDo = FALSE;
  154.     d3dappi.NumModes++;
  155.     if (d3dappi.NumModes == D3DAPP_MAXMODES)
  156.         return DDENUMRET_CANCEL;
  157.     else
  158.         return DDENUMRET_OK;
  159. }
  160.  
  161. /*
  162.  * CompareModes
  163.  * Compare two display modes during sorting.  Modes are sorted by depth and
  164.  * then resolution.
  165.  */
  166. static int
  167. _cdecl CompareModes(const void* element1, const void* element2) {
  168.     D3DAppMode *lpMode1, *lpMode2;
  169.  
  170.     lpMode1 = (D3DAppMode*)element1;
  171.     lpMode2 = (D3DAppMode*)element2;
  172.  
  173.     if (lpMode1->bpp > lpMode2->bpp)
  174.         return -1;
  175.     else if (lpMode2->bpp > lpMode1->bpp)
  176.         return 1;
  177.     else if (lpMode1->w > lpMode2->w)
  178.         return -1;
  179.     else if (lpMode2->w > lpMode1->w)
  180.         return 1;
  181.     else if (lpMode1->h > lpMode2->h)
  182.         return -1;
  183.     else if (lpMode2->h > lpMode1->h)
  184.         return 1;
  185.     else
  186.         return 0;
  187. }
  188.  
  189. /*
  190.  * EnumerateDisplayModes
  191.  * Generates the list of available display modes.
  192.  */
  193. BOOL
  194. D3DAppIEnumDisplayModes(void)
  195. {
  196.     int i;
  197.     /*
  198.      * Get a list of available display modes from DirectDraw
  199.      */
  200.     d3dappi.NumModes = 0;
  201.     LastError = d3dappi.lpDD->lpVtbl->EnumDisplayModes(d3dappi.lpDD, 0, NULL,
  202.                                                 0, EnumDisplayModesCallback);
  203.     if(LastError != DD_OK ) {
  204.         D3DAppISetErrorString("EnumDisplayModes failed.\n%s",
  205.                               D3DAppErrorToString(LastError));
  206.         d3dappi.NumModes = 0;
  207.         return FALSE;
  208.     }
  209.     /*
  210.      * Sort the list of display modes
  211.      */
  212.     qsort((void *)&d3dappi.Mode[0], (size_t)d3dappi.NumModes, sizeof(D3DAppMode),
  213.           CompareModes);
  214.     /*
  215.      * Pick a default display mode.  640x480x16 is a very good mode for
  216.      * rendering, so choose it over all others.  Otherwise, just take the
  217.      * first one.  This selection may be overriden later if a driver is
  218.      * created which cannot render in this mode.
  219.      */
  220.     d3dappi.CurrMode = 0;
  221.     for (i = 0; i < d3dappi.NumModes; i++) {
  222.         if (d3dappi.Mode[i].w == 640 && d3dappi.Mode[i].h == 480 &&
  223.             d3dappi.Mode[i].bpp == 16)
  224.             d3dappi.CurrMode = i;
  225.     }
  226.     memcpy(&d3dappi.ThisMode, &d3dappi.Mode[d3dappi.CurrMode],
  227.            sizeof(D3DAppMode));
  228.     return TRUE;
  229. }
  230.  
  231. /***************************************************************************/
  232. /*               Creating Front and Back Buffers (and misc surf funcs)     */
  233. /***************************************************************************/
  234. /*
  235.  * D3DAppICreateSurface
  236.  * Create a DirectDraw Surface of the given description.  Using this function
  237.  * ensures that all surfaces end up in system memory if that option was set.
  238.  * Returns the result of the CreateSurface call.
  239.  */
  240. HRESULT
  241. D3DAppICreateSurface(LPDDSURFACEDESC lpDDSurfDesc,
  242.                 LPDIRECTDRAWSURFACE FAR *lpDDSurface) {
  243.     HRESULT result;
  244.     if (d3dappi.bOnlySystemMemory)
  245.         lpDDSurfDesc->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  246.     result = d3dappi.lpDD->lpVtbl->CreateSurface(d3dappi.lpDD, lpDDSurfDesc,
  247.                                                  lpDDSurface, NULL);
  248.     return result;
  249. }
  250.  
  251. /*
  252.  * D3DAppIGetSurfDesc
  253.  * Get the description of the given surface.  Returns the result of the
  254.  * GetSurfaceDesc call.
  255.  */
  256. HRESULT
  257. D3DAppIGetSurfDesc(LPDDSURFACEDESC lpDDSurfDesc,LPDIRECTDRAWSURFACE lpDDSurf)
  258. {
  259.     HRESULT result;
  260.     memset(lpDDSurfDesc, 0, sizeof(DDSURFACEDESC));
  261.     lpDDSurfDesc->dwSize = sizeof(DDSURFACEDESC);
  262.     result = lpDDSurf->lpVtbl->GetSurfaceDesc(lpDDSurf, lpDDSurfDesc);
  263.     return result;
  264. }
  265.  
  266. /*
  267.  * D3DAppICreateBuffers
  268.  * Creates the front and back buffers for the window or fullscreen case
  269.  * depending on the bFullscreen flag.  In the window case, bpp is ignored.
  270.  */
  271. BOOL
  272. D3DAppICreateBuffers(HWND hwnd, int w, int h, int bpp, BOOL bFullscreen)
  273. {
  274.     DDSURFACEDESC ddsd;
  275.     DDSCAPS ddscaps;
  276.  
  277.     /*
  278.      * Release any old objects that might be lying around.  This should have
  279.      * already been taken care of, but just in case...
  280.      */
  281.     RELEASE(lpClipper);
  282.     RELEASE(d3dappi.lpBackBuffer);
  283.     RELEASE(d3dappi.lpFrontBuffer);
  284.     /*
  285.      * The size of the buffers is going to be w x h, so record it now
  286.      */
  287.     if (w < D3DAPP_WINDOWMINIMUM)
  288.         w = D3DAPP_WINDOWMINIMUM;
  289.     if (h < D3DAPP_WINDOWMINIMUM)
  290.         h = D3DAPP_WINDOWMINIMUM;
  291.     szBuffers.cx = w;
  292.     szBuffers.cy = h;
  293.  
  294.     if (bFullscreen) {
  295.         /*
  296.          * Create a complex flipping surface for fullscreen mode with one
  297.          * back buffer.
  298.          */
  299.         memset(&ddsd,0,sizeof(DDSURFACEDESC));
  300.         ddsd.dwSize = sizeof( ddsd );
  301.         ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  302.         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
  303.             DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX;
  304.         ddsd.dwBackBufferCount = 1;
  305.         LastError = D3DAppICreateSurface(&ddsd, &d3dappi.lpFrontBuffer);
  306.         if(LastError != DD_OK) {
  307.             D3DAppISetErrorString("CreateSurface for fullscreen flipping surface failed.\n%s",
  308.                                   D3DAppErrorToString(LastError));
  309.             goto exit_with_error;
  310.         }
  311.         /* 
  312.          * Obtain a pointer to the back buffer surface created above so we
  313.          * can use it later.  For now, just check to see if it ended up in
  314.          * video memory (FYI).
  315.          */
  316.         ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  317.         LastError = d3dappi.lpFrontBuffer->lpVtbl->GetAttachedSurface(d3dappi.lpFrontBuffer, &ddscaps, &d3dappi.lpBackBuffer);
  318.         if(LastError != DD_OK) {
  319.             D3DAppISetErrorString("GetAttachedSurface failed to get back buffer.\n%s",
  320.                                   D3DAppErrorToString(LastError));
  321.             goto exit_with_error;
  322.         }
  323.         LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpBackBuffer);
  324.         if (LastError != DD_OK) {
  325.             D3DAppISetErrorString("Failed to get surface description of back buffer.\n%s",
  326.                                   D3DAppErrorToString(LastError));
  327.             goto exit_with_error;
  328.         }
  329.         d3dappi.bBackBufferInVideo =
  330.                   (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE;
  331.     }
  332.     else {
  333.         /*
  334.          * In the window case, create a front buffer which is the primary
  335.          * surface and a back buffer which is an offscreen plane surface.
  336.          */
  337.         memset(&ddsd,0,sizeof(DDSURFACEDESC));
  338.         ddsd.dwSize = sizeof(DDSURFACEDESC);
  339.         ddsd.dwFlags = DDSD_CAPS;
  340.         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  341.         /*
  342.          * If we specify system memory when creating a primary surface, we
  343.          * won't get the actual primary surface in video memory.  So, don't
  344.          * use D3DAppICreateSurface().
  345.          */
  346.         LastError = d3dappi.lpDD->lpVtbl->CreateSurface(d3dappi.lpDD,
  347.                                         &ddsd, &d3dappi.lpFrontBuffer, NULL);
  348.         if(LastError != DD_OK ) {
  349.             D3DAppISetErrorString("CreateSurface for window front buffer failed.\n%s",
  350.                                   D3DAppErrorToString(LastError));
  351.             goto exit_with_error;
  352.         }
  353.         ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
  354.         ddsd.dwWidth = w;
  355.         ddsd.dwHeight = h;
  356.         ddsd.ddsCaps.dwCaps= DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
  357.         LastError = D3DAppICreateSurface(&ddsd, &d3dappi.lpBackBuffer);
  358.         if (LastError != DD_OK) {
  359.             D3DAppISetErrorString("CreateSurface for window back buffer failed.\n%s",
  360.                                   D3DAppErrorToString(LastError));
  361.             goto exit_with_error;
  362.         }
  363.         /*
  364.          * Check to see if the back buffer is in video memory (FYI).
  365.          */
  366.         LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpBackBuffer);
  367.         if (LastError != DD_OK) {
  368.             D3DAppISetErrorString("Failed to get surface description for back buffer.\n%s",
  369.                                   D3DAppErrorToString(LastError));
  370.             goto exit_with_error;
  371.         }
  372.         d3dappi.bBackBufferInVideo =
  373.                   (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE;
  374.         /*
  375.          * Create the DirectDraw Clipper object and attach it to the window
  376.          * and front buffer.
  377.          */
  378.         LastError = d3dappi.lpDD->lpVtbl->CreateClipper(d3dappi.lpDD, 0,
  379.                                                         &lpClipper, NULL);
  380.         if(LastError != DD_OK ) {
  381.             D3DAppISetErrorString("CreateClipper failed.\n%s",
  382.                                   D3DAppErrorToString(LastError));
  383.             goto exit_with_error;
  384.         }
  385.         LastError = lpClipper->lpVtbl->SetHWnd(lpClipper, 0, hwnd);
  386.         if(LastError != DD_OK ) {
  387.             D3DAppISetErrorString("Attaching clipper to window failed.\n%s",
  388.                                   D3DAppErrorToString(LastError));
  389.             goto exit_with_error;
  390.         }
  391.         LastError =
  392.              d3dappi.lpFrontBuffer->lpVtbl->SetClipper(d3dappi.lpFrontBuffer,
  393.                                                        lpClipper);
  394.         if(LastError != DD_OK ) {
  395.             D3DAppISetErrorString("Attaching clipper to front buffer failed.\n%s",
  396.                                   D3DAppErrorToString(LastError));
  397.             goto exit_with_error;
  398.         }
  399.     }
  400.  
  401.     D3DAppIClearBuffers();
  402.     return TRUE;
  403.  
  404. exit_with_error:
  405.     RELEASE(d3dappi.lpFrontBuffer);
  406.     RELEASE(d3dappi.lpBackBuffer);
  407.     RELEASE(lpClipper);
  408.     return FALSE;
  409. }
  410.  
  411. /*
  412.  * D3DAppICheckForPalettized
  413.  * If the front/back buffer is palettized, we need to create a palette.
  414.  */
  415. BOOL
  416. D3DAppICheckForPalettized(void)
  417. {
  418.     DDSURFACEDESC ddsd;
  419.     /*
  420.      * Get the back buffer surface description and check to see if it's
  421.      * palettized
  422.      */
  423.     LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpBackBuffer);
  424.     if (LastError != DD_OK) {
  425.         D3DAppISetErrorString("Failed to get surface description for back buffer for palettizing.\n%s",
  426.                               D3DAppErrorToString(LastError));
  427.         goto exit_with_error;
  428.     }
  429.     bPrimaryPalettized = 
  430.         (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) ? TRUE : FALSE;
  431.  
  432.     if (bPrimaryPalettized) {
  433.         int i;
  434.         /*
  435.          * Get the current palette.
  436.          */
  437.         HDC hdc = GetDC(NULL);
  438.         GetSystemPaletteEntries(hdc, 0, (1 << 8), ppe);
  439.         ReleaseDC(NULL, hdc);
  440.         /*
  441.          * Change the flags on the palette entries to allow D3D to change
  442.          * some of them.  In the window case, we must not change the top and
  443.          * bottom ten (system colors), but in a fullscreen mode we can have
  444.          * all but the first and last.
  445.          */
  446.         if (!d3dappi.bFullscreen) {
  447.             for (i = 0; i < 10; i++) ppe[i].peFlags = D3DPAL_READONLY;
  448.             for (i = 10; i < 256 - 10; i++) ppe[i].peFlags = PC_RESERVED;
  449.             for (i = 256 - 10; i < 256; i++) ppe[i].peFlags = D3DPAL_READONLY;
  450.         } else {
  451.             ppe[0].peFlags = D3DPAL_READONLY;
  452.             for (i = 1; i < 255; i++) ppe[i].peFlags = PC_RESERVED;
  453.             ppe[255].peFlags = D3DPAL_READONLY;
  454.         }
  455.         /*
  456.          * Create a palette using the old colors and new flags
  457.          */
  458.         LastError = d3dappi.lpDD->lpVtbl->CreatePalette(d3dappi.lpDD,
  459.                                            DDPCAPS_8BIT | DDPCAPS_INITIALIZE,
  460.                                            ppe, &lpPalette, NULL);
  461.         if (LastError != DD_OK) {
  462.             D3DAppISetErrorString("CreatePalette failed.\n%s",
  463.                                   D3DAppErrorToString(LastError));
  464.             goto exit_with_error;
  465.         }
  466.         /*
  467.          * Set this as the front and back buffers' palette
  468.          */
  469.         LastError =
  470.                d3dappi.lpBackBuffer->lpVtbl->SetPalette(d3dappi.lpBackBuffer,
  471.                                                         lpPalette);
  472.         if(LastError != DD_OK ) {
  473.             D3DAppISetErrorString("SetPalette failed on back buffer.\n%s",
  474.                                   D3DAppErrorToString(LastError));
  475.             goto exit_with_error;
  476.         }
  477.         LastError =
  478.              d3dappi.lpFrontBuffer->lpVtbl->SetPalette(d3dappi.lpFrontBuffer,
  479.                                                        lpPalette);
  480.         if(LastError != DD_OK ) {
  481.             D3DAppISetErrorString("SetPalette failed on front buffer.\n%s",
  482.                                   D3DAppErrorToString(LastError));
  483.             goto exit_with_error;
  484.         }
  485.         /*
  486.          * The palette is now valid, so set it again on anyt WM_ACTIVATE
  487.          */
  488.         bPaletteActivate = TRUE;
  489.     }
  490.     return TRUE;
  491. exit_with_error:
  492.     RELEASE(lpPalette);
  493.     return FALSE;
  494. }
  495.  
  496. /***************************************************************************/
  497. /*                           Creation of Z-Buffer                          */
  498. /***************************************************************************/
  499. /*
  500.  * D3DAppICreateZBuffer
  501.  * Create a Z-Buffer of the appropriate depth and attach it to the back
  502.  * buffer.
  503.  */
  504. BOOL
  505. D3DAppICreateZBuffer(int w, int h, int driver)
  506. {
  507.     DDSURFACEDESC ddsd;
  508.     DWORD devDepth;
  509.     /*
  510.      * Release any Z-Buffer that might be around just in case.
  511.      */
  512.     RELEASE(d3dappi.lpZBuffer);
  513.     
  514.     /*
  515.      * If this driver does not do z-buffering, don't create a z-buffer
  516.      */
  517.     if (!d3dappi.Driver[driver].bDoesZBuffer)
  518.         return TRUE;
  519.  
  520.     memset(&ddsd, 0 ,sizeof(DDSURFACEDESC));
  521.     ddsd.dwSize = sizeof( ddsd );
  522.     ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS |
  523.                    DDSD_ZBUFFERBITDEPTH;
  524.     ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
  525.     ddsd.dwHeight = h;
  526.     ddsd.dwWidth = w;
  527.     /*
  528.      * If this is a hardware D3D driver, the Z-Buffer MUST end up in video
  529.      * memory.  Otherwise, it MUST end up in system memory.
  530.      */
  531.     if (d3dappi.Driver[driver].bIsHardware)
  532.         ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  533.     else
  534.         ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  535.     /*
  536.      * Get the Z buffer bit depth from this driver's D3D device description
  537.      */
  538.     devDepth = d3dappi.Driver[driver].Desc.dwDeviceZBufferBitDepth;
  539.     if (devDepth & DDBD_32)
  540.         ddsd.dwZBufferBitDepth = 32;
  541.     else if (devDepth & DDBD_24)
  542.         ddsd.dwZBufferBitDepth = 24;
  543.     else if (devDepth & DDBD_16)
  544.         ddsd.dwZBufferBitDepth = 16;
  545.     else if (devDepth & DDBD_8)
  546.         ddsd.dwZBufferBitDepth = 8;
  547.     else {
  548.         D3DAppISetErrorString("Unsupported Z-buffer depth requested by device.\n");
  549.         return FALSE;
  550.     }
  551.     LastError = d3dappi.lpDD->lpVtbl->CreateSurface(d3dappi.lpDD, &ddsd,
  552.                                                     &d3dappi.lpZBuffer,
  553.                                                     NULL);
  554.     if(LastError != DD_OK) {
  555.         D3DAppISetErrorString("CreateSurface for Z-buffer failed.\n%s",
  556.                               D3DAppErrorToString(LastError));
  557.         goto exit_with_error;
  558.     }
  559.     /*
  560.      * Attach the Z-buffer to the back buffer so D3D will find it
  561.      */
  562.     LastError =
  563.        d3dappi.lpBackBuffer->lpVtbl->AddAttachedSurface(d3dappi.lpBackBuffer,
  564.                                                         d3dappi.lpZBuffer);
  565.     if(LastError != DD_OK) {
  566.         D3DAppISetErrorString("AddAttachedBuffer failed for Z-Buffer.\n%s",
  567.                               D3DAppErrorToString(LastError));
  568.         goto exit_with_error;
  569.     }
  570.     /*
  571.      * Find out if it ended up in video memory.
  572.      */
  573.     LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpZBuffer);
  574.     if (LastError != DD_OK) {
  575.         D3DAppISetErrorString("Failed to get surface description of Z buffer.\n%s",
  576.                               D3DAppErrorToString(LastError));
  577.         goto exit_with_error;
  578.     }
  579.     d3dappi.bZBufferInVideo =
  580.                   (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE;
  581.     if (d3dappi.Driver[driver].bIsHardware && !d3dappi.bZBufferInVideo) {
  582.         D3DAppISetErrorString("Could not fit the Z-buffer in video memory for this hardware device.\n");
  583.         goto exit_with_error;
  584.     }
  585.  
  586.     return TRUE;
  587.  
  588. exit_with_error:
  589.     RELEASE(d3dappi.lpZBuffer);
  590.     return FALSE;
  591. }
  592.  
  593. /***************************************************************************/
  594. /*                             WM_SIZE Handler                             */
  595. /***************************************************************************/
  596. /*
  597.  * D3DAppIHandleWM_SIZE
  598.  * Processes the WM_SIZE message.  Resizes all the buffers and re-creates
  599.  * device if necessary.
  600.  */
  601. BOOL
  602. D3DAppIHandleWM_SIZE(LRESULT* lresult, HWND hwnd, UINT message,
  603.                      WPARAM wParam, LPARAM lParam)
  604. {
  605.     int w, h, i;
  606.     /*
  607.      * If we have minimzied, take note and call the default window proc
  608.      */
  609.     if (wParam == SIZE_MINIMIZED) {
  610.         d3dappi.bMinimized = TRUE;
  611.         *lresult = DefWindowProc(hwnd, message, wParam, lParam);
  612.         return TRUE;
  613.     }
  614.     /*
  615.      * In fullscreen mode, restore our surfaces and let DDraw take
  616.      * care of the rest.
  617.      */
  618.     if (d3dappi.bFullscreen) {
  619.         D3DAppIValidateDirtyRects();
  620.         D3DAppCheckForLostSurfaces();
  621.         d3dappi.bMinimized = FALSE;
  622.         *lresult = DefWindowProc(hwnd, message, wParam, lParam);
  623.         return TRUE;
  624.     }
  625.     /*
  626.      * If we are minimized, this is the un-minimized size message.
  627.      */
  628.     if (d3dappi.bMinimized) {
  629.         /*
  630.          * Restore our surfaces and update the dirty rectangle info
  631.          */
  632.         D3DAppIValidateDirtyRects();
  633.         D3DAppCheckForLostSurfaces();
  634.         d3dappi.bMinimized = FALSE;
  635.         *lresult = DefWindowProc(hwnd, message, wParam, lParam);
  636.         return TRUE;
  637.     }
  638.     /*
  639.      * Since we are still here, this must be a regular, window resize
  640.      * message.  A new viewport will definitely be needed, but the
  641.      * device and buffers will only be re-created if they have gotten bigger
  642.      * or change size by a very large amount.
  643.      */
  644.     D3DAppIGetClientWin(hwnd);
  645.     w = LOWORD(lParam);
  646.     h = HIWORD(lParam);
  647.     /*
  648.      * If w and h are under the minimum, create buffers of the minimum size
  649.      */
  650.     if (w < D3DAPP_WINDOWMINIMUM)
  651.         w = D3DAPP_WINDOWMINIMUM;
  652.     if (h < D3DAPP_WINDOWMINIMUM)
  653.         h = D3DAPP_WINDOWMINIMUM;
  654.     /*
  655.      * Destroy the viewport and all execute buffers
  656.      */
  657.     d3dappi.bRenderingIsOK = FALSE;
  658.     ATTEMPT(D3DAppICallDeviceDestroyCallback());
  659.     /*
  660.      * Only create a new device and buffers if they changed significantly,
  661.      * otherwise just make sure the old buffers aren't lost.
  662.      */
  663.     if ((w > szBuffers.cx || h > szBuffers.cy) ||
  664.         (w < szBuffers.cx / 2 || h < szBuffers.cy / 2)) {
  665.         /*
  666.          * Release the device
  667.          */
  668.         RELEASE(d3dappi.lpD3DDevice);
  669.         /*
  670.          * Release the old buffers
  671.          */
  672.         RELEASE(d3dappi.lpZBuffer);
  673.         RELEASE(lpPalette);
  674.         RELEASE(lpClipper);
  675.         RELEASE(d3dappi.lpBackBuffer);
  676.         RELEASE(d3dappi.lpFrontBuffer);
  677.         /*
  678.          * Create new ones
  679.          */
  680.         ATTEMPT(D3DAppICreateBuffers(hwnd, w, h, D3DAPP_BOGUS, FALSE));
  681.         ATTEMPT(D3DAppICheckForPalettized());
  682.         ATTEMPT(D3DAppICreateZBuffer(w, h, d3dappi.CurrDriver));
  683.         /*
  684.          * Create the driver
  685.          */
  686.         ATTEMPT(D3DAppICreateDevice(d3dappi.CurrDriver));
  687.         /*
  688.          * Since the driver did not change, the texture surfaces are still valid.
  689.          * We just need to get new handles.
  690.          */
  691.         if (d3dappi.ThisDriver.bDoesTextures) {
  692.             for (i = 0; i < d3dappi.NumTextures; i++) {
  693.                 D3DAppIGetTextureHandle(i);
  694.             }
  695.         }
  696.     } else {
  697.         D3DAppCheckForLostSurfaces();
  698.     }
  699.     /*
  700.      * Call the device create callback to create the viewport, set the render
  701.      * state and clear the dirty rectangle info
  702.      */
  703.     ATTEMPT(D3DAppICallDeviceCreateCallback(w, h));
  704.     ATTEMPT(D3DAppISetRenderState());
  705.     D3DAppIValidateDirtyRects();
  706.     d3dappi.bRenderingIsOK = TRUE;
  707.     /*
  708.      * Call the default window proc
  709.      */
  710.     *lresult = DefWindowProc(hwnd, message, wParam, lParam);
  711.     return TRUE;
  712. exit_with_error:
  713.     D3DAppICallDeviceDestroyCallback();
  714.     RELEASE(d3dappi.lpD3DDevice);
  715.     RELEASE(d3dappi.lpZBuffer);
  716.     RELEASE(lpPalette);
  717.     RELEASE(lpClipper);
  718.     RELEASE(d3dappi.lpBackBuffer);
  719.     RELEASE(d3dappi.lpFrontBuffer);
  720.     return FALSE;
  721. }
  722.  
  723. /***************************************************************************/
  724. /*              Setting the display mode and cooperative level             */
  725. /***************************************************************************/
  726. /*
  727.  * D3DAppISetCoopLevel
  728.  * Set the cooperative level to exclusive mode for fullscreen and normal for
  729.  * a window.  Set the bIgnoreWM_SIZE flag because SetCooperativeLevel
  730.  * generates a WM_SIZE message you do not have to resize the buffers on.
  731.  */
  732. BOOL
  733. D3DAppISetCoopLevel(HWND hwnd, BOOL bFullscreen)
  734. {
  735.     if (bFullscreen) {
  736.         bIgnoreWM_SIZE = TRUE;
  737.         LastError = d3dappi.lpDD->lpVtbl->SetCooperativeLevel(d3dappi.lpDD,
  738.                                    hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
  739.         bIgnoreWM_SIZE = FALSE;
  740.         if(LastError != DD_OK ) {
  741.             D3DAppISetErrorString("SetCooperativeLevel to fullscreen failed.\n%s",
  742.                                   D3DAppErrorToString(LastError));
  743.             return FALSE;
  744.         }
  745.         d3dappi.bFullscreen = TRUE;
  746.     } else {
  747.         bIgnoreWM_SIZE = TRUE;
  748.         LastError = d3dappi.lpDD->lpVtbl->SetCooperativeLevel(d3dappi.lpDD,
  749.                                                          hwnd, DDSCL_NORMAL);
  750.         bIgnoreWM_SIZE = FALSE;
  751.         if(LastError != DD_OK ) {
  752.             D3DAppISetErrorString("SetCooperativeLevel to normal failed.\n%s",
  753.                                   D3DAppErrorToString(LastError));
  754.             return FALSE;
  755.         }
  756.         d3dappi.bFullscreen = FALSE;
  757.     }
  758.     return TRUE;
  759. }
  760.  
  761. /*
  762.  * D3DAppISetDisplayMode
  763.  * Set the display mode to the given dimensions and bits per pixel.  The
  764.  * bIgnoreWM_SIZE message is set because the display change generates a
  765.  * WM_SIZE message which we don't want to resize the buffers on.
  766.  */
  767. BOOL
  768. D3DAppISetDisplayMode(int w, int h, int bpp)
  769. {
  770.     d3dappi.ThisMode.w = w; d3dappi.ThisMode.h = h;
  771.     d3dappi.ThisMode.bpp = bpp;
  772.     bIgnoreWM_SIZE = TRUE;
  773.     LastError = d3dappi.lpDD->lpVtbl->SetDisplayMode(d3dappi.lpDD, w, h,
  774.                                                      bpp);
  775.     bIgnoreWM_SIZE = FALSE;
  776.     if(LastError != DD_OK ) {
  777.         D3DAppISetErrorString("SetDisplayMode to %dx%dx%d failed\n%s",
  778.                               w, h, bpp, D3DAppErrorToString(LastError));
  779.         return FALSE;
  780.     }
  781.     return TRUE;
  782. }
  783.  
  784. /*
  785.  * D3DAppIRestoreDispMode
  786.  * Restores the display mode to the current windows display mode.  The
  787.  * bIgnoreWM_SIZE message is set because the display change generates a
  788.  * WM_SIZE message which we don't want to resize the buffers on.
  789.  */
  790. BOOL
  791. D3DAppIRestoreDispMode(void)
  792. {
  793.     bIgnoreWM_SIZE = TRUE;
  794.     LastError = d3dappi.lpDD->lpVtbl->RestoreDisplayMode(d3dappi.lpDD);
  795.     if (LastError != DD_OK) {
  796.         D3DAppISetErrorString("RestoreDisplayMode failed.\n%s",
  797.                               D3DAppErrorToString(LastError));
  798.         return FALSE;
  799.     }
  800.     bIgnoreWM_SIZE = FALSE;
  801.     return TRUE;
  802. }
  803.  
  804. /*
  805.  * D3DAppRememberWindowsMode
  806.  * Record the current display mode in d3dappi.WindowsDisplay
  807.  */
  808. BOOL
  809. D3DAppIRememberWindowsMode(void)
  810. {
  811.     DDSURFACEDESC ddsd;
  812.  
  813.     memset(&ddsd, 0, sizeof(DDSURFACEDESC));
  814.     ddsd.dwSize = sizeof(DDSURFACEDESC);
  815.     LastError = d3dappi.lpDD->lpVtbl->GetDisplayMode(d3dappi.lpDD, &ddsd);
  816.     if (LastError != DD_OK) {
  817.         D3DAppISetErrorString("Getting the current display mode failed.\n%s",
  818.                               D3DAppErrorToString(LastError));
  819.         return FALSE;
  820.     }
  821.     d3dappi.WindowsDisplay.w = ddsd.dwWidth;
  822.     d3dappi.WindowsDisplay.h = ddsd.dwHeight;
  823.     d3dappi.WindowsDisplay.bpp = ddsd.ddpfPixelFormat.dwRGBBitCount;
  824.     return TRUE;
  825. }
  826.  
  827. /***************************************************************************/
  828. /*                          Misc DD Utilities                              */
  829. /***************************************************************************/
  830.  
  831. /*
  832.  * D3DAppIClearBuffers
  833.  * Clear the front and back buffers to black
  834.  */
  835. BOOL
  836. D3DAppIClearBuffers(void)
  837. {
  838.     DDSURFACEDESC ddsd;
  839.     RECT dst;
  840.     DDBLTFX ddbltfx;
  841.     /*
  842.      * Find the width and height of the front buffer by getting its
  843.      * DDSURFACEDESC
  844.      */
  845.     if (d3dappi.lpFrontBuffer) {
  846.         LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpFrontBuffer);
  847.         if (LastError != DD_OK) {
  848.             D3DAppISetErrorString("Failure getting the surface description of the front buffer before clearing.\n%s",
  849.                                   D3DAppErrorToString(LastError));
  850.             return FALSE;
  851.         }
  852.         /*
  853.          * Clear the front buffer to black
  854.          */
  855.         memset(&ddbltfx, 0, sizeof(ddbltfx));
  856.         ddbltfx.dwSize = sizeof(DDBLTFX);
  857.         SetRect(&dst, 0, 0, ddsd.dwWidth, ddsd.dwHeight);
  858.         LastError = d3dappi.lpFrontBuffer->lpVtbl->Blt(d3dappi.lpFrontBuffer,
  859.                                                     &dst, NULL, NULL, 
  860.                                                     DDBLT_COLORFILL | DDBLT_WAIT,
  861.                                                     &ddbltfx);
  862.         if (LastError != DD_OK) {
  863.             D3DAppISetErrorString("Clearing the front buffer failed.\n%s",
  864.                                   D3DAppErrorToString(LastError));
  865.             return FALSE;
  866.         }
  867.     }
  868.     if (d3dappi.lpBackBuffer) {
  869.         /*
  870.          * Find the width and height of the back buffer by getting its
  871.          * DDSURFACEDESC
  872.          */
  873.         LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpBackBuffer);
  874.         if (LastError != DD_OK) {
  875.             D3DAppISetErrorString("Failure while getting the surface description of the back buffer before clearing.\n%s",
  876.                                   D3DAppErrorToString(LastError));
  877.             return FALSE;
  878.         }
  879.         /*
  880.          * Clear the back buffer to black
  881.          */
  882.         memset(&ddbltfx, 0, sizeof(ddbltfx));
  883.         ddbltfx.dwSize = sizeof(DDBLTFX);
  884.         SetRect(&dst, 0, 0, ddsd.dwWidth, ddsd.dwHeight);
  885.         LastError = d3dappi.lpBackBuffer->lpVtbl->Blt(d3dappi.lpBackBuffer, &dst,
  886.                                                      NULL, NULL,
  887.                                                      DDBLT_COLORFILL | DDBLT_WAIT,
  888.                                                      &ddbltfx);
  889.         if (LastError != DD_OK) {
  890.             D3DAppISetErrorString("Clearing the front buffer failed.\n%s",
  891.                                   D3DAppErrorToString(LastError));
  892.             return FALSE;
  893.         }
  894.     }
  895.     return TRUE;
  896. }
  897.  
  898. /*
  899.  * D3DAppIBPPToDDBD
  900.  * Convert an integer bit per pixel number to a DirectDraw bit depth flag
  901.  */
  902. DWORD
  903. D3DAppIBPPToDDBD(int bpp)
  904. {
  905.     switch(bpp) {
  906.         case 1:
  907.             return DDBD_1;
  908.         case 2:
  909.             return DDBD_2;
  910.         case 4:
  911.             return DDBD_4;
  912.         case 8:
  913.             return DDBD_8;
  914.         case 16:
  915.             return DDBD_16;
  916.         case 24:
  917.             return DDBD_24;
  918.         case 32:
  919.             return DDBD_32;
  920.         default:
  921.             return (DWORD)D3DAPP_BOGUS;
  922.     }
  923. }
  924.  
  925. /*
  926.  * D3DAppTotalVideoMemory
  927.  * Returns the amount of total video memory supported (not free)
  928.  */
  929. DWORD
  930. D3DAppTotalVideoMemory(void)
  931. {
  932.     DDCAPS DriverCaps, HELCaps;
  933.     memset (&DriverCaps, 0, sizeof(DDCAPS));
  934.     DriverCaps.dwSize = sizeof(DDCAPS);
  935.     memset (&HELCaps, 0, sizeof(DDCAPS));
  936.     HELCaps.dwSize = sizeof(DDCAPS);
  937.     LastError = d3dappi.lpDD->lpVtbl->GetCaps(d3dappi.lpDD, &DriverCaps,
  938.                                               &HELCaps);
  939.     if (LastError != DD_OK) {
  940.         D3DAppISetErrorString("Getting DD capabilities failed while checking total video memory.\n%s",
  941.                               D3DAppErrorToString(LastError));
  942.         return 0L;
  943.     }
  944.     if (DriverCaps.dwVidMemTotal)
  945.         return DriverCaps.dwVidMemTotal;
  946.     else
  947.         return HELCaps.dwVidMemTotal;
  948. }
  949.