home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / boids / d3dtex.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-15  |  11.9 KB  |  425 lines

  1. /**************************************************************************
  2.  D3DTexture class
  3.  
  4.  **************************************************************************/
  5. #define D3D_OVERLOADS
  6.  
  7. #include <windows.h>
  8. #include <windowsx.h>
  9. #include <ddraw.h>
  10. #include <d3d.h>
  11.  
  12. #include "d3dtex.h"
  13.  
  14. /**************************************************************************
  15.  DEBUG junk
  16.  **************************************************************************/
  17. #if defined(DEBUG) || defined(_DEBUG)
  18. static void DPF(char *fmt, ...)
  19. {
  20.     char ach[128];
  21.     va_list va;
  22.     va_start( va, fmt );
  23.     wvsprintf( ach, fmt, va );
  24.     va_end( va );
  25.     OutputDebugString("TEXTURE: ");
  26.     OutputDebugString(ach);
  27.     OutputDebugString("\r\n");
  28. }
  29. #else
  30. #define DPF if (0) 
  31. #endif
  32.  
  33. /**************************************************************************
  34.  ChooseTextureFormat
  35.  **************************************************************************/
  36.  
  37. typedef struct {
  38.     DWORD           bpp;        // we want a texture format of this bpp
  39.     DDPIXELFORMAT   ddpf;       // place the format here
  40. }   FindTextureData;
  41.  
  42. HRESULT CALLBACK FindTextureCallback(DDSURFACEDESC *DeviceFmt, LPVOID lParam)
  43. {
  44.     FindTextureData * FindData = (FindTextureData *)lParam;
  45.     DDPIXELFORMAT ddpf = DeviceFmt->ddpfPixelFormat;
  46.  
  47.     DPF("FindTexture: %d %s%s%s %08X %08X %08X %08X", 
  48.     ddpf.dwRGBBitCount, 
  49.         (ddpf.dwFlags & (DDPF_ALPHA|DDPF_ALPHAPIXELS)) ? "ALPHA " : "", 
  50.         (ddpf.dwFlags &    (DDPF_RGB)) ? "RGB " : "", 
  51.         (ddpf.dwFlags &    (DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXED4)) ? "PAL " : "", 
  52.     ddpf.dwRBitMask,
  53.     ddpf.dwGBitMask,
  54.     ddpf.dwBBitMask,
  55.     ddpf.dwRGBAlphaBitMask);
  56.  
  57.     //
  58.     // we use GetDC/BitBlt to init textures so we only
  59.     // want to use formats that GetDC will support.
  60.     //
  61.     if (ddpf.dwFlags & (DDPF_ALPHA|DDPF_ALPHAPIXELS))
  62.         return DDENUMRET_OK;
  63.  
  64.     if (ddpf.dwRGBBitCount <= 8 &&
  65.         !(ddpf.dwFlags & (DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXED4)))
  66.         return DDENUMRET_OK;
  67.  
  68.     if (ddpf.dwRGBBitCount > 8 && !(ddpf.dwFlags & DDPF_RGB))
  69.         return DDENUMRET_OK;
  70.  
  71.     //
  72.     // BUGBUG GetDC does not work for 1 or 4bpp YET!
  73.     //
  74.     if (ddpf.dwRGBBitCount < 8)
  75.         return DDENUMRET_OK;
  76.  
  77.     //
  78.     // keep the texture format that is nearest to the bitmap we have
  79.     //
  80.     if (FindData->ddpf.dwRGBBitCount == 0 ||
  81.        (ddpf.dwRGBBitCount >= FindData->bpp &&
  82.        (UINT)(ddpf.dwRGBBitCount - FindData->bpp) < (UINT)(FindData->ddpf.dwRGBBitCount - FindData->bpp)))
  83.     {
  84.         FindData->ddpf = ddpf;
  85.     }
  86.  
  87.     return DDENUMRET_OK;
  88. }
  89.  
  90. void ChooseTextureFormat(IDirect3DDevice2 *Device, DWORD bpp, DDPIXELFORMAT *pddpf)
  91. {
  92.     FindTextureData FindData;
  93.     ZeroMemory(&FindData, sizeof(FindData));
  94.     FindData.bpp = bpp;
  95.     Device->EnumTextureFormats(FindTextureCallback, (LPVOID)&FindData);
  96.     *pddpf = FindData.ddpf;
  97.  
  98.     DPF("ChooseTexture: %d %s%s%s %08X %08X %08X %08X", 
  99.     pddpf->dwRGBBitCount, 
  100.         (pddpf->dwFlags & (DDPF_ALPHA|DDPF_ALPHAPIXELS)) ? "ALPHA " : "", 
  101.         (pddpf->dwFlags &    (DDPF_RGB)) ? "RGB " : "", 
  102.         (pddpf->dwFlags &    (DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXED4)) ? "PAL " : "", 
  103.     pddpf->dwRBitMask,
  104.     pddpf->dwGBitMask,
  105.     pddpf->dwBBitMask,
  106.     pddpf->dwRGBAlphaBitMask);
  107. }
  108.  
  109. /**************************************************************************
  110.  PaletteFromBitmap
  111.  **************************************************************************/
  112.  
  113. static IDirectDrawPalette * PaletteFromBitmap(IDirectDraw *DirectDraw, HBITMAP Bitmap)
  114. {
  115.     IDirectDrawPalette *    Palette = NULL;
  116.     HDC                     BitmapDC;
  117.     DWORD                   adw[256];
  118.     int                     colors, i;
  119.  
  120.     //
  121.     // get the color table from the DIBSection
  122.     //
  123.     BitmapDC = CreateCompatibleDC(NULL);
  124.     SelectObject(BitmapDC, Bitmap);
  125.     colors = GetDIBColorTable(BitmapDC, 0, 256, (RGBQUAD *)adw);
  126.     DeleteDC(BitmapDC);
  127.  
  128.     if (colors != 0)
  129.     {
  130.         //
  131.         // convert BGR to RGB (stupid IBM!)
  132.         //
  133.         for (i=0; i<colors; i++)
  134.             adw[i] = RGB(GetBValue(adw[i]),GetGValue(adw[i]),GetRValue(adw[i]));
  135.  
  136.         //
  137.         // create a DirectDraw palette for the texture.
  138.         //
  139.         DirectDraw->CreatePalette(colors <= 16 ? DDPCAPS_4BIT : DDPCAPS_8BIT,
  140.             (PALETTEENTRY *)adw, &Palette, NULL);
  141.     }
  142.  
  143.     return Palette;
  144. }
  145.  
  146. /**************************************************************************
  147.  GetDD
  148.  
  149.  get the IDirectDraw from a IDirect3DDevice, we need the DD
  150.  to create surfaces.
  151.  
  152.  this function does not do a AddRef on the DirectDraw object
  153.  (ie you dont need to Release)
  154.  
  155.  NOTE if your app has this around as a global you can use
  156.  the global instead of this code.
  157.  
  158.  **************************************************************************/
  159. static IDirectDraw * GetDD(IDirect3DDevice2 *Device)
  160. {
  161.     IDirectDraw *       DirectDraw;
  162.     IDirectDrawSurface *Target;
  163.     IDirectDrawSurface2*Target2;
  164.  
  165.     //
  166.     // get the render target (we need it to get the IDirectDraw)
  167.     //
  168.     if (Device==NULL || Device->GetRenderTarget(&Target) != DD_OK)
  169.         return NULL;
  170.  
  171.     //
  172.     // get the DirectDraw object, but first we need a IDirectDrawSurface2
  173.     //
  174.     if (Target->QueryInterface(IID_IDirectDrawSurface2, (void**)&Target2) != DD_OK)
  175.         return NULL;
  176.     Target->Release();
  177.     Target2->GetDDInterface((void**)&DirectDraw);
  178.     Target2->Release();
  179.     DirectDraw->Release();  // dont up ref count
  180.  
  181.     return DirectDraw;
  182. }
  183.  
  184. /**************************************************************************
  185.  D3DTexture::Load
  186.  
  187.  load a bitmap from the resource, or bmp file and create a
  188.  D3D texture map
  189.  
  190.  **************************************************************************/
  191.  
  192. BOOL D3DTexture::Load(IDirect3DDevice2 *Device, char *BitmapName)
  193. {
  194.     BITMAP              bm;
  195.     DDSURFACEDESC       ddsd;
  196.     HBITMAP             Bitmap;
  197.     IDirectDraw *       DirectDraw;
  198.  
  199.     DPF("D3DTexture::Load(%s)", BitmapName);
  200.  
  201.     //
  202.     // we need a IDirectDraw so we can create a surface.
  203.     //
  204.     if ((DirectDraw = GetDD(Device)) == NULL)
  205.         return FALSE;
  206.  
  207.     //
  208.     // load the bitmap from a resource or file.
  209.     //
  210.     Bitmap = (HBITMAP)LoadImage(GetModuleHandle(NULL), BitmapName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
  211.  
  212.     if (Bitmap == NULL)
  213.         Bitmap = (HBITMAP)LoadImage(NULL, BitmapName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
  214.  
  215.     if (Bitmap == NULL)
  216.         return FALSE;
  217.  
  218.     // free any existing texture.
  219.     Release();
  220.  
  221.     GetObject(Bitmap, sizeof(bm), &bm);      // get size of bitmap
  222.  
  223.     //
  224.     // find the best texture format to use.
  225.     //
  226.     ZeroMemory(&ddsd, sizeof(ddsd));
  227.     ddsd.dwSize = sizeof(ddsd);
  228.     ChooseTextureFormat(Device, bm.bmBitsPixel, &ddsd.ddpfPixelFormat);
  229.     ddsd.dwFlags |= DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  230.     ddsd.dwWidth = bm.bmWidth;
  231.     ddsd.dwHeight = bm.bmHeight;
  232.  
  233.     //
  234.     // create a video memory texture
  235.     //
  236.     // if we are dealing with a HAL create in video memory, else
  237.     // create in system memory.
  238.     //
  239.     D3DDEVICEDESC hal, hel;
  240.     ZeroMemory(&hal, sizeof(hal));
  241.     hal.dwSize = sizeof(hal);
  242.     ZeroMemory(&hel, sizeof(hel));
  243.     hel.dwSize = sizeof(hel);
  244.     Device->GetCaps(&hal, &hel);
  245.  
  246.     // BUGBUG should we check for texture caps?
  247.     if (hal.dcmColorModel)
  248.         ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD;
  249.     else
  250.         ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY| DDSCAPS_TEXTURE;
  251.  
  252.     if (DirectDraw->CreateSurface(&ddsd, &DeviceSurface, NULL) != DD_OK)
  253.         goto error;
  254.  
  255.     //
  256.     // create a system memory surface for the texture.
  257.     //
  258.     // we use this system memory surface for the ::Load call
  259.     // and this surface does not get lost.
  260.     //
  261.     if (hal.dcmColorModel)
  262.     {
  263.         ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE;
  264.  
  265.         if (DirectDraw->CreateSurface(&ddsd, &MemorySurface, NULL) != DD_OK)
  266.             goto error;
  267.     }
  268.     else
  269.     {
  270.         //
  271.         // when dealing with a SW rasterizer we dont need to make two
  272.         // surfaces.
  273.         //
  274.         MemorySurface = DeviceSurface;
  275.         DeviceSurface->AddRef();
  276.     }
  277.  
  278.     //
  279.     // create a palette for the texture
  280.     //
  281.     if (ddsd.ddpfPixelFormat.dwRGBBitCount <= 8)
  282.     {
  283.         Palette = PaletteFromBitmap(DirectDraw, Bitmap);
  284.  
  285.         //
  286.         // now we have a palette, attach the palette to the Surface
  287.         // and the texture
  288.         //
  289.         MemorySurface->SetPalette(Palette);
  290.         DeviceSurface->SetPalette(Palette);
  291.     }
  292.  
  293.     //
  294.     // copy the bitmap to our surface
  295.     //
  296.     if (!Copy(Bitmap))
  297.         goto error;
  298.  
  299.     //
  300.     // get the texture handle
  301.     //
  302.     IDirect3DTexture2 *    Texture;
  303.     DeviceSurface->QueryInterface(IID_IDirect3DTexture2, (void**)&Texture);
  304.     Texture->GetHandle(Device, &Handle);
  305.     Texture->Release();
  306.  
  307.     //
  308.     // we are done, delete the bitmap (we made a copy) and return.
  309.     //
  310.     DeleteObject(Bitmap);
  311.     return TRUE;
  312.  
  313. error:
  314.     if (Bitmap)
  315.         DeleteObject(Bitmap);
  316.     Release();
  317.     return FALSE;
  318. }
  319.  
  320. /**************************************************************************
  321.  D3DTexture::Copy
  322.  
  323.  init the system memory surface from a GDI Bitmap
  324.  
  325.  **************************************************************************/
  326.  
  327. BOOL D3DTexture::Copy(HBITMAP Bitmap)
  328. {
  329.     BITMAP  bm;
  330.     HDC     BitmapDC;
  331.     HDC     SurfaceDC;
  332.     BOOL    result = FALSE;
  333.  
  334.     DPF("D3DTexture::Copy");
  335.  
  336.     GetObject(Bitmap, sizeof(bm), &bm);    // get size of bitmap
  337.  
  338.     BitmapDC = CreateCompatibleDC(NULL);
  339.     SelectObject(BitmapDC, Bitmap);
  340.  
  341.     if (MemorySurface->GetDC(&SurfaceDC) == DD_OK)
  342.     {
  343.         BitBlt(SurfaceDC, 0, 0, bm.bmWidth, bm.bmHeight, BitmapDC, 0, 0, SRCCOPY);
  344.         MemorySurface->ReleaseDC(SurfaceDC);
  345.         result = Restore();
  346.     }
  347.     DeleteDC(BitmapDC);
  348.     return result;
  349. }
  350.  
  351.  
  352. /**************************************************************************
  353.  D3DTexture::Restore
  354.  
  355.  restore the texture image
  356.  
  357.  **************************************************************************/
  358.  
  359. BOOL D3DTexture::Restore()
  360. {
  361.     HRESULT             err;
  362.     IDirect3DTexture2  *MemoryTexture;
  363.     IDirect3DTexture2  *DeviceTexture;
  364.  
  365.     DPF("D3DTexture::Restore");
  366.  
  367.     if (DeviceSurface == NULL || MemorySurface == NULL)
  368.         return FALSE;
  369.  
  370.     //
  371.     // we dont need to do this step for system memory surfaces.
  372.     //
  373.     if (DeviceSurface == MemorySurface)
  374.         return TRUE;
  375.  
  376.     //
  377.     // restore the video memory texture.
  378.     //
  379.     if (DeviceSurface->Restore() != DD_OK)
  380.         return FALSE;
  381.  
  382.     //
  383.     // call IDirect3DTexture::Load() to copy the texture to the device.
  384.     //
  385.     DeviceSurface->QueryInterface(IID_IDirect3DTexture2, (void**)&DeviceTexture);
  386.     MemorySurface->QueryInterface(IID_IDirect3DTexture2, (void**)&MemoryTexture);
  387.  
  388.     err = DeviceTexture->Load(MemoryTexture);
  389.  
  390.     DeviceTexture->Release();
  391.     MemoryTexture->Release();
  392.  
  393.     return err == DD_OK;
  394. }
  395.  
  396. /**************************************************************************
  397.  D3DTexture::Release
  398.  
  399.  free the texture, free all objects associated with this texture
  400.  
  401.  NOTE we cant do this in the destructor because DirectDraw
  402.  will clean up all the surfaces when the main direct draw object
  403.  is destroyed, before a static destructor will be called.
  404.  
  405.  **************************************************************************/
  406.  
  407. void D3DTexture::Release()
  408. {
  409.     DPF("D3DTexture::Release");
  410.  
  411.     if (MemorySurface)
  412.        MemorySurface->Release();
  413.     MemorySurface = 0;
  414.  
  415.     if (DeviceSurface)
  416.        DeviceSurface->Release();
  417.     DeviceSurface = 0;
  418.  
  419.     if (Palette)
  420.        Palette->Release();
  421.     Palette = 0;
  422.  
  423.     Handle = 0;
  424. }
  425.