home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / directx2 / sdk / samples / iklowns / cgdib.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-28  |  28.0 KB  |  902 lines

  1. /*===========================================================================*\
  2. |
  3. |  File:        cgdib.cpp
  4. |
  5. |  Description: 
  6. |       
  7. |-----------------------------------------------------------------------------
  8. |
  9. |  Copyright (C) 1995-1996 Microsoft Corporation.  All Rights Reserved.
  10. |
  11. |  Written by Moss Bay Engineering, Inc. under contract to Microsoft Corporation
  12. |
  13. \*===========================================================================*/
  14.  
  15. /**************************************************************************
  16.  
  17.     (C) Copyright 1995-1996 Microsoft Corp.  All rights reserved.
  18.  
  19.     You have a royalty-free right to use, modify, reproduce and 
  20.     distribute the Sample Files (and/or any modified version) in 
  21.     any way you find useful, provided that you agree that 
  22.     Microsoft has no warranty obligations or liability for any 
  23.     Sample Application Files which are modified. 
  24.  
  25.     we do not recomend you base your game on IKlowns, start with one of
  26.     the other simpler sample apps in the GDK
  27.  
  28.  **************************************************************************/
  29.  
  30.  
  31. #ifdef __WATCOMC__
  32. #include <windows.h>
  33. #endif
  34. #include <windowsx.h>
  35. #include "cgglobl.h"
  36. #include "cgrsrce.h"
  37. #include "cgscreen.h"
  38. #include "cgexcpt.h"
  39. #include "cgdebug.h"
  40. #include "cgdib.h"
  41.  
  42. /* Macro to determine to round off the given value to the closest byte */
  43. #define WIDTHBYTES(i)   ((i+31)/32*4)
  44.  
  45. #define BFT_BITMAP 0x4d42           /* 'BM' */
  46.  
  47. /* macro to determine if resource is a DIB */
  48. #define ISDIB(bft) ((bft) == BFT_BITMAP)
  49.  
  50. /* Macros to display/remove hourglass cursor for lengthy operations */
  51. #define StartWait() hcurSave = SetCursor(hCursor=LoadCursor(NULL,IDC_WAIT));
  52. #define EndWait()   SetCursor(hCursor=hcurSave)
  53.  
  54. #define PALVERSION                0x300
  55. #define MAXPALETTE      256      /* max. # supported palette entries */
  56.  
  57. WORD                  PaletteSize (VOID FAR * pv);
  58. WORD                  DibNumColors (VOID FAR * pv);
  59. HPALETTE         CreateDibPalette (HANDLE hdib);
  60. HPALETTE         CreateBIPalette (LPBITMAPINFOHEADER lpbi);
  61. HANDLE            DibFromBitmap (HBITMAP hbm, DWORD biStyle, WORD biBits, HPALETTE hpal);
  62. HBITMAP           BitmapFromDib (HANDLE hdib, HPALETTE hpal);
  63. BOOL                  DibInfo (HANDLE hdib,LPBITMAPINFOHEADER lpbi);
  64. HANDLE            ReadDibBitmapInfo (int fh);
  65. VOID    ReadBitMapFileHeaderandConvertToDwordAlign(HFILE fh, LPBITMAPFILEHEADER pbf, LPDWORD lpdwoff);
  66.  
  67. static HCURSOR hCursor;
  68. static HCURSOR hcurSave;
  69.  
  70. /*---------------------------------------------------------------------------*\
  71. |
  72. |       Class CGameDIB
  73. |
  74. |  DESCRIPTION:
  75. |       
  76. |
  77. |
  78. \*---------------------------------------------------------------------------*/
  79. CGameDIB::CGameDIB(
  80.     ) : mImageValid( FALSE ),
  81.         mpBitmapInfo( NULL ),
  82.         mpBits( NULL ),
  83.         mpFileName( NULL ),
  84.         mhBitmap( NULL )
  85. {
  86. }
  87.  
  88. CGameDIB::CGameDIB(
  89.     LPSTR pFileName
  90.     ) : mImageValid( FALSE ),
  91.         mpBitmapInfo( NULL ),
  92.         mpBits( NULL ),
  93.         mpFileName( NULL ),
  94.         mhBitmap( NULL )
  95. {
  96.     if (pFileName)
  97.     {
  98.         mpFileName = new char[lstrlen(pFileName)+1];
  99.         lstrcpy( mpFileName, pFileName );
  100.     
  101.         // Load the DIB into memory.
  102.         OpenDIB(pFileName);
  103.  
  104.         // Set the flag to indicate that we now have a valid image in memory.
  105.         // NOTE: OpenDIB will throw exception if there's a problem, so we can
  106.         // assume here that image is valid.
  107.         mImageValid = TRUE;
  108.     }
  109. }
  110.  
  111. // construct a new DIB section in memory of given size, palette
  112. CGameDIB::CGameDIB(
  113.     int width,
  114.     int height,
  115.     HPALETTE hPal
  116.     ) : mImageValid( FALSE ),
  117.         mpBitmapInfo( NULL ),
  118.         mpBits( NULL ),
  119.         mpFileName( NULL ),
  120.         mhBitmap( NULL )
  121. {
  122.     PALETTEENTRY entries[256];
  123.     LPBITMAPINFO pBI = (LPBITMAPINFO) GlobalAllocPtr( GHND, sizeof( BITMAPINFO ) );
  124.  
  125.     if (!pBI)
  126.         throw CGameResourceError();
  127.  
  128.     // !!!NOTE: we're assuming 8 BPP
  129.     pBI->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  130.     pBI->bmiHeader.biWidth = width;
  131.     pBI->bmiHeader.biHeight = height;   // make it top-down
  132.     pBI->bmiHeader.biPlanes = 1;
  133.     pBI->bmiHeader.biBitCount = 8;
  134.  
  135.     pBI->bmiHeader.biCompression = BI_RGB;
  136.     pBI->bmiHeader.biXPelsPerMeter = 0;
  137.     pBI->bmiHeader.biYPelsPerMeter = 0;
  138.     pBI->bmiHeader.biClrUsed = 256;
  139.     pBI->bmiHeader.biClrImportant = 256;
  140.  
  141.     pBI->bmiHeader.biSizeImage = WIDTHBYTES(width*8) * height;
  142.  
  143.     /* Calculate the memory needed to hold the DIB */
  144.     DWORD dwBits = pBI->bmiHeader.biSizeImage;
  145.     DWORD dwLen  = pBI->bmiHeader.biSize + (DWORD)PaletteSize (pBI);
  146.  
  147.     /* Try to increase the size of the bitmap info. buffer to hold the DIB */
  148.     pBI = (LPBITMAPINFO) GlobalReAllocPtr(pBI, dwLen, GHND);
  149.     if (!pBI)
  150.     {
  151.         throw CGameResourceError();
  152.     }
  153.  
  154.     mpBitmapInfo = pBI;
  155.  
  156.     HDC hdc = GetDC( HWND_DESKTOP );
  157.  
  158.     if (hdc)
  159.     {
  160.         // now create the color table from given palette
  161.         HPALETTE hOldPal = NULL;
  162.  
  163.         if (hPal == NULL)
  164.                         hPal = (HPALETTE)GetCurrentObject( hdc, OBJ_PAL );
  165.         else
  166.         {
  167.             hOldPal = SelectPalette( hdc, hPal, FALSE );
  168.             RealizePalette( hdc );
  169.         }
  170.  
  171.         UINT numColors = GetSystemPaletteEntries(
  172.                         hdc,
  173.                         0,  // start index
  174.                         MAXPALETTE, // num to get
  175.                         entries
  176.                         );
  177.  
  178.  
  179.  
  180.         for (UINT i=0; i<numColors; i++)
  181.         {
  182.             pBI->bmiColors[i].rgbRed = entries[i].peRed;
  183.             pBI->bmiColors[i].rgbGreen = entries[i].peGreen;
  184.             pBI->bmiColors[i].rgbBlue = entries[i].peBlue;
  185.         }
  186.  
  187.         mhBitmap = CreateDIBSection(
  188.             hdc,
  189.             mpBitmapInfo,
  190.             DIB_RGB_COLORS,
  191.             (void**) &mpBits,
  192.             NULL,
  193.             0
  194.             );
  195.  
  196.         mImageValid = (mhBitmap != NULL);
  197.  
  198.         if (hOldPal)
  199.         {
  200.             SelectPalette( hdc, hOldPal, FALSE );
  201.             RealizePalette( hdc );
  202.         }
  203.  
  204.         ReleaseDC( HWND_DESKTOP, hdc );
  205.     }
  206. }
  207.  
  208. /*---------------------------------------------------------------------------*\
  209. |   ~CGameDIB
  210. \*---------------------------------------------------------------------------*/
  211. CGameDIB::~CGameDIB()
  212. {
  213.     delete[] mpFileName;
  214.  
  215.     if (mhBitmap)
  216.     {
  217.         DeleteObject( mhBitmap );
  218.     }
  219.  
  220.     if (mpBitmapInfo)
  221.     {
  222.         GlobalFreePtr( mpBitmapInfo );
  223.     }
  224. }   
  225.  
  226. /*---------------------------------------------------------------------------*\
  227. |   GetWidth()
  228. \*---------------------------------------------------------------------------*/
  229. int
  230. CGameDIB::GetWidth()
  231. {
  232.     if (mpBitmapInfo)
  233.         return mpBitmapInfo->bmiHeader.biWidth;
  234.  
  235.     return 0;
  236. }
  237.  
  238. /*---------------------------------------------------------------------------*\
  239. |   GetHeight()
  240. \*---------------------------------------------------------------------------*/
  241. int
  242. CGameDIB::GetHeight()
  243. {
  244.     if (mpBitmapInfo)
  245.         return mpBitmapInfo->bmiHeader.biHeight;
  246.  
  247.     return 0;
  248. }
  249.  
  250. /*---------------------------------------------------------------------------*\
  251. |   CreatePalette
  252. \*---------------------------------------------------------------------------*/
  253. HPALETTE
  254. CGameDIB::CreatePalette()
  255. {
  256.     return CreateBIPalette( (PBITMAPINFOHEADER) mpBitmapInfo );
  257. }
  258.  
  259. /*---------------------------------------------------------------------------*\
  260. |   OpenDIB
  261. \*---------------------------------------------------------------------------*/
  262. void
  263. CGameDIB::OpenDIB (char* pFileName)
  264. {
  265.     HFILE       fh;
  266.     BITMAPINFOHEADER    bi;
  267.     LPBITMAPINFOHEADER  lpbi;
  268.     DWORD       dwLen = 0;
  269.     DWORD       dwBits;
  270.     HANDLE      hdib;
  271.     HANDLE              h;
  272.     OFSTRUCT        of;
  273.  
  274.     if (!pFileName)
  275.         return;
  276.  
  277.     /* Open the file and read the DIB information */
  278.     fh = OpenFile(pFileName, &of, (UINT)OF_READ);
  279.     if (fh == -1)
  280.     {
  281.         DB_LOG(DB_PROBLEM, "DEBUG: OpenFile failed in OpenDIB");
  282.         throw CGameException(
  283.                     IDS_INVALID_FILE
  284.                    );
  285.     }
  286.  
  287.     hdib = ReadDibBitmapInfo(fh);
  288.  
  289.     DWORD offset = SetFilePointer( (HANDLE) fh, 0, NULL, FILE_CURRENT );
  290.  
  291.     if (!hdib)
  292.     {
  293.         DB_LOG(DB_PROBLEM, "DEBUG: Invalid DIB file in OpenDIB");
  294.         throw CGameException(
  295.                     IDS_INVALID_FILE
  296.                    );
  297.     }
  298.  
  299.     DibInfo(hdib,&bi);
  300.  
  301. #ifdef ConvertToPaletteRelative
  302.      /*  Convert the DIB color table to palette relative indexes, so
  303.       *  SetDIBits() and SetDIBitsToDevice() can avoid color matching.
  304.       *  We can do this because the palette we realize is identical
  305.       *  to the color table of the bitmap, ie the indexes match 1 to 1
  306.       *
  307.       *  Now that the DIB color table is palette indexes not RGB values
  308.       *  we must use DIB_PAL_COLORS as the wUsage parameter to SetDIBits()
  309.       */
  310.     lpbi = (VOID FAR *) GlobalLock(hbiCurrent);
  311.     if (lpbi->biBitCount != 24) {
  312.         fPalColors = TRUE;
  313.  
  314.         pw = (WORD FAR *) ((LPSTR) lpbi + lpbi->biSize);
  315.  
  316.         for (i = 0;  i < (int) lpbi->biClrUsed;  i++)
  317.             *pw++ = (WORD) i;
  318.         }
  319.     GlobalUnlock(hbiCurrent);
  320. #endif
  321.  
  322.     /* Calculate the memory needed to hold the DIB */
  323.     dwBits = bi.biSizeImage;
  324.     dwLen  = bi.biSize + (DWORD)PaletteSize (&bi);
  325.  
  326.     /* Try to increase the size of the bitmap info. buffer to hold the DIB */
  327.     h = GlobalReAlloc(hdib, dwLen, GHND);
  328.     if (!h)
  329.     {
  330.         GlobalFree(hdib);
  331.         hdib = NULL;
  332.         throw CGameResourceError();
  333.     }
  334.     else
  335.         hdib = h;
  336.  
  337.     /* Read in the bits */
  338.     if (hdib)
  339.     {
  340.         lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
  341.         mpBitmapInfo = (LPBITMAPINFO) lpbi;
  342.  
  343.         HDC hdc = GetDC( HWND_DESKTOP );
  344.  
  345.         if (hdc)
  346.         {
  347.             mhBitmap = CreateDIBSection(
  348.                 hdc,
  349.                 mpBitmapInfo,
  350.                 DIB_RGB_COLORS,
  351.                 (void**) &mpBits,
  352.                 NULL,
  353.                 0
  354.                 );
  355.  
  356.             ReadFile(
  357.                     (HANDLE)fh,
  358.                     mpBits,
  359.                     dwBits,
  360.                     &dwLen,
  361.                     NULL
  362.                     );
  363.  
  364.             ReleaseDC( HWND_DESKTOP, hdc );
  365.         }
  366.     }
  367.     
  368.     CloseHandle((HANDLE)fh);
  369. }
  370.  
  371. /*---------------------------------------------------------------------------*\
  372. |   GetPixelAddress()
  373. \*---------------------------------------------------------------------------*/
  374. LPBYTE  // return address of the pixel -- NULL if out of range
  375. CGameDIB::GetPixelAddress(
  376.     int x,
  377.     int y
  378.     )
  379. {
  380.     long width;
  381.  
  382.     // check params
  383.     if (( x < 0 ) || ( y < 0 ) || ( x >= GetWidth() ) || ( y >= GetHeight() ))
  384.     {
  385.         return NULL;
  386.     }
  387.  
  388.     // round up to DWORD boundary
  389.     width = (GetWidth() + 3) & ~3;
  390.     return mpBits + (long)(GetHeight()-y-1) * width + (long)x;
  391. }
  392.  
  393. /*---------------------------------------------------------------------------*\
  394. |   GetPixelAddress()
  395. \*---------------------------------------------------------------------------*/
  396. COLORREF
  397. CGameDIB::GetPixelColor(
  398.     int x,
  399.     int y
  400.     )
  401. {
  402.     LPBYTE pPixel = GetPixelAddress( x, y );
  403.  
  404.     if (pPixel)
  405.     {
  406.         RGBQUAD quad = mpBitmapInfo->bmiColors[*pPixel];
  407.  
  408.         return PALETTERGB( quad.rgbRed, quad.rgbGreen, quad.rgbBlue );
  409.     }
  410.  
  411.     // else
  412.     return 0;   // invalid params
  413. }
  414.  
  415. /*---------------------------------------------------------------------------*\
  416. |   GetColorTable()
  417. \*---------------------------------------------------------------------------*/
  418. UINT    // return the number of entries copied
  419. CGameDIB::GetColorTable(UINT start, UINT count, RGBQUAD* pArray)
  420. {
  421.     UINT result = 0;
  422.  
  423.     if (mpBitmapInfo)
  424.     {
  425.         for (int i=start; ( i < DibNumColors(mpBitmapInfo)) && (result < count); i++)
  426.         {
  427.             pArray[result] = mpBitmapInfo->bmiColors[i];
  428.             ++result;
  429.         }
  430.     }
  431.  
  432.     return result;
  433. }
  434.  
  435. /****************************************************************************
  436.  *                                      *
  437.  *  FUNCTION   : DibInfo(HANDLE hbi,LPBITMAPINFOHEADER lpbi)            *
  438.  *                                      *
  439.  *  PURPOSE    : Retrieves the DIB info associated with a CF_DIB        *
  440.  *       format memory block.                       *
  441.  *                                      *
  442.  *  RETURNS    : TRUE  - if successful.                     *
  443.  *       FALSE - otherwise                      *
  444.  *                                      *
  445.  ****************************************************************************/
  446. BOOL DibInfo (
  447.      HANDLE hbi,
  448.      LPBITMAPINFOHEADER lpbi)
  449. {
  450.     if (hbi)
  451.     {
  452.         *lpbi = *(LPBITMAPINFOHEADER)GlobalLock (hbi);
  453.  
  454.         /* fill in the default fields */
  455.         if (lpbi->biSize != sizeof (BITMAPCOREHEADER))
  456.         {
  457.             if (lpbi->biSizeImage == 0L)
  458.                 lpbi->biSizeImage = WIDTHBYTES(lpbi->biWidth*lpbi->biBitCount) * lpbi->biHeight;
  459.  
  460.             if (lpbi->biClrUsed == 0L)
  461.                 lpbi->biClrUsed = DibNumColors (lpbi);
  462.         }
  463.         GlobalUnlock (hbi);
  464.         return TRUE;
  465.     }
  466.     return FALSE;
  467. }
  468.  
  469. /****************************************************************************
  470.  *                                      *
  471.  *  FUNCTION   : CreateBIPalette(LPBITMAPINFOHEADER lpbi)           *
  472.  *                                      *
  473.  *  PURPOSE    : Given a Pointer to a BITMAPINFO struct will create a       *
  474.  *       a GDI palette object from the color table.         *
  475.  *                                      *
  476.  *  RETURNS    : A handle to the palette.                   *
  477.  *                                      *
  478.  ****************************************************************************/
  479. HPALETTE CreateBIPalette (LPBITMAPINFOHEADER lpbi)
  480. {
  481.      LOGPALETTE          *pPal;
  482.      HPALETTE            hpal = NULL;
  483.      WORD                nNumColors;
  484.      BYTE                red;
  485.      BYTE                green;
  486.      BYTE                blue;
  487.      WORD                i;
  488.      RGBQUAD        FAR *pRgb;
  489.  
  490.     if (!lpbi)
  491.         return NULL;
  492.  
  493.     if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
  494.         return NULL;
  495.  
  496.     /* Get a pointer to the color table and the number of colors in it */
  497.     pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (WORD)lpbi->biSize);
  498.     nNumColors = DibNumColors(lpbi);
  499.  
  500.     if (nNumColors)
  501.     {
  502.         /* Allocate for the logical palette structure */
  503.         pPal = (LOGPALETTE*)LocalAlloc(LPTR,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
  504.         if (!pPal)
  505.             return NULL;
  506.  
  507.         pPal->palNumEntries = nNumColors;
  508.         pPal->palVersion    = PALVERSION;
  509.  
  510.         /* Fill in the palette entries from the DIB color table and
  511.         * create a logical color palette.
  512.         */
  513.  
  514.         // keep index 0 black, index 255 white to keep Windows happy
  515.         pPal->palPalEntry[0].peRed   = 0;
  516.         pPal->palPalEntry[0].peGreen = 0;
  517.         pPal->palPalEntry[0].peBlue  = 0;
  518.         pPal->palPalEntry[0].peFlags = PC_EXPLICIT;
  519.  
  520.         for (i = 1; i < (nNumColors-1); i++)
  521.         {
  522.             pPal->palPalEntry[i].peRed   = pRgb[i].rgbRed;
  523.             pPal->palPalEntry[i].peGreen = pRgb[i].rgbGreen;
  524.             pPal->palPalEntry[i].peBlue  = pRgb[i].rgbBlue;
  525.             pPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
  526.         }
  527.  
  528.         if (nNumColors == 256)
  529.         {
  530.             pPal->palPalEntry[255].peRed   = 255;   // PC_EXPLICIT treats number as a long
  531.             pPal->palPalEntry[255].peGreen = 0;
  532.             pPal->palPalEntry[255].peBlue  = 0;
  533.             pPal->palPalEntry[255].peFlags = PC_EXPLICIT;
  534.         }
  535.  
  536.         hpal = CreatePalette(pPal);
  537.         LocalFree((HANDLE)pPal);
  538.     }
  539.     else if (lpbi->biBitCount == 24)
  540.     {
  541.         /* A 24 bitcount DIB has no color table entries so, set the number of
  542.         * to the maximum value (256).
  543.         */
  544.         nNumColors = MAXPALETTE;
  545.         pPal = (LOGPALETTE*)LocalAlloc(LPTR,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
  546.         if (!pPal)
  547.             return NULL;
  548.  
  549.         pPal->palNumEntries = nNumColors;
  550.         pPal->palVersion    = PALVERSION;
  551.  
  552.         red = green = blue = 0;
  553.  
  554.         /* Generate 256 (= 8*8*4) RGB combinations to fill the palette
  555.         * entries.
  556.         */
  557.         for (i = 0; i < pPal->palNumEntries; i++)
  558.         {
  559.             pPal->palPalEntry[i].peRed   = red;
  560.             pPal->palPalEntry[i].peGreen = green;
  561.             pPal->palPalEntry[i].peBlue  = blue;
  562.             pPal->palPalEntry[i].peFlags = (BYTE)0;
  563.  
  564.             if (!(red += 32))
  565.                 if (!(green += 32))
  566.                     blue += 64;
  567.         }
  568.         hpal = CreatePalette(pPal);
  569.         LocalFree((HANDLE)pPal);
  570.     }
  571.     return hpal;
  572. }
  573.  
  574. /****************************************************************************
  575.  *                                      *
  576.  *  FUNCTION   : CreateDibPalette(HANDLE hbi)                   *
  577.  *                                      *
  578.  *  PURPOSE    : Given a Global HANDLE to a BITMAPINFO Struct           *
  579.  *       will create a GDI palette object from the color table.     *
  580.  *       (BITMAPINFOHEADER format DIBs only)                     *
  581.  *                                      *
  582.  *  RETURNS    : A handle to the palette.                   *
  583.  *                                      *
  584.  ****************************************************************************/
  585. HPALETTE CreateDibPalette (HANDLE hbi)
  586. {
  587.     HPALETTE hpal;
  588.  
  589.     if (!hbi)
  590.         return NULL;
  591.     hpal = CreateBIPalette((LPBITMAPINFOHEADER)GlobalLock(hbi));
  592.     GlobalUnlock(hbi);
  593.     return hpal;
  594. }
  595.  
  596. /****************************************************************************
  597.  *                                      *
  598.  *  FUNCTION   : ReadDibBitmapInfo(int fh)                  *
  599.  *                                      *
  600.  *  PURPOSE    : Will read a file in DIB format and return a global HANDLE  *
  601.  *       to it's BITMAPINFO.  This function will work with both     *
  602.  *       "old" (BITMAPCOREHEADER) and "new" (BITMAPINFOHEADER)      *
  603.  *       bitmap formats, but will always return a "new" BITMAPINFO  *
  604.  *                                      *
  605.  *  RETURNS    : A handle to the BITMAPINFO of the DIB in the file.     *
  606.  *                                      *
  607.  ****************************************************************************/
  608. HANDLE ReadDibBitmapInfo (INT fh)
  609. {
  610.     DWORD     off;
  611.     HANDLE    hbi = NULL;
  612.     INT       size;
  613.     INT       i;
  614.     WORD      nNumColors;
  615.  
  616.     RGBQUAD FAR       *pRgb;
  617.     BITMAPINFOHEADER   bi;
  618.     BITMAPCOREHEADER   bc;
  619.     LPBITMAPINFOHEADER lpbi;
  620.     BITMAPFILEHEADER   bf;
  621.     DWORD          dwWidth = 0;
  622.     DWORD          dwHeight = 0;
  623.     WORD           wPlanes, wBitCount;
  624.  
  625.     if (fh == -1)
  626.         return NULL;
  627. #ifdef FIXDWORDALIGNMENT
  628.     /* Reset file pointer and read file header */
  629.     off = _llseek(fh, 0L, (UINT)SEEK_CUR);
  630.     if ((SIZEOF_BITMAPFILEHEADER_PACKED)  != _lread(fh, (LPSTR)&bf, (UINT)sizeof (SIZEOF_BITMAPFILEHEADER_PACKED)))
  631.         return FALSE;
  632. #else
  633.     ReadBitMapFileHeaderandConvertToDwordAlign(fh, &bf, &off);
  634.     /* at this point we have read the file into bf*/
  635. #endif
  636.  
  637.     /* Do we have a RC HEADER? */
  638.     if (!ISDIB (bf.bfType))
  639.     {
  640.         bf.bfOffBits = 0L;
  641.         SetFilePointer((HANDLE)fh, off, NULL, FILE_BEGIN); /*seek back to beginning of file*/
  642.     }
  643.     if (!ReadFile((HANDLE)fh, (LPSTR)&bi, (UINT)sizeof(bi), &dwWidth, NULL) ||
  644.         sizeof (bi) != dwWidth)
  645.         return FALSE;
  646.  
  647.     nNumColors = DibNumColors (&bi);
  648.  
  649.     /* Check the nature (BITMAPINFO or BITMAPCORE) of the info. block
  650.      * and extract the field information accordingly. If a BITMAPCOREHEADER,
  651.      * transfer it's field information to a BITMAPINFOHEADER-style block
  652.      */
  653.     switch (size = (INT)bi.biSize)
  654.     {
  655.         case sizeof (BITMAPINFOHEADER):
  656.             break;
  657.  
  658.         case sizeof (BITMAPCOREHEADER):
  659.             bc = *(BITMAPCOREHEADER*)&bi;
  660.  
  661.             dwWidth   = (DWORD)bc.bcWidth;
  662.             dwHeight  = (DWORD)bc.bcHeight;
  663.             wPlanes   = bc.bcPlanes;
  664.             wBitCount = bc.bcBitCount;
  665.  
  666.             bi.biSize           = sizeof(BITMAPINFOHEADER);
  667.             bi.biWidth          = dwWidth;
  668.             bi.biHeight         = dwHeight;
  669.             bi.biPlanes         = wPlanes;
  670.             bi.biBitCount       = wBitCount;
  671.  
  672.             bi.biCompression        = BI_RGB;
  673.             bi.biSizeImage          = 0;
  674.             bi.biXPelsPerMeter      = 0;
  675.             bi.biYPelsPerMeter      = 0;
  676.             bi.biClrUsed            = nNumColors;
  677.             bi.biClrImportant       = nNumColors;
  678.  
  679.             _llseek(fh, (LONG)sizeof (BITMAPCOREHEADER) - sizeof (BITMAPINFOHEADER), (UINT)SEEK_CUR);
  680.             break;
  681.  
  682.         default:
  683.             /* Not a DIB! */
  684.             return NULL;
  685.     }
  686.  
  687.     /* Fill in some default values if they are zero */
  688.     if (bi.biSizeImage == 0)
  689.     {
  690.         bi.biSizeImage = WIDTHBYTES ((DWORD)bi.biWidth * bi.biBitCount)
  691.                * bi.biHeight;
  692.     }
  693.     if (bi.biClrUsed == 0)
  694.         bi.biClrUsed = DibNumColors(&bi);
  695.  
  696.     /* Allocate for the BITMAPINFO structure and the color table. */
  697.     hbi = GlobalAlloc (GHND, (LONG)bi.biSize + nNumColors * sizeof(RGBQUAD));
  698.     if (!hbi)
  699.         return NULL;
  700.     lpbi = (LPBITMAPINFOHEADER)GlobalLock (hbi);
  701.     *lpbi = bi;
  702.  
  703.     /* Get a pointer to the color table */
  704.     pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + bi.biSize);
  705.     if (nNumColors)
  706.     {
  707.         DWORD bytesRead;
  708.  
  709.         if (size == sizeof(BITMAPCOREHEADER))
  710.         {
  711.             /* Convert a old color table (3 byte RGBTRIPLEs) to a new
  712.              * color table (4 byte RGBQUADs)
  713.              */
  714.             ReadFile((HANDLE)fh, (LPSTR)pRgb, (UINT)nNumColors * sizeof(RGBTRIPLE), &bytesRead, NULL);
  715.  
  716.             for (i = nNumColors - 1; i >= 0; i--)
  717.             {
  718.                 RGBQUAD rgb;
  719.  
  720.                 rgb.rgbRed      = ((RGBTRIPLE FAR *)pRgb)[i].rgbtRed;
  721.                 rgb.rgbBlue     = ((RGBTRIPLE FAR *)pRgb)[i].rgbtBlue;
  722.                 rgb.rgbGreen    = ((RGBTRIPLE FAR *)pRgb)[i].rgbtGreen;
  723.                 rgb.rgbReserved = (BYTE)0;
  724.  
  725.                 pRgb[i] = rgb;
  726.             }
  727.         }
  728.         else
  729.             ReadFile((HANDLE)fh, (LPSTR)pRgb, (UINT)nNumColors * sizeof(RGBQUAD), &bytesRead, NULL);
  730.     }
  731.  
  732.     if (bf.bfOffBits != 0L)
  733.     {
  734.         SetFilePointer((HANDLE)fh, off + bf.bfOffBits, NULL, FILE_BEGIN);
  735.     }
  736.     GlobalUnlock(hbi);
  737.     return hbi;
  738. }
  739.  
  740. /****************************************************************************
  741.  *                                      *
  742.  *  FUNCTION   :  PaletteSize(VOID FAR * pv)                    *
  743.  *                                      *
  744.  *  PURPOSE    :  Calculates the palette size in bytes. If the info. block  *
  745.  *        is of the BITMAPCOREHEADER type, the number of colors is  *
  746.  *        multiplied by 3 to give the palette size, otherwise the   *
  747.  *        number of colors is multiplied by 4.                              *
  748.  *                                      *
  749.  *  RETURNS    :  Palette size in number of bytes.              *
  750.  *                                      *
  751.  ****************************************************************************/
  752. WORD PaletteSize (VOID FAR * pv)
  753. {
  754.     LPBITMAPINFOHEADER lpbi;
  755.     WORD           NumColors;
  756.  
  757.     lpbi      = (LPBITMAPINFOHEADER)pv;
  758.     NumColors = DibNumColors(lpbi);
  759.  
  760.     if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
  761.         return (WORD)(NumColors * sizeof(RGBTRIPLE));
  762.     else
  763.         return (WORD)(NumColors * sizeof(RGBQUAD));
  764. }
  765.  
  766. /****************************************************************************
  767.  *                                      *
  768.  *  FUNCTION   : DibNumColors(VOID FAR * pv)                    *
  769.  *                                      *
  770.  *  PURPOSE    : Determines the number of colors in the DIB by looking at   *
  771.  *       the BitCount filed in the info block.              *
  772.  *                                      *
  773.  *  RETURNS    : The number of colors in the DIB.               *
  774.  *                                      *
  775.  ****************************************************************************/
  776. WORD DibNumColors (VOID FAR * pv)
  777. {
  778.     INT         bits;
  779.     LPBITMAPINFOHEADER  lpbi;
  780.     LPBITMAPCOREHEADER  lpbc;
  781.  
  782.     lpbi = ((LPBITMAPINFOHEADER)pv);
  783.     lpbc = ((LPBITMAPCOREHEADER)pv);
  784.  
  785.     /*  With the BITMAPINFO format headers, the size of the palette
  786.      *  is in biClrUsed, whereas in the BITMAPCORE - style headers, it
  787.      *  is dependent on the bits per pixel ( = 2 raised to the power of
  788.      *  bits/pixel).
  789.      */
  790.     if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
  791.     {
  792.         if (lpbi->biClrUsed != 0)
  793.             return (WORD)lpbi->biClrUsed;
  794.         bits = lpbi->biBitCount;
  795.     }
  796.     else
  797.         bits = lpbc->bcBitCount;
  798.  
  799.     switch (bits)
  800.     {
  801.         case 1:
  802.             return 2;
  803.         case 4:
  804.             return 16;
  805.         case 8:
  806.             return 256;
  807.         default:
  808.             /* A 24 bitcount DIB has no color table */
  809.             return 0;
  810.     }
  811. }
  812.  
  813. /****************************************************************************
  814.  *                                      *
  815.  *  FUNCTION   : BitmapFromDib(HANDLE hdib, HPALETTE hpal)          *
  816.  *                                      *
  817.  *  PURPOSE    : Will create a DDB (Device Dependent Bitmap) given a global *
  818.  *       handle to a memory block in CF_DIB format          *
  819.  *                                      *
  820.  *  RETURNS    : A handle to the DDB.                       *
  821.  *                                      *
  822.  ****************************************************************************/
  823.  
  824. HBITMAP BitmapFromDib (
  825.      HANDLE    hdib,
  826.      HPALETTE   hpal)
  827. {
  828.     LPBITMAPINFOHEADER  lpbi;
  829.     HPALETTE        hpalT;
  830.     HDC         hdc;
  831.     HBITMAP     hbm;
  832.  
  833.     StartWait();
  834.  
  835.     if (!hdib)
  836.         return NULL;
  837.  
  838.     lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
  839.  
  840.     if (!lpbi)
  841.         return NULL;
  842.  
  843.     hdc = GetDC(NULL);
  844.  
  845.     if (hpal)
  846.     {
  847.         hpalT = SelectPalette(hdc,hpal,FALSE);
  848.         RealizePalette(hdc);     // GDI Bug...????
  849.     }
  850.  
  851.     hbm = CreateDIBitmap(hdc,
  852.              (LPBITMAPINFOHEADER)lpbi,
  853.              (LONG)CBM_INIT,
  854.              (LPBYTE)lpbi + lpbi->biSize + PaletteSize(lpbi), //cast changed for C++
  855.              (LPBITMAPINFO)lpbi,
  856.              DIB_RGB_COLORS );
  857.  
  858.     if (hpal)
  859.         SelectPalette(hdc,hpalT,FALSE);
  860.  
  861.     ReleaseDC(NULL,hdc);
  862.     GlobalUnlock(hdib);
  863.  
  864.     EndWait();
  865.  
  866.     return hbm;
  867. }
  868.  
  869. /****************************************************************************
  870.  *                                      *
  871.  *  FUNCTION   : ReadBitMapFileHeaderandConvertToDwordAlign(HFILE fh, LPBITMAPFILEHEADER pbf)
  872.  *                                      *
  873.  *  PURPOSE    : read file header (which is packed) and convert into unpacked BITMAPFILEHEADER strucutre
  874.  *                                      *
  875.  *  RETURNS    : VOID
  876.  *                                      *
  877.  ****************************************************************************/
  878.  
  879. VOID ReadBitMapFileHeaderandConvertToDwordAlign(HFILE fh, LPBITMAPFILEHEADER pbf, LPDWORD lpdwoff)
  880. {
  881.     DWORD off;
  882.  
  883.     off = SetFilePointer((HANDLE)fh, 0L, NULL, FILE_CURRENT);
  884.     *lpdwoff = off;
  885.  
  886. /*      BITMAPFILEHEADER STRUCUTURE is as follows
  887.  *      BITMAPFILEHEADER
  888.  *          WORD    bfType
  889.  >          ....          < add WORD if packed here!
  890.  *          DWORD   bfSize
  891.  *          WORD    bfReserved1
  892.  *          WORD    bfReserved2
  893.  *          DWORD   bfOffBits
  894.  *          This is the packed format, unpacked adds a WORD after bfType
  895.  */
  896.  
  897.     /* read in bfType*/
  898.     ReadFile((HANDLE)fh, (LPSTR) &pbf->bfType, sizeof(WORD), &off, NULL);
  899.     /* read in last 3 dwords*/
  900.     ReadFile((HANDLE)fh, (LPSTR) &pbf->bfSize, sizeof(DWORD) * 3, &off, NULL);
  901. }
  902.