[MSVFW32] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / msvfw32 / drawdib.c
1 /*
2 * Copyright 2000 Bradley Baetz
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * 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 * Handle palettes
21 */
22
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "vfw.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
36
37 typedef struct tagWINE_HDD {
38 HDC hdc;
39 INT dxDst;
40 INT dyDst;
41 LPBITMAPINFOHEADER lpbi;
42 INT dxSrc;
43 INT dySrc;
44 HPALETTE hpal; /* Palette to use for the DIB */
45 BOOL begun; /* DrawDibBegin has been called */
46 LPBITMAPINFOHEADER lpbiOut; /* Output format */
47 HIC hic; /* HIC for decompression */
48 HDC hMemDC; /* DC for buffering */
49 HBITMAP hOldDib; /* Original Dib */
50 HBITMAP hDib; /* DibSection */
51 LPVOID lpvbits; /* Buffer for holding decompressed dib */
52 HDRAWDIB hSelf;
53 struct tagWINE_HDD* next;
54 } WINE_HDD;
55
56 static int num_colours(const BITMAPINFOHEADER *lpbi)
57 {
58 if(lpbi->biClrUsed)
59 return lpbi->biClrUsed;
60 if(lpbi->biBitCount<=8)
61 return 1<<lpbi->biBitCount;
62 return 0;
63 }
64
65 static WINE_HDD* HDD_FirstHdd /* = NULL */;
66
67 static WINE_HDD* MSVIDEO_GetHddPtr(HDRAWDIB hd)
68 {
69 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 HDRAWDIB VFWAPI DrawDibOpen(void)
81 {
82 WINE_HDD* whdd;
83
84 TRACE("(void)\n");
85
86 whdd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_HDD));
87 TRACE("=> %p\n", whdd);
88
89 while (MSVIDEO_GetHddPtr((HDRAWDIB)HDD_HandleRef) != NULL) HDD_HandleRef++;
90 whdd->hSelf = (HDRAWDIB)HDD_HandleRef++;
91
92 whdd->next = HDD_FirstHdd;
93 HDD_FirstHdd = whdd;
94
95 return whdd->hSelf;
96 }
97
98 /***********************************************************************
99 * DrawDibClose [MSVFW32.@]
100 */
101 BOOL VFWAPI DrawDibClose(HDRAWDIB hdd)
102 {
103 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 for (p = &HDD_FirstHdd; *p != NULL; p = &((*p)->next))
113 {
114 if (*p == whdd)
115 {
116 *p = whdd->next;
117 break;
118 }
119 }
120
121 HeapFree(GetProcessHeap(), 0, whdd);
122
123 return TRUE;
124 }
125
126 /***********************************************************************
127 * DrawDibEnd [MSVFW32.@]
128 */
129 BOOL VFWAPI DrawDibEnd(HDRAWDIB hdd)
130 {
131 BOOL ret = TRUE;
132 WINE_HDD *whdd = MSVIDEO_GetHddPtr(hdd);
133
134 TRACE("(%p)\n", hdd);
135
136 if (!whdd) return FALSE;
137
138 whdd->hpal = 0; /* Do not free this */
139 whdd->hdc = 0;
140 HeapFree(GetProcessHeap(), 0, whdd->lpbi);
141 whdd->lpbi = NULL;
142 HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
143 whdd->lpbiOut = NULL;
144
145 whdd->begun = FALSE;
146
147 /*if (whdd->lpvbits)
148 HeapFree(GetProcessHeap(), 0, whdd->lpvbuf);*/
149
150 if (whdd->hMemDC)
151 {
152 SelectObject(whdd->hMemDC, whdd->hOldDib);
153 DeleteDC(whdd->hMemDC);
154 whdd->hMemDC = 0;
155 }
156
157 if (whdd->hDib) DeleteObject(whdd->hDib);
158 whdd->hDib = 0;
159
160 if (whdd->hic)
161 {
162 ICDecompressEnd(whdd->hic);
163 ICClose(whdd->hic);
164 whdd->hic = 0;
165 }
166
167 whdd->lpvbits = NULL;
168
169 return ret;
170 }
171
172 /***********************************************************************
173 * DrawDibBegin [MSVFW32.@]
174 */
175 BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
176 HDC hdc,
177 INT dxDst,
178 INT dyDst,
179 LPBITMAPINFOHEADER lpbi,
180 INT dxSrc,
181 INT dySrc,
182 UINT wFlags)
183 {
184 BOOL ret = TRUE;
185 WINE_HDD *whdd;
186
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 lpbi->biSize, lpbi->biWidth, lpbi->biHeight, lpbi->biPlanes,
192 lpbi->biBitCount, lpbi->biCompression, lpbi->biSizeImage,
193 lpbi->biXPelsPerMeter, lpbi->biYPelsPerMeter, lpbi->biClrUsed,
194 lpbi->biClrImportant);
195
196 if (wFlags & ~(DDF_BUFFER))
197 FIXME("wFlags == 0x%08x not handled\n", wFlags & ~(DDF_BUFFER));
198
199 whdd = MSVIDEO_GetHddPtr(hdd);
200 if (!whdd) return FALSE;
201
202 if (whdd->begun) DrawDibEnd(hdd);
203
204 if (lpbi->biCompression)
205 {
206 DWORD size = 0;
207
208 whdd->hic = ICOpen(ICTYPE_VIDEO, lpbi->biCompression, ICMODE_DECOMPRESS);
209 if (!whdd->hic)
210 {
211 WARN("Could not open IC. biCompression == 0x%08x\n", lpbi->biCompression);
212 ret = FALSE;
213 }
214
215 if (ret)
216 {
217 size = ICDecompressGetFormat(whdd->hic, lpbi, NULL);
218 if (size == ICERR_UNSUPPORTED)
219 {
220 WARN("Codec doesn't support GetFormat, giving up.\n");
221 ret = FALSE;
222 }
223 }
224
225 if (ret)
226 {
227 whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, size);
228
229 if (ICDecompressGetFormat(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
230 ret = FALSE;
231 }
232
233 if (ret)
234 {
235 /* FIXME: Use Ex functions if available? */
236 if (ICDecompressBegin(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
237 ret = FALSE;
238
239 TRACE("biSizeImage == %d\n", whdd->lpbiOut->biSizeImage);
240 TRACE("biCompression == %d\n", whdd->lpbiOut->biCompression);
241 TRACE("biBitCount == %d\n", whdd->lpbiOut->biBitCount);
242 }
243 }
244 else
245 {
246 DWORD dwSize;
247 /* No compression */
248 TRACE("Not compressed!\n");
249 if (lpbi->biHeight <= 0)
250 {
251 /* we don't draw inverted DIBs */
252 TRACE("detected inverted DIB\n");
253 ret = FALSE;
254 }
255 else
256 {
257 dwSize = lpbi->biSize + num_colours(lpbi)*sizeof(RGBQUAD);
258 whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, dwSize);
259 memcpy(whdd->lpbiOut, lpbi, dwSize);
260 }
261 }
262
263 if (ret)
264 {
265 /*whdd->lpvbuf = HeapAlloc(GetProcessHeap(), 0, whdd->lpbiOut->biSizeImage);*/
266
267 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);
270 if (whdd->hDib)
271 {
272 TRACE("Created: %p,%p\n", whdd->hDib, whdd->lpvbits);
273 }
274 else
275 {
276 ret = FALSE;
277 TRACE("Error: %d\n", GetLastError());
278 }
279 whdd->hOldDib = SelectObject(whdd->hMemDC, whdd->hDib);
280 }
281
282 if (ret)
283 {
284 whdd->hdc = hdc;
285 whdd->dxDst = dxDst;
286 whdd->dyDst = dyDst;
287 whdd->lpbi = HeapAlloc(GetProcessHeap(), 0, lpbi->biSize);
288 memcpy(whdd->lpbi, lpbi, lpbi->biSize);
289 whdd->dxSrc = dxSrc;
290 whdd->dySrc = dySrc;
291 whdd->begun = TRUE;
292 whdd->hpal = 0;
293 }
294 else
295 {
296 if (whdd->hic)
297 ICClose(whdd->hic);
298 HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
299 whdd->lpbiOut = NULL;
300 }
301
302 return ret;
303 }
304
305 /**********************************************************************
306 * DrawDibDraw [MSVFW32.@]
307 */
308 BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd, HDC hdc,
309 INT xDst, INT yDst, INT dxDst, INT dyDst,
310 LPBITMAPINFOHEADER lpbi,
311 LPVOID lpBits,
312 INT xSrc, INT ySrc, INT dxSrc, INT dySrc,
313 UINT wFlags)
314 {
315 WINE_HDD *whdd;
316 BOOL ret;
317 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
325 TRACE("whdd=%p\n", whdd);
326
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 if (!lpBits)
331 {
332 /* Undocumented? */
333 lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(num_colours(lpbi)*sizeof(RGBQUAD));
334 }
335
336
337 #define CHANGED(x) (whdd->x != x)
338
339 /* Check if anything changed from the parameters passed and our struct.
340 * If anything changed we need to run DrawDibBegin again to ensure we
341 * can support the changes.
342 */
343 if (!whdd->begun)
344 reopen = 1;
345 else if (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc))
346 reopen = 2;
347 else if (!(wFlags & DDF_SAME_DRAW))
348 {
349 if (CHANGED(lpbi) && memcmp(lpbi, whdd->lpbi, sizeof(*lpbi))) reopen = 3;
350 else if (CHANGED(dxSrc)) reopen = 4;
351 else if (CHANGED(dySrc)) reopen = 5;
352 else if (CHANGED(dxDst)) reopen = 6;
353 else if (CHANGED(dyDst)) reopen = 7;
354 }
355 if (reopen)
356 {
357 TRACE("Something changed (reason %d)!\n", reopen);
358 ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
359 if (!ret)
360 return ret;
361 }
362
363 #undef CHANGED
364
365 /* If source dimensions are not specified derive them from bitmap header */
366 if (dxSrc == -1 && dySrc == -1)
367 {
368 dxSrc = lpbi->biWidth;
369 dySrc = lpbi->biHeight;
370 }
371 /* If destination dimensions are not specified derive them from source */
372 if (dxDst == -1 && dyDst == -1)
373 {
374 dxDst = dxSrc;
375 dyDst = dySrc;
376 }
377
378 if (!(wFlags & DDF_UPDATE))
379 {
380 if (lpbi->biCompression)
381 {
382 DWORD flags = 0;
383
384 TRACE("Compression == 0x%08x\n", lpbi->biCompression);
385
386 if (wFlags & DDF_NOTKEYFRAME)
387 flags |= ICDECOMPRESS_NOTKEYFRAME;
388
389 ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
390 }
391 else
392 {
393 /* BI_RGB: lpbi->biSizeImage isn't reliable */
394 DWORD biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
395 memcpy(whdd->lpvbits, lpBits, biSizeImage);
396 }
397 }
398 if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
399 {
400 if ((wFlags & DDF_BACKGROUNDPAL) && ! (wFlags & DDF_SAME_HDC))
401 SelectPalette(hdc, whdd->hpal, TRUE);
402 else
403 SelectPalette(hdc, whdd->hpal, FALSE);
404 }
405
406 ret = StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY);
407 TRACE("Painting %dx%d at %d,%d from %dx%d at %d,%d -> %d\n",
408 dxDst, dyDst, xDst, yDst, dxSrc, dySrc, xSrc, ySrc, ret);
409
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 return TRUE;
419 }
420
421 /*************************************************************************
422 * DrawDibStop [MSVFW32.@]
423 */
424 BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
425 FIXME("(%p), stub\n", hdd);
426 return TRUE;
427 }
428
429 /***********************************************************************
430 * DrawDibChangePalette [MSVFW32.@]
431 */
432 BOOL VFWAPI DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe)
433 {
434 FIXME("(%p, 0x%08x, 0x%08x, %p), stub\n", hdd, iStart, iLen, lppe);
435 return TRUE;
436 }
437
438 /***********************************************************************
439 * DrawDibSetPalette [MSVFW32.@]
440 */
441 BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal)
442 {
443 WINE_HDD *whdd;
444
445 TRACE("(%p, %p)\n", hdd, hpal);
446
447 whdd = MSVIDEO_GetHddPtr(hdd);
448 if (!whdd) return FALSE;
449
450 whdd->hpal = hpal;
451
452 if (whdd->begun)
453 {
454 SelectPalette(whdd->hdc, hpal, 0);
455 RealizePalette(whdd->hdc);
456 }
457
458 return TRUE;
459 }
460
461 /***********************************************************************
462 * DrawDibGetBuffer [MSVFW32.@]
463 */
464 LPVOID VFWAPI DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags)
465 {
466 FIXME("(%p, %p, 0x%08x, 0x%08x), stub\n", hdd, lpbi, dwSize, dwFlags);
467 return NULL;
468 }
469
470 /***********************************************************************
471 * DrawDibGetPalette [MSVFW32.@]
472 */
473 HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd)
474 {
475 WINE_HDD *whdd;
476
477 TRACE("(%p)\n", hdd);
478
479 whdd = MSVIDEO_GetHddPtr(hdd);
480 if (!whdd) return FALSE;
481
482 return whdd->hpal;
483 }
484
485 /***********************************************************************
486 * DrawDibRealize [MSVFW32.@]
487 */
488 UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground)
489 {
490 WINE_HDD *whdd;
491 UINT ret = 0;
492
493 FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
494
495 whdd = MSVIDEO_GetHddPtr(hdd);
496 if (!whdd) return FALSE;
497
498 if (!whdd->begun)
499 {
500 ret = 0;
501 goto out;
502 }
503
504 if (!whdd->hpal)
505 whdd->hpal = CreateHalftonePalette(hdc);
506
507 SelectPalette(hdc, whdd->hpal, fBackground);
508 ret = RealizePalette(hdc);
509
510 out:
511 TRACE("=> %u\n", ret);
512 return ret;
513 }
514
515 /***********************************************************************
516 * DrawDibTime [MSVFW32.@]
517 */
518 BOOL VFWAPI DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime)
519 {
520 FIXME("(%p, %p) stub\n", hdd, lpddtime);
521 return FALSE;
522 }
523
524 /***********************************************************************
525 * DrawDibProfileDisplay [MSVFW32.@]
526 */
527 DWORD VFWAPI DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi)
528 {
529 FIXME("(%p) stub\n", lpbi);
530
531 return PD_CAN_DRAW_DIB;
532 }