msi/tests: Prevent a popup on Windows NT.
[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_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
827     if(FAILED(hr)) {
828         ERR("Failed to lock the source surface\n");
829         IWineD3DSurface_Release(ret);
830         return NULL;
831     }
832     hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
833     if(FAILED(hr)) {
834         ERR("Failed to lock the dest surface\n");
835         IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
836         IWineD3DSurface_Release(ret);
837         return NULL;
838     }
839
840     conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
841                   source->currentDesc.Width, source->currentDesc.Height);
842
843     IWineD3DSurface_UnlockRect(ret);
844     IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
845
846     return (IWineD3DSurfaceImpl *) ret;
847 }
848
849 /*****************************************************************************
850  * _Blt_ColorFill
851  *
852  * Helper function that fills a memory area with a specific color
853  *
854  * Params:
855  *  buf: memory address to start filling at
856  *  width, height: Dimensions of the area to fill
857  *  bpp: Bit depth of the surface
858  *  lPitch: pitch of the surface
859  *  color: Color to fill with
860  *
861  *****************************************************************************/
862 static HRESULT
863         _Blt_ColorFill(BYTE *buf,
864                        int width, int height,
865                        int bpp, LONG lPitch,
866                        DWORD color)
867 {
868     int x, y;
869     LPBYTE first;
870
871     /* Do first row */
872
873 #define COLORFILL_ROW(type) \
874     { \
875     type *d = (type *) buf; \
876     for (x = 0; x < width; x++) \
877     d[x] = (type) color; \
878     break; \
879 }
880     switch(bpp)
881     {
882         case 1: COLORFILL_ROW(BYTE)
883                 case 2: COLORFILL_ROW(WORD)
884         case 3:
885         {
886             BYTE *d = buf;
887             for (x = 0; x < width; x++,d+=3)
888             {
889                 d[0] = (color    ) & 0xFF;
890                 d[1] = (color>> 8) & 0xFF;
891                 d[2] = (color>>16) & 0xFF;
892             }
893             break;
894         }
895         case 4: COLORFILL_ROW(DWORD)
896         default:
897             FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
898             return WINED3DERR_NOTAVAILABLE;
899     }
900
901 #undef COLORFILL_ROW
902
903     /* Now copy first row */
904     first = buf;
905     for (y = 1; y < height; y++)
906     {
907         buf += lPitch;
908         memcpy(buf, first, width * bpp);
909     }
910     return WINED3D_OK;
911 }
912
913 /*****************************************************************************
914  * IWineD3DSurface::Blt, SW emulation version
915  *
916  * Performs a blit to a surface, with or without a source surface.
917  * This is the main functionality of DirectDraw
918  *
919  * Params:
920  *  DestRect: Destination rectangle to write to
921  *  src_surface: Source surface, can be NULL
922  *  SrcRect: Source rectangle
923  *****************************************************************************/
924 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
925         const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
926 {
927     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
928     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
929     RECT        xdst,xsrc;
930     HRESULT     ret = WINED3D_OK;
931     WINED3DLOCKED_RECT  dlock, slock;
932     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
933     const struct wined3d_format *sEntry, *dEntry;
934     int x, y;
935     const BYTE *sbuf;
936     BYTE *dbuf;
937
938     TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
939             iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
940             Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
941
942     if ((This->Flags & SFLAG_LOCKED) || (src && (src->Flags & SFLAG_LOCKED)))
943     {
944         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
945         return WINEDDERR_SURFACEBUSY;
946     }
947
948     if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
949         /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
950         FIXME("Filters not supported in software blit\n");
951     }
952
953     /* First check for the validity of source / destination rectangles.
954      * This was verified using a test application + by MSDN. */
955
956     if (SrcRect)
957     {
958         if (src)
959         {
960             if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
961                     || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
962                     || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
963                     || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
964                     || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
965             {
966                 WARN("Application gave us bad source rectangle for Blt.\n");
967                 return WINEDDERR_INVALIDRECT;
968             }
969
970             if (!SrcRect->right || !SrcRect->bottom
971                     || SrcRect->left == (int)src->currentDesc.Width
972                     || SrcRect->top == (int)src->currentDesc.Height)
973             {
974                 TRACE("Nothing to be done.\n");
975                 return WINED3D_OK;
976             }
977         }
978
979         xsrc = *SrcRect;
980     }
981     else if (src)
982     {
983         xsrc.left = 0;
984         xsrc.top = 0;
985         xsrc.right = src->currentDesc.Width;
986         xsrc.bottom = src->currentDesc.Height;
987     }
988     else
989     {
990         memset(&xsrc, 0, sizeof(xsrc));
991     }
992
993     if (DestRect)
994     {
995         /* For the Destination rect, it can be out of bounds on the condition
996          * that a clipper is set for the given surface. */
997         if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
998                 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
999                 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1000                 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1001                 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1002         {
1003             WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1004             return WINEDDERR_INVALIDRECT;
1005         }
1006
1007         if (DestRect->right <= 0 || DestRect->bottom <= 0
1008                 || DestRect->left >= (int)This->currentDesc.Width
1009                 || DestRect->top >= (int)This->currentDesc.Height)
1010         {
1011             TRACE("Nothing to be done.\n");
1012             return WINED3D_OK;
1013         }
1014
1015         if (!src)
1016         {
1017             RECT full_rect;
1018
1019             full_rect.left = 0;
1020             full_rect.top = 0;
1021             full_rect.right = This->currentDesc.Width;
1022             full_rect.bottom = This->currentDesc.Height;
1023             IntersectRect(&xdst, &full_rect, DestRect);
1024         }
1025         else
1026         {
1027             BOOL clip_horiz, clip_vert;
1028
1029             xdst = *DestRect;
1030             clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1031             clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1032
1033             if (clip_vert || clip_horiz)
1034             {
1035                 /* Now check if this is a special case or not... */
1036                 if ((Flags & WINEDDBLT_DDFX)
1037                         || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1038                         || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1039                 {
1040                     WARN("Out of screen rectangle in special case. Not handled right now.\n");
1041                     return WINED3D_OK;
1042                 }
1043
1044                 if (clip_horiz)
1045                 {
1046                     if (xdst.left < 0)
1047                     {
1048                         xsrc.left -= xdst.left;
1049                         xdst.left = 0;
1050                     }
1051                     if (xdst.right > This->currentDesc.Width)
1052                     {
1053                         xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1054                         xdst.right = (int)This->currentDesc.Width;
1055                     }
1056                 }
1057
1058                 if (clip_vert)
1059                 {
1060                     if (xdst.top < 0)
1061                     {
1062                         xsrc.top -= xdst.top;
1063                         xdst.top = 0;
1064                     }
1065                     if (xdst.bottom > This->currentDesc.Height)
1066                     {
1067                         xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1068                         xdst.bottom = (int)This->currentDesc.Height;
1069                     }
1070                 }
1071
1072                 /* And check if after clipping something is still to be done... */
1073                 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1074                         || (xdst.left >= (int)This->currentDesc.Width)
1075                         || (xdst.top >= (int)This->currentDesc.Height)
1076                         || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1077                         || (xsrc.left >= (int)src->currentDesc.Width)
1078                         || (xsrc.top >= (int)src->currentDesc.Height))
1079                 {
1080                     TRACE("Nothing to be done after clipping.\n");
1081                     return WINED3D_OK;
1082                 }
1083             }
1084         }
1085     }
1086     else
1087     {
1088         xdst.left = 0;
1089         xdst.top = 0;
1090         xdst.right = This->currentDesc.Width;
1091         xdst.bottom = This->currentDesc.Height;
1092     }
1093
1094     if (src == This)
1095     {
1096         IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1097         slock = dlock;
1098         sEntry = This->resource.format;
1099         dEntry = sEntry;
1100     }
1101     else
1102     {
1103         dEntry = This->resource.format;
1104         if (src)
1105         {
1106             if (This->resource.format->id != src->resource.format->id)
1107             {
1108                 src = surface_convert_format(src, dEntry->id);
1109                 if (!src)
1110                 {
1111                     /* The conv function writes a FIXME */
1112                     WARN("Cannot convert source surface format to dest format\n");
1113                     goto release;
1114                 }
1115             }
1116             IWineD3DSurface_LockRect((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1117             sEntry = src->resource.format;
1118         }
1119         else
1120         {
1121             sEntry = dEntry;
1122         }
1123         if (DestRect)
1124             IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1125         else
1126             IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1127     }
1128
1129     if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1130
1131     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1132     {
1133         if (!DestRect || src == This)
1134         {
1135             memcpy(dlock.pBits, slock.pBits, This->resource.size);
1136             goto release;
1137         }
1138     }
1139
1140     bpp = This->resource.format->byte_count;
1141     srcheight = xsrc.bottom - xsrc.top;
1142     srcwidth = xsrc.right - xsrc.left;
1143     dstheight = xdst.bottom - xdst.top;
1144     dstwidth = xdst.right - xdst.left;
1145     width = (xdst.right - xdst.left) * bpp;
1146
1147     if (DestRect && src != This)
1148         dbuf = dlock.pBits;
1149     else
1150         dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1151
1152     if (Flags & WINEDDBLT_WAIT)
1153     {
1154         Flags &= ~WINEDDBLT_WAIT;
1155     }
1156     if (Flags & WINEDDBLT_ASYNC)
1157     {
1158         static BOOL displayed = FALSE;
1159         if (!displayed)
1160             FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1161         displayed = TRUE;
1162         Flags &= ~WINEDDBLT_ASYNC;
1163     }
1164     if (Flags & WINEDDBLT_DONOTWAIT)
1165     {
1166         /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1167         static BOOL displayed = FALSE;
1168         if (!displayed)
1169             FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1170         displayed = TRUE;
1171         Flags &= ~WINEDDBLT_DONOTWAIT;
1172     }
1173
1174     /* First, all the 'source-less' blits */
1175     if (Flags & WINEDDBLT_COLORFILL)
1176     {
1177         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1178                              dlock.Pitch, DDBltFx->u5.dwFillColor);
1179         Flags &= ~WINEDDBLT_COLORFILL;
1180     }
1181
1182     if (Flags & WINEDDBLT_DEPTHFILL)
1183     {
1184         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1185     }
1186     if (Flags & WINEDDBLT_ROP)
1187     {
1188         /* Catch some degenerate cases here */
1189         switch(DDBltFx->dwROP)
1190         {
1191             case BLACKNESS:
1192                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1193                 break;
1194                 case 0xAA0029: /* No-op */
1195                     break;
1196             case WHITENESS:
1197                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1198                 break;
1199                 case SRCCOPY: /* well, we do that below ? */
1200                     break;
1201             default:
1202                 FIXME("Unsupported raster op: %08x  Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1203                 goto error;
1204         }
1205         Flags &= ~WINEDDBLT_ROP;
1206     }
1207     if (Flags & WINEDDBLT_DDROPS)
1208     {
1209         FIXME("\tDdraw Raster Ops: %08x  Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1210     }
1211     /* Now the 'with source' blits */
1212     if (src)
1213     {
1214         const BYTE *sbase;
1215         int sx, xinc, sy, yinc;
1216
1217         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1218             goto release;
1219         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1220         xinc = (srcwidth << 16) / dstwidth;
1221         yinc = (srcheight << 16) / dstheight;
1222
1223         if (!Flags)
1224         {
1225             /* No effects, we can cheat here */
1226             if (dstwidth == srcwidth)
1227             {
1228                 if (dstheight == srcheight)
1229                 {
1230                     /* No stretching in either direction. This needs to be as
1231                     * fast as possible */
1232                     sbuf = sbase;
1233
1234                     /* check for overlapping surfaces */
1235                     if (src != This || xdst.top < xsrc.top ||
1236                         xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1237                     {
1238                         /* no overlap, or dst above src, so copy from top downwards */
1239                         for (y = 0; y < dstheight; y++)
1240                         {
1241                             memcpy(dbuf, sbuf, width);
1242                             sbuf += slock.Pitch;
1243                             dbuf += dlock.Pitch;
1244                         }
1245                     }
1246                     else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
1247                     {
1248                         sbuf += (slock.Pitch*dstheight);
1249                         dbuf += (dlock.Pitch*dstheight);
1250                         for (y = 0; y < dstheight; y++)
1251                         {
1252                             sbuf -= slock.Pitch;
1253                             dbuf -= dlock.Pitch;
1254                             memcpy(dbuf, sbuf, width);
1255                         }
1256                     }
1257                     else /* src and dst overlapping on the same line, use memmove */
1258                     {
1259                         for (y = 0; y < dstheight; y++)
1260                         {
1261                             memmove(dbuf, sbuf, width);
1262                             sbuf += slock.Pitch;
1263                             dbuf += dlock.Pitch;
1264                         }
1265                     }
1266                 } else {
1267                     /* Stretching in Y direction only */
1268                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1269                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1270                         memcpy(dbuf, sbuf, width);
1271                         dbuf += dlock.Pitch;
1272                     }
1273                 }
1274             }
1275             else
1276             {
1277                 /* Stretching in X direction */
1278                 int last_sy = -1;
1279                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1280                 {
1281                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1282
1283                     if ((sy >> 16) == (last_sy >> 16))
1284                     {
1285                         /* this sourcerow is the same as last sourcerow -
1286                         * copy already stretched row
1287                         */
1288                         memcpy(dbuf, dbuf - dlock.Pitch, width);
1289                     }
1290                     else
1291                     {
1292 #define STRETCH_ROW(type) { \
1293                         const type *s = (const type *)sbuf; \
1294                         type *d = (type *)dbuf; \
1295                         for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1296                         d[x] = s[sx >> 16]; \
1297                         break; }
1298
1299                         switch(bpp)
1300                         {
1301                             case 1: STRETCH_ROW(BYTE)
1302                                     case 2: STRETCH_ROW(WORD)
1303                                             case 4: STRETCH_ROW(DWORD)
1304                             case 3:
1305                             {
1306                                 const BYTE *s;
1307                                 BYTE *d = dbuf;
1308                                 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1309                                 {
1310                                     DWORD pixel;
1311
1312                                     s = sbuf+3*(sx>>16);
1313                                     pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1314                                     d[0] = (pixel    )&0xff;
1315                                     d[1] = (pixel>> 8)&0xff;
1316                                     d[2] = (pixel>>16)&0xff;
1317                                     d+=3;
1318                                 }
1319                                 break;
1320                             }
1321                             default:
1322                                 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1323                                 ret = WINED3DERR_NOTAVAILABLE;
1324                                 goto error;
1325                         }
1326 #undef STRETCH_ROW
1327                     }
1328                     dbuf += dlock.Pitch;
1329                     last_sy = sy;
1330                 }
1331             }
1332         }
1333         else
1334         {
1335             LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1336             DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1337             DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1338             if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1339             {
1340                 /* The color keying flags are checked for correctness in ddraw */
1341                 if (Flags & WINEDDBLT_KEYSRC)
1342                 {
1343                     keylow  = src->SrcBltCKey.dwColorSpaceLowValue;
1344                     keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1345                 }
1346                 else  if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1347                 {
1348                     keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1349                     keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1350                 }
1351
1352                 if (Flags & WINEDDBLT_KEYDEST)
1353                 {
1354                     /* Destination color keys are taken from the source surface ! */
1355                     destkeylow  = src->DestBltCKey.dwColorSpaceLowValue;
1356                     destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1357                 }
1358                 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1359                 {
1360                     destkeylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1361                     destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1362                 }
1363
1364                 if(bpp == 1)
1365                 {
1366                     keymask = 0xff;
1367                 }
1368                 else
1369                 {
1370                     keymask = sEntry->red_mask
1371                             | sEntry->green_mask
1372                             | sEntry->blue_mask;
1373                 }
1374                 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1375             }
1376
1377             if (Flags & WINEDDBLT_DDFX)
1378             {
1379                 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1380                 LONG tmpxy;
1381                 dTopLeft     = dbuf;
1382                 dTopRight    = dbuf+((dstwidth-1)*bpp);
1383                 dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
1384                 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1385
1386                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1387                 {
1388                     /* I don't think we need to do anything about this flag */
1389                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1390                 }
1391                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1392                 {
1393                     tmp          = dTopRight;
1394                     dTopRight    = dTopLeft;
1395                     dTopLeft     = tmp;
1396                     tmp          = dBottomRight;
1397                     dBottomRight = dBottomLeft;
1398                     dBottomLeft  = tmp;
1399                     dstxinc = dstxinc *-1;
1400                 }
1401                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1402                 {
1403                     tmp          = dTopLeft;
1404                     dTopLeft     = dBottomLeft;
1405                     dBottomLeft  = tmp;
1406                     tmp          = dTopRight;
1407                     dTopRight    = dBottomRight;
1408                     dBottomRight = tmp;
1409                     dstyinc = dstyinc *-1;
1410                 }
1411                 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1412                 {
1413                     /* I don't think we need to do anything about this flag */
1414                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1415                 }
1416                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1417                 {
1418                     tmp          = dBottomRight;
1419                     dBottomRight = dTopLeft;
1420                     dTopLeft     = tmp;
1421                     tmp          = dBottomLeft;
1422                     dBottomLeft  = dTopRight;
1423                     dTopRight    = tmp;
1424                     dstxinc = dstxinc * -1;
1425                     dstyinc = dstyinc * -1;
1426                 }
1427                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1428                 {
1429                     tmp          = dTopLeft;
1430                     dTopLeft     = dBottomLeft;
1431                     dBottomLeft  = dBottomRight;
1432                     dBottomRight = dTopRight;
1433                     dTopRight    = tmp;
1434                     tmpxy   = dstxinc;
1435                     dstxinc = dstyinc;
1436                     dstyinc = tmpxy;
1437                     dstxinc = dstxinc * -1;
1438                 }
1439                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1440                 {
1441                     tmp          = dTopLeft;
1442                     dTopLeft     = dTopRight;
1443                     dTopRight    = dBottomRight;
1444                     dBottomRight = dBottomLeft;
1445                     dBottomLeft  = tmp;
1446                     tmpxy   = dstxinc;
1447                     dstxinc = dstyinc;
1448                     dstyinc = tmpxy;
1449                     dstyinc = dstyinc * -1;
1450                 }
1451                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1452                 {
1453                     /* I don't think we need to do anything about this flag */
1454                     WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1455                 }
1456                 dbuf = dTopLeft;
1457                 Flags &= ~(WINEDDBLT_DDFX);
1458             }
1459
1460 #define COPY_COLORKEY_FX(type) { \
1461             const type *s; \
1462             type *d = (type *)dbuf, *dx, tmp; \
1463             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1464             s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1465             dx = d; \
1466             for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1467             tmp = s[sx >> 16]; \
1468             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1469             ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1470             dx[0] = tmp; \
1471         } \
1472             dx = (type*)(((LPBYTE)dx)+dstxinc); \
1473         } \
1474             d = (type*)(((LPBYTE)d)+dstyinc); \
1475         } \
1476             break; }
1477
1478             switch (bpp) {
1479                 case 1: COPY_COLORKEY_FX(BYTE)
1480                         case 2: COPY_COLORKEY_FX(WORD)
1481                                 case 4: COPY_COLORKEY_FX(DWORD)
1482                 case 3:
1483                 {
1484                     const BYTE *s;
1485                     BYTE *d = dbuf, *dx;
1486                     for (y = sy = 0; y < dstheight; y++, sy += yinc)
1487                     {
1488                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1489                         dx = d;
1490                         for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1491                         {
1492                             DWORD pixel, dpixel = 0;
1493                             s = sbuf+3*(sx>>16);
1494                             pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1495                             dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1496                             if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1497                                   ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1498                             {
1499                                 dx[0] = (pixel    )&0xff;
1500                                 dx[1] = (pixel>> 8)&0xff;
1501                                 dx[2] = (pixel>>16)&0xff;
1502                             }
1503                             dx+= dstxinc;
1504                         }
1505                         d += dstyinc;
1506                     }
1507                     break;
1508                 }
1509                 default:
1510                     FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1511                           (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1512                     ret = WINED3DERR_NOTAVAILABLE;
1513                     goto error;
1514 #undef COPY_COLORKEY_FX
1515             }
1516         }
1517     }
1518
1519 error:
1520     if (Flags && FIXME_ON(d3d_surface))
1521     {
1522         FIXME("\tUnsupported flags: %08x\n", Flags);
1523     }
1524
1525 release:
1526     IWineD3DSurface_UnlockRect(iface);
1527     if (src && src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *)src);
1528     /* Release the converted surface if any */
1529     if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1530     return ret;
1531 }
1532
1533 /*****************************************************************************
1534  * IWineD3DSurface::BltFast, SW emulation version
1535  *
1536  * This is the software implementation of BltFast, as used by GDI surfaces
1537  * and as a fallback for OpenGL surfaces. This code is taken from the old
1538  * DirectDraw code, and was originally written by TransGaming.
1539  *
1540  * Params:
1541  *  dstx:
1542  *  dsty:
1543  *  src_surface: Source surface to copy from
1544  *  rsrc: Source rectangle
1545  *  trans: Some Flags
1546  *
1547  * Returns:
1548  *  WINED3D_OK on success
1549  *
1550  *****************************************************************************/
1551 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1552         IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1553 {
1554     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1555     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1556
1557     int                 bpp, w, h, x, y;
1558     WINED3DLOCKED_RECT  dlock,slock;
1559     HRESULT             ret = WINED3D_OK;
1560     RECT                rsrc2;
1561     RECT                lock_src, lock_dst, lock_union;
1562     const BYTE          *sbuf;
1563     BYTE                *dbuf;
1564     const struct wined3d_format *sEntry, *dEntry;
1565
1566     TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1567             iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1568
1569     if ((This->Flags & SFLAG_LOCKED) || (src->Flags & SFLAG_LOCKED))
1570     {
1571         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1572         return WINEDDERR_SURFACEBUSY;
1573     }
1574
1575     if (!rsrc)
1576     {
1577         WARN("rsrc is NULL!\n");
1578         rsrc2.left = 0;
1579         rsrc2.top = 0;
1580         rsrc2.right = src->currentDesc.Width;
1581         rsrc2.bottom = src->currentDesc.Height;
1582         rsrc = &rsrc2;
1583     }
1584
1585     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1586     if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1587             || (rsrc->top   > src->currentDesc.Height) || (rsrc->top    < 0)
1588             || (rsrc->left  > src->currentDesc.Width)  || (rsrc->left   < 0)
1589             || (rsrc->right > src->currentDesc.Width)  || (rsrc->right  < 0)
1590             || (rsrc->right < rsrc->left)              || (rsrc->bottom < rsrc->top))
1591     {
1592         WARN("Application gave us bad source rectangle for BltFast.\n");
1593         return WINEDDERR_INVALIDRECT;
1594     }
1595
1596     h = rsrc->bottom - rsrc->top;
1597     if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1598     if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1599     if (h <= 0) return WINEDDERR_INVALIDRECT;
1600
1601     w = rsrc->right - rsrc->left;
1602     if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1603     if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1604     if (w <= 0) return WINEDDERR_INVALIDRECT;
1605
1606     /* Now compute the locking rectangle... */
1607     lock_src.left = rsrc->left;
1608     lock_src.top = rsrc->top;
1609     lock_src.right = lock_src.left + w;
1610     lock_src.bottom = lock_src.top + h;
1611
1612     lock_dst.left = dstx;
1613     lock_dst.top = dsty;
1614     lock_dst.right = dstx + w;
1615     lock_dst.bottom = dsty + h;
1616
1617     bpp = This->resource.format->byte_count;
1618
1619     /* We need to lock the surfaces, or we won't get refreshes when done. */
1620     if (src == This)
1621     {
1622         int pitch;
1623
1624         UnionRect(&lock_union, &lock_src, &lock_dst);
1625
1626         /* Lock the union of the two rectangles */
1627         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1628         if(ret != WINED3D_OK) goto error;
1629
1630         pitch = dlock.Pitch;
1631         slock.Pitch = dlock.Pitch;
1632
1633         /* Since slock was originally copied from this surface's description, we can just reuse it */
1634         sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1635         dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1636         sEntry = src->resource.format;
1637         dEntry = sEntry;
1638     }
1639     else
1640     {
1641         ret = IWineD3DSurface_LockRect(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1642         if(ret != WINED3D_OK) goto error;
1643         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1644         if(ret != WINED3D_OK) goto error;
1645
1646         sbuf = slock.pBits;
1647         dbuf = dlock.pBits;
1648         TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1649
1650         sEntry = src->resource.format;
1651         dEntry = This->resource.format;
1652     }
1653
1654     /* Handle compressed surfaces first... */
1655     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1656     {
1657         UINT row_block_count;
1658
1659         TRACE("compressed -> compressed copy\n");
1660         if (trans)
1661             FIXME("trans arg not supported when a compressed surface is involved\n");
1662         if (dstx || dsty)
1663             FIXME("offset for destination surface is not supported\n");
1664         if (src->resource.format->id != This->resource.format->id)
1665         {
1666             FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1667             ret = WINED3DERR_WRONGTEXTUREFORMAT;
1668             goto error;
1669         }
1670
1671         row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1672         for (y = 0; y < h; y += dEntry->block_height)
1673         {
1674             memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1675             dbuf += dlock.Pitch;
1676             sbuf += slock.Pitch;
1677         }
1678
1679         goto error;
1680     }
1681     if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1682     {
1683         /* TODO: Use the libtxc_dxtn.so shared library to do
1684          * software decompression
1685          */
1686         ERR("Software decompression not supported.\n");
1687         goto error;
1688     }
1689
1690     if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1691     {
1692         DWORD keylow, keyhigh;
1693         DWORD mask = src->resource.format->red_mask
1694                 | src->resource.format->green_mask
1695                 | src->resource.format->blue_mask;
1696
1697         /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1698         if(!mask && bpp==1)
1699             mask = 0xff;
1700
1701         TRACE("Color keyed copy\n");
1702         if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1703         {
1704             keylow  = src->SrcBltCKey.dwColorSpaceLowValue;
1705             keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1706         }
1707         else
1708         {
1709             /* I'm not sure if this is correct */
1710             FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1711             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1712             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1713         }
1714
1715 #define COPYBOX_COLORKEY(type) { \
1716         const type *s = (const type *)sbuf; \
1717         type *d = (type *)dbuf; \
1718         type tmp; \
1719         for (y = 0; y < h; y++) { \
1720         for (x = 0; x < w; x++) { \
1721         tmp = s[x]; \
1722         if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1723     } \
1724         s = (const type *)((const BYTE *)s + slock.Pitch); \
1725         d = (type *)((BYTE *)d + dlock.Pitch); \
1726     } \
1727         break; \
1728     }
1729
1730         switch (bpp) {
1731             case 1: COPYBOX_COLORKEY(BYTE)
1732                     case 2: COPYBOX_COLORKEY(WORD)
1733                             case 4: COPYBOX_COLORKEY(DWORD)
1734             case 3:
1735             {
1736                 const BYTE *s;
1737                 BYTE *d;
1738                 DWORD tmp;
1739                 s = sbuf;
1740                 d = dbuf;
1741                 for (y = 0; y < h; y++)
1742                 {
1743                     for (x = 0; x < w * 3; x += 3)
1744                     {
1745                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1746                         if (tmp < keylow || tmp > keyhigh)
1747                         {
1748                             d[x + 0] = s[x + 0];
1749                             d[x + 1] = s[x + 1];
1750                             d[x + 2] = s[x + 2];
1751                         }
1752                     }
1753                     s += slock.Pitch;
1754                     d += dlock.Pitch;
1755                 }
1756                 break;
1757             }
1758             default:
1759                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1760                 ret = WINED3DERR_NOTAVAILABLE;
1761                 goto error;
1762         }
1763 #undef COPYBOX_COLORKEY
1764         TRACE("Copy Done\n");
1765     }
1766     else
1767     {
1768         int width = w * bpp;
1769         INT sbufpitch, dbufpitch;
1770
1771         TRACE("NO color key copy\n");
1772         /* Handle overlapping surfaces */
1773         if (sbuf < dbuf)
1774         {
1775             sbuf += (h - 1) * slock.Pitch;
1776             dbuf += (h - 1) * dlock.Pitch;
1777             sbufpitch = -slock.Pitch;
1778             dbufpitch = -dlock.Pitch;
1779         }
1780         else
1781         {
1782             sbufpitch = slock.Pitch;
1783             dbufpitch = dlock.Pitch;
1784         }
1785         for (y = 0; y < h; y++)
1786         {
1787             /* This is pretty easy, a line for line memcpy */
1788             memmove(dbuf, sbuf, width);
1789             sbuf += sbufpitch;
1790             dbuf += dbufpitch;
1791         }
1792         TRACE("Copy done\n");
1793     }
1794
1795 error:
1796     if (src == This)
1797     {
1798         IWineD3DSurface_UnlockRect(iface);
1799     }
1800     else
1801     {
1802         IWineD3DSurface_UnlockRect(iface);
1803         IWineD3DSurface_UnlockRect(src_surface);
1804     }
1805
1806     return ret;
1807 }
1808
1809 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1810 {
1811     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1812
1813     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1814           This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1815
1816     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1817
1818     if (!pRect)
1819     {
1820         pLockedRect->pBits = This->resource.allocatedMemory;
1821         This->lockedRect.left   = 0;
1822         This->lockedRect.top    = 0;
1823         This->lockedRect.right  = This->currentDesc.Width;
1824         This->lockedRect.bottom = This->currentDesc.Height;
1825
1826         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1827               &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1828               This->lockedRect.right, This->lockedRect.bottom);
1829     }
1830     else
1831     {
1832         const struct wined3d_format *format = This->resource.format;
1833
1834         TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1835               pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1836
1837         if ((format->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1838         {
1839             /* Compressed textures are block based, so calculate the offset of
1840              * the block that contains the top-left pixel of the locked rectangle. */
1841             pLockedRect->pBits = This->resource.allocatedMemory
1842                     + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1843                     + ((pRect->left / format->block_width) * format->block_byte_count);
1844         }
1845         else
1846         {
1847             pLockedRect->pBits = This->resource.allocatedMemory +
1848                     (pLockedRect->Pitch * pRect->top) +
1849                     (pRect->left * format->byte_count);
1850         }
1851         This->lockedRect.left   = pRect->left;
1852         This->lockedRect.top    = pRect->top;
1853         This->lockedRect.right  = pRect->right;
1854         This->lockedRect.bottom = pRect->bottom;
1855     }
1856
1857     /* No dirtifying is needed for this surface implementation */
1858     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1859
1860     return WINED3D_OK;
1861 }
1862
1863 /* TODO: think about moving this down to resource? */
1864 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1865 {
1866     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1867
1868     /* This should only be called for sysmem textures, it may be a good idea
1869      * to extend this to all pools at some point in the future  */
1870     if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1871     {
1872         FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1873     }
1874     return This->resource.allocatedMemory;
1875 }