Sync with trunk head
[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 dwSize = lpbi->biSize + num_colours(lpbi)*sizeof(RGBQUAD);
250 whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, dwSize);
251 memcpy(whdd->lpbiOut, lpbi, dwSize);
252 }
253
254 if (ret)
255 {
256 /*whdd->lpvbuf = HeapAlloc(GetProcessHeap(), 0, whdd->lpbiOut->biSizeImage);*/
257
258 whdd->hMemDC = CreateCompatibleDC(hdc);
259 TRACE("Creating: %d, %p\n", whdd->lpbiOut->biSize, whdd->lpvbits);
260 whdd->hDib = CreateDIBSection(whdd->hMemDC, (BITMAPINFO *)whdd->lpbiOut, DIB_RGB_COLORS, &(whdd->lpvbits), 0, 0);
261 if (whdd->hDib)
262 {
263 TRACE("Created: %p,%p\n", whdd->hDib, whdd->lpvbits);
264 }
265 else
266 {
267 ret = FALSE;
268 TRACE("Error: %d\n", GetLastError());
269 }
270 whdd->hOldDib = SelectObject(whdd->hMemDC, whdd->hDib);
271 }
272
273 if (ret)
274 {
275 whdd->hdc = hdc;
276 whdd->dxDst = dxDst;
277 whdd->dyDst = dyDst;
278 whdd->lpbi = HeapAlloc(GetProcessHeap(), 0, lpbi->biSize);
279 memcpy(whdd->lpbi, lpbi, lpbi->biSize);
280 whdd->dxSrc = dxSrc;
281 whdd->dySrc = dySrc;
282 whdd->begun = TRUE;
283 whdd->hpal = 0;
284 }
285 else
286 {
287 if (whdd->hic)
288 ICClose(whdd->hic);
289 HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
290 whdd->lpbiOut = NULL;
291 }
292
293 return ret;
294 }
295
296 /**********************************************************************
297 * DrawDibDraw [MSVFW32.@]
298 */
299 BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd, HDC hdc,
300 INT xDst, INT yDst, INT dxDst, INT dyDst,
301 LPBITMAPINFOHEADER lpbi,
302 LPVOID lpBits,
303 INT xSrc, INT ySrc, INT dxSrc, INT dySrc,
304 UINT wFlags)
305 {
306 WINE_HDD *whdd;
307 BOOL ret = TRUE;
308
309 TRACE("(%p,%p,%d,%d,%d,%d,%p,%p,%d,%d,%d,%d,0x%08x)\n",
310 hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, wFlags);
311
312 whdd = MSVIDEO_GetHddPtr(hdd);
313 if (!whdd) return FALSE;
314
315 TRACE("whdd=%p\n", whdd);
316
317 if (wFlags & ~(DDF_SAME_HDC | DDF_SAME_DRAW | DDF_NOTKEYFRAME | DDF_UPDATE | DDF_DONTDRAW | DDF_BACKGROUNDPAL))
318 FIXME("wFlags == 0x%08x not handled\n", wFlags);
319
320 if (!lpBits)
321 {
322 /* Undocumented? */
323 lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(num_colours(lpbi)*sizeof(RGBQUAD));
324 }
325
326
327 #define CHANGED(x) (whdd->x != x)
328
329 if ((!whdd->begun) ||
330 (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc)) ||
331 (!(wFlags & DDF_SAME_DRAW) && (CHANGED(lpbi) || CHANGED(dxSrc) || CHANGED(dySrc) || CHANGED(dxDst) || CHANGED(dyDst))))
332 {
333 TRACE("Something changed!\n");
334 ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
335 }
336
337 #undef CHANGED
338
339 if ((dxDst == -1) && (dyDst == -1))
340 {
341 dxDst = dxSrc;
342 dyDst = dySrc;
343 }
344
345 if (!(wFlags & DDF_UPDATE))
346 {
347 DWORD biSizeImage = lpbi->biSizeImage;
348
349 /* biSizeImage may be set to 0 for BI_RGB (uncompressed) bitmaps */
350 if ((lpbi->biCompression == BI_RGB) && (biSizeImage == 0))
351 biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
352
353 if (lpbi->biCompression)
354 {
355 DWORD flags = 0;
356
357 TRACE("Compression == 0x%08x\n", lpbi->biCompression);
358
359 if (wFlags & DDF_NOTKEYFRAME)
360 flags |= ICDECOMPRESS_NOTKEYFRAME;
361
362 ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
363 }
364 else
365 {
366 memcpy(whdd->lpvbits, lpBits, biSizeImage);
367 }
368 }
369 if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
370 {
371 if ((wFlags & DDF_BACKGROUNDPAL) && ! (wFlags & DDF_SAME_HDC))
372 SelectPalette(hdc, whdd->hpal, TRUE);
373 else
374 SelectPalette(hdc, whdd->hpal, FALSE);
375 }
376
377 if (!(StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY)))
378 ret = FALSE;
379
380 return ret;
381 }
382
383 /*************************************************************************
384 * DrawDibStart [MSVFW32.@]
385 */
386 BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
387 FIXME("(%p, %d), stub\n", hdd, rate);
388 return TRUE;
389 }
390
391 /*************************************************************************
392 * DrawDibStop [MSVFW32.@]
393 */
394 BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
395 FIXME("(%p), stub\n", hdd);
396 return TRUE;
397 }
398
399 /***********************************************************************
400 * DrawDibChangePalette [MSVFW32.@]
401 */
402 BOOL VFWAPI DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe)
403 {
404 FIXME("(%p, 0x%08x, 0x%08x, %p), stub\n", hdd, iStart, iLen, lppe);
405 return TRUE;
406 }
407
408 /***********************************************************************
409 * DrawDibSetPalette [MSVFW32.@]
410 */
411 BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal)
412 {
413 WINE_HDD *whdd;
414
415 TRACE("(%p, %p)\n", hdd, hpal);
416
417 whdd = MSVIDEO_GetHddPtr(hdd);
418 if (!whdd) return FALSE;
419
420 whdd->hpal = hpal;
421
422 if (whdd->begun)
423 {
424 SelectPalette(whdd->hdc, hpal, 0);
425 RealizePalette(whdd->hdc);
426 }
427
428 return TRUE;
429 }
430
431 /***********************************************************************
432 * DrawDibGetBuffer [MSVFW32.@]
433 */
434 LPVOID VFWAPI DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags)
435 {
436 FIXME("(%p, %p, 0x%08x, 0x%08x), stub\n", hdd, lpbi, dwSize, dwFlags);
437 return NULL;
438 }
439
440 /***********************************************************************
441 * DrawDibGetPalette [MSVFW32.@]
442 */
443 HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd)
444 {
445 WINE_HDD *whdd;
446
447 TRACE("(%p)\n", hdd);
448
449 whdd = MSVIDEO_GetHddPtr(hdd);
450 if (!whdd) return FALSE;
451
452 return whdd->hpal;
453 }
454
455 /***********************************************************************
456 * DrawDibRealize [MSVFW32.@]
457 */
458 UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground)
459 {
460 WINE_HDD *whdd;
461 UINT ret = 0;
462
463 FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
464
465 whdd = MSVIDEO_GetHddPtr(hdd);
466 if (!whdd) return FALSE;
467
468 if (!whdd || !(whdd->begun))
469 {
470 ret = 0;
471 goto out;
472 }
473
474 if (!whdd->hpal)
475 whdd->hpal = CreateHalftonePalette(hdc);
476
477 SelectPalette(hdc, whdd->hpal, fBackground);
478 ret = RealizePalette(hdc);
479
480 out:
481 TRACE("=> %u\n", ret);
482 return ret;
483 }
484
485 /***********************************************************************
486 * DrawDibTime [MSVFW32.@]
487 */
488 BOOL VFWAPI DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime)
489 {
490 FIXME("(%p, %p) stub\n", hdd, lpddtime);
491 return FALSE;
492 }
493
494 /***********************************************************************
495 * DrawDibProfileDisplay [MSVFW32.@]
496 */
497 DWORD VFWAPI DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi)
498 {
499 FIXME("(%p) stub\n", lpbi);
500
501 return PD_CAN_DRAW_DIB;
502 }