Create the AHCI branch for Aman's work
[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;
307 int reopen = 0;
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 /* Check if anything changed from the parameters passed and our struct.
330 * If anything changed we need to run DrawDibBegin again to ensure we
331 * can support the changes.
332 */
333 if (!whdd->begun)
334 reopen = 1;
335 else if (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc))
336 reopen = 2;
337 else if (!(wFlags & DDF_SAME_DRAW))
338 {
339 if (CHANGED(lpbi) && memcmp(lpbi, whdd->lpbi, sizeof(*lpbi))) reopen = 3;
340 else if (CHANGED(dxSrc)) reopen = 4;
341 else if (CHANGED(dySrc)) reopen = 5;
342 else if (CHANGED(dxDst)) reopen = 6;
343 else if (CHANGED(dyDst)) reopen = 7;
344 }
345 if (reopen)
346 {
347 TRACE("Something changed (reason %d)!\n", reopen);
348 ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
349 if (!ret)
350 return ret;
351 }
352
353 #undef CHANGED
354
355 /* If source dimensions are not specified derive them from bitmap header */
356 if (dxSrc == -1 && dySrc == -1)
357 {
358 dxSrc = lpbi->biWidth;
359 dySrc = lpbi->biHeight;
360 }
361 /* If destination dimensions are not specified derive them from source */
362 if (dxDst == -1 && dyDst == -1)
363 {
364 dxDst = dxSrc;
365 dyDst = dySrc;
366 }
367
368 if (!(wFlags & DDF_UPDATE))
369 {
370 if (lpbi->biCompression)
371 {
372 DWORD flags = 0;
373
374 TRACE("Compression == 0x%08x\n", lpbi->biCompression);
375
376 if (wFlags & DDF_NOTKEYFRAME)
377 flags |= ICDECOMPRESS_NOTKEYFRAME;
378
379 ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
380 }
381 else
382 {
383 /* BI_RGB: lpbi->biSizeImage isn't reliable */
384 DWORD biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
385 memcpy(whdd->lpvbits, lpBits, biSizeImage);
386 }
387 }
388 if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
389 {
390 if ((wFlags & DDF_BACKGROUNDPAL) && ! (wFlags & DDF_SAME_HDC))
391 SelectPalette(hdc, whdd->hpal, TRUE);
392 else
393 SelectPalette(hdc, whdd->hpal, FALSE);
394 }
395
396 ret = StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY);
397 TRACE("Painting %dx%d at %d,%d from %dx%d at %d,%d -> %d\n",
398 dxDst, dyDst, xDst, yDst, dxSrc, dySrc, xSrc, ySrc, ret);
399
400 return ret;
401 }
402
403 /*************************************************************************
404 * DrawDibStart [MSVFW32.@]
405 */
406 BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
407 FIXME("(%p, %d), stub\n", hdd, rate);
408 return TRUE;
409 }
410
411 /*************************************************************************
412 * DrawDibStop [MSVFW32.@]
413 */
414 BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
415 FIXME("(%p), stub\n", hdd);
416 return TRUE;
417 }
418
419 /***********************************************************************
420 * DrawDibChangePalette [MSVFW32.@]
421 */
422 BOOL VFWAPI DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe)
423 {
424 FIXME("(%p, 0x%08x, 0x%08x, %p), stub\n", hdd, iStart, iLen, lppe);
425 return TRUE;
426 }
427
428 /***********************************************************************
429 * DrawDibSetPalette [MSVFW32.@]
430 */
431 BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal)
432 {
433 WINE_HDD *whdd;
434
435 TRACE("(%p, %p)\n", hdd, hpal);
436
437 whdd = MSVIDEO_GetHddPtr(hdd);
438 if (!whdd) return FALSE;
439
440 whdd->hpal = hpal;
441
442 if (whdd->begun)
443 {
444 SelectPalette(whdd->hdc, hpal, 0);
445 RealizePalette(whdd->hdc);
446 }
447
448 return TRUE;
449 }
450
451 /***********************************************************************
452 * DrawDibGetBuffer [MSVFW32.@]
453 */
454 LPVOID VFWAPI DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags)
455 {
456 FIXME("(%p, %p, 0x%08x, 0x%08x), stub\n", hdd, lpbi, dwSize, dwFlags);
457 return NULL;
458 }
459
460 /***********************************************************************
461 * DrawDibGetPalette [MSVFW32.@]
462 */
463 HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd)
464 {
465 WINE_HDD *whdd;
466
467 TRACE("(%p)\n", hdd);
468
469 whdd = MSVIDEO_GetHddPtr(hdd);
470 if (!whdd) return FALSE;
471
472 return whdd->hpal;
473 }
474
475 /***********************************************************************
476 * DrawDibRealize [MSVFW32.@]
477 */
478 UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground)
479 {
480 WINE_HDD *whdd;
481 UINT ret = 0;
482
483 FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
484
485 whdd = MSVIDEO_GetHddPtr(hdd);
486 if (!whdd) return FALSE;
487
488 if (!whdd->begun)
489 {
490 ret = 0;
491 goto out;
492 }
493
494 if (!whdd->hpal)
495 whdd->hpal = CreateHalftonePalette(hdc);
496
497 SelectPalette(hdc, whdd->hpal, fBackground);
498 ret = RealizePalette(hdc);
499
500 out:
501 TRACE("=> %u\n", ret);
502 return ret;
503 }
504
505 /***********************************************************************
506 * DrawDibTime [MSVFW32.@]
507 */
508 BOOL VFWAPI DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime)
509 {
510 FIXME("(%p, %p) stub\n", hdd, lpddtime);
511 return FALSE;
512 }
513
514 /***********************************************************************
515 * DrawDibProfileDisplay [MSVFW32.@]
516 */
517 DWORD VFWAPI DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi)
518 {
519 FIXME("(%p) stub\n", lpbi);
520
521 return PD_CAN_DRAW_DIB;
522 }