drawdib.c 14.3 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
                        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;
316 317
    BOOL ret;
    int reopen = 0;
318

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

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

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

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

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


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

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
    /* Check if anything changed from the parameters passed and our struct.
     * If anything changed we need to run DrawDibBegin again to ensure we
     * can support the changes.
     */
    if (!whdd->begun)
        reopen = 1;
    else if (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc))
        reopen = 2;
    else if (!(wFlags & DDF_SAME_DRAW))
    {
        if (CHANGED(lpbi) && memcmp(lpbi, whdd->lpbi, sizeof(*lpbi))) reopen = 3;
        else if (CHANGED(dxSrc)) reopen = 4;
        else if (CHANGED(dySrc)) reopen = 5;
        else if (CHANGED(dxDst)) reopen = 6;
        else if (CHANGED(dyDst)) reopen = 7;
    }
    if (reopen)
356
    {
357
        TRACE("Something changed (reason %d)!\n", reopen);
358
        ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
359 360
        if (!ret)
            return ret;
361
    }
362

363
#undef CHANGED
364

365 366 367 368 369 370 371 372
    /* If source dimensions are not specified derive them from bitmap header */
    if (dxSrc == -1 && dySrc == -1)
    {
        dxSrc = lpbi->biWidth;
        dySrc = lpbi->biHeight;
    }
    /* If destination dimensions are not specified derive them from source */
    if (dxDst == -1 && dyDst == -1)
373 374 375 376 377 378 379 380 381 382 383
    {
        dxDst = dxSrc;
        dyDst = dySrc;
    }

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

384
            TRACE("Compression == 0x%08x\n", lpbi->biCompression);
385 386 387 388 389 390 391 392

            if (wFlags & DDF_NOTKEYFRAME)
                flags |= ICDECOMPRESS_NOTKEYFRAME;

            ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
        }
        else
        {
393 394
            /* 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
395
            memcpy(whdd->lpvbits, lpBits, biSizeImage);
396 397 398
        }
    }
    if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
399 400 401 402 403 404
    {
        if ((wFlags & DDF_BACKGROUNDPAL) && ! (wFlags & DDF_SAME_HDC))
         SelectPalette(hdc, whdd->hpal, TRUE);
        else
         SelectPalette(hdc, whdd->hpal, FALSE);
    }
405

406 407 408 409
    ret = StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY);
    TRACE("Painting %dx%d at %d,%d from %dx%d at %d,%d -> %d\n",
          dxDst, dyDst, xDst, yDst, dxSrc, dySrc, xSrc, ySrc, ret);

410
    return ret;
411 412 413
}

/*************************************************************************
414
 *		DrawDibStart		[MSVFW32.@]
415 416
 */
BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
417
	FIXME("(%p, %d), stub\n", hdd, rate);
418 419 420 421
	return TRUE;
}

/*************************************************************************
422
 *		DrawDibStop		[MSVFW32.@]
423 424
 */
BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
425
	FIXME("(%p), stub\n", hdd);
426 427 428
	return TRUE;
}

429 430 431 432 433 434 435 436 437
/***********************************************************************
 *              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;
}

438
/***********************************************************************
439
 *              DrawDibSetPalette       [MSVFW32.@]
440
 */
441 442 443
BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal) 
{
    WINE_HDD *whdd;
444

445
    TRACE("(%p, %p)\n", hdd, hpal);
446

447 448
    whdd = MSVIDEO_GetHddPtr(hdd);
    if (!whdd) return FALSE;
449

450 451 452 453 454 455 456 457 458
    whdd->hpal = hpal;

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

    return TRUE;
459 460
}

461 462 463 464 465
/***********************************************************************
 *              DrawDibGetBuffer       [MSVFW32.@]
 */
LPVOID VFWAPI DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags)
{
466
    FIXME("(%p, %p, 0x%08x, 0x%08x), stub\n", hdd, lpbi, dwSize, dwFlags);
467 468 469
    return NULL;
}

470
/***********************************************************************
471
 *              DrawDibGetPalette       [MSVFW32.@]
472
 */
473 474 475 476 477
HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd) 
{
    WINE_HDD *whdd;

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

479 480
    whdd = MSVIDEO_GetHddPtr(hdd);
    if (!whdd) return FALSE;
481

482
    return whdd->hpal;
483 484 485
}

/***********************************************************************
486
 *              DrawDibRealize          [MSVFW32.@]
487
 */
488 489 490 491
UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground) 
{
    WINE_HDD *whdd;
    UINT ret = 0;
492

493
    FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
494

495 496
    whdd = MSVIDEO_GetHddPtr(hdd);
    if (!whdd) return FALSE;
497

498
    if (!whdd->begun)
499 500 501 502
    {
        ret = 0;
        goto out;
    }
503

504 505
    if (!whdd->hpal)
        whdd->hpal = CreateHalftonePalette(hdc);
506

507
    SelectPalette(hdc, whdd->hpal, fBackground);
508
    ret = RealizePalette(hdc);
509

510
 out:
511 512
    TRACE("=> %u\n", ret);
    return ret;
513
}
514

515 516 517 518 519 520 521 522 523 524 525 526
/***********************************************************************
 *              DrawDibTime          [MSVFW32.@]
 */
BOOL VFWAPI DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime)
{
    FIXME("(%p, %p) stub\n", hdd, lpddtime);
    return FALSE;
}

/***********************************************************************
 *              DrawDibProfileDisplay          [MSVFW32.@]
 */
527 528 529 530 531 532
DWORD VFWAPI DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi)
{
    FIXME("(%p) stub\n", lpbi);

    return PD_CAN_DRAW_DIB;
}