|
|
/******************************Module*Header*******************************\
* Module Name: fastdib.c * * CreateCompatibleDIB implementation. * * Created: 23-Jan-1996 21:08:18 * Author: Gilman Wong [gilmanw] * * Copyright (c) 1996 Microsoft Corporation * \**************************************************************************/
#include <windows.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "sscommon.h"
BOOL APIENTRY GetDIBTranslationVector(HDC hdcMem, HPALETTE hpal, BYTE *pbVector); static BOOL bFillBitmapInfo(HDC hdc, HPALETTE hpal, BITMAPINFO *pbmi); static BOOL bFillColorTable(HDC hdc, HPALETTE hpal, BITMAPINFO *pbmi); static UINT MyGetSystemPaletteEntries(HDC hdc, UINT iStartIndex, UINT nEntries, LPPALETTEENTRY lppe); static BOOL bComputeLogicalToSurfaceMap(HDC hdc, HPALETTE hpal, BYTE *pajVector);
/******************************Public*Routine******************************\
* CreateCompatibleDIB * * Create a DIB section with an optimal format w.r.t. the specified hdc. * * If DIB <= 8bpp, then the DIB color table is initialized based on the * specified palette. If the palette handle is NULL, then the system * palette is used. * * Note: The hdc must be a direct DC (not an info or memory DC). * * Note: On palettized displays, if the system palette changes the * UpdateDIBColorTable function should be called to maintain * the identity palette mapping between the DIB and the display. * * Returns: * Valid bitmap handle if successful, NULL if error. * * History: * 23-Jan-1996 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
//HBITMAP APIENTRY
HBITMAP SSDIB_CreateCompatibleDIB(HDC hdc, HPALETTE hpal, ULONG ulWidth, ULONG ulHeight, PVOID *ppvBits) { HBITMAP hbmRet = (HBITMAP) NULL; BYTE aj[sizeof(BITMAPINFO) + (sizeof(RGBQUAD) * 255)]; BITMAPINFO *pbmi = (BITMAPINFO *) aj;
//
// Validate hdc.
//
if ( GetObjectType(hdc) != OBJ_DC ) { SS_DBGPRINT("CreateCompatibleDIB: not OBJ_DC\n"); return hbmRet; }
memset(aj, 0, sizeof(aj)); if ( bFillBitmapInfo(hdc, hpal, pbmi) ) { //
// Change bitmap size to match specified dimensions.
//
pbmi->bmiHeader.biWidth = ulWidth; pbmi->bmiHeader.biHeight = ulHeight; if (pbmi->bmiHeader.biCompression == BI_RGB) { pbmi->bmiHeader.biSizeImage = 0; } else { if ( pbmi->bmiHeader.biBitCount == 16 ) pbmi->bmiHeader.biSizeImage = ulWidth * ulHeight * 2; else if ( pbmi->bmiHeader.biBitCount == 32 ) pbmi->bmiHeader.biSizeImage = ulWidth * ulHeight * 4; else pbmi->bmiHeader.biSizeImage = 0; } pbmi->bmiHeader.biClrUsed = 0; pbmi->bmiHeader.biClrImportant = 0;
//
// Create the DIB section. Let Win32 allocate the memory and return
// a pointer to the bitmap surface.
//
hbmRet = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, ppvBits, NULL, 0); GdiFlush();
if ( !hbmRet ) { SS_DBGPRINT("CreateCompatibleDIB: CreateDIBSection failed\n"); } } else { SS_DBGPRINT("CreateCompatibleDIB: bFillBitmapInfo failed\n"); }
return hbmRet; }
/******************************Public*Routine******************************\
* UpdateDIBColorTable * * Synchronize the DIB color table to the specified palette hpal. * If hpal is NULL, then use the system palette. * * Returns: * TRUE if successful, FALSE otherwise. * * History: * 23-Jan-1996 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
BOOL APIENTRY SSDIB_UpdateColorTable(HDC hdcMem, HDC hdc, HPALETTE hpal) { BOOL bRet = FALSE; HBITMAP hbm; DIBSECTION ds; BYTE aj[(sizeof(RGBQUAD) + sizeof(PALETTEENTRY)) * 256]; LPPALETTEENTRY lppe = (LPPALETTEENTRY) aj; LPRGBQUAD prgb = (LPRGBQUAD) (lppe + 256); ULONG i, cColors;
//
// Validate hdc.
//
if ( GetObjectType(hdc) != OBJ_DC ) { SS_DBGPRINT("UpdateDIBColorTable: not OBJ_DC\n"); return bRet; } if ( GetObjectType(hdcMem) != OBJ_MEMDC ) { SS_DBGPRINT("UpdateDIBColorTable: not OBJ_MEMDC\n"); return bRet; }
//
// Get the bitmap handle out of the memdc.
//
hbm = GetCurrentObject(hdcMem, OBJ_BITMAP);
//
// Validate bitmap (must be DIB section).
//
if ( (GetObject(hbm, sizeof(ds), &ds) == sizeof(ds)) && ds.dsBm.bmBits ) { //
// Get palette entries from specified palette or system palette.
//
cColors = 1 << ds.dsBmih.biBitCount;
if ( hpal ? GetPaletteEntries(hpal, 0, cColors, lppe) : MyGetSystemPaletteEntries(hdc, 0, cColors, lppe) ) { UINT i;
//
// Convert to RGBQUAD.
//
for (i = 0; i < cColors; i++) { prgb[i].rgbRed = lppe[i].peRed; prgb[i].rgbGreen = lppe[i].peGreen; prgb[i].rgbBlue = lppe[i].peBlue; prgb[i].rgbReserved = 0; }
//
// Set the DIB color table.
//
bRet = (BOOL) SetDIBColorTable(hdcMem, 0, cColors, prgb);
if (!bRet) { SS_DBGPRINT("UpdateDIBColorTable: SetDIBColorTable failed\n"); } } else { SS_DBGPRINT("UpdateDIBColorTable: MyGetSystemPaletteEntries failed\n"); } } else { SS_DBGPRINT("UpdateDIBColorTable: GetObject failed\n"); }
return bRet; }
/******************************Public*Routine******************************\
* GetCompatibleDIBInfo * * Copies pointer to bitmap origin to ppvBase and bitmap stride to plStride. * Win32 DIBs can be created bottom-up (the default) with the origin at the * lower left corner or top-down with the origin at the upper left corner. * If the bitmap is top-down, *plStride is positive; if bottom-up, *plStride * us negative. * * Also, because of restrictions on the alignment of scan lines the width * the bitmap is often not the same as the stride (stride is the number of * bytes between vertically adjacent pixels). * * The ppvBase and plStride value returned will allow you to address any * given pixel (x, y) in the bitmap as follows: * * PIXEL *ppix; * * ppix = (PIXEL *) (((BYTE *)*ppvBase) + (y * *plStride) + (x * sizeof(PIXEL))); * * Returns: * TRUE if successful, FALSE otherwise. * * History: * 02-Feb-1996 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
BOOL APIENTRY GetCompatibleDIBInfo(HBITMAP hbm, PVOID *ppvBase, LONG *plStride) { BOOL bRet = FALSE; DIBSECTION ds;
//
// Call GetObject to return a DIBSECTION. If successful, the
// bitmap is a DIB section and we can retrieve the pointer to
// the bitmap bits and other parameters.
//
if ( (GetObject(hbm, sizeof(ds), &ds) == sizeof(ds)) && ds.dsBm.bmBits ) { // For backwards compatibility with Get/SetBitmapBits, GDI does
// not accurately report the bitmap pitch in bmWidthBytes. It
// always computes bmWidthBytes assuming WORD-aligned scanlines
// regardless of the platform.
//
// Therefore, if the platform is WinNT, which uses DWORD-aligned
// scanlines, adjust the bmWidthBytes value.
{ OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(osvi); if (GetVersionEx(&osvi)) { if ( osvi.dwPlatformId == VER_PLATFORM_WIN32_NT ) { ds.dsBm.bmWidthBytes = (ds.dsBm.bmWidthBytes + 3) & ~3; } } else { SS_DBGPRINT1("GetCompatibleDIBInfo: GetVersionEx failed with %d\n", GetLastError()); return bRet; } }
//
// If biHeight is positive, then the bitmap is a bottom-up DIB.
// If biHeight is negative, then the bitmap is a top-down DIB.
//
if ( ds.dsBmih.biHeight > 0 ) { *ppvBase = (PVOID) (((INT_PTR) ds.dsBm.bmBits) + (ds.dsBm.bmWidthBytes * (ds.dsBm.bmHeight - 1))); *plStride = (ULONG) (-ds.dsBm.bmWidthBytes); } else { *ppvBase = ds.dsBm.bmBits; *plStride = ds.dsBm.bmWidthBytes; }
bRet = TRUE; } else { SS_DBGPRINT("GetCompatibleDIBInfo: cannot get pointer to DIBSECTION bmBits\n"); }
return bRet; }
/******************************Public*Routine******************************\
* GetDIBTranslationVector * * Copies the translation vector that maps colors in the specified palette, * hpal, to the DIB selected into the specified DC, hdcMem. * * Effects: * * Returns: * TRUE if successful, FALSE otherwise. * * History: * 02-Feb-1996 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
BOOL APIENTRY GetDIBTranslationVector(HDC hdcMem, HPALETTE hpal, BYTE *pbVector) { BOOL bRet = FALSE; HBITMAP hbm; DIBSECTION ds;
//
// Validate parameters.
//
if ( GetObjectType(hdcMem) != OBJ_MEMDC || GetObjectType(hpal) != OBJ_PAL || !pbVector ) { SS_DBGPRINT("GetDIBTranslationVector: bad parameter\n"); return bRet; }
//
// The function bComputeLogicalToSurfaceMap cannot handle palettes
// greater than 256 entries.
//
if ( GetPaletteEntries(hpal, 0, 1, NULL) > 256 ) { SS_DBGPRINT("GetDIBTranslationVector: palette too big\n"); return bRet; }
//
// The DIB must have a color table.
//
hbm = GetCurrentObject(hdcMem, OBJ_BITMAP); if ( (GetObject(hbm, sizeof(ds), &ds) == sizeof(ds)) && (ds.dsBmih.biBitCount <= 8) ) { bRet = bComputeLogicalToSurfaceMap(hdcMem, hpal, pbVector); } else { SS_DBGPRINT("GetDIBTranslationVector: not a DIB section\n"); return bRet; }
return bRet; }
//////////////////// Below here are internal-only routines ////////////////////
/******************************Public*Routine******************************\
* bFillBitmapInfo * * Fills in the fields of a BITMAPINFO so that we can create a bitmap * that matches the format of the display. * * This is done by creating a compatible bitmap and calling GetDIBits * to return the color masks. This is done with two calls. The first * call passes in biBitCount = 0 to GetDIBits which will fill in the * base BITMAPINFOHEADER data. The second call to GetDIBits (passing * in the BITMAPINFO filled in by the first call) will return the color * table or bitmasks, as appropriate. * * Returns: * TRUE if successful, FALSE otherwise. * * History: * 07-Jun-1995 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
static BOOL bFillBitmapInfo(HDC hdc, HPALETTE hpal, BITMAPINFO *pbmi) { HBITMAP hbm; BOOL bRet = FALSE;
//
// Create a dummy bitmap from which we can query color format info
// about the device surface.
//
if ( (hbm = CreateCompatibleBitmap(hdc, 1, 1)) != NULL ) { pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
//
// Call first time to fill in BITMAPINFO header.
//
GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
if ( pbmi->bmiHeader.biBitCount <= 8 ) { bRet = bFillColorTable(hdc, hpal, pbmi); } else { if ( pbmi->bmiHeader.biCompression == BI_BITFIELDS ) { //
// Call a second time to get the color masks.
// It's a GetDIBits Win32 "feature".
//
GetDIBits(hdc, hbm, 0, pbmi->bmiHeader.biHeight, NULL, pbmi, DIB_RGB_COLORS); }
bRet = TRUE; }
DeleteObject(hbm); } else { SS_DBGPRINT("bFillBitmapInfo: CreateCompatibleBitmap failed\n"); }
return bRet; }
/******************************Public*Routine******************************\
* bFillColorTable * * Initialize the color table of the BITMAPINFO pointed to by pbmi. Colors * are set to the current system palette. * * Note: call only valid for displays of 8bpp or less. * * Returns: * TRUE if successful, FALSE otherwise. * * History: * 23-Jan-1996 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
static BOOL bFillColorTable(HDC hdc, HPALETTE hpal, BITMAPINFO *pbmi) { BOOL bRet = FALSE; BYTE aj[sizeof(PALETTEENTRY) * 256]; LPPALETTEENTRY lppe = (LPPALETTEENTRY) aj; RGBQUAD *prgb = (RGBQUAD *) &pbmi->bmiColors[0]; ULONG i, cColors;
cColors = 1 << pbmi->bmiHeader.biBitCount; if ( cColors <= 256 ) { if ( hpal ? GetPaletteEntries(hpal, 0, cColors, lppe) : MyGetSystemPaletteEntries(hdc, 0, cColors, lppe) ) { UINT i;
for (i = 0; i < cColors; i++) { prgb[i].rgbRed = lppe[i].peRed; prgb[i].rgbGreen = lppe[i].peGreen; prgb[i].rgbBlue = lppe[i].peBlue; prgb[i].rgbReserved = 0; }
bRet = TRUE; } else { SS_DBGPRINT("bFillColorTable: MyGetSystemPaletteEntries failed\n"); } }
return bRet; }
/******************************Public*Routine******************************\
* MyGetSystemPaletteEntries * * Internal version of GetSystemPaletteEntries. * * GetSystemPaletteEntries fails on some 4bpp devices. This version * will detect the 4bpp case and supply the hardcoded 16-color VGA palette. * Otherwise, it will pass the call on to GDI's GetSystemPaletteEntries. * * It is expected that this call will only be called in the 4bpp and 8bpp * cases as it is not necessary for OpenGL to query the system palette * for > 8bpp devices. * * History: * 17-Aug-1995 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
static PALETTEENTRY gapeVgaPalette[16] = { { 0, 0, 0, 0 }, { 0x80,0, 0, 0 }, { 0, 0x80,0, 0 }, { 0x80,0x80,0, 0 }, { 0, 0, 0x80, 0 }, { 0x80,0, 0x80, 0 }, { 0, 0x80,0x80, 0 }, { 0x80,0x80,0x80, 0 }, { 0xC0,0xC0,0xC0, 0 }, { 0xFF,0, 0, 0 }, { 0, 0xFF,0, 0 }, { 0xFF,0xFF,0, 0 }, { 0, 0, 0xFF, 0 }, { 0xFF,0, 0xFF, 0 }, { 0, 0xFF,0xFF, 0 }, { 0xFF,0xFF,0xFF, 0 } };
static UINT MyGetSystemPaletteEntries(HDC hdc, UINT iStartIndex, UINT nEntries, LPPALETTEENTRY lppe) { int nDeviceBits;
nDeviceBits = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
//
// Some 4bpp displays will fail the GetSystemPaletteEntries call.
// So if detected, return the hardcoded table.
//
if ( nDeviceBits == 4 ) { if ( lppe ) { nEntries = min(nEntries, (16 - iStartIndex));
memcpy(lppe, &gapeVgaPalette[iStartIndex], nEntries * sizeof(PALETTEENTRY)); } else nEntries = 16;
return nEntries; } else { return GetSystemPaletteEntries(hdc, iStartIndex, nEntries, lppe); } }
/******************************Public*Routine******************************\
* bComputeLogicalToSurfaceMap * * Copy logical palette to surface palette translation vector to the buffer * pointed to by pajVector. The logical palette is specified by hpal. The * surface is specified by hdc. * * Note: The hdc may identify either a direct (display) dc or a DIB memory dc. * If hdc is a display dc, then the surface palette is the system palette. * If hdc is a memory dc, then the surface palette is the DIB color table. * * History: * 27-Jan-1996 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
static BOOL bComputeLogicalToSurfaceMap(HDC hdc, HPALETTE hpal, BYTE *pajVector) { BOOL bRet = FALSE; HPALETTE hpalSurf; ULONG cEntries, cSysEntries; DWORD dwDcType = GetObjectType(hdc); LPPALETTEENTRY lppeTmp, lppeEnd;
BYTE aj[sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 512) + (sizeof(RGBQUAD) * 256)]; LOGPALETTE *ppal = (LOGPALETTE *) aj; LPPALETTEENTRY lppeSurf = &ppal->palPalEntry[0]; LPPALETTEENTRY lppe = lppeSurf + 256; RGBQUAD *prgb = (RGBQUAD *) (lppe + 256);
//
// Determine number of colors in each palette.
//
cEntries = GetPaletteEntries(hpal, 0, 1, NULL); if ( dwDcType == OBJ_DC ) cSysEntries = MyGetSystemPaletteEntries(hdc, 0, 1, NULL); else cSysEntries = 256;
//
// Get the logical palette entries.
//
cEntries = GetPaletteEntries(hpal, 0, cEntries, lppe);
//
// Get the surface palette entries.
//
if ( dwDcType == OBJ_DC ) { cSysEntries = MyGetSystemPaletteEntries(hdc, 0, cSysEntries, lppeSurf);
lppeTmp = lppeSurf; lppeEnd = lppeSurf + cSysEntries;
for (; lppeTmp < lppeEnd; lppeTmp++) lppeTmp->peFlags = 0; } else { RGBQUAD *prgbTmp;
//
// First get RGBQUADs from DIB color table...
//
cSysEntries = GetDIBColorTable(hdc, 0, cSysEntries, prgb);
//
// ...then convert RGBQUADs into PALETTEENTRIES.
//
prgbTmp = prgb; lppeTmp = lppeSurf; lppeEnd = lppeSurf + cSysEntries;
while ( lppeTmp < lppeEnd ) { lppeTmp->peRed = prgbTmp->rgbRed; lppeTmp->peGreen = prgbTmp->rgbGreen; lppeTmp->peBlue = prgbTmp->rgbBlue; lppeTmp->peFlags = 0;
lppeTmp++; prgbTmp++;
} }
//
// Construct a translation vector by using GetNearestPaletteIndex to
// map each entry in the logical palette to the surface palette.
//
if ( cEntries && cSysEntries ) { //
// Create a temporary logical palette that matches the surface
// palette retrieved above.
//
ppal->palVersion = 0x300; ppal->palNumEntries = (USHORT) cSysEntries;
if ( hpalSurf = CreatePalette(ppal) ) { //
// Translate each logical palette entry into a surface palette
// index.
//
lppeTmp = lppe; lppeEnd = lppe + cEntries;
for ( ; lppeTmp < lppeEnd; lppeTmp++, pajVector++) { *pajVector = (BYTE) GetNearestPaletteIndex( hpalSurf, RGB(lppeTmp->peRed, lppeTmp->peGreen, lppeTmp->peBlue) ); }
bRet = TRUE;
DeleteObject(hpalSurf); } else { SS_DBGPRINT("bComputeLogicalToSurfaceMap: CreatePalette failed\n"); } } else { SS_DBGPRINT("bComputeLogicalToSurfaceMap: failed to get pal info\n"); }
return bRet; }
|