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