wined3d: Merge source rectangle operations into a single block in IWineD3DBaseSurface...
[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     /* For the Destination rect, it can be out of bounds on the condition that a clipper
1037      * is set for the given surface.
1038      */
1039     if (!This->clipper && DestRect &&
1040          ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
1041          (DestRect->top     > This->currentDesc.Height)||(DestRect->top    < 0) ||
1042          (DestRect->left    > This->currentDesc.Width) ||(DestRect->left   < 0) ||
1043          (DestRect->right   > This->currentDesc.Width) ||(DestRect->right  < 0) ||
1044          (DestRect->right   < DestRect->left)          ||(DestRect->bottom < DestRect->top)))
1045     {
1046         WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1047         return WINEDDERR_INVALIDRECT;
1048     }
1049
1050     /* Now handle negative values in the rectangles. Warning: only supported
1051      * for now in the 'simple' cases (ie not in any stretching / rotation
1052      * cases). First, the case where nothing is to be done. */
1053
1054     if (DestRect && (DestRect->bottom <= 0 || DestRect->right <= 0
1055             || DestRect->top >= (int)This->currentDesc.Height
1056             || DestRect->left >= (int)This->currentDesc.Width))
1057     {
1058         TRACE("Nothing to be done.\n");
1059         return WINED3D_OK;
1060     }
1061
1062     if (DestRect)
1063     {
1064         xdst = *DestRect;
1065     }
1066     else
1067     {
1068         xdst.top    = 0;
1069         xdst.bottom = This->currentDesc.Height;
1070         xdst.left   = 0;
1071         xdst.right  = This->currentDesc.Width;
1072     }
1073
1074     /* The easy case : the source-less blits.... */
1075     if (Src == NULL && DestRect)
1076     {
1077         RECT full_rect;
1078         RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1079
1080         full_rect.left   = 0;
1081         full_rect.top    = 0;
1082         full_rect.right  = This->currentDesc.Width;
1083         full_rect.bottom = This->currentDesc.Height;
1084         IntersectRect(&temp_rect, &full_rect, DestRect);
1085         xdst = temp_rect;
1086     }
1087     else if (DestRect)
1088     {
1089         /* Only handle clipping on the destination rectangle */
1090         int clip_horiz = (DestRect->left < 0) || (DestRect->right  > (int) This->currentDesc.Width );
1091         int clip_vert  = (DestRect->top  < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1092         if (clip_vert || clip_horiz)
1093         {
1094             /* Now check if this is a special case or not... */
1095             if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1096                    (((DestRect->right  - DestRect->left) != (xsrc.right  - xsrc.left)) && clip_horiz) ||
1097                    (Flags & WINEDDBLT_DDFX))
1098             {
1099                 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1100                 return  WINED3D_OK;
1101             }
1102
1103             if (clip_horiz)
1104             {
1105                 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1106                 if (DestRect->right > This->currentDesc.Width)
1107                 {
1108                     xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1109                     xdst.right = (int) This->currentDesc.Width;
1110                 }
1111             }
1112             if (clip_vert)
1113             {
1114                 if (DestRect->top < 0)
1115                 {
1116                     xsrc.top -= DestRect->top;
1117                     xdst.top = 0;
1118                 }
1119                 if (DestRect->bottom > This->currentDesc.Height)
1120                 {
1121                     xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1122                     xdst.bottom = (int) This->currentDesc.Height;
1123                 }
1124             }
1125             /* And check if after clipping something is still to be done... */
1126             if ((xdst.bottom <= 0)   || (xdst.right <= 0)       ||
1127                  (xdst.top   >= (int) This->currentDesc.Height)  ||
1128                  (xdst.left  >= (int) This->currentDesc.Width)   ||
1129                  (xsrc.bottom <= 0)   || (xsrc.right <= 0)       ||
1130                  (xsrc.top >= (int) Src->currentDesc.Height)     ||
1131                  (xsrc.left >= (int) Src->currentDesc.Width))
1132             {
1133                 TRACE("Nothing to be done after clipping !\n");
1134                 return  WINED3D_OK;
1135             }
1136         }
1137     }
1138
1139     if (Src == This)
1140     {
1141         IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1142         slock = dlock;
1143         sEntry = This->resource.format_desc;
1144         dEntry = sEntry;
1145     }
1146     else
1147     {
1148         dEntry = This->resource.format_desc;
1149         if (Src)
1150         {
1151             if (This->resource.format_desc->format != Src->resource.format_desc->format)
1152             {
1153                 Src = surface_convert_format(Src, dEntry->format);
1154                 if(!Src) {
1155                     /* The conv function writes a FIXME */
1156                     WARN("Cannot convert source surface format to dest format\n");
1157                     goto release;
1158                 }
1159             }
1160             IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1161             sEntry = Src->resource.format_desc;
1162         }
1163         else
1164         {
1165             sEntry = dEntry;
1166         }
1167         if (DestRect)
1168             IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1169         else
1170             IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1171     }
1172
1173     if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1174
1175     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1176     {
1177         if (!DestRect || Src == This)
1178         {
1179             memcpy(dlock.pBits, slock.pBits, This->resource.size);
1180             goto release;
1181         }
1182     }
1183
1184     bpp = This->resource.format_desc->byte_count;
1185     srcheight = xsrc.bottom - xsrc.top;
1186     srcwidth = xsrc.right - xsrc.left;
1187     dstheight = xdst.bottom - xdst.top;
1188     dstwidth = xdst.right - xdst.left;
1189     width = (xdst.right - xdst.left) * bpp;
1190
1191     if (DestRect && Src != This)
1192         dbuf = dlock.pBits;
1193     else
1194         dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1195
1196     if (Flags & WINEDDBLT_WAIT)
1197     {
1198         Flags &= ~WINEDDBLT_WAIT;
1199     }
1200     if (Flags & WINEDDBLT_ASYNC)
1201     {
1202         static BOOL displayed = FALSE;
1203         if (!displayed)
1204             FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1205         displayed = TRUE;
1206         Flags &= ~WINEDDBLT_ASYNC;
1207     }
1208     if (Flags & WINEDDBLT_DONOTWAIT)
1209     {
1210         /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1211         static BOOL displayed = FALSE;
1212         if (!displayed)
1213             FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1214         displayed = TRUE;
1215         Flags &= ~WINEDDBLT_DONOTWAIT;
1216     }
1217
1218     /* First, all the 'source-less' blits */
1219     if (Flags & WINEDDBLT_COLORFILL)
1220     {
1221         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1222                              dlock.Pitch, DDBltFx->u5.dwFillColor);
1223         Flags &= ~WINEDDBLT_COLORFILL;
1224     }
1225
1226     if (Flags & WINEDDBLT_DEPTHFILL)
1227     {
1228         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1229     }
1230     if (Flags & WINEDDBLT_ROP)
1231     {
1232         /* Catch some degenerate cases here */
1233         switch(DDBltFx->dwROP)
1234         {
1235             case BLACKNESS:
1236                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1237                 break;
1238                 case 0xAA0029: /* No-op */
1239                     break;
1240             case WHITENESS:
1241                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1242                 break;
1243                 case SRCCOPY: /* well, we do that below ? */
1244                     break;
1245             default:
1246                 FIXME("Unsupported raster op: %08x  Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1247                 goto error;
1248         }
1249         Flags &= ~WINEDDBLT_ROP;
1250     }
1251     if (Flags & WINEDDBLT_DDROPS)
1252     {
1253         FIXME("\tDdraw Raster Ops: %08x  Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1254     }
1255     /* Now the 'with source' blits */
1256     if (Src)
1257     {
1258         const BYTE *sbase;
1259         int sx, xinc, sy, yinc;
1260
1261         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1262             goto release;
1263         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1264         xinc = (srcwidth << 16) / dstwidth;
1265         yinc = (srcheight << 16) / dstheight;
1266
1267         if (!Flags)
1268         {
1269             /* No effects, we can cheat here */
1270             if (dstwidth == srcwidth)
1271             {
1272                 if (dstheight == srcheight)
1273                 {
1274                     /* No stretching in either direction. This needs to be as
1275                     * fast as possible */
1276                     sbuf = sbase;
1277
1278                     /* check for overlapping surfaces */
1279                     if (Src != This || xdst.top < xsrc.top ||
1280                         xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1281                     {
1282                         /* no overlap, or dst above src, so copy from top downwards */
1283                         for (y = 0; y < dstheight; y++)
1284                         {
1285                             memcpy(dbuf, sbuf, width);
1286                             sbuf += slock.Pitch;
1287                             dbuf += dlock.Pitch;
1288                         }
1289                     }
1290                     else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
1291                     {
1292                         sbuf += (slock.Pitch*dstheight);
1293                         dbuf += (dlock.Pitch*dstheight);
1294                         for (y = 0; y < dstheight; y++)
1295                         {
1296                             sbuf -= slock.Pitch;
1297                             dbuf -= dlock.Pitch;
1298                             memcpy(dbuf, sbuf, width);
1299                         }
1300                     }
1301                     else /* src and dst overlapping on the same line, use memmove */
1302                     {
1303                         for (y = 0; y < dstheight; y++)
1304                         {
1305                             memmove(dbuf, sbuf, width);
1306                             sbuf += slock.Pitch;
1307                             dbuf += dlock.Pitch;
1308                         }
1309                     }
1310                 } else {
1311                     /* Stretching in Y direction only */
1312                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1313                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1314                         memcpy(dbuf, sbuf, width);
1315                         dbuf += dlock.Pitch;
1316                     }
1317                 }
1318             }
1319             else
1320             {
1321                 /* Stretching in X direction */
1322                 int last_sy = -1;
1323                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1324                 {
1325                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1326
1327                     if ((sy >> 16) == (last_sy >> 16))
1328                     {
1329                         /* this sourcerow is the same as last sourcerow -
1330                         * copy already stretched row
1331                         */
1332                         memcpy(dbuf, dbuf - dlock.Pitch, width);
1333                     }
1334                     else
1335                     {
1336 #define STRETCH_ROW(type) { \
1337                         const type *s = (const type *)sbuf; \
1338                         type *d = (type *)dbuf; \
1339                         for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1340                         d[x] = s[sx >> 16]; \
1341                         break; }
1342
1343                         switch(bpp)
1344                         {
1345                             case 1: STRETCH_ROW(BYTE)
1346                                     case 2: STRETCH_ROW(WORD)
1347                                             case 4: STRETCH_ROW(DWORD)
1348                             case 3:
1349                             {
1350                                 const BYTE *s;
1351                                 BYTE *d = dbuf;
1352                                 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1353                                 {
1354                                     DWORD pixel;
1355
1356                                     s = sbuf+3*(sx>>16);
1357                                     pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1358                                     d[0] = (pixel    )&0xff;
1359                                     d[1] = (pixel>> 8)&0xff;
1360                                     d[2] = (pixel>>16)&0xff;
1361                                     d+=3;
1362                                 }
1363                                 break;
1364                             }
1365                             default:
1366                                 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1367                                 ret = WINED3DERR_NOTAVAILABLE;
1368                                 goto error;
1369                         }
1370 #undef STRETCH_ROW
1371                     }
1372                     dbuf += dlock.Pitch;
1373                     last_sy = sy;
1374                 }
1375             }
1376         }
1377         else
1378         {
1379             LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1380             DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1381             DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1382             if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1383             {
1384                 /* The color keying flags are checked for correctness in ddraw */
1385                 if (Flags & WINEDDBLT_KEYSRC)
1386                 {
1387                     keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1388                     keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1389                 }
1390                 else  if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1391                 {
1392                     keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1393                     keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1394                 }
1395
1396                 if (Flags & WINEDDBLT_KEYDEST)
1397                 {
1398                     /* Destination color keys are taken from the source surface ! */
1399                     destkeylow  = Src->DestBltCKey.dwColorSpaceLowValue;
1400                     destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1401                 }
1402                 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1403                 {
1404                     destkeylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1405                     destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1406                 }
1407
1408                 if(bpp == 1)
1409                 {
1410                     keymask = 0xff;
1411                 }
1412                 else
1413                 {
1414                     keymask = sEntry->red_mask
1415                             | sEntry->green_mask
1416                             | sEntry->blue_mask;
1417                 }
1418                 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1419             }
1420
1421             if (Flags & WINEDDBLT_DDFX)
1422             {
1423                 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1424                 LONG tmpxy;
1425                 dTopLeft     = dbuf;
1426                 dTopRight    = dbuf+((dstwidth-1)*bpp);
1427                 dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
1428                 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1429
1430                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1431                 {
1432                     /* I don't think we need to do anything about this flag */
1433                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1434                 }
1435                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1436                 {
1437                     tmp          = dTopRight;
1438                     dTopRight    = dTopLeft;
1439                     dTopLeft     = tmp;
1440                     tmp          = dBottomRight;
1441                     dBottomRight = dBottomLeft;
1442                     dBottomLeft  = tmp;
1443                     dstxinc = dstxinc *-1;
1444                 }
1445                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1446                 {
1447                     tmp          = dTopLeft;
1448                     dTopLeft     = dBottomLeft;
1449                     dBottomLeft  = tmp;
1450                     tmp          = dTopRight;
1451                     dTopRight    = dBottomRight;
1452                     dBottomRight = tmp;
1453                     dstyinc = dstyinc *-1;
1454                 }
1455                 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1456                 {
1457                     /* I don't think we need to do anything about this flag */
1458                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1459                 }
1460                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1461                 {
1462                     tmp          = dBottomRight;
1463                     dBottomRight = dTopLeft;
1464                     dTopLeft     = tmp;
1465                     tmp          = dBottomLeft;
1466                     dBottomLeft  = dTopRight;
1467                     dTopRight    = tmp;
1468                     dstxinc = dstxinc * -1;
1469                     dstyinc = dstyinc * -1;
1470                 }
1471                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1472                 {
1473                     tmp          = dTopLeft;
1474                     dTopLeft     = dBottomLeft;
1475                     dBottomLeft  = dBottomRight;
1476                     dBottomRight = dTopRight;
1477                     dTopRight    = tmp;
1478                     tmpxy   = dstxinc;
1479                     dstxinc = dstyinc;
1480                     dstyinc = tmpxy;
1481                     dstxinc = dstxinc * -1;
1482                 }
1483                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1484                 {
1485                     tmp          = dTopLeft;
1486                     dTopLeft     = dTopRight;
1487                     dTopRight    = dBottomRight;
1488                     dBottomRight = dBottomLeft;
1489                     dBottomLeft  = tmp;
1490                     tmpxy   = dstxinc;
1491                     dstxinc = dstyinc;
1492                     dstyinc = tmpxy;
1493                     dstyinc = dstyinc * -1;
1494                 }
1495                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1496                 {
1497                     /* I don't think we need to do anything about this flag */
1498                     WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1499                 }
1500                 dbuf = dTopLeft;
1501                 Flags &= ~(WINEDDBLT_DDFX);
1502             }
1503
1504 #define COPY_COLORKEY_FX(type) { \
1505             const type *s; \
1506             type *d = (type *)dbuf, *dx, tmp; \
1507             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1508             s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1509             dx = d; \
1510             for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1511             tmp = s[sx >> 16]; \
1512             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1513             ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1514             dx[0] = tmp; \
1515         } \
1516             dx = (type*)(((LPBYTE)dx)+dstxinc); \
1517         } \
1518             d = (type*)(((LPBYTE)d)+dstyinc); \
1519         } \
1520             break; }
1521
1522             switch (bpp) {
1523                 case 1: COPY_COLORKEY_FX(BYTE)
1524                         case 2: COPY_COLORKEY_FX(WORD)
1525                                 case 4: COPY_COLORKEY_FX(DWORD)
1526                 case 3:
1527                 {
1528                     const BYTE *s;
1529                     BYTE *d = dbuf, *dx;
1530                     for (y = sy = 0; y < dstheight; y++, sy += yinc)
1531                     {
1532                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1533                         dx = d;
1534                         for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1535                         {
1536                             DWORD pixel, dpixel = 0;
1537                             s = sbuf+3*(sx>>16);
1538                             pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1539                             dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1540                             if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1541                                   ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1542                             {
1543                                 dx[0] = (pixel    )&0xff;
1544                                 dx[1] = (pixel>> 8)&0xff;
1545                                 dx[2] = (pixel>>16)&0xff;
1546                             }
1547                             dx+= dstxinc;
1548                         }
1549                         d += dstyinc;
1550                     }
1551                     break;
1552                 }
1553                 default:
1554                     FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1555                           (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1556                     ret = WINED3DERR_NOTAVAILABLE;
1557                     goto error;
1558 #undef COPY_COLORKEY_FX
1559             }
1560         }
1561     }
1562
1563 error:
1564     if (Flags && FIXME_ON(d3d_surface))
1565     {
1566         FIXME("\tUnsupported flags: %08x\n", Flags);
1567     }
1568
1569 release:
1570     IWineD3DSurface_UnlockRect(iface);
1571     if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1572     /* Release the converted surface if any */
1573     if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1574     return ret;
1575 }
1576
1577 /*****************************************************************************
1578  * IWineD3DSurface::BltFast, SW emulation version
1579  *
1580  * This is the software implementation of BltFast, as used by GDI surfaces
1581  * and as a fallback for OpenGL surfaces. This code is taken from the old
1582  * DirectDraw code, and was originally written by TransGaming.
1583  *
1584  * Params:
1585  *  dstx:
1586  *  dsty:
1587  *  Source: Source surface to copy from
1588  *  rsrc: Source rectangle
1589  *  trans: Some Flags
1590  *
1591  * Returns:
1592  *  WINED3D_OK on success
1593  *
1594  *****************************************************************************/
1595 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1596         IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1597 {
1598     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1599     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1600
1601     int                 bpp, w, h, x, y;
1602     WINED3DLOCKED_RECT  dlock,slock;
1603     HRESULT             ret = WINED3D_OK;
1604     RECT                rsrc2;
1605     RECT                lock_src, lock_dst, lock_union;
1606     const BYTE          *sbuf;
1607     BYTE                *dbuf;
1608     const struct wined3d_format_desc *sEntry, *dEntry;
1609
1610     if (TRACE_ON(d3d_surface))
1611     {
1612         TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1613
1614         if (rsrc)
1615         {
1616             TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1617                   rsrc->right,rsrc->bottom);
1618         }
1619         else
1620         {
1621             TRACE(" srcrect: NULL\n");
1622         }
1623     }
1624
1625     if ((This->Flags & SFLAG_LOCKED) ||
1626             (Src->Flags & SFLAG_LOCKED))
1627     {
1628         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1629         return WINEDDERR_SURFACEBUSY;
1630     }
1631
1632     if (!rsrc)
1633     {
1634         WARN("rsrc is NULL!\n");
1635         rsrc2.left = 0;
1636         rsrc2.top = 0;
1637         rsrc2.right = Src->currentDesc.Width;
1638         rsrc2.bottom = Src->currentDesc.Height;
1639         rsrc = &rsrc2;
1640     }
1641
1642     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1643     if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1644          (rsrc->top    > Src->currentDesc.Height) || (rsrc->top    < 0) ||
1645          (rsrc->left   > Src->currentDesc.Width)  || (rsrc->left   < 0) ||
1646          (rsrc->right  > Src->currentDesc.Width)  || (rsrc->right  < 0) ||
1647          (rsrc->right  < rsrc->left)              || (rsrc->bottom < rsrc->top))
1648     {
1649         WARN("Application gave us bad source rectangle for BltFast.\n");
1650         return WINEDDERR_INVALIDRECT;
1651     }
1652
1653     h = rsrc->bottom - rsrc->top;
1654     if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1655     if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1656     if (h <= 0) return WINEDDERR_INVALIDRECT;
1657
1658     w = rsrc->right - rsrc->left;
1659     if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1660     if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1661     if (w <= 0) return WINEDDERR_INVALIDRECT;
1662
1663     /* Now compute the locking rectangle... */
1664     lock_src.left = rsrc->left;
1665     lock_src.top = rsrc->top;
1666     lock_src.right = lock_src.left + w;
1667     lock_src.bottom = lock_src.top + h;
1668
1669     lock_dst.left = dstx;
1670     lock_dst.top = dsty;
1671     lock_dst.right = dstx + w;
1672     lock_dst.bottom = dsty + h;
1673
1674     bpp = This->resource.format_desc->byte_count;
1675
1676     /* We need to lock the surfaces, or we won't get refreshes when done. */
1677     if (Src == This)
1678     {
1679         int pitch;
1680
1681         UnionRect(&lock_union, &lock_src, &lock_dst);
1682
1683         /* Lock the union of the two rectangles */
1684         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1685         if(ret != WINED3D_OK) goto error;
1686
1687         pitch = dlock.Pitch;
1688         slock.Pitch = dlock.Pitch;
1689
1690         /* Since slock was originally copied from this surface's description, we can just reuse it */
1691         sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1692         dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1693         sEntry = Src->resource.format_desc;
1694         dEntry = sEntry;
1695     }
1696     else
1697     {
1698         ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1699         if(ret != WINED3D_OK) goto error;
1700         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1701         if(ret != WINED3D_OK) goto error;
1702
1703         sbuf = slock.pBits;
1704         dbuf = dlock.pBits;
1705         TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1706
1707         sEntry = Src->resource.format_desc;
1708         dEntry = This->resource.format_desc;
1709     }
1710
1711     /* Handle compressed surfaces first... */
1712     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1713     {
1714         UINT row_block_count;
1715
1716         TRACE("compressed -> compressed copy\n");
1717         if (trans)
1718             FIXME("trans arg not supported when a compressed surface is involved\n");
1719         if (dstx || dsty)
1720             FIXME("offset for destination surface is not supported\n");
1721         if (Src->resource.format_desc->format != This->resource.format_desc->format)
1722         {
1723             FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1724             ret = WINED3DERR_WRONGTEXTUREFORMAT;
1725             goto error;
1726         }
1727
1728         row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1729         for (y = 0; y < h; y += dEntry->block_height)
1730         {
1731             memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1732             dbuf += dlock.Pitch;
1733             sbuf += slock.Pitch;
1734         }
1735
1736         goto error;
1737     }
1738     if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1739     {
1740         /* TODO: Use the libtxc_dxtn.so shared library to do
1741          * software decompression
1742          */
1743         ERR("Software decompression not supported.\n");
1744         goto error;
1745     }
1746
1747     if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1748     {
1749         DWORD keylow, keyhigh;
1750         DWORD mask = Src->resource.format_desc->red_mask |
1751                      Src->resource.format_desc->green_mask |
1752                      Src->resource.format_desc->blue_mask;
1753
1754         /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1755         if(!mask && bpp==1)
1756             mask = 0xff;
1757
1758         TRACE("Color keyed copy\n");
1759         if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1760         {
1761             keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1762             keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1763         }
1764         else
1765         {
1766             /* I'm not sure if this is correct */
1767             FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1768             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1769             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1770         }
1771
1772 #define COPYBOX_COLORKEY(type) { \
1773         const type *s = (const type *)sbuf; \
1774         type *d = (type *)dbuf; \
1775         type tmp; \
1776         for (y = 0; y < h; y++) { \
1777         for (x = 0; x < w; x++) { \
1778         tmp = s[x]; \
1779         if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1780     } \
1781         s = (const type *)((const BYTE *)s + slock.Pitch); \
1782         d = (type *)((BYTE *)d + dlock.Pitch); \
1783     } \
1784         break; \
1785     }
1786
1787         switch (bpp) {
1788             case 1: COPYBOX_COLORKEY(BYTE)
1789                     case 2: COPYBOX_COLORKEY(WORD)
1790                             case 4: COPYBOX_COLORKEY(DWORD)
1791             case 3:
1792             {
1793                 const BYTE *s;
1794                 BYTE *d;
1795                 DWORD tmp;
1796                 s = sbuf;
1797                 d = dbuf;
1798                 for (y = 0; y < h; y++)
1799                 {
1800                     for (x = 0; x < w * 3; x += 3)
1801                     {
1802                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1803                         if (tmp < keylow || tmp > keyhigh)
1804                         {
1805                             d[x + 0] = s[x + 0];
1806                             d[x + 1] = s[x + 1];
1807                             d[x + 2] = s[x + 2];
1808                         }
1809                     }
1810                     s += slock.Pitch;
1811                     d += dlock.Pitch;
1812                 }
1813                 break;
1814             }
1815             default:
1816                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1817                 ret = WINED3DERR_NOTAVAILABLE;
1818                 goto error;
1819         }
1820 #undef COPYBOX_COLORKEY
1821         TRACE("Copy Done\n");
1822     }
1823     else
1824     {
1825         int width = w * bpp;
1826         INT sbufpitch, dbufpitch;
1827
1828         TRACE("NO color key copy\n");
1829         /* Handle overlapping surfaces */
1830         if (sbuf < dbuf)
1831         {
1832             sbuf += (h - 1) * slock.Pitch;
1833             dbuf += (h - 1) * dlock.Pitch;
1834             sbufpitch = -slock.Pitch;
1835             dbufpitch = -dlock.Pitch;
1836         }
1837         else
1838         {
1839             sbufpitch = slock.Pitch;
1840             dbufpitch = dlock.Pitch;
1841         }
1842         for (y = 0; y < h; y++)
1843         {
1844             /* This is pretty easy, a line for line memcpy */
1845             memmove(dbuf, sbuf, width);
1846             sbuf += sbufpitch;
1847             dbuf += dbufpitch;
1848         }
1849         TRACE("Copy done\n");
1850     }
1851
1852 error:
1853     if (Src == This)
1854     {
1855         IWineD3DSurface_UnlockRect(iface);
1856     }
1857     else
1858     {
1859         IWineD3DSurface_UnlockRect(iface);
1860         IWineD3DSurface_UnlockRect(Source);
1861     }
1862
1863     return ret;
1864 }
1865
1866 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1867 {
1868     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1869
1870     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1871           This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1872
1873     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1874
1875     if (NULL == pRect)
1876     {
1877         pLockedRect->pBits = This->resource.allocatedMemory;
1878         This->lockedRect.left   = 0;
1879         This->lockedRect.top    = 0;
1880         This->lockedRect.right  = This->currentDesc.Width;
1881         This->lockedRect.bottom = This->currentDesc.Height;
1882
1883         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1884               &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1885               This->lockedRect.right, This->lockedRect.bottom);
1886     }
1887     else
1888     {
1889         const struct wined3d_format_desc *format_desc = This->resource.format_desc;
1890
1891         TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1892               pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1893
1894         if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1895         {
1896             /* Compressed textures are block based, so calculate the offset of
1897              * the block that contains the top-left pixel of the locked rectangle. */
1898             pLockedRect->pBits = This->resource.allocatedMemory
1899                     + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1900                     + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1901         }
1902         else
1903         {
1904             pLockedRect->pBits = This->resource.allocatedMemory +
1905                     (pLockedRect->Pitch * pRect->top) +
1906                     (pRect->left * format_desc->byte_count);
1907         }
1908         This->lockedRect.left   = pRect->left;
1909         This->lockedRect.top    = pRect->top;
1910         This->lockedRect.right  = pRect->right;
1911         This->lockedRect.bottom = pRect->bottom;
1912     }
1913
1914     /* No dirtifying is needed for this surface implementation */
1915     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1916
1917     return WINED3D_OK;
1918 }
1919
1920 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1921     ERR("Should not be called on base texture\n");
1922 }
1923
1924 /* TODO: think about moving this down to resource? */
1925 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1926 {
1927     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1928
1929     /* This should only be called for sysmem textures, it may be a good idea
1930      * to extend this to all pools at some point in the future  */
1931     if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1932     {
1933         FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1934     }
1935     return This->resource.allocatedMemory;
1936 }