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