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