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