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