* Sync up to trunk head (r65074).
[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 "msvideo_private.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
26
27 typedef struct tagWINE_HDD {
28 HDC hdc;
29 INT dxDst;
30 INT dyDst;
31 LPBITMAPINFOHEADER lpbi;
32 INT dxSrc;
33 INT dySrc;
34 HPALETTE hpal; /* Palette to use for the DIB */
35 BOOL begun; /* DrawDibBegin has been called */
36 LPBITMAPINFOHEADER lpbiOut; /* Output format */
37 HIC hic; /* HIC for decompression */
38 HDC hMemDC; /* DC for buffering */
39 HBITMAP hOldDib; /* Original Dib */
40 HBITMAP hDib; /* DibSection */
41 LPVOID lpvbits; /* Buffer for holding decompressed dib */
42 HDRAWDIB hSelf;
43 struct tagWINE_HDD* next;
44 } WINE_HDD;
45
46 static int num_colours(const BITMAPINFOHEADER *lpbi)
47 {
48 if(lpbi->biClrUsed)
49 return lpbi->biClrUsed;
50 if(lpbi->biBitCount<=8)
51 return 1<<lpbi->biBitCount;
52 return 0;
53 }
54
55 static WINE_HDD* HDD_FirstHdd /* = NULL */;
56
57 static WINE_HDD* MSVIDEO_GetHddPtr(HDRAWDIB hd)
58 {
59 WINE_HDD* hdd;
60
61 for (hdd = HDD_FirstHdd; hdd != NULL && hdd->hSelf != hd; hdd = hdd->next);
62 return hdd;
63 }
64
65 static UINT_PTR HDD_HandleRef = 1;
66
67 /***********************************************************************
68 * DrawDibOpen [MSVFW32.@]
69 */
70 HDRAWDIB VFWAPI DrawDibOpen(void)
71 {
72 WINE_HDD* whdd;
73
74 TRACE("(void)\n");
75
76 whdd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_HDD));
77 TRACE("=> %p\n", whdd);
78
79 while (MSVIDEO_GetHddPtr((HDRAWDIB)HDD_HandleRef) != NULL) HDD_HandleRef++;
80 whdd->hSelf = (HDRAWDIB)HDD_HandleRef++;
81
82 whdd->next = HDD_FirstHdd;
83 HDD_FirstHdd = whdd;
84
85 return whdd->hSelf;
86 }
87
88 /***********************************************************************
89 * DrawDibClose [MSVFW32.@]
90 */
91 BOOL VFWAPI DrawDibClose(HDRAWDIB hdd)
92 {
93 WINE_HDD* whdd = MSVIDEO_GetHddPtr(hdd);
94 WINE_HDD** p;
95
96 TRACE("(%p)\n", hdd);
97
98 if (!whdd) return FALSE;
99
100 if (whdd->begun) DrawDibEnd(hdd);
101
102 for (p = &HDD_FirstHdd; *p != NULL; p = &((*p)->next))
103 {
104 if (*p == whdd)
105 {
106 *p = whdd->next;
107 break;
108 }
109 }
110
111 HeapFree(GetProcessHeap(), 0, whdd);
112
113 return TRUE;
114 }
115
116 /***********************************************************************
117 * DrawDibEnd [MSVFW32.@]
118 */
119 BOOL VFWAPI DrawDibEnd(HDRAWDIB hdd)
120 {
121 BOOL ret = TRUE;
122 WINE_HDD *whdd = MSVIDEO_GetHddPtr(hdd);
123
124 TRACE("(%p)\n", hdd);
125
126 if (!whdd) return FALSE;
127
128 whdd->hpal = 0; /* Do not free this */
129 whdd->hdc = 0;
130 HeapFree(GetProcessHeap(), 0, whdd->lpbi);
131 whdd->lpbi = NULL;
132 HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
133 whdd->lpbiOut = NULL;
134
135 whdd->begun = FALSE;
136
137 /*if (whdd->lpvbits)
138 HeapFree(GetProcessHeap(), 0, whdd->lpvbuf);*/
139
140 if (whdd->hMemDC)
141 {
142 SelectObject(whdd->hMemDC, whdd->hOldDib);
143 DeleteDC(whdd->hMemDC);
144 whdd->hMemDC = 0;
145 }
146
147 if (whdd->hDib) DeleteObject(whdd->hDib);
148 whdd->hDib = 0;
149
150 if (whdd->hic)
151 {
152 ICDecompressEnd(whdd->hic);
153 ICClose(whdd->hic);
154 whdd->hic = 0;
155 }
156
157 whdd->lpvbits = NULL;
158
159 return ret;
160 }
161
162 /***********************************************************************
163 * DrawDibBegin [MSVFW32.@]
164 */
165 BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
166 HDC hdc,
167 INT dxDst,
168 INT dyDst,
169 LPBITMAPINFOHEADER lpbi,
170 INT dxSrc,
171 INT dySrc,
172 UINT wFlags)
173 {
174 BOOL ret = TRUE;
175 WINE_HDD *whdd;
176
177 TRACE("(%p,%p,%d,%d,%p,%d,%d,0x%08x)\n",
178 hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, wFlags);
179
180 TRACE("lpbi: %d,%d/%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
181 lpbi->biSize, lpbi->biWidth, lpbi->biHeight, lpbi->biPlanes,
182 lpbi->biBitCount, lpbi->biCompression, lpbi->biSizeImage,
183 lpbi->biXPelsPerMeter, lpbi->biYPelsPerMeter, lpbi->biClrUsed,
184 lpbi->biClrImportant);
185
186 if (wFlags & ~(DDF_BUFFER))
187 FIXME("wFlags == 0x%08x not handled\n", wFlags & ~(DDF_BUFFER));
188
189 whdd = MSVIDEO_GetHddPtr(hdd);
190 if (!whdd) return FALSE;
191
192 if (whdd->begun) DrawDibEnd(hdd);
193
194 if (lpbi->biCompression)
195 {
196 DWORD size = 0;
197
198 whdd->hic = ICOpen(ICTYPE_VIDEO, lpbi->biCompression, ICMODE_DECOMPRESS);
199 if (!whdd->hic)
200 {
201 WARN("Could not open IC. biCompression == 0x%08x\n", lpbi->biCompression);
202 ret = FALSE;
203 }
204
205 if (ret)
206 {
207 size = ICDecompressGetFormat(whdd->hic, lpbi, NULL);
208 if (size == ICERR_UNSUPPORTED)
209 {
210 WARN("Codec doesn't support GetFormat, giving up.\n");
211 ret = FALSE;
212 }
213 }
214
215 if (ret)
216 {
217 whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, size);
218
219 if (ICDecompressGetFormat(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
220 ret = FALSE;
221 }
222
223 if (ret)
224 {
225 /* FIXME: Use Ex functions if available? */
226 if (ICDecompressBegin(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
227 ret = FALSE;
228
229 TRACE("biSizeImage == %d\n", whdd->lpbiOut->biSizeImage);
230 TRACE("biCompression == %d\n", whdd->lpbiOut->biCompression);
231 TRACE("biBitCount == %d\n", whdd->lpbiOut->biBitCount);
232 }
233 }
234 else
235 {
236 DWORD dwSize;
237 /* No compression */
238 TRACE("Not compressed!\n");
239 if (lpbi->biHeight <= 0)
240 {
241 /* we don't draw inverted DIBs */
242 TRACE("detected inverted DIB\n");
243 ret = FALSE;
244 }
245 else
246 {
247 dwSize = lpbi->biSize + num_colours(lpbi)*sizeof(RGBQUAD);
248 whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, dwSize);
249 memcpy(whdd->lpbiOut, lpbi, dwSize);
250 }
251 }
252
253 if (ret)
254 {
255 /*whdd->lpvbuf = HeapAlloc(GetProcessHeap(), 0, whdd->lpbiOut->biSizeImage);*/
256
257 whdd->hMemDC = CreateCompatibleDC(hdc);
258 TRACE("Creating: %d, %p\n", whdd->lpbiOut->biSize, whdd->lpvbits);
259 whdd->hDib = CreateDIBSection(whdd->hMemDC, (BITMAPINFO *)whdd->lpbiOut, DIB_RGB_COLORS, &(whdd->lpvbits), 0, 0);
260 if (whdd->hDib)
261 {
262 TRACE("Created: %p,%p\n", whdd->hDib, whdd->lpvbits);
263 }
264 else
265 {
266 ret = FALSE;
267 TRACE("Error: %d\n", GetLastError());
268 }
269 whdd->hOldDib = SelectObject(whdd->hMemDC, whdd->hDib);
270 }
271
272 if (ret)
273 {
274 whdd->hdc = hdc;
275 whdd->dxDst = dxDst;
276 whdd->dyDst = dyDst;
277 whdd->lpbi = HeapAlloc(GetProcessHeap(), 0, lpbi->biSize);
278 memcpy(whdd->lpbi, lpbi, lpbi->biSize);
279 whdd->dxSrc = dxSrc;
280 whdd->dySrc = dySrc;
281 whdd->begun = TRUE;
282 whdd->hpal = 0;
283 }
284 else
285 {
286 if (whdd->hic)
287 ICClose(whdd->hic);
288 HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
289 whdd->lpbiOut = NULL;
290 }
291
292 return ret;
293 }
294
295 /**********************************************************************
296 * DrawDibDraw [MSVFW32.@]
297 */
298 BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd, HDC hdc,
299 INT xDst, INT yDst, INT dxDst, INT dyDst,
300 LPBITMAPINFOHEADER lpbi,
301 LPVOID lpBits,
302 INT xSrc, INT ySrc, INT dxSrc, INT dySrc,
303 UINT wFlags)
304 {
305 WINE_HDD *whdd;
306 BOOL ret = TRUE;
307
308 TRACE("(%p,%p,%d,%d,%d,%d,%p,%p,%d,%d,%d,%d,0x%08x)\n",
309 hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, wFlags);
310
311 whdd = MSVIDEO_GetHddPtr(hdd);
312 if (!whdd) return FALSE;
313
314 TRACE("whdd=%p\n", whdd);
315
316 if (wFlags & ~(DDF_SAME_HDC | DDF_SAME_DRAW | DDF_NOTKEYFRAME | DDF_UPDATE | DDF_DONTDRAW | DDF_BACKGROUNDPAL))
317 FIXME("wFlags == 0x%08x not handled\n", wFlags);
318
319 if (!lpBits)
320 {
321 /* Undocumented? */
322 lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(num_colours(lpbi)*sizeof(RGBQUAD));
323 }
324
325
326 #define CHANGED(x) (whdd->x != x)
327
328 if ((!whdd->begun) ||
329 (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc)) ||
330 (!(wFlags & DDF_SAME_DRAW) && (CHANGED(lpbi) || CHANGED(dxSrc) || CHANGED(dySrc) || CHANGED(dxDst) || CHANGED(dyDst))))
331 {
332 TRACE("Something changed!\n");
333 ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
334 if (!ret)
335 return ret;
336 }
337
338 #undef CHANGED
339
340 if ((dxDst == -1) && (dyDst == -1))
341 {
342 dxDst = dxSrc;
343 dyDst = dySrc;
344 }
345
346 if (!(wFlags & DDF_UPDATE))
347 {
348 if (lpbi->biCompression)
349 {
350 DWORD flags = 0;
351
352 TRACE("Compression == 0x%08x\n", lpbi->biCompression);
353
354 if (wFlags & DDF_NOTKEYFRAME)
355 flags |= ICDECOMPRESS_NOTKEYFRAME;
356
357 ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
358 }
359 else
360 {
361 /* BI_RGB: lpbi->biSizeImage isn't reliable */
362 DWORD biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
363 memcpy(whdd->lpvbits, lpBits, biSizeImage);
364 }
365 }
366 if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
367 {
368 if ((wFlags & DDF_BACKGROUNDPAL) && ! (wFlags & DDF_SAME_HDC))
369 SelectPalette(hdc, whdd->hpal, TRUE);
370 else
371 SelectPalette(hdc, whdd->hpal, FALSE);
372 }
373
374 if (!(StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY)))
375 ret = FALSE;
376
377 return ret;
378 }
379
380 /*************************************************************************
381 * DrawDibStart [MSVFW32.@]
382 */
383 BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
384 FIXME("(%p, %d), stub\n", hdd, rate);
385 return TRUE;
386 }
387
388 /*************************************************************************
389 * DrawDibStop [MSVFW32.@]
390 */
391 BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
392 FIXME("(%p), stub\n", hdd);
393 return TRUE;
394 }
395
396 /***********************************************************************
397 * DrawDibChangePalette [MSVFW32.@]
398 */
399 BOOL VFWAPI DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe)
400 {
401 FIXME("(%p, 0x%08x, 0x%08x, %p), stub\n", hdd, iStart, iLen, lppe);
402 return TRUE;
403 }
404
405 /***********************************************************************
406 * DrawDibSetPalette [MSVFW32.@]
407 */
408 BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal)
409 {
410 WINE_HDD *whdd;
411
412 TRACE("(%p, %p)\n", hdd, hpal);
413
414 whdd = MSVIDEO_GetHddPtr(hdd);
415 if (!whdd) return FALSE;
416
417 whdd->hpal = hpal;
418
419 if (whdd->begun)
420 {
421 SelectPalette(whdd->hdc, hpal, 0);
422 RealizePalette(whdd->hdc);
423 }
424
425 return TRUE;
426 }
427
428 /***********************************************************************
429 * DrawDibGetBuffer [MSVFW32.@]
430 */
431 LPVOID VFWAPI DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags)
432 {
433 FIXME("(%p, %p, 0x%08x, 0x%08x), stub\n", hdd, lpbi, dwSize, dwFlags);
434 return NULL;
435 }
436
437 /***********************************************************************
438 * DrawDibGetPalette [MSVFW32.@]
439 */
440 HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd)
441 {
442 WINE_HDD *whdd;
443
444 TRACE("(%p)\n", hdd);
445
446 whdd = MSVIDEO_GetHddPtr(hdd);
447 if (!whdd) return FALSE;
448
449 return whdd->hpal;
450 }
451
452 /***********************************************************************
453 * DrawDibRealize [MSVFW32.@]
454 */
455 UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground)
456 {
457 WINE_HDD *whdd;
458 UINT ret = 0;
459
460 FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
461
462 whdd = MSVIDEO_GetHddPtr(hdd);
463 if (!whdd) return FALSE;
464
465 if (!whdd || !(whdd->begun))
466 {
467 ret = 0;
468 goto out;
469 }
470
471 if (!whdd->hpal)
472 whdd->hpal = CreateHalftonePalette(hdc);
473
474 SelectPalette(hdc, whdd->hpal, fBackground);
475 ret = RealizePalette(hdc);
476
477 out:
478 TRACE("=> %u\n", ret);
479 return ret;
480 }
481
482 /***********************************************************************
483 * DrawDibTime [MSVFW32.@]
484 */
485 BOOL VFWAPI DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime)
486 {
487 FIXME("(%p, %p) stub\n", hdd, lpddtime);
488 return FALSE;
489 }
490
491 /***********************************************************************
492 * DrawDibProfileDisplay [MSVFW32.@]
493 */
494 DWORD VFWAPI DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi)
495 {
496 FIXME("(%p) stub\n", lpbi);
497
498 return PD_CAN_DRAW_DIB;
499 }