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