mcicda: Compare GetLastError() to kernel error codes, not ntdll ones.
[wine] / dlls / wined3d / surface_gdi.c
1 /*
2  * 2D Surface implementation without OpenGL
3  *
4  * Copyright 1997-2000 Marcus Meissner
5  * Copyright 1998-2000 Lionel Ulmer
6  * Copyright 2000-2001 TransGaming Technologies Inc.
7  * Copyright 2002-2005 Jason Edmeades
8  * Copyright 2002-2003 Raphael Junqueira
9  * Copyright 2004 Christian Costa
10  * Copyright 2005 Oliver Stieber
11  * Copyright 2006 Stefan Dösinger
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26  */
27
28 #include "config.h"
29 #include "wine/port.h"
30 #include "wined3d_private.h"
31
32 #include <assert.h>
33 #include <stdio.h>
34
35 /* Use the d3d_surface debug channel to have one channel for all surfaces */
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
37 WINE_DECLARE_DEBUG_CHANNEL(fps);
38
39 /*****************************************************************************
40  * x11_copy_to_screen
41  *
42  * Helper function that blts the front buffer contents to the target window
43  *
44  * Params:
45  *  This: Surface to copy from
46  *  rc: Rectangle to copy
47  *
48  *****************************************************************************/
49 static void
50 x11_copy_to_screen(IWineD3DSurfaceImpl *This,
51                    LPRECT rc)
52 {
53     if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
54     {
55         POINT offset = {0,0};
56         HWND hDisplayWnd;
57         HDC hDisplayDC;
58         HDC hSurfaceDC = 0;
59         RECT drawrect;
60         TRACE("(%p)->(%p): Copying to screen\n", This, rc);
61
62         hSurfaceDC = This->hDC;
63
64         hDisplayWnd = This->resource.wineD3DDevice->ddraw_window;
65         hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
66         if(rc)
67         {
68             TRACE(" copying rect (%d,%d)->(%d,%d), offset (%d,%d)\n",
69             rc->left, rc->top, rc->right, rc->bottom, offset.x, offset.y);
70         }
71 #if 0
72         /* FIXME: this doesn't work... if users really want to run
73         * X in 8bpp, then we need to call directly into display.drv
74         * (or Wine's equivalent), and force a private colormap
75         * without default entries. */
76         if (This->palette) {
77             SelectPalette(hDisplayDC, This->palette->hpal, FALSE);
78             RealizePalette(hDisplayDC); /* sends messages => deadlocks */
79         }
80 #endif
81         drawrect.left   = 0;
82         drawrect.right  = This->currentDesc.Width;
83         drawrect.top    = 0;
84         drawrect.bottom = This->currentDesc.Height;
85
86 #if 0
87         /* TODO: Support clippers */
88         if (This->clipper)
89         {
90             RECT xrc;
91             HWND hwnd = This->clipper->hWnd;
92             if (hwnd && GetClientRect(hwnd,&xrc))
93             {
94                 OffsetRect(&xrc,offset.x,offset.y);
95                 IntersectRect(&drawrect,&drawrect,&xrc);
96             }
97         }
98 #endif
99         if (rc)
100         {
101             IntersectRect(&drawrect,&drawrect,rc);
102         }
103         else
104         {
105             /* Only use this if the caller did not pass a rectangle, since
106              * due to double locking this could be the wrong one ...
107              */
108             if (This->lockedRect.left != This->lockedRect.right)
109             {
110                 IntersectRect(&drawrect,&drawrect,&This->lockedRect);
111             }
112         }
113
114         BitBlt(hDisplayDC,
115                drawrect.left-offset.x, drawrect.top-offset.y,
116                drawrect.right-drawrect.left, drawrect.bottom-drawrect.top,
117                hSurfaceDC,
118                drawrect.left, drawrect.top,
119                SRCCOPY);
120         ReleaseDC(hDisplayWnd, hDisplayDC);
121     }
122 }
123
124 /*****************************************************************************
125  * IWineD3DSurface::PreLoad, GDI version
126  *
127  * This call is unsupported on GDI surfaces, if it's called something went
128  * wrong in the parent library. Write an informative warning
129  *
130  *****************************************************************************/
131 static void WINAPI
132 IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface)
133 {
134     ERR("(%p): PreLoad is not supported on X11 surfaces!\n", iface);
135     ERR("(%p): Most likely the parent library did something wrong.\n", iface);
136     ERR("(%p): Please report to wine-devel\n", iface);
137 }
138
139 /*****************************************************************************
140  * IWineD3DSurface::LockRect, GDI version
141  *
142  * Locks the surface and returns a pointer to the surface memory
143  *
144  * Params:
145  *  pLockedRect: Address to return the locking info at
146  *  pRect: Rectangle to lock
147  *  Flags: Some flags
148  *
149  * Returns:
150  *  WINED3D_OK on success
151  *  WINED3DERR_INVALIDCALL on errors
152  *
153  *****************************************************************************/
154 static HRESULT WINAPI
155 IWineGDISurfaceImpl_LockRect(IWineD3DSurface *iface,
156                              WINED3DLOCKED_RECT* pLockedRect,
157                              CONST RECT* pRect,
158                              DWORD Flags)
159 {
160     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
161
162     /* Already locked? */
163     if(This->Flags & SFLAG_LOCKED)
164     {
165         ERR("(%p) Surface already locked\n", This);
166         /* What should I return here? */
167         return D3DERR_INVALIDCALL;
168     }
169
170     if (!(This->Flags & SFLAG_LOCKABLE))
171     {
172         /* This is some GL specific thing, see the OpenGL version of
173          * this method, but check for the flag and write a trace
174          */
175         TRACE("Warning: trying to lock unlockable surf@%p\n", This);
176     }
177
178     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
179           This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
180
181     if(!This->resource.allocatedMemory) {
182         HDC hdc;
183         HRESULT hr;
184         /* This happens on gdi surfaces if the application set a user pointer and resets it.
185          * Recreate the DIB section
186          */
187         hr = IWineD3DSurface_GetDC(iface, &hdc);  /* will recursively call lockrect, do not set the LOCKED flag to this line */
188         if(hr != WINED3D_OK) return hr;
189         hr = IWineD3DSurface_ReleaseDC(iface, hdc);
190         if(hr != WINED3D_OK) return hr;
191     }
192
193     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
194
195     if (NULL == pRect)
196     {
197         pLockedRect->pBits = This->resource.allocatedMemory;
198         This->lockedRect.left   = 0;
199         This->lockedRect.top    = 0;
200         This->lockedRect.right  = This->currentDesc.Width;
201         This->lockedRect.bottom = This->currentDesc.Height;
202
203         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
204         &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
205         This->lockedRect.right, This->lockedRect.bottom);
206     }
207     else
208     {
209         TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
210               pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
211
212         if ((pRect->top < 0) ||
213              (pRect->left < 0) ||
214              (pRect->left >= pRect->right) ||
215              (pRect->top >= pRect->bottom) ||
216              (pRect->right > This->currentDesc.Width) ||
217              (pRect->bottom > This->currentDesc.Height))
218         {
219             WARN(" Invalid values in pRect !!!\n");
220             return D3DERR_INVALIDCALL;
221         }
222
223         if (This->resource.format == WINED3DFMT_DXT1)
224         {
225             /* DXT1 is half byte per pixel */
226             pLockedRect->pBits = This->resource.allocatedMemory +
227                                   (pLockedRect->Pitch * pRect->top) +
228                                   ((pRect->left * This->bytesPerPixel / 2));
229         }
230         else
231         {
232             pLockedRect->pBits = This->resource.allocatedMemory +
233                                  (pLockedRect->Pitch * pRect->top) +
234                                  (pRect->left * This->bytesPerPixel);
235         }
236         This->lockedRect.left   = pRect->left;
237         This->lockedRect.top    = pRect->top;
238         This->lockedRect.right  = pRect->right;
239         This->lockedRect.bottom = pRect->bottom;
240     }
241
242     /* No dirtifying is needed for this surface implementation */
243     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
244
245     This->Flags |= SFLAG_LOCKED;
246     return D3D_OK;
247 }
248
249 /*****************************************************************************
250  * IWineD3DSurface::UnlockRect, GDI version
251  *
252  * Unlocks a surface. This implementation doesn't do much, except updating
253  * the window if the front buffer is unlocked
254  *
255  * Returns:
256  *  WINED3D_OK on success
257  *  WINED3DERR_INVALIDCALL on failure
258  *
259  *****************************************************************************/
260 static HRESULT WINAPI
261 IWineGDISurfaceImpl_UnlockRect(IWineD3DSurface *iface)
262 {
263     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
264     IWineD3DDeviceImpl *dev = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
265     TRACE("(%p)\n", This);
266
267     if (!(This->Flags & SFLAG_LOCKED))
268     {
269         WARN("trying to Unlock an unlocked surf@%p\n", This);
270         return WINED3DERR_INVALIDCALL;
271     }
272
273     /* Can be useful for debugging */
274 #if 0
275         {
276             static unsigned int gen = 0;
277             char buffer[4096];
278             ++gen;
279             if ((gen % 10) == 0) {
280                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
281                 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
282             }
283             /*
284              * debugging crash code
285             if (gen == 250) {
286               void** test = NULL;
287               *test = 0;
288             }
289             */
290         }
291 #endif
292
293     /* Update the screen */
294     if(This == (IWineD3DSurfaceImpl *) dev->ddraw_primary)
295     {
296         x11_copy_to_screen(This, &This->lockedRect);
297     }
298
299     This->Flags &= ~SFLAG_LOCKED;
300     memset(&This->lockedRect, 0, sizeof(RECT));
301     return WINED3D_OK;
302 }
303
304 /*****************************************************************************
305  * IWineD3DSurface::Flip, GDI version
306  *
307  * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
308  * the parent library. This implementation changes the data pointers of the
309  * surfaces and copies the new front buffer content to the screen
310  *
311  * Params:
312  *  override: Flipping target(e.g. back buffer)
313  *
314  * Returns:
315  *  WINED3D_OK on success
316  *
317  *****************************************************************************/
318 static HRESULT WINAPI
319 IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface,
320                          IWineD3DSurface *override,
321                          DWORD Flags)
322 {
323     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
324     IWineD3DSurfaceImpl *Target = (IWineD3DSurfaceImpl *) override;
325     TRACE("(%p)->(%p,%x)\n", This, override, Flags);
326
327     TRACE("(%p) Flipping to surface %p\n", This, Target);
328
329     if(Target == NULL)
330     {
331         ERR("(%p): Can't flip without a target\n", This);
332         return WINED3DERR_INVALIDCALL;
333     }
334
335     /* Flip the DC */
336     {
337         HDC tmp;
338         tmp = This->hDC;
339         This->hDC = Target->hDC;
340         Target->hDC = tmp;
341     }
342
343     /* Flip the DIBsection */
344     {
345         HBITMAP tmp;
346         tmp = This->dib.DIBsection;
347         This->dib.DIBsection = Target->dib.DIBsection;
348         Target->dib.DIBsection = tmp;
349     }
350
351     /* Flip the surface data */
352     {
353         void* tmp;
354
355         tmp = This->dib.bitmap_data;
356         This->dib.bitmap_data = Target->dib.bitmap_data;
357         Target->dib.bitmap_data = tmp;
358
359         tmp = This->resource.allocatedMemory;
360         This->resource.allocatedMemory = Target->resource.allocatedMemory;
361         Target->resource.allocatedMemory = tmp;
362     }
363
364     /* client_memory should not be different, but just in case */
365     {
366         BOOL tmp;
367         tmp = This->dib.client_memory;
368         This->dib.client_memory = Target->dib.client_memory;
369         Target->dib.client_memory = tmp;
370     }
371
372     /* Useful for debugging */
373 #if 0
374         {
375             static unsigned int gen = 0;
376             char buffer[4096];
377             ++gen;
378             if ((gen % 10) == 0) {
379                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
380                 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
381             }
382             /*
383              * debugging crash code
384             if (gen == 250) {
385               void** test = NULL;
386               *test = 0;
387             }
388             */
389         }
390 #endif
391
392     /* Update the screen */
393     x11_copy_to_screen(This, NULL);
394
395     /* FPS support */
396     if (TRACE_ON(fps))
397     {
398         static long prev_time, frames;
399
400         DWORD time = GetTickCount();
401         frames++;
402         /* every 1.5 seconds */
403         if (time - prev_time > 1500) {
404             TRACE_(fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
405             prev_time = time;
406             frames = 0;
407         }
408     }
409
410     return WINED3D_OK;
411 }
412
413 /*****************************************************************************
414  * _Blt_ColorFill
415  *
416  * Helper function that fills a memory area with a specific color
417  *
418  * Params:
419  *  buf: memory address to start filling at
420  *  width, height: Dimensions of the area to fill
421  *  bpp: Bit depth of the surface
422  *  lPitch: pitch of the surface
423  *  color: Color to fill with
424  *
425  *****************************************************************************/
426 static HRESULT
427 _Blt_ColorFill(BYTE *buf,
428                int width, int height,
429                int bpp, LONG lPitch,
430                DWORD color)
431 {
432     int x, y;
433     LPBYTE first;
434
435     /* Do first row */
436
437 #define COLORFILL_ROW(type) \
438 { \
439     type *d = (type *) buf; \
440     for (x = 0; x < width; x++) \
441         d[x] = (type) color; \
442     break; \
443 }
444     switch(bpp)
445     {
446         case 1: COLORFILL_ROW(BYTE)
447         case 2: COLORFILL_ROW(WORD)
448         case 3:
449         {
450             BYTE *d = (BYTE *) buf;
451             for (x = 0; x < width; x++,d+=3)
452             {
453                 d[0] = (color    ) & 0xFF;
454                 d[1] = (color>> 8) & 0xFF;
455                 d[2] = (color>>16) & 0xFF;
456             }
457             break;
458         }
459         case 4: COLORFILL_ROW(DWORD)
460         default:
461             FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
462             return DDERR_UNSUPPORTED;
463     }
464
465 #undef COLORFILL_ROW
466
467     /* Now copy first row */
468     first = buf;
469     for (y = 1; y < height; y++)
470     {
471         buf += lPitch;
472         memcpy(buf, first, width * bpp);
473     }
474     return DD_OK;
475 }
476
477 /*****************************************************************************
478  * IWineD3DSurface::Blt, GDI version
479  *
480  * Performs blits to a surface, eigher from a source of source-less blts
481  * This is the main functionality of DirectDraw
482  *
483  * Params:
484  *  DestRect: Destination rectangle to write to
485  *  SrcSurface: Source surface, can be NULL
486  *  SrcRect: Source rectangle
487  *****************************************************************************/
488 HRESULT WINAPI
489 IWineGDISurfaceImpl_Blt(IWineD3DSurface *iface,
490                         RECT *DestRect,
491                         IWineD3DSurface *SrcSurface,
492                         RECT *SrcRect,
493                         DWORD Flags,
494                         DDBLTFX *DDBltFx)
495 {
496     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
497     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
498     RECT                xdst,xsrc;
499     HRESULT             ret = DD_OK;
500     WINED3DLOCKED_RECT  dlock, slock;
501     WINED3DFORMAT       dfmt = WINED3DFMT_UNKNOWN, sfmt = WINED3DFMT_UNKNOWN;
502     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
503     int x, y;
504     const PixelFormatDesc *sEntry, *dEntry;
505     LPBYTE dbuf, sbuf;
506     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
507
508     if (TRACE_ON(d3d_surface))
509     {
510         if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
511         DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
512         if (SrcRect) TRACE("\tsrcrect  :%dx%d-%dx%d\n",
513         SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
514 #if 0
515         TRACE("\tflags: ");
516         DDRAW_dump_DDBLT(Flags);
517         if (Flags & DDBLT_DDFX)
518         {
519             TRACE("\tblitfx: ");
520             DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
521         }
522 #endif
523     }
524
525     if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
526     {
527         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
528         return DDERR_SURFACEBUSY;
529     }
530
531     if (Src == This)
532     {
533         IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
534         dfmt = This->resource.format;
535         slock = dlock;
536         sfmt = dfmt;
537         sEntry = getFormatDescEntry(sfmt);
538         dEntry = sEntry;
539     }
540     else
541     {
542         if (Src)
543         {
544             IWineD3DSurface_LockRect(SrcSurface, &slock, NULL, WINED3DLOCK_READONLY);
545             sfmt = Src->resource.format;
546         }
547         sEntry = getFormatDescEntry(sfmt);
548         dfmt = This->resource.format;
549         dEntry = getFormatDescEntry(dfmt);
550         IWineD3DSurface_LockRect(iface, &dlock,NULL,0);
551     }
552
553     if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~DDBLT_DDFX;
554
555     if (sEntry->isFourcc && dEntry->isFourcc)
556     {
557         if (sfmt != dfmt)
558         {
559             FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
560             ret = DDERR_INVALIDPIXELFORMAT;
561             goto release;
562         }
563         TRACE("Fourcc->Fourcc copy)\n");
564         memcpy(dlock.pBits, slock.pBits, This->currentDesc.Height * dlock.Pitch);
565         goto release;
566     }
567
568     if (sEntry->isFourcc && !dEntry->isFourcc)
569     {
570         FIXME("DXTC decompression not supported right now\n");
571         goto release;
572     }
573
574     if (DestRect)
575     {
576         memcpy(&xdst,DestRect,sizeof(xdst));
577     }
578     else
579     {
580         xdst.top        = 0;
581         xdst.bottom     = This->currentDesc.Height;
582         xdst.left       = 0;
583         xdst.right      = This->currentDesc.Width;
584     }
585
586     if (SrcRect)
587     {
588         memcpy(&xsrc,SrcRect,sizeof(xsrc));
589     }
590     else
591     {
592         if (Src)
593         {
594             xsrc.top    = 0;
595             xsrc.bottom = Src->currentDesc.Height;
596             xsrc.left   = 0;
597             xsrc.right  = Src->currentDesc.Width;
598         }
599         else
600         {
601             memset(&xsrc,0,sizeof(xsrc));
602         }
603     }
604
605     /* First check for the validity of source / destination rectangles. This was
606       verified using a test application + by MSDN.
607     */
608     if ((Src != NULL) &&
609         ((xsrc.bottom > Src->currentDesc.Height) || (xsrc.bottom < 0) ||
610         (xsrc.top     > Src->currentDesc.Height) || (xsrc.top    < 0) ||
611         (xsrc.left    > Src->currentDesc.Width)  || (xsrc.left   < 0) ||
612         (xsrc.right   > Src->currentDesc.Width)  || (xsrc.right  < 0) ||
613         (xsrc.right   < xsrc.left)               || (xsrc.bottom < xsrc.top)))
614     {
615         WARN("Application gave us bad source rectangle for Blt.\n");
616         ret = DDERR_INVALIDRECT;
617         goto release;
618     }
619     /* For the Destination rect, it can be out of bounds on the condition that a clipper
620       is set for the given surface.
621     */
622     if ((/*This->clipper == NULL*/ TRUE) &&
623         ((xdst.bottom  > This->currentDesc.Height) || (xdst.bottom < 0) ||
624         (xdst.top      > This->currentDesc.Height) || (xdst.top    < 0) ||
625         (xdst.left     > This->currentDesc.Width)  || (xdst.left   < 0) ||
626         (xdst.right    > This->currentDesc.Width)  || (xdst.right  < 0) ||
627         (xdst.right    < xdst.left)                || (xdst.bottom < xdst.top)))
628     {
629         WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
630         ret = DDERR_INVALIDRECT;
631         goto release;
632     }
633
634     /* Now handle negative values in the rectangles. Warning: only supported for now
635       in the 'simple' cases (ie not in any stretching / rotation cases).
636
637       First, the case where nothing is to be done.
638     */
639     if (((xdst.bottom <= 0) || (xdst.right <= 0)         ||
640          (xdst.top    >= (int) This->currentDesc.Height) ||
641          (xdst.left   >= (int) This->currentDesc.Width)) ||
642         ((Src != NULL) &&
643         ((xsrc.bottom <= 0) || (xsrc.right <= 0)     ||
644          (xsrc.top >= (int) Src->currentDesc.Height) ||
645          (xsrc.left >= (int) Src->currentDesc.Width))  ))
646     {
647         TRACE("Nothing to be done !\n");
648         goto release;
649     }
650
651     /* The easy case : the source-less blits.... */
652     if (Src == NULL)
653     {
654         RECT full_rect;
655         RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
656
657         full_rect.left   = 0;
658         full_rect.top    = 0;
659         full_rect.right  = This->currentDesc.Width;
660         full_rect.bottom = This->currentDesc.Height;
661         IntersectRect(&temp_rect, &full_rect, &xdst);
662         xdst = temp_rect;
663     }
664     else
665     {
666         /* Only handle clipping on the destination rectangle */
667         int clip_horiz = (xdst.left < 0) || (xdst.right  > (int) This->currentDesc.Width );
668         int clip_vert  = (xdst.top  < 0) || (xdst.bottom > (int) This->currentDesc.Height);
669         if (clip_vert || clip_horiz)
670         {
671             /* Now check if this is a special case or not... */
672             if ((((xdst.bottom - xdst.top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
673                 (((xdst.right  - xdst.left) != (xsrc.right  - xsrc.left)) && clip_horiz) ||
674                 (Flags & DDBLT_DDFX))
675             {
676                 WARN("Out of screen rectangle in special case. Not handled right now.\n");
677                 goto release;
678             }
679
680             if (clip_horiz)
681             {
682                 if (xdst.left < 0) { xsrc.left -= xdst.left; xdst.left = 0; }
683                 if (xdst.right > This->currentDesc.Width)
684                 {
685                     xsrc.right -= (xdst.right - (int) This->currentDesc.Width);
686                     xdst.right = (int) This->currentDesc.Width;
687                 }
688             }
689             if (clip_vert)
690             {
691                 if (xdst.top < 0)
692                 {
693                     xsrc.top -= xdst.top;
694                     xdst.top = 0;
695                 }
696                 if (xdst.bottom > This->currentDesc.Height)
697                 {
698                     xsrc.bottom -= (xdst.bottom - (int) This->currentDesc.Height);
699                     xdst.bottom = (int) This->currentDesc.Height;
700                 }
701             }
702             /* And check if after clipping something is still to be done... */
703             if ((xdst.bottom <= 0)   || (xdst.right <= 0)       ||
704                 (xdst.top   >= (int) This->currentDesc.Height)  ||
705                 (xdst.left  >= (int) This->currentDesc.Width)   ||
706                 (xsrc.bottom <= 0)   || (xsrc.right <= 0)       ||
707                 (xsrc.top >= (int) Src->currentDesc.Height)     ||
708                 (xsrc.left >= (int) Src->currentDesc.Width))
709             {
710                 TRACE("Nothing to be done after clipping !\n");
711                 goto release;
712             }
713         }
714     }
715
716     bpp = This->bytesPerPixel;
717     srcheight = xsrc.bottom - xsrc.top;
718     srcwidth = xsrc.right - xsrc.left;
719     dstheight = xdst.bottom - xdst.top;
720     dstwidth = xdst.right - xdst.left;
721     width = (xdst.right - xdst.left) * bpp;
722
723     assert(width <= dlock.Pitch);
724
725     dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
726
727     if (Flags & DDBLT_WAIT)
728     {
729         static BOOL displayed = FALSE;
730         if (!displayed)
731             FIXME("Can't handle DDBLT_WAIT flag right now.\n");
732         displayed = TRUE;
733         Flags &= ~DDBLT_WAIT;
734     }
735     if (Flags & DDBLT_ASYNC)
736     {
737         static BOOL displayed = FALSE;
738         if (!displayed)
739             FIXME("Can't handle DDBLT_ASYNC flag right now.\n");
740         displayed = TRUE;
741         Flags &= ~DDBLT_ASYNC;
742     }
743     if (Flags & DDBLT_DONOTWAIT)
744     {
745         /* DDBLT_DONOTWAIT appeared in DX7 */
746         static BOOL displayed = FALSE;
747         if (!displayed)
748             FIXME("Can't handle DDBLT_DONOTWAIT flag right now.\n");
749         displayed = TRUE;
750         Flags &= ~DDBLT_DONOTWAIT;
751     }
752
753     /* First, all the 'source-less' blits */
754     if (Flags & DDBLT_COLORFILL)
755     {
756         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
757                             dlock.Pitch, DDBltFx->u5.dwFillColor);
758         Flags &= ~DDBLT_COLORFILL;
759     }
760
761     if (Flags & DDBLT_DEPTHFILL)
762     {
763         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
764     }
765     if (Flags & DDBLT_ROP)
766     {
767         /* Catch some degenerate cases here */
768         switch(DDBltFx->dwROP)
769         {
770             case BLACKNESS:
771                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
772                 break;
773             case 0xAA0029: /* No-op */
774                 break;
775             case WHITENESS:
776                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
777                 break;
778             case SRCCOPY: /* well, we do that below ? */
779                 break;
780             default:
781                 FIXME("Unsupported raster op: %08x  Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
782                 goto error;
783         }
784         Flags &= ~DDBLT_ROP;
785     }
786     if (Flags & DDBLT_DDROPS)
787     {
788         FIXME("\tDdraw Raster Ops: %08x  Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
789     }
790     /* Now the 'with source' blits */
791     if (Src)
792     {
793         LPBYTE sbase;
794         int sx, xinc, sy, yinc;
795
796         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
797             goto release;
798         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
799         xinc = (srcwidth << 16) / dstwidth;
800         yinc = (srcheight << 16) / dstheight;
801
802         if (!Flags)
803         {
804             /* No effects, we can cheat here */
805             if (dstwidth == srcwidth)
806             {
807                 if (dstheight == srcheight)
808                 {
809                     /* No stretching in either direction. This needs to be as
810                     * fast as possible */
811                     sbuf = sbase;
812
813                     /* check for overlapping surfaces */
814                     if (SrcSurface != iface || xdst.top < xsrc.top ||
815                         xdst.right <= xsrc.left || xsrc.right <= xdst.left)
816                     {
817                         /* no overlap, or dst above src, so copy from top downwards */
818                         for (y = 0; y < dstheight; y++)
819                         {
820                             memcpy(dbuf, sbuf, width);
821                             sbuf += slock.Pitch;
822                             dbuf += dlock.Pitch;
823                         }
824                     }
825                     else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
826                     {
827                         sbuf += (slock.Pitch*dstheight);
828                         dbuf += (dlock.Pitch*dstheight);
829                         for (y = 0; y < dstheight; y++)
830                         {
831                             sbuf -= slock.Pitch;
832                             dbuf -= dlock.Pitch;
833                             memcpy(dbuf, sbuf, width);
834                         }
835                     }
836                     else /* src and dst overlapping on the same line, use memmove */
837                     {
838                         for (y = 0; y < dstheight; y++)
839                         {
840                             memmove(dbuf, sbuf, width);
841                             sbuf += slock.Pitch;
842                             dbuf += dlock.Pitch;
843                         }
844                     }
845                 } else {
846                     /* Stretching in Y direction only */
847                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
848                         sbuf = sbase + (sy >> 16) * slock.Pitch;
849                         memcpy(dbuf, sbuf, width);
850                         dbuf += dlock.Pitch;
851                     }
852                 }
853             }
854             else
855             {
856                 /* Stretching in X direction */
857                 int last_sy = -1;
858                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
859                 {
860                     sbuf = sbase + (sy >> 16) * slock.Pitch;
861
862                     if ((sy >> 16) == (last_sy >> 16))
863                     {
864                         /* this sourcerow is the same as last sourcerow -
865                          * copy already stretched row
866                          */
867                         memcpy(dbuf, dbuf - dlock.Pitch, width);
868                     }
869                     else
870                     {
871 #define STRETCH_ROW(type) { \
872                     type *s = (type *) sbuf, *d = (type *) dbuf; \
873                     for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
874                     d[x] = s[sx >> 16]; \
875                     break; }
876
877                     switch(bpp)
878                     {
879                         case 1: STRETCH_ROW(BYTE)
880                         case 2: STRETCH_ROW(WORD)
881                         case 4: STRETCH_ROW(DWORD)
882                         case 3:
883                         {
884                             LPBYTE s,d = dbuf;
885                             for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
886                             {
887                                 DWORD pixel;
888
889                                 s = sbuf+3*(sx>>16);
890                                 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
891                                 d[0] = (pixel    )&0xff;
892                                 d[1] = (pixel>> 8)&0xff;
893                                 d[2] = (pixel>>16)&0xff;
894                                 d+=3;
895                             }
896                             break;
897                     }
898                     default:
899                         FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
900                         ret = DDERR_UNSUPPORTED;
901                         goto error;
902                     }
903 #undef STRETCH_ROW
904                     }
905                     dbuf += dlock.Pitch;
906                     last_sy = sy;
907                 }
908             }
909         }
910         else
911         {
912           LONG dstyinc = dlock.Pitch, dstxinc = bpp;
913           DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
914           if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE))
915           {
916
917               if (Flags & DDBLT_KEYSRC)
918               {
919                 keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
920                 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
921               }
922               else if (Flags & DDBLT_KEYDEST)
923               {
924                 keylow  = This->DestBltCKey.dwColorSpaceLowValue;
925                 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
926               }
927               else if (Flags & DDBLT_KEYSRCOVERRIDE)
928               {
929                 keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
930                 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
931               }
932               else
933               {
934                 keylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
935                 keyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
936               }
937               if(bpp == 1)
938               {
939                   keymask = 0xff;
940               }
941               else
942               {
943                   keymask = sEntry->redMask   |
944                             sEntry->greenMask |
945                             sEntry->blueMask;
946               }
947               Flags &= ~(DDBLT_KEYSRC | DDBLT_KEYDEST | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE);
948           }
949
950           if (Flags & DDBLT_DDFX)
951           {
952               LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
953               LONG tmpxy;
954               dTopLeft     = dbuf;
955               dTopRight    = dbuf+((dstwidth-1)*bpp);
956               dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
957               dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
958
959               if (DDBltFx->dwDDFX & DDBLTFX_ARITHSTRETCHY)
960               {
961                 /* I don't think we need to do anything about this flag */
962                 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_ARITHSTRETCHY\n");
963               }
964               if (DDBltFx->dwDDFX & DDBLTFX_MIRRORLEFTRIGHT)
965               {
966                 tmp          = dTopRight;
967                 dTopRight    = dTopLeft;
968                 dTopLeft     = tmp;
969                 tmp          = dBottomRight;
970                 dBottomRight = dBottomLeft;
971                 dBottomLeft  = tmp;
972                 dstxinc = dstxinc *-1;
973               }
974               if (DDBltFx->dwDDFX & DDBLTFX_MIRRORUPDOWN)
975               {
976                 tmp          = dTopLeft;
977                 dTopLeft     = dBottomLeft;
978                 dBottomLeft  = tmp;
979                 tmp          = dTopRight;
980                 dTopRight    = dBottomRight;
981                 dBottomRight = tmp;
982                 dstyinc = dstyinc *-1;
983               }
984               if (DDBltFx->dwDDFX & DDBLTFX_NOTEARING)
985               {
986                 /* I don't think we need to do anything about this flag */
987                 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_NOTEARING\n");
988               }
989               if (DDBltFx->dwDDFX & DDBLTFX_ROTATE180)
990               {
991                 tmp          = dBottomRight;
992                 dBottomRight = dTopLeft;
993                 dTopLeft     = tmp;
994                 tmp          = dBottomLeft;
995                 dBottomLeft  = dTopRight;
996                 dTopRight    = tmp;
997                 dstxinc = dstxinc * -1;
998                 dstyinc = dstyinc * -1;
999               }
1000               if (DDBltFx->dwDDFX & DDBLTFX_ROTATE270)
1001               {
1002                 tmp          = dTopLeft;
1003                 dTopLeft     = dBottomLeft;
1004                 dBottomLeft  = dBottomRight;
1005                 dBottomRight = dTopRight;
1006                 dTopRight    = tmp;
1007                 tmpxy   = dstxinc;
1008                 dstxinc = dstyinc;
1009                 dstyinc = tmpxy;
1010                 dstxinc = dstxinc * -1;
1011               }
1012               if (DDBltFx->dwDDFX & DDBLTFX_ROTATE90)
1013               {
1014                 tmp          = dTopLeft;
1015                 dTopLeft     = dTopRight;
1016                 dTopRight    = dBottomRight;
1017                 dBottomRight = dBottomLeft;
1018                 dBottomLeft  = tmp;
1019                 tmpxy   = dstxinc;
1020                 dstxinc = dstyinc;
1021                 dstyinc = tmpxy;
1022                 dstyinc = dstyinc * -1;
1023               }
1024               if (DDBltFx->dwDDFX & DDBLTFX_ZBUFFERBASEDEST)
1025               {
1026                 /* I don't think we need to do anything about this flag */
1027                 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_ZBUFFERBASEDEST\n");
1028               }
1029               dbuf = dTopLeft;
1030               Flags &= ~(DDBLT_DDFX);
1031           }
1032
1033 #define COPY_COLORKEY_FX(type) { \
1034             type *s, *d = (type *) dbuf, *dx, tmp; \
1035             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1036               s = (type*)(sbase + (sy >> 16) * slock.Pitch); \
1037               dx = d; \
1038               for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1039                   tmp = s[sx >> 16]; \
1040                   if ((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) dx[0] = tmp; \
1041                   dx = (type*)(((LPBYTE)dx)+dstxinc); \
1042               } \
1043               d = (type*)(((LPBYTE)d)+dstyinc); \
1044             } \
1045             break; }
1046
1047             switch (bpp) {
1048             case 1: COPY_COLORKEY_FX(BYTE)
1049             case 2: COPY_COLORKEY_FX(WORD)
1050             case 4: COPY_COLORKEY_FX(DWORD)
1051             case 3:
1052             {
1053                 LPBYTE s,d = dbuf, dx;
1054                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1055                 {
1056                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1057                     dx = d;
1058                     for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1059                     {
1060                         DWORD pixel;
1061                         s = sbuf+3*(sx>>16);
1062                         pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1063                         if ((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
1064                         {
1065                             dx[0] = (pixel    )&0xff;
1066                             dx[1] = (pixel>> 8)&0xff;
1067                             dx[2] = (pixel>>16)&0xff;
1068                         }
1069                         dx+= dstxinc;
1070                     }
1071                     d += dstyinc;
1072                 }
1073                 break;
1074             }
1075             default:
1076               FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1077                   (Flags & DDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1078                   ret = DDERR_UNSUPPORTED;
1079                   goto error;
1080 #undef COPY_COLORKEY_FX
1081             }
1082         }
1083     }
1084
1085 error:
1086     if (Flags && FIXME_ON(d3d_surface))
1087     {
1088         FIXME("\tUnsupported flags: %08x\n", Flags);
1089     }
1090
1091 release:
1092     IWineD3DSurface_UnlockRect(iface);
1093     if (SrcSurface && SrcSurface != iface) IWineD3DSurface_UnlockRect(SrcSurface);
1094     return ret;
1095 }
1096
1097 /*****************************************************************************
1098  * IWineD3DSurface::BltFast, GDI version
1099  *
1100  * This is the software implementation of BltFast, as used by GDI surfaces
1101  * and as a fallback for OpenGL surfaces. This code is taken from the old
1102  * DirectDraw code, and was originally written by TransGaming.
1103  *
1104  * Params:
1105  *  dstx:
1106  *  dsty:
1107  *  Source: Source surface to copy from
1108  *  rsrc: Source rectangle
1109  *  trans: Some Flags
1110  *
1111  * Returns:
1112  *  WINED3D_OK on success
1113  *
1114  *****************************************************************************/
1115 HRESULT WINAPI
1116 IWineGDISurfaceImpl_BltFast(IWineD3DSurface *iface,
1117                             DWORD dstx,
1118                             DWORD dsty,
1119                             IWineD3DSurface *Source,
1120                             RECT *rsrc,
1121                             DWORD trans)
1122 {
1123     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1124     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1125
1126     int                 bpp, w, h, x, y;
1127     WINED3DLOCKED_RECT  dlock,slock;
1128     HRESULT             ret = DD_OK;
1129     RECT                rsrc2;
1130     RECT                lock_src, lock_dst, lock_union;
1131     BYTE                *sbuf, *dbuf;
1132     const PixelFormatDesc *sEntry, *dEntry;
1133
1134     if (TRACE_ON(d3d_surface))
1135     {
1136         TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1137
1138         if (rsrc)
1139         {
1140             TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1141                   rsrc->right,rsrc->bottom);
1142         }
1143         else
1144         {
1145             TRACE(" srcrect: NULL\n");
1146         }
1147     }
1148
1149     if ((This->Flags & SFLAG_LOCKED) ||
1150         ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
1151     {
1152         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1153         return DDERR_SURFACEBUSY;
1154     }
1155
1156     if (!rsrc)
1157     {
1158         WARN("rsrc is NULL!\n");
1159         rsrc = &rsrc2;
1160         rsrc->left = 0;
1161         rsrc->top = 0;
1162         rsrc->right = Src->currentDesc.Width;
1163         rsrc->bottom = Src->currentDesc.Height;
1164     }
1165
1166     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1167     if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1168         (rsrc->top    > Src->currentDesc.Height) || (rsrc->top    < 0) ||
1169         (rsrc->left   > Src->currentDesc.Width)  || (rsrc->left   < 0) ||
1170         (rsrc->right  > Src->currentDesc.Width)  || (rsrc->right  < 0) ||
1171         (rsrc->right  < rsrc->left)              || (rsrc->bottom < rsrc->top))
1172     {
1173         WARN("Application gave us bad source rectangle for BltFast.\n");
1174         return DDERR_INVALIDRECT;
1175     }
1176
1177     h = rsrc->bottom - rsrc->top;
1178     if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1179     if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1180     if (h <= 0) return DDERR_INVALIDRECT;
1181
1182     w = rsrc->right - rsrc->left;
1183     if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1184     if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1185     if (w <= 0) return DDERR_INVALIDRECT;
1186
1187     /* Now compute the locking rectangle... */
1188     lock_src.left = rsrc->left;
1189     lock_src.top = rsrc->top;
1190     lock_src.right = lock_src.left + w;
1191     lock_src.bottom = lock_src.top + h;
1192
1193     lock_dst.left = dstx;
1194     lock_dst.top = dsty;
1195     lock_dst.right = dstx + w;
1196     lock_dst.bottom = dsty + h;
1197
1198     bpp = This->bytesPerPixel;
1199
1200     /* We need to lock the surfaces, or we won't get refreshes when done. */
1201     if (Src == This)
1202     {
1203         int pitch;
1204
1205         UnionRect(&lock_union, &lock_src, &lock_dst);
1206
1207         /* Lock the union of the two rectangles */
1208         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1209         if(ret != D3D_OK) goto error;
1210
1211         pitch = dlock.Pitch;
1212         slock.Pitch = dlock.Pitch;
1213
1214         /* Since slock was originally copied from this surface's description, we can just reuse it */
1215         assert(This->resource.allocatedMemory != NULL);
1216         sbuf = (BYTE *)This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1217         dbuf = (BYTE *)This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1218         sEntry = getFormatDescEntry(Src->resource.format);
1219         dEntry = sEntry;
1220     }
1221     else
1222     {
1223         ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1224         if(ret != D3D_OK) goto error;
1225         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1226         if(ret != D3D_OK) goto error;
1227
1228         sbuf = slock.pBits;
1229         dbuf = dlock.pBits;
1230         TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1231
1232         sEntry = getFormatDescEntry(Src->resource.format);
1233         dEntry = getFormatDescEntry(This->resource.format);
1234     }
1235
1236     /* Handle first the FOURCC surfaces... */
1237     if (sEntry->isFourcc && dEntry->isFourcc)
1238     {
1239         TRACE("Fourcc -> Fourcc copy\n");
1240         if (trans)
1241             FIXME("trans arg not supported when a FOURCC surface is involved\n");
1242         if (dstx || dsty)
1243             FIXME("offset for destination surface is not supported\n");
1244         if (Src->resource.format != This->resource.format)
1245         {
1246             FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1247             ret = DDERR_INVALIDPIXELFORMAT;
1248             goto error;
1249         }
1250         /* FIXME: Watch out that the size is correct for FOURCC surfaces */
1251         memcpy(dbuf, sbuf, This->resource.size);
1252         goto error;
1253     }
1254     if (sEntry->isFourcc && !dEntry->isFourcc)
1255     {
1256         /* TODO: Use the libtxc_dxtn.so shared library to do
1257          * software decompression
1258          */
1259         ERR("DXTC decompression not supported by now\n");
1260         goto error;
1261     }
1262
1263     if (trans & (DDBLTFAST_SRCCOLORKEY | DDBLTFAST_DESTCOLORKEY))
1264     {
1265         DWORD keylow, keyhigh;
1266         TRACE("Color keyed copy\n");
1267         if (trans & DDBLTFAST_SRCCOLORKEY)
1268         {
1269             keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1270             keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1271         }
1272         else
1273         {
1274             /* I'm not sure if this is correct */
1275             FIXME("DDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1276             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1277             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1278         }
1279
1280 #define COPYBOX_COLORKEY(type) { \
1281             type *d, *s, tmp; \
1282             s = (type *) sbuf; \
1283             d = (type *) dbuf; \
1284             for (y = 0; y < h; y++) { \
1285                 for (x = 0; x < w; x++) { \
1286                     tmp = s[x]; \
1287                     if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1288                 } \
1289                 s = (type *)((BYTE *)s + slock.Pitch); \
1290                 d = (type *)((BYTE *)d + dlock.Pitch); \
1291             } \
1292             break; \
1293         }
1294
1295         switch (bpp) {
1296             case 1: COPYBOX_COLORKEY(BYTE)
1297             case 2: COPYBOX_COLORKEY(WORD)
1298             case 4: COPYBOX_COLORKEY(DWORD)
1299             case 3:
1300             {
1301                 BYTE *d, *s;
1302                 DWORD tmp;
1303                 s = (BYTE *) sbuf;
1304                 d = (BYTE *) dbuf;
1305                 for (y = 0; y < h; y++)
1306                 {
1307                     for (x = 0; x < w * 3; x += 3)
1308                     {
1309                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1310                         if (tmp < keylow || tmp > keyhigh)
1311                         {
1312                             d[x + 0] = s[x + 0];
1313                             d[x + 1] = s[x + 1];
1314                             d[x + 2] = s[x + 2];
1315                         }
1316                     }
1317                     s += slock.Pitch;
1318                     d += dlock.Pitch;
1319                 }
1320                 break;
1321             }
1322             default:
1323                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1324                 ret = DDERR_UNSUPPORTED;
1325                 goto error;
1326         }
1327 #undef COPYBOX_COLORKEY
1328         TRACE("Copy Done\n");
1329     }
1330     else
1331     {
1332         int width = w * bpp;
1333         TRACE("NO color key copy\n");
1334         for (y = 0; y < h; y++)
1335         {
1336             /* This is pretty easy, a line for line memcpy */
1337             memcpy(dbuf, sbuf, width);
1338             sbuf += slock.Pitch;
1339             dbuf += dlock.Pitch;
1340         }
1341         TRACE("Copy done\n");
1342     }
1343
1344 error:
1345     if (Src == This)
1346     {
1347         IWineD3DSurface_UnlockRect(iface);
1348     }
1349     else
1350     {
1351         IWineD3DSurface_UnlockRect(iface);
1352         IWineD3DSurface_UnlockRect(Source);
1353     }
1354
1355     return ret;
1356 }
1357
1358 /*****************************************************************************
1359  * IWineD3DSurface::LoadTexture, GDI version
1360  *
1361  * This is mutually unsupported by GDI surfaces
1362  *
1363  * Returns:
1364  *  D3DERR_INVALIDCALL
1365  *
1366  *****************************************************************************/
1367 HRESULT WINAPI
1368 IWineGDISurfaceImpl_LoadTexture(IWineD3DSurface *iface)
1369 {
1370     ERR("Unsupported on X11 surfaces\n");
1371     return D3DERR_INVALIDCALL;
1372 }
1373
1374 /*****************************************************************************
1375  * IWineD3DSurface::SaveSnapshot, GDI version
1376  *
1377  * This method writes the surface's contents to the in tga format to the
1378  * file specified in filename.
1379  *
1380  * Params:
1381  *  filename: File to write to
1382  *
1383  * Returns:
1384  *  WINED3DERR_INVALIDCALL if the file couldn't be opened
1385  *  WINED3D_OK on success
1386  *
1387  *****************************************************************************/
1388 static int get_shift(DWORD color_mask) {
1389     int shift = 0;
1390     while (color_mask > 0xFF) {
1391         color_mask >>= 1;
1392         shift += 1;
1393     }
1394     while ((color_mask & 0x80) == 0) {
1395         color_mask <<= 1;
1396         shift -= 1;
1397     }
1398     return shift;
1399 }
1400
1401
1402 HRESULT WINAPI
1403 IWineGDISurfaceImpl_SaveSnapshot(IWineD3DSurface *iface,
1404 const char* filename)
1405 {
1406     FILE* f = NULL;
1407     UINT y = 0, x = 0;
1408     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1409     static char *output = NULL;
1410     static int size = 0;
1411     const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1412
1413     if (This->pow2Width > size) {
1414         output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pow2Width * 3);
1415         size = This->pow2Width;
1416     }
1417
1418
1419     f = fopen(filename, "w+");
1420     if (NULL == f) {
1421         ERR("opening of %s failed with\n", filename);
1422         return WINED3DERR_INVALIDCALL;
1423     }
1424     fprintf(f, "P6\n%d %d\n255\n", This->pow2Width, This->pow2Height);
1425
1426     if (This->resource.format == WINED3DFMT_P8) {
1427         unsigned char table[256][3];
1428         int i;
1429
1430         if (This->palette == NULL) {
1431             fclose(f);
1432             return WINED3DERR_INVALIDCALL;
1433         }
1434         for (i = 0; i < 256; i++) {
1435             table[i][0] = This->palette->palents[i].peRed;
1436             table[i][1] = This->palette->palents[i].peGreen;
1437             table[i][2] = This->palette->palents[i].peBlue;
1438         }
1439         for (y = 0; y < This->pow2Height; y++) {
1440             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
1441             for (x = 0; x < This->pow2Width; x++) {
1442                 unsigned char color = *src;
1443                 src += 1;
1444
1445                 output[3 * x + 0] = table[color][0];
1446                 output[3 * x + 1] = table[color][1];
1447                 output[3 * x + 2] = table[color][2];
1448             }
1449             fwrite(output, 3 * This->pow2Width, 1, f);
1450         }
1451     } else {
1452         int red_shift, green_shift, blue_shift, pix_width;
1453
1454         pix_width = This->bytesPerPixel;
1455
1456         red_shift = get_shift(formatEntry->redMask);
1457         green_shift = get_shift(formatEntry->greenMask);
1458         blue_shift = get_shift(formatEntry->blueMask);
1459
1460         for (y = 0; y < This->pow2Height; y++) {
1461             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
1462             for (x = 0; x < This->pow2Width; x++) {         
1463                 unsigned int color;
1464                 unsigned int comp;
1465                 int i;
1466
1467                 color = 0;
1468                 for (i = 0; i < pix_width; i++) {
1469                     color |= src[i] << (8 * i);
1470                 }
1471                 src += 1 * pix_width;
1472
1473                 comp = color & formatEntry->redMask;
1474                 output[3 * x + 0] = red_shift > 0 ? comp >> red_shift : comp << -red_shift;
1475                 comp = color & formatEntry->greenMask;
1476                 output[3 * x + 1] = green_shift > 0 ? comp >> green_shift : comp << -green_shift;
1477                 comp = color & formatEntry->blueMask;
1478                 output[3 * x + 2] = blue_shift > 0 ? comp >> blue_shift : comp << -blue_shift;
1479             }
1480             fwrite(output, 3 * This->pow2Width, 1, f);
1481         }
1482     }
1483     fclose(f);
1484     return WINED3D_OK;
1485 }
1486
1487 /*****************************************************************************
1488  * IWineD3DSurface::PrivateSetup, GDI version
1489  *
1490  * Initializes the GDI surface, aka creates the DIB section we render to
1491  * The DIB section creation is done by calling GetDC, which will create the
1492  * section and releasing the dc to allow the app to use it. The dib section
1493  * will stay until the surface is released
1494  *
1495  * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1496  * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1497  * avoid confusion in the shared surface code.
1498  *
1499  * Returns:
1500  *  D3D_OK on success
1501  *  The return values of called methods on failure
1502  *
1503  *****************************************************************************/
1504 HRESULT WINAPI
1505 IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
1506 {
1507     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1508     HRESULT hr;
1509     HDC hdc;
1510     long oldsize = This->resource.size;
1511
1512     if(This->resource.usage & WINED3DUSAGE_OVERLAY)
1513     {
1514         ERR("(%p) Overlays not yet supported by GDI surfaces\n", This);
1515         return WINED3DERR_INVALIDCALL;
1516     }
1517     /* Sysmem textures have memory already allocated -
1518      * release it, this avoids an unnecessary memcpy
1519      */
1520     HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1521     This->resource.allocatedMemory = NULL;
1522
1523     /* We don't mind the nonpow2 stuff in GDI */
1524     This->resource.size = IWineD3DSurface_GetPitch(iface) * This->currentDesc.Height;
1525     This->pow2Size = This->resource.size;
1526     This->pow2Width = This->currentDesc.Width;
1527     This->pow2Height = This->currentDesc.Height;
1528     This->Flags &= ~SFLAG_NONPOW2;
1529
1530     /* Adjust the opengl mem counter */
1531     globalChangeGlRam(This->resource.size - oldsize);
1532
1533     /* Call GetDC to create a DIB section. We will use that
1534      * DIB section for rendering
1535      *
1536      * Release the DC afterwards to allow the app to use it
1537      */
1538     hr = IWineD3DSurface_GetDC(iface, &hdc);
1539     if(FAILED(hr))
1540     {
1541         ERR("(%p) IWineD3DSurface::GetDC failed with hr %08x\n", This, hr);
1542         return hr;
1543     }
1544     hr = IWineD3DSurface_ReleaseDC(iface, hdc);
1545     if(FAILED(hr))
1546     {
1547         ERR("(%p) IWineD3DSurface::ReleaseDC failed with hr %08x\n", This, hr);
1548         return hr;
1549     }
1550
1551     return WINED3D_OK;
1552 }
1553
1554 const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
1555 {
1556     /* IUnknown */
1557     IWineD3DSurfaceImpl_QueryInterface,
1558     IWineD3DSurfaceImpl_AddRef,
1559     IWineD3DSurfaceImpl_Release,
1560     /* IWineD3DResource */
1561     IWineD3DSurfaceImpl_GetParent,
1562     IWineD3DSurfaceImpl_GetDevice,
1563     IWineD3DSurfaceImpl_SetPrivateData,
1564     IWineD3DSurfaceImpl_GetPrivateData,
1565     IWineD3DSurfaceImpl_FreePrivateData,
1566     IWineD3DSurfaceImpl_SetPriority,
1567     IWineD3DSurfaceImpl_GetPriority,
1568     IWineGDISurfaceImpl_PreLoad,
1569     IWineD3DSurfaceImpl_GetType,
1570     /* IWineD3DSurface */
1571     IWineD3DSurfaceImpl_GetContainer,
1572     IWineD3DSurfaceImpl_GetDesc,
1573     IWineGDISurfaceImpl_LockRect,
1574     IWineGDISurfaceImpl_UnlockRect,
1575     IWineD3DSurfaceImpl_GetDC,
1576     IWineD3DSurfaceImpl_ReleaseDC,
1577     IWineGDISurfaceImpl_Flip,
1578     IWineGDISurfaceImpl_Blt,
1579     IWineD3DSurfaceImpl_GetBltStatus,
1580     IWineD3DSurfaceImpl_GetFlipStatus,
1581     IWineD3DSurfaceImpl_IsLost,
1582     IWineD3DSurfaceImpl_Restore,
1583     IWineGDISurfaceImpl_BltFast,
1584     IWineD3DSurfaceImpl_GetPalette,
1585     IWineD3DSurfaceImpl_SetPalette,
1586     IWineD3DSurfaceImpl_RealizePalette,
1587     IWineD3DSurfaceImpl_SetColorKey,
1588     IWineD3DSurfaceImpl_GetPitch,
1589     IWineD3DSurfaceImpl_SetMem,
1590     IWineD3DSurfaceImpl_SetOverlayPosition,
1591     IWineD3DSurfaceImpl_GetOverlayPosition,
1592     IWineD3DSurfaceImpl_UpdateOverlayZOrder,
1593     IWineD3DSurfaceImpl_UpdateOverlay,
1594     /* Internal use: */
1595     IWineD3DSurfaceImpl_CleanDirtyRect,
1596     IWineD3DSurfaceImpl_AddDirtyRect,
1597     IWineGDISurfaceImpl_LoadTexture,
1598     IWineGDISurfaceImpl_SaveSnapshot,
1599     IWineD3DSurfaceImpl_SetContainer,
1600     IWineD3DSurfaceImpl_SetPBufferState,
1601     IWineD3DSurfaceImpl_SetGlTextureDesc,
1602     IWineD3DSurfaceImpl_GetGlDesc,
1603     IWineD3DSurfaceImpl_GetData,
1604     IWineD3DSurfaceImpl_SetFormat,
1605     IWineGDISurfaceImpl_PrivateSetup
1606 };