drawdib.c 13.5 KB
Newer Older
1
/*
2 3
 * Copyright 2000 Bradley Baetz
 *
4 5 6 7 8 9 10 11 12 13 14 15
 * 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
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17
 *
18
 * FIXME: Some flags are ignored
19
 *
20 21 22
 * Handle palettes
 */

23 24
#include <stdarg.h>
#include <stdio.h>
25
#include <string.h>
26

27 28
#include "windef.h"
#include "winbase.h"
29 30
#include "wingdi.h"
#include "winuser.h"
31
#include "vfw.h"
32

33
#include "wine/debug.h"
34

35
WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
36

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
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;
54 55
} WINE_HDD;

56
static int num_colours(const BITMAPINFOHEADER *lpbi)
57 58 59 60 61 62 63 64
{
	if(lpbi->biClrUsed)
		return lpbi->biClrUsed;
	if(lpbi->biBitCount<=8)
		return 1<<lpbi->biBitCount;
	return 0;
}

65 66 67 68 69
static WINE_HDD*        HDD_FirstHdd /* = NULL */;

static WINE_HDD*       MSVIDEO_GetHddPtr(HDRAWDIB hd)
{
    WINE_HDD*   hdd;
70

71
    for (hdd = HDD_FirstHdd; hdd != NULL && hdd->hSelf != hd; hdd = hdd->next);
72
    return hdd;
73 74
}

75
static UINT_PTR HDD_HandleRef = 1;
76

77
/***********************************************************************
78
 *		DrawDibOpen		[MSVFW32.@]
79
 */
80 81 82
HDRAWDIB VFWAPI DrawDibOpen(void) 
{
    WINE_HDD*   whdd;
83

84 85 86 87
    TRACE("(void)\n");
	
    whdd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_HDD));
    TRACE("=> %p\n", whdd);
88

89 90
    while (MSVIDEO_GetHddPtr((HDRAWDIB)HDD_HandleRef) != NULL) HDD_HandleRef++;
    whdd->hSelf = (HDRAWDIB)HDD_HandleRef++;
91

92 93
    whdd->next = HDD_FirstHdd;
    HDD_FirstHdd = whdd;
94

95
    return whdd->hSelf;
96 97 98
}

/***********************************************************************
99
 *		DrawDibClose		[MSVFW32.@]
100
 */
101 102 103
BOOL VFWAPI DrawDibClose(HDRAWDIB hdd) 
{
    WINE_HDD* whdd = MSVIDEO_GetHddPtr(hdd);
104
    WINE_HDD** p;
105

106
    TRACE("(%p)\n", hdd);
107

108
    if (!whdd) return FALSE;
109

110
    if (whdd->begun) DrawDibEnd(hdd);
111

112 113 114 115 116 117 118 119 120
    for (p = &HDD_FirstHdd; *p != NULL; p = &((*p)->next))
    {
        if (*p == whdd)
        {
            *p = whdd->next;
            break;
        }
    }

121
    HeapFree(GetProcessHeap(), 0, whdd);
122

123 124
    return TRUE;
}
125

126 127 128 129 130 131 132 133 134 135
/***********************************************************************
 *		DrawDibEnd		[MSVFW32.@]
 */
BOOL VFWAPI DrawDibEnd(HDRAWDIB hdd) 
{
    BOOL ret = TRUE;
    WINE_HDD *whdd = MSVIDEO_GetHddPtr(hdd);

    TRACE("(%p)\n", hdd);

136 137
    if (!whdd) return FALSE;

138 139
    whdd->hpal = 0; /* Do not free this */
    whdd->hdc = 0;
140 141 142 143
    HeapFree(GetProcessHeap(), 0, whdd->lpbi);
    whdd->lpbi = NULL;
    HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
    whdd->lpbiOut = NULL;
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169

    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;
170 171 172
}

/***********************************************************************
173
 *              DrawDibBegin            [MSVFW32.@]
174 175
 */
BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
176 177 178 179 180 181 182 183 184 185 186
                         HDC      hdc,
                         INT      dxDst,
                         INT      dyDst,
                         LPBITMAPINFOHEADER lpbi,
                         INT      dxSrc,
                         INT      dySrc,
                         UINT     wFlags) 
{
    BOOL ret = TRUE;
    WINE_HDD *whdd;

187
    TRACE("(%p,%p,%d,%d,%p,%d,%d,0x%08x)\n",
188
          hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, wFlags);
189

190
    TRACE("lpbi: %d,%d/%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
          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) 
        {
211
            WARN("Could not open IC. biCompression == 0x%08x\n", lpbi->biCompression);
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
            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;
            
239 240
            TRACE("biSizeImage == %d\n", whdd->lpbiOut->biSizeImage);
            TRACE("biCompression == %d\n", whdd->lpbiOut->biCompression);
241 242 243 244 245 246 247 248
            TRACE("biBitCount == %d\n", whdd->lpbiOut->biBitCount);
        }
    }
    else 
    {
        DWORD dwSize;
        /* No compression */
        TRACE("Not compressed!\n");
249 250 251 252 253 254 255 256 257 258 259 260
        if (lpbi->biHeight <= 0)
        {
            /* we don't draw inverted DIBs */
            TRACE("detected inverted DIB\n");
            ret = FALSE;
        }
        else
        {
            dwSize = lpbi->biSize + num_colours(lpbi)*sizeof(RGBQUAD);
            whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, dwSize);
            memcpy(whdd->lpbiOut, lpbi, dwSize);
        }
261 262 263 264 265 266 267
    }

    if (ret) 
    {
        /*whdd->lpvbuf = HeapAlloc(GetProcessHeap(), 0, whdd->lpbiOut->biSizeImage);*/

        whdd->hMemDC = CreateCompatibleDC(hdc);
268
        TRACE("Creating: %d, %p\n", whdd->lpbiOut->biSize, whdd->lpvbits);
269
        whdd->hDib = CreateDIBSection(whdd->hMemDC, (BITMAPINFO *)whdd->lpbiOut, DIB_RGB_COLORS, &(whdd->lpvbits), 0, 0);
Richard Cohen's avatar
Richard Cohen committed
270
        if (whdd->hDib) 
271
        {
Richard Cohen's avatar
Richard Cohen committed
272 273 274 275 276
            TRACE("Created: %p,%p\n", whdd->hDib, whdd->lpvbits);
        }
        else
        {
            ret = FALSE;
277
            TRACE("Error: %d\n", GetLastError());
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
        }
        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);
298 299
        HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
        whdd->lpbiOut = NULL;
300 301 302
    }

    return ret;
303 304 305
}

/**********************************************************************
306
 *		DrawDibDraw		[MSVFW32.@]
307
 */
308
BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd, HDC hdc,
309 310 311 312 313 314 315 316
                        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;
317

318
    TRACE("(%p,%p,%d,%d,%d,%d,%p,%p,%d,%d,%d,%d,0x%08x)\n",
319
          hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, wFlags);
320

321
    whdd = MSVIDEO_GetHddPtr(hdd);
322
    if (!whdd) return FALSE;
323

Richard Cohen's avatar
Richard Cohen committed
324 325
    TRACE("whdd=%p\n", whdd);

326
    if (wFlags & ~(DDF_SAME_HDC | DDF_SAME_DRAW | DDF_NOTKEYFRAME | DDF_UPDATE | DDF_DONTDRAW | DDF_BACKGROUNDPAL))
327
        FIXME("wFlags == 0x%08x not handled\n", wFlags);
328

329 330 331 332 333
    if (!lpBits) 
    {
        /* Undocumented? */
        lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(num_colours(lpbi)*sizeof(RGBQUAD));
    }
334 335


336
#define CHANGED(x) (whdd->x != x)
337

338 339 340 341 342 343
    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);
344 345
        if (!ret)
            return ret;
346
    }
347

348
#undef CHANGED
349

350 351 352 353 354 355 356 357 358 359 360 361
    if ((dxDst == -1) && (dyDst == -1)) 
    {
        dxDst = dxSrc;
        dyDst = dySrc;
    }

    if (!(wFlags & DDF_UPDATE)) 
    {
        if (lpbi->biCompression) 
        {
            DWORD flags = 0;

362
            TRACE("Compression == 0x%08x\n", lpbi->biCompression);
363 364 365 366 367 368 369 370

            if (wFlags & DDF_NOTKEYFRAME)
                flags |= ICDECOMPRESS_NOTKEYFRAME;

            ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
        }
        else
        {
371 372
            /* BI_RGB: lpbi->biSizeImage isn't reliable */
            DWORD biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
Richard Cohen's avatar
Richard Cohen committed
373
            memcpy(whdd->lpvbits, lpBits, biSizeImage);
374 375 376
        }
    }
    if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
