Added regedit unit test, a couple minor changes to regedit.
[wine] / dlls / ddraw / dsurface / dib.c
1 /*              DIBSection DirectDrawSurface driver
2  *
3  * Copyright 1997-2000 Marcus Meissner
4  * Copyright 1998-2000 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "winerror.h"
28 #include "bitmap.h"
29 #include "wine/debug.h"
30 #include "ddraw_private.h"
31 #include "dsurface/main.h"
32 #include "dsurface/dib.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
35
36 static ICOM_VTABLE(IDirectDrawSurface7) DIB_IDirectDrawSurface7_VTable;
37
38 /* Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned. */
39 inline static int get_dib_width_bytes( int width, int depth )
40 {
41     int words;
42
43     switch(depth)
44     {
45     case 1:  words = (width + 31) / 32; break;
46     case 4:  words = (width + 7) / 8; break;
47     case 8:  words = (width + 3) / 4; break;
48     case 15:
49     case 16: words = (width + 1) / 2; break;
50     case 24: words = (width * 3 + 3)/4; break;
51     default:
52         WARN("(%d): Unsupported depth\n", depth );
53         /* fall through */
54     case 32: words = width; break;
55     }
56     return 4 * words;
57 }
58
59
60 static HRESULT create_dib(IDirectDrawSurfaceImpl* This)
61 {
62     BITMAPINFO* b_info;
63     UINT usage;
64     HDC ddc;
65     DIB_DirectDrawSurfaceImpl* priv = This->private;
66
67     assert(This->surface_desc.lpSurface != NULL);
68
69     switch (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount)
70     {
71     case 16:
72     case 32:
73         /* Allocate extra space to store the RGB bit masks. */
74         b_info = (BITMAPINFO*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
75                                         sizeof(BITMAPINFOHEADER)
76                                         + 3 * sizeof(DWORD));
77         break;
78
79     case 24:
80         b_info = (BITMAPINFO*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
81                                         sizeof(BITMAPINFOHEADER));
82         break;
83
84     default:
85         /* Allocate extra space for a palette. */
86         b_info = (BITMAPINFO*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
87                                         sizeof(BITMAPINFOHEADER)
88                                         + sizeof(RGBQUAD)
89                                         * (1 << This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount));
90         break;
91     }
92
93     b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
94     b_info->bmiHeader.biWidth = This->surface_desc.dwWidth;
95     b_info->bmiHeader.biHeight = -This->surface_desc.dwHeight;
96     b_info->bmiHeader.biPlanes = 1;
97     b_info->bmiHeader.biBitCount = This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount;
98
99     if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount != 16)
100         && (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount != 32))
101         b_info->bmiHeader.biCompression = BI_RGB;
102     else
103         b_info->bmiHeader.biCompression = BI_BITFIELDS;
104
105     b_info->bmiHeader.biSizeImage
106         = (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount / 8)
107         * This->surface_desc.dwWidth * This->surface_desc.dwHeight;
108
109     b_info->bmiHeader.biXPelsPerMeter = 0;
110     b_info->bmiHeader.biYPelsPerMeter = 0;
111     b_info->bmiHeader.biClrUsed = 0;
112     b_info->bmiHeader.biClrImportant = 0;
113
114     switch (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount)
115     {
116     case 16:
117     case 32:
118     {
119         DWORD *masks = (DWORD *) &(b_info->bmiColors);
120
121         usage = 0;
122         masks[0] = This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask;
123         masks[1] = This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask;
124         masks[2] = This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask;
125     }
126     break;
127
128     case 24:
129         /* Nothing to do */
130         usage = DIB_RGB_COLORS;
131         break;
132
133     default:
134         /* Don't know palette */
135         usage = 0;
136         break;
137     }
138
139     ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
140     if (ddc == 0)
141     {
142         HeapFree(GetProcessHeap(), 0, b_info);
143         return HRESULT_FROM_WIN32(GetLastError());
144     }
145
146     priv->dib.DIBsection
147         = DIB_CreateDIBSection(ddc, b_info, usage, &(priv->dib.bitmap_data), 0,
148                                (DWORD)This->surface_desc.lpSurface,
149                                This->surface_desc.u1.lPitch);
150     DeleteDC(ddc);
151     if (!priv->dib.DIBsection) {
152         ERR("CreateDIBSection failed!\n");
153         HeapFree(GetProcessHeap(), 0, b_info);
154         return HRESULT_FROM_WIN32(GetLastError());
155     }
156
157     TRACE("DIBSection at : %p\n", priv->dib.bitmap_data);
158     if (!This->surface_desc.u1.lPitch) {
159         /* This can't happen, right? */
160         /* or use GDI_GetObj to get it from the created DIB? */
161         This->surface_desc.u1.lPitch = get_dib_width_bytes(b_info->bmiHeader.biWidth, b_info->bmiHeader.biBitCount);
162         This->surface_desc.dwFlags |= DDSD_PITCH;
163     }
164
165     if (!This->surface_desc.lpSurface) {
166         This->surface_desc.lpSurface = priv->dib.bitmap_data;
167         This->surface_desc.dwFlags |= DDSD_LPSURFACE;
168     }
169
170     HeapFree(GetProcessHeap(), 0, b_info);
171
172     /* I don't think it's worth checking for this. */
173     if (priv->dib.bitmap_data != This->surface_desc.lpSurface)
174         ERR("unexpected error creating DirectDrawSurface DIB section\n");
175
176     /* this seems like a good place to put the handle for HAL driver use */
177     This->global_more.hKernelSurface = priv->dib.DIBsection;
178
179     return S_OK;
180 }
181
182 void DIB_DirectDrawSurface_final_release(IDirectDrawSurfaceImpl* This)
183 {
184     DIB_DirectDrawSurfaceImpl* priv = This->private;
185
186     DeleteObject(priv->dib.DIBsection);
187
188     if (!priv->dib.client_memory)
189         VirtualFree(This->surface_desc.lpSurface, 0, MEM_RELEASE);
190
191     Main_DirectDrawSurface_final_release(This);
192 }
193
194 HRESULT DIB_DirectDrawSurface_duplicate_surface(IDirectDrawSurfaceImpl* This,
195                                                 LPDIRECTDRAWSURFACE7* ppDup)
196 {
197     return DIB_DirectDrawSurface_Create(This->ddraw_owner,
198                                         &This->surface_desc, ppDup, NULL);
199 }
200
201 HRESULT DIB_DirectDrawSurface_Construct(IDirectDrawSurfaceImpl *This,
202                                         IDirectDrawImpl *pDD,
203                                         const DDSURFACEDESC2 *pDDSD)
204 {
205     HRESULT hr;
206     DIB_DirectDrawSurfaceImpl* priv = This->private;
207
208     TRACE("(%p)->(%p,%p)\n",This,pDD,pDDSD);
209     hr = Main_DirectDrawSurface_Construct(This, pDD, pDDSD);
210     if (FAILED(hr)) return hr;
211
212     ICOM_INIT_INTERFACE(This, IDirectDrawSurface7,
213                         DIB_IDirectDrawSurface7_VTable);
214
215     This->final_release = DIB_DirectDrawSurface_final_release;
216     This->duplicate_surface = DIB_DirectDrawSurface_duplicate_surface;
217     This->flip_data = DIB_DirectDrawSurface_flip_data;
218
219     This->get_dc     = DIB_DirectDrawSurface_get_dc;
220     This->release_dc = DIB_DirectDrawSurface_release_dc;
221     This->hDC = (HDC)NULL;
222
223     This->set_palette    = DIB_DirectDrawSurface_set_palette;
224     This->update_palette = DIB_DirectDrawSurface_update_palette;
225
226     TRACE("(%ldx%ld, pitch=%ld)\n",
227           This->surface_desc.dwWidth, This->surface_desc.dwHeight,
228           This->surface_desc.u1.lPitch);
229     /* XXX load dwWidth and dwHeight from pDD if they are not specified? */
230
231     if (This->surface_desc.dwFlags & DDSD_LPSURFACE)
232     {
233         /* "Client memory": it is managed by the application. */
234         /* XXX What if lPitch is not set? Use dwWidth or fail? */
235
236         priv->dib.client_memory = TRUE;
237     }
238     else
239     {
240         if (!(This->surface_desc.dwFlags & DDSD_PITCH))
241         {
242             int pitch = This->surface_desc.u1.lPitch;
243             if (pitch % 8 != 0)
244                 pitch += 8 - (pitch % 8);
245         }
246         /* XXX else: how should lPitch be verified? */
247
248         This->surface_desc.dwFlags |= DDSD_PITCH|DDSD_LPSURFACE;
249
250         This->surface_desc.lpSurface
251             = VirtualAlloc(NULL, This->surface_desc.u1.lPitch
252                            * This->surface_desc.dwHeight,
253                            MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
254
255         if (This->surface_desc.lpSurface == NULL)
256         {
257             Main_DirectDrawSurface_final_release(This);
258             return HRESULT_FROM_WIN32(GetLastError());
259         }
260
261         priv->dib.client_memory = FALSE;
262     }
263
264     hr = create_dib(This);
265     if (FAILED(hr))
266     {
267         if (!priv->dib.client_memory)
268             VirtualFree(This->surface_desc.lpSurface, 0, MEM_RELEASE);
269
270         Main_DirectDrawSurface_final_release(This);
271
272         return hr;
273     }
274
275     return DD_OK;
276 }
277
278 /* Not an API */
279 HRESULT DIB_DirectDrawSurface_Create(IDirectDrawImpl *pDD,
280                                      const DDSURFACEDESC2 *pDDSD,
281                                      LPDIRECTDRAWSURFACE7 *ppSurf,
282                                      IUnknown *pUnkOuter)
283 {
284     IDirectDrawSurfaceImpl* This;
285     HRESULT hr;
286     assert(pUnkOuter == NULL);
287
288     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
289                      sizeof(*This) + sizeof(DIB_DirectDrawSurfaceImpl));
290     if (This == NULL) return E_OUTOFMEMORY;
291
292     This->private = (DIB_DirectDrawSurfaceImpl*)(This+1);
293
294     hr = DIB_DirectDrawSurface_Construct(This, pDD, pDDSD);
295     if (FAILED(hr))
296         HeapFree(GetProcessHeap(), 0, This);
297     else
298         *ppSurf = ICOM_INTERFACE(This, IDirectDrawSurface7);
299
300     return hr;
301
302 }
303
304 /* AddAttachedSurface: generic */
305 /* AddOverlayDirtyRect: generic, unimplemented */
306
307 static HRESULT _Blt_ColorFill(
308     LPBYTE buf, int width, int height, int bpp, LONG lPitch, DWORD color
309 ) {
310     int x, y;
311     LPBYTE first;
312
313     /* Do first row */
314
315 #define COLORFILL_ROW(type) { \
316     type *d = (type *) buf; \
317     for (x = 0; x < width; x++) \
318         d[x] = (type) color; \
319     break; \
320 }
321
322     switch(bpp) {
323     case 1: COLORFILL_ROW(BYTE)
324     case 2: COLORFILL_ROW(WORD)
325     case 4: COLORFILL_ROW(DWORD)
326     default:
327         FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
328         return DDERR_UNSUPPORTED;
329     }
330
331 #undef COLORFILL_ROW
332
333     /* Now copy first row */
334     first = buf;
335     for (y = 1; y < height; y++) {
336         buf += lPitch;
337         memcpy(buf, first, width * bpp);
338     }
339     return DD_OK;
340 }
341
342 HRESULT WINAPI
343 DIB_DirectDrawSurface_Blt(LPDIRECTDRAWSURFACE7 iface, LPRECT rdst,
344                           LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
345                           DWORD dwFlags, LPDDBLTFX lpbltfx)
346 {
347     ICOM_THIS(IDirectDrawSurfaceImpl,iface);
348     RECT                xdst,xsrc;
349     DDSURFACEDESC2      ddesc,sdesc;
350     HRESULT             ret = DD_OK;
351     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
352     int x, y;
353     LPBYTE dbuf, sbuf;
354
355     TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This,rdst,src,rsrc,dwFlags,lpbltfx);
356
357     DD_STRUCT_INIT(&ddesc);
358     DD_STRUCT_INIT(&sdesc);
359
360     sdesc.dwSize = sizeof(sdesc);
361     if (src) IDirectDrawSurface7_Lock(src, NULL, &sdesc, DDLOCK_READONLY, 0);
362     ddesc.dwSize = sizeof(ddesc);
363     IDirectDrawSurface7_Lock(iface,NULL,&ddesc,DDLOCK_WRITEONLY,0);
364
365     if (TRACE_ON(ddraw)) {
366         if (rdst) TRACE("\tdestrect :%dx%d-%dx%d\n",rdst->left,rdst->top,rdst->right,rdst->bottom);
367         if (rsrc) TRACE("\tsrcrect  :%dx%d-%dx%d\n",rsrc->left,rsrc->top,rsrc->right,rsrc->bottom);
368         TRACE("\tflags: ");
369         DDRAW_dump_DDBLT(dwFlags);
370         if (dwFlags & DDBLT_DDFX) {
371             TRACE("\tblitfx: ");
372             DDRAW_dump_DDBLTFX(lpbltfx->dwDDFX);
373         }
374     }
375
376     if (rdst) {
377         if ((rdst->top < 0) ||
378             (rdst->left < 0) ||
379             (rdst->bottom < 0) ||
380             (rdst->right < 0)) {
381           ERR(" Negative values in LPRECT !!!\n");
382           goto release;
383         }
384         memcpy(&xdst,rdst,sizeof(xdst));
385     } else {
386         xdst.top        = 0;
387         xdst.bottom     = ddesc.dwHeight;
388         xdst.left       = 0;
389         xdst.right      = ddesc.dwWidth;
390     }
391
392     if (rsrc) {
393         if ((rsrc->top < 0) ||
394             (rsrc->left < 0) ||
395             (rsrc->bottom < 0) ||
396             (rsrc->right < 0)) {
397           ERR(" Negative values in LPRECT !!!\n");
398           goto release;
399         }
400         memcpy(&xsrc,rsrc,sizeof(xsrc));
401     } else {
402         if (src) {
403             xsrc.top    = 0;
404             xsrc.bottom = sdesc.dwHeight;
405             xsrc.left   = 0;
406             xsrc.right  = sdesc.dwWidth;
407         } else {
408             memset(&xsrc,0,sizeof(xsrc));
409         }
410     }
411     if (src) assert((xsrc.bottom-xsrc.top) <= sdesc.dwHeight);
412     assert((xdst.bottom-xdst.top) <= ddesc.dwHeight);
413
414     bpp = GET_BPP(ddesc);
415     srcheight = xsrc.bottom - xsrc.top;
416     srcwidth = xsrc.right - xsrc.left;
417     dstheight = xdst.bottom - xdst.top;
418     dstwidth = xdst.right - xdst.left;
419     width = (xdst.right - xdst.left) * bpp;
420
421     assert(width <= ddesc.u1.lPitch);
422
423     dbuf = (BYTE*)ddesc.lpSurface+(xdst.top*ddesc.u1.lPitch)+(xdst.left*bpp);
424
425     if (dwFlags & (DDBLT_WAIT|DDBLT_ASYNC))
426     {
427         static BOOL displayed = FALSE;
428         if (!displayed)
429         {
430             FIXME("dwFlags DDBLT_WAIT and/or DDBLT_ASYNC: can't handle right now.\n");
431             displayed = TRUE;
432         }
433         dwFlags &= ~(DDBLT_WAIT|DDBLT_ASYNC);
434     }
435
436     /* First, all the 'source-less' blits */
437     if (dwFlags & DDBLT_COLORFILL) {
438         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
439                              ddesc.u1.lPitch, lpbltfx->u5.dwFillColor);
440         dwFlags &= ~DDBLT_COLORFILL;
441     }
442
443     if (dwFlags & DDBLT_DEPTHFILL)
444         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
445     if (dwFlags & DDBLT_ROP) {
446         /* Catch some degenerate cases here */
447         switch(lpbltfx->dwROP) {
448         case BLACKNESS:
449             ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,ddesc.u1.lPitch,0);
450             break;
451         case 0xAA0029: /* No-op */
452             break;
453         case WHITENESS:
454             ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,ddesc.u1.lPitch,~0);
455             break;
456         case SRCCOPY: /* well, we do that below ? */
457             break;
458         default:
459             FIXME("Unsupported raster op: %08lx  Pattern: %p\n", lpbltfx->dwROP, lpbltfx->u5.lpDDSPattern);
460             goto error;
461         }
462         dwFlags &= ~DDBLT_ROP;
463     }
464     if (dwFlags & DDBLT_DDROPS) {
465         FIXME("\tDdraw Raster Ops: %08lx  Pattern: %p\n", lpbltfx->dwDDROP, lpbltfx->u5.lpDDSPattern);
466     }
467     /* Now the 'with source' blits */
468     if (src) {
469         LPBYTE sbase;
470         int sx, xinc, sy, yinc;
471
472         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
473             goto release;
474         sbase = (BYTE*)sdesc.lpSurface+(xsrc.top*sdesc.u1.lPitch)+xsrc.left*bpp;
475         xinc = (srcwidth << 16) / dstwidth;
476         yinc = (srcheight << 16) / dstheight;
477
478         if (!dwFlags) {
479             /* No effects, we can cheat here */
480             if (dstwidth == srcwidth) {
481                 if (dstheight == srcheight) {
482                     /* No stretching in either direction. This needs to be as
483                      * fast as possible */
484                     sbuf = sbase;
485                     for (y = 0; y < dstheight; y++) {
486                         memcpy(dbuf, sbuf, width);
487                         sbuf += sdesc.u1.lPitch;
488                         dbuf += ddesc.u1.lPitch;
489                     }
490                 } else {
491                     /* Stretching in Y direction only */
492                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
493                         sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
494                         memcpy(dbuf, sbuf, width);
495                         dbuf += ddesc.u1.lPitch;
496                     }
497                 }
498             } else {
499                 /* Stretching in X direction */
500                 int last_sy = -1;
501                 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
502                     sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
503
504                     if ((sy >> 16) == (last_sy >> 16)) {
505                         /* this sourcerow is the same as last sourcerow -
506                          * copy already stretched row
507                          */
508                         memcpy(dbuf, dbuf - ddesc.u1.lPitch, width);
509                     } else {
510 #define STRETCH_ROW(type) { \
511                     type *s = (type *) sbuf, *d = (type *) dbuf; \
512                     for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
513                     d[x] = s[sx >> 16]; \
514                     break; }
515
516                     switch(bpp) {
517                     case 1: STRETCH_ROW(BYTE)
518                     case 2: STRETCH_ROW(WORD)
519                     case 4: STRETCH_ROW(DWORD)
520                     case 3: {
521                         LPBYTE s,d = dbuf;
522                         for (x = sx = 0; x < dstwidth; x++, sx+= xinc) {
523                             DWORD pixel;
524
525                             s = sbuf+3*(sx>>16);
526                             pixel = (s[0]<<16)|(s[1]<<8)|s[2];
527                             d[0] = (pixel>>16)&0xff;
528                             d[1] = (pixel>> 8)&0xff;
529                             d[2] = (pixel    )&0xff;
530                             d+=3;
531                         }
532                         break;
533                     }
534                     default:
535                         FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
536                         ret = DDERR_UNSUPPORTED;
537                         goto error;
538                     }
539 #undef STRETCH_ROW
540                     }
541                     dbuf += ddesc.u1.lPitch;
542                     last_sy = sy;
543                 }
544             }
545         } else if (dwFlags & (DDBLT_KEYSRC | DDBLT_KEYDEST)) {
546             DWORD keylow, keyhigh;
547
548             if (dwFlags & DDBLT_KEYSRC) {
549                 keylow  = sdesc.ddckCKSrcBlt.dwColorSpaceLowValue;
550                 keyhigh = sdesc.ddckCKSrcBlt.dwColorSpaceHighValue;
551             } else {
552                 /* I'm not sure if this is correct */
553                 FIXME("DDBLT_KEYDEST not fully supported yet.\n");
554                 keylow  = ddesc.ddckCKDestBlt.dwColorSpaceLowValue;
555                 keyhigh = ddesc.ddckCKDestBlt.dwColorSpaceHighValue;
556             }
557
558
559             for (y = sy = 0; y < dstheight; y++, sy += yinc) {
560                 sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
561
562 #define COPYROW_COLORKEY(type) { \
563                 type *s = (type *) sbuf, *d = (type *) dbuf, tmp; \
564                 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
565                     tmp = s[sx >> 16]; \
566                     if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
567                 } \
568                 break; }
569
570                 switch (bpp) {
571                 case 1: COPYROW_COLORKEY(BYTE)
572                 case 2: COPYROW_COLORKEY(WORD)
573                 case 4: COPYROW_COLORKEY(DWORD)
574                 default:
575                     FIXME("%s color-keyed blit not implemented for bpp %d!\n",
576                     (dwFlags & DDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
577                     ret = DDERR_UNSUPPORTED;
578                     goto error;
579                 }
580                 dbuf += ddesc.u1.lPitch;
581             }
582 #undef COPYROW_COLORKEY
583             dwFlags &= ~(DDBLT_KEYSRC | DDBLT_KEYDEST);
584         }
585     }
586
587 error:
588     if (dwFlags && FIXME_ON(ddraw)) {
589         FIXME("\tUnsupported flags: ");
590         DDRAW_dump_DDBLT(dwFlags);
591     }
592
593 release:
594     IDirectDrawSurface7_Unlock(iface,NULL);
595     if (src) IDirectDrawSurface7_Unlock(src,NULL);
596     return DD_OK;
597 }
598
599 /* BltBatch: generic, unimplemented */
600
601 HRESULT WINAPI
602 DIB_DirectDrawSurface_BltFast(LPDIRECTDRAWSURFACE7 iface, DWORD dstx,
603                               DWORD dsty, LPDIRECTDRAWSURFACE7 src,
604                               LPRECT rsrc, DWORD trans)
605 {
606     ICOM_THIS(IDirectDrawSurfaceImpl,iface);
607     int                 bpp, w, h, x, y;
608     DDSURFACEDESC2      ddesc,sdesc;
609     HRESULT             ret = DD_OK;
610     LPBYTE              sbuf, dbuf;
611     RECT                rsrc2;
612
613
614     if (TRACE_ON(ddraw)) {
615         FIXME("(%p)->(%ld,%ld,%p,%p,%08lx)\n",
616                 This,dstx,dsty,src,rsrc,trans
617         );
618         FIXME("\ttrans:");
619         if (FIXME_ON(ddraw))
620           DDRAW_dump_DDBLTFAST(trans);
621         if (rsrc)
622           FIXME("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,rsrc->right,rsrc->bottom);
623         else
624           FIXME(" srcrect: NULL\n");
625     }
626
627     /* We need to lock the surfaces, or we won't get refreshes when done. */
628     sdesc.dwSize = sizeof(sdesc);
629     IDirectDrawSurface7_Lock(src, NULL,&sdesc,DDLOCK_READONLY, 0);
630     ddesc.dwSize = sizeof(ddesc);
631     IDirectDrawSurface7_Lock(iface,NULL,&ddesc,DDLOCK_WRITEONLY,0);
632
633    if (!rsrc) {
634            WARN("rsrc is NULL!\n");
635            rsrc = &rsrc2;
636            rsrc->left = rsrc->top = 0;
637            rsrc->right = sdesc.dwWidth;
638            rsrc->bottom = sdesc.dwHeight;
639    }
640
641     bpp = GET_BPP(This->surface_desc);
642     sbuf = (BYTE *)sdesc.lpSurface+(rsrc->top*sdesc.u1.lPitch)+rsrc->left*bpp;
643     dbuf = (BYTE *)ddesc.lpSurface+(dsty*ddesc.u1.lPitch)+dstx* bpp;
644
645
646     h=rsrc->bottom-rsrc->top;
647     if (h>ddesc.dwHeight-dsty) h=ddesc.dwHeight-dsty;
648     if (h>sdesc.dwHeight-rsrc->top) h=sdesc.dwHeight-rsrc->top;
649     if (h<0) h=0;
650
651     w=rsrc->right-rsrc->left;
652     if (w>ddesc.dwWidth-dstx) w=ddesc.dwWidth-dstx;
653     if (w>sdesc.dwWidth-rsrc->left) w=sdesc.dwWidth-rsrc->left;
654     if (w<0) w=0;
655
656     if (trans & (DDBLTFAST_SRCCOLORKEY | DDBLTFAST_DESTCOLORKEY)) {
657         DWORD keylow, keyhigh;
658         if (trans & DDBLTFAST_SRCCOLORKEY) {
659             keylow  = sdesc.ddckCKSrcBlt.dwColorSpaceLowValue;
660             keyhigh = sdesc.ddckCKSrcBlt.dwColorSpaceHighValue;
661         } else {
662             /* I'm not sure if this is correct */
663             FIXME("DDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
664             keylow  = ddesc.ddckCKDestBlt.dwColorSpaceLowValue;
665             keyhigh = ddesc.ddckCKDestBlt.dwColorSpaceHighValue;
666         }
667
668 #define COPYBOX_COLORKEY(type) { \
669     type *d = (type *)dbuf, *s = (type *)sbuf, tmp; \
670     s = (type *) ((BYTE *) sdesc.lpSurface + (rsrc->top * sdesc.u1.lPitch) + rsrc->left * bpp); \
671     d = (type *) ((BYTE *) ddesc.lpSurface + (dsty * ddesc.u1.lPitch) + dstx * bpp); \
672     for (y = 0; y < h; y++) { \
673         for (x = 0; x < w; x++) { \
674             tmp = s[x]; \
675             if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
676         } \
677         (LPBYTE)s += sdesc.u1.lPitch; \
678         (LPBYTE)d += ddesc.u1.lPitch; \
679     } \
680     break; \
681 }
682
683         switch (bpp) {
684         case 1: COPYBOX_COLORKEY(BYTE)
685         case 2: COPYBOX_COLORKEY(WORD)
686         case 4: COPYBOX_COLORKEY(DWORD)
687         default:
688             FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
689             ret = DDERR_UNSUPPORTED;
690             goto error;
691         }
692 #undef COPYBOX_COLORKEY
693     } else {
694         int width = w * bpp;
695
696         for (y = 0; y < h; y++) {
697             memcpy(dbuf, sbuf, width);
698             sbuf += sdesc.u1.lPitch;
699             dbuf += ddesc.u1.lPitch;
700         }
701     }
702 error:
703     IDirectDrawSurface7_Unlock(iface, NULL);
704     IDirectDrawSurface7_Unlock(src, NULL);
705     return ret;
706 }
707
708 /* ChangeUniquenessValue: generic */
709 /* DeleteAttachedSurface: generic */
710 /* EnumAttachedSurfaces: generic */
711 /* EnumOverlayZOrders: generic, unimplemented */
712
713 BOOL DIB_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front,
714                                      IDirectDrawSurfaceImpl* back,
715                                      DWORD dwFlags)
716 {
717     DIB_DirectDrawSurfaceImpl* front_priv = front->private;
718     DIB_DirectDrawSurfaceImpl* back_priv = back->private;
719
720     TRACE("(%p,%p)\n",front,back);
721
722     {
723         HBITMAP tmp;
724         tmp = front_priv->dib.DIBsection;
725         front_priv->dib.DIBsection = back_priv->dib.DIBsection;
726         back_priv->dib.DIBsection = tmp;
727     }
728
729     {
730         void* tmp;
731         tmp = front_priv->dib.bitmap_data;
732         front_priv->dib.bitmap_data = back_priv->dib.bitmap_data;
733         back_priv->dib.bitmap_data = tmp;
734
735         tmp = front->surface_desc.lpSurface;
736         front->surface_desc.lpSurface = back->surface_desc.lpSurface;
737         back->surface_desc.lpSurface = tmp;
738     }
739
740     /* client_memory should not be different, but just in case */
741     {
742         BOOL tmp;
743         tmp = front_priv->dib.client_memory;
744         front_priv->dib.client_memory = back_priv->dib.client_memory;
745         back_priv->dib.client_memory = tmp;
746     }
747
748     return Main_DirectDrawSurface_flip_data(front, back, dwFlags);
749 }
750
751 /* Flip: generic */
752 /* FreePrivateData: generic */
753 /* GetAttachedSurface: generic */
754 /* GetBltStatus: generic */
755 /* GetCaps: generic (Returns the caps from This->surface_desc.) */
756 /* GetClipper: generic */
757 /* GetColorKey: generic */
758
759 HRESULT DIB_DirectDrawSurface_alloc_dc(IDirectDrawSurfaceImpl* This, HDC* phDC)
760 {
761     DIB_PRIV_VAR(priv, This);
762     HDC hDC;
763
764     TRACE("Grabbing a DC for surface: %p\n", This);
765
766     hDC = CreateCompatibleDC(0);
767     priv->dib.holdbitmap = SelectObject(hDC, priv->dib.DIBsection);
768     if (This->palette)
769         SelectPalette(hDC, This->palette->hpal, FALSE);
770
771     *phDC = hDC;
772
773     return S_OK;
774 }
775
776 HRESULT DIB_DirectDrawSurface_free_dc(IDirectDrawSurfaceImpl* This, HDC hDC)
777 {
778     DIB_PRIV_VAR(priv, This);
779
780     TRACE("Releasing DC for surface: %p\n", This);
781
782     SelectObject(hDC, priv->dib.holdbitmap);
783     DeleteDC(hDC);
784
785     return S_OK;
786 }
787
788 HRESULT DIB_DirectDrawSurface_get_dc(IDirectDrawSurfaceImpl* This, HDC* phDC)
789 {
790     return DIB_DirectDrawSurface_alloc_dc(This, phDC);
791 }
792
793 HRESULT DIB_DirectDrawSurface_release_dc(IDirectDrawSurfaceImpl* This, HDC hDC)
794 {
795     return DIB_DirectDrawSurface_free_dc(This, hDC);
796 }
797
798 /* GetDDInterface: generic */
799 /* GetFlipStatus: generic */
800 /* GetLOD: generic */
801 /* GetOverlayPosition: generic */
802 /* GetPalette: generic */
803 /* GetPixelFormat: generic */
804 /* GetPriority: generic */
805 /* GetPrivateData: generic */
806 /* GetSurfaceDesc: generic */
807 /* GetUniquenessValue: generic */
808 /* Initialize: generic */
809 /* IsLost: generic */
810 /* Lock: generic with callback? */
811 /* PageLock: generic */
812 /* PageUnlock: generic */
813
814 HRESULT WINAPI
815 DIB_DirectDrawSurface_Restore(LPDIRECTDRAWSURFACE7 iface)
816 {
817     TRACE("(%p)\n",iface);
818     return DD_OK;       /* ??? */
819 }
820
821 /* SetClipper: generic */
822 /* SetColorKey: generic */
823 /* SetLOD: generic */
824 /* SetOverlayPosition: generic */
825
826 void DIB_DirectDrawSurface_set_palette(IDirectDrawSurfaceImpl* This,
827                                        IDirectDrawPaletteImpl* pal)
828 {
829     if (!pal) return;
830     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
831         This->update_palette(This, pal,
832                              0, pal->palNumEntries,
833                              pal->palents);
834 }
835
836 void DIB_DirectDrawSurface_update_palette(IDirectDrawSurfaceImpl* This,
837                                           IDirectDrawPaletteImpl* pal,
838                                           DWORD dwStart, DWORD dwCount,
839                                           LPPALETTEENTRY palent)
840 {
841     RGBQUAD col[256];
842     int n;
843     HDC dc;
844
845     TRACE("updating primary palette\n");
846     for (n=0; n<dwCount; n++) {
847       col[n].rgbRed   = palent[n].peRed;
848       col[n].rgbGreen = palent[n].peGreen;
849       col[n].rgbBlue  = palent[n].peBlue;
850       col[n].rgbReserved = 0;
851     }
852     This->get_dc(This, &dc);
853     SetDIBColorTable(dc, dwStart, dwCount, col);
854     This->release_dc(This, dc);
855
856     /* Propagate change to backbuffers if there are any */
857     /* Basically this is a modification of the Flip code to find the backbuffer */
858     /* and duplicate the palette update there as well */
859     if ((This->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
860         == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
861     {
862         static DDSCAPS2 back_caps = { DDSCAPS_BACKBUFFER };
863         LPDIRECTDRAWSURFACE7 tgt;
864
865         HRESULT hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This,IDirectDrawSurface7),
866                                                             &back_caps, &tgt);
867         if (!FAILED(hr))
868         {
869             IDirectDrawSurfaceImpl* target = ICOM_OBJECT(IDirectDrawSurfaceImpl,
870                                                          IDirectDrawSurface7,tgt);
871             IDirectDrawSurface7_Release(tgt);
872             target->get_dc(target, &dc);
873             SetDIBColorTable(dc, dwStart, dwCount, col);
874             target->release_dc(target, dc);
875         }
876     }
877 }
878
879 /* SetPalette: generic */
880 /* SetPriority: generic */
881 /* SetPrivateData: generic */
882
883 HRESULT WINAPI
884 DIB_DirectDrawSurface_SetSurfaceDesc(LPDIRECTDRAWSURFACE7 iface,
885                                      LPDDSURFACEDESC2 pDDSD, DWORD dwFlags)
886 {
887     ICOM_THIS(IDirectDrawSurfaceImpl,iface);
888     DIB_PRIV_VAR(priv, This);
889     HRESULT hr = DD_OK;
890
891     TRACE("(%p)->(%p,%08lx)\n",iface,pDDSD,dwFlags);
892     if (pDDSD->dwFlags == DDSD_LPSURFACE) {
893         HBITMAP oldbmp = priv->dib.DIBsection;
894         LPVOID oldsurf = This->surface_desc.lpSurface;
895         BOOL oldc = priv->dib.client_memory;
896
897         TRACE("new lpSurface=%p\n",pDDSD->lpSurface);
898         This->surface_desc.lpSurface = pDDSD->lpSurface;
899         priv->dib.client_memory = TRUE;
900
901         hr = create_dib(This);
902         if (FAILED(hr))
903         {
904             priv->dib.DIBsection = oldbmp;
905             This->surface_desc.lpSurface = oldsurf;
906             priv->dib.client_memory = oldc;
907             return hr;
908         }
909
910         DeleteObject(oldbmp);
911
912         if (!oldc)
913             VirtualFree(oldsurf, 0, MEM_RELEASE);
914
915         return hr;
916     }
917     else {
918         FIXME("flags=%08lx\n",pDDSD->dwFlags);
919         abort();
920         hr = E_FAIL;
921     }
922     return hr;
923 }
924
925 /* Unlock: ???, need callback */
926 /* UpdateOverlay: generic */
927 /* UpdateOverlayDisplay: generic */
928 /* UpdateOverlayZOrder: generic */
929
930 static ICOM_VTABLE(IDirectDrawSurface7) DIB_IDirectDrawSurface7_VTable =
931 {
932     Main_DirectDrawSurface_QueryInterface,
933     Main_DirectDrawSurface_AddRef,
934     Main_DirectDrawSurface_Release,
935     Main_DirectDrawSurface_AddAttachedSurface,
936     Main_DirectDrawSurface_AddOverlayDirtyRect,
937     DIB_DirectDrawSurface_Blt,
938     Main_DirectDrawSurface_BltBatch,
939     DIB_DirectDrawSurface_BltFast,
940     Main_DirectDrawSurface_DeleteAttachedSurface,
941     Main_DirectDrawSurface_EnumAttachedSurfaces,
942     Main_DirectDrawSurface_EnumOverlayZOrders,
943     Main_DirectDrawSurface_Flip,
944     Main_DirectDrawSurface_GetAttachedSurface,
945     Main_DirectDrawSurface_GetBltStatus,
946     Main_DirectDrawSurface_GetCaps,
947     Main_DirectDrawSurface_GetClipper,
948     Main_DirectDrawSurface_GetColorKey,
949     Main_DirectDrawSurface_GetDC,
950     Main_DirectDrawSurface_GetFlipStatus,
951     Main_DirectDrawSurface_GetOverlayPosition,
952     Main_DirectDrawSurface_GetPalette,
953     Main_DirectDrawSurface_GetPixelFormat,
954     Main_DirectDrawSurface_GetSurfaceDesc,
955     Main_DirectDrawSurface_Initialize,
956     Main_DirectDrawSurface_IsLost,
957     Main_DirectDrawSurface_Lock,
958     Main_DirectDrawSurface_ReleaseDC,
959     DIB_DirectDrawSurface_Restore,
960     Main_DirectDrawSurface_SetClipper,
961     Main_DirectDrawSurface_SetColorKey,
962     Main_DirectDrawSurface_SetOverlayPosition,
963     Main_DirectDrawSurface_SetPalette,
964     Main_DirectDrawSurface_Unlock,
965     Main_DirectDrawSurface_UpdateOverlay,
966     Main_DirectDrawSurface_UpdateOverlayDisplay,
967     Main_DirectDrawSurface_UpdateOverlayZOrder,
968     Main_DirectDrawSurface_GetDDInterface,
969     Main_DirectDrawSurface_PageLock,
970     Main_DirectDrawSurface_PageUnlock,
971     DIB_DirectDrawSurface_SetSurfaceDesc,
972     Main_DirectDrawSurface_SetPrivateData,
973     Main_DirectDrawSurface_GetPrivateData,
974     Main_DirectDrawSurface_FreePrivateData,
975     Main_DirectDrawSurface_GetUniquenessValue,
976     Main_DirectDrawSurface_ChangeUniquenessValue,
977     Main_DirectDrawSurface_SetPriority,
978     Main_DirectDrawSurface_GetPriority,
979     Main_DirectDrawSurface_SetLOD,
980     Main_DirectDrawSurface_GetLOD
981 };