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