377 378 379 380 381 382
    {
        if ((wFlags & DDF_BACKGROUNDPAL) && ! (wFlags & DDF_SAME_HDC))
         SelectPalette(hdc, whdd->hpal, TRUE);
        else
         SelectPalette(hdc, whdd->hpal, FALSE);
    }
383 384 385 386 387

    if (!(StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY)))
        ret = FALSE;
    
    return ret;
388 389 390
}

/*************************************************************************
391
 *		DrawDibStart		[MSVFW32.@]
392 393
 */
BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
394
	FIXME("(%p, %d), stub\n", hdd, rate);
395 396 397 398
	return TRUE;
}

/*************************************************************************
399
 *		DrawDibStop		[MSVFW32.@]
400 401
 */
BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
402
	FIXME("(%p), stub\n", hdd);
403 404 405
	return TRUE;
}

406 407 408 409 410 411 412 413 414
/***********************************************************************
 *              DrawDibChangePalette       [MSVFW32.@]
 */
BOOL VFWAPI DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe)
{
    FIXME("(%p, 0x%08x, 0x%08x, %p), stub\n", hdd, iStart, iLen, lppe);
    return TRUE;
}

415
/***********************************************************************
416
 *              DrawDibSetPalette       [MSVFW32.@]
417
 */
418 419 420
BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal) 
{
    WINE_HDD *whdd;
421

422
    TRACE("(%p, %p)\n", hdd, hpal);
423

424 425
    whdd = MSVIDEO_GetHddPtr(hdd);
    if (!whdd) return FALSE;
426

427 428 429 430 431 432 433 434 435
    whdd->hpal = hpal;

    if (whdd->begun) 
    {
        SelectPalette(whdd->hdc, hpal, 0);
        RealizePalette(whdd->hdc);
    }

    return TRUE;
436 437
}

438 439 440 441 442
/***********************************************************************
 *              DrawDibGetBuffer       [MSVFW32.@]
 */
LPVOID VFWAPI DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags)
{
443
    FIXME("(%p, %p, 0x%08x, 0x%08x), stub\n", hdd, lpbi, dwSize, dwFlags);
444 445 446
    return NULL;
}

447
/***********************************************************************
448
 *              DrawDibGetPalette       [MSVFW32.@]
449
 */
450 451 452 453 454
HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd) 
{
    WINE_HDD *whdd;

    TRACE("(%p)\n", hdd);
455

456 457
    whdd = MSVIDEO_GetHddPtr(hdd);
    if (!whdd) return FALSE;
458

459
    return whdd->hpal;
460 461 462
}

/***********************************************************************
463
 *              DrawDibRealize          [MSVFW32.@]
464
 */
465 466 467 468
UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground) 
{
    WINE_HDD *whdd;
    UINT ret = 0;
469

470
    FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
471

472 473
    whdd = MSVIDEO_GetHddPtr(hdd);
    if (!whdd) return FALSE;
474

475 476 477 478 479
    if (!whdd || !(whdd->begun)) 
    {
        ret = 0;
        goto out;
    }
480

481 482
    if (!whdd->hpal)
        whdd->hpal = CreateHalftonePalette(hdc);
483

484
    SelectPalette(hdc, whdd->hpal, fBackground);
485
    ret = RealizePalette(hdc);
486

487
 out:
488 489
    TRACE("=> %u\n", ret);
    return ret;
490
}
491

492 493 494 495 496 497 498 499 500 501 502 503
/***********************************************************************
 *              DrawDibTime          [MSVFW32.@]
 */
BOOL VFWAPI DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime)
{
    FIXME("(%p, %p) stub\n", hdd, lpddtime);
    return FALSE;
}

/***********************************************************************
 *              DrawDibProfileDisplay          [MSVFW32.@]
 */
504 505 506 507 508 509
DWORD VFWAPI DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi)
{
    FIXME("(%p) stub\n", lpbi);

    return PD_CAN_DRAW_DIB;
}