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