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 / tri3 / ddcalls.c < prev    next >
C/C++ Source or Header  |  1997-07-14  |  33KB  |  976 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. CompareModes(const void* element1, const void* element2)
  168. {
  169.     D3DAppMode *lpMode1, *lpMode2;
  170.  
  171.     lpMode1 = (D3DAppMode*)element1;
  172.     lpMode2 = (D3DAppMode*)element2;
  173.  
  174.     if (lpMode1->bpp > lpMode2->bpp)
  175.         return -1;
  176.     else if (lpMode2->bpp > lpMode1->bpp)
  177.         return 1;
  178.     else if (lpMode1->w > lpMode2->w)
  179.         return -1;
  180.     else if (lpMode2->w > lpMode1->w)
  181.         return 1;
  182.     else if (lpMode1->h > lpMode2->h)
  183.         return -1;
  184.     else if (lpMode2->h > lpMode1->h)
  185.         return 1;
  186.     else
  187.         return 0;
  188. }
  189.  
  190. /*
  191.  * EnumerateDisplayModes
  192.  * Generates the list of available display modes.
  193.  */
  194. BOOL
  195. D3DAppIEnumDisplayModes(void)
  196. {
  197.     int i;
  198.     /*
  199.      * Get a list of available display modes from DirectDraw
  200.      */
  201.     d3dappi.NumModes = 0;
  202.     LastError = d3dappi.lpDD->lpVtbl->EnumDisplayModes(d3dappi.lpDD, 0, NULL,
  203.                         0, EnumDisplayModesCallback);
  204.     if(LastError != DD_OK ) {
  205.         D3DAppISetErrorString("EnumDisplayModes failed.\n%s",
  206.                   D3DAppErrorToString(LastError));
  207.     d3dappi.NumModes = 0;
  208.         return FALSE;
  209.     }
  210.     /*
  211.      * Sort the list of display modes
  212.      */
  213.     qsort((void *)&d3dappi.Mode[0], (size_t)d3dappi.NumModes, sizeof(D3DAppMode),
  214.           CompareModes);
  215.     /*
  216.      * Pick a default display mode.  640x480x16 is a very good mode for
  217.      * rendering, so choose it over all others.  Otherwise, just take the
  218.      * first one.  This selection may be overriden later if a driver is
  219.      * created which cannot render in this mode.
  220.      */
  221.     d3dappi.CurrMode = 0;
  222.     for (i = 0; i < d3dappi.NumModes; i++) {
  223.     if (d3dappi.Mode[i].w == 640 && d3dappi.Mode[i].h == 480 &&
  224.         d3dappi.Mode[i].bpp == 16)
  225.         d3dappi.CurrMode = i;
  226.     }
  227.     memcpy(&d3dappi.ThisMode, &d3dappi.Mode[d3dappi.CurrMode],
  228.        sizeof(D3DAppMode));
  229.     return TRUE;
  230. }
  231.  
  232. /***************************************************************************/
  233. /*               Creating Front and Back Buffers (and misc surf funcs)     */
  234. /***************************************************************************/
  235. /*
  236.  * D3DAppICreateSurface
  237.  * Create a DirectDraw Surface of the given description.  Using this function
  238.  * ensures that all surfaces end up in system memory if that option was set.
  239.  * Returns the result of the CreateSurface call.
  240.  */
  241. HRESULT
  242. D3DAppICreateSurface(LPDDSURFACEDESC lpDDSurfDesc,
  243.                 LPDIRECTDRAWSURFACE FAR *lpDDSurface) {
  244.     HRESULT result;
  245.     if (d3dappi.bOnlySystemMemory)
  246.         lpDDSurfDesc->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  247.     result = d3dappi.lpDD->lpVtbl->CreateSurface(d3dappi.lpDD, lpDDSurfDesc,
  248.                          lpDDSurface, NULL);
  249.     return result;
  250. }
  251.  
  252. /*
  253.  * D3DAppIGetSurfDesc
  254.  * Get the description of the given surface.  Returns the result of the
  255.  * GetSurfaceDesc call.
  256.  */
  257. HRESULT
  258. D3DAppIGetSurfDesc(LPDDSURFACEDESC lpDDSurfDesc,LPDIRECTDRAWSURFACE lpDDSurf)
  259. {
  260.     HRESULT result;
  261.     memset(lpDDSurfDesc, 0, sizeof(DDSURFACEDESC));
  262.     lpDDSurfDesc->dwSize = sizeof(DDSURFACEDESC);
  263.     result = lpDDSurf->lpVtbl->GetSurfaceDesc(lpDDSurf, lpDDSurfDesc);
  264.     return result;
  265. }
  266.  
  267. /*
  268.  * D3DAppICreateBuffers
  269.  * Creates the front and back buffers for the window or fullscreen case
  270.  * depending on the bFullscreen flag.  In the window case, bpp is ignored.
  271.  */
  272. BOOL
  273. D3DAppICreateBuffers(HWND hwnd, int w, int h, int bpp, BOOL bFullscreen, BOOL bIsHardware)
  274. {
  275.     DDSURFACEDESC ddsd;
  276.     DDSCAPS ddscaps;
  277.  
  278.     /*
  279.      * Release any old objects that might be lying around.  This should have
  280.      * already been taken care of, but just in case...
  281.      */
  282.     RELEASE(lpClipper);
  283.     RELEASE(d3dappi.lpBackBuffer);
  284.     RELEASE(d3dappi.lpFrontBuffer);
  285.     /*
  286.      * The size of the buffers is going to be w x h, so record it now
  287.      */
  288.     if (w < D3DAPP_WINDOWMINIMUM)
  289.     w = D3DAPP_WINDOWMINIMUM;
  290.     if (h < D3DAPP_WINDOWMINIMUM)
  291.     h = D3DAPP_WINDOWMINIMUM;
  292.     szBuffers.cx = w;
  293.     szBuffers.cy = h;
  294.  
  295.     if (bFullscreen) {
  296.         /*
  297.          * Create a complex flipping surface for fullscreen mode with one
  298.      * back buffer.
  299.          */
  300.         memset(&ddsd,0,sizeof(DDSURFACEDESC));
  301.     ddsd.dwSize = sizeof( ddsd );
  302.         ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  303.         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
  304.             DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX;
  305.         ddsd.dwBackBufferCount = 1;
  306.     if (bIsHardware)
  307.         ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  308.         LastError = D3DAppICreateSurface(&ddsd, &d3dappi.lpFrontBuffer);
  309.         if(LastError != DD_OK) {
  310.         if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) {
  311.         D3DAppISetErrorString("There was not enough video memory to create the rendering surface.\nPlease restart the program and try another fullscreen mode with less resolution or lower bit depth.");
  312.         } else {
  313.         D3DAppISetErrorString("CreateSurface for fullscreen flipping surface failed.\n%s",
  314.                       D3DAppErrorToString(LastError));
  315.         }
  316.             goto exit_with_error;
  317.     }
  318.     /* 
  319.      * Obtain a pointer to the back buffer surface created above so we
  320.      * can use it later.  For now, just check to see if it ended up in
  321.      * video memory (FYI).
  322.      */
  323.         ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  324.         LastError = d3dappi.lpFrontBuffer->lpVtbl->GetAttachedSurface(d3dappi.lpFrontBuffer, &ddscaps, &d3dappi.lpBackBuffer);
  325.         if(LastError != DD_OK) {
  326.             D3DAppISetErrorString("GetAttachedSurface failed to get back buffer.\n%s",
  327.                   D3DAppErrorToString(LastError));
  328.             goto exit_with_error;
  329.     }
  330.         LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpBackBuffer);
  331.     if (LastError != DD_OK) {
  332.         D3DAppISetErrorString("Failed to get surface description of back buffer.\n%s",
  333.                   D3DAppErrorToString(LastError));
  334.             goto exit_with_error;
  335.     }
  336.         d3dappi.bBackBufferInVideo =
  337.               (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE;
  338.     }
  339.     else {
  340.         /*
  341.          * In the window case, create a front buffer which is the primary
  342.      * surface and a back buffer which is an offscreen plane surface.
  343.          */
  344.         memset(&ddsd,0,sizeof(DDSURFACEDESC));
  345.         ddsd.dwSize = sizeof(DDSURFACEDESC);
  346.         ddsd.dwFlags = DDSD_CAPS;
  347.         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  348.     /*
  349.      * If we specify system memory when creating a primary surface, we
  350.      * won't get the actual primary surface in video memory.  So, don't
  351.      * use D3DAppICreateSurface().
  352.      */
  353.     LastError = d3dappi.lpDD->lpVtbl->CreateSurface(d3dappi.lpDD,
  354.                     &ddsd, &d3dappi.lpFrontBuffer, NULL);
  355.         if(LastError != DD_OK ) {
  356.         if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) {
  357.         D3DAppISetErrorString("There was not enough video memory to create the rendering surface.\nTo run this program in a window of this size, please adjust your display settings for a smaller desktop area or a lower palette size and restart the program.");
  358.         } else {
  359.         D3DAppISetErrorString("CreateSurface for window front buffer failed.\n%s",
  360.                       D3DAppErrorToString(LastError));
  361.         }
  362.             goto exit_with_error;
  363.         }
  364.         ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
  365.         ddsd.dwWidth = w;
  366.         ddsd.dwHeight = h;
  367.         ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
  368.     if (bIsHardware)
  369.         ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  370.     else
  371.         ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  372.         LastError = D3DAppICreateSurface(&ddsd, &d3dappi.lpBackBuffer);
  373.         if (LastError != DD_OK) {
  374.         if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) {
  375.         D3DAppISetErrorString("There was not enough video memory to create the rendering surface.\nTo run this program in a window of this size, please adjust your display settings for a smaller desktop area or a lower palette size and restart the program.");
  376.         } else {
  377.         D3DAppISetErrorString("CreateSurface for window back buffer failed.\n%s",
  378.                       D3DAppErrorToString(LastError));
  379.         }
  380.             goto exit_with_error;
  381.     }
  382.     /*
  383.      * Check to see if the back buffer is in video memory (FYI).
  384.      */
  385.     LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpBackBuffer);
  386.     if (LastError != DD_OK) {
  387.         D3DAppISetErrorString("Failed to get surface description for back buffer.\n%s",
  388.                   D3DAppErrorToString(LastError));
  389.             goto exit_with_error;
  390.     }
  391.     d3dappi.bBackBufferInVideo =
  392.               (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE;
  393.         /*
  394.          * Create the DirectDraw Clipper object and attach it to the window
  395.      * and front buffer.
  396.          */
  397.         LastError = d3dappi.lpDD->lpVtbl->CreateClipper(d3dappi.lpDD, 0,
  398.                             &lpClipper, NULL);
  399.         if(LastError != DD_OK ) {
  400.             D3DAppISetErrorString("CreateClipper failed.\n%s",
  401.                   D3DAppErrorToString(LastError));
  402.             goto exit_with_error;
  403.     }
  404.         LastError = lpClipper->lpVtbl->SetHWnd(lpClipper, 0, hwnd);
  405.         if(LastError != DD_OK ) {
  406.             D3DAppISetErrorString("Attaching clipper to window failed.\n%s",
  407.                   D3DAppErrorToString(LastError));
  408.             goto exit_with_error;
  409.     }
  410.         LastError =
  411.          d3dappi.lpFrontBuffer->lpVtbl->SetClipper(d3dappi.lpFrontBuffer,
  412.                                lpClipper);
  413.         if(LastError != DD_OK ) {
  414.             D3DAppISetErrorString("Attaching clipper to front buffer failed.\n%s",
  415.                   D3DAppErrorToString(LastError));
  416.             goto exit_with_error;
  417.     }
  418.     }
  419.  
  420.     D3DAppIClearBuffers();
  421.     return TRUE;
  422.  
  423. exit_with_error:
  424.     RELEASE(d3dappi.lpFrontBuffer);
  425.     RELEASE(d3dappi.lpBackBuffer);
  426.     RELEASE(lpClipper);
  427.     return FALSE;
  428. }
  429.  
  430. /*
  431.  * D3DAppICheckForPalettized
  432.  * If the front/back buffer is palettized, we need to create a palette.
  433.  */
  434. BOOL
  435. D3DAppICheckForPalettized(void)
  436. {
  437.     DDSURFACEDESC ddsd;
  438.     /*
  439.      * Get the back buffer surface description and check to see if it's
  440.      * palettized
  441.      */
  442.     LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpBackBuffer);
  443.     if (LastError != DD_OK) {
  444.     D3DAppISetErrorString("Failed to get surface description for back buffer for palettizing.\n%s",
  445.                   D3DAppErrorToString(LastError));
  446.         goto exit_with_error;
  447.     }
  448.     bPrimaryPalettized = 
  449.     (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) ? TRUE : FALSE;
  450.  
  451.     if (bPrimaryPalettized) {
  452.     int i;
  453.     /*
  454.      * Get the current palette.
  455.      */
  456.      HDC hdc = GetDC(NULL);
  457.     GetSystemPaletteEntries(hdc, 0, (1 << 8), ppe);
  458.     ReleaseDC(NULL, hdc);
  459.     /*
  460.      * Change the flags on the palette entries to allow D3D to change
  461.      * some of them.  In the window case, we must not change the top and
  462.      * bottom ten (system colors), but in a fullscreen mode we can have
  463.      * all but the first and last.
  464.      */
  465.         if (!d3dappi.bFullscreen) {
  466.         for (i = 0; i < 10; i++) ppe[i].peFlags = D3DPAL_READONLY;
  467.         for (i = 10; i < 256 - 10; i++) ppe[i].peFlags = D3DPAL_FREE | PC_RESERVED;
  468.         for (i = 256 - 10; i < 256; i++) ppe[i].peFlags = D3DPAL_READONLY;
  469.         } else {
  470.         ppe[0].peFlags = D3DPAL_READONLY;
  471.         for (i = 1; i < 255; i++) ppe[i].peFlags = D3DPAL_FREE | PC_RESERVED;
  472.         ppe[255].peFlags = D3DPAL_READONLY;
  473.     }
  474.     /*
  475.      * Create a palette using the old colors and new flags
  476.      */
  477.     LastError = d3dappi.lpDD->lpVtbl->CreatePalette(d3dappi.lpDD,
  478.                        DDPCAPS_8BIT | DDPCAPS_INITIALIZE,
  479.                        ppe, &lpPalette, NULL);
  480.     if (LastError != DD_OK) {
  481.         D3DAppISetErrorString("CreatePalette failed.\n%s",
  482.                   D3DAppErrorToString(LastError));
  483.             goto exit_with_error;
  484.     }
  485.     /*
  486.      * Set this as the front and back buffers' palette
  487.      */
  488.     LastError =
  489.            d3dappi.lpBackBuffer->lpVtbl->SetPalette(d3dappi.lpBackBuffer,
  490.                                 lpPalette);
  491.         if(LastError != DD_OK ) {
  492.             D3DAppISetErrorString("SetPalette failed on back buffer.\n%s",
  493.                   D3DAppErrorToString(LastError));
  494.             goto exit_with_error;
  495.     }
  496.     LastError =
  497.          d3dappi.lpFrontBuffer->lpVtbl->SetPalette(d3dappi.lpFrontBuffer,
  498.                                lpPalette);
  499.         if(LastError != DD_OK ) {
  500.             D3DAppISetErrorString("SetPalette failed on front buffer.\n%s",
  501.                   D3DAppErrorToString(LastError));
  502.             goto exit_with_error;
  503.     }
  504.     /*
  505.      * The palette is now valid, so set it again on anyt WM_ACTIVATE
  506.      */
  507.     bPaletteActivate = TRUE;
  508.     }
  509.     return TRUE;
  510. exit_with_error:
  511.     RELEASE(lpPalette);
  512.     return FALSE;
  513. }
  514.  
  515. /***************************************************************************/
  516. /*                           Creation of Z-Buffer                          */
  517. /***************************************************************************/
  518. /*
  519.  * D3DAppICreateZBuffer
  520.  * Create a Z-Buffer of the appropriate depth and attach it to the back
  521.  * buffer.
  522.  */
  523. BOOL
  524. D3DAppICreateZBuffer(int w, int h, int driver)
  525. {
  526.     DDSURFACEDESC ddsd;
  527.     DWORD devDepth;
  528.     /*
  529.      * Release any Z-Buffer that might be around just in case.
  530.      */
  531.     RELEASE(d3dappi.lpZBuffer);
  532.     
  533.     /*
  534.      * If this driver does not do z-buffering, don't create a z-buffer
  535.      */
  536.     if (!d3dappi.Driver[driver].bDoesZBuffer)
  537.     return TRUE;
  538.  
  539.     memset(&ddsd, 0 ,sizeof(DDSURFACEDESC));
  540.     ddsd.dwSize = sizeof( ddsd );
  541.     ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS |
  542.            DDSD_ZBUFFERBITDEPTH;
  543.     ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
  544.     ddsd.dwHeight = h;
  545.     ddsd.dwWidth = w;
  546.     /*
  547.      * If this is a hardware D3D driver, the Z-Buffer MUST end up in video
  548.      * memory.  Otherwise, it MUST end up in system memory.
  549.      */
  550.     if (d3dappi.Driver[driver].bIsHardware)
  551.     ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  552.     else
  553.     ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  554.     /*
  555.      * Get the Z buffer bit depth from this driver's D3D device description
  556.      */
  557.     devDepth = d3dappi.Driver[driver].Desc.dwDeviceZBufferBitDepth;
  558.     if (devDepth & DDBD_32)
  559.     ddsd.dwZBufferBitDepth = 32;
  560.     else if (devDepth & DDBD_24)
  561.     ddsd.dwZBufferBitDepth = 24;
  562.     else if (devDepth & DDBD_16)
  563.     ddsd.dwZBufferBitDepth = 16;
  564.     else if (devDepth & DDBD_8)
  565.     ddsd.dwZBufferBitDepth = 8;
  566.     else {
  567.     D3DAppISetErrorString("Unsupported Z-buffer depth requested by device.\n");
  568.     return FALSE;
  569.     }
  570.     LastError = d3dappi.lpDD->lpVtbl->CreateSurface(d3dappi.lpDD, &ddsd,
  571.                             &d3dappi.lpZBuffer,
  572.                             NULL);
  573.     if(LastError != DD_OK) {
  574.     if (LastError == DDERR_OUTOFMEMORY || LastError == DDERR_OUTOFVIDEOMEMORY) {
  575.         if (d3dappi.bFullscreen) {
  576.         D3DAppISetErrorString("There was not enough video memory to create the Z-buffer surface.\nPlease restart the program and try another fullscreen mode with less resolution or lower bit depth.");
  577.         } else {
  578.         D3DAppISetErrorString("There was not enough video memory to create the Z-buffer surface.\nTo run this program in a window of this size, please adjust your display settings for a smaller desktop area or a lower palette size and restart the program.");
  579.         }
  580.     } else {
  581.         D3DAppISetErrorString("CreateSurface for Z-buffer failed.\n%s",
  582.                   D3DAppErrorToString(LastError));
  583.     }
  584.         goto exit_with_error;
  585.     }
  586.     /*
  587.      * Attach the Z-buffer to the back buffer so D3D will find it
  588.      */
  589.     LastError =
  590.        d3dappi.lpBackBuffer->lpVtbl->AddAttachedSurface(d3dappi.lpBackBuffer,
  591.                             d3dappi.lpZBuffer);
  592.     if(LastError != DD_OK) {
  593.         D3DAppISetErrorString("AddAttachedBuffer failed for Z-Buffer.\n%s",
  594.                   D3DAppErrorToString(LastError));
  595.     goto exit_with_error;
  596.     }
  597.     /*
  598.      * Find out if it ended up in video memory.
  599.      */
  600.     LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpZBuffer);
  601.     if (LastError != DD_OK) {
  602.     D3DAppISetErrorString("Failed to get surface description of Z buffer.\n%s",
  603.                   D3DAppErrorToString(LastError));
  604.         goto exit_with_error;
  605.     }
  606.     d3dappi.bZBufferInVideo =
  607.               (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE;
  608.     if (d3dappi.Driver[driver].bIsHardware && !d3dappi.bZBufferInVideo) {
  609.     D3DAppISetErrorString("Could not fit the Z-buffer in video memory for this hardware device.\n");
  610.     goto exit_with_error;
  611.     }
  612.  
  613.     return TRUE;
  614.  
  615. exit_with_error:
  616.     RELEASE(d3dappi.lpZBuffer);
  617.     return FALSE;
  618. }
  619.  
  620. /***************************************************************************/
  621. /*                             WM_SIZE Handler                             */
  622. /***************************************************************************/
  623. /*
  624.  * D3DAppIHandleWM_SIZE
  625.  * Processes the WM_SIZE message.  Resizes all the buffers and re-creates
  626.  * device if necessary.
  627.  */
  628. BOOL
  629. D3DAppIHandleWM_SIZE(LRESULT* lresult, HWND hwnd, UINT message,
  630.              WPARAM wParam, LPARAM lParam)
  631. {
  632.     int w, h, i;
  633.     /*
  634.      * If we have minimzied, take note and call the default window proc
  635.      */
  636.     if (wParam == SIZE_MINIMIZED) {
  637.     d3dappi.bMinimized = TRUE;
  638.     *lresult = DefWindowProc(hwnd, message, wParam, lParam);
  639.     return TRUE;
  640.     }
  641.     /*
  642.      * In fullscreen mode, restore our surfaces and let DDraw take
  643.      * care of the rest.
  644.      */
  645.     if (d3dappi.bFullscreen) {
  646.     D3DAppIValidateDirtyRects();
  647.     D3DAppCheckForLostSurfaces();
  648.     d3dappi.bMinimized = FALSE;
  649.     *lresult = DefWindowProc(hwnd, message, wParam, lParam);
  650.     return TRUE;
  651.     }
  652.     /*
  653.      * If we are minimized, this is the un-minimized size message.
  654.      */
  655.     if (d3dappi.bMinimized) {
  656.     /*
  657.      * Restore our surfaces and update the dirty rectangle info
  658.      */
  659.     D3DAppIValidateDirtyRects();
  660.     D3DAppCheckForLostSurfaces();
  661.     d3dappi.bMinimized = FALSE;
  662.     *lresult = DefWindowProc(hwnd, message, wParam, lParam);
  663.     return TRUE;
  664.     }
  665.     /*
  666.      * Since we are still here, this must be a regular, window resize
  667.      * message.  A new viewport will definitely be needed, but the
  668.      * device and buffers will only be re-created if they have gotten bigger
  669.      * or change size by a very large amount.
  670.      */
  671.     D3DAppIGetClientWin(hwnd);
  672.     w = LOWORD(lParam);
  673.     h = HIWORD(lParam);
  674.     /*
  675.      * If w and h are under the minimum, create buffers of the minimum size
  676.      */
  677.     if (w < D3DAPP_WINDOWMINIMUM)
  678.         w = D3DAPP_WINDOWMINIMUM;
  679.     if (h < D3DAPP_WINDOWMINIMUM)
  680.         h = D3DAPP_WINDOWMINIMUM;
  681.     /*
  682.      * Destroy the viewport and all execute buffers
  683.      */
  684.     d3dappi.bRenderingIsOK = FALSE;
  685.     ATTEMPT(D3DAppICallDeviceDestroyCallback());
  686.     /*
  687.      * Only create a new device and buffers if they changed significantly,
  688.      * otherwise just make sure the old buffers aren't lost.
  689.      */
  690.     if ((w > szBuffers.cx || h > szBuffers.cy) ||
  691.     (w < szBuffers.cx / 2 || h < szBuffers.cy / 2)) {
  692.     /*
  693.      * Release the device
  694.      */
  695.     RELEASE(d3dappi.lpD3DDevice);
  696.     /*
  697.      * Release the old buffers
  698.      */
  699.     RELEASE(d3dappi.lpZBuffer);
  700.     RELEASE(lpPalette);
  701.     RELEASE(lpClipper);
  702.     RELEASE(d3dappi.lpBackBuffer);
  703.     RELEASE(d3dappi.lpFrontBuffer);
  704.     /*
  705.      * Create new ones
  706.      */
  707.     ATTEMPT(D3DAppICreateBuffers(hwnd, w, h, D3DAPP_BOGUS, FALSE, d3dappi.ThisDriver.bIsHardware));
  708.     ATTEMPT(D3DAppICheckForPalettized());
  709.     ATTEMPT(D3DAppICreateZBuffer(w, h, d3dappi.CurrDriver));
  710.     /*
  711.      * Create the driver
  712.      */
  713.     ATTEMPT(D3DAppICreateDevice(d3dappi.CurrDriver));
  714.     /*
  715.      * Since the driver did not change, the texture surfaces are still valid.
  716.      * We just need to get new handles.
  717.      */
  718.     if (d3dappi.ThisDriver.bDoesTextures) {
  719.         for (i = 0; i < d3dappi.NumUsableTextures; i++) {
  720.         D3DAppIGetTextureHandle(i);
  721.         }
  722.     }
  723.     } else {
  724.     D3DAppCheckForLostSurfaces();
  725.     }
  726.     /*
  727.      * Call the device create callback to create the viewport, set the render
  728.      * state and clear the dirty rectangle info
  729.      */
  730.     ATTEMPT(D3DAppICallDeviceCreateCallback(w, h));
  731.     ATTEMPT(D3DAppISetRenderState());
  732.     D3DAppIValidateDirtyRects();
  733.     d3dappi.bRenderingIsOK = TRUE;
  734.     /*
  735.      * Call the default window proc
  736.      */
  737.     *lresult = DefWindowProc(hwnd, message, wParam, lParam);
  738.     return TRUE;
  739. exit_with_error:
  740.     D3DAppICallDeviceDestroyCallback();
  741.     RELEASE(d3dappi.lpD3DDevice);
  742.     RELEASE(d3dappi.lpZBuffer);
  743.     RELEASE(lpPalette);
  744.     RELEASE(lpClipper);
  745.     RELEASE(d3dappi.lpBackBuffer);
  746.     RELEASE(d3dappi.lpFrontBuffer);
  747.     return FALSE;
  748. }
  749.  
  750. /***************************************************************************/
  751. /*              Setting the display mode and cooperative level             */
  752. /***************************************************************************/
  753. /*
  754.  * D3DAppISetCoopLevel
  755.  * Set the cooperative level to exclusive mode for fullscreen and normal for
  756.  * a window.  Set the bIgnoreWM_SIZE flag because SetCooperativeLevel
  757.  * generates a WM_SIZE message you do not have to resize the buffers on.
  758.  */
  759. BOOL
  760. D3DAppISetCoopLevel(HWND hwnd, BOOL bFullscreen)
  761. {
  762.     if (bFullscreen) {
  763.     bIgnoreWM_SIZE = TRUE;
  764.     LastError = d3dappi.lpDD->lpVtbl->SetCooperativeLevel(d3dappi.lpDD,
  765.                    hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
  766.     bIgnoreWM_SIZE = FALSE;
  767.     if(LastError != DD_OK ) {
  768.         D3DAppISetErrorString("SetCooperativeLevel to fullscreen failed.\n%s",
  769.                   D3DAppErrorToString(LastError));
  770.         return FALSE;
  771.     }
  772.     d3dappi.bFullscreen = TRUE;
  773.     } else {
  774.     bIgnoreWM_SIZE = TRUE;
  775.         LastError = d3dappi.lpDD->lpVtbl->SetCooperativeLevel(d3dappi.lpDD,
  776.                              hwnd, DDSCL_NORMAL);
  777.     bIgnoreWM_SIZE = FALSE;
  778.     if(LastError != DD_OK ) {
  779.             D3DAppISetErrorString("SetCooperativeLevel to normal failed.\n%s",
  780.                   D3DAppErrorToString(LastError));
  781.             return FALSE;
  782.         }
  783.     d3dappi.bFullscreen = FALSE;
  784.     }
  785.     return TRUE;
  786. }
  787.  
  788. /*
  789.  * D3DAppISetDisplayMode
  790.  * Set the display mode to the given dimensions and bits per pixel.  The
  791.  * bIgnoreWM_SIZE message is set because the display change generates a
  792.  * WM_SIZE message which we don't want to resize the buffers on.
  793.  */
  794. BOOL
  795. D3DAppISetDisplayMode(int w, int h, int bpp)
  796. {
  797.     d3dappi.ThisMode.w = w; d3dappi.ThisMode.h = h;
  798.     d3dappi.ThisMode.bpp = bpp;
  799.     bIgnoreWM_SIZE = TRUE;
  800.     LastError = d3dappi.lpDD->lpVtbl->SetDisplayMode(d3dappi.lpDD, w, h,
  801.                              bpp);
  802.     bIgnoreWM_SIZE = FALSE;
  803.     if(LastError != DD_OK ) {
  804.         D3DAppISetErrorString("SetDisplayMode to %dx%dx%d failed\n%s",
  805.                   w, h, bpp, D3DAppErrorToString(LastError));
  806.         return FALSE;
  807.     }
  808.     return TRUE;
  809. }
  810.  
  811. /*
  812.  * D3DAppIRestoreDispMode
  813.  * Restores the display mode to the current windows display mode.  The
  814.  * bIgnoreWM_SIZE message is set because the display change generates a
  815.  * WM_SIZE message which we don't want to resize the buffers on.
  816.  */
  817. BOOL
  818. D3DAppIRestoreDispMode(void)
  819. {
  820.     bIgnoreWM_SIZE = TRUE;
  821.     LastError = d3dappi.lpDD->lpVtbl->RestoreDisplayMode(d3dappi.lpDD);
  822.     if (LastError != DD_OK) {
  823.     D3DAppISetErrorString("RestoreDisplayMode failed.\n%s",
  824.                   D3DAppErrorToString(LastError));
  825.     return FALSE;
  826.     }
  827.     bIgnoreWM_SIZE = FALSE;
  828.     return TRUE;
  829. }
  830.  
  831. /*
  832.  * D3DAppRememberWindowsMode
  833.  * Record the current display mode in d3dappi.WindowsDisplay
  834.  */
  835. BOOL
  836. D3DAppIRememberWindowsMode(void)
  837. {
  838.     DDSURFACEDESC ddsd;
  839.  
  840.     memset(&ddsd, 0, sizeof(DDSURFACEDESC));
  841.     ddsd.dwSize = sizeof(DDSURFACEDESC);
  842.     LastError = d3dappi.lpDD->lpVtbl->GetDisplayMode(d3dappi.lpDD, &ddsd);
  843.     if (LastError != DD_OK) {
  844.     D3DAppISetErrorString("Getting the current display mode failed.\n%s",
  845.                   D3DAppErrorToString(LastError));
  846.     return FALSE;
  847.     }
  848.     d3dappi.WindowsDisplay.w = ddsd.dwWidth;
  849.     d3dappi.WindowsDisplay.h = ddsd.dwHeight;
  850.     d3dappi.WindowsDisplay.bpp = ddsd.ddpfPixelFormat.dwRGBBitCount;
  851.     return TRUE;
  852. }
  853.  
  854. /***************************************************************************/
  855. /*                          Misc DD Utilities                              */
  856. /***************************************************************************/
  857.  
  858. /*
  859.  * D3DAppIClearBuffers
  860.  * Clear the front and back buffers to black
  861.  */
  862. BOOL
  863. D3DAppIClearBuffers(void)
  864. {
  865.     DDSURFACEDESC ddsd;
  866.     RECT dst;
  867.     DDBLTFX ddbltfx;
  868.     /*
  869.      * Find the width and height of the front buffer by getting its
  870.      * DDSURFACEDESC
  871.      */
  872.     if (d3dappi.lpFrontBuffer) {
  873.     LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpFrontBuffer);
  874.     if (LastError != DD_OK) {
  875.         D3DAppISetErrorString("Failure getting the surface description of the front buffer before clearing.\n%s",
  876.                   D3DAppErrorToString(LastError));
  877.         return FALSE;
  878.     }
  879.     /*
  880.      * Clear the front 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.lpFrontBuffer->lpVtbl->Blt(d3dappi.lpFrontBuffer,
  886.                             &dst, 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.     if (d3dappi.lpBackBuffer) {
  896.     /*
  897.      * Find the width and height of the back buffer by getting its
  898.      * DDSURFACEDESC
  899.      */
  900.     LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpBackBuffer);
  901.     if (LastError != DD_OK) {
  902.         D3DAppISetErrorString("Failure while getting the surface description of the back buffer before clearing.\n%s",
  903.                   D3DAppErrorToString(LastError));
  904.         return FALSE;
  905.     }
  906.     /*
  907.      * Clear the back buffer to black
  908.      */
  909.     memset(&ddbltfx, 0, sizeof(ddbltfx));
  910.     ddbltfx.dwSize = sizeof(DDBLTFX);
  911.     SetRect(&dst, 0, 0, ddsd.dwWidth, ddsd.dwHeight);
  912.     LastError = d3dappi.lpBackBuffer->lpVtbl->Blt(d3dappi.lpBackBuffer, &dst,
  913.                              NULL, NULL,
  914.                              DDBLT_COLORFILL | DDBLT_WAIT,
  915.                              &ddbltfx);
  916.     if (LastError != DD_OK) {
  917.         D3DAppISetErrorString("Clearing the front buffer failed.\n%s",
  918.                   D3DAppErrorToString(LastError));
  919.         return FALSE;
  920.     }
  921.     }
  922.     return TRUE;
  923. }
  924.  
  925. /*
  926.  * D3DAppIBPPToDDBD
  927.  * Convert an integer bit per pixel number to a DirectDraw bit depth flag
  928.  */
  929. DWORD
  930. D3DAppIBPPToDDBD(int bpp)
  931. {
  932.     switch(bpp) {
  933.     case 1:
  934.         return DDBD_1;
  935.     case 2:
  936.         return DDBD_2;
  937.     case 4:
  938.         return DDBD_4;
  939.     case 8:
  940.         return DDBD_8;
  941.     case 16:
  942.         return DDBD_16;
  943.     case 24:
  944.         return DDBD_24;
  945.     case 32:
  946.         return DDBD_32;
  947.     default:
  948.         return (DWORD)D3DAPP_BOGUS;
  949.     }
  950. }
  951.  
  952. /*
  953.  * D3DAppTotalVideoMemory
  954.  * Returns the amount of total video memory supported (not free)
  955.  */
  956. DWORD
  957. D3DAppTotalVideoMemory(void)
  958. {
  959.     DDCAPS DriverCaps, HELCaps;
  960.     memset (&DriverCaps, 0, sizeof(DDCAPS));
  961.     DriverCaps.dwSize = sizeof(DDCAPS);
  962.     memset (&HELCaps, 0, sizeof(DDCAPS));
  963.     HELCaps.dwSize = sizeof(DDCAPS);
  964.     LastError = d3dappi.lpDD->lpVtbl->GetCaps(d3dappi.lpDD, &DriverCaps,
  965.                           &HELCaps);
  966.     if (LastError != DD_OK) {
  967.     D3DAppISetErrorString("Getting DD capabilities failed while checking total video memory.\n%s",
  968.                   D3DAppErrorToString(LastError));
  969.     return 0L;
  970.     }
  971.     if (DriverCaps.dwVidMemTotal)
  972.     return DriverCaps.dwVidMemTotal;
  973.     else
  974.     return HELCaps.dwVidMemTotal;
  975. }
  976.