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