wined3d: Mark internal symbols hidden.
[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.0f) return 0x0000;
45     if(isnan(*in)) return 0x7C01;
46     if (isinf(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
47
48     if(tmp < pow(2, 10)) {
49         do
50         {
51             tmp = tmp * 2.0f;
52             exp--;
53         }while(tmp < pow(2, 10));
54     } else if(tmp >= pow(2, 11)) {
55         do
56         {
57             tmp /= 2.0f;
58             exp++;
59         }while(tmp >= pow(2, 11));
60     }
61
62     mantissa = (unsigned int) tmp;
63     if(tmp - mantissa >= 0.5f) 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.0f ? 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     if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
546     {
547         WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
548         return WINED3DERR_INVALIDCALL;
549     }
550
551     switch (format_desc->byte_count)
552     {
553         case 2:
554         case 4:
555             /* Allocate extra space to store the RGB bit masks. */
556             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
557             break;
558
559         case 3:
560             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
561             break;
562
563         default:
564             /* Allocate extra space for a palette. */
565             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
566                     sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
567             break;
568     }
569
570     if (!b_info)
571         return E_OUTOFMEMORY;
572
573         /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
574     * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
575     * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
576     * add an extra line to the dib section
577         */
578     GetSystemInfo(&sysInfo);
579     if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
580         extraline = 1;
581         TRACE("Adding an extra line to the dib section\n");
582     }
583
584     b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
585     /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
586     b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
587     b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
588     b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
589     b_info->bmiHeader.biPlanes = 1;
590     b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
591
592     b_info->bmiHeader.biXPelsPerMeter = 0;
593     b_info->bmiHeader.biYPelsPerMeter = 0;
594     b_info->bmiHeader.biClrUsed = 0;
595     b_info->bmiHeader.biClrImportant = 0;
596
597     /* Get the bit masks */
598     masks = (DWORD *)b_info->bmiColors;
599     switch (This->resource.format_desc->format)
600     {
601         case WINED3DFMT_R8G8B8:
602             usage = DIB_RGB_COLORS;
603             b_info->bmiHeader.biCompression = BI_RGB;
604             break;
605
606         case WINED3DFMT_X1R5G5B5:
607         case WINED3DFMT_A1R5G5B5:
608         case WINED3DFMT_A4R4G4B4:
609         case WINED3DFMT_X4R4G4B4:
610         case WINED3DFMT_R3G3B2:
611         case WINED3DFMT_A8R3G3B2:
612         case WINED3DFMT_R10G10B10A2_UNORM:
613         case WINED3DFMT_R8G8B8A8_UNORM:
614         case WINED3DFMT_X8B8G8R8:
615         case WINED3DFMT_A2R10G10B10:
616         case WINED3DFMT_R5G6B5:
617         case WINED3DFMT_R16G16B16A16_UNORM:
618             usage = 0;
619             b_info->bmiHeader.biCompression = BI_BITFIELDS;
620             masks[0] = format_desc->red_mask;
621             masks[1] = format_desc->green_mask;
622             masks[2] = format_desc->blue_mask;
623             break;
624
625         default:
626             /* Don't know palette */
627             b_info->bmiHeader.biCompression = BI_RGB;
628             usage = 0;
629             break;
630     }
631
632     ddc = GetDC(0);
633     if (ddc == 0) {
634         HeapFree(GetProcessHeap(), 0, b_info);
635         return HRESULT_FROM_WIN32(GetLastError());
636     }
637
638     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);
639     This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
640     ReleaseDC(0, ddc);
641
642     if (!This->dib.DIBsection) {
643         ERR("CreateDIBSection failed!\n");
644         HeapFree(GetProcessHeap(), 0, b_info);
645         return HRESULT_FROM_WIN32(GetLastError());
646     }
647
648     TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
649     /* copy the existing surface to the dib section */
650     if(This->resource.allocatedMemory) {
651         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory,  This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
652     } else {
653         /* This is to make LockRect read the gl Texture although memory is allocated */
654         This->Flags &= ~SFLAG_INSYSMEM;
655     }
656     This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
657
658     HeapFree(GetProcessHeap(), 0, b_info);
659
660     /* Now allocate a HDC */
661     This->hDC = CreateCompatibleDC(0);
662     This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
663     TRACE("using wined3d palette %p\n", This->palette);
664     SelectPalette(This->hDC,
665                   This->palette ? This->palette->hpal : 0,
666                   FALSE);
667
668     This->Flags |= SFLAG_DIBSECTION;
669
670     HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
671     This->resource.heapMemory = NULL;
672
673     return WINED3D_OK;
674 }
675
676 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
677                               unsigned int w, unsigned int h)
678 {
679     unsigned int x, y;
680     const float *src_f;
681     unsigned short *dst_s;
682
683     TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
684     for(y = 0; y < h; y++) {
685         src_f = (const float *)(src + y * pitch_in);
686         dst_s = (unsigned short *) (dst + y * pitch_out);
687         for(x = 0; x < w; x++) {
688             dst_s[x] = float_32_to_16(src_f + x);
689         }
690     }
691 }
692
693 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
694         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
695 {
696     static const unsigned char convert_5to8[] =
697     {
698         0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
699         0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
700         0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
701         0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
702     };
703     static const unsigned char convert_6to8[] =
704     {
705         0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
706         0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
707         0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
708         0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
709         0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
710         0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
711         0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
712         0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
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 WORD *src_line = (const WORD *)(src + y * pitch_in);
721         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
722         for (x = 0; x < w; ++x)
723         {
724             WORD pixel = src_line[x];
725             dst_line[x] = 0xff000000
726                     | convert_5to8[(pixel & 0xf800) >> 11] << 16
727                     | convert_6to8[(pixel & 0x07e0) >> 5] << 8
728                     | convert_5to8[(pixel & 0x001f)];
729         }
730     }
731 }
732
733 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
734         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
735 {
736     unsigned int x, y;
737
738     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
739
740     for (y = 0; y < h; ++y)
741     {
742         const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
743         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
744
745         for (x = 0; x < w; ++x)
746         {
747             dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
748         }
749     }
750 }
751
752 struct d3dfmt_convertor_desc {
753     WINED3DFORMAT from, to;
754     void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
755 };
756
757 static const struct d3dfmt_convertor_desc convertors[] =
758 {
759     {WINED3DFMT_R32_FLOAT,  WINED3DFMT_R16_FLOAT,   convert_r32_float_r16_float},
760     {WINED3DFMT_R5G6B5,     WINED3DFMT_X8R8G8B8,    convert_r5g6b5_x8r8g8b8},
761     {WINED3DFMT_A8R8G8B8,   WINED3DFMT_X8R8G8B8,    convert_a8r8g8b8_x8r8g8b8},
762 };
763
764 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
765 {
766     unsigned int i;
767     for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
768         if(convertors[i].from == from && convertors[i].to == to) {
769             return &convertors[i];
770         }
771     }
772     return NULL;
773 }
774
775 /*****************************************************************************
776  * surface_convert_format
777  *
778  * Creates a duplicate of a surface in a different format. Is used by Blt to
779  * blit between surfaces with different formats
780  *
781  * Parameters
782  *  source: Source surface
783  *  fmt: Requested destination format
784  *
785  *****************************************************************************/
786 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
787     IWineD3DSurface *ret = NULL;
788     const struct d3dfmt_convertor_desc *conv;
789     WINED3DLOCKED_RECT lock_src, lock_dst;
790     HRESULT hr;
791
792     conv = find_convertor(source->resource.format_desc->format, to_fmt);
793     if(!conv) {
794         FIXME("Cannot find a conversion function from format %s to %s\n",
795               debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
796         return NULL;
797     }
798
799     IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.wineD3DDevice, source->currentDesc.Width,
800             source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard  */, 0 /* level */, &ret,
801             0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
802             0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source), NULL /* parent */);
803     if(!ret) {
804         ERR("Failed to create a destination surface for conversion\n");
805         return NULL;
806     }
807
808     memset(&lock_src, 0, sizeof(lock_src));
809     memset(&lock_dst, 0, sizeof(lock_dst));
810
811     hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
812     if(FAILED(hr)) {
813         ERR("Failed to lock the source surface\n");
814         IWineD3DSurface_Release(ret);
815         return NULL;
816     }
817     hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
818     if(FAILED(hr)) {
819         ERR("Failed to lock the dest surface\n");
820         IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
821         IWineD3DSurface_Release(ret);
822         return NULL;
823     }
824
825     conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
826                   source->currentDesc.Width, source->currentDesc.Height);
827
828     IWineD3DSurface_UnlockRect(ret);
829     IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
830
831     return (IWineD3DSurfaceImpl *) ret;
832 }
833
834 /*****************************************************************************
835  * _Blt_ColorFill
836  *
837  * Helper function that fills a memory area with a specific color
838  *
839  * Params:
840  *  buf: memory address to start filling at
841  *  width, height: Dimensions of the area to fill
842  *  bpp: Bit depth of the surface
843  *  lPitch: pitch of the surface
844  *  color: Color to fill with
845  *
846  *****************************************************************************/
847 static HRESULT
848         _Blt_ColorFill(BYTE *buf,
849                        int width, int height,
850                        int bpp, LONG lPitch,
851                        DWORD color)
852 {
853     int x, y;
854     LPBYTE first;
855
856     /* Do first row */
857
858 #define COLORFILL_ROW(type) \
859     { \
860     type *d = (type *) buf; \
861     for (x = 0; x < width; x++) \
862     d[x] = (type) color; \
863     break; \
864 }
865     switch(bpp)
866     {
867         case 1: COLORFILL_ROW(BYTE)
868                 case 2: COLORFILL_ROW(WORD)
869         case 3:
870         {
871             BYTE *d = buf;
872             for (x = 0; x < width; x++,d+=3)
873             {
874                 d[0] = (color    ) & 0xFF;
875                 d[1] = (color>> 8) & 0xFF;
876                 d[2] = (color>>16) & 0xFF;
877             }
878             break;
879         }
880         case 4: COLORFILL_ROW(DWORD)
881         default:
882             FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
883             return WINED3DERR_NOTAVAILABLE;
884     }
885
886 #undef COLORFILL_ROW
887
888     /* Now copy first row */
889     first = buf;
890     for (y = 1; y < height; y++)
891     {
892         buf += lPitch;
893         memcpy(buf, first, width * bpp);
894     }
895     return WINED3D_OK;
896 }
897
898 /*****************************************************************************
899  * IWineD3DSurface::Blt, SW emulation version
900  *
901  * Performs blits to a surface, eigher from a source of source-less blts
902  * This is the main functionality of DirectDraw
903  *
904  * Params:
905  *  DestRect: Destination rectangle to write to
906  *  SrcSurface: Source surface, can be NULL
907  *  SrcRect: Source rectangle
908  *****************************************************************************/
909 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
910         const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
911 {
912     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
913     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
914     RECT        xdst,xsrc;
915     HRESULT     ret = WINED3D_OK;
916     WINED3DLOCKED_RECT  dlock, slock;
917     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
918     const struct GlPixelFormatDesc *sEntry, *dEntry;
919     int x, y;
920     const BYTE *sbuf;
921     BYTE *dbuf;
922     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
923
924     if (TRACE_ON(d3d_surface))
925     {
926         if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
927             DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
928         if (SrcRect) TRACE("\tsrcrect  :%dx%d-%dx%d\n",
929             SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
930 #if 0
931         TRACE("\tflags: ");
932                       DDRAW_dump_DDBLT(Flags);
933                       if (Flags & WINEDDBLT_DDFX)
934               {
935                       TRACE("\tblitfx: ");
936                       DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
937     }
938 #endif
939     }
940
941     if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
942     {
943         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
944         return WINEDDERR_SURFACEBUSY;
945     }
946
947     if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
948         /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
949         FIXME("Filters not supported in software blit\n");
950     }
951
952     /* First check for the validity of source / destination rectangles. This was
953      * verified using a test application + by MSDN.
954      */
955     if ((Src != NULL) && (SrcRect != NULL) &&
956          ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
957          (SrcRect->top     > Src->currentDesc.Height)||(SrcRect->top    < 0) ||
958          (SrcRect->left    > Src->currentDesc.Width) ||(SrcRect->left   < 0) ||
959          (SrcRect->right   > Src->currentDesc.Width) ||(SrcRect->right  < 0) ||
960          (SrcRect->right   < SrcRect->left)          ||(SrcRect->bottom < SrcRect->top)))
961     {
962         WARN("Application gave us bad source rectangle for Blt.\n");
963         return WINEDDERR_INVALIDRECT;
964     }
965     /* For the Destination rect, it can be out of bounds on the condition that a clipper
966      * is set for the given surface.
967      */
968     if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
969          ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
970          (DestRect->top     > This->currentDesc.Height)||(DestRect->top    < 0) ||
971          (DestRect->left    > This->currentDesc.Width) ||(DestRect->left   < 0) ||
972          (DestRect->right   > This->currentDesc.Width) ||(DestRect->right  < 0) ||
973          (DestRect->right   < DestRect->left)          ||(DestRect->bottom < DestRect->top)))
974     {
975         WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
976         return WINEDDERR_INVALIDRECT;
977     }
978
979     /* Now handle negative values in the rectangles. Warning: only supported for now
980     in the 'simple' cases (ie not in any stretching / rotation cases).
981
982     First, the case where nothing is to be done.
983     */
984     if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0)  ||
985           (DestRect->top    >= (int) This->currentDesc.Height) ||
986           (DestRect->left   >= (int) This->currentDesc.Width))) ||
987           ((Src != NULL) && (SrcRect != NULL) &&
988           ((SrcRect->bottom <= 0) || (SrcRect->right <= 0)     ||
989           (SrcRect->top >= (int) Src->currentDesc.Height) ||
990           (SrcRect->left >= (int) Src->currentDesc.Width))  ))
991     {
992         TRACE("Nothing to be done !\n");
993         return  WINED3D_OK;
994     }
995
996     if (DestRect)
997     {
998         xdst = *DestRect;
999     }
1000     else
1001     {
1002         xdst.top    = 0;
1003         xdst.bottom = This->currentDesc.Height;
1004         xdst.left   = 0;
1005         xdst.right  = This->currentDesc.Width;
1006     }
1007
1008     if (SrcRect)
1009     {
1010         xsrc = *SrcRect;
1011     }
1012     else
1013     {
1014         if (Src)
1015         {
1016             xsrc.top    = 0;
1017             xsrc.bottom = Src->currentDesc.Height;
1018             xsrc.left   = 0;
1019             xsrc.right  = Src->currentDesc.Width;
1020         }
1021         else
1022         {
1023             memset(&xsrc,0,sizeof(xsrc));
1024         }
1025     }
1026
1027     /* The easy case : the source-less blits.... */
1028     if (Src == NULL && DestRect)
1029     {
1030         RECT full_rect;
1031         RECT temp_rect; /* No idea if intersect rect can be the same as one of the source 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(&temp_rect, &full_rect, DestRect);
1038         xdst = temp_rect;
1039     }
1040     else if (DestRect)
1041     {
1042         /* Only handle clipping on the destination rectangle */
1043         int clip_horiz = (DestRect->left < 0) || (DestRect->right  > (int) This->currentDesc.Width );
1044         int clip_vert  = (DestRect->top  < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1045         if (clip_vert || clip_horiz)
1046         {
1047             /* Now check if this is a special case or not... */
1048             if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1049                    (((DestRect->right  - DestRect->left) != (xsrc.right  - xsrc.left)) && clip_horiz) ||
1050                    (Flags & WINEDDBLT_DDFX))
1051             {
1052                 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1053                 return  WINED3D_OK;
1054             }
1055
1056             if (clip_horiz)
1057             {
1058                 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1059                 if (DestRect->right > This->currentDesc.Width)
1060                 {
1061                     xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1062                     xdst.right = (int) This->currentDesc.Width;
1063                 }
1064             }
1065             if (clip_vert)
1066             {
1067                 if (DestRect->top < 0)
1068                 {
1069                     xsrc.top -= DestRect->top;
1070                     xdst.top = 0;
1071                 }
1072                 if (DestRect->bottom > This->currentDesc.Height)
1073                 {
1074                     xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1075                     xdst.bottom = (int) This->currentDesc.Height;
1076                 }
1077             }
1078             /* And check if after clipping something is still to be done... */
1079             if ((xdst.bottom <= 0)   || (xdst.right <= 0)       ||
1080                  (xdst.top   >= (int) This->currentDesc.Height)  ||
1081                  (xdst.left  >= (int) This->currentDesc.Width)   ||
1082                  (xsrc.bottom <= 0)   || (xsrc.right <= 0)       ||
1083                  (xsrc.top >= (int) Src->currentDesc.Height)     ||
1084                  (xsrc.left >= (int) Src->currentDesc.Width))
1085             {
1086                 TRACE("Nothing to be done after clipping !\n");
1087                 return  WINED3D_OK;
1088             }
1089         }
1090     }
1091
1092     if (Src == This)
1093     {
1094         IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1095         slock = dlock;
1096         sEntry = This->resource.format_desc;
1097         dEntry = sEntry;
1098     }
1099     else
1100     {
1101         dEntry = This->resource.format_desc;
1102         if (Src)
1103         {
1104             if (This->resource.format_desc->format != Src->resource.format_desc->format)
1105             {
1106                 Src = surface_convert_format(Src, dEntry->format);
1107                 if(!Src) {
1108                     /* The conv function writes a FIXME */
1109                     WARN("Cannot convert source surface format to dest format\n");
1110                     goto release;
1111                 }
1112             }
1113             IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1114             sEntry = Src->resource.format_desc;
1115         }
1116         else
1117         {
1118             sEntry = dEntry;
1119         }
1120         if (DestRect)
1121             IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1122         else
1123             IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1124     }
1125
1126     if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1127
1128     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1129     {
1130         if (!DestRect || Src == This)
1131         {
1132             memcpy(dlock.pBits, slock.pBits, This->resource.size);
1133             goto release;
1134         }
1135     }
1136
1137     bpp = This->resource.format_desc->byte_count;
1138     srcheight = xsrc.bottom - xsrc.top;
1139     srcwidth = xsrc.right - xsrc.left;
1140     dstheight = xdst.bottom - xdst.top;
1141     dstwidth = xdst.right - xdst.left;
1142     width = (xdst.right - xdst.left) * bpp;
1143
1144     if (DestRect && Src != This)
1145         dbuf = dlock.pBits;
1146     else
1147         dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1148
1149     if (Flags & WINEDDBLT_WAIT)
1150     {
1151         Flags &= ~WINEDDBLT_WAIT;
1152     }
1153     if (Flags & WINEDDBLT_ASYNC)
1154     {
1155         static BOOL displayed = FALSE;
1156         if (!displayed)
1157             FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1158         displayed = TRUE;
1159         Flags &= ~WINEDDBLT_ASYNC;
1160     }
1161     if (Flags & WINEDDBLT_DONOTWAIT)
1162     {
1163         /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1164         static BOOL displayed = FALSE;
1165         if (!displayed)
1166             FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1167         displayed = TRUE;
1168         Flags &= ~WINEDDBLT_DONOTWAIT;
1169     }
1170
1171     /* First, all the 'source-less' blits */
1172     if (Flags & WINEDDBLT_COLORFILL)
1173     {
1174         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1175                              dlock.Pitch, DDBltFx->u5.dwFillColor);
1176         Flags &= ~WINEDDBLT_COLORFILL;
1177     }
1178
1179     if (Flags & WINEDDBLT_DEPTHFILL)
1180     {
1181         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1182     }
1183     if (Flags & WINEDDBLT_ROP)
1184     {
1185         /* Catch some degenerate cases here */
1186         switch(DDBltFx->dwROP)
1187         {
1188             case BLACKNESS:
1189                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1190                 break;
1191                 case 0xAA0029: /* No-op */
1192                     break;
1193             case WHITENESS:
1194                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1195                 break;
1196                 case SRCCOPY: /* well, we do that below ? */
1197                     break;
1198             default:
1199                 FIXME("Unsupported raster op: %08x  Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1200                 goto error;
1201         }
1202         Flags &= ~WINEDDBLT_ROP;
1203     }
1204     if (Flags & WINEDDBLT_DDROPS)
1205     {
1206         FIXME("\tDdraw Raster Ops: %08x  Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1207     }
1208     /* Now the 'with source' blits */
1209     if (Src)
1210     {
1211         const BYTE *sbase;
1212         int sx, xinc, sy, yinc;
1213
1214         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1215             goto release;
1216         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1217         xinc = (srcwidth << 16) / dstwidth;
1218         yinc = (srcheight << 16) / dstheight;
1219
1220         if (!Flags)
1221         {
1222             /* No effects, we can cheat here */
1223             if (dstwidth == srcwidth)
1224             {
1225                 if (dstheight == srcheight)
1226                 {
1227                     /* No stretching in either direction. This needs to be as
1228                     * fast as possible */
1229                     sbuf = sbase;
1230
1231                     /* check for overlapping surfaces */
1232                     if (Src != This || xdst.top < xsrc.top ||
1233                         xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1234                     {
1235                         /* no overlap, or dst above src, so copy from top downwards */
1236                         for (y = 0; y < dstheight; y++)
1237                         {
1238                             memcpy(dbuf, sbuf, width);
1239                             sbuf += slock.Pitch;
1240                             dbuf += dlock.Pitch;
1241                         }
1242                     }
1243                     else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
1244                     {
1245                         sbuf += (slock.Pitch*dstheight);
1246                         dbuf += (dlock.Pitch*dstheight);
1247                         for (y = 0; y < dstheight; y++)
1248                         {
1249                             sbuf -= slock.Pitch;
1250                             dbuf -= dlock.Pitch;
1251                             memcpy(dbuf, sbuf, width);
1252                         }
1253                     }
1254                     else /* src and dst overlapping on the same line, use memmove */
1255                     {
1256                         for (y = 0; y < dstheight; y++)
1257                         {
1258                             memmove(dbuf, sbuf, width);
1259                             sbuf += slock.Pitch;
1260                             dbuf += dlock.Pitch;
1261                         }
1262                     }
1263                 } else {
1264                     /* Stretching in Y direction only */
1265                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1266                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1267                         memcpy(dbuf, sbuf, width);
1268                         dbuf += dlock.Pitch;
1269                     }
1270                 }
1271             }
1272             else
1273             {
1274                 /* Stretching in X direction */
1275                 int last_sy = -1;
1276                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1277                 {
1278                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1279
1280                     if ((sy >> 16) == (last_sy >> 16))
1281                     {
1282                         /* this sourcerow is the same as last sourcerow -
1283                         * copy already stretched row
1284                         */
1285                         memcpy(dbuf, dbuf - dlock.Pitch, width);
1286                     }
1287                     else
1288                     {
1289 #define STRETCH_ROW(type) { \
1290                         const type *s = (const type *)sbuf; \
1291                         type *d = (type *)dbuf; \
1292                         for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1293                         d[x] = s[sx >> 16]; \
1294                         break; }
1295
1296                         switch(bpp)
1297                         {
1298                             case 1: STRETCH_ROW(BYTE)
1299                                     case 2: STRETCH_ROW(WORD)
1300                                             case 4: STRETCH_ROW(DWORD)
1301                             case 3:
1302                             {
1303                                 const BYTE *s;
1304                                 BYTE *d = dbuf;
1305                                 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1306                                 {
1307                                     DWORD pixel;
1308
1309                                     s = sbuf+3*(sx>>16);
1310                                     pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1311                                     d[0] = (pixel    )&0xff;
1312                                     d[1] = (pixel>> 8)&0xff;
1313                                     d[2] = (pixel>>16)&0xff;
1314                                     d+=3;
1315                                 }
1316                                 break;
1317                             }
1318                             default:
1319                                 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1320                                 ret = WINED3DERR_NOTAVAILABLE;
1321                                 goto error;
1322                         }
1323 #undef STRETCH_ROW
1324                     }
1325                     dbuf += dlock.Pitch;
1326                     last_sy = sy;
1327                 }
1328             }
1329         }
1330         else
1331         {
1332             LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1333             DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1334             DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1335             if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1336             {
1337                 /* The color keying flags are checked for correctness in ddraw */
1338                 if (Flags & WINEDDBLT_KEYSRC)
1339                 {
1340                     keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1341                     keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1342                 }
1343                 else  if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1344                 {
1345                     keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1346                     keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1347                 }
1348
1349                 if (Flags & WINEDDBLT_KEYDEST)
1350                 {
1351                     /* Destination color keys are taken from the source surface ! */
1352                     destkeylow  = Src->DestBltCKey.dwColorSpaceLowValue;
1353                     destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1354                 }
1355                 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1356                 {
1357                     destkeylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1358                     destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1359                 }
1360
1361                 if(bpp == 1)
1362                 {
1363                     keymask = 0xff;
1364                 }
1365                 else
1366                 {
1367                     keymask = sEntry->red_mask
1368                             | sEntry->green_mask
1369                             | sEntry->blue_mask;
1370                 }
1371                 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1372             }
1373
1374             if (Flags & WINEDDBLT_DDFX)
1375             {
1376                 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1377                 LONG tmpxy;
1378                 dTopLeft     = dbuf;
1379                 dTopRight    = dbuf+((dstwidth-1)*bpp);
1380                 dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
1381                 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1382
1383                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1384                 {
1385                     /* I don't think we need to do anything about this flag */
1386                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1387                 }
1388                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1389                 {
1390                     tmp          = dTopRight;
1391                     dTopRight    = dTopLeft;
1392                     dTopLeft     = tmp;
1393                     tmp          = dBottomRight;
1394                     dBottomRight = dBottomLeft;
1395                     dBottomLeft  = tmp;
1396                     dstxinc = dstxinc *-1;
1397                 }
1398                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1399                 {
1400                     tmp          = dTopLeft;
1401                     dTopLeft     = dBottomLeft;
1402                     dBottomLeft  = tmp;
1403                     tmp          = dTopRight;
1404                     dTopRight    = dBottomRight;
1405                     dBottomRight = tmp;
1406                     dstyinc = dstyinc *-1;
1407                 }
1408                 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1409                 {
1410                     /* I don't think we need to do anything about this flag */
1411                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1412                 }
1413                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1414                 {
1415                     tmp          = dBottomRight;
1416                     dBottomRight = dTopLeft;
1417                     dTopLeft     = tmp;
1418                     tmp          = dBottomLeft;
1419                     dBottomLeft  = dTopRight;
1420                     dTopRight    = tmp;
1421                     dstxinc = dstxinc * -1;
1422                     dstyinc = dstyinc * -1;
1423                 }
1424                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1425                 {
1426                     tmp          = dTopLeft;
1427                     dTopLeft     = dBottomLeft;
1428                     dBottomLeft  = dBottomRight;
1429                     dBottomRight = dTopRight;
1430                     dTopRight    = tmp;
1431                     tmpxy   = dstxinc;
1432                     dstxinc = dstyinc;
1433                     dstyinc = tmpxy;
1434                     dstxinc = dstxinc * -1;
1435                 }
1436                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1437                 {
1438                     tmp          = dTopLeft;
1439                     dTopLeft     = dTopRight;
1440                     dTopRight    = dBottomRight;
1441                     dBottomRight = dBottomLeft;
1442                     dBottomLeft  = tmp;
1443                     tmpxy   = dstxinc;
1444                     dstxinc = dstyinc;
1445                     dstyinc = tmpxy;
1446                     dstyinc = dstyinc * -1;
1447                 }
1448                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1449                 {
1450                     /* I don't think we need to do anything about this flag */
1451                     WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1452                 }
1453                 dbuf = dTopLeft;
1454                 Flags &= ~(WINEDDBLT_DDFX);
1455             }
1456
1457 #define COPY_COLORKEY_FX(type) { \
1458             const type *s; \
1459             type *d = (type *)dbuf, *dx, tmp; \
1460             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1461             s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1462             dx = d; \
1463             for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1464             tmp = s[sx >> 16]; \
1465             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1466             ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1467             dx[0] = tmp; \
1468         } \
1469             dx = (type*)(((LPBYTE)dx)+dstxinc); \
1470         } \
1471             d = (type*)(((LPBYTE)d)+dstyinc); \
1472         } \
1473             break; }
1474
1475             switch (bpp) {
1476                 case 1: COPY_COLORKEY_FX(BYTE)
1477                         case 2: COPY_COLORKEY_FX(WORD)
1478                                 case 4: COPY_COLORKEY_FX(DWORD)
1479                 case 3:
1480                 {
1481                     const BYTE *s;
1482                     BYTE *d = dbuf, *dx;
1483                     for (y = sy = 0; y < dstheight; y++, sy += yinc)
1484                     {
1485                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1486                         dx = d;
1487                         for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1488                         {
1489                             DWORD pixel, dpixel = 0;
1490                             s = sbuf+3*(sx>>16);
1491                             pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1492                             dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1493                             if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1494                                   ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1495                             {
1496                                 dx[0] = (pixel    )&0xff;
1497                                 dx[1] = (pixel>> 8)&0xff;
1498                                 dx[2] = (pixel>>16)&0xff;
1499                             }
1500                             dx+= dstxinc;
1501                         }
1502                         d += dstyinc;
1503                     }
1504                     break;
1505                 }
1506                 default:
1507                     FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1508                           (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1509                     ret = WINED3DERR_NOTAVAILABLE;
1510                     goto error;
1511 #undef COPY_COLORKEY_FX
1512             }
1513         }
1514     }
1515
1516 error:
1517     if (Flags && FIXME_ON(d3d_surface))
1518     {
1519         FIXME("\tUnsupported flags: %08x\n", Flags);
1520     }
1521
1522 release:
1523     IWineD3DSurface_UnlockRect(iface);
1524     if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1525     /* Release the converted surface if any */
1526     if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1527     return ret;
1528 }
1529
1530 /*****************************************************************************
1531  * IWineD3DSurface::BltFast, SW emulation version
1532  *
1533  * This is the software implementation of BltFast, as used by GDI surfaces
1534  * and as a fallback for OpenGL surfaces. This code is taken from the old
1535  * DirectDraw code, and was originally written by TransGaming.
1536  *
1537  * Params:
1538  *  dstx:
1539  *  dsty:
1540  *  Source: Source surface to copy from
1541  *  rsrc: Source rectangle
1542  *  trans: Some Flags
1543  *
1544  * Returns:
1545  *  WINED3D_OK on success
1546  *
1547  *****************************************************************************/
1548 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1549         IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1550 {
1551     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1552     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1553
1554     int                 bpp, w, h, x, y;
1555     WINED3DLOCKED_RECT  dlock,slock;
1556     HRESULT             ret = WINED3D_OK;
1557     RECT                rsrc2;
1558     RECT                lock_src, lock_dst, lock_union;
1559     const BYTE          *sbuf;
1560     BYTE                *dbuf;
1561     const struct GlPixelFormatDesc *sEntry, *dEntry;
1562
1563     if (TRACE_ON(d3d_surface))
1564     {
1565         TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1566
1567         if (rsrc)
1568         {
1569             TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1570                   rsrc->right,rsrc->bottom);
1571         }
1572         else
1573         {
1574             TRACE(" srcrect: NULL\n");
1575         }
1576     }
1577
1578     if ((This->Flags & SFLAG_LOCKED) ||
1579             (Src->Flags & SFLAG_LOCKED))
1580     {
1581         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1582         return WINEDDERR_SURFACEBUSY;
1583     }
1584
1585     if (!rsrc)
1586     {
1587         WARN("rsrc is NULL!\n");
1588         rsrc2.left = 0;
1589         rsrc2.top = 0;
1590         rsrc2.right = Src->currentDesc.Width;
1591         rsrc2.bottom = Src->currentDesc.Height;
1592         rsrc = &rsrc2;
1593     }
1594
1595     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1596     if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1597          (rsrc->top    > Src->currentDesc.Height) || (rsrc->top    < 0) ||
1598          (rsrc->left   > Src->currentDesc.Width)  || (rsrc->left   < 0) ||
1599          (rsrc->right  > Src->currentDesc.Width)  || (rsrc->right  < 0) ||
1600          (rsrc->right  < rsrc->left)              || (rsrc->bottom < rsrc->top))
1601     {
1602         WARN("Application gave us bad source rectangle for BltFast.\n");
1603         return WINEDDERR_INVALIDRECT;
1604     }
1605
1606     h = rsrc->bottom - rsrc->top;
1607     if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1608     if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1609     if (h <= 0) return WINEDDERR_INVALIDRECT;
1610
1611     w = rsrc->right - rsrc->left;
1612     if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1613     if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1614     if (w <= 0) return WINEDDERR_INVALIDRECT;
1615
1616     /* Now compute the locking rectangle... */
1617     lock_src.left = rsrc->left;
1618     lock_src.top = rsrc->top;
1619     lock_src.right = lock_src.left + w;
1620     lock_src.bottom = lock_src.top + h;
1621
1622     lock_dst.left = dstx;
1623     lock_dst.top = dsty;
1624     lock_dst.right = dstx + w;
1625     lock_dst.bottom = dsty + h;
1626
1627     bpp = This->resource.format_desc->byte_count;
1628
1629     /* We need to lock the surfaces, or we won't get refreshes when done. */
1630     if (Src == This)
1631     {
1632         int pitch;
1633
1634         UnionRect(&lock_union, &lock_src, &lock_dst);
1635
1636         /* Lock the union of the two rectangles */
1637         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1638         if(ret != WINED3D_OK) goto error;
1639
1640         pitch = dlock.Pitch;
1641         slock.Pitch = dlock.Pitch;
1642
1643         /* Since slock was originally copied from this surface's description, we can just reuse it */
1644         sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1645         dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1646         sEntry = Src->resource.format_desc;
1647         dEntry = sEntry;
1648     }
1649     else
1650     {
1651         ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1652         if(ret != WINED3D_OK) goto error;
1653         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1654         if(ret != WINED3D_OK) goto error;
1655
1656         sbuf = slock.pBits;
1657         dbuf = dlock.pBits;
1658         TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1659
1660         sEntry = Src->resource.format_desc;
1661         dEntry = This->resource.format_desc;
1662     }
1663
1664     /* Handle compressed surfaces first... */
1665     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1666     {
1667         UINT row_block_count;
1668
1669         TRACE("compressed -> compressed copy\n");
1670         if (trans)
1671             FIXME("trans arg not supported when a compressed surface is involved\n");
1672         if (dstx || dsty)
1673             FIXME("offset for destination surface is not supported\n");
1674         if (Src->resource.format_desc->format != This->resource.format_desc->format)
1675         {
1676             FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1677             ret = WINED3DERR_WRONGTEXTUREFORMAT;
1678             goto error;
1679         }
1680
1681         row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1682         for (y = 0; y < h; y += dEntry->block_height)
1683         {
1684             memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1685             dbuf += dlock.Pitch;
1686             sbuf += slock.Pitch;
1687         }
1688
1689         goto error;
1690     }
1691     if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1692     {
1693         /* TODO: Use the libtxc_dxtn.so shared library to do
1694          * software decompression
1695          */
1696         ERR("Software decompression not supported.\n");
1697         goto error;
1698     }
1699
1700     if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1701     {
1702         DWORD keylow, keyhigh;
1703         TRACE("Color keyed copy\n");
1704         if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1705         {
1706             keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1707             keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1708         }
1709         else
1710         {
1711             /* I'm not sure if this is correct */
1712             FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1713             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1714             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1715         }
1716
1717 #define COPYBOX_COLORKEY(type) { \
1718         const type *s = (const type *)sbuf; \
1719         type *d = (type *)dbuf; \
1720         type tmp; \
1721         for (y = 0; y < h; y++) { \
1722         for (x = 0; x < w; x++) { \
1723         tmp = s[x]; \
1724         if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1725     } \
1726         s = (const type *)((const BYTE *)s + slock.Pitch); \
1727         d = (type *)((BYTE *)d + dlock.Pitch); \
1728     } \
1729         break; \
1730     }
1731
1732         switch (bpp) {
1733             case 1: COPYBOX_COLORKEY(BYTE)
1734                     case 2: COPYBOX_COLORKEY(WORD)
1735                             case 4: COPYBOX_COLORKEY(DWORD)
1736             case 3:
1737             {
1738                 const BYTE *s;
1739                 BYTE *d;
1740                 DWORD tmp;
1741                 s = sbuf;
1742                 d = dbuf;
1743                 for (y = 0; y < h; y++)
1744                 {
1745                     for (x = 0; x < w * 3; x += 3)
1746                     {
1747                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1748                         if (tmp < keylow || tmp > keyhigh)
1749                         {
1750                             d[x + 0] = s[x + 0];
1751                             d[x + 1] = s[x + 1];
1752                             d[x + 2] = s[x + 2];
1753                         }
1754                     }
1755                     s += slock.Pitch;
1756                     d += dlock.Pitch;
1757                 }
1758                 break;
1759             }
1760             default:
1761                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1762                 ret = WINED3DERR_NOTAVAILABLE;
1763                 goto error;
1764         }
1765 #undef COPYBOX_COLORKEY
1766         TRACE("Copy Done\n");
1767     }
1768     else
1769     {
1770         int width = w * bpp;
1771         INT sbufpitch, dbufpitch;
1772
1773         TRACE("NO color key copy\n");
1774         /* Handle overlapping surfaces */
1775         if (sbuf < dbuf)
1776         {
1777             sbuf += (h - 1) * slock.Pitch;
1778             dbuf += (h - 1) * dlock.Pitch;
1779             sbufpitch = -slock.Pitch;
1780             dbufpitch = -dlock.Pitch;
1781         }
1782         else
1783         {
1784             sbufpitch = slock.Pitch;
1785             dbufpitch = dlock.Pitch;
1786         }
1787         for (y = 0; y < h; y++)
1788         {
1789             /* This is pretty easy, a line for line memcpy */
1790             memmove(dbuf, sbuf, width);
1791             sbuf += sbufpitch;
1792             dbuf += dbufpitch;
1793         }
1794         TRACE("Copy done\n");
1795     }
1796
1797 error:
1798     if (Src == This)
1799     {
1800         IWineD3DSurface_UnlockRect(iface);
1801     }
1802     else
1803     {
1804         IWineD3DSurface_UnlockRect(iface);
1805         IWineD3DSurface_UnlockRect(Source);
1806     }
1807
1808     return ret;
1809 }
1810
1811 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1812 {
1813     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1814
1815     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1816           This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1817
1818     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1819
1820     if (NULL == pRect)
1821     {
1822         pLockedRect->pBits = This->resource.allocatedMemory;
1823         This->lockedRect.left   = 0;
1824         This->lockedRect.top    = 0;
1825         This->lockedRect.right  = This->currentDesc.Width;
1826         This->lockedRect.bottom = This->currentDesc.Height;
1827
1828         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1829               &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1830               This->lockedRect.right, This->lockedRect.bottom);
1831     }
1832     else
1833     {
1834         const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
1835
1836         TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1837               pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1838
1839         if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1840         {
1841             /* Compressed textures are block based, so calculate the offset of
1842              * the block that contains the top-left pixel of the locked rectangle. */
1843             pLockedRect->pBits = This->resource.allocatedMemory
1844                     + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1845                     + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1846         }
1847         else
1848         {
1849             pLockedRect->pBits = This->resource.allocatedMemory +
1850                     (pLockedRect->Pitch * pRect->top) +
1851                     (pRect->left * format_desc->byte_count);
1852         }
1853         This->lockedRect.left   = pRect->left;
1854         This->lockedRect.top    = pRect->top;
1855         This->lockedRect.right  = pRect->right;
1856         This->lockedRect.bottom = pRect->bottom;
1857     }
1858
1859     /* No dirtifying is needed for this surface implementation */
1860     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1861
1862     return WINED3D_OK;
1863 }
1864
1865 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1866     ERR("Should not be called on base texture\n");
1867     return;
1868 }
1869
1870 /* TODO: think about moving this down to resource? */
1871 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1872 {
1873     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1874
1875     /* This should only be called for sysmem textures, it may be a good idea
1876      * to extend this to all pools at some point in the future  */
1877     if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1878     {
1879         FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1880     }
1881     return This->resource.allocatedMemory;
1882 }