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