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