wined3d: Merge source rectangle operations into a single block in IWineD3DBaseSurface...
[wine/hacks.git] / dlls / wined3d / surface_base.c
blob4e964dafc581ec91cdbd96ebcd9390e1e2993a4e
1 /*
2 * IWineD3DSurface Implementation of management(non-rendering) functions
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 Henri Verbeet for CodeWeavers
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.
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.
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
30 #include "config.h"
31 #include "wine/port.h"
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
36 /* See also float_16_to_32() in wined3d_private.h */
37 static inline unsigned short float_32_to_16(const float *in)
39 int exp = 0;
40 float tmp = fabs(*in);
41 unsigned int mantissa;
42 unsigned short ret;
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);
49 if(tmp < pow(2, 10)) {
52 tmp = tmp * 2.0f;
53 exp--;
54 }while(tmp < pow(2, 10));
55 } else if(tmp >= pow(2, 11)) {
58 tmp /= 2.0f;
59 exp++;
60 }while(tmp >= pow(2, 11));
63 mantissa = (unsigned int) tmp;
64 if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
66 exp += 10; /* Normalize the mantissa */
67 exp += 15; /* Exponent is encoded with excess 15 */
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++;
77 ret = mantissa & 0x3ff;
78 } else {
79 ret = (exp << 10) | (mantissa & 0x3ff);
82 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
83 return ret;
87 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
89 /* *******************************************
90 IWineD3DSurface IUnknown parts follow
91 ******************************************* */
92 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
94 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
95 /* Warn ,but be nice about things */
96 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
98 if (IsEqualGUID(riid, &IID_IUnknown)
99 || IsEqualGUID(riid, &IID_IWineD3DBase)
100 || IsEqualGUID(riid, &IID_IWineD3DResource)
101 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
102 IUnknown_AddRef((IUnknown*)iface);
103 *ppobj = This;
104 return S_OK;
106 *ppobj = NULL;
107 return E_NOINTERFACE;
110 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
111 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
112 ULONG ref = InterlockedIncrement(&This->resource.ref);
113 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
114 return ref;
117 /* ****************************************************
118 IWineD3DSurface IWineD3DResource parts follow
119 **************************************************** */
120 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
121 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
124 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
125 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
128 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
129 return resource_free_private_data((IWineD3DResource *)iface, refguid);
132 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
133 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
136 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
137 return resource_get_priority((IWineD3DResource *)iface);
140 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
141 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
142 return resource_get_type((IWineD3DResource *)iface);
145 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
146 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
147 return resource_get_parent((IWineD3DResource *)iface, pParent);
150 /* ******************************************************
151 IWineD3DSurface IWineD3DSurface parts follow
152 ****************************************************** */
154 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
155 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
156 IWineD3DBase *container = 0;
158 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
160 if (!ppContainer) {
161 ERR("Called without a valid ppContainer.\n");
164 /* Standalone surfaces return the device as container. */
165 if (This->container) container = This->container;
166 else container = (IWineD3DBase *)This->resource.device;
168 TRACE("Relaying to QueryInterface\n");
169 return IUnknown_QueryInterface(container, riid, ppContainer);
172 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
173 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
175 TRACE("(%p) : copying into %p\n", This, pDesc);
177 pDesc->format = This->resource.format_desc->format;
178 pDesc->resource_type = This->resource.resourceType;
179 pDesc->usage = This->resource.usage;
180 pDesc->pool = This->resource.pool;
181 pDesc->size = This->resource.size; /* dx8 only */
182 pDesc->multisample_type = This->currentDesc.MultiSampleType;
183 pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
184 pDesc->width = This->currentDesc.Width;
185 pDesc->height = This->currentDesc.Height;
187 return WINED3D_OK;
190 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags)
192 TRACE("iface %p, flags %#x.\n", iface, Flags);
194 switch (Flags)
196 case WINEDDGBS_CANBLT:
197 case WINEDDGBS_ISBLTDONE:
198 return WINED3D_OK;
200 default:
201 return WINED3DERR_INVALIDCALL;
205 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
206 /* XXX: DDERR_INVALIDSURFACETYPE */
208 TRACE("(%p)->(%08x)\n",iface,Flags);
209 switch (Flags) {
210 case WINEDDGFS_CANFLIP:
211 case WINEDDGFS_ISFLIPDONE:
212 return WINED3D_OK;
214 default:
215 return WINED3DERR_INVALIDCALL;
219 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
220 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
221 TRACE("(%p)\n", This);
223 /* D3D8 and 9 loose full devices, ddraw only surfaces */
224 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
227 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
228 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
229 TRACE("(%p)\n", This);
231 /* So far we don't lose anything :) */
232 This->Flags &= ~SFLAG_LOST;
233 return WINED3D_OK;
236 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
237 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
238 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
239 TRACE("(%p)->(%p)\n", This, Pal);
241 if(This->palette == PalImpl) {
242 TRACE("Nop palette change\n");
243 return WINED3D_OK;
246 if(This->palette != NULL)
247 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
248 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
250 This->palette = PalImpl;
252 if(PalImpl != NULL) {
253 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
254 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
257 return IWineD3DSurface_RealizePalette(iface);
259 else return WINED3D_OK;
262 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
264 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
265 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
267 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
268 FIXME(" colorkey value not supported (%08x) !\n", Flags);
269 return WINED3DERR_INVALIDCALL;
272 /* Dirtify the surface, but only if a key was changed */
273 if(CKey) {
274 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
275 case WINEDDCKEY_DESTBLT:
276 This->DestBltCKey = *CKey;
277 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
278 break;
280 case WINEDDCKEY_DESTOVERLAY:
281 This->DestOverlayCKey = *CKey;
282 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
283 break;
285 case WINEDDCKEY_SRCOVERLAY:
286 This->SrcOverlayCKey = *CKey;
287 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
288 break;
290 case WINEDDCKEY_SRCBLT:
291 This->SrcBltCKey = *CKey;
292 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
293 break;
296 else {
297 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
298 case WINEDDCKEY_DESTBLT:
299 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
300 break;
302 case WINEDDCKEY_DESTOVERLAY:
303 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
304 break;
306 case WINEDDCKEY_SRCOVERLAY:
307 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
308 break;
310 case WINEDDCKEY_SRCBLT:
311 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
312 break;
316 return WINED3D_OK;
319 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
320 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
321 TRACE("(%p)->(%p)\n", This, Pal);
323 *Pal = (IWineD3DPalette *) This->palette;
324 return WINED3D_OK;
327 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
328 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
329 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
330 DWORD ret;
331 TRACE("(%p)\n", This);
333 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
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->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
338 ret = row_block_count * format_desc->block_byte_count;
340 else
342 unsigned char alignment = This->resource.device->surface_alignment;
343 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
344 ret = (ret + alignment - 1) & ~(alignment - 1);
346 TRACE("(%p) Returning %d\n", This, ret);
347 return ret;
350 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
351 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
352 LONG w, h;
354 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
356 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
358 TRACE("(%p): Not an overlay surface\n", This);
359 return WINEDDERR_NOTAOVERLAYSURFACE;
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;
369 IWineD3DSurface_DrawOverlay(iface);
371 return WINED3D_OK;
374 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
375 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
376 HRESULT hr;
378 TRACE("(%p)->(%p,%p)\n", This, X, Y);
380 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
382 TRACE("(%p): Not an overlay surface\n", This);
383 return WINEDDERR_NOTAOVERLAYSURFACE;
385 if(This->overlay_dest == NULL) {
386 *X = 0; *Y = 0;
387 hr = WINEDDERR_OVERLAYNOTVISIBLE;
388 } else {
389 *X = This->overlay_destrect.left;
390 *Y = This->overlay_destrect.top;
391 hr = WINED3D_OK;
394 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
395 return hr;
398 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
399 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
401 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, Flags, Ref);
403 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
405 TRACE("(%p): Not an overlay surface\n", This);
406 return WINEDDERR_NOTAOVERLAYSURFACE;
409 return WINED3D_OK;
412 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
413 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
415 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
416 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
417 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
419 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
421 WARN("(%p): Not an overlay surface\n", This);
422 return WINEDDERR_NOTAOVERLAYSURFACE;
423 } else if(!DstSurface) {
424 WARN("(%p): Dest surface is NULL\n", This);
425 return WINED3DERR_INVALIDCALL;
428 if(SrcRect) {
429 This->overlay_srcrect = *SrcRect;
430 } else {
431 This->overlay_srcrect.left = 0;
432 This->overlay_srcrect.top = 0;
433 This->overlay_srcrect.right = This->currentDesc.Width;
434 This->overlay_srcrect.bottom = This->currentDesc.Height;
437 if(DstRect) {
438 This->overlay_destrect = *DstRect;
439 } else {
440 This->overlay_destrect.left = 0;
441 This->overlay_destrect.top = 0;
442 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
443 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
446 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
447 list_remove(&This->overlay_entry);
450 if(Flags & WINEDDOVER_SHOW) {
451 if(This->overlay_dest != Dst) {
452 This->overlay_dest = Dst;
453 list_add_tail(&Dst->overlays, &This->overlay_entry);
455 } else if(Flags & WINEDDOVER_HIDE) {
456 /* tests show that the rectangles are erased on hide */
457 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
458 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
459 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
460 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
461 This->overlay_dest = NULL;
464 IWineD3DSurface_DrawOverlay(iface);
466 return WINED3D_OK;
469 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
471 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
472 TRACE("(%p)->(%p)\n", This, clipper);
474 This->clipper = clipper;
475 return WINED3D_OK;
478 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
480 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
481 TRACE("(%p)->(%p)\n", This, clipper);
483 *clipper = This->clipper;
484 if(*clipper) {
485 IWineD3DClipper_AddRef(*clipper);
487 return WINED3D_OK;
490 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
491 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
493 TRACE("This %p, container %p\n", This, container);
495 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
497 TRACE("Setting container to %p from %p\n", container, This->container);
498 This->container = container;
500 return WINED3D_OK;
503 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
504 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
505 const struct wined3d_format_desc *format_desc = getFormatDescEntry(format,
506 &This->resource.device->adapter->gl_info);
508 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
510 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
511 return WINED3DERR_INVALIDCALL;
514 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
516 This->resource.size = surface_calculate_size(format_desc, This->resource.device->surface_alignment,
517 This->pow2Width, This->pow2Height);
519 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
521 This->resource.format_desc = format_desc;
523 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
525 return WINED3D_OK;
528 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
529 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
530 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
531 int extraline = 0;
532 SYSTEM_INFO sysInfo;
533 BITMAPINFO* b_info;
534 HDC ddc;
535 DWORD *masks;
536 UINT usage;
538 if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
540 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
541 return WINED3DERR_INVALIDCALL;
544 switch (format_desc->byte_count)
546 case 2:
547 case 4:
548 /* Allocate extra space to store the RGB bit masks. */
549 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
550 break;
552 case 3:
553 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
554 break;
556 default:
557 /* Allocate extra space for a palette. */
558 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
559 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
560 break;
563 if (!b_info)
564 return E_OUTOFMEMORY;
566 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
567 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
568 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
569 * add an extra line to the dib section
571 GetSystemInfo(&sysInfo);
572 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
573 extraline = 1;
574 TRACE("Adding an extra line to the dib section\n");
577 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
578 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
579 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
580 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
581 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
582 b_info->bmiHeader.biPlanes = 1;
583 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
585 b_info->bmiHeader.biXPelsPerMeter = 0;
586 b_info->bmiHeader.biYPelsPerMeter = 0;
587 b_info->bmiHeader.biClrUsed = 0;
588 b_info->bmiHeader.biClrImportant = 0;
590 /* Get the bit masks */
591 masks = (DWORD *)b_info->bmiColors;
592 switch (This->resource.format_desc->format)
594 case WINED3DFMT_B8G8R8_UNORM:
595 usage = DIB_RGB_COLORS;
596 b_info->bmiHeader.biCompression = BI_RGB;
597 break;
599 case WINED3DFMT_B5G5R5X1_UNORM:
600 case WINED3DFMT_B5G5R5A1_UNORM:
601 case WINED3DFMT_B4G4R4A4_UNORM:
602 case WINED3DFMT_B4G4R4X4_UNORM:
603 case WINED3DFMT_B2G3R3_UNORM:
604 case WINED3DFMT_B2G3R3A8_UNORM:
605 case WINED3DFMT_R10G10B10A2_UNORM:
606 case WINED3DFMT_R8G8B8A8_UNORM:
607 case WINED3DFMT_R8G8B8X8_UNORM:
608 case WINED3DFMT_B10G10R10A2_UNORM:
609 case WINED3DFMT_B5G6R5_UNORM:
610 case WINED3DFMT_R16G16B16A16_UNORM:
611 usage = 0;
612 b_info->bmiHeader.biCompression = BI_BITFIELDS;
613 masks[0] = format_desc->red_mask;
614 masks[1] = format_desc->green_mask;
615 masks[2] = format_desc->blue_mask;
616 break;
618 default:
619 /* Don't know palette */
620 b_info->bmiHeader.biCompression = BI_RGB;
621 usage = 0;
622 break;
625 ddc = GetDC(0);
626 if (ddc == 0) {
627 HeapFree(GetProcessHeap(), 0, b_info);
628 return HRESULT_FROM_WIN32(GetLastError());
631 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);
632 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
633 ReleaseDC(0, ddc);
635 if (!This->dib.DIBsection) {
636 ERR("CreateDIBSection failed!\n");
637 HeapFree(GetProcessHeap(), 0, b_info);
638 return HRESULT_FROM_WIN32(GetLastError());
641 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
642 /* copy the existing surface to the dib section */
643 if(This->resource.allocatedMemory) {
644 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
645 } else {
646 /* This is to make LockRect read the gl Texture although memory is allocated */
647 This->Flags &= ~SFLAG_INSYSMEM;
649 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
651 HeapFree(GetProcessHeap(), 0, b_info);
653 /* Now allocate a HDC */
654 This->hDC = CreateCompatibleDC(0);
655 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
656 TRACE("using wined3d palette %p\n", This->palette);
657 SelectPalette(This->hDC,
658 This->palette ? This->palette->hpal : 0,
659 FALSE);
661 This->Flags |= SFLAG_DIBSECTION;
663 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
664 This->resource.heapMemory = NULL;
666 return WINED3D_OK;
669 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
670 unsigned int w, unsigned int h)
672 unsigned int x, y;
673 const float *src_f;
674 unsigned short *dst_s;
676 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
677 for(y = 0; y < h; y++) {
678 src_f = (const float *)(src + y * pitch_in);
679 dst_s = (unsigned short *) (dst + y * pitch_out);
680 for(x = 0; x < w; x++) {
681 dst_s[x] = float_32_to_16(src_f + x);
686 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
687 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
689 static const unsigned char convert_5to8[] =
691 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
692 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
693 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
694 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
696 static const unsigned char convert_6to8[] =
698 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
699 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
700 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
701 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
702 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
703 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
704 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
705 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
707 unsigned int x, y;
709 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
711 for (y = 0; y < h; ++y)
713 const WORD *src_line = (const WORD *)(src + y * pitch_in);
714 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
715 for (x = 0; x < w; ++x)
717 WORD pixel = src_line[x];
718 dst_line[x] = 0xff000000
719 | convert_5to8[(pixel & 0xf800) >> 11] << 16
720 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
721 | convert_5to8[(pixel & 0x001f)];
726 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
727 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
729 unsigned int x, y;
731 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
733 for (y = 0; y < h; ++y)
735 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
736 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
738 for (x = 0; x < w; ++x)
740 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
745 static inline BYTE cliptobyte(int x)
747 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
750 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
751 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
753 unsigned int x, y;
754 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
756 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
758 for (y = 0; y < h; ++y)
760 const BYTE *src_line = src + y * pitch_in;
761 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
762 for (x = 0; x < w; ++x)
764 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
765 * C = Y - 16; D = U - 128; E = V - 128;
766 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
767 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
768 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
769 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
770 * U and V are shared between the pixels.
772 if (!(x & 1)) /* for every even pixel, read new U and V */
774 d = (int) src_line[1] - 128;
775 e = (int) src_line[3] - 128;
776 r2 = 409 * e + 128;
777 g2 = - 100 * d - 208 * e + 128;
778 b2 = 516 * d + 128;
780 c2 = 298 * ((int) src_line[0] - 16);
781 dst_line[x] = 0xff000000
782 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
783 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
784 | cliptobyte((c2 + b2) >> 8); /* blue */
785 /* Scale RGB values to 0..255 range,
786 * then clip them if still not in range (may be negative),
787 * then shift them within DWORD if necessary.
789 src_line += 2;
794 struct d3dfmt_convertor_desc {
795 WINED3DFORMAT from, to;
796 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
799 static const struct d3dfmt_convertor_desc convertors[] =
801 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
802 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
803 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
804 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
807 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
809 unsigned int i;
810 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
811 if(convertors[i].from == from && convertors[i].to == to) {
812 return &convertors[i];
815 return NULL;
818 /*****************************************************************************
819 * surface_convert_format
821 * Creates a duplicate of a surface in a different format. Is used by Blt to
822 * blit between surfaces with different formats
824 * Parameters
825 * source: Source surface
826 * fmt: Requested destination format
828 *****************************************************************************/
829 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
830 IWineD3DSurface *ret = NULL;
831 const struct d3dfmt_convertor_desc *conv;
832 WINED3DLOCKED_RECT lock_src, lock_dst;
833 HRESULT hr;
835 conv = find_convertor(source->resource.format_desc->format, to_fmt);
836 if(!conv) {
837 FIXME("Cannot find a conversion function from format %s to %s\n",
838 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
839 return NULL;
842 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
843 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
844 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
845 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
846 NULL /* parent */, &wined3d_null_parent_ops);
847 if(!ret) {
848 ERR("Failed to create a destination surface for conversion\n");
849 return NULL;
852 memset(&lock_src, 0, sizeof(lock_src));
853 memset(&lock_dst, 0, sizeof(lock_dst));
855 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
856 if(FAILED(hr)) {
857 ERR("Failed to lock the source surface\n");
858 IWineD3DSurface_Release(ret);
859 return NULL;
861 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
862 if(FAILED(hr)) {
863 ERR("Failed to lock the dest surface\n");
864 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
865 IWineD3DSurface_Release(ret);
866 return NULL;
869 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
870 source->currentDesc.Width, source->currentDesc.Height);
872 IWineD3DSurface_UnlockRect(ret);
873 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
875 return (IWineD3DSurfaceImpl *) ret;
878 /*****************************************************************************
879 * _Blt_ColorFill
881 * Helper function that fills a memory area with a specific color
883 * Params:
884 * buf: memory address to start filling at
885 * width, height: Dimensions of the area to fill
886 * bpp: Bit depth of the surface
887 * lPitch: pitch of the surface
888 * color: Color to fill with
890 *****************************************************************************/
891 static HRESULT
892 _Blt_ColorFill(BYTE *buf,
893 int width, int height,
894 int bpp, LONG lPitch,
895 DWORD color)
897 int x, y;
898 LPBYTE first;
900 /* Do first row */
902 #define COLORFILL_ROW(type) \
904 type *d = (type *) buf; \
905 for (x = 0; x < width; x++) \
906 d[x] = (type) color; \
907 break; \
909 switch(bpp)
911 case 1: COLORFILL_ROW(BYTE)
912 case 2: COLORFILL_ROW(WORD)
913 case 3:
915 BYTE *d = buf;
916 for (x = 0; x < width; x++,d+=3)
918 d[0] = (color ) & 0xFF;
919 d[1] = (color>> 8) & 0xFF;
920 d[2] = (color>>16) & 0xFF;
922 break;
924 case 4: COLORFILL_ROW(DWORD)
925 default:
926 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
927 return WINED3DERR_NOTAVAILABLE;
930 #undef COLORFILL_ROW
932 /* Now copy first row */
933 first = buf;
934 for (y = 1; y < height; y++)
936 buf += lPitch;
937 memcpy(buf, first, width * bpp);
939 return WINED3D_OK;
942 /*****************************************************************************
943 * IWineD3DSurface::Blt, SW emulation version
945 * Performs a blit to a surface, with or without a source surface.
946 * This is the main functionality of DirectDraw
948 * Params:
949 * DestRect: Destination rectangle to write to
950 * SrcSurface: Source surface, can be NULL
951 * SrcRect: Source rectangle
952 *****************************************************************************/
953 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
954 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
956 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
957 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
958 RECT xdst,xsrc;
959 HRESULT ret = WINED3D_OK;
960 WINED3DLOCKED_RECT dlock, slock;
961 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
962 const struct wined3d_format_desc *sEntry, *dEntry;
963 int x, y;
964 const BYTE *sbuf;
965 BYTE *dbuf;
966 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
968 if (TRACE_ON(d3d_surface))
970 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
971 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
972 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
973 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
974 #if 0
975 TRACE("\tflags: ");
976 DDRAW_dump_DDBLT(Flags);
977 if (Flags & WINEDDBLT_DDFX)
979 TRACE("\tblitfx: ");
980 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
982 #endif
985 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
987 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
988 return WINEDDERR_SURFACEBUSY;
991 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
992 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
993 FIXME("Filters not supported in software blit\n");
996 /* First check for the validity of source / destination rectangles.
997 * This was verified using a test application + by MSDN. */
999 if (SrcRect)
1001 if (Src)
1003 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
1004 || SrcRect->left > Src->currentDesc.Width || SrcRect->left < 0
1005 || SrcRect->top > Src->currentDesc.Height || SrcRect->top < 0
1006 || SrcRect->right > Src->currentDesc.Width || SrcRect->right < 0
1007 || SrcRect->bottom > Src->currentDesc.Height || SrcRect->bottom < 0)
1009 WARN("Application gave us bad source rectangle for Blt.\n");
1010 return WINEDDERR_INVALIDRECT;
1013 if (!SrcRect->right || !SrcRect->bottom
1014 || SrcRect->left == (int)Src->currentDesc.Width
1015 || SrcRect->top == (int)Src->currentDesc.Height)
1017 TRACE("Nothing to be done.\n");
1018 return WINED3D_OK;
1022 xsrc = *SrcRect;
1024 else if (Src)
1026 xsrc.left = 0;
1027 xsrc.top = 0;
1028 xsrc.right = Src->currentDesc.Width;
1029 xsrc.bottom = Src->currentDesc.Height;
1031 else
1033 memset(&xsrc, 0, sizeof(xsrc));
1036 /* For the Destination rect, it can be out of bounds on the condition that a clipper
1037 * is set for the given surface.
1039 if (!This->clipper && DestRect &&
1040 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
1041 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
1042 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
1043 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
1044 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
1046 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1047 return WINEDDERR_INVALIDRECT;
1050 /* Now handle negative values in the rectangles. Warning: only supported
1051 * for now in the 'simple' cases (ie not in any stretching / rotation
1052 * cases). First, the case where nothing is to be done. */
1054 if (DestRect && (DestRect->bottom <= 0 || DestRect->right <= 0
1055 || DestRect->top >= (int)This->currentDesc.Height
1056 || DestRect->left >= (int)This->currentDesc.Width))
1058 TRACE("Nothing to be done.\n");
1059 return WINED3D_OK;
1062 if (DestRect)
1064 xdst = *DestRect;
1066 else
1068 xdst.top = 0;
1069 xdst.bottom = This->currentDesc.Height;
1070 xdst.left = 0;
1071 xdst.right = This->currentDesc.Width;
1074 /* The easy case : the source-less blits.... */
1075 if (Src == NULL && DestRect)
1077 RECT full_rect;
1078 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1080 full_rect.left = 0;
1081 full_rect.top = 0;
1082 full_rect.right = This->currentDesc.Width;
1083 full_rect.bottom = This->currentDesc.Height;
1084 IntersectRect(&temp_rect, &full_rect, DestRect);
1085 xdst = temp_rect;
1087 else if (DestRect)
1089 /* Only handle clipping on the destination rectangle */
1090 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1091 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1092 if (clip_vert || clip_horiz)
1094 /* Now check if this is a special case or not... */
1095 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1096 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1097 (Flags & WINEDDBLT_DDFX))
1099 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1100 return WINED3D_OK;
1103 if (clip_horiz)
1105 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1106 if (DestRect->right > This->currentDesc.Width)
1108 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1109 xdst.right = (int) This->currentDesc.Width;
1112 if (clip_vert)
1114 if (DestRect->top < 0)
1116 xsrc.top -= DestRect->top;
1117 xdst.top = 0;
1119 if (DestRect->bottom > This->currentDesc.Height)
1121 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1122 xdst.bottom = (int) This->currentDesc.Height;
1125 /* And check if after clipping something is still to be done... */
1126 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1127 (xdst.top >= (int) This->currentDesc.Height) ||
1128 (xdst.left >= (int) This->currentDesc.Width) ||
1129 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1130 (xsrc.top >= (int) Src->currentDesc.Height) ||
1131 (xsrc.left >= (int) Src->currentDesc.Width))
1133 TRACE("Nothing to be done after clipping !\n");
1134 return WINED3D_OK;
1139 if (Src == This)
1141 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1142 slock = dlock;
1143 sEntry = This->resource.format_desc;
1144 dEntry = sEntry;
1146 else
1148 dEntry = This->resource.format_desc;
1149 if (Src)
1151 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1153 Src = surface_convert_format(Src, dEntry->format);
1154 if(!Src) {
1155 /* The conv function writes a FIXME */
1156 WARN("Cannot convert source surface format to dest format\n");
1157 goto release;
1160 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1161 sEntry = Src->resource.format_desc;
1163 else
1165 sEntry = dEntry;
1167 if (DestRect)
1168 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1169 else
1170 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1173 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1175 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1177 if (!DestRect || Src == This)
1179 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1180 goto release;
1184 bpp = This->resource.format_desc->byte_count;
1185 srcheight = xsrc.bottom - xsrc.top;
1186 srcwidth = xsrc.right - xsrc.left;
1187 dstheight = xdst.bottom - xdst.top;
1188 dstwidth = xdst.right - xdst.left;
1189 width = (xdst.right - xdst.left) * bpp;
1191 if (DestRect && Src != This)
1192 dbuf = dlock.pBits;
1193 else
1194 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1196 if (Flags & WINEDDBLT_WAIT)
1198 Flags &= ~WINEDDBLT_WAIT;
1200 if (Flags & WINEDDBLT_ASYNC)
1202 static BOOL displayed = FALSE;
1203 if (!displayed)
1204 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1205 displayed = TRUE;
1206 Flags &= ~WINEDDBLT_ASYNC;
1208 if (Flags & WINEDDBLT_DONOTWAIT)
1210 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1211 static BOOL displayed = FALSE;
1212 if (!displayed)
1213 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1214 displayed = TRUE;
1215 Flags &= ~WINEDDBLT_DONOTWAIT;
1218 /* First, all the 'source-less' blits */
1219 if (Flags & WINEDDBLT_COLORFILL)
1221 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1222 dlock.Pitch, DDBltFx->u5.dwFillColor);
1223 Flags &= ~WINEDDBLT_COLORFILL;
1226 if (Flags & WINEDDBLT_DEPTHFILL)
1228 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1230 if (Flags & WINEDDBLT_ROP)
1232 /* Catch some degenerate cases here */
1233 switch(DDBltFx->dwROP)
1235 case BLACKNESS:
1236 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1237 break;
1238 case 0xAA0029: /* No-op */
1239 break;
1240 case WHITENESS:
1241 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1242 break;
1243 case SRCCOPY: /* well, we do that below ? */
1244 break;
1245 default:
1246 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1247 goto error;
1249 Flags &= ~WINEDDBLT_ROP;
1251 if (Flags & WINEDDBLT_DDROPS)
1253 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1255 /* Now the 'with source' blits */
1256 if (Src)
1258 const BYTE *sbase;
1259 int sx, xinc, sy, yinc;
1261 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1262 goto release;
1263 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1264 xinc = (srcwidth << 16) / dstwidth;
1265 yinc = (srcheight << 16) / dstheight;
1267 if (!Flags)
1269 /* No effects, we can cheat here */
1270 if (dstwidth == srcwidth)
1272 if (dstheight == srcheight)
1274 /* No stretching in either direction. This needs to be as
1275 * fast as possible */
1276 sbuf = sbase;
1278 /* check for overlapping surfaces */
1279 if (Src != This || xdst.top < xsrc.top ||
1280 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1282 /* no overlap, or dst above src, so copy from top downwards */
1283 for (y = 0; y < dstheight; y++)
1285 memcpy(dbuf, sbuf, width);
1286 sbuf += slock.Pitch;
1287 dbuf += dlock.Pitch;
1290 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1292 sbuf += (slock.Pitch*dstheight);
1293 dbuf += (dlock.Pitch*dstheight);
1294 for (y = 0; y < dstheight; y++)
1296 sbuf -= slock.Pitch;
1297 dbuf -= dlock.Pitch;
1298 memcpy(dbuf, sbuf, width);
1301 else /* src and dst overlapping on the same line, use memmove */
1303 for (y = 0; y < dstheight; y++)
1305 memmove(dbuf, sbuf, width);
1306 sbuf += slock.Pitch;
1307 dbuf += dlock.Pitch;
1310 } else {
1311 /* Stretching in Y direction only */
1312 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1313 sbuf = sbase + (sy >> 16) * slock.Pitch;
1314 memcpy(dbuf, sbuf, width);
1315 dbuf += dlock.Pitch;
1319 else
1321 /* Stretching in X direction */
1322 int last_sy = -1;
1323 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1325 sbuf = sbase + (sy >> 16) * slock.Pitch;
1327 if ((sy >> 16) == (last_sy >> 16))
1329 /* this sourcerow is the same as last sourcerow -
1330 * copy already stretched row
1332 memcpy(dbuf, dbuf - dlock.Pitch, width);
1334 else
1336 #define STRETCH_ROW(type) { \
1337 const type *s = (const type *)sbuf; \
1338 type *d = (type *)dbuf; \
1339 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1340 d[x] = s[sx >> 16]; \
1341 break; }
1343 switch(bpp)
1345 case 1: STRETCH_ROW(BYTE)
1346 case 2: STRETCH_ROW(WORD)
1347 case 4: STRETCH_ROW(DWORD)
1348 case 3:
1350 const BYTE *s;
1351 BYTE *d = dbuf;
1352 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1354 DWORD pixel;
1356 s = sbuf+3*(sx>>16);
1357 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1358 d[0] = (pixel )&0xff;
1359 d[1] = (pixel>> 8)&0xff;
1360 d[2] = (pixel>>16)&0xff;
1361 d+=3;
1363 break;
1365 default:
1366 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1367 ret = WINED3DERR_NOTAVAILABLE;
1368 goto error;
1370 #undef STRETCH_ROW
1372 dbuf += dlock.Pitch;
1373 last_sy = sy;
1377 else
1379 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1380 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1381 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1382 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1384 /* The color keying flags are checked for correctness in ddraw */
1385 if (Flags & WINEDDBLT_KEYSRC)
1387 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1388 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1390 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1392 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1393 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1396 if (Flags & WINEDDBLT_KEYDEST)
1398 /* Destination color keys are taken from the source surface ! */
1399 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1400 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1402 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1404 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1405 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1408 if(bpp == 1)
1410 keymask = 0xff;
1412 else
1414 keymask = sEntry->red_mask
1415 | sEntry->green_mask
1416 | sEntry->blue_mask;
1418 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1421 if (Flags & WINEDDBLT_DDFX)
1423 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1424 LONG tmpxy;
1425 dTopLeft = dbuf;
1426 dTopRight = dbuf+((dstwidth-1)*bpp);
1427 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1428 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1430 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1432 /* I don't think we need to do anything about this flag */
1433 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1435 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1437 tmp = dTopRight;
1438 dTopRight = dTopLeft;
1439 dTopLeft = tmp;
1440 tmp = dBottomRight;
1441 dBottomRight = dBottomLeft;
1442 dBottomLeft = tmp;
1443 dstxinc = dstxinc *-1;
1445 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1447 tmp = dTopLeft;
1448 dTopLeft = dBottomLeft;
1449 dBottomLeft = tmp;
1450 tmp = dTopRight;
1451 dTopRight = dBottomRight;
1452 dBottomRight = tmp;
1453 dstyinc = dstyinc *-1;
1455 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1457 /* I don't think we need to do anything about this flag */
1458 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1460 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1462 tmp = dBottomRight;
1463 dBottomRight = dTopLeft;
1464 dTopLeft = tmp;
1465 tmp = dBottomLeft;
1466 dBottomLeft = dTopRight;
1467 dTopRight = tmp;
1468 dstxinc = dstxinc * -1;
1469 dstyinc = dstyinc * -1;
1471 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1473 tmp = dTopLeft;
1474 dTopLeft = dBottomLeft;
1475 dBottomLeft = dBottomRight;
1476 dBottomRight = dTopRight;
1477 dTopRight = tmp;
1478 tmpxy = dstxinc;
1479 dstxinc = dstyinc;
1480 dstyinc = tmpxy;
1481 dstxinc = dstxinc * -1;
1483 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1485 tmp = dTopLeft;
1486 dTopLeft = dTopRight;
1487 dTopRight = dBottomRight;
1488 dBottomRight = dBottomLeft;
1489 dBottomLeft = tmp;
1490 tmpxy = dstxinc;
1491 dstxinc = dstyinc;
1492 dstyinc = tmpxy;
1493 dstyinc = dstyinc * -1;
1495 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1497 /* I don't think we need to do anything about this flag */
1498 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1500 dbuf = dTopLeft;
1501 Flags &= ~(WINEDDBLT_DDFX);
1504 #define COPY_COLORKEY_FX(type) { \
1505 const type *s; \
1506 type *d = (type *)dbuf, *dx, tmp; \
1507 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1508 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1509 dx = d; \
1510 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1511 tmp = s[sx >> 16]; \
1512 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1513 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1514 dx[0] = tmp; \
1516 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1518 d = (type*)(((LPBYTE)d)+dstyinc); \
1520 break; }
1522 switch (bpp) {
1523 case 1: COPY_COLORKEY_FX(BYTE)
1524 case 2: COPY_COLORKEY_FX(WORD)
1525 case 4: COPY_COLORKEY_FX(DWORD)
1526 case 3:
1528 const BYTE *s;
1529 BYTE *d = dbuf, *dx;
1530 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1532 sbuf = sbase + (sy >> 16) * slock.Pitch;
1533 dx = d;
1534 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1536 DWORD pixel, dpixel = 0;
1537 s = sbuf+3*(sx>>16);
1538 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1539 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1540 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1541 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1543 dx[0] = (pixel )&0xff;
1544 dx[1] = (pixel>> 8)&0xff;
1545 dx[2] = (pixel>>16)&0xff;
1547 dx+= dstxinc;
1549 d += dstyinc;
1551 break;
1553 default:
1554 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1555 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1556 ret = WINED3DERR_NOTAVAILABLE;
1557 goto error;
1558 #undef COPY_COLORKEY_FX
1563 error:
1564 if (Flags && FIXME_ON(d3d_surface))
1566 FIXME("\tUnsupported flags: %08x\n", Flags);
1569 release:
1570 IWineD3DSurface_UnlockRect(iface);
1571 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1572 /* Release the converted surface if any */
1573 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1574 return ret;
1577 /*****************************************************************************
1578 * IWineD3DSurface::BltFast, SW emulation version
1580 * This is the software implementation of BltFast, as used by GDI surfaces
1581 * and as a fallback for OpenGL surfaces. This code is taken from the old
1582 * DirectDraw code, and was originally written by TransGaming.
1584 * Params:
1585 * dstx:
1586 * dsty:
1587 * Source: Source surface to copy from
1588 * rsrc: Source rectangle
1589 * trans: Some Flags
1591 * Returns:
1592 * WINED3D_OK on success
1594 *****************************************************************************/
1595 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1596 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1598 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1599 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1601 int bpp, w, h, x, y;
1602 WINED3DLOCKED_RECT dlock,slock;
1603 HRESULT ret = WINED3D_OK;
1604 RECT rsrc2;
1605 RECT lock_src, lock_dst, lock_union;
1606 const BYTE *sbuf;
1607 BYTE *dbuf;
1608 const struct wined3d_format_desc *sEntry, *dEntry;
1610 if (TRACE_ON(d3d_surface))
1612 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1614 if (rsrc)
1616 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1617 rsrc->right,rsrc->bottom);
1619 else
1621 TRACE(" srcrect: NULL\n");
1625 if ((This->Flags & SFLAG_LOCKED) ||
1626 (Src->Flags & SFLAG_LOCKED))
1628 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1629 return WINEDDERR_SURFACEBUSY;
1632 if (!rsrc)
1634 WARN("rsrc is NULL!\n");
1635 rsrc2.left = 0;
1636 rsrc2.top = 0;
1637 rsrc2.right = Src->currentDesc.Width;
1638 rsrc2.bottom = Src->currentDesc.Height;
1639 rsrc = &rsrc2;
1642 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1643 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1644 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1645 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1646 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1647 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1649 WARN("Application gave us bad source rectangle for BltFast.\n");
1650 return WINEDDERR_INVALIDRECT;
1653 h = rsrc->bottom - rsrc->top;
1654 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1655 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1656 if (h <= 0) return WINEDDERR_INVALIDRECT;
1658 w = rsrc->right - rsrc->left;
1659 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1660 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1661 if (w <= 0) return WINEDDERR_INVALIDRECT;
1663 /* Now compute the locking rectangle... */
1664 lock_src.left = rsrc->left;
1665 lock_src.top = rsrc->top;
1666 lock_src.right = lock_src.left + w;
1667 lock_src.bottom = lock_src.top + h;
1669 lock_dst.left = dstx;
1670 lock_dst.top = dsty;
1671 lock_dst.right = dstx + w;
1672 lock_dst.bottom = dsty + h;
1674 bpp = This->resource.format_desc->byte_count;
1676 /* We need to lock the surfaces, or we won't get refreshes when done. */
1677 if (Src == This)
1679 int pitch;
1681 UnionRect(&lock_union, &lock_src, &lock_dst);
1683 /* Lock the union of the two rectangles */
1684 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1685 if(ret != WINED3D_OK) goto error;
1687 pitch = dlock.Pitch;
1688 slock.Pitch = dlock.Pitch;
1690 /* Since slock was originally copied from this surface's description, we can just reuse it */
1691 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1692 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1693 sEntry = Src->resource.format_desc;
1694 dEntry = sEntry;
1696 else
1698 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1699 if(ret != WINED3D_OK) goto error;
1700 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1701 if(ret != WINED3D_OK) goto error;
1703 sbuf = slock.pBits;
1704 dbuf = dlock.pBits;
1705 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1707 sEntry = Src->resource.format_desc;
1708 dEntry = This->resource.format_desc;
1711 /* Handle compressed surfaces first... */
1712 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1714 UINT row_block_count;
1716 TRACE("compressed -> compressed copy\n");
1717 if (trans)
1718 FIXME("trans arg not supported when a compressed surface is involved\n");
1719 if (dstx || dsty)
1720 FIXME("offset for destination surface is not supported\n");
1721 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1723 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1724 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1725 goto error;
1728 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1729 for (y = 0; y < h; y += dEntry->block_height)
1731 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1732 dbuf += dlock.Pitch;
1733 sbuf += slock.Pitch;
1736 goto error;
1738 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1740 /* TODO: Use the libtxc_dxtn.so shared library to do
1741 * software decompression
1743 ERR("Software decompression not supported.\n");
1744 goto error;
1747 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1749 DWORD keylow, keyhigh;
1750 DWORD mask = Src->resource.format_desc->red_mask |
1751 Src->resource.format_desc->green_mask |
1752 Src->resource.format_desc->blue_mask;
1754 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1755 if(!mask && bpp==1)
1756 mask = 0xff;
1758 TRACE("Color keyed copy\n");
1759 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1761 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1762 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1764 else
1766 /* I'm not sure if this is correct */
1767 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1768 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1769 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1772 #define COPYBOX_COLORKEY(type) { \
1773 const type *s = (const type *)sbuf; \
1774 type *d = (type *)dbuf; \
1775 type tmp; \
1776 for (y = 0; y < h; y++) { \
1777 for (x = 0; x < w; x++) { \
1778 tmp = s[x]; \
1779 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1781 s = (const type *)((const BYTE *)s + slock.Pitch); \
1782 d = (type *)((BYTE *)d + dlock.Pitch); \
1784 break; \
1787 switch (bpp) {
1788 case 1: COPYBOX_COLORKEY(BYTE)
1789 case 2: COPYBOX_COLORKEY(WORD)
1790 case 4: COPYBOX_COLORKEY(DWORD)
1791 case 3:
1793 const BYTE *s;
1794 BYTE *d;
1795 DWORD tmp;
1796 s = sbuf;
1797 d = dbuf;
1798 for (y = 0; y < h; y++)
1800 for (x = 0; x < w * 3; x += 3)
1802 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1803 if (tmp < keylow || tmp > keyhigh)
1805 d[x + 0] = s[x + 0];
1806 d[x + 1] = s[x + 1];
1807 d[x + 2] = s[x + 2];
1810 s += slock.Pitch;
1811 d += dlock.Pitch;
1813 break;
1815 default:
1816 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1817 ret = WINED3DERR_NOTAVAILABLE;
1818 goto error;
1820 #undef COPYBOX_COLORKEY
1821 TRACE("Copy Done\n");
1823 else
1825 int width = w * bpp;
1826 INT sbufpitch, dbufpitch;
1828 TRACE("NO color key copy\n");
1829 /* Handle overlapping surfaces */
1830 if (sbuf < dbuf)
1832 sbuf += (h - 1) * slock.Pitch;
1833 dbuf += (h - 1) * dlock.Pitch;
1834 sbufpitch = -slock.Pitch;
1835 dbufpitch = -dlock.Pitch;
1837 else
1839 sbufpitch = slock.Pitch;
1840 dbufpitch = dlock.Pitch;
1842 for (y = 0; y < h; y++)
1844 /* This is pretty easy, a line for line memcpy */
1845 memmove(dbuf, sbuf, width);
1846 sbuf += sbufpitch;
1847 dbuf += dbufpitch;
1849 TRACE("Copy done\n");
1852 error:
1853 if (Src == This)
1855 IWineD3DSurface_UnlockRect(iface);
1857 else
1859 IWineD3DSurface_UnlockRect(iface);
1860 IWineD3DSurface_UnlockRect(Source);
1863 return ret;
1866 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1868 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1870 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1871 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1873 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1875 if (NULL == pRect)
1877 pLockedRect->pBits = This->resource.allocatedMemory;
1878 This->lockedRect.left = 0;
1879 This->lockedRect.top = 0;
1880 This->lockedRect.right = This->currentDesc.Width;
1881 This->lockedRect.bottom = This->currentDesc.Height;
1883 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1884 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1885 This->lockedRect.right, This->lockedRect.bottom);
1887 else
1889 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
1891 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1892 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1894 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1896 /* Compressed textures are block based, so calculate the offset of
1897 * the block that contains the top-left pixel of the locked rectangle. */
1898 pLockedRect->pBits = This->resource.allocatedMemory
1899 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1900 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1902 else
1904 pLockedRect->pBits = This->resource.allocatedMemory +
1905 (pLockedRect->Pitch * pRect->top) +
1906 (pRect->left * format_desc->byte_count);
1908 This->lockedRect.left = pRect->left;
1909 This->lockedRect.top = pRect->top;
1910 This->lockedRect.right = pRect->right;
1911 This->lockedRect.bottom = pRect->bottom;
1914 /* No dirtifying is needed for this surface implementation */
1915 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1917 return WINED3D_OK;
1920 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1921 ERR("Should not be called on base texture\n");
1924 /* TODO: think about moving this down to resource? */
1925 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1927 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1929 /* This should only be called for sysmem textures, it may be a good idea
1930 * to extend this to all pools at some point in the future */
1931 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1933 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1935 return This->resource.allocatedMemory;