wined3d: Implement a R5G6B5 to X8R8G8B8 surface format converter.
[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     /** From MSDN:
170      * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
171      * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
172      * GetContainer will return the Direct3D device used to create the surface.
173      */
174     if (This->container) {
175         container = This->container;
176     } else {
177         container = (IWineD3DBase *)This->resource.wineD3DDevice;
178     }
179
180     TRACE("Relaying to QueryInterface\n");
181     return IUnknown_QueryInterface(container, riid, ppContainer);
182 }
183
184 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
185     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
186
187     TRACE("(%p) : copying into %p\n", This, pDesc);
188     if(pDesc->Format != NULL)             *(pDesc->Format) = This->resource.format;
189     if(pDesc->Type != NULL)               *(pDesc->Type)   = This->resource.resourceType;
190     if(pDesc->Usage != NULL)              *(pDesc->Usage)              = This->resource.usage;
191     if(pDesc->Pool != NULL)               *(pDesc->Pool)               = This->resource.pool;
192     if(pDesc->Size != NULL)               *(pDesc->Size)               = This->resource.size;   /* dx8 only */
193     if(pDesc->MultiSampleType != NULL)    *(pDesc->MultiSampleType)    = This->currentDesc.MultiSampleType;
194     if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
195     if(pDesc->Width != NULL)              *(pDesc->Width)              = This->currentDesc.Width;
196     if(pDesc->Height != NULL)             *(pDesc->Height)             = This->currentDesc.Height;
197     return WINED3D_OK;
198 }
199
200 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
201     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
202     TRACE("(%p)->(%x)\n", This, Flags);
203
204     switch (Flags)
205     {
206         case WINEDDGBS_CANBLT:
207         case WINEDDGBS_ISBLTDONE:
208             return WINED3D_OK;
209
210         default:
211             return WINED3DERR_INVALIDCALL;
212     }
213 }
214
215 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
216     /* XXX: DDERR_INVALIDSURFACETYPE */
217
218     TRACE("(%p)->(%08x)\n",iface,Flags);
219     switch (Flags) {
220         case WINEDDGFS_CANFLIP:
221         case WINEDDGFS_ISFLIPDONE:
222             return WINED3D_OK;
223
224         default:
225             return WINED3DERR_INVALIDCALL;
226     }
227 }
228
229 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
230     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
231     TRACE("(%p)\n", This);
232
233     /* D3D8 and 9 loose full devices, ddraw only surfaces */
234     return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
235 }
236
237 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
238     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
239     TRACE("(%p)\n", This);
240
241     /* So far we don't lose anything :) */
242     This->Flags &= ~SFLAG_LOST;
243     return WINED3D_OK;
244 }
245
246 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
247     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
248     IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
249     TRACE("(%p)->(%p)\n", This, Pal);
250
251     if(This->palette == PalImpl) {
252         TRACE("Nop palette change\n");
253         return WINED3D_OK;
254     }
255
256     if(This->palette != NULL)
257         if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
258             This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
259
260     This->palette = PalImpl;
261
262     if(PalImpl != NULL) {
263         if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
264             (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
265         }
266
267         return IWineD3DSurface_RealizePalette(iface);
268     }
269     else return WINED3D_OK;
270 }
271
272 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
273 {
274     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
275     TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
276
277     if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
278         FIXME(" colorkey value not supported (%08x) !\n", Flags);
279         return WINED3DERR_INVALIDCALL;
280     }
281
282     /* Dirtify the surface, but only if a key was changed */
283     if(CKey) {
284         switch (Flags & ~WINEDDCKEY_COLORSPACE) {
285             case WINEDDCKEY_DESTBLT:
286                 This->DestBltCKey = *CKey;
287                 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
288                 break;
289
290             case WINEDDCKEY_DESTOVERLAY:
291                 This->DestOverlayCKey = *CKey;
292                 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
293                 break;
294
295             case WINEDDCKEY_SRCOVERLAY:
296                 This->SrcOverlayCKey = *CKey;
297                 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
298                 break;
299
300             case WINEDDCKEY_SRCBLT:
301                 This->SrcBltCKey = *CKey;
302                 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
303                 break;
304         }
305     }
306     else {
307         switch (Flags & ~WINEDDCKEY_COLORSPACE) {
308             case WINEDDCKEY_DESTBLT:
309                 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
310                 break;
311
312             case WINEDDCKEY_DESTOVERLAY:
313                 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
314                 break;
315
316             case WINEDDCKEY_SRCOVERLAY:
317                 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
318                 break;
319
320             case WINEDDCKEY_SRCBLT:
321                 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
322                 break;
323         }
324     }
325
326     return WINED3D_OK;
327 }
328
329 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
330     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
331     TRACE("(%p)->(%p)\n", This, Pal);
332
333     *Pal = (IWineD3DPalette *) This->palette;
334     return WINED3D_OK;
335 }
336
337 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
338     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
339     DWORD ret;
340     TRACE("(%p)\n", This);
341
342     /* DXTn formats don't have exact pitches as they are to the new row of blocks,
343     where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
344     ie pitch = (width/4) * bytes per block                                  */
345     if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
346         ret = ((This->currentDesc.Width + 3) >> 2) << 3;
347     else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
348              This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
349         ret = ((This->currentDesc.Width + 3) >> 2) << 4;
350     else {
351         unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
352         ret = This->bytesPerPixel * This->currentDesc.Width;  /* Bytes / row */
353         ret = (ret + alignment - 1) & ~(alignment - 1);
354     }
355     TRACE("(%p) Returning %d\n", This, ret);
356     return ret;
357 }
358
359 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
360     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
361     LONG w, h;
362
363     TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
364
365     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
366     {
367         TRACE("(%p): Not an overlay surface\n", This);
368         return WINEDDERR_NOTAOVERLAYSURFACE;
369     }
370
371     w = This->overlay_destrect.right - This->overlay_destrect.left;
372     h = This->overlay_destrect.bottom - This->overlay_destrect.top;
373     This->overlay_destrect.left = X;
374     This->overlay_destrect.top = Y;
375     This->overlay_destrect.right = X + w;
376     This->overlay_destrect.bottom = Y + h;
377
378     IWineD3DSurface_DrawOverlay(iface);
379
380     return WINED3D_OK;
381 }
382
383 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
384     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
385     HRESULT hr;
386
387     TRACE("(%p)->(%p,%p)\n", This, X, Y);
388
389     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
390     {
391         TRACE("(%p): Not an overlay surface\n", This);
392         return WINEDDERR_NOTAOVERLAYSURFACE;
393     }
394     if(This->overlay_dest == NULL) {
395         *X = 0; *Y = 0;
396         hr = WINEDDERR_OVERLAYNOTVISIBLE;
397     } else {
398         *X = This->overlay_destrect.left;
399         *Y = This->overlay_destrect.top;
400         hr = WINED3D_OK;
401     }
402
403     TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
404     return hr;
405 }
406
407 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
408     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
409     IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
410
411     FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
412
413     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
414     {
415         TRACE("(%p): Not an overlay surface\n", This);
416         return WINEDDERR_NOTAOVERLAYSURFACE;
417     }
418
419     return WINED3D_OK;
420 }
421
422 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
423         IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
424 {
425     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
426     IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
427     TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
428
429     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
430     {
431         WARN("(%p): Not an overlay surface\n", This);
432         return WINEDDERR_NOTAOVERLAYSURFACE;
433     } else if(!DstSurface) {
434         WARN("(%p): Dest surface is NULL\n", This);
435         return WINED3DERR_INVALIDCALL;
436     }
437
438     if(SrcRect) {
439         This->overlay_srcrect = *SrcRect;
440     } else {
441         This->overlay_srcrect.left = 0;
442         This->overlay_srcrect.top = 0;
443         This->overlay_srcrect.right = This->currentDesc.Width;
444         This->overlay_srcrect.bottom = This->currentDesc.Height;
445     }
446
447     if(DstRect) {
448         This->overlay_destrect = *DstRect;
449     } else {
450         This->overlay_destrect.left = 0;
451         This->overlay_destrect.top = 0;
452         This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
453         This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
454     }
455
456     if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
457         list_remove(&This->overlay_entry);
458     }
459
460     if(Flags & WINEDDOVER_SHOW) {
461         if(This->overlay_dest != Dst) {
462             This->overlay_dest = Dst;
463             list_add_tail(&Dst->overlays, &This->overlay_entry);
464         }
465     } else if(Flags & WINEDDOVER_HIDE) {
466         /* tests show that the rectangles are erased on hide */
467         This->overlay_srcrect.left   = 0; This->overlay_srcrect.top     = 0;
468         This->overlay_srcrect.right  = 0; This->overlay_srcrect.bottom  = 0;
469         This->overlay_destrect.left  = 0; This->overlay_destrect.top    = 0;
470         This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
471         This->overlay_dest = NULL;
472     }
473
474     IWineD3DSurface_DrawOverlay(iface);
475
476     return WINED3D_OK;
477 }
478
479 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
480 {
481     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
482     TRACE("(%p)->(%p)\n", This, clipper);
483
484     This->clipper = clipper;
485     return WINED3D_OK;
486 }
487
488 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
489 {
490     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
491     TRACE("(%p)->(%p)\n", This, clipper);
492
493     *clipper = This->clipper;
494     if(*clipper) {
495         IWineD3DClipper_AddRef(*clipper);
496     }
497     return WINED3D_OK;
498 }
499
500 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
501     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
502
503     TRACE("This %p, container %p\n", This, container);
504
505     /* We can't keep a reference to the container, since the container already keeps a reference to us. */
506
507     TRACE("Setting container to %p from %p\n", container, This->container);
508     This->container = container;
509
510     return WINED3D_OK;
511 }
512
513 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
514     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
515     const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(format, NULL, NULL);
516
517     if (This->resource.format != WINED3DFMT_UNKNOWN) {
518         FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
519         return WINED3DERR_INVALIDCALL;
520     }
521
522     TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
523     if (format == WINED3DFMT_UNKNOWN) {
524         This->resource.size = 0;
525     } else if (format == WINED3DFMT_DXT1) {
526         /* DXT1 is half byte per pixel */
527         This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
528
529     } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
530                format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
531         This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
532     } else {
533         unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
534         This->resource.size = ((This->pow2Width * formatEntry->bpp) + alignment - 1) & ~(alignment - 1);
535         This->resource.size *= This->pow2Height;
536     }
537
538     if (format != WINED3DFMT_UNKNOWN) {
539         This->bytesPerPixel = formatEntry->bpp;
540     } else {
541         This->bytesPerPixel = 0;
542     }
543
544     This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
545
546     This->resource.format = format;
547
548     TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, This->bytesPerPixel);
549
550     return WINED3D_OK;
551 }
552
553 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
554     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
555     int extraline = 0;
556     SYSTEM_INFO sysInfo;
557     BITMAPINFO* b_info;
558     HDC ddc;
559     DWORD *masks;
560     const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format, NULL, NULL);
561     UINT usage;
562
563     switch (This->bytesPerPixel) {
564         case 2:
565         case 4:
566             /* Allocate extra space to store the RGB bit masks. */
567             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
568             break;
569
570         case 3:
571             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
572             break;
573
574         default:
575             /* Allocate extra space for a palette. */
576             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
577                                sizeof(BITMAPINFOHEADER)
578                                + sizeof(RGBQUAD)
579                                * (1 << (This->bytesPerPixel * 8)));
580             break;
581     }
582
583     if (!b_info)
584         return E_OUTOFMEMORY;
585
586         /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
587     * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
588     * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
589     * add an extra line to the dib section
590         */
591     GetSystemInfo(&sysInfo);
592     if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
593         extraline = 1;
594         TRACE("Adding an extra line to the dib section\n");
595     }
596
597     b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
598     /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
599     b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / This->bytesPerPixel;
600     b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
601     b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
602     b_info->bmiHeader.biPlanes = 1;
603     b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
604
605     b_info->bmiHeader.biXPelsPerMeter = 0;
606     b_info->bmiHeader.biYPelsPerMeter = 0;
607     b_info->bmiHeader.biClrUsed = 0;
608     b_info->bmiHeader.biClrImportant = 0;
609
610     /* Get the bit masks */
611     masks = (DWORD *)b_info->bmiColors;
612     switch (This->resource.format) {
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_A2B10G10R10:
625         case WINED3DFMT_A8B8G8R8:
626         case WINED3DFMT_X8B8G8R8:
627         case WINED3DFMT_A2R10G10B10:
628         case WINED3DFMT_R5G6B5:
629         case WINED3DFMT_A16B16G16R16:
630             usage = 0;
631             b_info->bmiHeader.biCompression = BI_BITFIELDS;
632             masks[0] = formatEntry->redMask;
633             masks[1] = formatEntry->greenMask;
634             masks[2] = formatEntry->blueMask;
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_r32f_r16f(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_R32F,       WINED3DFMT_R16F,        convert_r32f_r16f},
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, to_fmt);
785     if(!conv) {
786         FIXME("Cannot find a conversion function from format %s to %s\n",
787               debug_d3dformat(source->resource.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     WINED3DFORMAT       dfmt = WINED3DFMT_UNKNOWN, sfmt = WINED3DFMT_UNKNOWN;
922     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
923     int x, y;
924     const StaticPixelFormatDesc *sEntry, *dEntry;
925     const BYTE *sbuf;
926     BYTE *dbuf;
927     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
928
929     if (TRACE_ON(d3d_surface))
930     {
931         if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
932             DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
933         if (SrcRect) TRACE("\tsrcrect  :%dx%d-%dx%d\n",
934             SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
935 #if 0
936         TRACE("\tflags: ");
937                       DDRAW_dump_DDBLT(Flags);
938                       if (Flags & WINEDDBLT_DDFX)
939               {
940                       TRACE("\tblitfx: ");
941                       DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
942     }
943 #endif
944     }
945
946     if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
947     {
948         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
949         return WINEDDERR_SURFACEBUSY;
950     }
951
952     if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
953         /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
954         FIXME("Filters not supported in software blit\n");
955     }
956
957     /* First check for the validity of source / destination rectangles. This was
958      * verified using a test application + by MSDN.
959      */
960     if ((Src != NULL) && (SrcRect != NULL) &&
961          ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
962          (SrcRect->top     > Src->currentDesc.Height)||(SrcRect->top    < 0) ||
963          (SrcRect->left    > Src->currentDesc.Width) ||(SrcRect->left   < 0) ||
964          (SrcRect->right   > Src->currentDesc.Width) ||(SrcRect->right  < 0) ||
965          (SrcRect->right   < SrcRect->left)          ||(SrcRect->bottom < SrcRect->top)))
966     {
967         WARN("Application gave us bad source rectangle for Blt.\n");
968         return WINEDDERR_INVALIDRECT;
969     }
970     /* For the Destination rect, it can be out of bounds on the condition that a clipper
971      * is set for the given surface.
972      */
973     if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
974          ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
975          (DestRect->top     > This->currentDesc.Height)||(DestRect->top    < 0) ||
976          (DestRect->left    > This->currentDesc.Width) ||(DestRect->left   < 0) ||
977          (DestRect->right   > This->currentDesc.Width) ||(DestRect->right  < 0) ||
978          (DestRect->right   < DestRect->left)          ||(DestRect->bottom < DestRect->top)))
979     {
980         WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
981         return WINEDDERR_INVALIDRECT;
982     }
983
984     /* Now handle negative values in the rectangles. Warning: only supported for now
985     in the 'simple' cases (ie not in any stretching / rotation cases).
986
987     First, the case where nothing is to be done.
988     */
989     if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0)  ||
990           (DestRect->top    >= (int) This->currentDesc.Height) ||
991           (DestRect->left   >= (int) This->currentDesc.Width))) ||
992           ((Src != NULL) && (SrcRect != NULL) &&
993           ((SrcRect->bottom <= 0) || (SrcRect->right <= 0)     ||
994           (SrcRect->top >= (int) Src->currentDesc.Height) ||
995           (SrcRect->left >= (int) Src->currentDesc.Width))  ))
996     {
997         TRACE("Nothing to be done !\n");
998         return  WINED3D_OK;
999     }
1000
1001     if (DestRect)
1002     {
1003         xdst = *DestRect;
1004     }
1005     else
1006     {
1007         xdst.top    = 0;
1008         xdst.bottom = This->currentDesc.Height;
1009         xdst.left   = 0;
1010         xdst.right  = This->currentDesc.Width;
1011     }
1012
1013     if (SrcRect)
1014     {
1015         xsrc = *SrcRect;
1016     }
1017     else
1018     {
1019         if (Src)
1020         {
1021             xsrc.top    = 0;
1022             xsrc.bottom = Src->currentDesc.Height;
1023             xsrc.left   = 0;
1024             xsrc.right  = Src->currentDesc.Width;
1025         }
1026         else
1027         {
1028             memset(&xsrc,0,sizeof(xsrc));
1029         }
1030     }
1031
1032     /* The easy case : the source-less blits.... */
1033     if (Src == NULL && DestRect)
1034     {
1035         RECT full_rect;
1036         RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1037
1038         full_rect.left   = 0;
1039         full_rect.top    = 0;
1040         full_rect.right  = This->currentDesc.Width;
1041         full_rect.bottom = This->currentDesc.Height;
1042         IntersectRect(&temp_rect, &full_rect, DestRect);
1043         xdst = temp_rect;
1044     }
1045     else if (DestRect)
1046     {
1047         /* Only handle clipping on the destination rectangle */
1048         int clip_horiz = (DestRect->left < 0) || (DestRect->right  > (int) This->currentDesc.Width );
1049         int clip_vert  = (DestRect->top  < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1050         if (clip_vert || clip_horiz)
1051         {
1052             /* Now check if this is a special case or not... */
1053             if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1054                    (((DestRect->right  - DestRect->left) != (xsrc.right  - xsrc.left)) && clip_horiz) ||
1055                    (Flags & WINEDDBLT_DDFX))
1056             {
1057                 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1058                 return  WINED3D_OK;
1059             }
1060
1061             if (clip_horiz)
1062             {
1063                 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1064                 if (DestRect->right > This->currentDesc.Width)
1065                 {
1066                     xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1067                     xdst.right = (int) This->currentDesc.Width;
1068                 }
1069             }
1070             if (clip_vert)
1071             {
1072                 if (DestRect->top < 0)
1073                 {
1074                     xsrc.top -= DestRect->top;
1075                     xdst.top = 0;
1076                 }
1077                 if (DestRect->bottom > This->currentDesc.Height)
1078                 {
1079                     xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1080                     xdst.bottom = (int) This->currentDesc.Height;
1081                 }
1082             }
1083             /* And check if after clipping something is still to be done... */
1084             if ((xdst.bottom <= 0)   || (xdst.right <= 0)       ||
1085                  (xdst.top   >= (int) This->currentDesc.Height)  ||
1086                  (xdst.left  >= (int) This->currentDesc.Width)   ||
1087                  (xsrc.bottom <= 0)   || (xsrc.right <= 0)       ||
1088                  (xsrc.top >= (int) Src->currentDesc.Height)     ||
1089                  (xsrc.left >= (int) Src->currentDesc.Width))
1090             {
1091                 TRACE("Nothing to be done after clipping !\n");
1092                 return  WINED3D_OK;
1093             }
1094         }
1095     }
1096
1097     if (Src == This)
1098     {
1099         IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1100         dfmt = This->resource.format;
1101         slock = dlock;
1102         sfmt = dfmt;
1103         sEntry = getFormatDescEntry(sfmt, NULL, NULL);
1104         dEntry = sEntry;
1105     }
1106     else
1107     {
1108         dfmt = This->resource.format;
1109         dEntry = getFormatDescEntry(dfmt, NULL, NULL);
1110         if (Src)
1111         {
1112             if(This->resource.format != Src->resource.format) {
1113                 Src = surface_convert_format(Src, dfmt);
1114                 if(!Src) {
1115                     /* The conv function writes a FIXME */
1116                     WARN("Cannot convert source surface format to dest format\n");
1117                     goto release;
1118                 }
1119             }
1120             IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1121             sfmt = Src->resource.format;
1122         }
1123         sEntry = getFormatDescEntry(sfmt, NULL, NULL);
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->isFourcc && dEntry->isFourcc)
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 = (BYTE*)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->redMask   |
1374                             sEntry->greenMask |
1375                             sEntry->blueMask;
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 StaticPixelFormatDesc *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 = getFormatDescEntry(Src->resource.format, NULL, NULL);
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 = getFormatDescEntry(Src->resource.format, NULL, NULL);
1668         dEntry = getFormatDescEntry(This->resource.format, NULL, NULL);
1669     }
1670
1671     /* Handle first the FOURCC surfaces... */
1672     if (sEntry->isFourcc && dEntry->isFourcc)
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 != This->resource.format)
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->isFourcc && !dEntry->isFourcc)
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 == WINED3DFMT_DXT1)
1843         {
1844             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2);
1845         }
1846         else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
1847                     This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5)
1848         {
1849             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4);
1850         }
1851         else
1852         {
1853             pLockedRect->pBits = This->resource.allocatedMemory +
1854                     (pLockedRect->Pitch * pRect->top) +
1855                     (pRect->left * This->bytesPerPixel);
1856         }
1857         This->lockedRect.left   = pRect->left;
1858         This->lockedRect.top    = pRect->top;
1859         This->lockedRect.right  = pRect->right;
1860         This->lockedRect.bottom = pRect->bottom;
1861     }
1862
1863     /* No dirtifying is needed for this surface implementation */
1864     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1865
1866     return WINED3D_OK;
1867 }
1868
1869 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface) {
1870     ERR("Should not be called on base texture\n");
1871     return;
1872 }
1873
1874 /* TODO: think about moving this down to resource? */
1875 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1876 {
1877     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1878
1879     /* This should only be called for sysmem textures, it may be a good idea
1880      * to extend this to all pools at some point in the future  */
1881     if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1882     {
1883         FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1884     }
1885     return This->resource.allocatedMemory;
1886 }