/************************************************************************** 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 #include #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 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 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 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 * **************************************************************************/ 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

handle * after the application has finished drawing. * * @xref **************************************************************************/ 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 . * * @parm PDD | pdd | Pointer to a . * * @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 . * * @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 * 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 * ). * * @flag DDF_SAME_DRAW | Uses the drawing parameters previously * specified for this function. Use this flag only * if

,

,

,

, and

* have not changed since using or . * * @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 creates will have the PC_RESERVED flag set for * as many entries as possible, and the palette can be animated by * . If using with * , set this flag with * rather than . * * @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 to . * * @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 with * , set this flag with * rather than . * * @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 . * * * @rdesc Returns TRUE if successful. * * @comm This function prepares to draw a bitmap specified by

* to the display context

. The image is stretched to * the size specified by

and

. If

and *

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 to draw the image. * If you do not use this function, implicitly * uses it when it draws the image. * * To update the flags set with , call * with new parameters. * * When is used, the * flag is normally set for . * * If the parameters of have not changed, subsequent * uses of it have not effect. * * Use to free memory used by the DrawDib context. * * @xref **************************************************************************/ //#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 or * is discarded by . * **************************************************************************/ 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 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 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 . 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 * has been used without pairing it with * , or if has been used. * * @xref * **************************************************************************/ 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 * **************************************************************************/ 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 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 . * * The DIB color table must be changed by the user or * the next use of without the DDF_SAME_DRAW flag * implicity calls . * * If the DDF_ANIMATE flag is not set in the previous call to * or , this function will * animate the palette. In this case, update the DIB color * table from the palette specified by

and use * to realize the updated palette. Redraw * the image to see the updated colors. * * @xref * **************************************************************************/ 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; ilpargbqIn))[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; iargbq[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; iaw[i] = GetNearestPaletteIndex(pdd->hpalDraw, RGB(lppe[i].peRed,lppe[i].peGreen,lppe[i].peBlue)); } } else if (pdd->ulFlags & DDF_ANIMATE) { for (i=iStart; 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= 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; iaw)[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 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 or * message, or used in conjunction with the DDF_SAME_HDC flag * to prepare a display context prior to calling * multiple times. * * @ex The following example shows how the function is used to * handle a or * 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 prior to * calling 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 with * 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 . * * To make 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 , , , or * (with a different draw/format) on the same DrawDib * context

. These can free the selected palette * while it is being used by your display context and cause * a GDI error. * * will return 0 if called before a * or * * @xref * **************************************************************************/ 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 * structure. * * @parm DWORD | dwSize | Specifies the size of the buffer pointed to by

* * @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

is not NULL, * it is filled in with a copy of the * describing the buffer. * * The structure for

must have room for a * 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 * **************************************************************************/ 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 * **************************************************************************/ 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 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 *

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 *

is -1, the height of the bitmap is used. * * @parm LPBITMAPINFOHEADER | lpbi | Specifies a pointer to the * 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 * prior to this call and should not * initialize it. * * @flag DDF_SAME_DRAW | Uses the drawing parameters previously * specified for this function. Use this flag only * if

,

,

,

, and

* have not changed since using or . * Normally checks the parameters, and if they * have changed, prepares the DrawDib context * for drawing. * * @flag DDF_DONTDRAW | Indicates the frame is not to be drawn and will * later be recalled with the 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 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 , * set this flag for it rather than . * * @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 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; ibiSize); 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 #include 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