windows-nt/Source/XPSP1/NT/multimedia/media/avi/drawdib.16/drawdib.c

4024 lines
121 KiB
C
Raw Permalink Normal View History

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