DDCALLS.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:32k
源码类别:

Windows编程

开发平台:

Visual C++

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