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