|
|
/**************************************************************************
DRAWDIB.C - routines for drawing DIBs to the screen.
this code handles stretching and dithering with custom code, none of this slow GDI code.
the following DIB formats are supported:
4bpp (will just draw it with GDI...) 8bpp 16bpp 24bpp compressed DIBs
drawing to:
16 color DC (will dither 8bpp down) 256 (paletized) DC (will dither 16 and 24bpp down) Full-color DC (will just draw it!)
**************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include "drawdibi.h"
#ifndef ICMODE_FASTDECOMPRESS
#define ICMODE_FASTDECOMPRESS 3
#endif
#define USE_SETDI 1
#ifndef BI_BITMAP
#define BI_BITMAP 0x4D544942 // 'BITM'
#endif
#ifdef WIN32
#define FlatToHuge(a, b, c)
#define HugeToFlat(a, b, c)
#else
extern FAR PASCAL FlatToHuge(LPVOID,DWORD,DWORD); extern FAR PASCAL HugeToFlat(LPVOID,DWORD,DWORD); #endif
//!!! not quite right.
#ifndef WIN32
#define IsScreenDC(hdc) (GetDCOrg(hdc) != 0L)
#else
#define IsScreenDC(hdc) (WindowFromDC(hdc) != NULL)
#endif
#define DCAlignment 3
__inline int DCNotAligned(HDC hdc, int xDst) { POINT pt;
pt.x = xDst; pt.y = 0; LPtoDP(hdc, &pt, 1); xDst = pt.x;
#ifdef _WIN32
GetDCOrgEx(hdc, &pt); #else
pt.x = LOWORD(GetDCOrg(hdc)); #endif
return (pt.x + xDst) & DCAlignment; }
/**************************************************************************
**************************************************************************/
UINT gwScreenBitDepth = (UINT)-1; UINT gwRasterCaps = 0; BOOL gf286= FALSE; static UINT gUsage = 0; static BOOL gfInit = FALSE; static BOOL gfHalftone = FALSE; static BOOL gfBitmap = FALSE; static BOOL gfBitmapX = FALSE; static BOOL gfScreenX = FALSE; static BOOL gfDrawX = FALSE; static HBITMAP hbmStockMono; // the stock mono bitmap.
#ifndef WIN32
static BOOL gfDisplayHasBrokenRasters; static HDC hdcDCI; static DCISURFACEINFO FAR *pdci;
static struct { BITMAPINFOHEADER bi; DWORD dwMask[3]; } biScreen; static LPVOID lpScreen;
SZCODE szDVA[] = TEXT("dva"); #endif
/**************************************************************************
**************************************************************************/
SZCODE szDrawDib[] = TEXT("DrawDib"); SZCODE szHalftone[] = TEXT("Halftone"); SZCODE szDrawToBitmap[] = TEXT("DrawToBitmap"); SZCODE szDecompressToBitmap[] = TEXT("DecompressToBitmap"); SZCODE szDecompressToScreen[] = TEXT("DecompressToScreen"); SZCODE szDrawToScreen[] = TEXT("DrawToScreen");
/**************************************************************************
**************************************************************************/
static BOOL NEAR PASCAL DrawDibFree(PDD pdd, BOOL fSameDib, BOOL fSameSize); static HPALETTE CreateBIPalette(HPALETTE hpal, LPBITMAPINFOHEADER lpbi); static BOOL NEAR IsIdentityPalette(HPALETTE hpal); static BOOL NEAR AreColorsAllGDIColors(LPBITMAPINFOHEADER lpbi); static BOOL SetPalFlags(HPALETTE hpal, int iIndex, int cntEntries, UINT wFlags); static HPALETTE CreateExplicitPalette(void);
void DrawDibPalChange(PDD pdd, HDC hdc, HPALETTE hpal); void DrawDibClipChange(PDD pdd, UINT wFlags);
static BOOL FixUpCodecPalette(HIC hic, LPBITMAPINFOHEADER lpbi); static BOOL NEAR SendSetPalette(PDD pdd);
#ifndef WIN32
extern BOOL gf286;
/**************************************************************************
**************************************************************************/ static void InitDCI() { UINT WidthBytes;
//
// initialize DCI and open a surface handle to it.
//
// if DVA = 0 in WIN.INI, don't use DCI or DVA.
// PSS tells people to use this if they have video problems,
// so we shouldn't change the string.
if (gf286 || !GetProfileInt(szDrawDib, szDVA, TRUE)) return;
hdcDCI = DCIOpenProvider();
if (hdcDCI == NULL) return;
DCICreatePrimary(hdcDCI, &pdci);
if (pdci == NULL) return;
WidthBytes = abs((UINT)pdci->lStride);
//
// convert DCISURFACEINFO into a BITMAPINFOHEADER...
//
biScreen.bi.biSize = sizeof(BITMAPINFOHEADER); biScreen.bi.biWidth = WidthBytes*8/(UINT)pdci->dwBitCount; biScreen.bi.biHeight = pdci->dwHeight; biScreen.bi.biPlanes = 1; biScreen.bi.biBitCount = (UINT)pdci->dwBitCount; biScreen.bi.biCompression = BI_1632; //!!!???
biScreen.bi.biSizeImage = pdci->dwHeight * WidthBytes; biScreen.bi.biXPelsPerMeter = WidthBytes; biScreen.bi.biYPelsPerMeter = 0; biScreen.bi.biClrUsed = 0; biScreen.bi.biClrImportant = 0; biScreen.dwMask[0] = pdci->dwMask[0]; biScreen.dwMask[1] = pdci->dwMask[1]; biScreen.dwMask[2] = pdci->dwMask[2];
if (pdci->dwCompression == 0 && (UINT)pdci->dwBitCount == 16) { biScreen.dwMask[0] = 0x007C00; biScreen.dwMask[1] = 0x0003E0; biScreen.dwMask[2] = 0x00001F; }
if (pdci->dwCompression == 0 && (UINT)pdci->dwBitCount >= 24) { biScreen.dwMask[0] = 0xFF0000; biScreen.dwMask[1] = 0x00FF00; biScreen.dwMask[2] = 0x0000FF; }
DPF(("DCI Surface: %dx%dx%d", (int)pdci->dwWidth, (int)pdci->dwHeight, (int)LOWORD(pdci->dwBitCount))); DPF(("DCI Surface: biCompression=%ld Masks: %04lX %04lX %04lX",biScreen.bi.biCompression,biScreen.dwMask[0],biScreen.dwMask[1],biScreen.dwMask[2]));
if (pdci->lStride > 0) biScreen.bi.biHeight = -(int)pdci->dwHeight; else pdci->dwOffSurface -= biScreen.bi.biSizeImage;
//
// make sure the pointer is valid.
//
if (pdci->dwOffSurface >= 0x10000) { DPF(("DCI Surface cant be supported"));
lpScreen = NULL; biScreen.bi.biSize = 0; } else { lpScreen = (LPVOID)MAKELP(pdci->wSelSurface,pdci->dwOffSurface); }
//
// check if the display has broken rasters.
//
if (pdci->dwDCICaps & DCI_1632_ACCESS) gfDisplayHasBrokenRasters = (0x10000l % WidthBytes) != 0;
if (gfDisplayHasBrokenRasters) { DPF(("*** Display has broken rasters")); } }
void TermDCI() { if (pdci) { DCIDestroy(pdci); pdci = NULL; }
if (hdcDCI) { DeleteDC(hdcDCI); hdcDCI = NULL; } }
#else
#define InitDCI()
#define TermDCI()
#endif
/**************************************************************************
* @doc INTERNAL DrawDib * * @api BOOL | DrawDibInit | This function initalizes the DrawDib library. * * @rdesc Returns TRUE if the library is initialized properly, otherwise * it returns FALSE. * * @comm Users don't need to call this, because <f DrawDibOpen> does it for them. * * @xref DrawDibTerm * **************************************************************************/ BOOL VFWAPI DrawDibInit() { HDC hdc;
if (gfInit) return TRUE;
gf286 = (BOOL)(GetWinFlags() & WF_CPU286);
hdc = GetDC(NULL);
gwScreenBitDepth = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES); gwRasterCaps = GetDeviceCaps(hdc, RASTERCAPS);
InitDCI();
ReleaseDC(NULL, hdc);
gfHalftone = GetProfileInt(szDrawDib, szHalftone, FALSE); gfBitmap = GetProfileInt(szDrawDib, szDrawToBitmap, -1); gfBitmapX = GetProfileInt(szDrawDib, szDecompressToBitmap, TRUE); gfScreenX = GetProfileInt(szDrawDib, szDecompressToScreen, TRUE); gfDrawX = GetProfileInt(szDrawDib, szDrawToScreen, TRUE);
#ifdef DEBUG
gwRasterCaps = GetProfileIntA("drawdib", "RasterCaps", gwRasterCaps); gwScreenBitDepth = GetProfileIntA("drawdib", "ScreenBitDepth", gwScreenBitDepth); gf286 = GetProfileIntA("drawdib", "cpu", gf286 ? 286 : 386) == 286; #endif
//
// fix up the bit-depth of the display.
//
if (gwScreenBitDepth > 32) gwScreenBitDepth = 32;
if (gwScreenBitDepth == 16 || gwScreenBitDepth == 32) { BITMAPINFOHEADER bi; UINT u;
bi.biSize = sizeof(bi); bi.biWidth = 1; bi.biHeight = 1; bi.biPlanes = 1; bi.biBitCount = gwScreenBitDepth; bi.biCompression = 0; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; bi.biClrImportant = 0;
u = (UINT)DrawDibProfileDisplay(&bi);
if (u == 0) { DPF(("Pretending display is 24 bit (not %d)", gwScreenBitDepth)); gwScreenBitDepth = 24; } }
gfInit = TRUE; return TRUE; }
/**************************************************************************
* @doc INTERNAL DrawTerm * * @api BOOL | DrawDibTerm | This function teminates the DrawDib library. * * @rdesc Returns TRUE. * * @comm Users don't need to call this, because <f DrawDibClose> does it for them. * * @xref DrawDibInit * **************************************************************************/ BOOL VFWAPI DrawDibTerm() { //
// free global stuff.
//
TermDCI(); gfInit = FALSE; return TRUE; }
/**************************************************************************
* @doc INTERNAL DrawDib * * @api void | DrawDibCleanup | clean up drawdib stuff * called in MSVIDEOs WEP() * **************************************************************************/ void FAR PASCAL DrawDibCleanup(HTASK hTask) { if (gUsage > 0) RPF(("%d DrawDib handles left open", gUsage));
DrawDibTerm(); }
/**************************************************************************
* @doc INTERNAL * * @api BOOL | DibEq | This function compares two dibs. * * @parm LPBITMAPINFOHEADER | lpbi1 | Pointer to one bitmap. * this DIB is assumed to have the colors after biSize bytes. * * @parm LPBITMAPINFOHEADER | lpbi2 | Pointer to second bitmap. * this DIB is assumed to have the colors after biSize bytes. * * @rdesc Returns TRUE if bitmaps are identical, FALSE otherwise. * **************************************************************************/ INLINE BOOL NEAR PASCAL DibEq(LPBITMAPINFOHEADER lpbi1, LPBITMAPINFOHEADER lpbi2) { if (lpbi1 == NULL || lpbi2 == NULL) return FALSE;
return lpbi1->biCompression == lpbi2->biCompression && (int)lpbi1->biSize == (int)lpbi2->biSize && (int)lpbi1->biWidth == (int)lpbi2->biWidth && (int)lpbi1->biHeight == (int)lpbi2->biHeight && (int)lpbi1->biBitCount == (int)lpbi2->biBitCount && ((int)lpbi1->biBitCount > 8 || (int)lpbi1->biClrUsed == (int)lpbi2->biClrUsed && _fmemcmp((LPBYTE)lpbi1 + lpbi1->biSize, (LPBYTE)lpbi2 + lpbi2->biSize, (int)lpbi1->biClrUsed*sizeof(RGBQUAD)) == 0); }
/**************************************************************************
* @doc INTERNAL * * @api PDD NEAR | DrawDibLock | Lock the DrawDib handle. * * @parm HDRAWDIB | hdd | DrawDib handle. * * @rdesc Returns a pointer to a <t DRAWDIB_STRUCT> if successful, NULL otherwise. * **************************************************************************/
#define DrawDibLock(hdd) (\
hdd == NULL || ((PDD)hdd)->wSize != sizeof(DRAWDIB_STRUCT) ? NULL : \ (PDD)hdd)
/**************************************************************************
* @doc EXTERNAL DrawDib * * @api HDRAWDIB | DrawDibOpen | This function opens a DrawDib context for drawing. * * @rdesc Returns a handle to a DrawDib context if successful, * otherwise it returns NULL. * * @comm Use this function to obtain a handle to a DrawDib context * before drawing device independent bitmaps. * * If drawing multiple device independent bitmaps simultaneously, * obtain a handle to a DrawDib context for each bitmap. * * @xref <f DrawDibClose> * **************************************************************************/ HDRAWDIB VFWAPI DrawDibOpen(void) { HDRAWDIB hdd; PDD pdd;
hdd = LocalAlloc(LPTR, sizeof(DRAWDIB_STRUCT)); /* zero init */
if (hdd == NULL) return NULL;
pdd = (PDD)hdd; pdd->wSize = sizeof(DRAWDIB_STRUCT);
if (gUsage++ == 0) DrawDibInit();
return hdd; }
/**************************************************************************
* @doc EXTERNAL DrawDib * * @api BOOL | DrawDibClose | This function closes a DrawDib context * and frees the resources DrawDib allocated for it. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @rdesc Returns TRUE if the context closed successfully. * * @comm Use this function to free the <p hdd> handle * after the application has finished drawing. * * @xref <f DrawDibOpen> **************************************************************************/ BOOL VFWAPI DrawDibClose(HDRAWDIB hdd) { PDD pdd;
if ((pdd = DrawDibLock(hdd)) == NULL) return FALSE;
DrawDibFree(pdd, FALSE, FALSE);
pdd->wSize = 0; LocalFree(hdd);
if (--gUsage == 0) DrawDibTerm();
return TRUE; }
/**************************************************************************
* @doc INTERNAL * * @api BOOL | DrawDibFree | Free up everything in a <t DRAWDIB_STRUCT>. * * @parm PDD | pdd | Pointer to a <t DRAWDIB_STRUCT>. * * @rdesc Returns TRUE if successful, FALSE otherwise. * **************************************************************************/ static BOOL NEAR PASCAL DrawDibFree(PDD pdd, BOOL fSameDib, BOOL fSameSize) { if (pdd == NULL) return FALSE;
//
// If the draw palette has changed, the compressor may now be giving us DIBs
// mapped to a different palette, so we need to clean up so we'll produce
// a new mapping table so we'll actually draw with the new palette.
// (see SendSetPalette)
//
if (!fSameDib) { //
// if this palette is selected as the foreground palette
// and we delete it we are going to hose GDI!
//
if (pdd->hpal) DeleteObject(pdd->hpal); if (pdd->hpalCopy) DeleteObject(pdd->hpalCopy);
pdd->hpal = NULL; pdd->hpalCopy = NULL; }
if (!fSameDib) {
if (pdd->lpbi) { GlobalFreePtr(pdd->lpbi); pdd->lpbi = NULL; pdd->lpargbqIn = NULL; }
if (pdd->lpDitherTable) { DitherTerm(pdd->lpDitherTable); pdd->lpDitherTable = NULL; }
if (pdd->hic && pdd->hic != (HIC)-1) { ICDecompressEnd(pdd->hic); ICDecompressExEnd(pdd->hic); ICClose(pdd->hic); }
pdd->ulFlags &= ~(DDF_IDENTITYPAL); pdd->hic = NULL;
pdd->iAnimateStart = 0; pdd->iAnimateLen = 0; pdd->iAnimateEnd = 0; }
if (!fSameSize || !fSameDib) { if (pdd->hdcDraw && hbmStockMono) SelectObject(pdd->hdcDraw, hbmStockMono);
if (pdd->hdcDraw) DeleteDC(pdd->hdcDraw);
if (pdd->hbmDraw) { DeleteObject(pdd->hbmDraw);
//
// if we have a bitmap pointer lose it
//
if (pdd->ulFlags & (DDF_CANBITMAPX)) pdd->pbBitmap = NULL; }
if ((pdd->pbStretch) && (pdd->pbStretch != pdd->lpDIBSection)) GlobalFreePtr(pdd->pbStretch);
if ((pdd->pbDither) && (pdd->pbDither != pdd->lpDIBSection)) GlobalFreePtr(pdd->pbDither);
if ((pdd->pbBuffer) && (pdd->pbBuffer != pdd->lpDIBSection)) GlobalFreePtr(pdd->pbBuffer);
#if USE_SETDI
if (pdd->hbmDraw) SetBitmapEnd(&pdd->sd); #endif
pdd->hdcDraw = NULL; pdd->hbmDraw = NULL; pdd->lpDIBSection = NULL; pdd->pbStretch = NULL; pdd->pbDither = NULL; pdd->pbBuffer = NULL;
pdd->biDraw.biBitCount = 0; pdd->biDraw.biWidth = 0; pdd->biDraw.biHeight = 0;
pdd->biBuffer.biBitCount = 0; pdd->biBuffer.biWidth = 0; pdd->biBuffer.biHeight = 0;
// clear all the internal flags (except palette stuff)
pdd->ulFlags &= ~(DDF_OURFLAGS ^ DDF_IDENTITYPAL); pdd->ulFlags |= DDF_DIRTY;
pdd->iDecompress = 0; }
return TRUE; }
/**************************************************************************
* @doc INTERNAL * * @api UINT | QueryDraw | see if the current display device * (DISPDIB or GDI) can draw the given dib * * @parm PDD | pdd | pointer to a <t DRAWDIB_STRUCT>. * * @parm LPBITMAPINFOHEADER | lpbi | pointer to a bitmap. * * @rdesc Returns display flags, see profdisp.h * **************************************************************************/
static UINT NEAR QueryDraw(PDD pdd, LPBITMAPINFOHEADER lpbi) { return (UINT)DrawDibProfileDisplay(lpbi); }
/**************************************************************************
* @doc INTERNAL DrawDib * * @comm Called from DrawDibBegin to try decompression to a bitmap. * **************************************************************************/ BOOL DrawDibQueryBitmapX( PDD pdd ) { BITMAPINFOHEADER *pbi;
#ifndef _WIN32
if (!CanLockBitmaps()) { return FALSE; } #endif
if (gwScreenBitDepth == 8 && !(gwRasterCaps & RC_PALETTE)) return FALSE;
if ((gwRasterCaps & RC_PALETTE) && !(pdd->ulFlags & DDF_IDENTITYPAL)) return FALSE;
pbi = &pdd->biStretch;
if (!GetDIBBitmap(pdd->hbmDraw, pbi)) return FALSE;
#ifdef XDEBUG
if (ICDecompressQuery(pdd->hic, pdd->lpbi, pbi) != ICERR_OK) { if (mmGetProfileIntA(szDrawDib, "ForceDecompressToBitmap", FALSE)) { pbi->biHeight = -pbi->biHeight; pbi->biCompression = 0; } } #endif
if (ICDecompressQuery(pdd->hic, pdd->lpbi, pbi) != ICERR_OK) { if (pbi->biCompression == BI_BITMAP && pbi->biSizeImage <= 128*1024l && (pbi->biXPelsPerMeter & 0x03) == 0 && pbi->biSizeImage > 64*1024l) { pdd->ulFlags |= DDF_HUGEBITMAP; pbi->biCompression = 0;
pbi->biSizeImage -= pbi->biYPelsPerMeter; //FillBytes
if (ICDecompressQuery(pdd->hic, pdd->lpbi, pbi) != ICERR_OK) return FALSE; } else return FALSE; }
pdd->ulFlags |= DDF_NEWPALETTE; // force check in DrawDibRealize
pdd->ulFlags |= DDF_CANBITMAPX; // can decompress to bitmaps
if (pdd->ulFlags & DDF_HUGEBITMAP) RPF((" Can decompress '%4.4hs' to a HUGE BITMAP (%dx%dx%d)",(LPSTR)&pdd->lpbi->biCompression, PUSHBI(*pbi))); else RPF((" Can decompress '%4.4hs' to a BITMAP (%dx%dx%d)",(LPSTR)&pdd->lpbi->biCompression, PUSHBI(*pbi)));
//
// reuse the stretch buffer for the bitmap.
//
pdd->biStretch = *pbi; #ifndef _WIN32
pdd->pbStretch = LockBitmap(pdd->hbmDraw);
if (pdd->pbStretch == NULL) { DPF((" Unable to lock bitmap!")); pdd->ulFlags &= ~DDF_CANBITMAPX; // can't decompress to bitmaps
return FALSE; } #endif
return TRUE; }
#define Is565(bi) (((bi)->biCompression == BI_BITFIELDS) && \
((bi)->biBitCount == 16) && \ (((LPDWORD)((bi)+1))[0] == 0x00F800) && \ (((LPDWORD)((bi)+1))[1] == 0x0007E0) && \ (((LPDWORD)((bi)+1))[2] == 0x00001F) )
/**************************************************************************
* @doc EXTERNAL DrawDib * * @api BOOL | DrawDibBegin | This function changes parameters * of a DrawDib context or it initializes a new DrawDib context. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @parm HDC | hdc | Specifies a handle to a display context for drawing (optional). * * @parm int | dxDest | Specifies the width of the destination rectangle. * Width is specified in MM_TEXT client units. * * @parm int | dyDest | Specifies the height of the destination rectangle. * Height is specified in MM_TEXT client units. * * @parm LPBITMAPINFOHEADER | lpbi | Specifies a pointer to a * <t BITMAPINFOHEADER> structure containing the * image format. The color table for the DIB follows the * image format. * * @parm int | dxSrc | Specifies the width of the source rectangle. * Width is specified in pixels. * * @parm int | dySrc | Specifies the height of the source rectangle. * Height is specified in pixels. * * @parm UNIT | wFlags | Specifies the applicable flags for * the function. The following flags are defined: * * @flag DDF_SAME_HDC | Assumes the handle to the display context * is already specified. When this flag is used, * DrawDib also assumes the correct palette has already been * realized into the device context (possibly by * <f DrawDibRealize>). * * @flag DDF_SAME_DRAW | Uses the drawing parameters previously * specified for this function. Use this flag only * if <p lpbi>, <p dxDst>, <p dyDst>, <p dxSrc>, and <p dySrc> * have not changed since using <f DrawDibDraw> or <f DrawDibBegin>. * * @flag DDF_DONTDRAW | Indicates the frame is to be decompressed * and not drawn. The DDF_UPDATE flag can be used later * to actually draw the image. * * @flag DDF_ANIMATE | Allows palette animation. If this flag is present, * the palette <f DrawDib> creates will have the PC_RESERVED flag set for * as many entries as possible, and the palette can be animated by * <f DrawDibChangePalette>. If using <f DrawDibBegin> with * <f DrawDibDraw>, set this flag with <f DrawDibBegin> * rather than <f DrawDibDraw>. * * @flag DDF_JUSTDRAWIT | Uses GDI to draw the image. This prevents * the DrawDib functions from calling ICM to decompress * the image or prevents them from * using their own routines to stretch or dither the image. * This essentially reduces <f DrawDibDraw> to <f StretchDIBits>. * * @flag DDF_BACKGROUNDPAL | Realizes the palette used for drawing * in the background leaving the actual palette used for display * unchanged. (This flag is valid only if DDF_SAME_HDC is not set.) * * @flag DDF_HALFTONE | Always dithers the DIB to a standard palette * regardless of the palette of the DIB. If using <f DrawDibBegin> with * <f DrawDibDraw>, set this flag with <f DrawDibBegin> * rather than <f DrawDibDraw>. * * @flag DDF_BUFFER | Indicates DrawDib should try to use a * offscreen buffer so DDF_UPDATE can be used. This * disables decompression and drawing directly to the screen. * If DrawDib is unable to create an offscreen buffer, * it will decompress or draw directly to the screen. * * For more information, see the DDF_UPDATE and DDF_DONTDRAW * flags described for <f DrawDibDraw>. * * * @rdesc Returns TRUE if successful. * * @comm This function prepares to draw a bitmap specified by <p lpbi> * to the display context <p hdc>. The image is stretched to * the size specified by <p dxDest> and <p dyDest>. If <p dxDest> and * <p dyDest> are (-1, -1), the bitmap is drawn to a * 1:1 scale without stretching. * * Use this function only if you want to prepare DrawDib * before using <f DrawDibDraw> to draw the image. * If you do not use this function, <f DrawDibDraw> implicitly * uses it when it draws the image. * * To update the flags set with <f DrawDibBegin>, call <f DrawDibBegin> * with new parameters. * * When <f DrawDibBegin> is used, the <f DDF_SAME_DRAW> * flag is normally set for <f DrawDibDraw>. * * If the parameters of <f DrawDibBegin> have not changed, subsequent * uses of it have not effect. * * Use <f DrawDibEnd> to free memory used by the DrawDib context. * * @xref <f DrawDibEnd> <f DrawDibDraw> **************************************************************************/ //#ifndef WIN32
//#pragma message("Make DrawDibBegin faster for changing the size only!")
//#endif
BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd, HDC hdc, int dxDst, int dyDst, LPBITMAPINFOHEADER lpbi, int dxSrc, int dySrc, UINT wFlags) { PDD pdd; int ScreenBitDepth; int dxSave,dySave; BOOL fNewPal; BOOL fSameDib; BOOL fSameSize; BOOL fSameFlags; BOOL fSameHdc; UINT wFlagsChanged; DWORD ulFlagsSave; DWORD dw; UINT w; HPALETTE hPal; LONG lSize;
//
// Quick sanity checks....
//
if (lpbi == NULL) return FALSE;
if ((pdd = DrawDibLock(hdd)) == NULL) return FALSE;
if (!gfInit) DrawDibInit();
//
// fill in defaults.
//
if (dxSrc < 0) dxSrc = (int)lpbi->biWidth;
if (dySrc < 0) dySrc = (int)lpbi->biHeight;
if (dxDst < 0) dxDst = dxSrc;
if (dyDst < 0) dyDst = dySrc;
if (dxSrc == 0 || dySrc == 0) // !!! || dxDst == 0 || dyDst == 0)
return FALSE;
ulFlagsSave = pdd->ulFlags; wFlagsChanged = ((UINT)pdd->ulFlags ^ wFlags);
fSameHdc = hdc == pdd->hdcLast; fSameDib = DibEq(pdd->lpbi, lpbi) && !(wFlagsChanged & DDF_HALFTONE) && (pdd->hpalDraw == pdd->hpalDrawLast);
fSameFlags = (pdd->ulFlags & DDF_BEGINFLAGS) == (wFlags & DDF_BEGINFLAGS); fSameSize = pdd->dxDst == dxDst && pdd->dyDst == dyDst && pdd->dxSrc == dxSrc && pdd->dySrc == dySrc; pdd->hdcLast = hdc;
//
// do a quick check to see if the params have changed.
// If the DIB, and size of the DIB, and flags used are the same as the last
// time we called DrawDibBegin, then there's nothing to do and we'll only
// waste time plodding through this code.
// There is one case when all these could be the same, but the situation
// has still changed enough so that we need to recompute things... if the
// hdc is different than last time, and we're dealing with RLE. You see,
// we make some decisions about RLE (like we can go direct to a screen DC
// but not a memory DC) that are affected by what hdc we're using. So
// we will not bail out early if we are using RLE and the hdc's are
// different.
//
if (fSameDib && fSameSize && fSameFlags) { if ((lpbi->biCompression != BI_RLE8 && lpbi->biCompression != BI_RLE4) || fSameHdc) return TRUE; }
pdd->hpalDrawLast = pdd->hpalDraw;
RPF(("DrawDibBegin %dx%dx%d '%4.4hs' [%d %d] [%d %d]", (int)lpbi->biWidth, (int)lpbi->biHeight, (int)lpbi->biBitCount, (lpbi->biCompression == BI_RGB ? (LPSTR)"None" : lpbi->biCompression == BI_RLE8 ? (LPSTR)"Rle8" : lpbi->biCompression == BI_RLE4 ? (LPSTR)"Rle4" : (LPSTR)&lpbi->biCompression), dxSrc, dySrc, dxDst, dyDst));
fNewPal = pdd->hpal == NULL || !fSameDib;
//
// make sure this palette is not the in the DC, because we
// are going to delete it, and GDI get real upset if we do this.
//
if (fNewPal && pdd->hpal && hdc) { hPal = SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), TRUE);
if (hPal == pdd->hpal) RPF((" Warning unselecting palette...")); }
DrawDibFree(pdd, fSameDib, fSameSize);
pdd->dxSrc = dxSrc; pdd->dySrc = dySrc; pdd->dxDst = dxDst; pdd->dyDst = dyDst;
//
// copy the source DIB header and the colors.
//
if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8) lpbi->biClrUsed = (1 << (int)lpbi->biBitCount);
////if (lpbi->biClrUsed != 0 && lpbi->biBitCount > 8)
//// lpbi->biClrUsed = 0;
// Make a copy of the source format. Remember, some codec could have
// defined a custom format larger than a BITMAPINFOHEADER so make a copy
// of EVERYTHING.
if (!fSameDib) { lSize = lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD); pdd->lpbi = (LPBITMAPINFOHEADER)GlobalAllocPtr(GPTR, lSize); if (pdd->lpbi == NULL) return FALSE; _fmemcpy(pdd->lpbi, lpbi, (int)lSize); // This is where the colour info is
pdd->lpargbqIn = (LPVOID)((LPBYTE)lpbi + lpbi->biSize); }
pdd->biBuffer = *lpbi;
pdd->lpbi->biSizeImage = 0; pdd->biBuffer.biSizeImage = 0;
//
// init all other color tables to be the initial colors
//
if (lpbi->biBitCount <= 8) { _fmemcpy(pdd->argbq, (LPBYTE)lpbi+(int)lpbi->biSize, (int)lpbi->biClrUsed * sizeof(RGBQUAD)); _fmemcpy(pdd->aw, (LPBYTE)lpbi+(int)lpbi->biSize, (int)lpbi->biClrUsed * sizeof(RGBQUAD)); }
// set PalUse to default: DIB_PAL_COLORS. This will be set
// to DIB_PAL_INDICES if DrawdibCheckPalette is called and detects
// that it is safe to use indices. DIB_PAL_COLORS is a safe
// default.
pdd->uiPalUse = DIB_RGB_COLORS; // assume RGB colors for now.
//
// make sure the device is a palette device before dinking with
// palette animation.
//
if (wFlags & DDF_ANIMATE) { if (!(gwRasterCaps & RC_PALETTE) || (int)lpbi->biBitCount > 8 || pdd->hpalDraw) wFlags &= ~DDF_ANIMATE; }
//
// copy the flags
//
try_again: pdd->ulFlags &= ~DDF_USERFLAGS; pdd->ulFlags |= (wFlags & DDF_USERFLAGS);
pdd->ulFlags &= ~DDF_UPDATE;
//
// deal with a decompressor if needed.
//
switch (lpbi->biCompression) { case BI_RGB: break;
default: //
// see if the DISPLAY/DISPDIB can draw the format directly!
//
// if the buffer flag is set we MUST use a decompress buffer.
// regardless of what the display can do
//
if (wFlags & DDF_BUFFER) w = 0; else w = QueryDraw(pdd, lpbi);
if (w & PD_CAN_DRAW_DIB) { if (((dxSrc == dxDst && dySrc == dyDst) && (w & PD_STRETCHDIB_1_1_OK)) || ((dxSrc != dxDst || dySrc != dyDst) && (w & PD_STRETCHDIB_1_N_OK)) || ((dxDst % dxSrc) == 0 && (dyDst % dySrc) == 0 && (w & PD_STRETCHDIB_1_2_OK))) { // GDI can't handle drawing RLEs to a memory DC so we will
// have to pretend that RLE can't be drawn to the screen
// and decompress it first.
// We also can't DITHER RLE, so if we're running on a
// 16 colour display, make sure we're using a decompressor.
if (((lpbi->biCompression != BI_RLE8) && (lpbi->biCompression != BI_RLE4)) || (hdc && IsScreenDC(hdc) && gwScreenBitDepth >=8)) { wFlags |= DDF_JUSTDRAWIT;
if (pdd->hic) ICClose(pdd->hic);
pdd->hic = NULL; goto no_decomp; } } }
if (pdd->hic == NULL) { DWORD fccHandler;
fccHandler = 0;
if (lpbi->biCompression == BI_RLE8) fccHandler = mmioFOURCC('R','L','E',' ');
pdd->hic = ICLocate(ICTYPE_VIDEO, fccHandler, lpbi, NULL, ICMODE_FASTDECOMPRESS);
if (pdd->hic == NULL) pdd->hic = ICDecompressOpen(ICTYPE_VIDEO, fccHandler,lpbi,NULL);
if (pdd->hic) { //
// make sure the codec uses its default palette out of the gate
//
if (ICDecompressSetPalette(pdd->hic, NULL) == ICERR_OK) { pdd->ulFlags |= DDF_CANSETPAL; RPF((" codec supports ICM_SET_PALETTE")); } else { pdd->ulFlags &= ~DDF_CANSETPAL; } } }
if (pdd->hic == NULL || pdd->hic == (HIC)-1) { RPF((" Unable to open compressor '%4.4ls'",(LPSTR)&lpbi->biCompression)); pdd->hic = (HIC)-1;
if (wFlags & DDF_BUFFER) { RPF((" Turning DDF_BUFFER off")); wFlags &= ~DDF_BUFFER; goto try_again; }
return FALSE; }
//
// now find the best DIB format to decompress to.
//
if (!ICGetDisplayFormat(pdd->hic, lpbi, &pdd->biBuffer, (gfHalftone || (wFlags & DDF_HALFTONE)) ? 16 : 0, MulDiv(dxDst,abs((int)lpbi->biWidth),dxSrc), MulDiv(dyDst,abs((int)lpbi->biHeight),dySrc))) { RPF((" Compressor error!")); codec_error: //ICClose(pdd->hic);
//pdd->hic = (HIC)-1;
return FALSE; }
//
// we have new source params
//
dxSrc = MulDiv(dxSrc, abs((int)pdd->biBuffer.biWidth), (int)pdd->lpbi->biWidth); dySrc = MulDiv(dySrc, abs((int)pdd->biBuffer.biHeight), (int)pdd->lpbi->biHeight); // xSrc = MulDiv(xSrc, abs((int)pdd->biBuffer.biWidth), (int)pdd->lpbi->biWidth);
// ySrc = MulDiv(ySrc, abs((int)pdd->biBuffer.biHeight), (int)pdd->lpbi->biHeight);
//
// now allocate the decompress buffer!
//
pdd->biBuffer.biSizeImage = DIBSIZEIMAGE(pdd->biBuffer); pdd->pbBuffer = GlobalAllocPtr(GHND,pdd->biBuffer.biSizeImage);
if (pdd->pbBuffer == NULL) { RPF((" No Memory for decompress buffer")); ICClose(pdd->hic); pdd->hic = (HIC)-1; return FALSE; } pdd->ulFlags |= DDF_DIRTY;
dw = ICDecompressBegin(pdd->hic, lpbi, &pdd->biBuffer);
if (dw != ICERR_OK) { RPF((" Compressor failed ICM_DECOMPRESS_BEGIN")); goto codec_error; return FALSE; }
RPF((" Decompressing '%4.4hs' to %dx%dx%d%s",(LPSTR)&lpbi->biCompression, PUSHBI(pdd->biBuffer), Is565(&pdd->biBuffer) ? (LPSTR) "(565)" : (LPSTR) "" )); pdd->iDecompress = DECOMPRESS_BUFFER;
_fmemcpy(pdd->aw,pdd->argbq, 256*sizeof(RGBQUAD)); lpbi = &pdd->biBuffer; break; } no_decomp: pdd->biDraw = pdd->biBuffer; pdd->biDraw.biSizeImage = 0;
pdd->biDraw.biHeight = abs((int)pdd->biDraw.biHeight);
if ((!(wFlags & DDF_JUSTDRAWIT)) && (lpbi->biCompression == BI_RGB)) { //
// test the display device for this DIB format
//
w = QueryDraw(pdd, lpbi);
//
// get the bit depth of the screen device.
//
ScreenBitDepth = gwScreenBitDepth;
if (ScreenBitDepth > 24) ScreenBitDepth = 32; //???!!!
// does the display support drawing 16bpp DIBs?
// if it does not, treat it like a 24bpp device.
if (ScreenBitDepth >= 24 && lpbi->biBitCount == 32 && !(w & PD_CAN_DRAW_DIB)) ScreenBitDepth = 24;
if (ScreenBitDepth >= 16 && lpbi->biBitCount == 16 && !(w & PD_CAN_DRAW_DIB)) ScreenBitDepth = 24;
//
// check if the display driver isn't very good, for this format
//
if (!(w & PD_STRETCHDIB_1_1_OK)) { pdd->ulFlags |= DDF_BITMAP; }
//
// if the display driver isn't very good make a bitmap to copy into
// to draw.
//
switch (gfBitmap) { case 0: pdd->ulFlags &= ~DDF_BITMAP; break;
case 1: pdd->ulFlags |= DDF_BITMAP; break; }
#ifndef WIN32
//
// for 16/32 bit DIBs, the display may not support DIBS at all and
// we should use bitmaps anyway just in case, even if the user
// tried to override
//
if ((pdd->biDraw.biBitCount == 16 || pdd->biDraw.biBitCount == 32) && w == PD_CAN_DRAW_DIB) { pdd->ulFlags |= DDF_BITMAP; } #endif
if ((dxSrc != dxDst || dySrc != dyDst) && !(w & PD_STRETCHDIB_1_N_OK)) pdd->ulFlags |= DDF_STRETCH;
if (dxSrc*2 == dxDst && dySrc*2 == dyDst && (w & PD_STRETCHDIB_1_2_OK)) pdd->ulFlags &= ~DDF_STRETCH;
if ((dxDst % dxSrc) == 0 && (dyDst % dySrc) == 0 && (w & PD_STRETCHDIB_1_2_OK)) pdd->ulFlags &= ~DDF_STRETCH;
if ((int)lpbi->biBitCount > ScreenBitDepth) pdd->ulFlags |= DDF_DITHER;
//
// force halftone palette
//
if ((gfHalftone || (wFlags & DDF_HALFTONE)) && ScreenBitDepth <= 8) pdd->ulFlags |= DDF_DITHER;
// NOTE we treat a convert up (ie 16->24) as a dither too.
if ((int)lpbi->biBitCount > 8 && (int)lpbi->biBitCount < ScreenBitDepth) pdd->ulFlags |= DDF_DITHER;
if (pdd->ulFlags & DDF_DITHER) { if (lpbi->biBitCount == 16 && (w & PD_CAN_DRAW_DIB)) { pdd->ulFlags &= ~DDF_DITHER; DPF(("Turning off DITHER for 16-bit DIBs, since we can draw them")); }
if (lpbi->biBitCount == 32 && (w & PD_CAN_DRAW_DIB)) { pdd->ulFlags &= ~DDF_DITHER; DPF(("Turning off DITHER for 32-bit DIBs, since we can draw them")); }
if (lpbi->biBitCount == 8 && lpbi->biClrUsed <= 16 && AreColorsAllGDIColors(lpbi)) { pdd->ulFlags &= ~DDF_DITHER; DPF(("Turning off DITHER for 8-bit DIBs already using the VGA colors")); } }
// force stretching in drawdib if we are dithering
if ((pdd->ulFlags & DDF_DITHER) && ((dxSrc != dxDst) || (dySrc != dyDst))) { pdd->ulFlags |= DDF_STRETCH; }
//
// force a buffer if we dont have one.
//
if ((pdd->ulFlags & DDF_BUFFER) && pdd->hic == NULL && !(pdd->ulFlags & DDF_DITHER) && !(pdd->ulFlags & DDF_STRETCH) && !(pdd->ulFlags & DDF_BITMAP)) { RPF((" Using a buffer because DDF_BUFFER is set.")); pdd->ulFlags |= DDF_STRETCH; // force a 1:1 stretch
}
if (lpbi->biBitCount != 8 && lpbi->biBitCount != 16 && lpbi->biBitCount != 24 #ifndef _WIN32
&& lpbi->biBitCount != 32 #endif
) { DPF(("Turning off stretch for an unsupported format....")); pdd->ulFlags &= ~(DDF_STRETCH); }
}
//
// delete the palette if we are changing who dithers.
//
if (pdd->hpal && pdd->lpbi->biBitCount > 8 && ((pdd->ulFlags ^ ulFlagsSave) & (DDF_DITHER))) { DPF((" Dither person has changed..."));
if (pdd->lpDitherTable) { DitherTerm(pdd->lpDitherTable); pdd->lpDitherTable = NULL; }
if (hdc) { hPal = SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), TRUE);
if (hPal == pdd->hpal) RPF((" Warning unselecting palette...")); }
DeleteObject(pdd->hpal); if (pdd->hpalCopy) DeleteObject(pdd->hpalCopy); pdd->hpal = NULL; pdd->hpalCopy = NULL; }
if (pdd->ulFlags & DDF_STRETCH) { /* the code for stretching *only* works on a 386+ */ if (gf286 || pdd->biBuffer.biBitCount < 8) { RPF((" Using GDI to stretch")); pdd->ulFlags &= ~DDF_STRETCH; } else { //
// we have stretching to do, this requires extra
// headers and buffers.
//
pdd->biStretch = pdd->biBuffer; pdd->biStretch.biWidth = dxDst; pdd->biStretch.biHeight = dyDst; pdd->biStretch.biSizeImage = DIBSIZEIMAGE(pdd->biStretch);
pdd->pbStretch = GlobalAllocPtr(GHND,pdd->biStretch.biSizeImage);
if (pdd->pbStretch == NULL) { RPF((" No memory for stretch buffer, using GDI")); pdd->ulFlags &= ~DDF_STRETCH; } else { RPF((" Stretching %dx%dx%d%s --> %dx%dx%d", dxSrc, dySrc, (int)lpbi->biBitCount, (LPSTR) (Is565(lpbi) ? "(565)":""), dxDst, dyDst, (int)pdd->biStretch.biBitCount, (LPSTR) (Is565(&pdd->biStretch) ? "(565)":"") )); pdd->biDraw.biWidth = dxDst; pdd->biDraw.biHeight = dyDst; dxSrc = dxDst; dySrc = dyDst; lpbi = &pdd->biStretch; } } }
if (pdd->ulFlags & DDF_DITHER) { pdd->ulFlags &= ~DDF_ANIMATE; // cant animate and dither!
if (ScreenBitDepth <= 8) pdd->biDraw.biBitCount = 8; else if (lpbi->biBitCount <= 8) pdd->biDraw.biBitCount = lpbi->biBitCount; else ////////////pdd->biDraw.biBitCount = 24; //!!! what about 16bit DIB support
pdd->biDraw.biBitCount = ScreenBitDepth;
w = QueryDraw(pdd, &pdd->biDraw);
if (w & PD_STRETCHDIB_1_1_OK) pdd->ulFlags &= ~DDF_BITMAP; else pdd->ulFlags |= DDF_BITMAP;
// this is wrong isn't it ? biDraw will be set to
// dxDst if we are stretching, or dxSrc if not. If we are asked to
// dither and stretch together, and we choose to leave the stretching
// to GDI, we will here set biDraw so that we ask the dither code
// to dither from dx/dySrc to dx/dyDst - ie stretch and dither in
// one go. Our current dither code will crash if you ask it to do this.
dxSave = (int)pdd->biDraw.biWidth; dySave = (int)pdd->biDraw.biHeight; #if 0
pdd->biDraw.biWidth = dxDst; // lpbi->biWidth;
pdd->biDraw.biHeight = dyDst; // lpbi->biHeight;
#endif
// !!! So DrawDibDraw will not DebugBreak
pdd->biDraw.biWidth = dxSrc; pdd->biDraw.biHeight = dySrc; pdd->biDraw.biSizeImage = DIBSIZEIMAGE(pdd->biDraw);
RPF((" Dithering %dx%dx%d --> %dx%dx%d", PUSHBI(*lpbi), PUSHBI(pdd->biDraw)));
//
// NOTE we need to use &pdd->biBuffer *not* lpbi because in the
// stretched case lpbi will point to pdd->biStretch and biStretch
// has NO COLOR TABLE
//
pdd->lpDitherTable = DitherInit(&pdd->biBuffer, &pdd->biDraw, &pdd->DitherProc, pdd->lpDitherTable);
if (pdd->lpDitherTable == (LPVOID)-1 || pdd->DitherProc == NULL || !(pdd->pbDither = GlobalAllocPtr(GHND,pdd->biDraw.biSizeImage))) { if (pdd->lpDitherTable == (LPVOID)-1) pdd->lpDitherTable = NULL;
if (pdd->lpDitherTable) DitherTerm(pdd->lpDitherTable);
if (pdd->pbDither) GlobalFreePtr(pdd->pbDither);
pdd->lpDitherTable = NULL; pdd->pbDither = NULL; pdd->biDraw.biBitCount = pdd->biBuffer.biBitCount; pdd->biDraw.biWidth = dxSave; pdd->biDraw.biHeight = dySave; pdd->biDraw.biSizeImage = 0; pdd->ulFlags &= ~DDF_DITHER;
#ifdef DEBUG_RETAIL
if (pdd->DitherProc) RPF((" No Memory for dither tables!")); else RPF((" No DitherProc!")); #endif
} }
//
// create a palette (if needed)
//
if ((gwRasterCaps & RC_PALETTE) && pdd->biDraw.biBitCount <= 8 && pdd->hpal == NULL) { pdd->hpal = CreateBIPalette(pdd->hpal, &pdd->biDraw); pdd->ulFlags |= DDF_NEWPALETTE; }
//
// make sure we treat the palette as new when starting/stopping animate
//
if (wFlagsChanged & DDF_ANIMATE) { pdd->ulFlags |= DDF_NEWPALETTE; }
//
// check for a identity palette
//
if (pdd->hpal == NULL) { pdd->ClrUsed = 0; } else if (pdd->ulFlags & DDF_NEWPALETTE) { GetObject(pdd->hpal,sizeof(int),(LPVOID)&pdd->ClrUsed);
if (wFlagsChanged & DDF_ANIMATE) SetPalFlags(pdd->hpal,0,pdd->ClrUsed,0);
if (IsIdentityPalette(pdd->hpal)) { pdd->ulFlags |= DDF_IDENTITYPAL; pdd->iAnimateStart = 10; } else { pdd->ulFlags &= ~DDF_IDENTITYPAL; pdd->iAnimateStart = 0; }
pdd->iAnimateLen = min(236,pdd->ClrUsed); pdd->iAnimateEnd = pdd->iAnimateStart + pdd->iAnimateLen;
if (pdd->ulFlags & DDF_ANIMATE) { RPF((" Palette animation")); SetPalFlags(pdd->hpal,pdd->iAnimateStart,pdd->iAnimateLen,PC_RESERVED); } }
//
// because of bugs in GDIs StretchDIBits (doing a stretch) we
// always set the number of colors to be the maximum.
//
// this is not a big deal because we are mostly drawing full-color-table
// DIBs any way.
//
if (pdd->biDraw.biBitCount <= 8) pdd->biDraw.biClrUsed = (1 << (int)pdd->biDraw.biBitCount); else pdd->biDraw.biClrUsed = 0;
DrawDibSetPalette(hdd, pdd->hpalDraw);
if (pdd->hpal) { if (pdd->ulFlags & DDF_IDENTITYPAL) RPF((" Drawing with an identity palette")); else RPF((" Drawing with a non-identity palette")); }
if (pdd->uiPalUse == DIB_RGB_COLORS) RPF((" Using DIB_RGB_COLORS")); else RPF((" Using DIB_PAL_COLORS"));
if (pdd->hpalDraw) RPF((" Mapping to another palette"));
if (pdd->ulFlags & DDF_BITMAP) { BOOL fGetDC; BOOL f; HWND hwndActive;
RPF((" Display driver slow for DIBs, using bitmaps"));
if (fGetDC = (hdc == NULL)) { hwndActive = GetActiveWindow(); hdc = GetDC(hwndActive); }
if (pdd->hdcDraw) { if (hbmStockMono) { SelectObject(pdd->hdcDraw, hbmStockMono); } } else /* if (!pdd->hdcDraw) */ { pdd->hdcDraw = CreateCompatibleDC(hdc); }
if (pdd->hbmDraw) { // This fixes a memory leak. Perhaps we can just use the old one?
DPF(("Freeing hbmDraw!\n")); DeleteObject(pdd->hbmDraw); }
//
// NOTE the bitmap must be as wide as the source DIB when we are
// using SetDIBits() because SetDIBits() only takes a start scan not a (x,y)
//
// pdd->hbmDraw = CreateCompatibleBitmap(hdc, (int)pdd->biDraw.biWidth, (int)pdd->biDraw.biHeight);
pdd->hbmDraw = CreateCompatibleBitmap(hdc, (int)pdd->biDraw.biWidth, dySrc);
if (pdd->hbmDraw == NULL || pdd->hdcDraw == NULL) goto bitmap_fail;
hbmStockMono = SelectObject(pdd->hdcDraw,pdd->hbmDraw);
pdd->ulFlags |= DDF_NEWPALETTE;
#if USE_SETDI
f = SetBitmapBegin( &pdd->sd, // structure
hdc, // device
pdd->hbmDraw, // bitmap to set into
&pdd->biDraw, // --> BITMAPINFO of source
pdd->uiPalUse); #else
f = TRUE; #endif
if (!f) { bitmap_fail: if (pdd->hdcDraw) DeleteDC(pdd->hdcDraw);
if (pdd->hbmDraw) DeleteObject(pdd->hbmDraw);
pdd->hdcDraw = NULL; pdd->hbmDraw = NULL; pdd->ulFlags &= ~DDF_BITMAP; }
if (fGetDC) { ReleaseDC(hwndActive, hdc); hdc = NULL; } }
//
// now try to decompress to a bitmap, we only decompress to
// bitmaps if the following is true.
//
// the decompressor must decompress direct, we will not
// stretch/dither afterward
//
// if on a palette device, the color table must be 1:1
//
// we should check a decompressor flag
//
if (pdd->hic && !(pdd->ulFlags & (DDF_STRETCH|DDF_DITHER)) && gfBitmapX && (pdd->lpDIBSection == NULL) && (dxDst == pdd->lpbi->biWidth) && (dyDst == pdd->lpbi->biHeight) ) {
if (pdd->ulFlags & DDF_BITMAP) { if (pdd->hbmDraw) { DrawDibQueryBitmapX(pdd); } } else {
//even though we decided not to use bitmaps, it might still
//be worth trying decompression to bitmaps. the DDF_BITMAP
//flag is based on a comparison of StretchDIBits vs
//SetDIBits+BitBlt. Decompressing to a bitmap could be
//faster even when SetDIBits+Bitblt is slower
// but in this case, if we fail, we have to make sure we don't
// end up doing DDF_BITMAP as we know that's slower.
#if 0
if (QueryDraw(pdd, &pdd->biBuffer) & PD_BITBLT_FAST) {
BOOL fGetDC; HWND hwndActive;
RPF((" Not using BITMAPS, but trying Decomp to Bitmap"));
if (fGetDC = (hdc == NULL)) { hwndActive = GetActiveWindow(); hdc = GetDC(hwndActive); }
pdd->hdcDraw = CreateCompatibleDC(hdc); pdd->hbmDraw = CreateCompatibleBitmap(hdc, (int)pdd->biDraw.biWidth, (int)pdd->biDraw.biHeight);
if ((pdd->hbmDraw != NULL) && (pdd->hdcDraw != NULL)) {
hbmStockMono = SelectObject(pdd->hdcDraw,pdd->hbmDraw);
if (fGetDC) { ReleaseDC(hwndActive, hdc); hdc = NULL; }
DrawDibQueryBitmapX(pdd); }
if (!(pdd->ulFlags & DDF_CANBITMAPX)) { if (pdd->hdcDraw) { DeleteDC(pdd->hdcDraw); pdd->hdcDraw = NULL; }
if (pdd->hbmDraw) { DeleteObject(pdd->hbmDraw); pdd->hbmDraw = NULL; } } } #endif
} }
#ifndef WIN32 // Note: pdci will be 0 for Win32
//
// see if the decompressor can decompress directly to the screen
// doing everything, stretching and all.
//
if (pdd->hic && pdci && gfScreenX) { if (wFlags & DDF_BUFFER) { DPF((" DDF_BUFFER specified, unable to decompress to screen")); goto cant_do_screen; }
//
// try to decompress to screen.
//
if (((gwRasterCaps & RC_PALETTE) && !(pdd->ulFlags & DDF_IDENTITYPAL)) || (gwScreenBitDepth == 8 && !(gwRasterCaps & RC_PALETTE)) || (pdd->ulFlags & (DDF_STRETCH|DDF_DITHER)) || (ICDecompressExQuery(pdd->hic, 0, pdd->lpbi, NULL, 0, 0, pdd->dxSrc, pdd->dySrc, (LPBITMAPINFOHEADER) &biScreen, lpScreen, 0, 0, pdd->dxDst, pdd->dyDst) != ICERR_OK)) { cant_do_screen: ; // we can't decompress to the screen
} else { // we can decompress to the screen
pdd->ulFlags |= DDF_CLIPCHECK; // we need clipping checking
pdd->ulFlags |= DDF_NEWPALETTE; // force check in DrawDibRealize
pdd->ulFlags |= DDF_CANSCREENX; // we can decompress to screen
pdd->ulFlags |= DDF_CLIPPED; // we are initialized for clipped now
RPF((" Can decompress '%4.4hs' to the SCREEN",(LPSTR)&pdd->lpbi->biCompression)); } }
#if 0
//
// see if we can draw direct to the screen
//
if (pdd->hic && pdci && gfDrawX) { if (TRUE) goto cant_draw_screen;
pdd->ulFlags |= DDF_CLIPCHECK; // we need clipping checking
pdd->ulFlags |= DDF_NEWPALETTE; // force check in DrawDibRealize
pdd->ulFlags |= DDF_CANDRAWX; // we can decompress to screen
pdd->ulFlags |= DDF_CLIPPED; // we are initialized for clipped now
RPF((" Can draw to the SCREEN"));
cant_draw_screen: ; } #endif
#endif
//
// see if the source cordinates need translated
//
if (abs((int)pdd->biBuffer.biWidth) != (int)pdd->lpbi->biWidth || abs((int)pdd->biBuffer.biHeight) != (int)pdd->lpbi->biHeight) { pdd->ulFlags |= DDF_XLATSOURCE; }
return TRUE; }
/**************************************************************************
* @doc EXTERNAL DrawDib * * @api BOOL | DrawDibEnd | This function frees a DrawDib context. * * @parm HDRAWDIB | hdd | Specifies the handle to the DrawDib context to free. * * @rdesc Returns TRUE if successful. * * @comm Any flags set or palette changes made by <f DrawDibBegin> or * <f DrawDibDraw> is discarded by <f DrawDibEnd>. * **************************************************************************/ BOOL VFWAPI DrawDibEnd(HDRAWDIB hdd) { PDD pdd;
if ((pdd = DrawDibLock(hdd)) == NULL) return FALSE;
DrawDibFree(pdd, FALSE, FALSE);
return TRUE; }
/**************************************************************************
* @doc EXTERNAL DrawDib * * @api BOOL | DrawDibTime | Returns timing information about * the drawing during debug operation. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @parm LPDRAWDIBTIME | lpddtime | Specifies a pointer to * a <t DRAWDIBTIME> structure. * * @rdesc Returns TRUE if successful. * **************************************************************************/ BOOL VFWAPI DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime) { #ifdef DEBUG_RETAIL
PDD pdd;
if ((pdd = DrawDibLock(hdd)) == NULL) return FALSE;
if (lpddtime) *lpddtime = pdd->ddtime;
if (pdd->ddtime.timeCount > 0) { RPF(("timeCount: %u", (UINT)pdd->ddtime.timeCount)); RPF(("timeDraw: %ums (%u)", (UINT)pdd->ddtime.timeDraw, (UINT)pdd->ddtime.timeDraw/(UINT)pdd->ddtime.timeCount)); RPF(("timeDecompress: %ums (%u)", (UINT)pdd->ddtime.timeDecompress, (UINT)pdd->ddtime.timeDecompress/(UINT)pdd->ddtime.timeCount)); RPF(("timeDither: %ums (%u)", (UINT)pdd->ddtime.timeDither, (UINT)pdd->ddtime.timeDither/(UINT)pdd->ddtime.timeCount)); RPF(("timeStretch: %ums (%u)", (UINT)pdd->ddtime.timeStretch, (UINT)pdd->ddtime.timeStretch/(UINT)pdd->ddtime.timeCount)); RPF(("timeSetDIBits: %ums (%u)", (UINT)pdd->ddtime.timeSetDIBits, (UINT)pdd->ddtime.timeSetDIBits/(UINT)pdd->ddtime.timeCount)); RPF(("timeBlt: %ums (%u)", (UINT)pdd->ddtime.timeBlt, (UINT)pdd->ddtime.timeBlt/(UINT)pdd->ddtime.timeCount)); }
pdd->ddtime.timeCount = 0; pdd->ddtime.timeDraw = 0; pdd->ddtime.timeDecompress = 0; pdd->ddtime.timeDither = 0; pdd->ddtime.timeStretch = 0; pdd->ddtime.timeSetDIBits = 0; pdd->ddtime.timeBlt = 0;
return TRUE; #else
return FALSE; #endif
}
/*
* CopyPal -- copy a palette */ HPALETTE CopyPal(HPALETTE hpal) { NPLOGPALETTE pLogPal = NULL; HPALETTE hpalNew = NULL; int iSizePalette = 0; // size of entire palette
if (hpal == NULL) return NULL;
GetObject(hpal,sizeof(iSizePalette),(LPSTR)&iSizePalette);
pLogPal = (NPLOGPALETTE)LocalAlloc(LPTR, sizeof(LOGPALETTE) + iSizePalette * sizeof(PALETTEENTRY));
if (!pLogPal) return NULL;
pLogPal->palVersion = 0x300; pLogPal->palNumEntries = iSizePalette;
GetPaletteEntries(hpal, 0, iSizePalette, pLogPal->palPalEntry);
hpal = CreatePalette(pLogPal);
LocalFree((HLOCAL) pLogPal);
return hpal; }
/**************************************************************************
* @doc EXTERNAL DrawDib * * @api HPALETTE | DrawDibGetPalette | This function obtains the palette * used by a DrawDib context. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @rdesc Returns a handle for the palette if successful, otherwise * it returns NULL. * * @comm Use <f DrawDibRealize> instead of this function * to realize the correct palette in response to a window * message. You should rarely need to call this function. * * Applications do not have exclusive use of the palette * obtained with this function. Applications should not * free the palette or assign it to a display context * with functions such as <f SelectPalette>. Applications * should also anticipate that some other * application can invalidate the handle. The palette * handle might also become invalid after the next use of a DrawDib function. * * This function returns a valid handle only after * <f DrawDibBegin> has been used without pairing it with * <f DrawDibEnd>, or if <f DrawDibDraw> has been used. * * @xref <f DrawDibSetPalette> <f DrawDibRealize> * **************************************************************************/ HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd) { PDD pdd;
if ((pdd = DrawDibLock(hdd)) == NULL) return NULL;
if (pdd->hpalDraw) return pdd->hpalDraw; else { // For palette animation we can't return a different palette than the
// real palette, so return hpal, not hpalCopy.
// Just trust me. - Toddla
if (pdd->ulFlags & DDF_ANIMATE) return pdd->hpal;
// In order for us to play direct to screen, etc, all palette
// realization has to come through DrawDibRealize. But that won't
// always happen. Some apps will always ask us for our palette and
// realize it themselves. So if we give them a copy of our palette,
// and never our true palette, when our play code realizes the true
// palette it's guarenteed to cause an actual palette change and we'll
// correctly detect playing to screen. (BUG 1761)
if (pdd->hpalCopy == NULL) pdd->hpalCopy = CopyPal(pdd->hpal);
return pdd->hpalCopy; } }
/**************************************************************************
* @doc EXTERNAL DrawDib * * @api BOOL | DrawDibSetPalette | This function sets the palette * used for drawing device independent bitmaps. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @parm HPALETTE | hpal | Specifies a handle to the palette. * Specify NULL to use the default palette. * * @rdesc Returns TRUE if successful. * * @comm Use this function when the application needs to realize an * alternate palette. The function forces the DrawDib context to use the * specified palette, possibly at the expense of image quality. * * Do not free a palette assigned to a DrawDib context until * either a new palette replaces it (for example, if hpal1 is the * current palette, replacing it with DrawDibSetPalette(hdd, hpal2)), * or until the palette handle for the DrawDib context is set to * to the default palette (for example, DrawDibSetPalette(hdd, NULL)). * * @xref <f DrawDibGetPalette> * **************************************************************************/ BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal) { PDD pdd; int i;
if ((pdd = DrawDibLock(hdd)) == NULL) return FALSE;
if (hpal == pdd->hpalCopy) hpal = NULL;
if (pdd->hpalDraw != hpal) pdd->ulFlags |= DDF_NEWPALETTE;
pdd->hpalDraw = hpal; // always set this variable
if (pdd->hpal == NULL) // no palette to dink with
return TRUE;
if (pdd->biDraw.biBitCount > 8) // make sure we are drawing palettized
return TRUE;
if (pdd->ulFlags & DDF_ANIMATE) { DPF(("DrawDibSetPalette called while in DDF_ANIMATE mode!")); }
//
// we are now using PAL colors...
//
pdd->uiPalUse = DIB_PAL_COLORS;
if (pdd->hpalDraw != NULL) { /* Set up table for BI_PAL_COLORS non 1:1 drawing */
//
// map all of our colors onto the given palette
// NOTE we can't use the select background trick
// because the given palette <hpalDraw> may have
// PC_RESERVED entries in it.
//
// SendSetPalette(pdd);
for (i=0; i < 256; i++) { if (pdd->biBuffer.biBitCount == 8) { pdd->aw[i] = GetNearestPaletteIndex(pdd->hpalDraw, RGB(pdd->argbq[i].rgbRed, pdd->argbq[i].rgbGreen, pdd->argbq[i].rgbBlue)); } else { PALETTEENTRY pe; GetPaletteEntries(pdd->hpal, i, 1, &pe); pdd->aw[i] = GetNearestPaletteIndex(pdd->hpalDraw, RGB(pe.peRed, pe.peGreen, pe.peBlue)); } }
for (; i<256; i++) pdd->aw[i] = 0; } else { /* Set up table for BI_PAL_COLORS 1:1 drawing */
// SendSetPalette(pdd);
for (i=0; i<(int)pdd->ClrUsed; i++) pdd->aw[i] = i;
for (; i<256; i++) pdd->aw[i] = 0; }
return TRUE; }
/**************************************************************************
* @doc EXTERNAL DrawDib * * @api BOOL | DrawDibChangePalette | This function sets the palette entries * used for drawing device independent bitmaps. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @parm int | iStart | Specifies the starting palette entry number. * * @parm int | iLen | Specifies the number of palette entries. * * @parm LPPALETTEENTRY | lppe | Specifies a pointer to an * array of palette entries. * * @rdesc Returns TRUE if successful. * * @comm * Use this function when the DIB color table changes and * other parameters stay constant. This function changes * the physical palette only if the current * DrawDib palette is curently realized by calling <f DrawDibRealize>. * * The DIB color table must be changed by the user or * the next use of <f DrawDibDraw> without the DDF_SAME_DRAW flag * implicity calls <f DrawDibBegin>. * * If the DDF_ANIMATE flag is not set in the previous call to * <f DrawDibBegin> or <f DrawDibDraw>, this function will * animate the palette. In this case, update the DIB color * table from the palette specified by <p lppe> and use * <f DrawDibRealize> to realize the updated palette. Redraw * the image to see the updated colors. *
* @xref <f DrawDibSetPalette> <f DrawDibRealize> * **************************************************************************/ BOOL VFWAPI DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe) { PDD pdd; int i;
int iStartSave; int iLenSave; LPPALETTEENTRY lppeSave;
if ((pdd = DrawDibLock(hdd)) == NULL) return FALSE;
if (pdd->biBuffer.biBitCount != 8) return FALSE;
if (lppe == NULL || iStart < 0 || iLen + iStart > 256) return FALSE;
for (i=0; i<iLen; i++) { (*(pdd->lpargbqIn))[iStart+i].rgbRed = lppe[i].peRed; (*(pdd->lpargbqIn))[iStart+i].rgbGreen = lppe[i].peGreen; (*(pdd->lpargbqIn))[iStart+i].rgbBlue = lppe[i].peBlue; }
//
// handle a palette change for 8bit dither
//
if (pdd->lpDitherTable) { for (i=0; i<iLen; i++) { pdd->argbq[iStart+i].rgbRed = lppe[i].peRed; pdd->argbq[iStart+i].rgbGreen = lppe[i].peGreen; pdd->argbq[iStart+i].rgbBlue = lppe[i].peBlue; }
pdd->lpDitherTable = DitherInit(pdd->lpbi, &pdd->biDraw, &pdd->DitherProc, pdd->lpDitherTable); } else if (pdd->hpalDraw) { SetPaletteEntries(pdd->hpal, iStart, iLen, lppe); pdd->ulFlags |= DDF_NEWPALETTE;
for (i=iStart; i<iLen; i++) { pdd->aw[i] = GetNearestPaletteIndex(pdd->hpalDraw, RGB(lppe[i].peRed,lppe[i].peGreen,lppe[i].peBlue)); } } else if (pdd->ulFlags & DDF_ANIMATE) { for (i=iStart; i<iStart+iLen; i++) { if (i >= pdd->iAnimateStart && i < pdd->iAnimateEnd) lppe[i-iStart].peFlags = PC_RESERVED; else lppe[i-iStart].peFlags = 0; }
/* Change iLen, iStart so that they only include the colors
** we can actually animate. If we don't do this, the ** AnimatePalette() call just returns without doing anything. */
iStartSave = iStart; iLenSave = iLen; lppeSave = lppe;
if (iStart < pdd->iAnimateStart) { iLen -= (pdd->iAnimateStart - iStart); lppe += (pdd->iAnimateStart - iStart); iStart = pdd->iAnimateStart; }
if (iStart + iLen > pdd->iAnimateEnd) iLen = pdd->iAnimateEnd - iStart;
AnimatePalette(pdd->hpal, iStart, iLen, lppe);
//
// any colors we could not animate, map to nearest
//
for (i=iStartSave; i<iStartSave+iLenSave; i++) { if (i >= pdd->iAnimateStart && i < pdd->iAnimateEnd) pdd->aw[i] = i; else pdd->aw[i] = GetNearestPaletteIndex(pdd->hpal, RGB(lppeSave[i-iStartSave].peRed, lppeSave[i-iStartSave].peGreen, lppeSave[i-iStartSave].peBlue)); } } else if (pdd->hpal) { SetPaletteEntries(pdd->hpal, iStart, iLen, lppe); pdd->ulFlags |= DDF_NEWPALETTE; } else { for (i=0; i<iLen; i++) { ((RGBQUAD *)pdd->aw)[iStart+i].rgbRed = lppe[i].peRed; ((RGBQUAD *)pdd->aw)[iStart+i].rgbGreen = lppe[i].peGreen; ((RGBQUAD *)pdd->aw)[iStart+i].rgbBlue = lppe[i].peBlue; }
if (pdd->hbmDraw) pdd->ulFlags |= DDF_NEWPALETTE; }
#ifdef DIBSECTION
if (pdd->lpDIBSection) {
// the colour table of a DIB Section is not changed when the palette
// used to create it changes. We need to explicitly change it.
SetDIBColorTable(pdd->hdcDraw, iStart, iLen, &(*(pdd->lpargbqIn))[iStart]); } #endif
// We'll break buggy apps if we delete a palette we've given them
// even though we told them not to use it.
//
// if (pdd->hpalCopy)
// DeleteObject(pdd->hpalCopy);
// pdd->hpalCopy = NULL;
return TRUE; }
/**************************************************************************
* * @doc EXTERNAL DrawDib * * @api UINT | DrawDibRealize | This function realizes palette * of the display context specified into the DrawDib context. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @parm HDC | hdc | Specifies a handle to the display context containing * the palette. * * @parm BOOL | fBackground | If set to a nonzero value, * the selected palette is selected as a background palette. * If this is set to zero and the device context is attached * to a window, the logical palette is a foreground palette when * the window has the input focus. (The device context is attached * to a window if it was obtained by using the <f GetDC> function * or if the window-class style is CS_OWNDC.) * * @rdesc Returns number of entries in the logical palette * mapped to different values in the system palette. If * an error occurs or no colors were updated, it returns zero. * * @comm This function should only be used to * handle a <m WM_PALETTECHANGE> or <m WM_QUERYNEWPALETTE> * message, or used in conjunction with the DDF_SAME_HDC flag * to prepare a display context prior to calling <f DrawDibDraw> * multiple times. * * @ex The following example shows how the function is used to * handle a <m WM_PALETTECHANGE> or <m WM_QUERYNEWPALETTE> * message: | * * case WM_PALETTECHANGE: * if ((HWND)wParam == hwnd) * break; * * case WM_QUERYNEWPALETTE: * hdc = GetDC(hwnd); * * f = DrawDibRealize(hdd, hdc, FALSE) > 0; * * ReleaseDC(hwnd, hdc); * * if (f) * InvalidateRect(hwnd, NULL, TRUE); * break; * * @ex The following example shows using <f DrawDibRealize> prior to * calling <f DrawDibDraw> multiple times: | * * hdc = GetDC(hwnd); * DrawDibRealize(hdd, hdc, fBackground); * DrawDibDraw(hdd, hdc, ..........., DDF_SAME_DRAW|DDF_SAME_HDC); * DrawDibDraw(hdd, hdc, ..........., DDF_SAME_DRAW|DDF_SAME_HDC); * DrawDibDraw(hdd, hdc, ..........., DDF_SAME_DRAW|DDF_SAME_HDC); * ReleaseDC(hwnd, hdc); * * @ex The following example shows using <f DrawDibRealize> with <f DDF_ANIMATE> * and (f DrawDibChangePalette> to do palette animation | * * hdc = GetDC(hwnd); * DrawDibBegin(hdd, ....., DDF_ANIMATE); * DrawDibRealize(hdd, hdc, fBackground); * DrawDibDraw(hdd, hdc, ...., DDF_SAME_DRAW|DDF_SAME_HDC); * DrawDibChangePalette(hdd, ....); * ReleaseDC(hwnd, hdc); * * @comm To draw an image mapped to another palette use <f DrawDibSetPalette>. * * To make <f DrawDibDraw> select its palette as a background palette * use the DDF_BACKGROUNDPAL flag and not this function. * * While the DrawDib palette is selected into the display context, * do not call <f DrawDibEnd>, <f DrawDibClose>, <f DrawDibBegin>, or * <f DrawDibDraw> (with a different draw/format) on the same DrawDib * context <p hdd>. These can free the selected palette * while it is being used by your display context and cause * a GDI error. * * <f DrawDibRealize> will return 0 if called before a * <f DrawDibBegin> or <f DrawDibDraw> * * @xref <f SelectPalette> * **************************************************************************/ UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground) { PDD pdd; HPALETTE hpal; UINT u;
if (hdc == NULL) return 0;
if ((pdd = DrawDibLock(hdd)) == NULL) return 0;
if (IsScreenDC(hdc)) pdd->ulFlags &= ~DDF_MEMORYDC; else pdd->ulFlags |= DDF_MEMORYDC;
if (pdd->ulFlags & DDF_MEMORYDC) DPF(("Drawing to a memory DC"));
SetStretchBltMode(hdc, COLORONCOLOR);
//
// what palette should we realize
//
hpal = pdd->hpalDraw ? pdd->hpalDraw : pdd->hpal;
//
// if we dont have a palette, we have nothing to realize
// still call DrawDibPalChange though
//
if (hpal == NULL) { if (pdd->ulFlags & DDF_NEWPALETTE) { DrawDibPalChange(pdd, hdc, hpal); pdd->ulFlags &= ~DDF_NEWPALETTE; }
return 0; }
// !!! There is a bug in GDI that will not map an identity palette 1-1 into
// !!! the system palette every time, which hoses us and makes it look like
// !!! dog spew. This ICKITY-ACKITY-OOP code will flush the palette and
// !!! prevent the bug... BUT it introduces another bug where if we are a
// !!! background app, we hose everybody else's palette but ours. So let's
// !!! live with the GDI bug. One other thing... attempting this fix will
// !!! cause the bug to repro more often than it would have if you had left
// !!! it alone, unless you do the fix JUST RIGHT! I don't trust myself
// !!! that much.
#if 0
if ((pdd->ulFlags & DDF_NEWPALETTE) && (pdd->ulFlags & DDF_IDENTITYPAL) && !fBackground) { //
// this will flush the palette clean to avoid a GDI BUG!!!
//
SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC); SetSystemPaletteUse(hdc, SYSPAL_STATIC); } #endif
//
// select and realize it
//
SelectPalette(hdc, hpal, fBackground); u = RealizePalette(hdc);
// !!! If two DrawDib instances share the same palette handle, the second
// one will not change any colours and u will be 0, and it will not stop
// decompressing to screen or recompute stuff for bitmaps when it goes
// into the background and it will get a messed up palette.
// !!! This is a known bug we don't care about
//
// this should be fixed by the hpalCopy stuff.
if (u > 0 || (pdd->ulFlags & DDF_NEWPALETTE)) { pdd->ulFlags |= DDF_NEWPALETTE; DrawDibPalChange(pdd, hdc, hpal); pdd->ulFlags &= ~DDF_NEWPALETTE; }
return u; }
/**************************************************************************
* @doc EXTERNAL DrawDib VFW11 * * @api LPVOID | DrawDibGetBuffer | This function returns the pointer * to the DrawDib decompress buffer. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @parm LPBITMAPINFOHEADER | lpbi | Specifies a pointer to a * <t BITMAPINFOHEADER> structure. * * @parm DWORD | dwSize | Specifies the size of the buffer pointed to by <p lpbi> * * @parm DWORD | dwFlags | Set to zero. * * @rdesc Returns a pointer to the buffer used by DrawDib for decompression, * or NULL if no buffer is used. If <p lpbi> is not NULL, * it is filled in with a copy of the <t BITMAPINFOHEADER> * describing the buffer. * * The structure for <p lpbi> must have room for a * <t BITMAPINFOHEADER> and 256 colors. * **************************************************************************/
LPVOID VFWAPI DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags) { PDD pdd;
if ((pdd = DrawDibLock(hdd)) == NULL) return NULL;
if (lpbi) { hmemcpy(lpbi, &pdd->biBuffer, min(dwSize, pdd->biBuffer.biSize + 256*sizeof(RGBQUAD))); }
return pdd->pbBuffer; }
LPVOID VFWAPI DrawDibGetBufferOld(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi) { return DrawDibGetBuffer(hdd, lpbi, sizeof(BITMAPINFOHEADER), 0); }
/**************************************************************************
* @doc EXTERNAL DrawDibStart * * @api BOOL | DrawDibStart | This function prepares a DrawDib * context for streaming playback. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @parm LONG | rate | Specifies the playback rate (in microseconds per frame). * * @rdesc Returns TRUE if successful. * * @xref <f DrawDibStop> * **************************************************************************/ BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) { PDD pdd;
if ((pdd = DrawDibLock(hdd)) == NULL) return FALSE;
if (pdd->hic == (HIC)-1) return FALSE;
// if the codec does not care about this message dont fail.
if (pdd->hic != NULL) ICSendMessage(pdd->hic, ICM_DRAW_START, rate, 0);
return TRUE; }
/**************************************************************************
* @doc EXTERNAL DrawDibStop * * @api BOOL | DrawDibStop | This function frees the resources * used by a DrawDib context for streaming playback. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @rdesc Returns TRUE if successful. * * @xref <f DrawDibStart> * **************************************************************************/ BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) { PDD pdd;
if ((pdd = DrawDibLock(hdd)) == NULL) return FALSE;
if (pdd->hic == (HIC)-1) return FALSE;
if (pdd->hic != NULL) ICSendMessage(pdd->hic, ICM_DRAW_STOP, 0, 0);
return TRUE; }
/**************************************************************************
* @doc EXTERNAL DrawDib * * @api BOOL | DrawDibUpdate | This macro updates the last * buffered frame drawn. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @parm HDC | hdc | Specifies a handle to the display context. * * @parm int | xDst | Specifies the x-coordinate of the upper left-corner * of the destination rectangle. Coordinates are specified * in MM_TEXT client coordinates. * * @parm int | yDst | Specifies the y-coordinate of the upper-left corner * of the destination rectangle. Coordinates are specified * in MM_TEXT client coordinates. * * @rdesc Returns TRUE if successful. * * @comm This macro uses <f DrawDibDraw> to send the DDF_UPDATE flag * to the DrawDib context. * **************************************************************************/
/**************************************************************************
* @doc EXTERNAL DrawDib * * @api BOOL | DrawDibDraw | This function draws a device independent * bitmap to the screen. * * @parm HDRAWDIB | hdd | Specifies a handle to a DrawDib context. * * @parm HDC | hdc | Specifies a handle to the display context. * * @parm int | xDst | Specifies the x-coordinate of the upper left-corner * of the destination rectangle. Coordinates are specified * in MM_TEXT client coordinates. * * @parm int | yDst | Specifies the y-coordinate of the upper-left corner * of the destination rectangle. Coordinates are specified * in MM_TEXT client coordinates. * * @parm int | dxDst | Specifies the width of the destination rectangle. * The width is specified in MM_TEXT client coordinates. If * <p dxDst> is -1, the width of the bitmap is used. * * @parm int | dyDst | Specifies the height of the destination rectangle. * The height is specified in MM_TEXT client coordinates. If * <p dyDst> is -1, the height of the bitmap is used. * * @parm LPBITMAPINFOHEADER | lpbi | Specifies a pointer to the * <t BITMAPINFOHEADER> structure for the bitmap. The color * table for the DIB follows the format information. The * height specified for the DIB in the structure must be * positive (that is, this function will not draw inverted DIBs). * * @parm LPVOID | lpBits | Specifies a pointer to the buffer * containing the bitmap bits. * * @parm int | xSrc | Specifies the x-coordinate of the upper-left corner * source rectangle. Coordinates are specified in pixels. * The coordinates (0,0) represent the upper left corner * of the bitmap. * * @parm int | ySrc | Specifies the y-coordinate of the upper left corner * source rectangle. Coordinates are specified in pixels. * The coordinates (0,0) represent the upper left corner * of the bitmap. * * @parm int | dxSrc | Specifies the width of the source rectangle. * The width is specified in pixels. * * @parm int | dySrc | Specifies the height of the source rectangle. * The height is specified in pixels. * * @parm UINT | wFlags | Specifies any applicable flags for drawing. * The following flags are defined: * * @flag DDF_UPDATE | Indicates the last buffered bitmap is to be redrawn. * If drawing fails with this flag, a buffered image is not available * and a new image needs to be specified before the display is updated. * * @flag DDF_SAME_HDC | Assumes the display context has been prepared with * <f DrawDibRealize> prior to this call and <f DrawDibDraw> should not * initialize it. * * @flag DDF_SAME_DRAW | Uses the drawing parameters previously * specified for this function. Use this flag only * if <p lpbi>, <p dxDst>, <p dyDst>, <p dxSrc>, and <p dySrc> * have not changed since using <f DrawDibDraw> or <f DrawDibBegin>. * Normally <f DrawDibDraw> checks the parameters, and if they * have changed, <f DrawDibBegin> prepares the DrawDib context * for drawing. * * @flag DDF_DONTDRAW | Indicates the frame is not to be drawn and will * later be recalled with the <f DDF_UPDATE> flag. DrawDib does * not buffer an image if an offscreen buffer does not exist. * In this case, DDF_DONTDRAW draws the frame to the screen and * the subsequent use of DDF_UPDATE fails. DrawDib does * guarantee that the following will * always draw "image" B to the screen. * * DrawDibDraw(hdd, ..., lpbiA, ..., DDF_DONTDRAW); * * DrawDibDraw(hdd, ..., lpbiB, ..., DDF_DONTDRAW); * * DrawDibDraw(hdd, ..., NULL, ..., DDF_UPDATE); * * The DDF_UPDATE and DDF_DONTDRAW flags are used * together to create composite images * offscreen, and then do a final update when finished. * * @flag DDF_HURRYUP | Indicates the data does not have to * drawn (that is, it can be dropped) and the DDF_UPDATE flags will * not be used to recall this information. DrawDib looks at * this data only if it is required to build the next frame, otherwise * the data is ignored. * * This flag is usually used to resynchronize video and audio. When * resynchronizing data, applications should send the image * with this flag in case the driver needs to * to buffer the frame to decompress subsequent frames. * * @flag DDF_UPDATE | Indicates the last buffered bitmap is to be redrawn. * If drawing fails with this flag, a buffered image is not available * and a new image needs to be specified before the display is updated. * For more information, see the <f DDF_DONTDRAW> flag. * * @flag DDF_BACKGROUNDPAL | Realizes the palette used for drawing * in the background leaving the actual palette used for display * unchanged. (This flag is valid only if DDF_SAME_HDC is not set.) * * @flag DDF_HALFTONE | Always dithers the DIB to a standard palette * regardless of the palette of the DIB. If using <f DrawDibBegin>, * set this flag for it rather than <f DrawDibDraw>. * * @flag DDF_NOTKEYFRAME | Indicates the DIB data is not a key frame. * * @flag DDF_HURRYUP | Indicates the DIB data does not have to * drawn (that is, it can be dropped). This flag is usually * used to resynchronize the video to the audio. When * resynchronizing data, applications should send the image * with this flag in case the driver needs to * to buffer the frame to decompress subsequent frames. * * @rdesc Returns TRUE if successful. * * @comm This function replaces <f StretchDIBits> and supports * decompression of bitmaps by installable compressors. * This function dithers true color bitmaps properly on * 8-bit display devices. * **************************************************************************/
BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd, HDC hdc, int xDst, int yDst, int dxDst, int dyDst, LPBITMAPINFOHEADER lpbi, LPVOID lpBits, int xSrc, int ySrc, int dxSrc, int dySrc, UINT wFlags) { PDD pdd; BOOL f; RECT rc; DWORD icFlags; DWORD dw;
if ((pdd = DrawDibLock(hdd)) == NULL) return FALSE;
if (hdc == NULL) return FALSE;
if (wFlags & DDF_UPDATE) { lpbi = pdd->lpbi;
dxDst = pdd->dxDst; dyDst = pdd->dyDst; dxSrc = pdd->dxSrc; dySrc = pdd->dySrc; } else { if (lpbi == NULL) return FALSE;
//
// fill in defaults.
//
if (dxSrc < 0) dxSrc = (int)lpbi->biWidth - xSrc;
if (dySrc < 0) dySrc = (int)lpbi->biHeight - ySrc;
if (dxDst < 0) dxDst = dxSrc;
if (dyDst < 0) dyDst = dySrc; } #ifdef DEBUG_RETAIL
if (xSrc < 0 || ySrc < 0 || dxSrc <= 0 || dySrc <= 0 || xSrc + dxSrc > (int)lpbi->biWidth || ySrc + dySrc > (int)lpbi->biHeight) { RPF(("DrawDibBegin(): bad source parameters [%d %d %d %d]", xSrc, ySrc, dxSrc, dySrc)); // return 0; // see what happens.
} #endif
if (dxSrc == 0 || dySrc == 0) // !!! || dxDst == 0 || dyDst == 0)
return FALSE;
//
// check and make sure the params of the draw has not changed
//
if (!(wFlags & (DDF_SAME_DRAW|DDF_UPDATE)) && !(DibEq(pdd->lpbi, lpbi) && !(((UINT)pdd->ulFlags ^ wFlags) & DDF_HALFTONE) && pdd->dxDst == dxDst && pdd->dyDst == dyDst && pdd->dxSrc == dxSrc && pdd->dySrc == dySrc)) { wFlags &= ~(DDF_UPDATE | DDF_FULLSCREEN); if (!DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, wFlags)) return FALSE; }
TIMEINC(); // should we include DibEq?
TIMESTART(timeDraw);
// convert to DIB cordinates
ySrc = (int)pdd->lpbi->biHeight - (ySrc + dySrc);
//
// Initialize the DC: We need to realize the palette if we are not
// guarenteed to be using the same DC as before, if we've been told we
// have a new palette, or if we are mapping to somebody else's palette.
// The owner of the palette could be changing it on us all the time or
// doing who knows what, so to be safe we will realize it every frame.
// If nothing's changed, this should be a really cheap operation, and
// it doesn't appear to be causing any palette fights that end in somebody
// getting hurt. This is required for Magic School Bus, and PageMaster,
// at the very least. (WIN95B 12204 and 9637)
//
if (!(wFlags & DDF_SAME_HDC) || (pdd->ulFlags & DDF_NEWPALETTE) || pdd->hpalDraw) { //
// image will be totally clipped anyway
//
if (GetClipBox(hdc, &rc) == NULLREGION) { wFlags |= DDF_DONTDRAW; }
//
// select and realize the palette.
//
// NOTE you must unselect this thing, dont return early
//
DrawDibRealize(hdd, hdc, (wFlags & DDF_BACKGROUNDPAL) != 0); }
#ifndef WIN32
//
// do a clipping check
//
if (pdd->ulFlags & DDF_CLIPCHECK) { RECT rc;
if (!(pdd->ulFlags & DDF_CLIPPED) && (pdd->iDecompress == DECOMPRESS_SCREEN) && // (pdd->ulFlags & DDF_SCREENX) &&
(wFlags & (DDF_PREROLL|DDF_DONTDRAW))) { DPF(("DDF_DONTDRAW while decompressing to screen, staying clipped")); }
if ((pdd->ulFlags & DDF_MEMORYDC) || GetClipBox(hdc, &rc) != SIMPLEREGION || xDst < rc.left || yDst < rc.top || xDst + dxDst > rc.right || yDst + dyDst > rc.bottom || (wFlags & (DDF_PREROLL|DDF_DONTDRAW)) || (gfDisplayHasBrokenRasters && (DCNotAligned(hdc, xDst) || gwScreenBitDepth == 24))) // Note: if we're on a 24-bit display with broken rasters, we don't
// decompress to the screen even if the rectangle is aligned,
// because it's just too easy for somebody to try to write out
// a whole pixel in one gulp and hit the 64K boundary.
{ //
// we are clipped, check for a change.
//
if (!(pdd->ulFlags & DDF_CLIPPED)) { pdd->ulFlags |= DDF_CLIPPED; DrawDibClipChange(pdd, wFlags); } } else { //
// we are now unclipped, check for a change
//
if (pdd->ulFlags & DDF_CLIPPED) { #ifdef DEBUG
if (DCNotAligned(hdc, xDst)) DPF(("Warning draw is not aligned on 4 pixel boundry")); #endif
pdd->ulFlags &= ~DDF_CLIPPED; DrawDibClipChange(pdd, wFlags); } } }
#endif //WIN32
if (pdd->ulFlags & DDF_WANTKEY) { //
// Adobe hack: If the DDF_UPDATE flag is on in our internal
// flags, that means we've just been getting a bunch of frames
// with the DONTDRAW flag set. In that case, if this frame
// immediately after those frames is marked as a key frame
// we assume that it might not be a key frame and refrain from
// switching immediately to decompressing to screen.
//
if (!(wFlags & DDF_NOTKEYFRAME) && !(pdd->ulFlags & DDF_UPDATE)) { pdd->ulFlags &= ~DDF_WANTKEY; DrawDibClipChange(pdd, wFlags); } }
//
// if update is set re-draw what ever we drew last time
//
if (wFlags & DDF_UPDATE) { if (pdd->hic == (HIC)-1 || (pdd->ulFlags & DDF_DIRTY)) { f = FALSE; goto exit; }
if (pdd->hic) { if (pdd->ulFlags & DDF_UPDATE) { goto redraw; }
lpbi = &pdd->biBuffer; lpBits = pdd->pbBuffer;
//!!! set the source right.
if ((pdd->ulFlags & DDF_XLATSOURCE)) { dxSrc = MulDiv(dxSrc, abs((int)pdd->biBuffer.biWidth), (int)pdd->lpbi->biWidth); dySrc = MulDiv(dySrc, abs((int)pdd->biBuffer.biHeight), (int)pdd->lpbi->biHeight); xSrc = MulDiv(xSrc, abs((int)pdd->biBuffer.biWidth), (int)pdd->lpbi->biWidth); ySrc = MulDiv(ySrc, abs((int)pdd->biBuffer.biHeight), (int)pdd->lpbi->biHeight); } }
if (pdd->ulFlags & DDF_STRETCH) { lpbi = &pdd->biStretch; lpBits = pdd->pbStretch; dxSrc = dxDst; dySrc = dyDst; xSrc = 0; ySrc = 0; }
if (pdd->ulFlags & DDF_DITHER) { lpBits = pdd->pbDither; xSrc = 0; ySrc = 0; }
if (pdd->lpDIBSection != NULL) goto bltDIB;
if (pdd->hbmDraw && (pdd->ulFlags & DDF_BITMAP)) goto bltit;
if (lpBits == NULL) { f = FALSE; // no buffer, can't update....
goto exit; }
goto drawit; }
//
// default for bits pointerdefault
//
if (lpBits == NULL) lpBits = (LPBYTE)lpbi+(int)lpbi->biSize + (int)lpbi->biClrUsed * sizeof(RGBQUAD);
//
// call any decompressor if needed
//
if (pdd->hic) { if (pdd->hic == (HIC)-1) { f = FALSE; goto exit; }
#ifndef WIN32 // exclude all code that references biscreen
if (pdd->iDecompress == DECOMPRESS_SCREEN) // ulFlags & DDF_SCREENX
{ //
// we are decompressing to the screen not the buffer, so
// the buffer is dirty now
//
pdd->ulFlags |= DDF_DIRTY;
dw = GetDCOrg(hdc); xDst += LOWORD(dw); yDst += HIWORD(dw);
//
// if DCIBeginAccess fails we are in the background, and should
// not draw.
//
if (DCIBeginAccess(pdci, xDst, yDst, dxDst, dyDst) != 0) { DPF(("DCIBeginAccess failed!!!")); f = TRUE; //!!! is this right?
goto exit; }
//convert to DIB corrds.
yDst = (int)pdci->dwHeight - (yDst + dyDst);
TIMESTART(timeDecompress);
icFlags = 0;
if (wFlags & DDF_HURRYUP) icFlags |= ICDECOMPRESS_HURRYUP;
if (wFlags & DDF_NOTKEYFRAME) icFlags |= ICDECOMPRESS_NOTKEYFRAME;
dw = ICDecompressEx(pdd->hic, icFlags, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, &biScreen, lpScreen, xDst, yDst, dxDst, dyDst);
if (dw == ICERR_DONTDRAW) dw = ICERR_OK;
f = (dw == ICERR_OK);
TIMEEND(timeDecompress);
DCIEndAccess(pdci); goto exit; } else #endif // biscreen references
{ //
// if the offscreen buffer is dirty, only a key frame will
// clean our soul.
//
if (pdd->ulFlags & DDF_DIRTY) { if (wFlags & DDF_NOTKEYFRAME) { //!!! playing files with no key frames we will get into
//a state where we will never draw a frame ever again.
//we need a punt count?
DPF(("punt frame"));
f = TRUE; goto exit; } else // if (!(wFlags & DDF_HURRYUP))
{ pdd->ulFlags &= ~DDF_DIRTY; } }
TIMESTART(timeDecompress);
icFlags = 0;
if (wFlags & DDF_HURRYUP) icFlags |= ICDECOMPRESS_HURRYUP;
if (wFlags & DDF_NOTKEYFRAME) icFlags |= ICDECOMPRESS_NOTKEYFRAME;
if (pdd->iDecompress == DECOMPRESS_BITMAP) // ulFlags & DDF_BITMAPX
{ //!!! should we check FASTTEMPORALD?
if (pdd->ulFlags & DDF_HUGEBITMAP) { HugeToFlat(pdd->pbBitmap,pdd->biBitmap.biSizeImage,pdd->biBitmap.biYPelsPerMeter); }
dw = ICDecompress(pdd->hic, icFlags, lpbi, lpBits, &pdd->biBitmap, pdd->pbBitmap);
if (pdd->ulFlags & DDF_HUGEBITMAP) { FlatToHuge(pdd->pbBitmap,pdd->biBitmap.biSizeImage,pdd->biBitmap.biYPelsPerMeter); } } else { dw = ICDecompress(pdd->hic, icFlags, lpbi, lpBits, &pdd->biBuffer, pdd->pbBuffer); }
TIMEEND(timeDecompress);
if (dw == ICERR_DONTDRAW) { // Decompressor doesn't want us to draw, for some reason....
wFlags |= DDF_DONTDRAW; } else if (dw != 0) { f = FALSE; DPF(("Error %ld from decompressor!\n", dw)); goto exit; } }
//
// if don't draw is set we just need to decompress
//
if (wFlags & (DDF_DONTDRAW|DDF_HURRYUP)) { f = TRUE; pdd->ulFlags |= DDF_UPDATE|DDF_DONTDRAW; // make sure update knows what to do
goto exit; }
//
// draw RLE delta's to the screen even when we are buffering.
//
if (!(pdd->ulFlags & (DDF_DONTDRAW|DDF_STRETCH|DDF_DITHER|DDF_NAKED)) && lpbi->biCompression == BI_RLE8 && lpbi->biSizeImage != pdd->biBuffer.biSizeImage) { pdd->ulFlags |= DDF_UPDATE; // make sure update knows what to do
pdd->biDraw.biCompression = BI_RLE8; goto drawit; } redraw: pdd->ulFlags &= ~(DDF_UPDATE|DDF_DONTDRAW);
if ((pdd->ulFlags & DDF_XLATSOURCE)) { dxSrc = MulDiv(dxSrc, abs((int)pdd->biBuffer.biWidth), (int)pdd->lpbi->biWidth); dySrc = MulDiv(dySrc, abs((int)pdd->biBuffer.biHeight), (int)pdd->lpbi->biHeight); xSrc = MulDiv(xSrc, abs((int)pdd->biBuffer.biWidth), (int)pdd->lpbi->biWidth); ySrc = MulDiv(ySrc, abs((int)pdd->biBuffer.biHeight), (int)pdd->lpbi->biHeight); }
lpbi = &pdd->biBuffer; lpBits = pdd->pbBuffer;
pdd->biDraw.biCompression = pdd->biBuffer.biCompression; } else { if (pdd->lpDIBSection && ((pdd->ulFlags & (DDF_STRETCH|DDF_DITHER)) == 0)) { // Include time taken here as 'stretching'.
// Really, though, we shouldn't be using DIB Sections in this case.
TIMESTART(timeStretch); if (lpbi->biCompression == BI_RGB) { lpbi->biSizeImage = DIBSIZEIMAGE(*lpbi); }
hmemcpy(pdd->lpDIBSection, lpBits, lpbi->biSizeImage); TIMEEND(timeStretch); }
//
// when directly drawing RLE data we cant hurry
//
if (pdd->lpbi->biCompression == BI_RLE8) wFlags &= ~DDF_HURRYUP;
//
// if don't draw is set we just need to stretch/dither
//
if (wFlags & DDF_HURRYUP) { f = TRUE; pdd->ulFlags |= DDF_DIRTY; goto exit; }
pdd->ulFlags &= ~DDF_DIRTY; pdd->biDraw.biCompression = lpbi->biCompression; }
if (pdd->biDraw.biCompression == BI_RGB && (pdd->ulFlags & (DDF_DITHER|DDF_STRETCH))) { if (pdd->ulFlags & DDF_STRETCH) { TIMESTART(timeStretch);
StretchDIB(&pdd->biStretch, pdd->pbStretch, 0, 0, dxDst, dyDst, lpbi,lpBits, xSrc,ySrc,dxSrc,dySrc);
TIMEEND(timeStretch);
lpbi = &pdd->biStretch; lpBits = pdd->pbStretch; dxSrc = dxDst; dySrc = dyDst; xSrc = 0; ySrc = 0; }
if (pdd->ulFlags & DDF_DITHER) { TIMESTART(timeDither);
pdd->DitherProc(&pdd->biDraw, pdd->pbDither,0,0,dxSrc,dySrc, lpbi,lpBits,xSrc, ySrc, pdd->lpDitherTable);
TIMEEND(timeDither);
lpBits = pdd->pbDither; xSrc = 0; ySrc = 0; }
if ((wFlags & DDF_DONTDRAW) && !pdd->hbmDraw) { f = TRUE; goto exit; } } else if (pdd->biDraw.biCompression == BI_RLE8) { /*
* if drawing RLE deltas on NT, the biSizeImage field needs to * accurately reflect the amount of RLE data present in lpBits. */ pdd->biDraw.biSizeImage = lpbi->biSizeImage; }
if (pdd->lpDIBSection != NULL) {
//ASSERT(pdd->hbmDraw != NULL);
if (wFlags & DDF_DONTDRAW) { f = TRUE; goto exit; }
bltDIB: TIMESTART(timeBlt);
// Put things back in right-side-up coordinates
ySrc = (int)pdd->biDraw.biHeight - (ySrc + dySrc); // ySrc = 0; // Was like this for Chicago M6!
f = StretchBlt(hdc,xDst,yDst,dxDst,dyDst,pdd->hdcDraw, xSrc,ySrc,dxSrc,dySrc,SRCCOPY) != 0;
TIMEEND(timeBlt);
} else if (pdd->hbmDraw) { //
// when MCIAVI is playing we need realize our palette for each
// draw operation because another app may have drawn a translated
// bitmap thus screwing up the GDI *global* device translate table.
// RonG I hate you some times
//
if (pdd->hpal && (wFlags & DDF_SAME_HDC)) { if (GetProfileInt(szDrawDib, "switchpalette", TRUE)) RealizePalette(hdc); }
if (pdd->iDecompress != DECOMPRESS_BITMAP) // !(pdd->ulFlags & DDF_BITMAPX)
{ TIMESTART(timeSetDIBits); #if USE_SETDI
pdd->sd.hdc = hdc; //!!!ack!
SetBitmap(&pdd->sd,xSrc,0,dxSrc,dySrc,lpBits,xSrc,ySrc,dxSrc,dySrc); pdd->sd.hdc = NULL; //!!!ack!
ySrc = 0; #else
SetDIBits(hdc, pdd->hbmDraw, 0, dySrc, lpBits, (LPBITMAPINFO)&pdd->biDraw, pdd->uiPalUse); #endif
TIMEEND(timeSetDIBits); }
if (wFlags & DDF_DONTDRAW) { f = TRUE; goto exit; } bltit: TIMESTART(timeBlt);
// Put things back in right-side-up coordinates
ySrc = (int)pdd->biDraw.biHeight - (ySrc + dySrc); // ySrc = 0;
f = StretchBlt(hdc,xDst,yDst,dxDst,dyDst,pdd->hdcDraw, xSrc,ySrc,dxSrc,dySrc,SRCCOPY) != 0;
TIMEEND(timeBlt); } else drawit: {
// Sometimes when you read an RLE file, you get RGB data back (ie. the
// first frame). Passing RGB data to a display driver who thinks it
// is getting RLE data will blow it up. If the RLE data is the exact
// size of RGB data, we decide that's just too much of a coincidence.
BOOL fNotReallyRLE = (pdd->biDraw.biCompression == BI_RLE8 && lpbi->biSizeImage == DIBWIDTHBYTES(*lpbi) * (DWORD)lpbi->biHeight);
// !!! We've been told not to draw, but I'm going to draw anyway, to fix bug
// WIN95C 14453. MCIAVI draws from a keyframe forward, saying DONTDRAW on
// every frame but the last. Works fine in theory, but in theory, communism
// works! Because of other bugs declared WONTFIX, Drawdib doesn't buffer the
// images as it goes along, so when it comes time to draw the result at the
// end, it goes "ACK! I have no idea what I was told to draw!". So the only
// safe way to fix it is to draw even though we were told not to. I feel safe
// doing this because this is the way VFW1.1 worked, and nobody has complained
// in over a year.
#if 0
if (wFlags & DDF_DONTDRAW) { f = TRUE; goto exit; } #endif
if (fNotReallyRLE) pdd->biDraw.biCompression = BI_RGB;
if (pdd->biDraw.biCompression == BI_RLE8) { /*
* if drawing RLE deltas on NT, the biSizeImage field needs to * accurately reflect the amount of RLE data present in lpBits. */ pdd->biDraw.biSizeImage = lpbi->biSizeImage; }
TIMESTART(timeBlt);
/*
* NT stretchdibits does not work with RLE deltas, even 1:1 * * also note use of pdd->uiPalUse: this is DIB_PAL_COLORS by * default, but may be set to DIB_PAL_INDICES if we detect that * the system palette is identical to ours, and thus * we can safely take this huge performance benefit (on NT, * DIB_PAL_INDICES nearly halves the cost of this call) */ if ((dxDst == dxSrc) && (dyDst == dySrc)) { f = SetDIBitsToDevice(hdc, xDst, yDst, dxDst, dyDst, xSrc, ySrc, 0, (UINT)pdd->biDraw.biHeight, lpBits, (LPBITMAPINFO)&pdd->biDraw, pdd->uiPalUse) != 0; } else { f = StretchDIBits(hdc,xDst,yDst,dxDst,dyDst, xSrc,ySrc,dxSrc,dySrc, lpBits, (LPBITMAPINFO)&pdd->biDraw, pdd->uiPalUse, SRCCOPY) != 0; }
TIMEEND(timeBlt); if (fNotReallyRLE) pdd->biDraw.biCompression = BI_RLE8; }
exit: if (!(wFlags & DDF_SAME_HDC) && pdd->hpal) SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), TRUE);
TIMEEND(timeDraw); return f; }
#if 0
/**************************************************************************
* @doc INTERNAL * * @api BOOL| InitDrawToScreen | init drawing to the screen via DCI * **************************************************************************/ static BOOL InitDrawToScreen(PDD pdd) { BOOL f;
if (!(pdd->ulFlags & DDF_CANDRAWX)) return FALSE;
f = !(pdd->ulFlags & DDF_CLIPPED);
if (f && !(pdd->ulFlags & DDF_DRAWX)) { DPF(("drawing to SCREEN now"));
pdd->ulFlags |= DDF_DRAWX; } else if (!f && (pdd->ulFlags & DDF_DRAWX)) { DPF(("not drawing to SCREEN anymore"));
pdd->ulFlags &= ~DDF_DRAWX; } } #endif
/**************************************************************************
* @doc INTERNAL * * @api BOOL| InitDecompress | init every thing for decompressing * to the screen or a bitmap or a memory buffer. * * we can decompress to the screen if the following is true: * * palette must be 1:1 * must be unclipped * **************************************************************************/ static BOOL InitDecompress(PDD pdd) { BOOL f; BOOL fBitmap; BOOL fScreen;
//
// nothing to init
//
if (!(pdd->ulFlags & (DDF_CANSCREENX|DDF_CANBITMAPX))) return TRUE;
//
// make sure we rebegin when the palette changes
//
if (pdd->ulFlags & (DDF_NEWPALETTE|DDF_WANTKEY)) pdd->iDecompress = 0;
//
// we need to decompress to either a memory bitmap or buffer.
//
fBitmap = (pdd->ulFlags & DDF_CANBITMAPX) && (pdd->ulFlags & (DDF_IDENTITYPAL|DDF_CANSETPAL));
fScreen = (pdd->ulFlags & DDF_CANSCREENX) && !(pdd->ulFlags & DDF_CLIPPED) && !(pdd->ulFlags & DDF_MEMORYDC) && (pdd->ulFlags & (DDF_IDENTITYPAL|DDF_CANSETPAL));
//
// should we be decompressing to the screen?
//
if (fScreen && pdd->iDecompress != DECOMPRESS_SCREEN) { if (pdd->ulFlags & DDF_IDENTITYPAL) { if (pdd->hpalDraw) ICDecompressSetPalette(pdd->hic, &pdd->biBuffer); else ICDecompressSetPalette(pdd->hic, NULL); } else { if (FixUpCodecPalette(pdd->hic, pdd->lpbi)) { DPF(("Codec notified of palette change....")); } else { DPF(("Codec failed palette change....")); pdd->iDecompress = 0; goto ack; } }
//
// now init the compressor for screen decompress.
//
f = ICDecompressExBegin(pdd->hic, 0, pdd->lpbi, NULL, 0, 0, pdd->dxSrc, pdd->dySrc, &biScreen, lpScreen, 0, 0, pdd->dxDst, pdd->dyDst) == ICERR_OK;
if (f) { pdd->ulFlags |= DDF_DIRTY; // buffer is dirty now?
RPF(("Decompressing to screen now")); pdd->iDecompress = DECOMPRESS_SCREEN; return TRUE; } else { ack: DPF(("Compressor failed decompress to SCREEN, so not decompressing to screen!!!!")); pdd->iDecompress = 0; pdd->ulFlags &= ~DDF_CANSCREENX; } } else if (fScreen) { //
// already decompressing to screen.
//
return TRUE; }
//
// should we decompress to a bitmap?
//
if (fBitmap && pdd->iDecompress != DECOMPRESS_BITMAP) { if (pdd->ulFlags & DDF_IDENTITYPAL) { if (pdd->hpalDraw) ICDecompressSetPalette(pdd->hic, &pdd->biBuffer); else ICDecompressSetPalette(pdd->hic, NULL); } else { if (FixUpCodecPalette(pdd->hic, pdd->lpbi)) { DPF(("Codec notified of palette change....")); } else { DPF(("Codec failed palette change....")); pdd->iDecompress = 0; goto ackack; } }
f = ICDecompressBegin(pdd->hic, pdd->lpbi, &pdd->biBitmap) == ICERR_OK;
if (f) { pdd->ulFlags |= DDF_DIRTY; // buffer is dirty now?
DPF(("decompressing to BITMAP now")); pdd->iDecompress = DECOMPRESS_BITMAP;
return TRUE; } else { ackack: DPF(("Unable to init decompress to bitmap")); pdd->iDecompress = 0; } } else if (fBitmap) { //
// already decompressing to bitmap
//
return TRUE; }
//
// should we decompress to a buffer?
//
if (pdd->iDecompress != DECOMPRESS_BUFFER) { DPF(("decompressing to DIB now"));
pdd->ulFlags |= DDF_DIRTY; // buffer is dirty now?
pdd->iDecompress = DECOMPRESS_BUFFER;
if (pdd->hpalDraw) ICDecompressSetPalette(pdd->hic, &pdd->biBuffer); else ICDecompressSetPalette(pdd->hic, NULL);
f = ICDecompressBegin(pdd->hic, pdd->lpbi, &pdd->biBuffer) == ICERR_OK;
if (!f) { DPF(("Unable to re-begin compressor")); } }
return TRUE; // nothing to change
}
/**************************************************************************
* @doc INTERNAL * * @api void | DrawDibClipChange | called when the clipping has changed * from clipped to totaly un-clipped or whatever. * **************************************************************************/ void DrawDibClipChange(PDD pdd, UINT wFlags) { if (!(pdd->ulFlags & DDF_NEWPALETTE)) { if (pdd->ulFlags & DDF_CLIPPED) DPF(("now clipped")); else DPF(("now un-clipped")); }
////InitDrawToScreen(pdd);
//
// dont change Decompressors on a non key frame, unless we have
// to (ie going clipped and decompressing to screen)
//
if (pdd->ulFlags & DDF_NEWPALETTE) { if (wFlags & DDF_NOTKEYFRAME) { if (pdd->iDecompress == DECOMPRESS_BUFFER) // !(pdd->ulFlags & DDF_SCREENX))
{ DPF(("waiting for a key frame to change (palette) decompressor")); pdd->ulFlags |= DDF_WANTKEY; return; } } } else { if (wFlags & DDF_NOTKEYFRAME) { if (pdd->iDecompress != DECOMPRESS_SCREEN) // !(pdd->ulFlags & DDF_SCREENX))
{ DPF(("waiting for a key frame to change (clipped) decompressor")); pdd->ulFlags |= DDF_WANTKEY; return; } } }
InitDecompress(pdd); pdd->ulFlags &= ~DDF_WANTKEY; }
/**************************************************************************
* @doc INTERNAL * * @api void | DrawDibPalChange | called when the physical palette mapping * has changed. * **************************************************************************/ void DrawDibPalChange(PDD pdd, HDC hdc, HPALETTE hpal) { #ifndef WIN32
#ifdef DEBUG
// extern BOOL FAR PASCAL IsDCCurrentPalette(HDC hdc);
// BOOL fForeground = IsDCCurrentPalette(hdc);
// if (fForeground)
// DPF(("Palette mapping has changed (foreground)..."));
// else
// DPF(("Palette mapping has changed (background)..."));
#endif
#endif
//
// if we are on a palette device we need to do some special stuff.
//
if (gwScreenBitDepth == 8 && (gwRasterCaps & RC_PALETTE)) { //
// get the logical->physical mapping
//
if (GetPhysDibPaletteMap(hdc, &pdd->biDraw, pdd->uiPalUse, pdd->ab)) pdd->ulFlags |= DDF_IDENTITYPAL; else pdd->ulFlags &= ~DDF_IDENTITYPAL;
if (pdd->ulFlags & DDF_IDENTITYPAL) DPF(("Palette mapping is 1:1")); else DPF(("Palette mapping is not 1:1"));
#ifdef WIN32 //!!!NT Only
if (pdd->ulFlags & DDF_IDENTITYPAL) pdd->uiPalUse = DIB_PAL_INDICES; else pdd->uiPalUse = DIB_PAL_COLORS; #endif
} else { //
// we are not on a palette device, some code checks DDF_IDENTITYPAL
// anyway so set it.
//
pdd->ulFlags |= DDF_IDENTITYPAL; }
if (pdd->hbmDraw && (pdd->ulFlags & DDF_BITMAP)) { //!!! we should pass pdd->ab to this function!
//!!! and use a naked translate.
SetBitmapColorChange(&pdd->sd, hdc, hpal); }
DrawDibClipChange(pdd, DDF_NOTKEYFRAME); }
/**************************************************************************
* @doc INTERNAL * * @api HPALETTE | CreateBIPalette | Create palette from bitmap. * * @parm LPBITMAPINFOHEADER | lpbi | Pointer to bitmap. * * @rdesc Returns handle to the palette, NULL if error. * **************************************************************************/ static HPALETTE CreateBIPalette(HPALETTE hpal, LPBITMAPINFOHEADER lpbi) { LPRGBQUAD prgb; int i;
// This structure is the same as LOGPALETTE EXCEPT for the array of
// palette entries which here is 256 long. The "template" in the
// SDK header files only has an array of size one, hence the "duplication".
struct { WORD palVersion; /* tomor - don't mess with word */ WORD palNumEntries; PALETTEENTRY palPalEntry[256]; } pal;
pal.palVersion = 0x300; pal.palNumEntries = (int)lpbi->biClrUsed;
if (pal.palNumEntries == 0 && lpbi->biBitCount <= 8) pal.palNumEntries = (1 << (int)lpbi->biBitCount);
if (pal.palNumEntries == 0) return NULL;
prgb = (LPRGBQUAD)(lpbi+1);
for (i=0; i<(int)pal.palNumEntries; i++) { pal.palPalEntry[i].peRed = prgb[i].rgbRed; pal.palPalEntry[i].peGreen = prgb[i].rgbGreen; pal.palPalEntry[i].peBlue = prgb[i].rgbBlue; pal.palPalEntry[i].peFlags = 0; }
if (hpal) { ResizePalette(hpal, pal.palNumEntries); SetPaletteEntries(hpal, 0, pal.palNumEntries, pal.palPalEntry); } else { hpal = CreatePalette((LPLOGPALETTE)&pal); }
return hpal; }
/**************************************************************************
* @doc INTERNAL * * @api BOOL | SetPalFlags | Modifies the palette flags. * * @parm HPALETTE | hpal | Handle to the palette. * * @parm int | iIndex | Starting palette index. * * @parm int | cntEntries | Number of entries to set flags on. * * @parm UINT | wFlags | Palette flags. * * @rdesc Returns TRUE if successful, FALSE otherwise. * **************************************************************************/ static BOOL SetPalFlags(HPALETTE hpal, int iIndex, int cntEntries, UINT wFlags) { int i; PALETTEENTRY ape[256];
if (hpal == NULL) return FALSE;
if (cntEntries < 0) GetObject(hpal,sizeof(int),(LPSTR)&cntEntries);
GetPaletteEntries(hpal, iIndex, cntEntries, ape);
for (i=0; i<cntEntries; i++) ape[i].peFlags = (BYTE)wFlags;
return SetPaletteEntries(hpal, iIndex, cntEntries, ape); }
/**************************************************************************
* @doc INTERNAL * * @api BOOL | IsIdentityPalette | Check if palette is an identity palette. * * @parm HPALETTE | hpal | Handle to the palette. * * @rdesc Returns TRUE if the palette is an identity palette, FALSE otherwise. * **************************************************************************/
#define CODE _based(_segname("_CODE"))
//
// These are the standard VGA colors, we will be stuck with until the
// end of time!
//
static PALETTEENTRY CODE apeCosmic[16] = { 0x00, 0x00, 0x00, 0x00, // 0000 black
0x80, 0x00, 0x00, 0x00, // 0001 dark red
0x00, 0x80, 0x00, 0x00, // 0010 dark green
0x80, 0x80, 0x00, 0x00, // 0011 mustard
0x00, 0x00, 0x80, 0x00, // 0100 dark blue
0x80, 0x00, 0x80, 0x00, // 0101 purple
0x00, 0x80, 0x80, 0x00, // 0110 dark turquoise
0xC0, 0xC0, 0xC0, 0x00, // 1000 gray
0x80, 0x80, 0x80, 0x00, // 0111 dark gray
0xFF, 0x00, 0x00, 0x00, // 1001 red
0x00, 0xFF, 0x00, 0x00, // 1010 green
0xFF, 0xFF, 0x00, 0x00, // 1011 yellow
0x00, 0x00, 0xFF, 0x00, // 1100 blue
0xFF, 0x00, 0xFF, 0x00, // 1101 pink (magenta)
0x00, 0xFF, 0xFF, 0x00, // 1110 cyan
0xFF, 0xFF, 0xFF, 0x00 // 1111 white
};
static PALETTEENTRY CODE apeFake[16] = { 0x00, 0x00, 0x00, 0x00, // 0000 black
0xBF, 0x00, 0x00, 0x00, // 0001 dark red
0x00, 0xBF, 0x00, 0x00, // 0010 dark green
0xBF, 0xBF, 0x00, 0x00, // 0011 mustard
0x00, 0x00, 0xBF, 0x00, // 0100 dark blue
0xBF, 0x00, 0xBF, 0x00, // 0101 purple
0x00, 0xBF, 0xBF, 0x00, // 0110 dark turquoise
0xC0, 0xC0, 0xC0, 0x00, // 1000 gray
0x80, 0x80, 0x80, 0x00, // 0111 dark gray
0xFF, 0x00, 0x00, 0x00, // 1001 red
0x00, 0xFF, 0x00, 0x00, // 1010 green
0xFF, 0xFF, 0x00, 0x00, // 1011 yellow
0x00, 0x00, 0xFF, 0x00, // 1100 blue
0xFF, 0x00, 0xFF, 0x00, // 1101 pink (magenta)
0x00, 0xFF, 0xFF, 0x00, // 1110 cyan
0xFF, 0xFF, 0xFF, 0x00, // 1111 white
};
static PALETTEENTRY CODE apeBlackWhite[16] = { 0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0x00, 0x00, 0x00, 0x00, // 0000 black
0xFF, 0xFF, 0xFF, 0x00 // 1111 white
};
static BOOL NEAR IsIdentityPalette(HPALETTE hpal) { int i,n=0; // n is initialised as GetObject returns a 2 byte value
HDC hdc;
PALETTEENTRY ape[256]; PALETTEENTRY apeSystem[16];
if (hpal == NULL || !(gwRasterCaps & RC_PALETTE) || gwScreenBitDepth != 8) return FALSE;
// Some wierd display cards actually have different numbers of system
// colours! We definitely don't want to think we can do identity palettes.
hdc = GetDC(NULL); n = GetDeviceCaps(hdc, NUMRESERVED); ReleaseDC(NULL, hdc);
if (n != 20) return FALSE;
GetObject(hpal, sizeof(n), (LPVOID)&n);
if (n != 256) return FALSE;
GetPaletteEntries(hpal, 0, 8, &ape[0]); GetPaletteEntries(hpal, 248, 8, &ape[8]);
for (i=0; i<16; i++) ape[i].peFlags = 0;
if (!_fmemcmp(ape, apeCosmic, sizeof(apeCosmic))) goto DoneChecking;
if (!_fmemcmp(ape, apeFake, sizeof(apeFake))) goto DoneChecking;
if (!_fmemcmp(ape, apeBlackWhite, sizeof(apeBlackWhite))) goto DoneChecking;
hdc = GetDC(NULL); GetSystemPaletteEntries(hdc, 0, 8, &apeSystem[0]); GetSystemPaletteEntries(hdc, 248, 8, &apeSystem[8]); ReleaseDC(NULL, hdc);
for (i=0; i<16; i++) apeSystem[i].peFlags = 0;
if (!_fmemcmp(ape, apeSystem, sizeof(apeSystem))) goto DoneChecking;
return FALSE;
DoneChecking: //
// if we have an identity palette then, patch the colors to match
// the driver ones exactly.
//
GetPaletteEntries(hpal, 0, 256, ape);
hdc = GetDC(NULL); GetSystemPaletteEntries(hdc, 0, 10, &ape[0]); GetSystemPaletteEntries(hdc, 246, 10, &ape[246]); ReleaseDC(NULL, hdc);
for (i=0; i<10; i++) ape[i].peFlags = 0;
for (i=10; i<246; i++) ape[i].peFlags = PC_NOCOLLAPSE;
for (i=246; i<256; i++) ape[i].peFlags = 0;
SetPaletteEntries(hpal, 0, 256, ape); UnrealizeObject(hpal); //??? needed
return TRUE; }
#define COLORMASK 0xF8
STATICFN BOOL NEAR AreColorsAllGDIColors(LPBITMAPINFOHEADER lpbi) { int cColors; LPRGBQUAD lprgb = (LPRGBQUAD) ((LPBYTE) lpbi + lpbi->biSize); int i;
for (cColors = (int) lpbi->biClrUsed; cColors > 0; cColors--, lprgb++) { for (i = 0; i < 16; i++) { if (((lprgb->rgbRed & COLORMASK) == (apeCosmic[i].peRed & COLORMASK)) && ((lprgb->rgbGreen & COLORMASK) == (apeCosmic[i].peGreen & COLORMASK)) && ((lprgb->rgbBlue & COLORMASK) == (apeCosmic[i].peBlue & COLORMASK))) goto Onward; if (((lprgb->rgbRed & COLORMASK) == (apeFake[i].peRed & COLORMASK)) && ((lprgb->rgbGreen & COLORMASK) == (apeFake[i].peGreen & COLORMASK)) && ((lprgb->rgbBlue & COLORMASK) == (apeFake[i].peBlue & COLORMASK))) goto Onward; }
return FALSE; Onward: ; // There's got to be a nicer way to arrange this code!
}
return TRUE; // !!!!!
}
/**************************************************************************
let codec adapt to the system palette.
**************************************************************************/
static BOOL FixUpCodecPalette(HIC hic, LPBITMAPINFOHEADER lpbi) { struct { BITMAPINFOHEADER bi; RGBQUAD argbq[256]; } s; int i; HDC hdc;
s.bi.biSize = sizeof(s.bi); s.bi.biWidth = lpbi->biWidth; s.bi.biHeight = lpbi->biHeight; s.bi.biPlanes = 1; s.bi.biBitCount = 8; s.bi.biCompression = 0; s.bi.biSizeImage = 0; s.bi.biXPelsPerMeter = 0; s.bi.biYPelsPerMeter = 0; s.bi.biClrUsed = 256; s.bi.biClrImportant = 0;
hdc = GetDC(NULL); GetSystemPaletteEntries(hdc, 0, 256, (LPPALETTEENTRY) &s.argbq); ReleaseDC(NULL, hdc);
for (i = 0; i < 256; i++) ((DWORD FAR*)s.argbq)[i] = i < 8 || i >= 248 ? 0 : RGB(s.argbq[i].rgbRed,s.argbq[i].rgbGreen,s.argbq[i].rgbBlue);
return ICDecompressSetPalette(hic, &s.bi) == ICERR_OK; }
/**************************************************************************
let codec adapt to a palette passed by the app.
**************************************************************************/
static BOOL NEAR SendSetPalette(PDD pdd) { int i; int iPalColors = 0; BOOL f;
if (pdd->hic == NULL) // nobody to send too
return FALSE;
if (pdd->biBuffer.biBitCount != 8) // not decompressing to 8bit
return FALSE;
if (!(gwRasterCaps & RC_PALETTE)) // not a palette device who cares.
return FALSE;
if (pdd->hpalDraw) { GetObject(pdd->hpalDraw, sizeof(iPalColors), (void FAR *)&iPalColors);
if (iPalColors == 0) return FALSE;
if (iPalColors > 256) iPalColors = 256;
pdd->biBuffer.biClrUsed = iPalColors; GetPaletteEntries(pdd->hpalDraw, 0, iPalColors, (PALETTEENTRY FAR *)pdd->argbq);
for (i = 0; i < iPalColors; i++) ((DWORD*)pdd->argbq)[i] = RGB(pdd->argbq[i].rgbRed,pdd->argbq[i].rgbGreen,pdd->argbq[i].rgbBlue);
f = ICDecompressSetPalette(pdd->hic, &pdd->biBuffer) == ICERR_OK; ICDecompressGetPalette(pdd->hic, pdd->lpbi, &pdd->biBuffer); } else { pdd->biBuffer.biClrUsed = pdd->ClrUsed; f = ICDecompressSetPalette(pdd->hic, NULL) == ICERR_OK; ICDecompressGetPalette(pdd->hic, pdd->lpbi, &pdd->biBuffer); }
return f; }
#ifdef DEBUG_RETAIL
#define _WINDLL
#include <stdarg.h>
#include <stdio.h>
void FAR CDECL ddprintf(LPSTR szFormat, ...) { char ach[128]; va_list va; UINT n; static int fDebug = -1;
if (fDebug == -1) fDebug = GetProfileIntA("Debug", MODNAME, FALSE);
if (!fDebug) return;
va_start(va, szFormat); #ifdef WIN32
n = sprintf(ach, MODNAME ": (tid %x) ", GetCurrentThreadId()); n += vsprintf(ach+n, szFormat, va); #else
lstrcpy(ach, MODNAME ": "); n = lstrlen(ach); n += wvsprintf(ach+n, szFormat, va); #endif
va_end(va); ach[n++] = '\r'; ach[n++] = '\n'; ach[n] = 0; OutputDebugStringA(ach); } #endif
|