msvcrt/tests: Properly remove temporary directory.
[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 WINED3DERR_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 WINED3DERR_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 WINED3D_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           DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
915           if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE))
916           {
917               /* The color keying flags are checked for correctness in ddraw */
918               if (Flags & DDBLT_KEYSRC)
919               {
920                 keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
921                 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
922               }
923               else  if (Flags & DDBLT_KEYSRCOVERRIDE)
924               {
925                 keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
926                 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
927               }
928
929               if (Flags & DDBLT_KEYDEST)
930               {
931                 /* Destination color keys are taken from the source surface ! */
932                 destkeylow  = Src->DestBltCKey.dwColorSpaceLowValue;
933                 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
934               }
935               else if (Flags & DDBLT_KEYDESTOVERRIDE)
936               {
937                 destkeylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
938                 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
939               }
940
941               if(bpp == 1)
942               {
943                   keymask = 0xff;
944               }
945               else
946               {
947                   keymask = sEntry->redMask   |
948                             sEntry->greenMask |
949                             sEntry->blueMask;
950               }
951               Flags &= ~(DDBLT_KEYSRC | DDBLT_KEYDEST | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE);
952           }
953
954           if (Flags & DDBLT_DDFX)
955           {
956               LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
957               LONG tmpxy;
958               dTopLeft     = dbuf;
959               dTopRight    = dbuf+((dstwidth-1)*bpp);
960               dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
961               dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
962
963               if (DDBltFx->dwDDFX & DDBLTFX_ARITHSTRETCHY)
964               {
965                 /* I don't think we need to do anything about this flag */
966                 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_ARITHSTRETCHY\n");
967               }
968               if (DDBltFx->dwDDFX & DDBLTFX_MIRRORLEFTRIGHT)
969               {
970                 tmp          = dTopRight;
971                 dTopRight    = dTopLeft;
972                 dTopLeft     = tmp;
973                 tmp          = dBottomRight;
974                 dBottomRight = dBottomLeft;
975                 dBottomLeft  = tmp;
976                 dstxinc = dstxinc *-1;
977               }
978               if (DDBltFx->dwDDFX & DDBLTFX_MIRRORUPDOWN)
979               {
980                 tmp          = dTopLeft;
981                 dTopLeft     = dBottomLeft;
982                 dBottomLeft  = tmp;
983                 tmp          = dTopRight;
984                 dTopRight    = dBottomRight;
985                 dBottomRight = tmp;
986                 dstyinc = dstyinc *-1;
987               }
988               if (DDBltFx->dwDDFX & DDBLTFX_NOTEARING)
989               {
990                 /* I don't think we need to do anything about this flag */
991                 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_NOTEARING\n");
992               }
993               if (DDBltFx->dwDDFX & DDBLTFX_ROTATE180)
994               {
995                 tmp          = dBottomRight;
996                 dBottomRight = dTopLeft;
997                 dTopLeft     = tmp;
998                 tmp          = dBottomLeft;
999                 dBottomLeft  = dTopRight;
1000                 dTopRight    = tmp;
1001                 dstxinc = dstxinc * -1;
1002                 dstyinc = dstyinc * -1;
1003               }
1004               if (DDBltFx->dwDDFX & DDBLTFX_ROTATE270)
1005               {
1006                 tmp          = dTopLeft;
1007                 dTopLeft     = dBottomLeft;
1008                 dBottomLeft  = dBottomRight;
1009                 dBottomRight = dTopRight;
1010                 dTopRight    = tmp;
1011                 tmpxy   = dstxinc;
1012                 dstxinc = dstyinc;
1013                 dstyinc = tmpxy;
1014                 dstxinc = dstxinc * -1;
1015               }
1016               if (DDBltFx->dwDDFX & DDBLTFX_ROTATE90)
1017               {
1018                 tmp          = dTopLeft;
1019                 dTopLeft     = dTopRight;
1020                 dTopRight    = dBottomRight;
1021                 dBottomRight = dBottomLeft;
1022                 dBottomLeft  = tmp;
1023                 tmpxy   = dstxinc;
1024                 dstxinc = dstyinc;
1025                 dstyinc = tmpxy;
1026                 dstyinc = dstyinc * -1;
1027               }
1028               if (DDBltFx->dwDDFX & DDBLTFX_ZBUFFERBASEDEST)
1029               {
1030                 /* I don't think we need to do anything about this flag */
1031                 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_ZBUFFERBASEDEST\n");
1032               }
1033               dbuf = dTopLeft;
1034               Flags &= ~(DDBLT_DDFX);
1035           }
1036
1037 #define COPY_COLORKEY_FX(type) { \
1038             type *s, *d = (type *) dbuf, *dx, tmp; \
1039             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1040               s = (type*)(sbase + (sy >> 16) * slock.Pitch); \
1041               dx = d; \
1042               for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1043                   tmp = s[sx >> 16]; \
1044                   if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1045                       ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1046                        dx[0] = tmp; \
1047                      } \
1048                   dx = (type*)(((LPBYTE)dx)+dstxinc); \
1049               } \
1050               d = (type*)(((LPBYTE)d)+dstyinc); \
1051             } \
1052             break; }
1053
1054             switch (bpp) {
1055             case 1: COPY_COLORKEY_FX(BYTE)
1056             case 2: COPY_COLORKEY_FX(WORD)
1057             case 4: COPY_COLORKEY_FX(DWORD)
1058             case 3:
1059             {
1060                 LPBYTE s,d = dbuf, dx;
1061                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1062                 {
1063                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1064                     dx = d;
1065                     for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1066                     {
1067                         DWORD pixel, dpixel = 0;
1068                         s = sbuf+3*(sx>>16);
1069                         pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1070                         dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1071                         if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1072                             ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1073                         {
1074                             dx[0] = (pixel    )&0xff;
1075                             dx[1] = (pixel>> 8)&0xff;
1076                             dx[2] = (pixel>>16)&0xff;
1077                         }
1078                         dx+= dstxinc;
1079                     }
1080                     d += dstyinc;
1081                 }
1082                 break;
1083             }
1084             default:
1085               FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1086                   (Flags & DDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1087                   ret = DDERR_UNSUPPORTED;
1088                   goto error;
1089 #undef COPY_COLORKEY_FX
1090             }
1091         }
1092     }
1093
1094 error:
1095     if (Flags && FIXME_ON(d3d_surface))
1096     {
1097         FIXME("\tUnsupported flags: %08x\n", Flags);
1098     }
1099
1100 release:
1101     IWineD3DSurface_UnlockRect(iface);
1102     if (SrcSurface && SrcSurface != iface) IWineD3DSurface_UnlockRect(SrcSurface);
1103     return ret;
1104 }
1105
1106 /*****************************************************************************
1107  * IWineD3DSurface::BltFast, GDI version
1108  *
1109  * This is the software implementation of BltFast, as used by GDI surfaces
1110  * and as a fallback for OpenGL surfaces. This code is taken from the old
1111  * DirectDraw code, and was originally written by TransGaming.
1112  *
1113  * Params:
1114  *  dstx:
1115  *  dsty:
1116  *  Source: Source surface to copy from
1117  *  rsrc: Source rectangle
1118  *  trans: Some Flags
1119  *
1120  * Returns:
1121  *  WINED3D_OK on success
1122  *
1123  *****************************************************************************/
1124 HRESULT WINAPI
1125 IWineGDISurfaceImpl_BltFast(IWineD3DSurface *iface,
1126                             DWORD dstx,
1127                             DWORD dsty,
1128                             IWineD3DSurface *Source,
1129                             RECT *rsrc,
1130                             DWORD trans)
1131 {
1132     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1133     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1134
1135     int                 bpp, w, h, x, y;
1136     WINED3DLOCKED_RECT  dlock,slock;
1137     HRESULT             ret = DD_OK;
1138     RECT                rsrc2;
1139     RECT                lock_src, lock_dst, lock_union;
1140     BYTE                *sbuf, *dbuf;
1141     const PixelFormatDesc *sEntry, *dEntry;
1142
1143     if (TRACE_ON(d3d_surface))
1144     {
1145         TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1146
1147         if (rsrc)
1148         {
1149             TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1150                   rsrc->right,rsrc->bottom);
1151         }
1152         else
1153         {
1154             TRACE(" srcrect: NULL\n");
1155         }
1156     }
1157
1158     if ((This->Flags & SFLAG_LOCKED) ||
1159         ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
1160     {
1161         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1162         return DDERR_SURFACEBUSY;
1163     }
1164
1165     if (!rsrc)
1166     {
1167         WARN("rsrc is NULL!\n");
1168         rsrc = &rsrc2;
1169         rsrc->left = 0;
1170         rsrc->top = 0;
1171         rsrc->right = Src->currentDesc.Width;
1172         rsrc->bottom = Src->currentDesc.Height;
1173     }
1174
1175     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1176     if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1177         (rsrc->top    > Src->currentDesc.Height) || (rsrc->top    < 0) ||
1178         (rsrc->left   > Src->currentDesc.Width)  || (rsrc->left   < 0) ||
1179         (rsrc->right  > Src->currentDesc.Width)  || (rsrc->right  < 0) ||
1180         (rsrc->right  < rsrc->left)              || (rsrc->bottom < rsrc->top))
1181     {
1182         WARN("Application gave us bad source rectangle for BltFast.\n");
1183         return DDERR_INVALIDRECT;
1184     }
1185
1186     h = rsrc->bottom - rsrc->top;
1187     if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1188     if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1189     if (h <= 0) return DDERR_INVALIDRECT;
1190
1191     w = rsrc->right - rsrc->left;
1192     if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1193     if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1194     if (w <= 0) return DDERR_INVALIDRECT;
1195
1196     /* Now compute the locking rectangle... */
1197     lock_src.left = rsrc->left;
1198     lock_src.top = rsrc->top;
1199     lock_src.right = lock_src.left + w;
1200     lock_src.bottom = lock_src.top + h;
1201
1202     lock_dst.left = dstx;
1203     lock_dst.top = dsty;
1204     lock_dst.right = dstx + w;
1205     lock_dst.bottom = dsty + h;
1206
1207     bpp = This->bytesPerPixel;
1208
1209     /* We need to lock the surfaces, or we won't get refreshes when done. */
1210     if (Src == This)
1211     {
1212         int pitch;
1213
1214         UnionRect(&lock_union, &lock_src, &lock_dst);
1215
1216         /* Lock the union of the two rectangles */
1217         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1218         if(ret != WINED3D_OK) goto error;
1219
1220         pitch = dlock.Pitch;
1221         slock.Pitch = dlock.Pitch;
1222
1223         /* Since slock was originally copied from this surface's description, we can just reuse it */
1224         assert(This->resource.allocatedMemory != NULL);
1225         sbuf = (BYTE *)This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1226         dbuf = (BYTE *)This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1227         sEntry = getFormatDescEntry(Src->resource.format);
1228         dEntry = sEntry;
1229     }
1230     else
1231     {
1232         ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1233         if(ret != WINED3D_OK) goto error;
1234         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1235         if(ret != WINED3D_OK) goto error;
1236
1237         sbuf = slock.pBits;
1238         dbuf = dlock.pBits;
1239         TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1240
1241         sEntry = getFormatDescEntry(Src->resource.format);
1242         dEntry = getFormatDescEntry(This->resource.format);
1243     }
1244
1245     /* Handle first the FOURCC surfaces... */
1246     if (sEntry->isFourcc && dEntry->isFourcc)
1247     {
1248         TRACE("Fourcc -> Fourcc copy\n");
1249         if (trans)
1250             FIXME("trans arg not supported when a FOURCC surface is involved\n");
1251         if (dstx || dsty)
1252             FIXME("offset for destination surface is not supported\n");
1253         if (Src->resource.format != This->resource.format)
1254         {
1255             FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1256             ret = DDERR_INVALIDPIXELFORMAT;
1257             goto error;
1258         }
1259         /* FIXME: Watch out that the size is correct for FOURCC surfaces */
1260         memcpy(dbuf, sbuf, This->resource.size);
1261         goto error;
1262     }
1263     if (sEntry->isFourcc && !dEntry->isFourcc)
1264     {
1265         /* TODO: Use the libtxc_dxtn.so shared library to do
1266          * software decompression
1267          */
1268         ERR("DXTC decompression not supported by now\n");
1269         goto error;
1270     }
1271
1272     if (trans & (DDBLTFAST_SRCCOLORKEY | DDBLTFAST_DESTCOLORKEY))
1273     {
1274         DWORD keylow, keyhigh;
1275         TRACE("Color keyed copy\n");
1276         if (trans & DDBLTFAST_SRCCOLORKEY)
1277         {
1278             keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1279             keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1280         }
1281         else
1282         {
1283             /* I'm not sure if this is correct */
1284             FIXME("DDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1285             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1286             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1287         }
1288
1289 #define COPYBOX_COLORKEY(type) { \
1290             type *d, *s, tmp; \
1291             s = (type *) sbuf; \
1292             d = (type *) dbuf; \
1293             for (y = 0; y < h; y++) { \
1294                 for (x = 0; x < w; x++) { \
1295                     tmp = s[x]; \
1296                     if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1297                 } \
1298                 s = (type *)((BYTE *)s + slock.Pitch); \
1299                 d = (type *)((BYTE *)d + dlock.Pitch); \
1300             } \
1301             break; \
1302         }
1303
1304         switch (bpp) {
1305             case 1: COPYBOX_COLORKEY(BYTE)
1306             case 2: COPYBOX_COLORKEY(WORD)
1307             case 4: COPYBOX_COLORKEY(DWORD)
1308             case 3:
1309             {
1310                 BYTE *d, *s;
1311                 DWORD tmp;
1312                 s = (BYTE *) sbuf;
1313                 d = (BYTE *) dbuf;
1314                 for (y = 0; y < h; y++)
1315                 {
1316                     for (x = 0; x < w * 3; x += 3)
1317                     {
1318                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1319                         if (tmp < keylow || tmp > keyhigh)
1320                         {
1321                             d[x + 0] = s[x + 0];
1322                             d[x + 1] = s[x + 1];
1323                             d[x + 2] = s[x + 2];
1324                         }
1325                     }
1326                     s += slock.Pitch;
1327                     d += dlock.Pitch;
1328                 }
1329                 break;
1330             }
1331             default:
1332                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1333                 ret = DDERR_UNSUPPORTED;
1334                 goto error;
1335         }
1336 #undef COPYBOX_COLORKEY
1337         TRACE("Copy Done\n");
1338     }
1339     else
1340     {
1341         int width = w * bpp;
1342         TRACE("NO color key copy\n");
1343         for (y = 0; y < h; y++)
1344         {
1345             /* This is pretty easy, a line for line memcpy */
1346             memcpy(dbuf, sbuf, width);
1347             sbuf += slock.Pitch;
1348             dbuf += dlock.Pitch;
1349         }
1350         TRACE("Copy done\n");
1351     }
1352
1353 error:
1354     if (Src == This)
1355     {
1356         IWineD3DSurface_UnlockRect(iface);
1357     }
1358     else
1359     {
1360         IWineD3DSurface_UnlockRect(iface);
1361         IWineD3DSurface_UnlockRect(Source);
1362     }
1363
1364     return ret;
1365 }
1366
1367 /*****************************************************************************
1368  * IWineD3DSurface::LoadTexture, GDI version
1369  *
1370  * This is mutually unsupported by GDI surfaces
1371  *
1372  * Returns:
1373  *  D3DERR_INVALIDCALL
1374  *
1375  *****************************************************************************/
1376 HRESULT WINAPI
1377 IWineGDISurfaceImpl_LoadTexture(IWineD3DSurface *iface)
1378 {
1379     ERR("Unsupported on X11 surfaces\n");
1380     return WINED3DERR_INVALIDCALL;
1381 }
1382
1383 /*****************************************************************************
1384  * IWineD3DSurface::SaveSnapshot, GDI version
1385  *
1386  * This method writes the surface's contents to the in tga format to the
1387  * file specified in filename.
1388  *
1389  * Params:
1390  *  filename: File to write to
1391  *
1392  * Returns:
1393  *  WINED3DERR_INVALIDCALL if the file couldn't be opened
1394  *  WINED3D_OK on success
1395  *
1396  *****************************************************************************/
1397 static int get_shift(DWORD color_mask) {
1398     int shift = 0;
1399     while (color_mask > 0xFF) {
1400         color_mask >>= 1;
1401         shift += 1;
1402     }
1403     while ((color_mask & 0x80) == 0) {
1404         color_mask <<= 1;
1405         shift -= 1;
1406     }
1407     return shift;
1408 }
1409
1410
1411 HRESULT WINAPI
1412 IWineGDISurfaceImpl_SaveSnapshot(IWineD3DSurface *iface,
1413 const char* filename)
1414 {
1415     FILE* f = NULL;
1416     UINT y = 0, x = 0;
1417     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1418     static char *output = NULL;
1419     static int size = 0;
1420     const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1421
1422     if (This->pow2Width > size) {
1423         output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pow2Width * 3);
1424         size = This->pow2Width;
1425     }
1426
1427
1428     f = fopen(filename, "w+");
1429     if (NULL == f) {
1430         ERR("opening of %s failed with\n", filename);
1431         return WINED3DERR_INVALIDCALL;
1432     }
1433     fprintf(f, "P6\n%d %d\n255\n", This->pow2Width, This->pow2Height);
1434
1435     if (This->resource.format == WINED3DFMT_P8) {
1436         unsigned char table[256][3];
1437         int i;
1438
1439         if (This->palette == NULL) {
1440             fclose(f);
1441             return WINED3DERR_INVALIDCALL;
1442         }
1443         for (i = 0; i < 256; i++) {
1444             table[i][0] = This->palette->palents[i].peRed;
1445             table[i][1] = This->palette->palents[i].peGreen;
1446             table[i][2] = This->palette->palents[i].peBlue;
1447         }
1448         for (y = 0; y < This->pow2Height; y++) {
1449             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
1450             for (x = 0; x < This->pow2Width; x++) {
1451                 unsigned char color = *src;
1452                 src += 1;
1453
1454                 output[3 * x + 0] = table[color][0];
1455                 output[3 * x + 1] = table[color][1];
1456                 output[3 * x + 2] = table[color][2];
1457             }
1458             fwrite(output, 3 * This->pow2Width, 1, f);
1459         }
1460     } else {
1461         int red_shift, green_shift, blue_shift, pix_width;
1462
1463         pix_width = This->bytesPerPixel;
1464
1465         red_shift = get_shift(formatEntry->redMask);
1466         green_shift = get_shift(formatEntry->greenMask);
1467         blue_shift = get_shift(formatEntry->blueMask);
1468
1469         for (y = 0; y < This->pow2Height; y++) {
1470             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
1471             for (x = 0; x < This->pow2Width; x++) {         
1472                 unsigned int color;
1473                 unsigned int comp;
1474                 int i;
1475
1476                 color = 0;
1477                 for (i = 0; i < pix_width; i++) {
1478                     color |= src[i] << (8 * i);
1479                 }
1480                 src += 1 * pix_width;
1481
1482                 comp = color & formatEntry->redMask;
1483                 output[3 * x + 0] = red_shift > 0 ? comp >> red_shift : comp << -red_shift;
1484                 comp = color & formatEntry->greenMask;
1485                 output[3 * x + 1] = green_shift > 0 ? comp >> green_shift : comp << -green_shift;
1486                 comp = color & formatEntry->blueMask;
1487                 output[3 * x + 2] = blue_shift > 0 ? comp >> blue_shift : comp << -blue_shift;
1488             }
1489             fwrite(output, 3 * This->pow2Width, 1, f);
1490         }
1491     }
1492     fclose(f);
1493     return WINED3D_OK;
1494 }
1495
1496 /*****************************************************************************
1497  * IWineD3DSurface::PrivateSetup, GDI version
1498  *
1499  * Initializes the GDI surface, aka creates the DIB section we render to
1500  * The DIB section creation is done by calling GetDC, which will create the
1501  * section and releasing the dc to allow the app to use it. The dib section
1502  * will stay until the surface is released
1503  *
1504  * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1505  * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1506  * avoid confusion in the shared surface code.
1507  *
1508  * Returns:
1509  *  WINED3D_OK on success
1510  *  The return values of called methods on failure
1511  *
1512  *****************************************************************************/
1513 HRESULT WINAPI
1514 IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
1515 {
1516     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1517     HRESULT hr;
1518     HDC hdc;
1519     long oldsize = This->resource.size;
1520
1521     if(This->resource.usage & WINED3DUSAGE_OVERLAY)
1522     {
1523         ERR("(%p) Overlays not yet supported by GDI surfaces\n", This);
1524         return WINED3DERR_INVALIDCALL;
1525     }
1526     /* Sysmem textures have memory already allocated -
1527      * release it, this avoids an unnecessary memcpy
1528      */
1529     HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1530     This->resource.allocatedMemory = NULL;
1531
1532     /* We don't mind the nonpow2 stuff in GDI */
1533     This->resource.size = IWineD3DSurface_GetPitch(iface) * This->currentDesc.Height;
1534     This->pow2Width = This->currentDesc.Width;
1535     This->pow2Height = This->currentDesc.Height;
1536     This->Flags &= ~SFLAG_NONPOW2;
1537
1538     /* Adjust the opengl mem counter */
1539     globalChangeGlRam(This->resource.size - oldsize);
1540
1541     /* Call GetDC to create a DIB section. We will use that
1542      * DIB section for rendering
1543      *
1544      * Release the DC afterwards to allow the app to use it
1545      */
1546     hr = IWineD3DSurface_GetDC(iface, &hdc);
1547     if(FAILED(hr))
1548     {
1549         ERR("(%p) IWineD3DSurface::GetDC failed with hr %08x\n", This, hr);
1550         return hr;
1551     }
1552     hr = IWineD3DSurface_ReleaseDC(iface, hdc);
1553     if(FAILED(hr))
1554     {
1555         ERR("(%p) IWineD3DSurface::ReleaseDC failed with hr %08x\n", This, hr);
1556         return hr;
1557     }
1558
1559     return WINED3D_OK;
1560 }
1561
1562 const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
1563 {
1564     /* IUnknown */
1565     IWineD3DSurfaceImpl_QueryInterface,
1566     IWineD3DSurfaceImpl_AddRef,
1567     IWineD3DSurfaceImpl_Release,
1568     /* IWineD3DResource */
1569     IWineD3DSurfaceImpl_GetParent,
1570     IWineD3DSurfaceImpl_GetDevice,
1571     IWineD3DSurfaceImpl_SetPrivateData,
1572     IWineD3DSurfaceImpl_GetPrivateData,
1573     IWineD3DSurfaceImpl_FreePrivateData,
1574     IWineD3DSurfaceImpl_SetPriority,
1575     IWineD3DSurfaceImpl_GetPriority,
1576     IWineGDISurfaceImpl_PreLoad,
1577     IWineD3DSurfaceImpl_GetType,
1578     /* IWineD3DSurface */
1579     IWineD3DSurfaceImpl_GetContainer,
1580     IWineD3DSurfaceImpl_GetDesc,
1581     IWineGDISurfaceImpl_LockRect,
1582     IWineGDISurfaceImpl_UnlockRect,
1583     IWineD3DSurfaceImpl_GetDC,
1584     IWineD3DSurfaceImpl_ReleaseDC,
1585     IWineGDISurfaceImpl_Flip,
1586     IWineGDISurfaceImpl_Blt,
1587     IWineD3DSurfaceImpl_GetBltStatus,
1588     IWineD3DSurfaceImpl_GetFlipStatus,
1589     IWineD3DSurfaceImpl_IsLost,
1590     IWineD3DSurfaceImpl_Restore,
1591     IWineGDISurfaceImpl_BltFast,
1592     IWineD3DSurfaceImpl_GetPalette,
1593     IWineD3DSurfaceImpl_SetPalette,
1594     IWineD3DSurfaceImpl_RealizePalette,
1595     IWineD3DSurfaceImpl_SetColorKey,
1596     IWineD3DSurfaceImpl_GetPitch,
1597     IWineD3DSurfaceImpl_SetMem,
1598     IWineD3DSurfaceImpl_SetOverlayPosition,
1599     IWineD3DSurfaceImpl_GetOverlayPosition,
1600     IWineD3DSurfaceImpl_UpdateOverlayZOrder,
1601     IWineD3DSurfaceImpl_UpdateOverlay,
1602     /* Internal use: */
1603     IWineD3DSurfaceImpl_CleanDirtyRect,
1604     IWineD3DSurfaceImpl_AddDirtyRect,
1605     IWineGDISurfaceImpl_LoadTexture,
1606     IWineGDISurfaceImpl_SaveSnapshot,
1607     IWineD3DSurfaceImpl_SetContainer,
1608     IWineD3DSurfaceImpl_SetPBufferState,
1609     IWineD3DSurfaceImpl_SetGlTextureDesc,
1610     IWineD3DSurfaceImpl_GetGlDesc,
1611     IWineD3DSurfaceImpl_GetData,
1612     IWineD3DSurfaceImpl_SetFormat,
1613     IWineGDISurfaceImpl_PrivateSetup
1614 };