Use the same 8/16bit conversion routines as in pcmconverter.c.
[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     if (whdd->lpbi) 
135     {
136         HeapFree(GetProcessHeap(), 0, whdd->lpbi);
137         whdd->lpbi = NULL;
138     }
139     if (whdd->lpbiOut) 
140     {
141         HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
142         whdd->lpbiOut = NULL;
143     }
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%08lx)\n",
188           hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, (DWORD)wFlags);
189
190     TRACE("lpbi: %ld,%ld/%ld,%d,%d,%ld,%ld,%ld,%ld,%ld,%ld\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%08lx\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 == %ld\n", whdd->lpbiOut->biSizeImage);
240             TRACE("biCompression == %ld\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: %ld, %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("Error: %ld\n", GetLastError());
264         }
265         TRACE("Created: %p,%p\n", whdd->hDib, whdd->lpvbits);
266         whdd->hOldDib = SelectObject(whdd->hMemDC, whdd->hDib);
267     }
268
269     if (ret) 
270     {
271         whdd->hdc = hdc;
272         whdd->dxDst = dxDst;
273         whdd->dyDst = dyDst;
274         whdd->lpbi = HeapAlloc(GetProcessHeap(), 0, lpbi->biSize);
275         memcpy(whdd->lpbi, lpbi, lpbi->biSize);
276         whdd->dxSrc = dxSrc;
277         whdd->dySrc = dySrc;
278         whdd->begun = TRUE;
279         whdd->hpal = 0;
280     } 
281     else 
282     {
283         if (whdd->hic)
284             ICClose(whdd->hic);
285         if (whdd->lpbiOut) 
286         {
287             HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
288             whdd->lpbiOut = NULL;
289         }
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%08lx)\n",
309           hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, (DWORD)wFlags);
310
311     whdd = MSVIDEO_GetHddPtr(hdd);
312     if (!whdd) return FALSE;
313
314     if (wFlags & ~(DDF_SAME_HDC | DDF_SAME_DRAW | DDF_NOTKEYFRAME | DDF_UPDATE | DDF_DONTDRAW))
315         FIXME("wFlags == 0x%08lx not handled\n", (DWORD)wFlags);
316
317     if (!lpBits) 
318     {
319         /* Undocumented? */
320         lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(num_colours(lpbi)*sizeof(RGBQUAD));
321     }
322
323
324 #define CHANGED(x) (whdd->x != x)
325
326     if ((!whdd->begun) || 
327         (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc)) || 
328         (!(wFlags & DDF_SAME_DRAW) && (CHANGED(lpbi) || CHANGED(dxSrc) || CHANGED(dySrc) || CHANGED(dxDst) || CHANGED(dyDst)))) 
329     {
330         TRACE("Something changed!\n");
331         ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
332     }
333
334 #undef CHANGED
335
336     if ((dxDst == -1) && (dyDst == -1)) 
337     {
338         dxDst = dxSrc;
339         dyDst = dySrc;
340     }
341
342     if (!(wFlags & DDF_UPDATE)) 
343     {
344         /* biSizeImage may be set to 0 for BI_RGB (uncompressed) bitmaps */
345         if ((lpbi->biCompression == BI_RGB) && (lpbi->biSizeImage == 0))
346             lpbi->biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
347
348         if (lpbi->biCompression) 
349         {
350             DWORD flags = 0;
351
352             TRACE("Compression == 0x%08lx\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             memcpy(whdd->lpvbits, lpBits, lpbi->biSizeImage);
362         }
363     }
364     if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
365         SelectPalette(hdc, whdd->hpal, FALSE);
366
367     if (!(StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY)))
368         ret = FALSE;
369     
370     return ret;
371 }
372
373 /*************************************************************************
374  *              DrawDibStart            [MSVFW32.@]
375  */
376 BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
377         FIXME("(%p, %ld), stub\n", hdd, rate);
378         return TRUE;
379 }
380
381 /*************************************************************************
382  *              DrawDibStop             [MSVFW32.@]
383  */
384 BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
385         FIXME("(%p), stub\n", hdd);
386         return TRUE;
387 }
388
389 /***********************************************************************
390  *              DrawDibSetPalette       [MSVFW32.@]
391  */
392 BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal) 
393 {
394     WINE_HDD *whdd;
395
396     TRACE("(%p, %p)\n", hdd, hpal);
397
398     whdd = MSVIDEO_GetHddPtr(hdd);
399     if (!whdd) return FALSE;
400
401     whdd->hpal = hpal;
402
403     if (whdd->begun) 
404     {
405         SelectPalette(whdd->hdc, hpal, 0);
406         RealizePalette(whdd->hdc);
407     }
408
409     return TRUE;
410 }
411
412 /***********************************************************************
413  *              DrawDibGetPalette       [MSVFW32.@]
414  */
415 HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd) 
416 {
417     WINE_HDD *whdd;
418
419     TRACE("(%p)\n", hdd);
420
421     whdd = MSVIDEO_GetHddPtr(hdd);
422     if (!whdd) return FALSE;
423
424     return whdd->hpal;
425 }
426
427 /***********************************************************************
428  *              DrawDibRealize          [MSVFW32.@]
429  */
430 UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground) 
431 {
432     WINE_HDD *whdd;
433     HPALETTE oldPal;
434     UINT ret = 0;
435
436     FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
437
438     whdd = MSVIDEO_GetHddPtr(hdd);
439     if (!whdd) return FALSE;
440
441     if (!whdd || !(whdd->begun)) 
442     {
443         ret = 0;
444         goto out;
445     }
446
447     if (!whdd->hpal)
448         whdd->hpal = CreateHalftonePalette(hdc);
449
450     oldPal = SelectPalette(hdc, whdd->hpal, fBackground);
451     ret = RealizePalette(hdc);
452
453  out:
454     TRACE("=> %u\n", ret);
455     return ret;
456 }