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