Added mappings for a few messages.
[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, 0, 0);
326     ddesc.dwSize = sizeof(ddesc);
327     IDirectDrawSurface7_Lock(iface,NULL,&ddesc,0,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     dwFlags &= ~(DDBLT_WAIT|DDBLT_ASYNC);/* FIXME: can't handle right now */
390
391     /* First, all the 'source-less' blits */
392     if (dwFlags & DDBLT_COLORFILL) {
393         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
394                              ddesc.u1.lPitch, lpbltfx->u5.dwFillColor);
395         dwFlags &= ~DDBLT_COLORFILL;
396     }
397
398     if (dwFlags & DDBLT_DEPTHFILL)
399         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
400     if (dwFlags & DDBLT_ROP) {
401         /* Catch some degenerate cases here */
402         switch(lpbltfx->dwROP) {
403         case BLACKNESS:
404             ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,ddesc.u1.lPitch,0);
405             break;
406         case 0xAA0029: /* No-op */
407             break;
408         case WHITENESS:
409             ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,ddesc.u1.lPitch,~0);
410             break;
411         case SRCCOPY: /* well, we do that below ? */
412             break;
413         default: 
414             FIXME("Unsupported raster op: %08lx  Pattern: %p\n", lpbltfx->dwROP, lpbltfx->u5.lpDDSPattern);
415             goto error;
416         }
417         dwFlags &= ~DDBLT_ROP;
418     }
419     if (dwFlags & DDBLT_DDROPS) {
420         FIXME("\tDdraw Raster Ops: %08lx  Pattern: %p\n", lpbltfx->dwDDROP, lpbltfx->u5.lpDDSPattern);
421     }
422     /* Now the 'with source' blits */
423     if (src) {
424         LPBYTE sbase;
425         int sx, xinc, sy, yinc;
426
427         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
428             goto release;
429         sbase = (BYTE*)sdesc.lpSurface+(xsrc.top*sdesc.u1.lPitch)+xsrc.left*bpp;
430         xinc = (srcwidth << 16) / dstwidth;
431         yinc = (srcheight << 16) / dstheight;
432
433         if (!dwFlags) {
434             /* No effects, we can cheat here */
435             if (dstwidth == srcwidth) {
436                 if (dstheight == srcheight) {
437                     /* No stretching in either direction. This needs to be as
438                      * fast as possible */
439                     sbuf = sbase;
440                     for (y = 0; y < dstheight; y++) {
441                         memcpy(dbuf, sbuf, width);
442                         sbuf += sdesc.u1.lPitch;
443                         dbuf += ddesc.u1.lPitch;
444                     }
445                 } else {
446                     /* Stretching in Y direction only */
447                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
448                         sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
449                         memcpy(dbuf, sbuf, width);
450                         dbuf += ddesc.u1.lPitch;
451                     }
452                 }
453             } else {
454                 /* Stretching in X direction */
455                 int last_sy = -1;
456                 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
457                     sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
458
459                     if ((sy >> 16) == (last_sy >> 16)) {
460                         /* this sourcerow is the same as last sourcerow -
461                          * copy already stretched row
462                          */
463                         memcpy(dbuf, dbuf - ddesc.u1.lPitch, width);
464                     } else {
465 #define STRETCH_ROW(type) { \
466                     type *s = (type *) sbuf, *d = (type *) dbuf; \
467                     for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
468                     d[x] = s[sx >> 16]; \
469                     break; }
470
471                     switch(bpp) {
472                     case 1: STRETCH_ROW(BYTE)
473                     case 2: STRETCH_ROW(WORD)
474                     case 4: STRETCH_ROW(DWORD)
475                     case 3: {
476                         LPBYTE s,d = dbuf;
477                         for (x = sx = 0; x < dstwidth; x++, sx+= xinc) {
478                             DWORD pixel;
479
480                             s = sbuf+3*(sx>>16);
481                             pixel = (s[0]<<16)|(s[1]<<8)|s[2];
482                             d[0] = (pixel>>16)&0xff;
483                             d[1] = (pixel>> 8)&0xff;
484                             d[2] = (pixel    )&0xff;
485                             d+=3;
486                         }
487                         break;
488                     }
489                     default:
490                         FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
491                         ret = DDERR_UNSUPPORTED;
492                         goto error;
493                     }
494 #undef STRETCH_ROW
495                     }
496                     dbuf += ddesc.u1.lPitch;
497                     last_sy = sy;
498                 }
499             }
500         } else if (dwFlags & (DDBLT_KEYSRC | DDBLT_KEYDEST)) {
501             DWORD keylow, keyhigh;
502
503             if (dwFlags & DDBLT_KEYSRC) {
504                 keylow  = sdesc.ddckCKSrcBlt.dwColorSpaceLowValue;
505                 keyhigh = sdesc.ddckCKSrcBlt.dwColorSpaceHighValue;
506             } else {
507                 /* I'm not sure if this is correct */
508                 FIXME("DDBLT_KEYDEST not fully supported yet.\n");
509                 keylow  = ddesc.ddckCKDestBlt.dwColorSpaceLowValue;
510                 keyhigh = ddesc.ddckCKDestBlt.dwColorSpaceHighValue;
511             }
512
513
514             for (y = sy = 0; y < dstheight; y++, sy += yinc) {
515                 sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
516
517 #define COPYROW_COLORKEY(type) { \
518                 type *s = (type *) sbuf, *d = (type *) dbuf, tmp; \
519                 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
520                     tmp = s[sx >> 16]; \
521                     if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
522                 } \
523                 break; }
524
525                 switch (bpp) {
526                 case 1: COPYROW_COLORKEY(BYTE)
527                 case 2: COPYROW_COLORKEY(WORD)
528                 case 4: COPYROW_COLORKEY(DWORD)
529                 default:
530                     FIXME("%s color-keyed blit not implemented for bpp %d!\n",
531                     (dwFlags & DDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
532                     ret = DDERR_UNSUPPORTED;
533                     goto error;
534                 }
535                 dbuf += ddesc.u1.lPitch;
536             }
537 #undef COPYROW_COLORKEY
538             dwFlags &= ~(DDBLT_KEYSRC | DDBLT_KEYDEST);
539         }
540     }
541
542 error:
543     if (dwFlags && FIXME_ON(ddraw)) {
544         FIXME("\tUnsupported flags: ");
545         DDRAW_dump_DDBLT(dwFlags);
546     }
547
548 release:
549     IDirectDrawSurface7_Unlock(iface,NULL);
550     if (src) IDirectDrawSurface7_Unlock(src,NULL);
551     return DD_OK;
552 }
553
554 /* BltBatch: generic, unimplemented */
555
556 HRESULT WINAPI
557 DIB_DirectDrawSurface_BltFast(LPDIRECTDRAWSURFACE7 iface, DWORD dstx,
558                               DWORD dsty, LPDIRECTDRAWSURFACE7 src,
559                               LPRECT rsrc, DWORD trans)
560 {
561     ICOM_THIS(IDirectDrawSurfaceImpl,iface);
562     int                 bpp, w, h, x, y;
563     DDSURFACEDESC2      ddesc,sdesc;
564     HRESULT             ret = DD_OK;
565     LPBYTE              sbuf, dbuf;
566     RECT                rsrc2;
567
568
569     if (TRACE_ON(ddraw)) {
570         FIXME("(%p)->(%ld,%ld,%p,%p,%08lx)\n",
571                 This,dstx,dsty,src,rsrc,trans
572         );
573         FIXME(" trans:");
574         if (FIXME_ON(ddraw))
575           DDRAW_dump_DDBLTFAST(trans);
576         if (rsrc)
577           FIXME("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,rsrc->right,rsrc->bottom);
578         else
579           FIXME(" srcrect: NULL\n");
580     }
581     
582     /* We need to lock the surfaces, or we won't get refreshes when done. */
583     sdesc.dwSize = sizeof(sdesc);
584     IDirectDrawSurface7_Lock(src, NULL,&sdesc,DDLOCK_READONLY, 0);
585     ddesc.dwSize = sizeof(ddesc);
586     IDirectDrawSurface7_Lock(iface,NULL,&ddesc,DDLOCK_WRITEONLY,0);
587
588    if (!rsrc) {
589            WARN("rsrc is NULL!\n");
590            rsrc = &rsrc2;
591            rsrc->left = rsrc->top = 0;
592            rsrc->right = sdesc.dwWidth;
593            rsrc->bottom = sdesc.dwHeight;
594    }
595
596     bpp = GET_BPP(This->surface_desc);
597     sbuf = (BYTE *)sdesc.lpSurface+(rsrc->top*sdesc.u1.lPitch)+rsrc->left*bpp;
598     dbuf = (BYTE *)ddesc.lpSurface+(dsty*ddesc.u1.lPitch)+dstx* bpp;
599
600
601     h=rsrc->bottom-rsrc->top;
602     if (h>ddesc.dwHeight-dsty) h=ddesc.dwHeight-dsty;
603     if (h>sdesc.dwHeight-rsrc->top) h=sdesc.dwHeight-rsrc->top;
604     if (h<0) h=0;
605
606     w=rsrc->right-rsrc->left;
607     if (w>ddesc.dwWidth-dstx) w=ddesc.dwWidth-dstx;
608     if (w>sdesc.dwWidth-rsrc->left) w=sdesc.dwWidth-rsrc->left;
609     if (w<0) w=0;
610
611     if (trans & (DDBLTFAST_SRCCOLORKEY | DDBLTFAST_DESTCOLORKEY)) {
612         DWORD keylow, keyhigh;
613         if (trans & DDBLTFAST_SRCCOLORKEY) {
614             keylow  = sdesc.ddckCKSrcBlt.dwColorSpaceLowValue;
615             keyhigh = sdesc.ddckCKSrcBlt.dwColorSpaceHighValue;
616         } else {
617             /* I'm not sure if this is correct */
618             FIXME("DDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
619             keylow  = ddesc.ddckCKDestBlt.dwColorSpaceLowValue;
620             keyhigh = ddesc.ddckCKDestBlt.dwColorSpaceHighValue;
621         }
622
623 #define COPYBOX_COLORKEY(type) { \
624     type *d = (type *)dbuf, *s = (type *)sbuf, tmp; \
625     s = (type *) ((BYTE *) sdesc.lpSurface + (rsrc->top * sdesc.u1.lPitch) + rsrc->left * bpp); \
626     d = (type *) ((BYTE *) ddesc.lpSurface + (dsty * ddesc.u1.lPitch) + dstx * bpp); \
627     for (y = 0; y < h; y++) { \
628         for (x = 0; x < w; x++) { \
629             tmp = s[x]; \
630             if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
631         } \
632         (LPBYTE)s += sdesc.u1.lPitch; \
633         (LPBYTE)d += ddesc.u1.lPitch; \
634     } \
635     break; \
636 }
637
638         switch (bpp) {
639         case 1: COPYBOX_COLORKEY(BYTE)
640         case 2: COPYBOX_COLORKEY(WORD)
641         case 4: COPYBOX_COLORKEY(DWORD)
642         default:
643             FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
644             ret = DDERR_UNSUPPORTED;
645             goto error;
646         }
647 #undef COPYBOX_COLORKEY
648     } else {
649         int width = w * bpp;
650
651         for (y = 0; y < h; y++) {
652             memcpy(dbuf, sbuf, width);
653             sbuf += sdesc.u1.lPitch;
654             dbuf += ddesc.u1.lPitch;
655         }
656     }
657 error:
658     IDirectDrawSurface7_Unlock(iface, NULL);
659     IDirectDrawSurface7_Unlock(src, NULL);
660     return ret;
661 }
662
663 /* ChangeUniquenessValue: generic */
664 /* DeleteAttachedSurface: generic */
665 /* EnumAttachedSurfaces: generic */
666 /* EnumOverlayZOrders: generic, unimplemented */
667
668 BOOL DIB_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front,
669                                      IDirectDrawSurfaceImpl* back,
670                                      DWORD dwFlags)
671 {
672     DIB_DirectDrawSurfaceImpl* front_priv = front->private;
673     DIB_DirectDrawSurfaceImpl* back_priv = back->private;
674
675     TRACE("(%p,%p)\n",front,back);
676
677     {
678         HBITMAP tmp;
679         tmp = front_priv->dib.DIBsection;
680         front_priv->dib.DIBsection = back_priv->dib.DIBsection;
681         back_priv->dib.DIBsection = tmp;
682     }
683
684     {
685         void* tmp;
686         tmp = front_priv->dib.bitmap_data;
687         front_priv->dib.bitmap_data = back_priv->dib.bitmap_data;
688         back_priv->dib.bitmap_data = tmp;
689
690         tmp = front->surface_desc.lpSurface;
691         front->surface_desc.lpSurface = back->surface_desc.lpSurface;
692         back->surface_desc.lpSurface = tmp;
693     }
694
695     /* client_memory should not be different, but just in case */
696     {
697         BOOL tmp;
698         tmp = front_priv->dib.client_memory;
699         front_priv->dib.client_memory = back_priv->dib.client_memory;
700         back_priv->dib.client_memory = tmp;
701     }
702
703     return Main_DirectDrawSurface_flip_data(front, back, dwFlags);
704 }
705
706 /* Flip: generic */
707 /* FreePrivateData: generic */
708 /* GetAttachedSurface: generic */
709 /* GetBltStatus: generic */
710 /* GetCaps: generic (Returns the caps from This->surface_desc.) */
711 /* GetClipper: generic */
712 /* GetColorKey: generic */
713
714 HRESULT DIB_DirectDrawSurface_alloc_dc(IDirectDrawSurfaceImpl* This, HDC* phDC)
715 {
716     DIB_PRIV_VAR(priv, This);
717     HDC hDC;
718
719     TRACE("Grabbing a DC for surface: %p\n", This);
720
721     hDC = CreateCompatibleDC(0);
722     priv->dib.holdbitmap = SelectObject(hDC, priv->dib.DIBsection);
723     if (This->palette)
724         SelectPalette(hDC, This->palette->hpal, FALSE);
725
726     *phDC = hDC;
727
728     return S_OK;
729 }
730
731 HRESULT DIB_DirectDrawSurface_free_dc(IDirectDrawSurfaceImpl* This, HDC hDC)
732 {
733     DIB_PRIV_VAR(priv, This);
734
735     TRACE("Releasing DC for surface: %p\n", This);
736
737     SelectObject(hDC, priv->dib.holdbitmap);
738     DeleteDC(hDC);
739
740     return S_OK;
741 }
742
743 HRESULT DIB_DirectDrawSurface_get_dc(IDirectDrawSurfaceImpl* This, HDC* phDC)
744 {
745     return DIB_DirectDrawSurface_alloc_dc(This, phDC);
746 }
747
748 HRESULT DIB_DirectDrawSurface_release_dc(IDirectDrawSurfaceImpl* This, HDC hDC)
749 {
750     return DIB_DirectDrawSurface_free_dc(This, hDC);
751 }
752
753 /* GetDDInterface: generic */
754 /* GetFlipStatus: generic */
755 /* GetLOD: generic */
756 /* GetOverlayPosition: generic */
757 /* GetPalette: generic */
758 /* GetPixelFormat: generic */
759 /* GetPriority: generic */
760 /* GetPrivateData: generic */
761 /* GetSurfaceDesc: generic */
762 /* GetUniquenessValue: generic */
763 /* Initialize: generic */
764 /* IsLost: generic */
765 /* Lock: generic with callback? */
766 /* PageLock: generic */
767 /* PageUnlock: generic */
768
769 HRESULT WINAPI
770 DIB_DirectDrawSurface_Restore(LPDIRECTDRAWSURFACE7 iface)
771 {
772     TRACE("(%p)\n",iface);
773     return DD_OK;       /* ??? */
774 }
775
776 /* SetClipper: generic */
777 /* SetColorKey: generic */
778 /* SetLOD: generic */
779 /* SetOverlayPosition: generic */
780
781 void DIB_DirectDrawSurface_set_palette(IDirectDrawSurfaceImpl* This,
782                                        IDirectDrawPaletteImpl* pal) 
783 {
784     if (!pal) return;
785     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
786         This->update_palette(This, pal,
787                              0, pal->palNumEntries,
788                              pal->palents);
789 }
790
791 void DIB_DirectDrawSurface_update_palette(IDirectDrawSurfaceImpl* This,
792                                           IDirectDrawPaletteImpl* pal,
793                                           DWORD dwStart, DWORD dwCount,
794                                           LPPALETTEENTRY palent)
795 {
796     RGBQUAD col[256];
797     int n;
798     HDC dc;
799
800     TRACE("updating primary palette\n");
801     for (n=0; n<dwCount; n++) {
802       col[n].rgbRed   = palent[n].peRed;
803       col[n].rgbGreen = palent[n].peGreen;
804       col[n].rgbBlue  = palent[n].peBlue;
805       col[n].rgbReserved = 0;
806     }
807     This->get_dc(This, &dc);
808     SetDIBColorTable(dc, dwStart, dwCount, col);
809     This->release_dc(This, dc);
810
811     /* Propagate change to backbuffers if there are any */
812     /* Basically this is a modification of the Flip code to find the backbuffer */
813     /* and duplicate the palette update there as well */
814     if ((This->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
815         == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
816     {
817         static DDSCAPS2 back_caps = { DDSCAPS_BACKBUFFER };
818         LPDIRECTDRAWSURFACE7 tgt;
819
820         HRESULT hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This,IDirectDrawSurface7),
821                                                             &back_caps, &tgt);
822         if (!FAILED(hr))
823         {
824             IDirectDrawSurfaceImpl* target = ICOM_OBJECT(IDirectDrawSurfaceImpl,
825                                                          IDirectDrawSurface7,tgt);
826             IDirectDrawSurface7_Release(tgt);
827             target->get_dc(target, &dc);
828             SetDIBColorTable(dc, dwStart, dwCount, col);
829             target->release_dc(target, dc);
830         }
831     }
832 }
833
834 /* SetPalette: generic */
835 /* SetPriority: generic */
836 /* SetPrivateData: generic */
837
838 HRESULT WINAPI
839 DIB_DirectDrawSurface_SetSurfaceDesc(LPDIRECTDRAWSURFACE7 iface,
840                                      LPDDSURFACEDESC2 pDDSD, DWORD dwFlags)
841 {
842     ICOM_THIS(IDirectDrawSurfaceImpl,iface);
843     DIB_PRIV_VAR(priv, This);
844     HRESULT hr = DD_OK;
845
846     TRACE("(%p)->(%p,%08lx)\n",iface,pDDSD,dwFlags);
847     if (pDDSD->dwFlags == DDSD_LPSURFACE) {
848         HBITMAP oldbmp = priv->dib.DIBsection;
849         LPVOID oldsurf = This->surface_desc.lpSurface;
850         BOOL oldc = priv->dib.client_memory;
851
852         TRACE("new lpSurface=%p\n",pDDSD->lpSurface);
853         This->surface_desc.lpSurface = pDDSD->lpSurface;
854         priv->dib.client_memory = TRUE;
855
856         hr = create_dib(This);
857         if (FAILED(hr))
858         {
859             priv->dib.DIBsection = oldbmp;
860             This->surface_desc.lpSurface = oldsurf;
861             priv->dib.client_memory = oldc;
862             return hr;
863         }
864
865         DeleteObject(oldbmp);
866
867         if (!oldc)
868             VirtualFree(oldsurf, 0, MEM_RELEASE);
869
870         return hr;
871     }
872     else {
873         FIXME("flags=%08lx\n",pDDSD->dwFlags);
874         abort();
875         hr = E_FAIL;
876     }
877     return hr;
878 }
879
880 /* Unlock: ???, need callback */
881 /* UpdateOverlay: generic */
882 /* UpdateOverlayDisplay: generic */
883 /* UpdateOverlayZOrder: generic */
884
885 static ICOM_VTABLE(IDirectDrawSurface7) DIB_IDirectDrawSurface7_VTable =
886 {
887     Main_DirectDrawSurface_QueryInterface,
888     Main_DirectDrawSurface_AddRef,
889     Main_DirectDrawSurface_Release,
890     Main_DirectDrawSurface_AddAttachedSurface,
891     Main_DirectDrawSurface_AddOverlayDirtyRect,
892     DIB_DirectDrawSurface_Blt,
893     Main_DirectDrawSurface_BltBatch,
894     DIB_DirectDrawSurface_BltFast,
895     Main_DirectDrawSurface_DeleteAttachedSurface,
896     Main_DirectDrawSurface_EnumAttachedSurfaces,
897     Main_DirectDrawSurface_EnumOverlayZOrders,
898     Main_DirectDrawSurface_Flip,
899     Main_DirectDrawSurface_GetAttachedSurface,
900     Main_DirectDrawSurface_GetBltStatus,
901     Main_DirectDrawSurface_GetCaps,
902     Main_DirectDrawSurface_GetClipper,
903     Main_DirectDrawSurface_GetColorKey,
904     Main_DirectDrawSurface_GetDC,
905     Main_DirectDrawSurface_GetFlipStatus,
906     Main_DirectDrawSurface_GetOverlayPosition,
907     Main_DirectDrawSurface_GetPalette,
908     Main_DirectDrawSurface_GetPixelFormat,
909     Main_DirectDrawSurface_GetSurfaceDesc,
910     Main_DirectDrawSurface_Initialize,
911     Main_DirectDrawSurface_IsLost,
912     Main_DirectDrawSurface_Lock,
913     Main_DirectDrawSurface_ReleaseDC,
914     DIB_DirectDrawSurface_Restore,
915     Main_DirectDrawSurface_SetClipper,
916     Main_DirectDrawSurface_SetColorKey,
917     Main_DirectDrawSurface_SetOverlayPosition,
918     Main_DirectDrawSurface_SetPalette,
919     Main_DirectDrawSurface_Unlock,
920     Main_DirectDrawSurface_UpdateOverlay,
921     Main_DirectDrawSurface_UpdateOverlayDisplay,
922     Main_DirectDrawSurface_UpdateOverlayZOrder,
923     Main_DirectDrawSurface_GetDDInterface,
924     Main_DirectDrawSurface_PageLock,
925     Main_DirectDrawSurface_PageUnlock,
926     DIB_DirectDrawSurface_SetSurfaceDesc,
927     Main_DirectDrawSurface_SetPrivateData,
928     Main_DirectDrawSurface_GetPrivateData,
929     Main_DirectDrawSurface_FreePrivateData,
930     Main_DirectDrawSurface_GetUniquenessValue,
931     Main_DirectDrawSurface_ChangeUniquenessValue,
932     Main_DirectDrawSurface_SetPriority,
933     Main_DirectDrawSurface_GetPriority,
934     Main_DirectDrawSurface_SetLOD,
935     Main_DirectDrawSurface_GetLOD
936 };