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