wintrust: Implement WintrustLoadFunctionPointers.
[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 WINED3DERR_NOTAVAILABLE;
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 WINED3D_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                         WINEDDBLTFX *DDBltFx,
495                         WINED3DTEXTUREFILTERTYPE Filter)
496 {
497     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
498     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
499     RECT                xdst,xsrc;
500     HRESULT             ret = WINED3D_OK;
501     WINED3DLOCKED_RECT  dlock, slock;
502     WINED3DFORMAT       dfmt = WINED3DFMT_UNKNOWN, sfmt = WINED3DFMT_UNKNOWN;
503     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
504     int x, y;
505     const PixelFormatDesc *sEntry, *dEntry;
506     LPBYTE dbuf, sbuf;
507     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
508
509     if (TRACE_ON(d3d_surface))
510     {
511         if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
512         DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
513         if (SrcRect) TRACE("\tsrcrect  :%dx%d-%dx%d\n",
514         SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
515 #if 0
516         TRACE("\tflags: ");
517         DDRAW_dump_DDBLT(Flags);
518         if (Flags & WINEDDBLT_DDFX)
519         {
520             TRACE("\tblitfx: ");
521             DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
522         }
523 #endif
524     }
525
526     if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
527     {
528         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
529         return WINEDDERR_SURFACEBUSY;
530     }
531
532     if(Filter != WINED3DTEXF_NONE) {
533         /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
534         FIXME("Filters not supported in software blit\n");
535     }
536
537     if (Src == This)
538     {
539         IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
540         dfmt = This->resource.format;
541         slock = dlock;
542         sfmt = dfmt;
543         sEntry = getFormatDescEntry(sfmt);
544         dEntry = sEntry;
545     }
546     else
547     {
548         if (Src)
549         {
550             IWineD3DSurface_LockRect(SrcSurface, &slock, NULL, WINED3DLOCK_READONLY);
551             sfmt = Src->resource.format;
552         }
553         sEntry = getFormatDescEntry(sfmt);
554         dfmt = This->resource.format;
555         dEntry = getFormatDescEntry(dfmt);
556         IWineD3DSurface_LockRect(iface, &dlock,NULL,0);
557     }
558
559     if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
560
561     if (sEntry->isFourcc && dEntry->isFourcc)
562     {
563         if (sfmt != dfmt)
564         {
565             FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
566             ret = WINED3DERR_WRONGTEXTUREFORMAT;
567             goto release;
568         }
569         TRACE("Fourcc->Fourcc copy)\n");
570         memcpy(dlock.pBits, slock.pBits, This->currentDesc.Height * dlock.Pitch);
571         goto release;
572     }
573
574     if (sEntry->isFourcc && !dEntry->isFourcc)
575     {
576         FIXME("DXTC decompression not supported right now\n");
577         goto release;
578     }
579
580     if (DestRect)
581     {
582         memcpy(&xdst,DestRect,sizeof(xdst));
583     }
584     else
585     {
586         xdst.top        = 0;
587         xdst.bottom     = This->currentDesc.Height;
588         xdst.left       = 0;
589         xdst.right      = This->currentDesc.Width;
590     }
591
592     if (SrcRect)
593     {
594         memcpy(&xsrc,SrcRect,sizeof(xsrc));
595     }
596     else
597     {
598         if (Src)
599         {
600             xsrc.top    = 0;
601             xsrc.bottom = Src->currentDesc.Height;
602             xsrc.left   = 0;
603             xsrc.right  = Src->currentDesc.Width;
604         }
605         else
606         {
607             memset(&xsrc,0,sizeof(xsrc));
608         }
609     }
610
611     /* First check for the validity of source / destination rectangles. This was
612       verified using a test application + by MSDN.
613     */
614     if ((Src != NULL) &&
615         ((xsrc.bottom > Src->currentDesc.Height) || (xsrc.bottom < 0) ||
616         (xsrc.top     > Src->currentDesc.Height) || (xsrc.top    < 0) ||
617         (xsrc.left    > Src->currentDesc.Width)  || (xsrc.left   < 0) ||
618         (xsrc.right   > Src->currentDesc.Width)  || (xsrc.right  < 0) ||
619         (xsrc.right   < xsrc.left)               || (xsrc.bottom < xsrc.top)))
620     {
621         WARN("Application gave us bad source rectangle for Blt.\n");
622         ret = WINEDDERR_INVALIDRECT;
623         goto release;
624     }
625     /* For the Destination rect, it can be out of bounds on the condition that a clipper
626       is set for the given surface.
627     */
628     if ((/*This->clipper == NULL*/ TRUE) &&
629         ((xdst.bottom  > This->currentDesc.Height) || (xdst.bottom < 0) ||
630         (xdst.top      > This->currentDesc.Height) || (xdst.top    < 0) ||
631         (xdst.left     > This->currentDesc.Width)  || (xdst.left   < 0) ||
632         (xdst.right    > This->currentDesc.Width)  || (xdst.right  < 0) ||
633         (xdst.right    < xdst.left)                || (xdst.bottom < xdst.top)))
634     {
635         WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
636         ret = WINEDDERR_INVALIDRECT;
637         goto release;
638     }
639
640     /* Now handle negative values in the rectangles. Warning: only supported for now
641       in the 'simple' cases (ie not in any stretching / rotation cases).
642
643       First, the case where nothing is to be done.
644     */
645     if (((xdst.bottom <= 0) || (xdst.right <= 0)         ||
646          (xdst.top    >= (int) This->currentDesc.Height) ||
647          (xdst.left   >= (int) This->currentDesc.Width)) ||
648         ((Src != NULL) &&
649         ((xsrc.bottom <= 0) || (xsrc.right <= 0)     ||
650          (xsrc.top >= (int) Src->currentDesc.Height) ||
651          (xsrc.left >= (int) Src->currentDesc.Width))  ))
652     {
653         TRACE("Nothing to be done !\n");
654         goto release;
655     }
656
657     /* The easy case : the source-less blits.... */
658     if (Src == NULL)
659     {
660         RECT full_rect;
661         RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
662
663         full_rect.left   = 0;
664         full_rect.top    = 0;
665         full_rect.right  = This->currentDesc.Width;
666         full_rect.bottom = This->currentDesc.Height;
667         IntersectRect(&temp_rect, &full_rect, &xdst);
668         xdst = temp_rect;
669     }
670     else
671     {
672         /* Only handle clipping on the destination rectangle */
673         int clip_horiz = (xdst.left < 0) || (xdst.right  > (int) This->currentDesc.Width );
674         int clip_vert  = (xdst.top  < 0) || (xdst.bottom > (int) This->currentDesc.Height);
675         if (clip_vert || clip_horiz)
676         {
677             /* Now check if this is a special case or not... */
678             if ((((xdst.bottom - xdst.top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
679                 (((xdst.right  - xdst.left) != (xsrc.right  - xsrc.left)) && clip_horiz) ||
680                 (Flags & WINEDDBLT_DDFX))
681             {
682                 WARN("Out of screen rectangle in special case. Not handled right now.\n");
683                 goto release;
684             }
685
686             if (clip_horiz)
687             {
688                 if (xdst.left < 0) { xsrc.left -= xdst.left; xdst.left = 0; }
689                 if (xdst.right > This->currentDesc.Width)
690                 {
691                     xsrc.right -= (xdst.right - (int) This->currentDesc.Width);
692                     xdst.right = (int) This->currentDesc.Width;
693                 }
694             }
695             if (clip_vert)
696             {
697                 if (xdst.top < 0)
698                 {
699                     xsrc.top -= xdst.top;
700                     xdst.top = 0;
701                 }
702                 if (xdst.bottom > This->currentDesc.Height)
703                 {
704                     xsrc.bottom -= (xdst.bottom - (int) This->currentDesc.Height);
705                     xdst.bottom = (int) This->currentDesc.Height;
706                 }
707             }
708             /* And check if after clipping something is still to be done... */
709             if ((xdst.bottom <= 0)   || (xdst.right <= 0)       ||
710                 (xdst.top   >= (int) This->currentDesc.Height)  ||
711                 (xdst.left  >= (int) This->currentDesc.Width)   ||
712                 (xsrc.bottom <= 0)   || (xsrc.right <= 0)       ||
713                 (xsrc.top >= (int) Src->currentDesc.Height)     ||
714                 (xsrc.left >= (int) Src->currentDesc.Width))
715             {
716                 TRACE("Nothing to be done after clipping !\n");
717                 goto release;
718             }
719         }
720     }
721
722     bpp = This->bytesPerPixel;
723     srcheight = xsrc.bottom - xsrc.top;
724     srcwidth = xsrc.right - xsrc.left;
725     dstheight = xdst.bottom - xdst.top;
726     dstwidth = xdst.right - xdst.left;
727     width = (xdst.right - xdst.left) * bpp;
728
729     assert(width <= dlock.Pitch);
730
731     dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
732
733     if (Flags & WINEDDBLT_WAIT)
734     {
735         Flags &= ~WINEDDBLT_WAIT;
736     }
737     if (Flags & WINEDDBLT_ASYNC)
738     {
739         static BOOL displayed = FALSE;
740         if (!displayed)
741             FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
742         displayed = TRUE;
743         Flags &= ~WINEDDBLT_ASYNC;
744     }
745     if (Flags & WINEDDBLT_DONOTWAIT)
746     {
747         /* WINEDDBLT_DONOTWAIT appeared in DX7 */
748         static BOOL displayed = FALSE;
749         if (!displayed)
750             FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
751         displayed = TRUE;
752         Flags &= ~WINEDDBLT_DONOTWAIT;
753     }
754
755     /* First, all the 'source-less' blits */
756     if (Flags & WINEDDBLT_COLORFILL)
757     {
758         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
759                             dlock.Pitch, DDBltFx->u5.dwFillColor);
760         Flags &= ~WINEDDBLT_COLORFILL;
761     }
762
763     if (Flags & WINEDDBLT_DEPTHFILL)
764     {
765         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
766     }
767     if (Flags & WINEDDBLT_ROP)
768     {
769         /* Catch some degenerate cases here */
770         switch(DDBltFx->dwROP)
771         {
772             case BLACKNESS:
773                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
774                 break;
775             case 0xAA0029: /* No-op */
776                 break;
777             case WHITENESS:
778                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
779                 break;
780             case SRCCOPY: /* well, we do that below ? */
781                 break;
782             default:
783                 FIXME("Unsupported raster op: %08x  Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
784                 goto error;
785         }
786         Flags &= ~WINEDDBLT_ROP;
787     }
788     if (Flags & WINEDDBLT_DDROPS)
789     {
790         FIXME("\tDdraw Raster Ops: %08x  Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
791     }
792     /* Now the 'with source' blits */
793     if (Src)
794     {
795         LPBYTE sbase;
796         int sx, xinc, sy, yinc;
797
798         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
799             goto release;
800         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
801         xinc = (srcwidth << 16) / dstwidth;
802         yinc = (srcheight << 16) / dstheight;
803
804         if (!Flags)
805         {
806             /* No effects, we can cheat here */
807             if (dstwidth == srcwidth)
808             {
809                 if (dstheight == srcheight)
810                 {
811                     /* No stretching in either direction. This needs to be as
812                     * fast as possible */
813                     sbuf = sbase;
814
815                     /* check for overlapping surfaces */
816                     if (SrcSurface != iface || xdst.top < xsrc.top ||
817                         xdst.right <= xsrc.left || xsrc.right <= xdst.left)
818                     {
819                         /* no overlap, or dst above src, so copy from top downwards */
820                         for (y = 0; y < dstheight; y++)
821                         {
822                             memcpy(dbuf, sbuf, width);
823                             sbuf += slock.Pitch;
824                             dbuf += dlock.Pitch;
825                         }
826                     }
827                     else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
828                     {
829                         sbuf += (slock.Pitch*dstheight);
830                         dbuf += (dlock.Pitch*dstheight);
831                         for (y = 0; y < dstheight; y++)
832                         {
833                             sbuf -= slock.Pitch;
834                             dbuf -= dlock.Pitch;
835                             memcpy(dbuf, sbuf, width);
836                         }
837                     }
838                     else /* src and dst overlapping on the same line, use memmove */
839                     {
840                         for (y = 0; y < dstheight; y++)
841                         {
842                             memmove(dbuf, sbuf, width);
843                             sbuf += slock.Pitch;
844                             dbuf += dlock.Pitch;
845                         }
846                     }
847                 } else {
848                     /* Stretching in Y direction only */
849                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
850                         sbuf = sbase + (sy >> 16) * slock.Pitch;
851                         memcpy(dbuf, sbuf, width);
852                         dbuf += dlock.Pitch;
853                     }
854                 }
855             }
856             else
857             {
858                 /* Stretching in X direction */
859                 int last_sy = -1;
860                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
861                 {
862                     sbuf = sbase + (sy >> 16) * slock.Pitch;
863
864                     if ((sy >> 16) == (last_sy >> 16))
865                     {
866                         /* this sourcerow is the same as last sourcerow -
867                          * copy already stretched row
868                          */
869                         memcpy(dbuf, dbuf - dlock.Pitch, width);
870                     }
871                     else
872                     {
873 #define STRETCH_ROW(type) { \
874                     type *s = (type *) sbuf, *d = (type *) dbuf; \
875                     for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
876                     d[x] = s[sx >> 16]; \
877                     break; }
878
879                     switch(bpp)
880                     {
881                         case 1: STRETCH_ROW(BYTE)
882                         case 2: STRETCH_ROW(WORD)
883                         case 4: STRETCH_ROW(DWORD)
884                         case 3:
885                         {
886                             LPBYTE s,d = dbuf;
887                             for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
888                             {
889                                 DWORD pixel;
890
891                                 s = sbuf+3*(sx>>16);
892                                 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
893                                 d[0] = (pixel    )&0xff;
894                                 d[1] = (pixel>> 8)&0xff;
895                                 d[2] = (pixel>>16)&0xff;
896                                 d+=3;
897                             }
898                             break;
899                     }
900                     default:
901                         FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
902                         ret = WINED3DERR_NOTAVAILABLE;
903                         goto error;
904                     }
905 #undef STRETCH_ROW
906                     }
907                     dbuf += dlock.Pitch;
908                     last_sy = sy;
909                 }
910             }
911         }
912         else
913         {
914           LONG dstyinc = dlock.Pitch, dstxinc = bpp;
915           DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
916           DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
917           if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
918           {
919               /* The color keying flags are checked for correctness in ddraw */
920               if (Flags & WINEDDBLT_KEYSRC)
921               {
922                 keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
923                 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
924               }
925               else  if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
926               {
927                 keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
928                 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
929               }
930
931               if (Flags & WINEDDBLT_KEYDEST)
932               {
933                 /* Destination color keys are taken from the source surface ! */
934                 destkeylow  = Src->DestBltCKey.dwColorSpaceLowValue;
935                 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
936               }
937               else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
938               {
939                 destkeylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
940                 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
941               }
942
943               if(bpp == 1)
944               {
945                   keymask = 0xff;
946               }
947               else
948               {
949                   keymask = sEntry->redMask   |
950                             sEntry->greenMask |
951                             sEntry->blueMask;
952               }
953               Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
954           }
955
956           if (Flags & WINEDDBLT_DDFX)
957           {
958               LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
959               LONG tmpxy;
960               dTopLeft     = dbuf;
961               dTopRight    = dbuf+((dstwidth-1)*bpp);
962               dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
963               dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
964
965               if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
966               {
967                 /* I don't think we need to do anything about this flag */
968                 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
969               }
970               if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
971               {
972                 tmp          = dTopRight;
973                 dTopRight    = dTopLeft;
974                 dTopLeft     = tmp;
975                 tmp          = dBottomRight;
976                 dBottomRight = dBottomLeft;
977                 dBottomLeft  = tmp;
978                 dstxinc = dstxinc *-1;
979               }
980               if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
981               {
982                 tmp          = dTopLeft;
983                 dTopLeft     = dBottomLeft;
984                 dBottomLeft  = tmp;
985                 tmp          = dTopRight;
986                 dTopRight    = dBottomRight;
987                 dBottomRight = tmp;
988                 dstyinc = dstyinc *-1;
989               }
990               if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
991               {
992                 /* I don't think we need to do anything about this flag */
993                 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
994               }
995               if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
996               {
997                 tmp          = dBottomRight;
998                 dBottomRight = dTopLeft;
999                 dTopLeft     = tmp;
1000                 tmp          = dBottomLeft;
1001                 dBottomLeft  = dTopRight;
1002                 dTopRight    = tmp;
1003                 dstxinc = dstxinc * -1;
1004                 dstyinc = dstyinc * -1;
1005               }
1006               if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1007               {
1008                 tmp          = dTopLeft;
1009                 dTopLeft     = dBottomLeft;
1010                 dBottomLeft  = dBottomRight;
1011                 dBottomRight = dTopRight;
1012                 dTopRight    = tmp;
1013                 tmpxy   = dstxinc;
1014                 dstxinc = dstyinc;
1015                 dstyinc = tmpxy;
1016                 dstxinc = dstxinc * -1;
1017               }
1018               if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1019               {
1020                 tmp          = dTopLeft;
1021                 dTopLeft     = dTopRight;
1022                 dTopRight    = dBottomRight;
1023                 dBottomRight = dBottomLeft;
1024                 dBottomLeft  = tmp;
1025                 tmpxy   = dstxinc;
1026                 dstxinc = dstyinc;
1027                 dstyinc = tmpxy;
1028                 dstyinc = dstyinc * -1;
1029               }
1030               if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1031               {
1032                 /* I don't think we need to do anything about this flag */
1033                 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1034               }
1035               dbuf = dTopLeft;
1036               Flags &= ~(WINEDDBLT_DDFX);
1037           }
1038
1039 #define COPY_COLORKEY_FX(type) { \
1040             type *s, *d = (type *) dbuf, *dx, tmp; \
1041             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1042               s = (type*)(sbase + (sy >> 16) * slock.Pitch); \
1043               dx = d; \
1044               for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1045                   tmp = s[sx >> 16]; \
1046                   if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1047                       ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1048                        dx[0] = tmp; \
1049                      } \
1050                   dx = (type*)(((LPBYTE)dx)+dstxinc); \
1051               } \
1052               d = (type*)(((LPBYTE)d)+dstyinc); \
1053             } \
1054             break; }
1055
1056             switch (bpp) {
1057             case 1: COPY_COLORKEY_FX(BYTE)
1058             case 2: COPY_COLORKEY_FX(WORD)
1059             case 4: COPY_COLORKEY_FX(DWORD)
1060             case 3:
1061             {
1062                 LPBYTE s,d = dbuf, dx;
1063                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1064                 {
1065                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1066                     dx = d;
1067                     for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1068                     {
1069                         DWORD pixel, dpixel = 0;
1070                         s = sbuf+3*(sx>>16);
1071                         pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1072                         dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1073                         if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1074                             ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1075                         {
1076                             dx[0] = (pixel    )&0xff;
1077                             dx[1] = (pixel>> 8)&0xff;
1078                             dx[2] = (pixel>>16)&0xff;
1079                         }
1080                         dx+= dstxinc;
1081                     }
1082                     d += dstyinc;
1083                 }
1084                 break;
1085             }
1086             default:
1087               FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1088                   (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1089                   ret = WINED3DERR_NOTAVAILABLE;
1090                   goto error;
1091 #undef COPY_COLORKEY_FX
1092             }
1093         }
1094     }
1095
1096 error:
1097     if (Flags && FIXME_ON(d3d_surface))
1098     {
1099         FIXME("\tUnsupported flags: %08x\n", Flags);
1100     }
1101
1102 release:
1103     IWineD3DSurface_UnlockRect(iface);
1104     if (SrcSurface && SrcSurface != iface) IWineD3DSurface_UnlockRect(SrcSurface);
1105     return ret;
1106 }
1107
1108 /*****************************************************************************
1109  * IWineD3DSurface::BltFast, GDI version
1110  *
1111  * This is the software implementation of BltFast, as used by GDI surfaces
1112  * and as a fallback for OpenGL surfaces. This code is taken from the old
1113  * DirectDraw code, and was originally written by TransGaming.
1114  *
1115  * Params:
1116  *  dstx:
1117  *  dsty:
1118  *  Source: Source surface to copy from
1119  *  rsrc: Source rectangle
1120  *  trans: Some Flags
1121  *
1122  * Returns:
1123  *  WINED3D_OK on success
1124  *
1125  *****************************************************************************/
1126 HRESULT WINAPI
1127 IWineGDISurfaceImpl_BltFast(IWineD3DSurface *iface,
1128                             DWORD dstx,
1129                             DWORD dsty,
1130                             IWineD3DSurface *Source,
1131                             RECT *rsrc,
1132                             DWORD trans)
1133 {
1134     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1135     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1136
1137     int                 bpp, w, h, x, y;
1138     WINED3DLOCKED_RECT  dlock,slock;
1139     HRESULT             ret = WINED3D_OK;
1140     RECT                rsrc2;
1141     RECT                lock_src, lock_dst, lock_union;
1142     BYTE                *sbuf, *dbuf;
1143     const PixelFormatDesc *sEntry, *dEntry;
1144
1145     if (TRACE_ON(d3d_surface))
1146     {
1147         TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1148
1149         if (rsrc)
1150         {
1151             TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1152                   rsrc->right,rsrc->bottom);
1153         }
1154         else
1155         {
1156             TRACE(" srcrect: NULL\n");
1157         }
1158     }
1159
1160     if ((This->Flags & SFLAG_LOCKED) ||
1161         ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
1162     {
1163         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1164         return WINEDDERR_SURFACEBUSY;
1165     }
1166
1167     if (!rsrc)
1168     {
1169         WARN("rsrc is NULL!\n");
1170         rsrc = &rsrc2;
1171         rsrc->left = 0;
1172         rsrc->top = 0;
1173         rsrc->right = Src->currentDesc.Width;
1174         rsrc->bottom = Src->currentDesc.Height;
1175     }
1176
1177     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1178     if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1179         (rsrc->top    > Src->currentDesc.Height) || (rsrc->top    < 0) ||
1180         (rsrc->left   > Src->currentDesc.Width)  || (rsrc->left   < 0) ||
1181         (rsrc->right  > Src->currentDesc.Width)  || (rsrc->right  < 0) ||
1182         (rsrc->right  < rsrc->left)              || (rsrc->bottom < rsrc->top))
1183     {
1184         WARN("Application gave us bad source rectangle for BltFast.\n");
1185         return WINEDDERR_INVALIDRECT;
1186     }
1187
1188     h = rsrc->bottom - rsrc->top;
1189     if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1190     if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1191     if (h <= 0) return WINEDDERR_INVALIDRECT;
1192
1193     w = rsrc->right - rsrc->left;
1194     if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1195     if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1196     if (w <= 0) return WINEDDERR_INVALIDRECT;
1197
1198     /* Now compute the locking rectangle... */
1199     lock_src.left = rsrc->left;
1200     lock_src.top = rsrc->top;
1201     lock_src.right = lock_src.left + w;
1202     lock_src.bottom = lock_src.top + h;
1203
1204     lock_dst.left = dstx;
1205     lock_dst.top = dsty;
1206     lock_dst.right = dstx + w;
1207     lock_dst.bottom = dsty + h;
1208
1209     bpp = This->bytesPerPixel;
1210
1211     /* We need to lock the surfaces, or we won't get refreshes when done. */
1212     if (Src == This)
1213     {
1214         int pitch;
1215
1216         UnionRect(&lock_union, &lock_src, &lock_dst);
1217
1218         /* Lock the union of the two rectangles */
1219         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1220         if(ret != WINED3D_OK) goto error;
1221
1222         pitch = dlock.Pitch;
1223         slock.Pitch = dlock.Pitch;
1224
1225         /* Since slock was originally copied from this surface's description, we can just reuse it */
1226         assert(This->resource.allocatedMemory != NULL);
1227         sbuf = (BYTE *)This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1228         dbuf = (BYTE *)This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1229         sEntry = getFormatDescEntry(Src->resource.format);
1230         dEntry = sEntry;
1231     }
1232     else
1233     {
1234         ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1235         if(ret != WINED3D_OK) goto error;
1236         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1237         if(ret != WINED3D_OK) goto error;
1238
1239         sbuf = slock.pBits;
1240         dbuf = dlock.pBits;
1241         TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1242
1243         sEntry = getFormatDescEntry(Src->resource.format);
1244         dEntry = getFormatDescEntry(This->resource.format);
1245     }
1246
1247     /* Handle first the FOURCC surfaces... */
1248     if (sEntry->isFourcc && dEntry->isFourcc)
1249     {
1250         TRACE("Fourcc -> Fourcc copy\n");
1251         if (trans)
1252             FIXME("trans arg not supported when a FOURCC surface is involved\n");
1253         if (dstx || dsty)
1254             FIXME("offset for destination surface is not supported\n");
1255         if (Src->resource.format != This->resource.format)
1256         {
1257             FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1258             ret = WINED3DERR_WRONGTEXTUREFORMAT;
1259             goto error;
1260         }
1261         /* FIXME: Watch out that the size is correct for FOURCC surfaces */
1262         memcpy(dbuf, sbuf, This->resource.size);
1263         goto error;
1264     }
1265     if (sEntry->isFourcc && !dEntry->isFourcc)
1266     {
1267         /* TODO: Use the libtxc_dxtn.so shared library to do
1268          * software decompression
1269          */
1270         ERR("DXTC decompression not supported by now\n");
1271         goto error;
1272     }
1273
1274     if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1275     {
1276         DWORD keylow, keyhigh;
1277         TRACE("Color keyed copy\n");
1278         if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1279         {
1280             keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1281             keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1282         }
1283         else
1284         {
1285             /* I'm not sure if this is correct */
1286             FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1287             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1288             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1289         }
1290
1291 #define COPYBOX_COLORKEY(type) { \
1292             type *d, *s, tmp; \
1293             s = (type *) sbuf; \
1294             d = (type *) dbuf; \
1295             for (y = 0; y < h; y++) { \
1296                 for (x = 0; x < w; x++) { \
1297                     tmp = s[x]; \
1298                     if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1299                 } \
1300                 s = (type *)((BYTE *)s + slock.Pitch); \
1301                 d = (type *)((BYTE *)d + dlock.Pitch); \
1302             } \
1303             break; \
1304         }
1305
1306         switch (bpp) {
1307             case 1: COPYBOX_COLORKEY(BYTE)
1308             case 2: COPYBOX_COLORKEY(WORD)
1309             case 4: COPYBOX_COLORKEY(DWORD)
1310             case 3:
1311             {
1312                 BYTE *d, *s;
1313                 DWORD tmp;
1314                 s = (BYTE *) sbuf;
1315                 d = (BYTE *) dbuf;
1316                 for (y = 0; y < h; y++)
1317                 {
1318                     for (x = 0; x < w * 3; x += 3)
1319                     {
1320                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1321                         if (tmp < keylow || tmp > keyhigh)
1322                         {
1323                             d[x + 0] = s[x + 0];
1324                             d[x + 1] = s[x + 1];
1325                             d[x + 2] = s[x + 2];
1326                         }
1327                     }
1328                     s += slock.Pitch;
1329                     d += dlock.Pitch;
1330                 }
1331                 break;
1332             }
1333             default:
1334                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1335                 ret = WINED3DERR_NOTAVAILABLE;
1336                 goto error;
1337         }
1338 #undef COPYBOX_COLORKEY
1339         TRACE("Copy Done\n");
1340     }
1341     else
1342     {
1343         int width = w * bpp;
1344         TRACE("NO color key copy\n");
1345         for (y = 0; y < h; y++)
1346         {
1347             /* This is pretty easy, a line for line memcpy */
1348             memcpy(dbuf, sbuf, width);
1349             sbuf += slock.Pitch;
1350             dbuf += dlock.Pitch;
1351         }
1352         TRACE("Copy done\n");
1353     }
1354
1355 error:
1356     if (Src == This)
1357     {
1358         IWineD3DSurface_UnlockRect(iface);
1359     }
1360     else
1361     {
1362         IWineD3DSurface_UnlockRect(iface);
1363         IWineD3DSurface_UnlockRect(Source);
1364     }
1365
1366     return ret;
1367 }
1368
1369 /*****************************************************************************
1370  * IWineD3DSurface::LoadTexture, GDI version
1371  *
1372  * This is mutually unsupported by GDI surfaces
1373  *
1374  * Returns:
1375  *  D3DERR_INVALIDCALL
1376  *
1377  *****************************************************************************/
1378 HRESULT WINAPI
1379 IWineGDISurfaceImpl_LoadTexture(IWineD3DSurface *iface)
1380 {
1381     ERR("Unsupported on X11 surfaces\n");
1382     return WINED3DERR_INVALIDCALL;
1383 }
1384
1385 /*****************************************************************************
1386  * IWineD3DSurface::SaveSnapshot, GDI version
1387  *
1388  * This method writes the surface's contents to the in tga format to the
1389  * file specified in filename.
1390  *
1391  * Params:
1392  *  filename: File to write to
1393  *
1394  * Returns:
1395  *  WINED3DERR_INVALIDCALL if the file couldn't be opened
1396  *  WINED3D_OK on success
1397  *
1398  *****************************************************************************/
1399 static int get_shift(DWORD color_mask) {
1400     int shift = 0;
1401     while (color_mask > 0xFF) {
1402         color_mask >>= 1;
1403         shift += 1;
1404     }
1405     while ((color_mask & 0x80) == 0) {
1406         color_mask <<= 1;
1407         shift -= 1;
1408     }
1409     return shift;
1410 }
1411
1412
1413 HRESULT WINAPI
1414 IWineGDISurfaceImpl_SaveSnapshot(IWineD3DSurface *iface,
1415 const char* filename)
1416 {
1417     FILE* f = NULL;
1418     UINT y = 0, x = 0;
1419     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1420     static char *output = NULL;
1421     static int size = 0;
1422     const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1423
1424     if (This->pow2Width > size) {
1425         output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pow2Width * 3);
1426         size = This->pow2Width;
1427     }
1428
1429
1430     f = fopen(filename, "w+");
1431     if (NULL == f) {
1432         ERR("opening of %s failed with\n", filename);
1433         return WINED3DERR_INVALIDCALL;
1434     }
1435     fprintf(f, "P6\n%d %d\n255\n", This->pow2Width, This->pow2Height);
1436
1437     if (This->resource.format == WINED3DFMT_P8) {
1438         unsigned char table[256][3];
1439         int i;
1440
1441         if (This->palette == NULL) {
1442             fclose(f);
1443             return WINED3DERR_INVALIDCALL;
1444         }
1445         for (i = 0; i < 256; i++) {
1446             table[i][0] = This->palette->palents[i].peRed;
1447             table[i][1] = This->palette->palents[i].peGreen;
1448             table[i][2] = This->palette->palents[i].peBlue;
1449         }
1450         for (y = 0; y < This->pow2Height; y++) {
1451             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
1452             for (x = 0; x < This->pow2Width; x++) {
1453                 unsigned char color = *src;
1454                 src += 1;
1455
1456                 output[3 * x + 0] = table[color][0];
1457                 output[3 * x + 1] = table[color][1];
1458                 output[3 * x + 2] = table[color][2];
1459             }
1460             fwrite(output, 3 * This->pow2Width, 1, f);
1461         }
1462     } else {
1463         int red_shift, green_shift, blue_shift, pix_width;
1464
1465         pix_width = This->bytesPerPixel;
1466
1467         red_shift = get_shift(formatEntry->redMask);
1468         green_shift = get_shift(formatEntry->greenMask);
1469         blue_shift = get_shift(formatEntry->blueMask);
1470
1471         for (y = 0; y < This->pow2Height; y++) {
1472             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
1473             for (x = 0; x < This->pow2Width; x++) {         
1474                 unsigned int color;
1475                 unsigned int comp;
1476                 int i;
1477
1478                 color = 0;
1479                 for (i = 0; i < pix_width; i++) {
1480                     color |= src[i] << (8 * i);
1481                 }
1482                 src += 1 * pix_width;
1483
1484                 comp = color & formatEntry->redMask;
1485                 output[3 * x + 0] = red_shift > 0 ? comp >> red_shift : comp << -red_shift;
1486                 comp = color & formatEntry->greenMask;
1487                 output[3 * x + 1] = green_shift > 0 ? comp >> green_shift : comp << -green_shift;
1488                 comp = color & formatEntry->blueMask;
1489                 output[3 * x + 2] = blue_shift > 0 ? comp >> blue_shift : comp << -blue_shift;
1490             }
1491             fwrite(output, 3 * This->pow2Width, 1, f);
1492         }
1493     }
1494     fclose(f);
1495     return WINED3D_OK;
1496 }
1497
1498 /*****************************************************************************
1499  * IWineD3DSurface::PrivateSetup, GDI version
1500  *
1501  * Initializes the GDI surface, aka creates the DIB section we render to
1502  * The DIB section creation is done by calling GetDC, which will create the
1503  * section and releasing the dc to allow the app to use it. The dib section
1504  * will stay until the surface is released
1505  *
1506  * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1507  * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1508  * avoid confusion in the shared surface code.
1509  *
1510  * Returns:
1511  *  WINED3D_OK on success
1512  *  The return values of called methods on failure
1513  *
1514  *****************************************************************************/
1515 HRESULT WINAPI
1516 IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
1517 {
1518     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1519     HRESULT hr;
1520     HDC hdc;
1521     long oldsize = This->resource.size;
1522
1523     if(This->resource.usage & WINED3DUSAGE_OVERLAY)
1524     {
1525         ERR("(%p) Overlays not yet supported by GDI surfaces\n", This);
1526         return WINED3DERR_INVALIDCALL;
1527     }
1528     /* Sysmem textures have memory already allocated -
1529      * release it, this avoids an unnecessary memcpy
1530      */
1531     HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1532     This->resource.allocatedMemory = NULL;
1533
1534     /* We don't mind the nonpow2 stuff in GDI */
1535     This->resource.size = IWineD3DSurface_GetPitch(iface) * This->currentDesc.Height;
1536     This->pow2Width = This->currentDesc.Width;
1537     This->pow2Height = This->currentDesc.Height;
1538     This->Flags &= ~SFLAG_NONPOW2;
1539
1540     /* Adjust the opengl mem counter */
1541     globalChangeGlRam(This->resource.size - oldsize);
1542
1543     /* Call GetDC to create a DIB section. We will use that
1544      * DIB section for rendering
1545      *
1546      * Release the DC afterwards to allow the app to use it
1547      */
1548     hr = IWineD3DSurface_GetDC(iface, &hdc);
1549     if(FAILED(hr))
1550     {
1551         ERR("(%p) IWineD3DSurface::GetDC failed with hr %08x\n", This, hr);
1552         return hr;
1553     }
1554     hr = IWineD3DSurface_ReleaseDC(iface, hdc);
1555     if(FAILED(hr))
1556     {
1557         ERR("(%p) IWineD3DSurface::ReleaseDC failed with hr %08x\n", This, hr);
1558         return hr;
1559     }
1560
1561     return WINED3D_OK;
1562 }
1563
1564 const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
1565 {
1566     /* IUnknown */
1567     IWineD3DSurfaceImpl_QueryInterface,
1568     IWineD3DSurfaceImpl_AddRef,
1569     IWineD3DSurfaceImpl_Release,
1570     /* IWineD3DResource */
1571     IWineD3DSurfaceImpl_GetParent,
1572     IWineD3DSurfaceImpl_GetDevice,
1573     IWineD3DSurfaceImpl_SetPrivateData,
1574     IWineD3DSurfaceImpl_GetPrivateData,
1575     IWineD3DSurfaceImpl_FreePrivateData,
1576     IWineD3DSurfaceImpl_SetPriority,
1577     IWineD3DSurfaceImpl_GetPriority,
1578     IWineGDISurfaceImpl_PreLoad,
1579     IWineD3DSurfaceImpl_GetType,
1580     /* IWineD3DSurface */
1581     IWineD3DSurfaceImpl_GetContainer,
1582     IWineD3DSurfaceImpl_GetDesc,
1583     IWineGDISurfaceImpl_LockRect,
1584     IWineGDISurfaceImpl_UnlockRect,
1585     IWineD3DSurfaceImpl_GetDC,
1586     IWineD3DSurfaceImpl_ReleaseDC,
1587     IWineGDISurfaceImpl_Flip,
1588     IWineGDISurfaceImpl_Blt,
1589     IWineD3DSurfaceImpl_GetBltStatus,
1590     IWineD3DSurfaceImpl_GetFlipStatus,
1591     IWineD3DSurfaceImpl_IsLost,
1592     IWineD3DSurfaceImpl_Restore,
1593     IWineGDISurfaceImpl_BltFast,
1594     IWineD3DSurfaceImpl_GetPalette,
1595     IWineD3DSurfaceImpl_SetPalette,
1596     IWineD3DSurfaceImpl_RealizePalette,
1597     IWineD3DSurfaceImpl_SetColorKey,
1598     IWineD3DSurfaceImpl_GetPitch,
1599     IWineD3DSurfaceImpl_SetMem,
1600     IWineD3DSurfaceImpl_SetOverlayPosition,
1601     IWineD3DSurfaceImpl_GetOverlayPosition,
1602     IWineD3DSurfaceImpl_UpdateOverlayZOrder,
1603     IWineD3DSurfaceImpl_UpdateOverlay,
1604     /* Internal use: */
1605     IWineD3DSurfaceImpl_AddDirtyRect,
1606     IWineGDISurfaceImpl_LoadTexture,
1607     IWineGDISurfaceImpl_SaveSnapshot,
1608     IWineD3DSurfaceImpl_SetContainer,
1609     IWineD3DSurfaceImpl_SetGlTextureDesc,
1610     IWineD3DSurfaceImpl_GetGlDesc,
1611     IWineD3DSurfaceImpl_GetData,
1612     IWineD3DSurfaceImpl_SetFormat,
1613     IWineGDISurfaceImpl_PrivateSetup
1614 };