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

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