wined3d: Add hardware cursor support.
[wine] / dlls / 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 DWORD 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     whdd->hpal = 0; /* Do not free this */
137     whdd->hdc = 0;
138     HeapFree(GetProcessHeap(), 0, whdd->lpbi);
139     whdd->lpbi = NULL;
140     HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
141     whdd->lpbiOut = NULL;
142
143     whdd->begun = FALSE;
144
145     /*if (whdd->lpvbits)
146       HeapFree(GetProcessHeap(), 0, whdd->lpvbuf);*/
147
148     if (whdd->hMemDC) 
149     {
150         SelectObject(whdd->hMemDC, whdd->hOldDib);
151         DeleteDC(whdd->hMemDC);
152         whdd->hMemDC = 0;
153     }
154
155     if (whdd->hDib) DeleteObject(whdd->hDib);
156     whdd->hDib = 0;
157
158     if (whdd->hic) 
159     {
160         ICDecompressEnd(whdd->hic);
161         ICClose(whdd->hic);
162         whdd->hic = 0;
163     }
164
165     whdd->lpvbits = NULL;
166
167     return ret;
168 }
169
170 /***********************************************************************
171  *              DrawDibBegin            [MSVFW32.@]
172  */
173 BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
174                          HDC      hdc,
175                          INT      dxDst,
176                          INT      dyDst,
177                          LPBITMAPINFOHEADER lpbi,
178                          INT      dxSrc,
179                          INT      dySrc,
180                          UINT     wFlags) 
181 {
182     BOOL ret = TRUE;
183     WINE_HDD *whdd;
184
185     TRACE("(%p,%p,%d,%d,%p,%d,%d,0x%08x)\n",
186           hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, (DWORD)wFlags);
187
188     TRACE("lpbi: %d,%d/%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
189           lpbi->biSize, lpbi->biWidth, lpbi->biHeight, lpbi->biPlanes,
190           lpbi->biBitCount, lpbi->biCompression, lpbi->biSizeImage,
191           lpbi->biXPelsPerMeter, lpbi->biYPelsPerMeter, lpbi->biClrUsed,
192           lpbi->biClrImportant);
193
194     if (wFlags & ~(DDF_BUFFER))
195         FIXME("wFlags == 0x%08x not handled\n", wFlags & ~(DDF_BUFFER));
196
197     whdd = MSVIDEO_GetHddPtr(hdd);
198     if (!whdd) return FALSE;
199
200     if (whdd->begun) DrawDibEnd(hdd);
201
202     if (lpbi->biCompression) 
203     {
204         DWORD size = 0;
205
206         whdd->hic = ICOpen(ICTYPE_VIDEO, lpbi->biCompression, ICMODE_DECOMPRESS);
207         if (!whdd->hic) 
208         {
209             WARN("Could not open IC. biCompression == 0x%08x\n", lpbi->biCompression);
210             ret = FALSE;
211         }
212
213         if (ret) 
214         {
215             size = ICDecompressGetFormat(whdd->hic, lpbi, NULL);
216             if (size == ICERR_UNSUPPORTED) 
217             {
218                 WARN("Codec doesn't support GetFormat, giving up.\n");
219                 ret = FALSE;
220             }
221         }
222
223         if (ret) 
224         {
225             whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, size);
226
227             if (ICDecompressGetFormat(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
228                 ret = FALSE;
229         }
230
231         if (ret) 
232         {
233             /* FIXME: Use Ex functions if available? */
234             if (ICDecompressBegin(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
235                 ret = FALSE;
236             
237             TRACE("biSizeImage == %d\n", whdd->lpbiOut->biSizeImage);
238             TRACE("biCompression == %d\n", whdd->lpbiOut->biCompression);
239             TRACE("biBitCount == %d\n", whdd->lpbiOut->biBitCount);
240         }
241     }
242     else 
243     {
244         DWORD dwSize;
245         /* No compression */
246         TRACE("Not compressed!\n");
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     if (ret) 
253     {
254         /*whdd->lpvbuf = HeapAlloc(GetProcessHeap(), 0, whdd->lpbiOut->biSizeImage);*/
255
256         whdd->hMemDC = CreateCompatibleDC(hdc);
257         TRACE("Creating: %d, %p\n", whdd->lpbiOut->biSize, whdd->lpvbits);
258         whdd->hDib = CreateDIBSection(whdd->hMemDC, (BITMAPINFO *)whdd->lpbiOut, DIB_RGB_COLORS, &(whdd->lpvbits), 0, 0);
259         if (whdd->hDib) 
260         {
261             TRACE("Created: %p,%p\n", whdd->hDib, whdd->lpvbits);
262         }
263         else
264         {
265             ret = FALSE;
266             TRACE("Error: %d\n", GetLastError());
267         }
268         whdd->hOldDib = SelectObject(whdd->hMemDC, whdd->hDib);
269     }
270
271     if (ret) 
272     {
273         whdd->hdc = hdc;
274         whdd->dxDst = dxDst;
275         whdd->dyDst = dyDst;
276         whdd->lpbi = HeapAlloc(GetProcessHeap(), 0, lpbi->biSize);
277         memcpy(whdd->lpbi, lpbi, lpbi->biSize);
278         whdd->dxSrc = dxSrc;
279         whdd->dySrc = dySrc;
280         whdd->begun = TRUE;
281         whdd->hpal = 0;
282     } 
283     else 
284     {
285         if (whdd->hic)
286             ICClose(whdd->hic);
287         HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
288         whdd->lpbiOut = NULL;
289     }
290
291     return ret;
292 }
293
294 /**********************************************************************
295  *              DrawDibDraw             [MSVFW32.@]
296  */
297 BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd, HDC hdc,
298                         INT xDst, INT yDst, INT dxDst, INT dyDst,
299                         LPBITMAPINFOHEADER lpbi,
300                         LPVOID lpBits,
301                         INT xSrc, INT ySrc, INT dxSrc, INT dySrc,
302                         UINT wFlags)
303 {
304     WINE_HDD *whdd;
305     BOOL ret = TRUE;
306
307     TRACE("(%p,%p,%d,%d,%d,%d,%p,%p,%d,%d,%d,%d,0x%08x)\n",
308           hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, (DWORD)wFlags);
309
310     whdd = MSVIDEO_GetHddPtr(hdd);
311     if (!whdd) return FALSE;
312
313     TRACE("whdd=%p\n", whdd);
314
315     if (wFlags & ~(DDF_SAME_HDC | DDF_SAME_DRAW | DDF_NOTKEYFRAME | DDF_UPDATE | DDF_DONTDRAW | DDF_BACKGROUNDPAL))
316         FIXME("wFlags == 0x%08x not handled\n", (DWORD)wFlags);
317
318     if (!lpBits) 
319     {
320         /* Undocumented? */
321         lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(num_colours(lpbi)*sizeof(RGBQUAD));
322     }
323
324
325 #define CHANGED(x) (whdd->x != x)
326
327     if ((!whdd->begun) || 
328         (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc)) || 
329         (!(wFlags & DDF_SAME_DRAW) && (CHANGED(lpbi) || CHANGED(dxSrc) || CHANGED(dySrc) || CHANGED(dxDst) || CHANGED(dyDst)))) 
330     {
331         TRACE("Something changed!\n");
332         ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
333     }
334
335 #undef CHANGED
336
337     if ((dxDst == -1) && (dyDst == -1)) 
338     {
339         dxDst = dxSrc;
340         dyDst = dySrc;
341     }
342
343     if (!(wFlags & DDF_UPDATE)) 
344     {
345         DWORD biSizeImage = lpbi->biSizeImage;
346
347         /* biSizeImage may be set to 0 for BI_RGB (uncompressed) bitmaps */
348         if ((lpbi->biCompression == BI_RGB) && (biSizeImage == 0))
349             biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
350
351         if (lpbi->biCompression) 
352         {
353             DWORD flags = 0;
354
355             TRACE("Compression == 0x%08x\n", lpbi->biCompression);
356
357             if (wFlags & DDF_NOTKEYFRAME)
358                 flags |= ICDECOMPRESS_NOTKEYFRAME;
359
360             ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
361         }
362         else
363         {
364             memcpy(whdd->lpvbits, lpBits, biSizeImage);
365         }
366     }
367     if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
368     {
369         if ((wFlags & DDF_BACKGROUNDPAL) && ! (wFlags & DDF_SAME_HDC))
370          SelectPalette(hdc, whdd->hpal, TRUE);
371         else
372          SelectPalette(hdc, whdd->hpal, FALSE);
373     }
374
375     if (!(StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY)))
376         ret = FALSE;
377     
378     return ret;
379 }
380
381 /*************************************************************************
382  *              DrawDibStart            [MSVFW32.@]
383  */
384 BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
385         FIXME("(%p, %d), stub\n", hdd, rate);
386         return TRUE;
387 }
388
389 /*************************************************************************
390  *              DrawDibStop             [MSVFW32.@]
391  */
392 BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
393         FIXME("(%p), stub\n", hdd);
394         return TRUE;
395 }
396
397 /***********************************************************************
398  *              DrawDibChangePalette       [MSVFW32.@]
399  */
400 BOOL VFWAPI DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe)
401 {
402     FIXME("(%p, 0x%08x, 0x%08x, %p), stub\n", hdd, iStart, iLen, lppe);
403     return TRUE;
404 }
405
406 /***********************************************************************
407  *              DrawDibSetPalette       [MSVFW32.@]
408  */
409 BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal) 
410 {
411     WINE_HDD *whdd;
412
413     TRACE("(%p, %p)\n", hdd, hpal);
414
415     whdd = MSVIDEO_GetHddPtr(hdd);
416     if (!whdd) return FALSE;
417
418     whdd->hpal = hpal;
419
420     if (whdd->begun) 
421     {
422         SelectPalette(whdd->hdc, hpal, 0);
423         RealizePalette(whdd->hdc);
424     }
425
426     return TRUE;
427 }
428
429 /***********************************************************************
430  *              DrawDibGetBuffer       [MSVFW32.@]
431  */
432 LPVOID VFWAPI DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags)
433 {
434     FIXME("(%p, %p, 0x%08x, 0x%08x), stub\n", hdd, lpbi, dwSize, dwFlags);
435     return NULL;
436 }
437
438 /***********************************************************************
439  *              DrawDibGetPalette       [MSVFW32.@]
440  */
441 HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd) 
442 {
443     WINE_HDD *whdd;
444
445     TRACE("(%p)\n", hdd);
446
447     whdd = MSVIDEO_GetHddPtr(hdd);
448     if (!whdd) return FALSE;
449
450     return whdd->hpal;
451 }
452
453 /***********************************************************************
454  *              DrawDibRealize          [MSVFW32.@]
455  */
456 UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground) 
457 {
458     WINE_HDD *whdd;
459     HPALETTE oldPal;
460     UINT ret = 0;
461
462     FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
463
464     whdd = MSVIDEO_GetHddPtr(hdd);
465     if (!whdd) return FALSE;
466
467     if (!whdd || !(whdd->begun)) 
468     {
469         ret = 0;
470         goto out;
471     }
472
473     if (!whdd->hpal)
474         whdd->hpal = CreateHalftonePalette(hdc);
475
476     oldPal = SelectPalette(hdc, whdd->hpal, fBackground);
477     ret = RealizePalette(hdc);
478
479  out:
480     TRACE("=> %u\n", ret);
481     return ret;
482 }
483
484 /***********************************************************************
485  *              DrawDibTime          [MSVFW32.@]
486  */
487 BOOL VFWAPI DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime)
488 {
489     FIXME("(%p, %p) stub\n", hdd, lpddtime);
490     return FALSE;
491 }
492
493 /***********************************************************************
494  *              DrawDibProfileDisplay          [MSVFW32.@]
495  */
496 DWORD VFWAPI DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi)
497 {
498     FIXME("(%p) stub\n", lpbi);
499
500     return PD_CAN_DRAW_DIB;
501 }