wined3d: Get rid of IWineD3DSurface::GetDesc().
[wine] / dlls / wined3d / surface_base.c
1 /*
2  * IWineD3DSurface Implementation of management(non-rendering) functions
3  *
4  * Copyright 1998 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  * Copyright 2002-2005 Jason Edmeades
7  * Copyright 2002-2003 Raphael Junqueira
8  * Copyright 2004 Christian Costa
9  * Copyright 2005 Oliver Stieber
10  * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11  * Copyright 2007 Henri Verbeet
12  * Copyright 2006-2007 Roderick Colenbrander
13  * Copyright 2009-2010 Henri Verbeet for CodeWeavers
14  *
15  * This library is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Lesser General Public
17  * License as published by the Free Software Foundation; either
18  * version 2.1 of the License, or (at your option) any later version.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * Lesser General Public License for more details.
24  *
25  * You should have received a copy of the GNU Lesser General Public
26  * License along with this library; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28  */
29
30 #include "config.h"
31 #include "wine/port.h"
32 #include "wined3d_private.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
35
36 /* See also float_16_to_32() in wined3d_private.h */
37 static inline unsigned short float_32_to_16(const float *in)
38 {
39     int exp = 0;
40     float tmp = fabs(*in);
41     unsigned int mantissa;
42     unsigned short ret;
43
44     /* Deal with special numbers */
45     if (*in == 0.0f) return 0x0000;
46     if(isnan(*in)) return 0x7C01;
47     if (isinf(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
48
49     if(tmp < powf(2, 10)) {
50         do
51         {
52             tmp = tmp * 2.0f;
53             exp--;
54         }while(tmp < powf(2, 10));
55     } else if(tmp >= powf(2, 11)) {
56         do
57         {
58             tmp /= 2.0f;
59             exp++;
60         }while(tmp >= powf(2, 11));
61     }
62
63     mantissa = (unsigned int) tmp;
64     if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
65
66     exp += 10;  /* Normalize the mantissa */
67     exp += 15;  /* Exponent is encoded with excess 15 */
68
69     if(exp > 30) { /* too big */
70         ret = 0x7c00; /* INF */
71     } else if(exp <= 0) {
72         /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
73         while(exp <= 0) {
74             mantissa = mantissa >> 1;
75             exp++;
76         }
77         ret = mantissa & 0x3ff;
78     } else {
79         ret = (exp << 10) | (mantissa & 0x3ff);
80     }
81
82     ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
83     return ret;
84 }
85
86 /* *******************************************
87    IWineD3DSurface IUnknown parts follow
88    ******************************************* */
89 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
90 {
91     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
92     /* Warn ,but be nice about things */
93     TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
94
95     if (IsEqualGUID(riid, &IID_IUnknown)
96         || IsEqualGUID(riid, &IID_IWineD3DBase)
97         || IsEqualGUID(riid, &IID_IWineD3DResource)
98         || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
99         IUnknown_AddRef((IUnknown*)iface);
100         *ppobj = This;
101         return S_OK;
102         }
103         *ppobj = NULL;
104         return E_NOINTERFACE;
105 }
106
107 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
108     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
109     ULONG ref = InterlockedIncrement(&This->resource.ref);
110     TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
111     return ref;
112 }
113
114 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface,
115         REFGUID riid, const void *data, DWORD data_size, DWORD flags)
116 {
117     return resource_set_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, riid, data, data_size, flags);
118 }
119
120 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface,
121         REFGUID guid, void *data, DWORD *data_size)
122 {
123     return resource_get_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, guid, data, data_size);
124 }
125
126 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid)
127 {
128     return resource_free_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, refguid);
129 }
130
131 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD priority)
132 {
133     return resource_set_priority(&((IWineD3DSurfaceImpl *)iface)->resource, priority);
134 }
135
136 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface)
137 {
138     return resource_get_priority(&((IWineD3DSurfaceImpl *)iface)->resource);
139 }
140
141 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface)
142 {
143     return resource_get_type(&((IWineD3DSurfaceImpl *)iface)->resource);
144 }
145
146 void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
147 {
148     TRACE("iface %p.\n", iface);
149
150     return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
151 }
152
153 struct wined3d_resource * WINAPI IWineD3DBaseSurfaceImpl_GetResource(IWineD3DSurface *iface)
154 {
155     TRACE("iface %p.\n", iface);
156
157     return &((IWineD3DSurfaceImpl *)iface)->resource;
158 }
159
160 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD flags)
161 {
162     TRACE("iface %p, flags %#x.\n", iface, flags);
163
164     switch (flags)
165     {
166         case WINEDDGBS_CANBLT:
167         case WINEDDGBS_ISBLTDONE:
168             return WINED3D_OK;
169
170         default:
171             return WINED3DERR_INVALIDCALL;
172     }
173 }
174
175 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD flags)
176 {
177     /* XXX: DDERR_INVALIDSURFACETYPE */
178
179     TRACE("iface %p, flags %#x.\n", iface, flags);
180
181     switch (flags)
182     {
183         case WINEDDGFS_CANFLIP:
184         case WINEDDGFS_ISFLIPDONE:
185             return WINED3D_OK;
186
187         default:
188             return WINED3DERR_INVALIDCALL;
189     }
190 }
191
192 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
193     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
194     TRACE("(%p)\n", This);
195
196     /* D3D8 and 9 loose full devices, ddraw only surfaces */
197     return This->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
198 }
199
200 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
201     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
202     TRACE("(%p)\n", This);
203
204     /* So far we don't lose anything :) */
205     This->flags &= ~SFLAG_LOST;
206     return WINED3D_OK;
207 }
208
209 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, struct wined3d_palette *palette)
210 {
211     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
212
213     TRACE("iface %p, palette %p.\n", iface, palette);
214
215     if (This->palette == palette)
216     {
217         TRACE("Nop palette change\n");
218         return WINED3D_OK;
219     }
220
221     if (This->palette)
222         if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
223             This->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
224
225     This->palette = palette;
226
227     if (palette)
228     {
229         if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
230             palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
231
232         This->surface_ops->surface_realize_palette(This);
233     }
234
235     return WINED3D_OK;
236 }
237
238 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD flags, const WINEDDCOLORKEY *CKey)
239 {
240     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
241
242     TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, CKey);
243
244     if (flags & WINEDDCKEY_COLORSPACE)
245     {
246         FIXME(" colorkey value not supported (%08x) !\n", flags);
247         return WINED3DERR_INVALIDCALL;
248     }
249
250     /* Dirtify the surface, but only if a key was changed */
251     if (CKey)
252     {
253         switch (flags & ~WINEDDCKEY_COLORSPACE)
254         {
255             case WINEDDCKEY_DESTBLT:
256                 This->DestBltCKey = *CKey;
257                 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
258                 break;
259
260             case WINEDDCKEY_DESTOVERLAY:
261                 This->DestOverlayCKey = *CKey;
262                 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
263                 break;
264
265             case WINEDDCKEY_SRCOVERLAY:
266                 This->SrcOverlayCKey = *CKey;
267                 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
268                 break;
269
270             case WINEDDCKEY_SRCBLT:
271                 This->SrcBltCKey = *CKey;
272                 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
273                 break;
274         }
275     }
276     else
277     {
278         switch (flags & ~WINEDDCKEY_COLORSPACE)
279         {
280             case WINEDDCKEY_DESTBLT:
281                 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
282                 break;
283
284             case WINEDDCKEY_DESTOVERLAY:
285                 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
286                 break;
287
288             case WINEDDCKEY_SRCOVERLAY:
289                 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
290                 break;
291
292             case WINEDDCKEY_SRCBLT:
293                 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
294                 break;
295         }
296     }
297
298     return WINED3D_OK;
299 }
300
301 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, struct wined3d_palette **palette)
302 {
303     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
304
305     TRACE("iface %p, palette %p.\n", iface, palette);
306
307     *palette = This->palette;
308
309     return WINED3D_OK;
310 }
311
312 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
313 {
314     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
315     const struct wined3d_format *format = This->resource.format;
316     DWORD ret;
317     TRACE("(%p)\n", This);
318
319     if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
320     {
321         /* Since compressed formats are block based, pitch means the amount of
322          * bytes to the next row of block rather than the next row of pixels. */
323         UINT row_block_count = (This->resource.width + format->block_width - 1) / format->block_width;
324         ret = row_block_count * format->block_byte_count;
325     }
326     else
327     {
328         unsigned char alignment = This->resource.device->surface_alignment;
329         ret = This->resource.format->byte_count * This->resource.width;  /* Bytes / row */
330         ret = (ret + alignment - 1) & ~(alignment - 1);
331     }
332     TRACE("(%p) Returning %d\n", This, ret);
333     return ret;
334 }
335
336 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
337     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
338     LONG w, h;
339
340     TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
341
342     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
343     {
344         TRACE("(%p): Not an overlay surface\n", This);
345         return WINEDDERR_NOTAOVERLAYSURFACE;
346     }
347
348     w = This->overlay_destrect.right - This->overlay_destrect.left;
349     h = This->overlay_destrect.bottom - This->overlay_destrect.top;
350     This->overlay_destrect.left = X;
351     This->overlay_destrect.top = Y;
352     This->overlay_destrect.right = X + w;
353     This->overlay_destrect.bottom = Y + h;
354
355     This->surface_ops->surface_draw_overlay(This);
356
357     return WINED3D_OK;
358 }
359
360 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
361     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
362     HRESULT hr;
363
364     TRACE("(%p)->(%p,%p)\n", This, X, Y);
365
366     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
367     {
368         TRACE("(%p): Not an overlay surface\n", This);
369         return WINEDDERR_NOTAOVERLAYSURFACE;
370     }
371
372     if (!This->overlay_dest)
373     {
374         *X = 0; *Y = 0;
375         hr = WINEDDERR_OVERLAYNOTVISIBLE;
376     } else {
377         *X = This->overlay_destrect.left;
378         *Y = This->overlay_destrect.top;
379         hr = WINED3D_OK;
380     }
381
382     TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
383     return hr;
384 }
385
386 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD flags, IWineD3DSurface *Ref)
387 {
388     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
389
390     FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, Ref);
391
392     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
393     {
394         TRACE("(%p): Not an overlay surface\n", This);
395         return WINEDDERR_NOTAOVERLAYSURFACE;
396     }
397
398     return WINED3D_OK;
399 }
400
401 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
402         IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD flags, const WINEDDOVERLAYFX *FX)
403 {
404     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
405     IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
406
407     TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
408             iface, wine_dbgstr_rect(SrcRect), DstSurface, wine_dbgstr_rect(DstRect), flags, FX);
409
410     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
411     {
412         WARN("(%p): Not an overlay surface\n", This);
413         return WINEDDERR_NOTAOVERLAYSURFACE;
414     } else if(!DstSurface) {
415         WARN("(%p): Dest surface is NULL\n", This);
416         return WINED3DERR_INVALIDCALL;
417     }
418
419     if(SrcRect) {
420         This->overlay_srcrect = *SrcRect;
421     } else {
422         This->overlay_srcrect.left = 0;
423         This->overlay_srcrect.top = 0;
424         This->overlay_srcrect.right = This->resource.width;
425         This->overlay_srcrect.bottom = This->resource.height;
426     }
427
428     if(DstRect) {
429         This->overlay_destrect = *DstRect;
430     } else {
431         This->overlay_destrect.left = 0;
432         This->overlay_destrect.top = 0;
433         This->overlay_destrect.right = Dst ? Dst->resource.width : 0;
434         This->overlay_destrect.bottom = Dst ? Dst->resource.height : 0;
435     }
436
437     if (This->overlay_dest && (This->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
438     {
439         list_remove(&This->overlay_entry);
440     }
441
442     if (flags & WINEDDOVER_SHOW)
443     {
444         if (This->overlay_dest != Dst)
445         {
446             This->overlay_dest = Dst;
447             list_add_tail(&Dst->overlays, &This->overlay_entry);
448         }
449     }
450     else if (flags & WINEDDOVER_HIDE)
451     {
452         /* tests show that the rectangles are erased on hide */
453         This->overlay_srcrect.left   = 0; This->overlay_srcrect.top     = 0;
454         This->overlay_srcrect.right  = 0; This->overlay_srcrect.bottom  = 0;
455         This->overlay_destrect.left  = 0; This->overlay_destrect.top    = 0;
456         This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
457         This->overlay_dest = NULL;
458     }
459
460     This->surface_ops->surface_draw_overlay(This);
461
462     return WINED3D_OK;
463 }
464
465 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, struct wined3d_clipper *clipper)
466 {
467     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
468
469     TRACE("iface %p, clipper %p.\n", iface, clipper);
470
471     This->clipper = clipper;
472
473     return WINED3D_OK;
474 }
475
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, struct wined3d_clipper **clipper)
477 {
478     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479
480     TRACE("iface %p, clipper %p.\n", iface, clipper);
481
482     *clipper = This->clipper;
483     if (*clipper)
484         wined3d_clipper_incref(*clipper);
485
486     return WINED3D_OK;
487 }
488
489 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
490 {
491     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
492     const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
493
494     if (This->resource.format->id != WINED3DFMT_UNKNOWN)
495     {
496         FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
497         return WINED3DERR_INVALIDCALL;
498     }
499
500     TRACE("(%p) : Setting texture format to %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
501
502     This->resource.size = wined3d_format_calculate_size(format, This->resource.device->surface_alignment,
503             This->pow2Width, This->pow2Height);
504
505     This->flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
506
507     This->resource.format = format;
508
509     TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
510
511     return WINED3D_OK;
512 }
513
514 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
515 {
516     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
517     const struct wined3d_format *format = This->resource.format;
518     int extraline = 0;
519     SYSTEM_INFO sysInfo;
520     BITMAPINFO* b_info;
521     HDC ddc;
522     DWORD *masks;
523     UINT usage;
524
525     if (!(format->flags & WINED3DFMT_FLAG_GETDC))
526     {
527         WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
528         return WINED3DERR_INVALIDCALL;
529     }
530
531     switch (format->byte_count)
532     {
533         case 2:
534         case 4:
535             /* Allocate extra space to store the RGB bit masks. */
536             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
537             break;
538
539         case 3:
540             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
541             break;
542
543         default:
544             /* Allocate extra space for a palette. */
545             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
546                     sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
547             break;
548     }
549
550     if (!b_info)
551         return E_OUTOFMEMORY;
552
553         /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
554     * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
555     * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
556     * add an extra line to the dib section
557         */
558     GetSystemInfo(&sysInfo);
559     if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
560         extraline = 1;
561         TRACE("Adding an extra line to the dib section\n");
562     }
563
564     b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
565     /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
566     b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
567     b_info->bmiHeader.biHeight = -This->resource.height - extraline;
568     b_info->bmiHeader.biSizeImage = (This->resource.height + extraline) * IWineD3DSurface_GetPitch(iface);
569     b_info->bmiHeader.biPlanes = 1;
570     b_info->bmiHeader.biBitCount = format->byte_count * 8;
571
572     b_info->bmiHeader.biXPelsPerMeter = 0;
573     b_info->bmiHeader.biYPelsPerMeter = 0;
574     b_info->bmiHeader.biClrUsed = 0;
575     b_info->bmiHeader.biClrImportant = 0;
576
577     /* Get the bit masks */
578     masks = (DWORD *)b_info->bmiColors;
579     switch (This->resource.format->id)
580     {
581         case WINED3DFMT_B8G8R8_UNORM:
582             usage = DIB_RGB_COLORS;
583             b_info->bmiHeader.biCompression = BI_RGB;
584             break;
585
586         case WINED3DFMT_B5G5R5X1_UNORM:
587         case WINED3DFMT_B5G5R5A1_UNORM:
588         case WINED3DFMT_B4G4R4A4_UNORM:
589         case WINED3DFMT_B4G4R4X4_UNORM:
590         case WINED3DFMT_B2G3R3_UNORM:
591         case WINED3DFMT_B2G3R3A8_UNORM:
592         case WINED3DFMT_R10G10B10A2_UNORM:
593         case WINED3DFMT_R8G8B8A8_UNORM:
594         case WINED3DFMT_R8G8B8X8_UNORM:
595         case WINED3DFMT_B10G10R10A2_UNORM:
596         case WINED3DFMT_B5G6R5_UNORM:
597         case WINED3DFMT_R16G16B16A16_UNORM:
598             usage = 0;
599             b_info->bmiHeader.biCompression = BI_BITFIELDS;
600             masks[0] = format->red_mask;
601             masks[1] = format->green_mask;
602             masks[2] = format->blue_mask;
603             break;
604
605         default:
606             /* Don't know palette */
607             b_info->bmiHeader.biCompression = BI_RGB;
608             usage = 0;
609             break;
610     }
611
612     if (!(ddc = GetDC(0)))
613     {
614         HeapFree(GetProcessHeap(), 0, b_info);
615         return HRESULT_FROM_WIN32(GetLastError());
616     }
617
618     TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
619     This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
620     ReleaseDC(0, ddc);
621
622     if (!This->dib.DIBsection) {
623         ERR("CreateDIBSection failed!\n");
624         HeapFree(GetProcessHeap(), 0, b_info);
625         return HRESULT_FROM_WIN32(GetLastError());
626     }
627
628     TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
629     /* copy the existing surface to the dib section */
630     if (This->resource.allocatedMemory)
631     {
632         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory,
633                 This->resource.height * IWineD3DSurface_GetPitch(iface));
634     }
635     else
636     {
637         /* This is to make LockRect read the gl Texture although memory is allocated */
638         This->flags &= ~SFLAG_INSYSMEM;
639     }
640     This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
641
642     HeapFree(GetProcessHeap(), 0, b_info);
643
644     /* Now allocate a HDC */
645     This->hDC = CreateCompatibleDC(0);
646     This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
647     TRACE("using wined3d palette %p\n", This->palette);
648     SelectPalette(This->hDC,
649                   This->palette ? This->palette->hpal : 0,
650                   FALSE);
651
652     This->flags |= SFLAG_DIBSECTION;
653
654     HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
655     This->resource.heapMemory = NULL;
656
657     return WINED3D_OK;
658 }
659
660 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
661                               unsigned int w, unsigned int h)
662 {
663     unsigned int x, y;
664     const float *src_f;
665     unsigned short *dst_s;
666
667     TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
668     for(y = 0; y < h; y++) {
669         src_f = (const float *)(src + y * pitch_in);
670         dst_s = (unsigned short *) (dst + y * pitch_out);
671         for(x = 0; x < w; x++) {
672             dst_s[x] = float_32_to_16(src_f + x);
673         }
674     }
675 }
676
677 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
678         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
679 {
680     static const unsigned char convert_5to8[] =
681     {
682         0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
683         0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
684         0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
685         0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
686     };
687     static const unsigned char convert_6to8[] =
688     {
689         0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
690         0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
691         0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
692         0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
693         0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
694         0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
695         0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
696         0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
697     };
698     unsigned int x, y;
699
700     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
701
702     for (y = 0; y < h; ++y)
703     {
704         const WORD *src_line = (const WORD *)(src + y * pitch_in);
705         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
706         for (x = 0; x < w; ++x)
707         {
708             WORD pixel = src_line[x];
709             dst_line[x] = 0xff000000
710                     | convert_5to8[(pixel & 0xf800) >> 11] << 16
711                     | convert_6to8[(pixel & 0x07e0) >> 5] << 8
712                     | convert_5to8[(pixel & 0x001f)];
713         }
714     }
715 }
716
717 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
718         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
719 {
720     unsigned int x, y;
721
722     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
723
724     for (y = 0; y < h; ++y)
725     {
726         const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
727         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
728
729         for (x = 0; x < w; ++x)
730         {
731             dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
732         }
733     }
734 }
735
736 static inline BYTE cliptobyte(int x)
737 {
738     return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
739 }
740
741 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
742         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
743 {
744     unsigned int x, y;
745     int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
746
747     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
748
749     for (y = 0; y < h; ++y)
750     {
751         const BYTE *src_line = src + y * pitch_in;
752         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
753         for (x = 0; x < w; ++x)
754         {
755             /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
756              *     C = Y - 16; D = U - 128; E = V - 128;
757              *     R = cliptobyte((298 * C + 409 * E + 128) >> 8);
758              *     G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
759              *     B = cliptobyte((298 * C + 516 * D + 128) >> 8);
760              * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
761              * U and V are shared between the pixels.
762              */
763             if (!(x & 1))         /* for every even pixel, read new U and V */
764             {
765                 d = (int) src_line[1] - 128;
766                 e = (int) src_line[3] - 128;
767                 r2 = 409 * e + 128;
768                 g2 = - 100 * d - 208 * e + 128;
769                 b2 = 516 * d + 128;
770             }
771             c2 = 298 * ((int) src_line[0] - 16);
772             dst_line[x] = 0xff000000
773                 | cliptobyte((c2 + r2) >> 8) << 16    /* red   */
774                 | cliptobyte((c2 + g2) >> 8) << 8     /* green */
775                 | cliptobyte((c2 + b2) >> 8);         /* blue  */
776                 /* Scale RGB values to 0..255 range,
777                  * then clip them if still not in range (may be negative),
778                  * then shift them within DWORD if necessary.
779                  */
780             src_line += 2;
781         }
782     }
783 }
784
785 struct d3dfmt_convertor_desc
786 {
787     enum wined3d_format_id from, to;
788     void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
789 };
790
791 static const struct d3dfmt_convertor_desc convertors[] =
792 {
793     {WINED3DFMT_R32_FLOAT,      WINED3DFMT_R16_FLOAT,       convert_r32_float_r16_float},
794     {WINED3DFMT_B5G6R5_UNORM,   WINED3DFMT_B8G8R8X8_UNORM,  convert_r5g6b5_x8r8g8b8},
795     {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM,  convert_a8r8g8b8_x8r8g8b8},
796     {WINED3DFMT_YUY2,           WINED3DFMT_B8G8R8X8_UNORM,  convert_yuy2_x8r8g8b8},
797 };
798
799 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
800 {
801     unsigned int i;
802     for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
803         if(convertors[i].from == from && convertors[i].to == to) {
804             return &convertors[i];
805         }
806     }
807     return NULL;
808 }
809
810 /*****************************************************************************
811  * surface_convert_format
812  *
813  * Creates a duplicate of a surface in a different format. Is used by Blt to
814  * blit between surfaces with different formats
815  *
816  * Parameters
817  *  source: Source surface
818  *  fmt: Requested destination format
819  *
820  *****************************************************************************/
821 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
822 {
823     IWineD3DSurface *ret = NULL;
824     const struct d3dfmt_convertor_desc *conv;
825     WINED3DLOCKED_RECT lock_src, lock_dst;
826     HRESULT hr;
827
828     conv = find_convertor(source->resource.format->id, to_fmt);
829     if (!conv)
830     {
831         FIXME("Cannot find a conversion function from format %s to %s.\n",
832                 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
833         return NULL;
834     }
835
836     IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->resource.width,
837             source->resource.height, to_fmt, TRUE /* lockable */, TRUE /* discard  */, 0 /* level */,
838             0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
839             0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
840             NULL /* parent */, &wined3d_null_parent_ops, &ret);
841     if(!ret) {
842         ERR("Failed to create a destination surface for conversion\n");
843         return NULL;
844     }
845
846     memset(&lock_src, 0, sizeof(lock_src));
847     memset(&lock_dst, 0, sizeof(lock_dst));
848
849     hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
850     if (FAILED(hr))
851     {
852         ERR("Failed to lock the source surface.\n");
853         IWineD3DSurface_Release(ret);
854         return NULL;
855     }
856     hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
857     if (FAILED(hr))
858     {
859         ERR("Failed to lock the dest surface\n");
860         IWineD3DSurface_Unmap((IWineD3DSurface *)source);
861         IWineD3DSurface_Release(ret);
862         return NULL;
863     }
864
865     conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
866             source->resource.width, source->resource.height);
867
868     IWineD3DSurface_Unmap(ret);
869     IWineD3DSurface_Unmap((IWineD3DSurface *)source);
870
871     return (IWineD3DSurfaceImpl *) ret;
872 }
873
874 /*****************************************************************************
875  * _Blt_ColorFill
876  *
877  * Helper function that fills a memory area with a specific color
878  *
879  * Params:
880  *  buf: memory address to start filling at
881  *  width, height: Dimensions of the area to fill
882  *  bpp: Bit depth of the surface
883  *  lPitch: pitch of the surface
884  *  color: Color to fill with
885  *
886  *****************************************************************************/
887 static HRESULT
888         _Blt_ColorFill(BYTE *buf,
889                        int width, int height,
890                        int bpp, LONG lPitch,
891                        DWORD color)
892 {
893     int x, y;
894     LPBYTE first;
895
896     /* Do first row */
897
898 #define COLORFILL_ROW(type) \
899     { \
900     type *d = (type *) buf; \
901     for (x = 0; x < width; x++) \
902     d[x] = (type) color; \
903     break; \
904 }
905     switch(bpp)
906     {
907         case 1: COLORFILL_ROW(BYTE)
908                 case 2: COLORFILL_ROW(WORD)
909         case 3:
910         {
911             BYTE *d = buf;
912             for (x = 0; x < width; x++,d+=3)
913             {
914                 d[0] = (color    ) & 0xFF;
915                 d[1] = (color>> 8) & 0xFF;
916                 d[2] = (color>>16) & 0xFF;
917             }
918             break;
919         }
920         case 4: COLORFILL_ROW(DWORD)
921         default:
922             FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
923             return WINED3DERR_NOTAVAILABLE;
924     }
925
926 #undef COLORFILL_ROW
927
928     /* Now copy first row */
929     first = buf;
930     for (y = 1; y < height; y++)
931     {
932         buf += lPitch;
933         memcpy(buf, first, width * bpp);
934     }
935     return WINED3D_OK;
936 }
937
938 /*****************************************************************************
939  * IWineD3DSurface::Blt, SW emulation version
940  *
941  * Performs a blit to a surface, with or without a source surface.
942  * This is the main functionality of DirectDraw
943  *
944  * Params:
945  *  DestRect: Destination rectangle to write to
946  *  src_surface: Source surface, can be NULL
947  *  SrcRect: Source rectangle
948  *****************************************************************************/
949 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
950         const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
951 {
952     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
953     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
954     RECT        xdst,xsrc;
955     HRESULT     ret = WINED3D_OK;
956     WINED3DLOCKED_RECT  dlock, slock;
957     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
958     const struct wined3d_format *sEntry, *dEntry;
959     int x, y;
960     const BYTE *sbuf;
961     BYTE *dbuf;
962
963     TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
964             iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
965             flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
966
967     if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
968     {
969         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
970         return WINEDDERR_SURFACEBUSY;
971     }
972
973     /* First check for the validity of source / destination rectangles.
974      * This was verified using a test application + by MSDN. */
975
976     if (SrcRect)
977     {
978         if (src)
979         {
980             if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
981                     || SrcRect->left > src->resource.width || SrcRect->left < 0
982                     || SrcRect->top > src->resource.height || SrcRect->top < 0
983                     || SrcRect->right > src->resource.width || SrcRect->right < 0
984                     || SrcRect->bottom > src->resource.height || SrcRect->bottom < 0)
985             {
986                 WARN("Application gave us bad source rectangle for Blt.\n");
987                 return WINEDDERR_INVALIDRECT;
988             }
989
990             if (!SrcRect->right || !SrcRect->bottom
991                     || SrcRect->left == (int)src->resource.width
992                     || SrcRect->top == (int)src->resource.height)
993             {
994                 TRACE("Nothing to be done.\n");
995                 return WINED3D_OK;
996             }
997         }
998
999         xsrc = *SrcRect;
1000     }
1001     else if (src)
1002     {
1003         xsrc.left = 0;
1004         xsrc.top = 0;
1005         xsrc.right = src->resource.width;
1006         xsrc.bottom = src->resource.height;
1007     }
1008     else
1009     {
1010         memset(&xsrc, 0, sizeof(xsrc));
1011     }
1012
1013     if (DestRect)
1014     {
1015         /* For the Destination rect, it can be out of bounds on the condition
1016          * that a clipper is set for the given surface. */
1017         if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1018                 || DestRect->left > This->resource.width || DestRect->left < 0
1019                 || DestRect->top > This->resource.height || DestRect->top < 0
1020                 || DestRect->right > This->resource.width || DestRect->right < 0
1021                 || DestRect->bottom > This->resource.height || DestRect->bottom < 0))
1022         {
1023             WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1024             return WINEDDERR_INVALIDRECT;
1025         }
1026
1027         if (DestRect->right <= 0 || DestRect->bottom <= 0
1028                 || DestRect->left >= (int)This->resource.width
1029                 || DestRect->top >= (int)This->resource.height)
1030         {
1031             TRACE("Nothing to be done.\n");
1032             return WINED3D_OK;
1033         }
1034
1035         if (!src)
1036         {
1037             RECT full_rect;
1038
1039             full_rect.left = 0;
1040             full_rect.top = 0;
1041             full_rect.right = This->resource.width;
1042             full_rect.bottom = This->resource.height;
1043             IntersectRect(&xdst, &full_rect, DestRect);
1044         }
1045         else
1046         {
1047             BOOL clip_horiz, clip_vert;
1048
1049             xdst = *DestRect;
1050             clip_horiz = xdst.left < 0 || xdst.right > (int)This->resource.width;
1051             clip_vert = xdst.top < 0 || xdst.bottom > (int)This->resource.height;
1052
1053             if (clip_vert || clip_horiz)
1054             {
1055                 /* Now check if this is a special case or not... */
1056                 if ((flags & WINEDDBLT_DDFX)
1057                         || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1058                         || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1059                 {
1060                     WARN("Out of screen rectangle in special case. Not handled right now.\n");
1061                     return WINED3D_OK;
1062                 }
1063
1064                 if (clip_horiz)
1065                 {
1066                     if (xdst.left < 0)
1067                     {
1068                         xsrc.left -= xdst.left;
1069                         xdst.left = 0;
1070                     }
1071                     if (xdst.right > This->resource.width)
1072                     {
1073                         xsrc.right -= (xdst.right - (int)This->resource.width);
1074                         xdst.right = (int)This->resource.width;
1075                     }
1076                 }
1077
1078                 if (clip_vert)
1079                 {
1080                     if (xdst.top < 0)
1081                     {
1082                         xsrc.top -= xdst.top;
1083                         xdst.top = 0;
1084                     }
1085                     if (xdst.bottom > This->resource.height)
1086                     {
1087                         xsrc.bottom -= (xdst.bottom - (int)This->resource.height);
1088                         xdst.bottom = (int)This->resource.height;
1089                     }
1090                 }
1091
1092                 /* And check if after clipping something is still to be done... */
1093                 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1094                         || (xdst.left >= (int)This->resource.width)
1095                         || (xdst.top >= (int)This->resource.height)
1096                         || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1097                         || (xsrc.left >= (int)src->resource.width)
1098                         || (xsrc.top >= (int)src->resource.height))
1099                 {
1100                     TRACE("Nothing to be done after clipping.\n");
1101                     return WINED3D_OK;
1102                 }
1103             }
1104         }
1105     }
1106     else
1107     {
1108         xdst.left = 0;
1109         xdst.top = 0;
1110         xdst.right = This->resource.width;
1111         xdst.bottom = This->resource.height;
1112     }
1113
1114     if (src == This)
1115     {
1116         IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1117         slock = dlock;
1118         sEntry = This->resource.format;
1119         dEntry = sEntry;
1120     }
1121     else
1122     {
1123         dEntry = This->resource.format;
1124         if (src)
1125         {
1126             if (This->resource.format->id != src->resource.format->id)
1127             {
1128                 src = surface_convert_format(src, dEntry->id);
1129                 if (!src)
1130                 {
1131                     /* The conv function writes a FIXME */
1132                     WARN("Cannot convert source surface format to dest format\n");
1133                     goto release;
1134                 }
1135             }
1136             IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1137             sEntry = src->resource.format;
1138         }
1139         else
1140         {
1141             sEntry = dEntry;
1142         }
1143         if (DestRect)
1144             IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1145         else
1146             IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1147     }
1148
1149     if (!DDBltFx || !(DDBltFx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
1150
1151     if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_FOURCC)
1152     {
1153         if (!DestRect || src == This)
1154         {
1155             memcpy(dlock.pBits, slock.pBits, This->resource.size);
1156             goto release;
1157         }
1158     }
1159
1160     bpp = This->resource.format->byte_count;
1161     srcheight = xsrc.bottom - xsrc.top;
1162     srcwidth = xsrc.right - xsrc.left;
1163     dstheight = xdst.bottom - xdst.top;
1164     dstwidth = xdst.right - xdst.left;
1165     width = (xdst.right - xdst.left) * bpp;
1166
1167     if (DestRect && src != This)
1168         dbuf = dlock.pBits;
1169     else
1170         dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1171
1172     if (flags & WINEDDBLT_WAIT)
1173     {
1174         flags &= ~WINEDDBLT_WAIT;
1175     }
1176     if (flags & WINEDDBLT_ASYNC)
1177     {
1178         static BOOL displayed = FALSE;
1179         if (!displayed)
1180             FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1181         displayed = TRUE;
1182         flags &= ~WINEDDBLT_ASYNC;
1183     }
1184     if (flags & WINEDDBLT_DONOTWAIT)
1185     {
1186         /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1187         static BOOL displayed = FALSE;
1188         if (!displayed)
1189             FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1190         displayed = TRUE;
1191         flags &= ~WINEDDBLT_DONOTWAIT;
1192     }
1193
1194     /* First, all the 'source-less' blits */
1195     if (flags & WINEDDBLT_COLORFILL)
1196     {
1197         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1198                              dlock.Pitch, DDBltFx->u5.dwFillColor);
1199         flags &= ~WINEDDBLT_COLORFILL;
1200     }
1201
1202     if (flags & WINEDDBLT_DEPTHFILL)
1203     {
1204         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1205     }
1206     if (flags & WINEDDBLT_ROP)
1207     {
1208         /* Catch some degenerate cases here */
1209         switch(DDBltFx->dwROP)
1210         {
1211             case BLACKNESS:
1212                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1213                 break;
1214                 case 0xAA0029: /* No-op */
1215                     break;
1216             case WHITENESS:
1217                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1218                 break;
1219                 case SRCCOPY: /* well, we do that below ? */
1220                     break;
1221             default:
1222                 FIXME("Unsupported raster op: %08x  Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1223                 goto error;
1224         }
1225         flags &= ~WINEDDBLT_ROP;
1226     }
1227     if (flags & WINEDDBLT_DDROPS)
1228     {
1229         FIXME("\tDdraw Raster Ops: %08x  Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1230     }
1231     /* Now the 'with source' blits */
1232     if (src)
1233     {
1234         const BYTE *sbase;
1235         int sx, xinc, sy, yinc;
1236
1237         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1238             goto release;
1239
1240         if (Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT
1241                 && (srcwidth != dstwidth || srcheight != dstheight))
1242         {
1243             /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1244             FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter));
1245         }
1246
1247         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1248         xinc = (srcwidth << 16) / dstwidth;
1249         yinc = (srcheight << 16) / dstheight;
1250
1251         if (!flags)
1252         {
1253             /* No effects, we can cheat here */
1254             if (dstwidth == srcwidth)
1255             {
1256                 if (dstheight == srcheight)
1257                 {
1258                     /* No stretching in either direction. This needs to be as
1259                     * fast as possible */
1260                     sbuf = sbase;
1261
1262                     /* check for overlapping surfaces */
1263                     if (src != This || xdst.top < xsrc.top ||
1264                         xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1265                     {
1266                         /* no overlap, or dst above src, so copy from top downwards */
1267                         for (y = 0; y < dstheight; y++)
1268                         {
1269                             memcpy(dbuf, sbuf, width);
1270                             sbuf += slock.Pitch;
1271                             dbuf += dlock.Pitch;
1272                         }
1273                     }
1274                     else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
1275                     {
1276                         sbuf += (slock.Pitch*dstheight);
1277                         dbuf += (dlock.Pitch*dstheight);
1278                         for (y = 0; y < dstheight; y++)
1279                         {
1280                             sbuf -= slock.Pitch;
1281                             dbuf -= dlock.Pitch;
1282                             memcpy(dbuf, sbuf, width);
1283                         }
1284                     }
1285                     else /* src and dst overlapping on the same line, use memmove */
1286                     {
1287                         for (y = 0; y < dstheight; y++)
1288                         {
1289                             memmove(dbuf, sbuf, width);
1290                             sbuf += slock.Pitch;
1291                             dbuf += dlock.Pitch;
1292                         }
1293                     }
1294                 } else {
1295                     /* Stretching in Y direction only */
1296                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1297                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1298                         memcpy(dbuf, sbuf, width);
1299                         dbuf += dlock.Pitch;
1300                     }
1301                 }
1302             }
1303             else
1304             {
1305                 /* Stretching in X direction */
1306                 int last_sy = -1;
1307                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1308                 {
1309                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1310
1311                     if ((sy >> 16) == (last_sy >> 16))
1312                     {
1313                         /* this sourcerow is the same as last sourcerow -
1314                         * copy already stretched row
1315                         */
1316                         memcpy(dbuf, dbuf - dlock.Pitch, width);
1317                     }
1318                     else
1319                     {
1320 #define STRETCH_ROW(type) { \
1321                         const type *s = (const type *)sbuf; \
1322                         type *d = (type *)dbuf; \
1323                         for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1324                         d[x] = s[sx >> 16]; \
1325                         break; }
1326
1327                         switch(bpp)
1328                         {
1329                             case 1: STRETCH_ROW(BYTE)
1330                                     case 2: STRETCH_ROW(WORD)
1331                                             case 4: STRETCH_ROW(DWORD)
1332                             case 3:
1333                             {
1334                                 const BYTE *s;
1335                                 BYTE *d = dbuf;
1336                                 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1337                                 {
1338                                     DWORD pixel;
1339
1340                                     s = sbuf+3*(sx>>16);
1341                                     pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1342                                     d[0] = (pixel    )&0xff;
1343                                     d[1] = (pixel>> 8)&0xff;
1344                                     d[2] = (pixel>>16)&0xff;
1345                                     d+=3;
1346                                 }
1347                                 break;
1348                             }
1349                             default:
1350                                 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1351                                 ret = WINED3DERR_NOTAVAILABLE;
1352                                 goto error;
1353                         }
1354 #undef STRETCH_ROW
1355                     }
1356                     dbuf += dlock.Pitch;
1357                     last_sy = sy;
1358                 }
1359             }
1360         }
1361         else
1362         {
1363             LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1364             DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1365             DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1366             if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1367             {
1368                 /* The color keying flags are checked for correctness in ddraw */
1369                 if (flags & WINEDDBLT_KEYSRC)
1370                 {
1371                     keylow  = src->SrcBltCKey.dwColorSpaceLowValue;
1372                     keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1373                 }
1374                 else  if (flags & WINEDDBLT_KEYSRCOVERRIDE)
1375                 {
1376                     keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1377                     keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1378                 }
1379
1380                 if (flags & WINEDDBLT_KEYDEST)
1381                 {
1382                     /* Destination color keys are taken from the source surface ! */
1383                     destkeylow  = src->DestBltCKey.dwColorSpaceLowValue;
1384                     destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1385                 }
1386                 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
1387                 {
1388                     destkeylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1389                     destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1390                 }
1391
1392                 if(bpp == 1)
1393                 {
1394                     keymask = 0xff;
1395                 }
1396                 else
1397                 {
1398                     keymask = sEntry->red_mask
1399                             | sEntry->green_mask
1400                             | sEntry->blue_mask;
1401                 }
1402                 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1403             }
1404
1405             if (flags & WINEDDBLT_DDFX)
1406             {
1407                 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1408                 LONG tmpxy;
1409                 dTopLeft     = dbuf;
1410                 dTopRight    = dbuf+((dstwidth-1)*bpp);
1411                 dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
1412                 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1413
1414                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1415                 {
1416                     /* I don't think we need to do anything about this flag */
1417                     WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1418                 }
1419                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1420                 {
1421                     tmp          = dTopRight;
1422                     dTopRight    = dTopLeft;
1423                     dTopLeft     = tmp;
1424                     tmp          = dBottomRight;
1425                     dBottomRight = dBottomLeft;
1426                     dBottomLeft  = tmp;
1427                     dstxinc = dstxinc *-1;
1428                 }
1429                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1430                 {
1431                     tmp          = dTopLeft;
1432                     dTopLeft     = dBottomLeft;
1433                     dBottomLeft  = tmp;
1434                     tmp          = dTopRight;
1435                     dTopRight    = dBottomRight;
1436                     dBottomRight = tmp;
1437                     dstyinc = dstyinc *-1;
1438                 }
1439                 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1440                 {
1441                     /* I don't think we need to do anything about this flag */
1442                     WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1443                 }
1444                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1445                 {
1446                     tmp          = dBottomRight;
1447                     dBottomRight = dTopLeft;
1448                     dTopLeft     = tmp;
1449                     tmp          = dBottomLeft;
1450                     dBottomLeft  = dTopRight;
1451                     dTopRight    = tmp;
1452                     dstxinc = dstxinc * -1;
1453                     dstyinc = dstyinc * -1;
1454                 }
1455                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1456                 {
1457                     tmp          = dTopLeft;
1458                     dTopLeft     = dBottomLeft;
1459                     dBottomLeft  = dBottomRight;
1460                     dBottomRight = dTopRight;
1461                     dTopRight    = tmp;
1462                     tmpxy   = dstxinc;
1463                     dstxinc = dstyinc;
1464                     dstyinc = tmpxy;
1465                     dstxinc = dstxinc * -1;
1466                 }
1467                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1468                 {
1469                     tmp          = dTopLeft;
1470                     dTopLeft     = dTopRight;
1471                     dTopRight    = dBottomRight;
1472                     dBottomRight = dBottomLeft;
1473                     dBottomLeft  = tmp;
1474                     tmpxy   = dstxinc;
1475                     dstxinc = dstyinc;
1476                     dstyinc = tmpxy;
1477                     dstyinc = dstyinc * -1;
1478                 }
1479                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1480                 {
1481                     /* I don't think we need to do anything about this flag */
1482                     WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1483                 }
1484                 dbuf = dTopLeft;
1485                 flags &= ~(WINEDDBLT_DDFX);
1486             }
1487
1488 #define COPY_COLORKEY_FX(type) { \
1489             const type *s; \
1490             type *d = (type *)dbuf, *dx, tmp; \
1491             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1492             s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1493             dx = d; \
1494             for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1495             tmp = s[sx >> 16]; \
1496             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1497             ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1498             dx[0] = tmp; \
1499         } \
1500             dx = (type*)(((LPBYTE)dx)+dstxinc); \
1501         } \
1502             d = (type*)(((LPBYTE)d)+dstyinc); \
1503         } \
1504             break; }
1505
1506             switch (bpp) {
1507                 case 1: COPY_COLORKEY_FX(BYTE)
1508                         case 2: COPY_COLORKEY_FX(WORD)
1509                                 case 4: COPY_COLORKEY_FX(DWORD)
1510                 case 3:
1511                 {
1512                     const BYTE *s;
1513                     BYTE *d = dbuf, *dx;
1514                     for (y = sy = 0; y < dstheight; y++, sy += yinc)
1515                     {
1516                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1517                         dx = d;
1518                         for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1519                         {
1520                             DWORD pixel, dpixel = 0;
1521                             s = sbuf+3*(sx>>16);
1522                             pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1523                             dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1524                             if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1525                                   ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1526                             {
1527                                 dx[0] = (pixel    )&0xff;
1528                                 dx[1] = (pixel>> 8)&0xff;
1529                                 dx[2] = (pixel>>16)&0xff;
1530                             }
1531                             dx+= dstxinc;
1532                         }
1533                         d += dstyinc;
1534                     }
1535                     break;
1536                 }
1537                 default:
1538                     FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1539                           (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1540                     ret = WINED3DERR_NOTAVAILABLE;
1541                     goto error;
1542 #undef COPY_COLORKEY_FX
1543             }
1544         }
1545     }
1546
1547 error:
1548     if (flags && FIXME_ON(d3d_surface))
1549     {
1550         FIXME("\tUnsupported flags: %#x.\n", flags);
1551     }
1552
1553 release:
1554     IWineD3DSurface_Unmap(iface);
1555     if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1556     /* Release the converted surface if any */
1557     if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1558     return ret;
1559 }
1560
1561 /*****************************************************************************
1562  * IWineD3DSurface::BltFast, SW emulation version
1563  *
1564  * This is the software implementation of BltFast, as used by GDI surfaces
1565  * and as a fallback for OpenGL surfaces. This code is taken from the old
1566  * DirectDraw code, and was originally written by TransGaming.
1567  *
1568  * Params:
1569  *  dstx:
1570  *  dsty:
1571  *  src_surface: Source surface to copy from
1572  *  rsrc: Source rectangle
1573  *  trans: Some flags
1574  *
1575  * Returns:
1576  *  WINED3D_OK on success
1577  *
1578  *****************************************************************************/
1579 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1580         IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1581 {
1582     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1583     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1584
1585     int                 bpp, w, h, x, y;
1586     WINED3DLOCKED_RECT  dlock,slock;
1587     HRESULT             ret = WINED3D_OK;
1588     RECT                rsrc2;
1589     RECT                lock_src, lock_dst, lock_union;
1590     const BYTE          *sbuf;
1591     BYTE                *dbuf;
1592     const struct wined3d_format *sEntry, *dEntry;
1593
1594     TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1595             iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1596
1597     if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
1598     {
1599         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1600         return WINEDDERR_SURFACEBUSY;
1601     }
1602
1603     if (!rsrc)
1604     {
1605         WARN("rsrc is NULL!\n");
1606         rsrc2.left = 0;
1607         rsrc2.top = 0;
1608         rsrc2.right = src->resource.width;
1609         rsrc2.bottom = src->resource.height;
1610         rsrc = &rsrc2;
1611     }
1612
1613     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1614     if ((rsrc->bottom > src->resource.height) || (rsrc->bottom < 0)
1615             || (rsrc->top   > src->resource.height) || (rsrc->top    < 0)
1616             || (rsrc->left  > src->resource.width)  || (rsrc->left   < 0)
1617             || (rsrc->right > src->resource.width)  || (rsrc->right  < 0)
1618             || (rsrc->right < rsrc->left)              || (rsrc->bottom < rsrc->top))
1619     {
1620         WARN("Application gave us bad source rectangle for BltFast.\n");
1621         return WINEDDERR_INVALIDRECT;
1622     }
1623
1624     h = rsrc->bottom - rsrc->top;
1625     if (h > This->resource.height-dsty)
1626         h = This->resource.height-dsty;
1627     if (h > src->resource.height-rsrc->top)
1628         h = src->resource.height-rsrc->top;
1629     if (h <= 0)
1630         return WINEDDERR_INVALIDRECT;
1631
1632     w = rsrc->right - rsrc->left;
1633     if (w > This->resource.width-dstx)
1634         w = This->resource.width-dstx;
1635     if (w > src->resource.width-rsrc->left)
1636         w = src->resource.width-rsrc->left;
1637     if (w <= 0)
1638         return WINEDDERR_INVALIDRECT;
1639
1640     /* Now compute the locking rectangle... */
1641     lock_src.left = rsrc->left;
1642     lock_src.top = rsrc->top;
1643     lock_src.right = lock_src.left + w;
1644     lock_src.bottom = lock_src.top + h;
1645
1646     lock_dst.left = dstx;
1647     lock_dst.top = dsty;
1648     lock_dst.right = dstx + w;
1649     lock_dst.bottom = dsty + h;
1650
1651     bpp = This->resource.format->byte_count;
1652
1653     /* We need to lock the surfaces, or we won't get refreshes when done. */
1654     if (src == This)
1655     {
1656         int pitch;
1657
1658         UnionRect(&lock_union, &lock_src, &lock_dst);
1659
1660         /* Lock the union of the two rectangles */
1661         ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
1662         if (FAILED(ret)) goto error;
1663
1664         pitch = dlock.Pitch;
1665         slock.Pitch = dlock.Pitch;
1666
1667         /* Since slock was originally copied from this surface's description, we can just reuse it */
1668         sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1669         dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1670         sEntry = src->resource.format;
1671         dEntry = sEntry;
1672     }
1673     else
1674     {
1675         ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1676         if (FAILED(ret)) goto error;
1677         ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
1678         if (FAILED(ret)) goto error;
1679
1680         sbuf = slock.pBits;
1681         dbuf = dlock.pBits;
1682         TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1683
1684         sEntry = src->resource.format;
1685         dEntry = This->resource.format;
1686     }
1687
1688     /* Handle compressed surfaces first... */
1689     if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_COMPRESSED)
1690     {
1691         UINT row_block_count;
1692
1693         TRACE("compressed -> compressed copy\n");
1694         if (trans)
1695             FIXME("trans arg not supported when a compressed surface is involved\n");
1696         if (dstx || dsty)
1697             FIXME("offset for destination surface is not supported\n");
1698         if (src->resource.format->id != This->resource.format->id)
1699         {
1700             FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1701             ret = WINED3DERR_WRONGTEXTUREFORMAT;
1702             goto error;
1703         }
1704
1705         row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1706         for (y = 0; y < h; y += dEntry->block_height)
1707         {
1708             memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1709             dbuf += dlock.Pitch;
1710             sbuf += slock.Pitch;
1711         }
1712
1713         goto error;
1714     }
1715     if ((sEntry->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->flags & WINED3DFMT_FLAG_COMPRESSED))
1716     {
1717         /* TODO: Use the libtxc_dxtn.so shared library to do
1718          * software decompression
1719          */
1720         ERR("Software decompression not supported.\n");
1721         goto error;
1722     }
1723
1724     if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1725     {
1726         DWORD keylow, keyhigh;
1727         DWORD mask = src->resource.format->red_mask
1728                 | src->resource.format->green_mask
1729                 | src->resource.format->blue_mask;
1730
1731         /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1732         if(!mask && bpp==1)
1733             mask = 0xff;
1734
1735         TRACE("Color keyed copy\n");
1736         if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1737         {
1738             keylow  = src->SrcBltCKey.dwColorSpaceLowValue;
1739             keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1740         }
1741         else
1742         {
1743             /* I'm not sure if this is correct */
1744             FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1745             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1746             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1747         }
1748
1749 #define COPYBOX_COLORKEY(type) { \
1750         const type *s = (const type *)sbuf; \
1751         type *d = (type *)dbuf; \
1752         type tmp; \
1753         for (y = 0; y < h; y++) { \
1754         for (x = 0; x < w; x++) { \
1755         tmp = s[x]; \
1756         if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1757     } \
1758         s = (const type *)((const BYTE *)s + slock.Pitch); \
1759         d = (type *)((BYTE *)d + dlock.Pitch); \
1760     } \
1761         break; \
1762     }
1763
1764         switch (bpp) {
1765             case 1: COPYBOX_COLORKEY(BYTE)
1766                     case 2: COPYBOX_COLORKEY(WORD)
1767                             case 4: COPYBOX_COLORKEY(DWORD)
1768             case 3:
1769             {
1770                 const BYTE *s;
1771                 BYTE *d;
1772                 DWORD tmp;
1773                 s = sbuf;
1774                 d = dbuf;
1775                 for (y = 0; y < h; y++)
1776                 {
1777                     for (x = 0; x < w * 3; x += 3)
1778                     {
1779                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1780                         if (tmp < keylow || tmp > keyhigh)
1781                         {
1782                             d[x + 0] = s[x + 0];
1783                             d[x + 1] = s[x + 1];
1784                             d[x + 2] = s[x + 2];
1785                         }
1786                     }
1787                     s += slock.Pitch;
1788                     d += dlock.Pitch;
1789                 }
1790                 break;
1791             }
1792             default:
1793                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1794                 ret = WINED3DERR_NOTAVAILABLE;
1795                 goto error;
1796         }
1797 #undef COPYBOX_COLORKEY
1798         TRACE("Copy Done\n");
1799     }
1800     else
1801     {
1802         int width = w * bpp;
1803         INT sbufpitch, dbufpitch;
1804
1805         TRACE("NO color key copy\n");
1806         /* Handle overlapping surfaces */
1807         if (sbuf < dbuf)
1808         {
1809             sbuf += (h - 1) * slock.Pitch;
1810             dbuf += (h - 1) * dlock.Pitch;
1811             sbufpitch = -slock.Pitch;
1812             dbufpitch = -dlock.Pitch;
1813         }
1814         else
1815         {
1816             sbufpitch = slock.Pitch;
1817             dbufpitch = dlock.Pitch;
1818         }
1819         for (y = 0; y < h; y++)
1820         {
1821             /* This is pretty easy, a line for line memcpy */
1822             memmove(dbuf, sbuf, width);
1823             sbuf += sbufpitch;
1824             dbuf += dbufpitch;
1825         }
1826         TRACE("Copy done\n");
1827     }
1828
1829 error:
1830     if (src == This)
1831     {
1832         IWineD3DSurface_Unmap(iface);
1833     }
1834     else
1835     {
1836         IWineD3DSurface_Unmap(iface);
1837         IWineD3DSurface_Unmap(src_surface);
1838     }
1839
1840     return ret;
1841 }
1842
1843 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
1844         WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
1845 {
1846     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1847
1848     TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1849             iface, pLockedRect, wine_dbgstr_rect(pRect), flags);
1850
1851     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1852
1853     if (!pRect)
1854     {
1855         pLockedRect->pBits = This->resource.allocatedMemory;
1856         This->lockedRect.left   = 0;
1857         This->lockedRect.top    = 0;
1858         This->lockedRect.right  = This->resource.width;
1859         This->lockedRect.bottom = This->resource.height;
1860
1861         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1862               &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1863               This->lockedRect.right, This->lockedRect.bottom);
1864     }
1865     else
1866     {
1867         const struct wined3d_format *format = This->resource.format;
1868
1869         TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1870               pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1871
1872         if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1873         {
1874             /* Compressed textures are block based, so calculate the offset of
1875              * the block that contains the top-left pixel of the locked rectangle. */
1876             pLockedRect->pBits = This->resource.allocatedMemory
1877                     + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1878                     + ((pRect->left / format->block_width) * format->block_byte_count);
1879         }
1880         else
1881         {
1882             pLockedRect->pBits = This->resource.allocatedMemory +
1883                     (pLockedRect->Pitch * pRect->top) +
1884                     (pRect->left * format->byte_count);
1885         }
1886         This->lockedRect.left   = pRect->left;
1887         This->lockedRect.top    = pRect->top;
1888         This->lockedRect.right  = pRect->right;
1889         This->lockedRect.bottom = pRect->bottom;
1890     }
1891
1892     /* No dirtifying is needed for this surface implementation */
1893     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1894
1895     return WINED3D_OK;
1896 }