ws2_32: name is never NULL as array (Coverity).
[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((IWineD3DResourceImpl *)iface, 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((IWineD3DResourceImpl *)iface, guid, data, data_size);
124 }
125
126 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid)
127 {
128     return resource_free_private_data((IWineD3DResourceImpl *)iface, refguid);
129 }
130
131 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD priority)
132 {
133     return resource_set_priority((IWineD3DResourceImpl *)iface, priority);
134 }
135
136 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface)
137 {
138     return resource_get_priority((IWineD3DResourceImpl *)iface);
139 }
140
141 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface)
142 {
143     return resource_get_type((IWineD3DResourceImpl *)iface);
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 void WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *desc)
154 {
155     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
156
157     TRACE("iface %p, desc %p.\n", iface, desc);
158
159     desc->format = surface->resource.format->id;
160     desc->resource_type = surface->resource.resourceType;
161     desc->usage = surface->resource.usage;
162     desc->pool = surface->resource.pool;
163     desc->size = surface->resource.size; /* dx8 only */
164     desc->multisample_type = surface->currentDesc.MultiSampleType;
165     desc->multisample_quality = surface->currentDesc.MultiSampleQuality;
166     desc->width = surface->currentDesc.Width;
167     desc->height = surface->currentDesc.Height;
168 }
169
170 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD flags)
171 {
172     TRACE("iface %p, flags %#x.\n", iface, flags);
173
174     switch (flags)
175     {
176         case WINEDDGBS_CANBLT:
177         case WINEDDGBS_ISBLTDONE:
178             return WINED3D_OK;
179
180         default:
181             return WINED3DERR_INVALIDCALL;
182     }
183 }
184
185 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD flags)
186 {
187     /* XXX: DDERR_INVALIDSURFACETYPE */
188
189     TRACE("iface %p, flags %#x.\n", iface, flags);
190
191     switch (flags)
192     {
193         case WINEDDGFS_CANFLIP:
194         case WINEDDGFS_ISFLIPDONE:
195             return WINED3D_OK;
196
197         default:
198             return WINED3DERR_INVALIDCALL;
199     }
200 }
201
202 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
203     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
204     TRACE("(%p)\n", This);
205
206     /* D3D8 and 9 loose full devices, ddraw only surfaces */
207     return This->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
208 }
209
210 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
211     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
212     TRACE("(%p)\n", This);
213
214     /* So far we don't lose anything :) */
215     This->flags &= ~SFLAG_LOST;
216     return WINED3D_OK;
217 }
218
219 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, struct wined3d_palette *palette)
220 {
221     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
222
223     TRACE("iface %p, palette %p.\n", iface, palette);
224
225     if (This->palette == palette)
226     {
227         TRACE("Nop palette change\n");
228         return WINED3D_OK;
229     }
230
231     if (This->palette)
232         if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
233             This->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
234
235     This->palette = palette;
236
237     if (palette)
238     {
239         if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
240             palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
241
242         This->surface_ops->surface_realize_palette(This);
243     }
244
245     return WINED3D_OK;
246 }
247
248 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD flags, const WINEDDCOLORKEY *CKey)
249 {
250     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
251
252     TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, CKey);
253
254     if (flags & WINEDDCKEY_COLORSPACE)
255     {
256         FIXME(" colorkey value not supported (%08x) !\n", flags);
257         return WINED3DERR_INVALIDCALL;
258     }
259
260     /* Dirtify the surface, but only if a key was changed */
261     if (CKey)
262     {
263         switch (flags & ~WINEDDCKEY_COLORSPACE)
264         {
265             case WINEDDCKEY_DESTBLT:
266                 This->DestBltCKey = *CKey;
267                 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
268                 break;
269
270             case WINEDDCKEY_DESTOVERLAY:
271                 This->DestOverlayCKey = *CKey;
272                 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
273                 break;
274
275             case WINEDDCKEY_SRCOVERLAY:
276                 This->SrcOverlayCKey = *CKey;
277                 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
278                 break;
279
280             case WINEDDCKEY_SRCBLT:
281                 This->SrcBltCKey = *CKey;
282                 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
283                 break;
284         }
285     }
286     else
287     {
288         switch (flags & ~WINEDDCKEY_COLORSPACE)
289         {
290             case WINEDDCKEY_DESTBLT:
291                 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
292                 break;
293
294             case WINEDDCKEY_DESTOVERLAY:
295                 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
296                 break;
297
298             case WINEDDCKEY_SRCOVERLAY:
299                 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
300                 break;
301
302             case WINEDDCKEY_SRCBLT:
303                 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
304                 break;
305         }
306     }
307
308     return WINED3D_OK;
309 }
310
311 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, struct wined3d_palette **palette)
312 {
313     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
314
315     TRACE("iface %p, palette %p.\n", iface, palette);
316
317     *palette = This->palette;
318
319     return WINED3D_OK;
320 }
321
322 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
323 {
324     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
325     const struct wined3d_format *format = This->resource.format;
326     DWORD ret;
327     TRACE("(%p)\n", This);
328
329     if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
330     {
331         /* Since compressed formats are block based, pitch means the amount of
332          * bytes to the next row of block rather than the next row of pixels. */
333         UINT row_block_count = (This->currentDesc.Width + format->block_width - 1) / format->block_width;
334         ret = row_block_count * format->block_byte_count;
335     }
336     else
337     {
338         unsigned char alignment = This->resource.device->surface_alignment;
339         ret = This->resource.format->byte_count * This->currentDesc.Width;  /* Bytes / row */
340         ret = (ret + alignment - 1) & ~(alignment - 1);
341     }
342     TRACE("(%p) Returning %d\n", This, ret);
343     return ret;
344 }
345
346 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
347     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
348     LONG w, h;
349
350     TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
351
352     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
353     {
354         TRACE("(%p): Not an overlay surface\n", This);
355         return WINEDDERR_NOTAOVERLAYSURFACE;
356     }
357
358     w = This->overlay_destrect.right - This->overlay_destrect.left;
359     h = This->overlay_destrect.bottom - This->overlay_destrect.top;
360     This->overlay_destrect.left = X;
361     This->overlay_destrect.top = Y;
362     This->overlay_destrect.right = X + w;
363     This->overlay_destrect.bottom = Y + h;
364
365     This->surface_ops->surface_draw_overlay(This);
366
367     return WINED3D_OK;
368 }
369
370 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
371     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
372     HRESULT hr;
373
374     TRACE("(%p)->(%p,%p)\n", This, X, Y);
375
376     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
377     {
378         TRACE("(%p): Not an overlay surface\n", This);
379         return WINEDDERR_NOTAOVERLAYSURFACE;
380     }
381
382     if (!This->overlay_dest)
383     {
384         *X = 0; *Y = 0;
385         hr = WINEDDERR_OVERLAYNOTVISIBLE;
386     } else {
387         *X = This->overlay_destrect.left;
388         *Y = This->overlay_destrect.top;
389         hr = WINED3D_OK;
390     }
391
392     TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
393     return hr;
394 }
395
396 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD flags, IWineD3DSurface *Ref)
397 {
398     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
399
400     FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, Ref);
401
402     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
403     {
404         TRACE("(%p): Not an overlay surface\n", This);
405         return WINEDDERR_NOTAOVERLAYSURFACE;
406     }
407
408     return WINED3D_OK;
409 }
410
411 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
412         IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD flags, const WINEDDOVERLAYFX *FX)
413 {
414     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
415     IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
416
417     TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
418             iface, wine_dbgstr_rect(SrcRect), DstSurface, wine_dbgstr_rect(DstRect), flags, FX);
419
420     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
421     {
422         WARN("(%p): Not an overlay surface\n", This);
423         return WINEDDERR_NOTAOVERLAYSURFACE;
424     } else if(!DstSurface) {
425         WARN("(%p): Dest surface is NULL\n", This);
426         return WINED3DERR_INVALIDCALL;
427     }
428
429     if(SrcRect) {
430         This->overlay_srcrect = *SrcRect;
431     } else {
432         This->overlay_srcrect.left = 0;
433         This->overlay_srcrect.top = 0;
434         This->overlay_srcrect.right = This->currentDesc.Width;
435         This->overlay_srcrect.bottom = This->currentDesc.Height;
436     }
437
438     if(DstRect) {
439         This->overlay_destrect = *DstRect;
440     } else {
441         This->overlay_destrect.left = 0;
442         This->overlay_destrect.top = 0;
443         This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
444         This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
445     }
446
447     if (This->overlay_dest && (This->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
448     {
449         list_remove(&This->overlay_entry);
450     }
451
452     if (flags & WINEDDOVER_SHOW)
453     {
454         if (This->overlay_dest != Dst)
455         {
456             This->overlay_dest = Dst;
457             list_add_tail(&Dst->overlays, &This->overlay_entry);
458         }
459     }
460     else if (flags & WINEDDOVER_HIDE)
461     {
462         /* tests show that the rectangles are erased on hide */
463         This->overlay_srcrect.left   = 0; This->overlay_srcrect.top     = 0;
464         This->overlay_srcrect.right  = 0; This->overlay_srcrect.bottom  = 0;
465         This->overlay_destrect.left  = 0; This->overlay_destrect.top    = 0;
466         This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
467         This->overlay_dest = NULL;
468     }
469
470     This->surface_ops->surface_draw_overlay(This);
471
472     return WINED3D_OK;
473 }
474
475 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, struct wined3d_clipper *clipper)
476 {
477     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
478
479     TRACE("iface %p, clipper %p.\n", iface, clipper);
480
481     This->clipper = clipper;
482
483     return WINED3D_OK;
484 }
485
486 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, struct wined3d_clipper **clipper)
487 {
488     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
489
490     TRACE("iface %p, clipper %p.\n", iface, clipper);
491
492     *clipper = This->clipper;
493     if (*clipper)
494         wined3d_clipper_incref(*clipper);
495
496     return WINED3D_OK;
497 }
498
499 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
500 {
501     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
502     const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
503
504     if (This->resource.format->id != WINED3DFMT_UNKNOWN)
505     {
506         FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
507         return WINED3DERR_INVALIDCALL;
508     }
509
510     TRACE("(%p) : Setting texture format to %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
511
512     This->resource.size = wined3d_format_calculate_size(format, This->resource.device->surface_alignment,
513             This->pow2Width, This->pow2Height);
514
515     This->flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
516
517     This->resource.format = format;
518
519     TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
520
521     return WINED3D_OK;
522 }
523
524 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
525 {
526     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
527     const struct wined3d_format *format = This->resource.format;
528     int extraline = 0;
529     SYSTEM_INFO sysInfo;
530     BITMAPINFO* b_info;
531     HDC ddc;
532     DWORD *masks;
533     UINT usage;
534
535     if (!(format->flags & WINED3DFMT_FLAG_GETDC))
536     {
537         WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
538         return WINED3DERR_INVALIDCALL;
539     }
540
541     switch (format->byte_count)
542     {
543         case 2:
544         case 4:
545             /* Allocate extra space to store the RGB bit masks. */
546             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
547             break;
548
549         case 3:
550             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
551             break;
552
553         default:
554             /* Allocate extra space for a palette. */
555             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
556                     sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
557             break;
558     }
559
560     if (!b_info)
561         return E_OUTOFMEMORY;
562
563         /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
564     * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
565     * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
566     * add an extra line to the dib section
567         */
568     GetSystemInfo(&sysInfo);
569     if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
570         extraline = 1;
571         TRACE("Adding an extra line to the dib section\n");
572     }
573
574     b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
575     /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
576     b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
577     b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
578     b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
579     b_info->bmiHeader.biPlanes = 1;
580     b_info->bmiHeader.biBitCount = format->byte_count * 8;
581
582     b_info->bmiHeader.biXPelsPerMeter = 0;
583     b_info->bmiHeader.biYPelsPerMeter = 0;
584     b_info->bmiHeader.biClrUsed = 0;
585     b_info->bmiHeader.biClrImportant = 0;
586
587     /* Get the bit masks */
588     masks = (DWORD *)b_info->bmiColors;
589     switch (This->resource.format->id)
590     {
591         case WINED3DFMT_B8G8R8_UNORM:
592             usage = DIB_RGB_COLORS;
593             b_info->bmiHeader.biCompression = BI_RGB;
594             break;
595
596         case WINED3DFMT_B5G5R5X1_UNORM:
597         case WINED3DFMT_B5G5R5A1_UNORM:
598         case WINED3DFMT_B4G4R4A4_UNORM:
599         case WINED3DFMT_B4G4R4X4_UNORM:
600         case WINED3DFMT_B2G3R3_UNORM:
601         case WINED3DFMT_B2G3R3A8_UNORM:
602         case WINED3DFMT_R10G10B10A2_UNORM:
603         case WINED3DFMT_R8G8B8A8_UNORM:
604         case WINED3DFMT_R8G8B8X8_UNORM:
605         case WINED3DFMT_B10G10R10A2_UNORM:
606         case WINED3DFMT_B5G6R5_UNORM:
607         case WINED3DFMT_R16G16B16A16_UNORM:
608             usage = 0;
609             b_info->bmiHeader.biCompression = BI_BITFIELDS;
610             masks[0] = format->red_mask;
611             masks[1] = format->green_mask;
612             masks[2] = format->blue_mask;
613             break;
614
615         default:
616             /* Don't know palette */
617             b_info->bmiHeader.biCompression = BI_RGB;
618             usage = 0;
619             break;
620     }
621
622     if (!(ddc = GetDC(0)))
623     {
624         HeapFree(GetProcessHeap(), 0, b_info);
625         return HRESULT_FROM_WIN32(GetLastError());
626     }
627
628     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);
629     This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
630     ReleaseDC(0, ddc);
631
632     if (!This->dib.DIBsection) {
633         ERR("CreateDIBSection failed!\n");
634         HeapFree(GetProcessHeap(), 0, b_info);
635         return HRESULT_FROM_WIN32(GetLastError());
636     }
637
638     TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
639     /* copy the existing surface to the dib section */
640     if(This->resource.allocatedMemory) {
641         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory,  This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
642     } else {
643         /* This is to make LockRect read the gl Texture although memory is allocated */
644         This->flags &= ~SFLAG_INSYSMEM;
645     }
646     This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
647
648     HeapFree(GetProcessHeap(), 0, b_info);
649
650     /* Now allocate a HDC */
651     This->hDC = CreateCompatibleDC(0);
652     This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
653     TRACE("using wined3d palette %p\n", This->palette);
654     SelectPalette(This->hDC,
655                   This->palette ? This->palette->hpal : 0,
656                   FALSE);
657
658     This->flags |= SFLAG_DIBSECTION;
659
660     HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
661     This->resource.heapMemory = NULL;
662
663     return WINED3D_OK;
664 }
665
666 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
667                               unsigned int w, unsigned int h)
668 {
669     unsigned int x, y;
670     const float *src_f;
671     unsigned short *dst_s;
672
673     TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
674     for(y = 0; y < h; y++) {
675         src_f = (const float *)(src + y * pitch_in);
676         dst_s = (unsigned short *) (dst + y * pitch_out);
677         for(x = 0; x < w; x++) {
678             dst_s[x] = float_32_to_16(src_f + x);
679         }
680     }
681 }
682
683 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
684         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
685 {
686     static const unsigned char convert_5to8[] =
687     {
688         0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
689         0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
690         0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
691         0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
692     };
693     static const unsigned char convert_6to8[] =
694     {
695         0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
696         0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
697         0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
698         0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
699         0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
700         0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
701         0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
702         0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
703     };
704     unsigned int x, y;
705
706     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
707
708     for (y = 0; y < h; ++y)
709     {
710         const WORD *src_line = (const WORD *)(src + y * pitch_in);
711         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
712         for (x = 0; x < w; ++x)
713         {
714             WORD pixel = src_line[x];
715             dst_line[x] = 0xff000000
716                     | convert_5to8[(pixel & 0xf800) >> 11] << 16
717                     | convert_6to8[(pixel & 0x07e0) >> 5] << 8
718                     | convert_5to8[(pixel & 0x001f)];
719         }
720     }
721 }
722
723 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
724         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
725 {
726     unsigned int x, y;
727
728     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
729
730     for (y = 0; y < h; ++y)
731     {
732         const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
733         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
734
735         for (x = 0; x < w; ++x)
736         {
737             dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
738         }
739     }
740 }
741
742 static inline BYTE cliptobyte(int x)
743 {
744     return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
745 }
746
747 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
748         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
749 {
750     unsigned int x, y;
751     int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
752
753     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
754
755     for (y = 0; y < h; ++y)
756     {
757         const BYTE *src_line = src + y * pitch_in;
758         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
759         for (x = 0; x < w; ++x)
760         {
761             /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
762              *     C = Y - 16; D = U - 128; E = V - 128;
763              *     R = cliptobyte((298 * C + 409 * E + 128) >> 8);
764              *     G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
765              *     B = cliptobyte((298 * C + 516 * D + 128) >> 8);
766              * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
767              * U and V are shared between the pixels.
768              */
769             if (!(x & 1))         /* for every even pixel, read new U and V */
770             {
771                 d = (int) src_line[1] - 128;
772                 e = (int) src_line[3] - 128;
773                 r2 = 409 * e + 128;
774                 g2 = - 100 * d - 208 * e + 128;
775                 b2 = 516 * d + 128;
776             }
777             c2 = 298 * ((int) src_line[0] - 16);
778             dst_line[x] = 0xff000000
779                 | cliptobyte((c2 + r2) >> 8) << 16    /* red   */
780                 | cliptobyte((c2 + g2) >> 8) << 8     /* green */
781                 | cliptobyte((c2 + b2) >> 8);         /* blue  */
782                 /* Scale RGB values to 0..255 range,
783                  * then clip them if still not in range (may be negative),
784                  * then shift them within DWORD if necessary.
785                  */
786             src_line += 2;
787         }
788     }
789 }
790
791 struct d3dfmt_convertor_desc
792 {
793     enum wined3d_format_id from, to;
794     void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
795 };
796
797 static const struct d3dfmt_convertor_desc convertors[] =
798 {
799     {WINED3DFMT_R32_FLOAT,      WINED3DFMT_R16_FLOAT,       convert_r32_float_r16_float},
800     {WINED3DFMT_B5G6R5_UNORM,   WINED3DFMT_B8G8R8X8_UNORM,  convert_r5g6b5_x8r8g8b8},
801     {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM,  convert_a8r8g8b8_x8r8g8b8},
802     {WINED3DFMT_YUY2,           WINED3DFMT_B8G8R8X8_UNORM,  convert_yuy2_x8r8g8b8},
803 };
804
805 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
806 {
807     unsigned int i;
808     for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
809         if(convertors[i].from == from && convertors[i].to == to) {
810             return &convertors[i];
811         }
812     }
813     return NULL;
814 }
815
816 /*****************************************************************************
817  * surface_convert_format
818  *
819  * Creates a duplicate of a surface in a different format. Is used by Blt to
820  * blit between surfaces with different formats
821  *
822  * Parameters
823  *  source: Source surface
824  *  fmt: Requested destination format
825  *
826  *****************************************************************************/
827 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
828 {
829     IWineD3DSurface *ret = NULL;
830     const struct d3dfmt_convertor_desc *conv;
831     WINED3DLOCKED_RECT lock_src, lock_dst;
832     HRESULT hr;
833
834     conv = find_convertor(source->resource.format->id, to_fmt);
835     if (!conv)
836     {
837         FIXME("Cannot find a conversion function from format %s to %s.\n",
838                 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
839         return NULL;
840     }
841
842     IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
843             source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard  */, 0 /* level */,
844             0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
845             0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
846             NULL /* parent */, &wined3d_null_parent_ops, &ret);
847     if(!ret) {
848         ERR("Failed to create a destination surface for conversion\n");
849         return NULL;
850     }
851
852     memset(&lock_src, 0, sizeof(lock_src));
853     memset(&lock_dst, 0, sizeof(lock_dst));
854
855     hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
856     if (FAILED(hr))
857     {
858         ERR("Failed to lock the source surface.\n");
859         IWineD3DSurface_Release(ret);
860         return NULL;
861     }
862     hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
863     if (FAILED(hr))
864     {
865         ERR("Failed to lock the dest surface\n");
866         IWineD3DSurface_Unmap((IWineD3DSurface *)source);
867         IWineD3DSurface_Release(ret);
868         return NULL;
869     }
870
871     conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
872                   source->currentDesc.Width, source->currentDesc.Height);
873
874     IWineD3DSurface_Unmap(ret);
875     IWineD3DSurface_Unmap((IWineD3DSurface *)source);
876
877     return (IWineD3DSurfaceImpl *) ret;
878 }
879
880 /*****************************************************************************
881  * _Blt_ColorFill
882  *
883  * Helper function that fills a memory area with a specific color
884  *
885  * Params:
886  *  buf: memory address to start filling at
887  *  width, height: Dimensions of the area to fill
888  *  bpp: Bit depth of the surface
889  *  lPitch: pitch of the surface
890  *  color: Color to fill with
891  *
892  *****************************************************************************/
893 static HRESULT
894         _Blt_ColorFill(BYTE *buf,
895                        int width, int height,
896                        int bpp, LONG lPitch,
897                        DWORD color)
898 {
899     int x, y;
900     LPBYTE first;
901
902     /* Do first row */
903
904 #define COLORFILL_ROW(type) \
905     { \
906     type *d = (type *) buf; \
907     for (x = 0; x < width; x++) \
908     d[x] = (type) color; \
909     break; \
910 }
911     switch(bpp)
912     {
913         case 1: COLORFILL_ROW(BYTE)
914                 case 2: COLORFILL_ROW(WORD)
915         case 3:
916         {
917             BYTE *d = buf;
918             for (x = 0; x < width; x++,d+=3)
919             {
920                 d[0] = (color    ) & 0xFF;
921                 d[1] = (color>> 8) & 0xFF;
922                 d[2] = (color>>16) & 0xFF;
923             }
924             break;
925         }
926         case 4: COLORFILL_ROW(DWORD)
927         default:
928             FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
929             return WINED3DERR_NOTAVAILABLE;
930     }
931
932 #undef COLORFILL_ROW
933
934     /* Now copy first row */
935     first = buf;
936     for (y = 1; y < height; y++)
937     {
938         buf += lPitch;
939         memcpy(buf, first, width * bpp);
940     }
941     return WINED3D_OK;
942 }
943
944 /*****************************************************************************
945  * IWineD3DSurface::Blt, SW emulation version
946  *
947  * Performs a blit to a surface, with or without a source surface.
948  * This is the main functionality of DirectDraw
949  *
950  * Params:
951  *  DestRect: Destination rectangle to write to
952  *  src_surface: Source surface, can be NULL
953  *  SrcRect: Source rectangle
954  *****************************************************************************/
955 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
956         const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
957 {
958     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
959     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
960     RECT        xdst,xsrc;
961     HRESULT     ret = WINED3D_OK;
962     WINED3DLOCKED_RECT  dlock, slock;
963     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
964     const struct wined3d_format *sEntry, *dEntry;
965     int x, y;
966     const BYTE *sbuf;
967     BYTE *dbuf;
968
969     TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
970             iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
971             flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
972
973     if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
974     {
975         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
976         return WINEDDERR_SURFACEBUSY;
977     }
978
979     /* First check for the validity of source / destination rectangles.
980      * This was verified using a test application + by MSDN. */
981
982     if (SrcRect)
983     {
984         if (src)
985         {
986             if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
987                     || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
988                     || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
989                     || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
990                     || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
991             {
992                 WARN("Application gave us bad source rectangle for Blt.\n");
993                 return WINEDDERR_INVALIDRECT;
994             }
995
996             if (!SrcRect->right || !SrcRect->bottom
997                     || SrcRect->left == (int)src->currentDesc.Width
998                     || SrcRect->top == (int)src->currentDesc.Height)
999             {
1000                 TRACE("Nothing to be done.\n");
1001                 return WINED3D_OK;
1002             }
1003         }
1004
1005         xsrc = *SrcRect;
1006     }
1007     else if (src)
1008     {
1009         xsrc.left = 0;
1010         xsrc.top = 0;
1011         xsrc.right = src->currentDesc.Width;
1012         xsrc.bottom = src->currentDesc.Height;
1013     }
1014     else
1015     {
1016         memset(&xsrc, 0, sizeof(xsrc));
1017     }
1018
1019     if (DestRect)
1020     {
1021         /* For the Destination rect, it can be out of bounds on the condition
1022          * that a clipper is set for the given surface. */
1023         if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1024                 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
1025                 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1026                 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1027                 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1028         {
1029             WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1030             return WINEDDERR_INVALIDRECT;
1031         }
1032
1033         if (DestRect->right <= 0 || DestRect->bottom <= 0
1034                 || DestRect->left >= (int)This->currentDesc.Width
1035                 || DestRect->top >= (int)This->currentDesc.Height)
1036         {
1037             TRACE("Nothing to be done.\n");
1038             return WINED3D_OK;
1039         }
1040
1041         if (!src)
1042         {
1043             RECT full_rect;
1044
1045             full_rect.left = 0;
1046             full_rect.top = 0;
1047             full_rect.right = This->currentDesc.Width;
1048             full_rect.bottom = This->currentDesc.Height;
1049             IntersectRect(&xdst, &full_rect, DestRect);
1050         }
1051         else
1052         {
1053             BOOL clip_horiz, clip_vert;
1054
1055             xdst = *DestRect;
1056             clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1057             clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1058
1059             if (clip_vert || clip_horiz)
1060             {
1061                 /* Now check if this is a special case or not... */
1062                 if ((flags & WINEDDBLT_DDFX)
1063                         || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1064                         || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1065                 {
1066                     WARN("Out of screen rectangle in special case. Not handled right now.\n");
1067                     return WINED3D_OK;
1068                 }
1069
1070                 if (clip_horiz)
1071                 {
1072                     if (xdst.left < 0)
1073                     {
1074                         xsrc.left -= xdst.left;
1075                         xdst.left = 0;
1076                     }
1077                     if (xdst.right > This->currentDesc.Width)
1078                     {
1079                         xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1080                         xdst.right = (int)This->currentDesc.Width;
1081                     }
1082                 }
1083
1084                 if (clip_vert)
1085                 {
1086                     if (xdst.top < 0)
1087                     {
1088                         xsrc.top -= xdst.top;
1089                         xdst.top = 0;
1090                     }
1091                     if (xdst.bottom > This->currentDesc.Height)
1092                     {
1093                         xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1094                         xdst.bottom = (int)This->currentDesc.Height;
1095                     }
1096                 }
1097
1098                 /* And check if after clipping something is still to be done... */
1099                 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1100                         || (xdst.left >= (int)This->currentDesc.Width)
1101                         || (xdst.top >= (int)This->currentDesc.Height)
1102                         || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1103                         || (xsrc.left >= (int)src->currentDesc.Width)
1104                         || (xsrc.top >= (int)src->currentDesc.Height))
1105                 {
1106                     TRACE("Nothing to be done after clipping.\n");
1107                     return WINED3D_OK;
1108                 }
1109             }
1110         }
1111     }
1112     else
1113     {
1114         xdst.left = 0;
1115         xdst.top = 0;
1116         xdst.right = This->currentDesc.Width;
1117         xdst.bottom = This->currentDesc.Height;
1118     }
1119
1120     if (src == This)
1121     {
1122         IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1123         slock = dlock;
1124         sEntry = This->resource.format;
1125         dEntry = sEntry;
1126     }
1127     else
1128     {
1129         dEntry = This->resource.format;
1130         if (src)
1131         {
1132             if (This->resource.format->id != src->resource.format->id)
1133             {
1134                 src = surface_convert_format(src, dEntry->id);
1135                 if (!src)
1136                 {
1137                     /* The conv function writes a FIXME */
1138                     WARN("Cannot convert source surface format to dest format\n");
1139                     goto release;
1140                 }
1141             }
1142             IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1143             sEntry = src->resource.format;
1144         }
1145         else
1146         {
1147             sEntry = dEntry;
1148         }
1149         if (DestRect)
1150             IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1151         else
1152             IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1153     }
1154
1155     if (!DDBltFx || !(DDBltFx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
1156
1157     if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_FOURCC)
1158     {
1159         if (!DestRect || src == This)
1160         {
1161             memcpy(dlock.pBits, slock.pBits, This->resource.size);
1162             goto release;
1163         }
1164     }
1165
1166     bpp = This->resource.format->byte_count;
1167     srcheight = xsrc.bottom - xsrc.top;
1168     srcwidth = xsrc.right - xsrc.left;
1169     dstheight = xdst.bottom - xdst.top;
1170     dstwidth = xdst.right - xdst.left;
1171     width = (xdst.right - xdst.left) * bpp;
1172
1173     if (DestRect && src != This)
1174         dbuf = dlock.pBits;
1175     else
1176         dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1177
1178     if (flags & WINEDDBLT_WAIT)
1179     {
1180         flags &= ~WINEDDBLT_WAIT;
1181     }
1182     if (flags & WINEDDBLT_ASYNC)
1183     {
1184         static BOOL displayed = FALSE;
1185         if (!displayed)
1186             FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1187         displayed = TRUE;
1188         flags &= ~WINEDDBLT_ASYNC;
1189     }
1190     if (flags & WINEDDBLT_DONOTWAIT)
1191     {
1192         /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1193         static BOOL displayed = FALSE;
1194         if (!displayed)
1195             FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1196         displayed = TRUE;
1197         flags &= ~WINEDDBLT_DONOTWAIT;
1198     }
1199
1200     /* First, all the 'source-less' blits */
1201     if (flags & WINEDDBLT_COLORFILL)
1202     {
1203         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1204                              dlock.Pitch, DDBltFx->u5.dwFillColor);
1205         flags &= ~WINEDDBLT_COLORFILL;
1206     }
1207
1208     if (flags & WINEDDBLT_DEPTHFILL)
1209     {
1210         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1211     }
1212     if (flags & WINEDDBLT_ROP)
1213     {
1214         /* Catch some degenerate cases here */
1215         switch(DDBltFx->dwROP)
1216         {
1217             case BLACKNESS:
1218                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1219                 break;
1220                 case 0xAA0029: /* No-op */
1221                     break;
1222             case WHITENESS:
1223                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1224                 break;
1225                 case SRCCOPY: /* well, we do that below ? */
1226                     break;
1227             default:
1228                 FIXME("Unsupported raster op: %08x  Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1229                 goto error;
1230         }
1231         flags &= ~WINEDDBLT_ROP;
1232     }
1233     if (flags & WINEDDBLT_DDROPS)
1234     {
1235         FIXME("\tDdraw Raster Ops: %08x  Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1236     }
1237     /* Now the 'with source' blits */
1238     if (src)
1239     {
1240         const BYTE *sbase;
1241         int sx, xinc, sy, yinc;
1242
1243         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1244             goto release;
1245
1246         if (Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT
1247                 && (srcwidth != dstwidth || srcheight != dstheight))
1248         {
1249             /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1250             FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter));
1251         }
1252
1253         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1254         xinc = (srcwidth << 16) / dstwidth;
1255         yinc = (srcheight << 16) / dstheight;
1256
1257         if (!flags)
1258         {
1259             /* No effects, we can cheat here */
1260             if (dstwidth == srcwidth)
1261             {
1262                 if (dstheight == srcheight)
1263                 {
1264                     /* No stretching in either direction. This needs to be as
1265                     * fast as possible */
1266                     sbuf = sbase;
1267
1268                     /* check for overlapping surfaces */
1269                     if (src != This || xdst.top < xsrc.top ||
1270                         xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1271                     {
1272                         /* no overlap, or dst above src, so copy from top downwards */
1273                         for (y = 0; y < dstheight; y++)
1274                         {
1275                             memcpy(dbuf, sbuf, width);
1276                             sbuf += slock.Pitch;
1277                             dbuf += dlock.Pitch;
1278                         }
1279                     }
1280                     else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
1281                     {
1282                         sbuf += (slock.Pitch*dstheight);
1283                         dbuf += (dlock.Pitch*dstheight);
1284                         for (y = 0; y < dstheight; y++)
1285                         {
1286                             sbuf -= slock.Pitch;
1287                             dbuf -= dlock.Pitch;
1288                             memcpy(dbuf, sbuf, width);
1289                         }
1290                     }
1291                     else /* src and dst overlapping on the same line, use memmove */
1292                     {
1293                         for (y = 0; y < dstheight; y++)
1294                         {
1295                             memmove(dbuf, sbuf, width);
1296                             sbuf += slock.Pitch;
1297                             dbuf += dlock.Pitch;
1298                         }
1299                     }
1300                 } else {
1301                     /* Stretching in Y direction only */
1302                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1303                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1304                         memcpy(dbuf, sbuf, width);
1305                         dbuf += dlock.Pitch;
1306                     }
1307                 }
1308             }
1309             else
1310             {
1311                 /* Stretching in X direction */
1312                 int last_sy = -1;
1313                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1314                 {
1315                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1316
1317                     if ((sy >> 16) == (last_sy >> 16))
1318                     {
1319                         /* this sourcerow is the same as last sourcerow -
1320                         * copy already stretched row
1321                         */
1322                         memcpy(dbuf, dbuf - dlock.Pitch, width);
1323                     }
1324                     else
1325                     {
1326 #define STRETCH_ROW(type) { \
1327                         const type *s = (const type *)sbuf; \
1328                         type *d = (type *)dbuf; \
1329                         for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1330                         d[x] = s[sx >> 16]; \
1331                         break; }
1332
1333                         switch(bpp)
1334                         {
1335                             case 1: STRETCH_ROW(BYTE)
1336                                     case 2: STRETCH_ROW(WORD)
1337                                             case 4: STRETCH_ROW(DWORD)
1338                             case 3:
1339                             {
1340                                 const BYTE *s;
1341                                 BYTE *d = dbuf;
1342                                 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1343                                 {
1344                                     DWORD pixel;
1345
1346                                     s = sbuf+3*(sx>>16);
1347                                     pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1348                                     d[0] = (pixel    )&0xff;
1349                                     d[1] = (pixel>> 8)&0xff;
1350                                     d[2] = (pixel>>16)&0xff;
1351                                     d+=3;
1352                                 }
1353                                 break;
1354                             }
1355                             default:
1356                                 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1357                                 ret = WINED3DERR_NOTAVAILABLE;
1358                                 goto error;
1359                         }
1360 #undef STRETCH_ROW
1361                     }
1362                     dbuf += dlock.Pitch;
1363                     last_sy = sy;
1364                 }
1365             }
1366         }
1367         else
1368         {
1369             LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1370             DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1371             DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1372             if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1373             {
1374                 /* The color keying flags are checked for correctness in ddraw */
1375                 if (flags & WINEDDBLT_KEYSRC)
1376                 {
1377                     keylow  = src->SrcBltCKey.dwColorSpaceLowValue;
1378                     keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1379                 }
1380                 else  if (flags & WINEDDBLT_KEYSRCOVERRIDE)
1381                 {
1382                     keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1383                     keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1384                 }
1385
1386                 if (flags & WINEDDBLT_KEYDEST)
1387                 {
1388                     /* Destination color keys are taken from the source surface ! */
1389                     destkeylow  = src->DestBltCKey.dwColorSpaceLowValue;
1390                     destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1391                 }
1392                 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
1393                 {
1394                     destkeylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1395                     destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1396                 }
1397
1398                 if(bpp == 1)
1399                 {
1400                     keymask = 0xff;
1401                 }
1402                 else
1403                 {
1404                     keymask = sEntry->red_mask
1405                             | sEntry->green_mask
1406                             | sEntry->blue_mask;
1407                 }
1408                 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1409             }
1410
1411             if (flags & WINEDDBLT_DDFX)
1412             {
1413                 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1414                 LONG tmpxy;
1415                 dTopLeft     = dbuf;
1416                 dTopRight    = dbuf+((dstwidth-1)*bpp);
1417                 dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
1418                 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1419
1420                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1421                 {
1422                     /* I don't think we need to do anything about this flag */
1423                     WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1424                 }
1425                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1426                 {
1427                     tmp          = dTopRight;
1428                     dTopRight    = dTopLeft;
1429                     dTopLeft     = tmp;
1430                     tmp          = dBottomRight;
1431                     dBottomRight = dBottomLeft;
1432                     dBottomLeft  = tmp;
1433                     dstxinc = dstxinc *-1;
1434                 }
1435                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1436                 {
1437                     tmp          = dTopLeft;
1438                     dTopLeft     = dBottomLeft;
1439                     dBottomLeft  = tmp;
1440                     tmp          = dTopRight;
1441                     dTopRight    = dBottomRight;
1442                     dBottomRight = tmp;
1443                     dstyinc = dstyinc *-1;
1444                 }
1445                 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1446                 {
1447                     /* I don't think we need to do anything about this flag */
1448                     WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1449                 }
1450                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1451                 {
1452                     tmp          = dBottomRight;
1453                     dBottomRight = dTopLeft;
1454                     dTopLeft     = tmp;
1455                     tmp          = dBottomLeft;
1456                     dBottomLeft  = dTopRight;
1457                     dTopRight    = tmp;
1458                     dstxinc = dstxinc * -1;
1459                     dstyinc = dstyinc * -1;
1460                 }
1461                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1462                 {
1463                     tmp          = dTopLeft;
1464                     dTopLeft     = dBottomLeft;
1465                     dBottomLeft  = dBottomRight;
1466                     dBottomRight = dTopRight;
1467                     dTopRight    = tmp;
1468                     tmpxy   = dstxinc;
1469                     dstxinc = dstyinc;
1470                     dstyinc = tmpxy;
1471                     dstxinc = dstxinc * -1;
1472                 }
1473                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1474                 {
1475                     tmp          = dTopLeft;
1476                     dTopLeft     = dTopRight;
1477                     dTopRight    = dBottomRight;
1478                     dBottomRight = dBottomLeft;
1479                     dBottomLeft  = tmp;
1480                     tmpxy   = dstxinc;
1481                     dstxinc = dstyinc;
1482                     dstyinc = tmpxy;
1483                     dstyinc = dstyinc * -1;
1484                 }
1485                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1486                 {
1487                     /* I don't think we need to do anything about this flag */
1488                     WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1489                 }
1490                 dbuf = dTopLeft;
1491                 flags &= ~(WINEDDBLT_DDFX);
1492             }
1493
1494 #define COPY_COLORKEY_FX(type) { \
1495             const type *s; \
1496             type *d = (type *)dbuf, *dx, tmp; \
1497             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1498             s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1499             dx = d; \
1500             for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1501             tmp = s[sx >> 16]; \
1502             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1503             ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1504             dx[0] = tmp; \
1505         } \
1506             dx = (type*)(((LPBYTE)dx)+dstxinc); \
1507         } \
1508             d = (type*)(((LPBYTE)d)+dstyinc); \
1509         } \
1510             break; }
1511
1512             switch (bpp) {
1513                 case 1: COPY_COLORKEY_FX(BYTE)
1514                         case 2: COPY_COLORKEY_FX(WORD)
1515                                 case 4: COPY_COLORKEY_FX(DWORD)
1516                 case 3:
1517                 {
1518                     const BYTE *s;
1519                     BYTE *d = dbuf, *dx;
1520                     for (y = sy = 0; y < dstheight; y++, sy += yinc)
1521                     {
1522                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1523                         dx = d;
1524                         for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1525                         {
1526                             DWORD pixel, dpixel = 0;
1527                             s = sbuf+3*(sx>>16);
1528                             pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1529                             dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1530                             if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1531                                   ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1532                             {
1533                                 dx[0] = (pixel    )&0xff;
1534                                 dx[1] = (pixel>> 8)&0xff;
1535                                 dx[2] = (pixel>>16)&0xff;
1536                             }
1537                             dx+= dstxinc;
1538                         }
1539                         d += dstyinc;
1540                     }
1541                     break;
1542                 }
1543                 default:
1544                     FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1545                           (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1546                     ret = WINED3DERR_NOTAVAILABLE;
1547                     goto error;
1548 #undef COPY_COLORKEY_FX
1549             }
1550         }
1551     }
1552
1553 error:
1554     if (flags && FIXME_ON(d3d_surface))
1555     {
1556         FIXME("\tUnsupported flags: %#x.\n", flags);
1557     }
1558
1559 release:
1560     IWineD3DSurface_Unmap(iface);
1561     if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1562     /* Release the converted surface if any */
1563     if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1564     return ret;
1565 }
1566
1567 /*****************************************************************************
1568  * IWineD3DSurface::BltFast, SW emulation version
1569  *
1570  * This is the software implementation of BltFast, as used by GDI surfaces
1571  * and as a fallback for OpenGL surfaces. This code is taken from the old
1572  * DirectDraw code, and was originally written by TransGaming.
1573  *
1574  * Params:
1575  *  dstx:
1576  *  dsty:
1577  *  src_surface: Source surface to copy from
1578  *  rsrc: Source rectangle
1579  *  trans: Some flags
1580  *
1581  * Returns:
1582  *  WINED3D_OK on success
1583  *
1584  *****************************************************************************/
1585 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1586         IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1587 {
1588     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1589     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1590
1591     int                 bpp, w, h, x, y;
1592     WINED3DLOCKED_RECT  dlock,slock;
1593     HRESULT             ret = WINED3D_OK;
1594     RECT                rsrc2;
1595     RECT                lock_src, lock_dst, lock_union;
1596     const BYTE          *sbuf;
1597     BYTE                *dbuf;
1598     const struct wined3d_format *sEntry, *dEntry;
1599
1600     TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1601             iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1602
1603     if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
1604     {
1605         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1606         return WINEDDERR_SURFACEBUSY;
1607     }
1608
1609     if (!rsrc)
1610     {
1611         WARN("rsrc is NULL!\n");
1612         rsrc2.left = 0;
1613         rsrc2.top = 0;
1614         rsrc2.right = src->currentDesc.Width;
1615         rsrc2.bottom = src->currentDesc.Height;
1616         rsrc = &rsrc2;
1617     }
1618
1619     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1620     if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1621             || (rsrc->top   > src->currentDesc.Height) || (rsrc->top    < 0)
1622             || (rsrc->left  > src->currentDesc.Width)  || (rsrc->left   < 0)
1623             || (rsrc->right > src->currentDesc.Width)  || (rsrc->right  < 0)
1624             || (rsrc->right < rsrc->left)              || (rsrc->bottom < rsrc->top))
1625     {
1626         WARN("Application gave us bad source rectangle for BltFast.\n");
1627         return WINEDDERR_INVALIDRECT;
1628     }
1629
1630     h = rsrc->bottom - rsrc->top;
1631     if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1632     if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1633     if (h <= 0) return WINEDDERR_INVALIDRECT;
1634
1635     w = rsrc->right - rsrc->left;
1636     if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1637     if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1638     if (w <= 0) 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->currentDesc.Width;
1859         This->lockedRect.bottom = This->currentDesc.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 }