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