wine/dlls/msvideo/drawdib.c
2004-10-18 21:20:09 +00:00

469 lines
12 KiB
C

/*
* Copyright 2000 Bradley Baetz
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* FIXME: Some flags are ignored
*
* Handle palettes
*/
#include <string.h>
#include "msvideo_private.h"
#include "wingdi.h"
#include "winuser.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
typedef struct tagWINE_HDD {
HDC hdc;
INT dxDst;
INT dyDst;
LPBITMAPINFOHEADER lpbi;
INT dxSrc;
INT dySrc;
HPALETTE hpal; /* Palette to use for the DIB */
BOOL begun; /* DrawDibBegin has been called */
LPBITMAPINFOHEADER lpbiOut; /* Output format */
HIC hic; /* HIC for decompression */
HDC hMemDC; /* DC for buffering */
HBITMAP hOldDib; /* Original Dib */
HBITMAP hDib; /* DibSection */
LPVOID lpvbits; /* Buffer for holding decompressed dib */
HDRAWDIB hSelf;
struct tagWINE_HDD* next;
} WINE_HDD;
int num_colours(LPBITMAPINFOHEADER lpbi)
{
if(lpbi->biClrUsed)
return lpbi->biClrUsed;
if(lpbi->biBitCount<=8)
return 1<<lpbi->biBitCount;
return 0;
}
static WINE_HDD* HDD_FirstHdd /* = NULL */;
static WINE_HDD* MSVIDEO_GetHddPtr(HDRAWDIB hd)
{
WINE_HDD* hdd;
for (hdd = HDD_FirstHdd; hdd != NULL && hdd->hSelf != hd; hdd = hdd->next);
return hdd;
}
static DWORD HDD_HandleRef = 1;
/***********************************************************************
* DrawDibOpen [MSVFW32.@]
*/
HDRAWDIB VFWAPI DrawDibOpen(void)
{
WINE_HDD* whdd;
TRACE("(void)\n");
whdd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_HDD));
TRACE("=> %p\n", whdd);
while (MSVIDEO_GetHddPtr((HDRAWDIB)HDD_HandleRef) != NULL) HDD_HandleRef++;
whdd->hSelf = (HDRAWDIB)HDD_HandleRef++;
whdd->next = HDD_FirstHdd;
HDD_FirstHdd = whdd;
return whdd->hSelf;
}
/***********************************************************************
* DrawDibClose [MSVFW32.@]
*/
BOOL VFWAPI DrawDibClose(HDRAWDIB hdd)
{
WINE_HDD* whdd = MSVIDEO_GetHddPtr(hdd);
WINE_HDD** p;
TRACE("(%p)\n", hdd);
if (!whdd) return FALSE;
if (whdd->begun) DrawDibEnd(hdd);
for (p = &HDD_FirstHdd; *p != NULL; p = &((*p)->next))
{
if (*p == whdd)
{
*p = whdd->next;
break;
}
}
HeapFree(GetProcessHeap(), 0, whdd);
return TRUE;
}
/***********************************************************************
* DrawDibEnd [MSVFW32.@]
*/
BOOL VFWAPI DrawDibEnd(HDRAWDIB hdd)
{
BOOL ret = TRUE;
WINE_HDD *whdd = MSVIDEO_GetHddPtr(hdd);
TRACE("(%p)\n", hdd);
whdd->hpal = 0; /* Do not free this */
whdd->hdc = 0;
if (whdd->lpbi)
{
HeapFree(GetProcessHeap(), 0, whdd->lpbi);
whdd->lpbi = NULL;
}
if (whdd->lpbiOut)
{
HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
whdd->lpbiOut = NULL;
}
whdd->begun = FALSE;
/*if (whdd->lpvbits)
HeapFree(GetProcessHeap(), 0, whdd->lpvbuf);*/
if (whdd->hMemDC)
{
SelectObject(whdd->hMemDC, whdd->hOldDib);
DeleteDC(whdd->hMemDC);
whdd->hMemDC = 0;
}
if (whdd->hDib) DeleteObject(whdd->hDib);
whdd->hDib = 0;
if (whdd->hic)
{
ICDecompressEnd(whdd->hic);
ICClose(whdd->hic);
whdd->hic = 0;
}
whdd->lpvbits = NULL;
return ret;
}
/***********************************************************************
* DrawDibBegin [MSVFW32.@]
*/
BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
HDC hdc,
INT dxDst,
INT dyDst,
LPBITMAPINFOHEADER lpbi,
INT dxSrc,
INT dySrc,
UINT wFlags)
{
BOOL ret = TRUE;
WINE_HDD *whdd;
TRACE("(%p,%p,%d,%d,%p,%d,%d,0x%08lx)\n",
hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, (DWORD)wFlags);
TRACE("lpbi: %ld,%ld/%ld,%d,%d,%ld,%ld,%ld,%ld,%ld,%ld\n",
lpbi->biSize, lpbi->biWidth, lpbi->biHeight, lpbi->biPlanes,
lpbi->biBitCount, lpbi->biCompression, lpbi->biSizeImage,
lpbi->biXPelsPerMeter, lpbi->biYPelsPerMeter, lpbi->biClrUsed,
lpbi->biClrImportant);
if (wFlags & ~(DDF_BUFFER))
FIXME("wFlags == 0x%08x not handled\n", wFlags & ~(DDF_BUFFER));
whdd = MSVIDEO_GetHddPtr(hdd);
if (!whdd) return FALSE;
if (whdd->begun) DrawDibEnd(hdd);
if (lpbi->biCompression)
{
DWORD size = 0;
whdd->hic = ICOpen(ICTYPE_VIDEO, lpbi->biCompression, ICMODE_DECOMPRESS);
if (!whdd->hic)
{
WARN("Could not open IC. biCompression == 0x%08lx\n", lpbi->biCompression);
ret = FALSE;
}
if (ret)
{
size = ICDecompressGetFormat(whdd->hic, lpbi, NULL);
if (size == ICERR_UNSUPPORTED)
{
WARN("Codec doesn't support GetFormat, giving up.\n");
ret = FALSE;
}
}
if (ret)
{
whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, size);
if (ICDecompressGetFormat(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
ret = FALSE;
}
if (ret)
{
/* FIXME: Use Ex functions if available? */
if (ICDecompressBegin(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
ret = FALSE;
TRACE("biSizeImage == %ld\n", whdd->lpbiOut->biSizeImage);
TRACE("biCompression == %ld\n", whdd->lpbiOut->biCompression);
TRACE("biBitCount == %d\n", whdd->lpbiOut->biBitCount);
}
}
else
{
DWORD dwSize;
/* No compression */
TRACE("Not compressed!\n");
dwSize = lpbi->biSize + num_colours(lpbi)*sizeof(RGBQUAD);
whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, dwSize);
memcpy(whdd->lpbiOut, lpbi, dwSize);
}
if (ret)
{
/*whdd->lpvbuf = HeapAlloc(GetProcessHeap(), 0, whdd->lpbiOut->biSizeImage);*/
whdd->hMemDC = CreateCompatibleDC(hdc);
TRACE("Creating: %ld, %p\n", whdd->lpbiOut->biSize, whdd->lpvbits);
whdd->hDib = CreateDIBSection(whdd->hMemDC, (BITMAPINFO *)whdd->lpbiOut, DIB_RGB_COLORS, &(whdd->lpvbits), 0, 0);
if (!whdd->hDib)
{
TRACE("Error: %ld\n", GetLastError());
}
TRACE("Created: %p,%p\n", whdd->hDib, whdd->lpvbits);
whdd->hOldDib = SelectObject(whdd->hMemDC, whdd->hDib);
}
if (ret)
{
whdd->hdc = hdc;
whdd->dxDst = dxDst;
whdd->dyDst = dyDst;
whdd->lpbi = HeapAlloc(GetProcessHeap(), 0, lpbi->biSize);
memcpy(whdd->lpbi, lpbi, lpbi->biSize);
whdd->dxSrc = dxSrc;
whdd->dySrc = dySrc;
whdd->begun = TRUE;
whdd->hpal = 0;
}
else
{
if (whdd->hic)
ICClose(whdd->hic);
if (whdd->lpbiOut)
{
HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
whdd->lpbiOut = NULL;
}
}
return ret;
}
/**********************************************************************
* DrawDibDraw [MSVFW32.@]
*/
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)
{
WINE_HDD *whdd;
BOOL ret = TRUE;
TRACE("(%p,%p,%d,%d,%d,%d,%p,%p,%d,%d,%d,%d,0x%08lx)\n",
hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, (DWORD)wFlags);
whdd = MSVIDEO_GetHddPtr(hdd);
if (!whdd) return FALSE;
if (wFlags & ~(DDF_SAME_HDC | DDF_SAME_DRAW | DDF_NOTKEYFRAME | DDF_UPDATE | DDF_DONTDRAW | DDF_BACKGROUNDPAL))
FIXME("wFlags == 0x%08lx not handled\n", (DWORD)wFlags);
if (!lpBits)
{
/* Undocumented? */
lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(num_colours(lpbi)*sizeof(RGBQUAD));
}
#define CHANGED(x) (whdd->x != x)
if ((!whdd->begun) ||
(!(wFlags & DDF_SAME_HDC) && CHANGED(hdc)) ||
(!(wFlags & DDF_SAME_DRAW) && (CHANGED(lpbi) || CHANGED(dxSrc) || CHANGED(dySrc) || CHANGED(dxDst) || CHANGED(dyDst))))
{
TRACE("Something changed!\n");
ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
}
#undef CHANGED
if ((dxDst == -1) && (dyDst == -1))
{
dxDst = dxSrc;
dyDst = dySrc;
}
if (!(wFlags & DDF_UPDATE))
{
/* biSizeImage may be set to 0 for BI_RGB (uncompressed) bitmaps */
if ((lpbi->biCompression == BI_RGB) && (lpbi->biSizeImage == 0))
lpbi->biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
if (lpbi->biCompression)
{
DWORD flags = 0;
TRACE("Compression == 0x%08lx\n", lpbi->biCompression);
if (wFlags & DDF_NOTKEYFRAME)
flags |= ICDECOMPRESS_NOTKEYFRAME;
ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
}
else
{
memcpy(whdd->lpvbits, lpBits, lpbi->biSizeImage);
}
}
if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
{
if ((wFlags & DDF_BACKGROUNDPAL) && ! (wFlags & DDF_SAME_HDC))
SelectPalette(hdc, whdd->hpal, TRUE);
else
SelectPalette(hdc, whdd->hpal, FALSE);
}
if (!(StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY)))
ret = FALSE;
return ret;
}
/*************************************************************************
* DrawDibStart [MSVFW32.@]
*/
BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
FIXME("(%p, %ld), stub\n", hdd, rate);
return TRUE;
}
/*************************************************************************
* DrawDibStop [MSVFW32.@]
*/
BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
FIXME("(%p), stub\n", hdd);
return TRUE;
}
/***********************************************************************
* DrawDibSetPalette [MSVFW32.@]
*/
BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal)
{
WINE_HDD *whdd;
TRACE("(%p, %p)\n", hdd, hpal);
whdd = MSVIDEO_GetHddPtr(hdd);
if (!whdd) return FALSE;
whdd->hpal = hpal;
if (whdd->begun)
{
SelectPalette(whdd->hdc, hpal, 0);
RealizePalette(whdd->hdc);
}
return TRUE;
}
/***********************************************************************
* DrawDibGetPalette [MSVFW32.@]
*/
HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd)
{
WINE_HDD *whdd;
TRACE("(%p)\n", hdd);
whdd = MSVIDEO_GetHddPtr(hdd);
if (!whdd) return FALSE;
return whdd->hpal;
}
/***********************************************************************
* DrawDibRealize [MSVFW32.@]
*/
UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground)
{
WINE_HDD *whdd;
HPALETTE oldPal;
UINT ret = 0;
FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
whdd = MSVIDEO_GetHddPtr(hdd);
if (!whdd) return FALSE;
if (!whdd || !(whdd->begun))
{
ret = 0;
goto out;
}
if (!whdd->hpal)
whdd->hpal = CreateHalftonePalette(hdc);
oldPal = SelectPalette(hdc, whdd->hpal, fBackground);
ret = RealizePalette(hdc);
out:
TRACE("=> %u\n", ret);
return ret;
}
DWORD VFWAPI DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi)
{
FIXME("(%p) stub\n", lpbi);
return PD_CAN_DRAW_DIB;
}