ddcalls.cpp
上传用户:garry_shen
上传日期:2015-04-15
资源大小:45647k
文件大小:33k
源码类别:

游戏引擎

开发平台:

Visual C++

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