oleaut32: Convert CustData to use standard linked lists.
[wine.git] / dlls / wined3d / surface_base.c
blob74fa1961f1c22a5680ba5d9587ccfffbdf0f0049
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-2010 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 < powf(2, 10)) {
52 tmp = tmp * 2.0f;
53 exp--;
54 }while(tmp < powf(2, 10));
55 } else if(tmp >= powf(2, 11)) {
58 tmp /= 2.0f;
59 exp++;
60 }while(tmp >= powf(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;
86 /* *******************************************
87 IWineD3DSurface IUnknown parts follow
88 ******************************************* */
89 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
91 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
92 /* Warn ,but be nice about things */
93 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
95 if (IsEqualGUID(riid, &IID_IUnknown)
96 || IsEqualGUID(riid, &IID_IWineD3DBase)
97 || IsEqualGUID(riid, &IID_IWineD3DResource)
98 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
99 IUnknown_AddRef((IUnknown*)iface);
100 *ppobj = This;
101 return S_OK;
103 *ppobj = NULL;
104 return E_NOINTERFACE;
107 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
108 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
109 ULONG ref = InterlockedIncrement(&This->resource.ref);
110 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
111 return ref;
114 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface,
115 REFGUID riid, const void *data, DWORD data_size, DWORD flags)
117 return resource_set_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, riid, data, data_size, flags);
120 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface,
121 REFGUID guid, void *data, DWORD *data_size)
123 return resource_get_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, guid, data, data_size);
126 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid)
128 return resource_free_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, refguid);
131 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD priority)
133 return resource_set_priority(&((IWineD3DSurfaceImpl *)iface)->resource, priority);
136 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface)
138 return resource_get_priority(&((IWineD3DSurfaceImpl *)iface)->resource);
141 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface)
143 return resource_get_type(&((IWineD3DSurfaceImpl *)iface)->resource);
146 void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
148 TRACE("iface %p.\n", iface);
150 return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
153 struct wined3d_resource * WINAPI IWineD3DBaseSurfaceImpl_GetResource(IWineD3DSurface *iface)
155 TRACE("iface %p.\n", iface);
157 return &((IWineD3DSurfaceImpl *)iface)->resource;
160 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD flags)
162 TRACE("iface %p, flags %#x.\n", iface, flags);
164 switch (flags)
166 case WINEDDGBS_CANBLT:
167 case WINEDDGBS_ISBLTDONE:
168 return WINED3D_OK;
170 default:
171 return WINED3DERR_INVALIDCALL;
175 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD flags)
177 /* XXX: DDERR_INVALIDSURFACETYPE */
179 TRACE("iface %p, flags %#x.\n", iface, flags);
181 switch (flags)
183 case WINEDDGFS_CANFLIP:
184 case WINEDDGFS_ISFLIPDONE:
185 return WINED3D_OK;
187 default:
188 return WINED3DERR_INVALIDCALL;
192 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
193 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
194 TRACE("(%p)\n", This);
196 /* D3D8 and 9 loose full devices, ddraw only surfaces */
197 return This->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
200 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
201 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
202 TRACE("(%p)\n", This);
204 /* So far we don't lose anything :) */
205 This->flags &= ~SFLAG_LOST;
206 return WINED3D_OK;
209 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, struct wined3d_palette *palette)
211 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
213 TRACE("iface %p, palette %p.\n", iface, palette);
215 if (This->palette == palette)
217 TRACE("Nop palette change\n");
218 return WINED3D_OK;
221 if (This->palette)
222 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
223 This->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
225 This->palette = palette;
227 if (palette)
229 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
230 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
232 This->surface_ops->surface_realize_palette(This);
235 return WINED3D_OK;
238 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD flags, const WINEDDCOLORKEY *CKey)
240 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
242 TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, CKey);
244 if (flags & WINEDDCKEY_COLORSPACE)
246 FIXME(" colorkey value not supported (%08x) !\n", flags);
247 return WINED3DERR_INVALIDCALL;
250 /* Dirtify the surface, but only if a key was changed */
251 if (CKey)
253 switch (flags & ~WINEDDCKEY_COLORSPACE)
255 case WINEDDCKEY_DESTBLT:
256 This->DestBltCKey = *CKey;
257 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
258 break;
260 case WINEDDCKEY_DESTOVERLAY:
261 This->DestOverlayCKey = *CKey;
262 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
263 break;
265 case WINEDDCKEY_SRCOVERLAY:
266 This->SrcOverlayCKey = *CKey;
267 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
268 break;
270 case WINEDDCKEY_SRCBLT:
271 This->SrcBltCKey = *CKey;
272 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
273 break;
276 else
278 switch (flags & ~WINEDDCKEY_COLORSPACE)
280 case WINEDDCKEY_DESTBLT:
281 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
282 break;
284 case WINEDDCKEY_DESTOVERLAY:
285 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
286 break;
288 case WINEDDCKEY_SRCOVERLAY:
289 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
290 break;
292 case WINEDDCKEY_SRCBLT:
293 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
294 break;
298 return WINED3D_OK;
301 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, struct wined3d_palette **palette)
303 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
305 TRACE("iface %p, palette %p.\n", iface, palette);
307 *palette = This->palette;
309 return WINED3D_OK;
312 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
314 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
315 const struct wined3d_format *format = This->resource.format;
316 DWORD ret;
317 TRACE("(%p)\n", This);
319 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
321 /* Since compressed formats are block based, pitch means the amount of
322 * bytes to the next row of block rather than the next row of pixels. */
323 UINT row_block_count = (This->resource.width + format->block_width - 1) / format->block_width;
324 ret = row_block_count * format->block_byte_count;
326 else
328 unsigned char alignment = This->resource.device->surface_alignment;
329 ret = This->resource.format->byte_count * This->resource.width; /* Bytes / row */
330 ret = (ret + alignment - 1) & ~(alignment - 1);
332 TRACE("(%p) Returning %d\n", This, ret);
333 return ret;
336 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
337 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
338 LONG w, h;
340 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
342 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
344 TRACE("(%p): Not an overlay surface\n", This);
345 return WINEDDERR_NOTAOVERLAYSURFACE;
348 w = This->overlay_destrect.right - This->overlay_destrect.left;
349 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
350 This->overlay_destrect.left = X;
351 This->overlay_destrect.top = Y;
352 This->overlay_destrect.right = X + w;
353 This->overlay_destrect.bottom = Y + h;
355 This->surface_ops->surface_draw_overlay(This);
357 return WINED3D_OK;
360 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
361 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
362 HRESULT hr;
364 TRACE("(%p)->(%p,%p)\n", This, X, Y);
366 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
368 TRACE("(%p): Not an overlay surface\n", This);
369 return WINEDDERR_NOTAOVERLAYSURFACE;
372 if (!This->overlay_dest)
374 *X = 0; *Y = 0;
375 hr = WINEDDERR_OVERLAYNOTVISIBLE;
376 } else {
377 *X = This->overlay_destrect.left;
378 *Y = This->overlay_destrect.top;
379 hr = WINED3D_OK;
382 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
383 return hr;
386 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD flags, IWineD3DSurface *Ref)
388 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
390 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, Ref);
392 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
394 TRACE("(%p): Not an overlay surface\n", This);
395 return WINEDDERR_NOTAOVERLAYSURFACE;
398 return WINED3D_OK;
401 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
402 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD flags, const WINEDDOVERLAYFX *FX)
404 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
405 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
407 TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
408 iface, wine_dbgstr_rect(SrcRect), DstSurface, wine_dbgstr_rect(DstRect), flags, FX);
410 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
412 WARN("(%p): Not an overlay surface\n", This);
413 return WINEDDERR_NOTAOVERLAYSURFACE;
414 } else if(!DstSurface) {
415 WARN("(%p): Dest surface is NULL\n", This);
416 return WINED3DERR_INVALIDCALL;
419 if(SrcRect) {
420 This->overlay_srcrect = *SrcRect;
421 } else {
422 This->overlay_srcrect.left = 0;
423 This->overlay_srcrect.top = 0;
424 This->overlay_srcrect.right = This->resource.width;
425 This->overlay_srcrect.bottom = This->resource.height;
428 if(DstRect) {
429 This->overlay_destrect = *DstRect;
430 } else {
431 This->overlay_destrect.left = 0;
432 This->overlay_destrect.top = 0;
433 This->overlay_destrect.right = Dst ? Dst->resource.width : 0;
434 This->overlay_destrect.bottom = Dst ? Dst->resource.height : 0;
437 if (This->overlay_dest && (This->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
439 list_remove(&This->overlay_entry);
442 if (flags & WINEDDOVER_SHOW)
444 if (This->overlay_dest != Dst)
446 This->overlay_dest = Dst;
447 list_add_tail(&Dst->overlays, &This->overlay_entry);
450 else if (flags & WINEDDOVER_HIDE)
452 /* tests show that the rectangles are erased on hide */
453 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
454 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
455 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
456 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
457 This->overlay_dest = NULL;
460 This->surface_ops->surface_draw_overlay(This);
462 return WINED3D_OK;
465 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, struct wined3d_clipper *clipper)
467 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
469 TRACE("iface %p, clipper %p.\n", iface, clipper);
471 This->clipper = clipper;
473 return WINED3D_OK;
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, struct wined3d_clipper **clipper)
478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
480 TRACE("iface %p, clipper %p.\n", iface, clipper);
482 *clipper = This->clipper;
483 if (*clipper)
484 wined3d_clipper_incref(*clipper);
486 return WINED3D_OK;
489 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
491 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
492 const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
494 if (This->resource.format->id != WINED3DFMT_UNKNOWN)
496 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
497 return WINED3DERR_INVALIDCALL;
500 TRACE("(%p) : Setting texture format to %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
502 This->resource.size = wined3d_format_calculate_size(format, This->resource.device->surface_alignment,
503 This->pow2Width, This->pow2Height);
505 This->flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
507 This->resource.format = format;
509 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
511 return WINED3D_OK;
514 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
516 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
517 const struct wined3d_format *format = This->resource.format;
518 int extraline = 0;
519 SYSTEM_INFO sysInfo;
520 BITMAPINFO* b_info;
521 HDC ddc;
522 DWORD *masks;
523 UINT usage;
525 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
527 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
528 return WINED3DERR_INVALIDCALL;
531 switch (format->byte_count)
533 case 2:
534 case 4:
535 /* Allocate extra space to store the RGB bit masks. */
536 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
537 break;
539 case 3:
540 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
541 break;
543 default:
544 /* Allocate extra space for a palette. */
545 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
546 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
547 break;
550 if (!b_info)
551 return E_OUTOFMEMORY;
553 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
554 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
555 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
556 * add an extra line to the dib section
558 GetSystemInfo(&sysInfo);
559 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
560 extraline = 1;
561 TRACE("Adding an extra line to the dib section\n");
564 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
565 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
566 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
567 b_info->bmiHeader.biHeight = -This->resource.height - extraline;
568 b_info->bmiHeader.biSizeImage = (This->resource.height + extraline) * IWineD3DSurface_GetPitch(iface);
569 b_info->bmiHeader.biPlanes = 1;
570 b_info->bmiHeader.biBitCount = format->byte_count * 8;
572 b_info->bmiHeader.biXPelsPerMeter = 0;
573 b_info->bmiHeader.biYPelsPerMeter = 0;
574 b_info->bmiHeader.biClrUsed = 0;
575 b_info->bmiHeader.biClrImportant = 0;
577 /* Get the bit masks */
578 masks = (DWORD *)b_info->bmiColors;
579 switch (This->resource.format->id)
581 case WINED3DFMT_B8G8R8_UNORM:
582 usage = DIB_RGB_COLORS;
583 b_info->bmiHeader.biCompression = BI_RGB;
584 break;
586 case WINED3DFMT_B5G5R5X1_UNORM:
587 case WINED3DFMT_B5G5R5A1_UNORM:
588 case WINED3DFMT_B4G4R4A4_UNORM:
589 case WINED3DFMT_B4G4R4X4_UNORM:
590 case WINED3DFMT_B2G3R3_UNORM:
591 case WINED3DFMT_B2G3R3A8_UNORM:
592 case WINED3DFMT_R10G10B10A2_UNORM:
593 case WINED3DFMT_R8G8B8A8_UNORM:
594 case WINED3DFMT_R8G8B8X8_UNORM:
595 case WINED3DFMT_B10G10R10A2_UNORM:
596 case WINED3DFMT_B5G6R5_UNORM:
597 case WINED3DFMT_R16G16B16A16_UNORM:
598 usage = 0;
599 b_info->bmiHeader.biCompression = BI_BITFIELDS;
600 masks[0] = format->red_mask;
601 masks[1] = format->green_mask;
602 masks[2] = format->blue_mask;
603 break;
605 default:
606 /* Don't know palette */
607 b_info->bmiHeader.biCompression = BI_RGB;
608 usage = 0;
609 break;
612 if (!(ddc = GetDC(0)))
614 HeapFree(GetProcessHeap(), 0, b_info);
615 return HRESULT_FROM_WIN32(GetLastError());
618 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);
619 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
620 ReleaseDC(0, ddc);
622 if (!This->dib.DIBsection) {
623 ERR("CreateDIBSection failed!\n");
624 HeapFree(GetProcessHeap(), 0, b_info);
625 return HRESULT_FROM_WIN32(GetLastError());
628 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
629 /* copy the existing surface to the dib section */
630 if (This->resource.allocatedMemory)
632 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory,
633 This->resource.height * IWineD3DSurface_GetPitch(iface));
635 else
637 /* This is to make LockRect read the gl Texture although memory is allocated */
638 This->flags &= ~SFLAG_INSYSMEM;
640 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
642 HeapFree(GetProcessHeap(), 0, b_info);
644 /* Now allocate a HDC */
645 This->hDC = CreateCompatibleDC(0);
646 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
647 TRACE("using wined3d palette %p\n", This->palette);
648 SelectPalette(This->hDC,
649 This->palette ? This->palette->hpal : 0,
650 FALSE);
652 This->flags |= SFLAG_DIBSECTION;
654 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
655 This->resource.heapMemory = NULL;
657 return WINED3D_OK;
660 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
661 unsigned int w, unsigned int h)
663 unsigned int x, y;
664 const float *src_f;
665 unsigned short *dst_s;
667 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
668 for(y = 0; y < h; y++) {
669 src_f = (const float *)(src + y * pitch_in);
670 dst_s = (unsigned short *) (dst + y * pitch_out);
671 for(x = 0; x < w; x++) {
672 dst_s[x] = float_32_to_16(src_f + x);
677 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
678 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
680 static const unsigned char convert_5to8[] =
682 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
683 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
684 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
685 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
687 static const unsigned char convert_6to8[] =
689 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
690 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
691 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
692 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
693 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
694 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
695 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
696 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
698 unsigned int x, y;
700 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
702 for (y = 0; y < h; ++y)
704 const WORD *src_line = (const WORD *)(src + y * pitch_in);
705 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
706 for (x = 0; x < w; ++x)
708 WORD pixel = src_line[x];
709 dst_line[x] = 0xff000000
710 | convert_5to8[(pixel & 0xf800) >> 11] << 16
711 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
712 | convert_5to8[(pixel & 0x001f)];
717 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
718 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
720 unsigned int x, y;
722 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
724 for (y = 0; y < h; ++y)
726 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
727 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
729 for (x = 0; x < w; ++x)
731 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
736 static inline BYTE cliptobyte(int x)
738 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
741 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
742 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
744 unsigned int x, y;
745 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
747 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
749 for (y = 0; y < h; ++y)
751 const BYTE *src_line = src + y * pitch_in;
752 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
753 for (x = 0; x < w; ++x)
755 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
756 * C = Y - 16; D = U - 128; E = V - 128;
757 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
758 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
759 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
760 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
761 * U and V are shared between the pixels.
763 if (!(x & 1)) /* for every even pixel, read new U and V */
765 d = (int) src_line[1] - 128;
766 e = (int) src_line[3] - 128;
767 r2 = 409 * e + 128;
768 g2 = - 100 * d - 208 * e + 128;
769 b2 = 516 * d + 128;
771 c2 = 298 * ((int) src_line[0] - 16);
772 dst_line[x] = 0xff000000
773 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
774 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
775 | cliptobyte((c2 + b2) >> 8); /* blue */
776 /* Scale RGB values to 0..255 range,
777 * then clip them if still not in range (may be negative),
778 * then shift them within DWORD if necessary.
780 src_line += 2;
785 struct d3dfmt_convertor_desc
787 enum wined3d_format_id from, to;
788 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
791 static const struct d3dfmt_convertor_desc convertors[] =
793 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
794 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
795 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
796 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
799 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
801 unsigned int i;
802 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
803 if(convertors[i].from == from && convertors[i].to == to) {
804 return &convertors[i];
807 return NULL;
810 /*****************************************************************************
811 * surface_convert_format
813 * Creates a duplicate of a surface in a different format. Is used by Blt to
814 * blit between surfaces with different formats
816 * Parameters
817 * source: Source surface
818 * fmt: Requested destination format
820 *****************************************************************************/
821 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
823 IWineD3DSurface *ret = NULL;
824 const struct d3dfmt_convertor_desc *conv;
825 WINED3DLOCKED_RECT lock_src, lock_dst;
826 HRESULT hr;
828 conv = find_convertor(source->resource.format->id, to_fmt);
829 if (!conv)
831 FIXME("Cannot find a conversion function from format %s to %s.\n",
832 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
833 return NULL;
836 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->resource.width,
837 source->resource.height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
838 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
839 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
840 NULL /* parent */, &wined3d_null_parent_ops, &ret);
841 if(!ret) {
842 ERR("Failed to create a destination surface for conversion\n");
843 return NULL;
846 memset(&lock_src, 0, sizeof(lock_src));
847 memset(&lock_dst, 0, sizeof(lock_dst));
849 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
850 if (FAILED(hr))
852 ERR("Failed to lock the source surface.\n");
853 IWineD3DSurface_Release(ret);
854 return NULL;
856 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
857 if (FAILED(hr))
859 ERR("Failed to lock the dest surface\n");
860 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
861 IWineD3DSurface_Release(ret);
862 return NULL;
865 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
866 source->resource.width, source->resource.height);
868 IWineD3DSurface_Unmap(ret);
869 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
871 return (IWineD3DSurfaceImpl *) ret;
874 /*****************************************************************************
875 * _Blt_ColorFill
877 * Helper function that fills a memory area with a specific color
879 * Params:
880 * buf: memory address to start filling at
881 * width, height: Dimensions of the area to fill
882 * bpp: Bit depth of the surface
883 * lPitch: pitch of the surface
884 * color: Color to fill with
886 *****************************************************************************/
887 static HRESULT
888 _Blt_ColorFill(BYTE *buf,
889 int width, int height,
890 int bpp, LONG lPitch,
891 DWORD color)
893 int x, y;
894 LPBYTE first;
896 /* Do first row */
898 #define COLORFILL_ROW(type) \
900 type *d = (type *) buf; \
901 for (x = 0; x < width; x++) \
902 d[x] = (type) color; \
903 break; \
905 switch(bpp)
907 case 1: COLORFILL_ROW(BYTE)
908 case 2: COLORFILL_ROW(WORD)
909 case 3:
911 BYTE *d = buf;
912 for (x = 0; x < width; x++,d+=3)
914 d[0] = (color ) & 0xFF;
915 d[1] = (color>> 8) & 0xFF;
916 d[2] = (color>>16) & 0xFF;
918 break;
920 case 4: COLORFILL_ROW(DWORD)
921 default:
922 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
923 return WINED3DERR_NOTAVAILABLE;
926 #undef COLORFILL_ROW
928 /* Now copy first row */
929 first = buf;
930 for (y = 1; y < height; y++)
932 buf += lPitch;
933 memcpy(buf, first, width * bpp);
935 return WINED3D_OK;
938 /*****************************************************************************
939 * IWineD3DSurface::Blt, SW emulation version
941 * Performs a blit to a surface, with or without a source surface.
942 * This is the main functionality of DirectDraw
944 * Params:
945 * DestRect: Destination rectangle to write to
946 * src_surface: Source surface, can be NULL
947 * SrcRect: Source rectangle
948 *****************************************************************************/
949 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
950 const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
952 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
953 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
954 RECT xdst,xsrc;
955 HRESULT ret = WINED3D_OK;
956 WINED3DLOCKED_RECT dlock, slock;
957 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
958 const struct wined3d_format *sEntry, *dEntry;
959 int x, y;
960 const BYTE *sbuf;
961 BYTE *dbuf;
963 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
964 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
965 flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
967 if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
969 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
970 return WINEDDERR_SURFACEBUSY;
973 /* First check for the validity of source / destination rectangles.
974 * This was verified using a test application + by MSDN. */
976 if (SrcRect)
978 if (src)
980 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
981 || SrcRect->left > src->resource.width || SrcRect->left < 0
982 || SrcRect->top > src->resource.height || SrcRect->top < 0
983 || SrcRect->right > src->resource.width || SrcRect->right < 0
984 || SrcRect->bottom > src->resource.height || SrcRect->bottom < 0)
986 WARN("Application gave us bad source rectangle for Blt.\n");
987 return WINEDDERR_INVALIDRECT;
990 if (!SrcRect->right || !SrcRect->bottom
991 || SrcRect->left == (int)src->resource.width
992 || SrcRect->top == (int)src->resource.height)
994 TRACE("Nothing to be done.\n");
995 return WINED3D_OK;
999 xsrc = *SrcRect;
1001 else if (src)
1003 xsrc.left = 0;
1004 xsrc.top = 0;
1005 xsrc.right = src->resource.width;
1006 xsrc.bottom = src->resource.height;
1008 else
1010 memset(&xsrc, 0, sizeof(xsrc));
1013 if (DestRect)
1015 /* For the Destination rect, it can be out of bounds on the condition
1016 * that a clipper is set for the given surface. */
1017 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1018 || DestRect->left > This->resource.width || DestRect->left < 0
1019 || DestRect->top > This->resource.height || DestRect->top < 0
1020 || DestRect->right > This->resource.width || DestRect->right < 0
1021 || DestRect->bottom > This->resource.height || DestRect->bottom < 0))
1023 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1024 return WINEDDERR_INVALIDRECT;
1027 if (DestRect->right <= 0 || DestRect->bottom <= 0
1028 || DestRect->left >= (int)This->resource.width
1029 || DestRect->top >= (int)This->resource.height)
1031 TRACE("Nothing to be done.\n");
1032 return WINED3D_OK;
1035 if (!src)
1037 RECT full_rect;
1039 full_rect.left = 0;
1040 full_rect.top = 0;
1041 full_rect.right = This->resource.width;
1042 full_rect.bottom = This->resource.height;
1043 IntersectRect(&xdst, &full_rect, DestRect);
1045 else
1047 BOOL clip_horiz, clip_vert;
1049 xdst = *DestRect;
1050 clip_horiz = xdst.left < 0 || xdst.right > (int)This->resource.width;
1051 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->resource.height;
1053 if (clip_vert || clip_horiz)
1055 /* Now check if this is a special case or not... */
1056 if ((flags & WINEDDBLT_DDFX)
1057 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1058 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1060 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1061 return WINED3D_OK;
1064 if (clip_horiz)
1066 if (xdst.left < 0)
1068 xsrc.left -= xdst.left;
1069 xdst.left = 0;
1071 if (xdst.right > This->resource.width)
1073 xsrc.right -= (xdst.right - (int)This->resource.width);
1074 xdst.right = (int)This->resource.width;
1078 if (clip_vert)
1080 if (xdst.top < 0)
1082 xsrc.top -= xdst.top;
1083 xdst.top = 0;
1085 if (xdst.bottom > This->resource.height)
1087 xsrc.bottom -= (xdst.bottom - (int)This->resource.height);
1088 xdst.bottom = (int)This->resource.height;
1092 /* And check if after clipping something is still to be done... */
1093 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1094 || (xdst.left >= (int)This->resource.width)
1095 || (xdst.top >= (int)This->resource.height)
1096 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1097 || (xsrc.left >= (int)src->resource.width)
1098 || (xsrc.top >= (int)src->resource.height))
1100 TRACE("Nothing to be done after clipping.\n");
1101 return WINED3D_OK;
1106 else
1108 xdst.left = 0;
1109 xdst.top = 0;
1110 xdst.right = This->resource.width;
1111 xdst.bottom = This->resource.height;
1114 if (src == This)
1116 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1117 slock = dlock;
1118 sEntry = This->resource.format;
1119 dEntry = sEntry;
1121 else
1123 dEntry = This->resource.format;
1124 if (src)
1126 if (This->resource.format->id != src->resource.format->id)
1128 src = surface_convert_format(src, dEntry->id);
1129 if (!src)
1131 /* The conv function writes a FIXME */
1132 WARN("Cannot convert source surface format to dest format\n");
1133 goto release;
1136 IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1137 sEntry = src->resource.format;
1139 else
1141 sEntry = dEntry;
1143 if (DestRect)
1144 IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1145 else
1146 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1149 if (!DDBltFx || !(DDBltFx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
1151 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_FOURCC)
1153 if (!DestRect || src == This)
1155 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1156 goto release;
1160 bpp = This->resource.format->byte_count;
1161 srcheight = xsrc.bottom - xsrc.top;
1162 srcwidth = xsrc.right - xsrc.left;
1163 dstheight = xdst.bottom - xdst.top;
1164 dstwidth = xdst.right - xdst.left;
1165 width = (xdst.right - xdst.left) * bpp;
1167 if (DestRect && src != This)
1168 dbuf = dlock.pBits;
1169 else
1170 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1172 if (flags & WINEDDBLT_WAIT)
1174 flags &= ~WINEDDBLT_WAIT;
1176 if (flags & WINEDDBLT_ASYNC)
1178 static BOOL displayed = FALSE;
1179 if (!displayed)
1180 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1181 displayed = TRUE;
1182 flags &= ~WINEDDBLT_ASYNC;
1184 if (flags & WINEDDBLT_DONOTWAIT)
1186 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1187 static BOOL displayed = FALSE;
1188 if (!displayed)
1189 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1190 displayed = TRUE;
1191 flags &= ~WINEDDBLT_DONOTWAIT;
1194 /* First, all the 'source-less' blits */
1195 if (flags & WINEDDBLT_COLORFILL)
1197 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1198 dlock.Pitch, DDBltFx->u5.dwFillColor);
1199 flags &= ~WINEDDBLT_COLORFILL;
1202 if (flags & WINEDDBLT_DEPTHFILL)
1204 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1206 if (flags & WINEDDBLT_ROP)
1208 /* Catch some degenerate cases here */
1209 switch(DDBltFx->dwROP)
1211 case BLACKNESS:
1212 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1213 break;
1214 case 0xAA0029: /* No-op */
1215 break;
1216 case WHITENESS:
1217 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1218 break;
1219 case SRCCOPY: /* well, we do that below ? */
1220 break;
1221 default:
1222 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1223 goto error;
1225 flags &= ~WINEDDBLT_ROP;
1227 if (flags & WINEDDBLT_DDROPS)
1229 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1231 /* Now the 'with source' blits */
1232 if (src)
1234 const BYTE *sbase;
1235 int sx, xinc, sy, yinc;
1237 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1238 goto release;
1240 if (Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT
1241 && (srcwidth != dstwidth || srcheight != dstheight))
1243 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1244 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter));
1247 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1248 xinc = (srcwidth << 16) / dstwidth;
1249 yinc = (srcheight << 16) / dstheight;
1251 if (!flags)
1253 /* No effects, we can cheat here */
1254 if (dstwidth == srcwidth)
1256 if (dstheight == srcheight)
1258 /* No stretching in either direction. This needs to be as
1259 * fast as possible */
1260 sbuf = sbase;
1262 /* check for overlapping surfaces */
1263 if (src != This || xdst.top < xsrc.top ||
1264 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1266 /* no overlap, or dst above src, so copy from top downwards */
1267 for (y = 0; y < dstheight; y++)
1269 memcpy(dbuf, sbuf, width);
1270 sbuf += slock.Pitch;
1271 dbuf += dlock.Pitch;
1274 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1276 sbuf += (slock.Pitch*dstheight);
1277 dbuf += (dlock.Pitch*dstheight);
1278 for (y = 0; y < dstheight; y++)
1280 sbuf -= slock.Pitch;
1281 dbuf -= dlock.Pitch;
1282 memcpy(dbuf, sbuf, width);
1285 else /* src and dst overlapping on the same line, use memmove */
1287 for (y = 0; y < dstheight; y++)
1289 memmove(dbuf, sbuf, width);
1290 sbuf += slock.Pitch;
1291 dbuf += dlock.Pitch;
1294 } else {
1295 /* Stretching in Y direction only */
1296 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1297 sbuf = sbase + (sy >> 16) * slock.Pitch;
1298 memcpy(dbuf, sbuf, width);
1299 dbuf += dlock.Pitch;
1303 else
1305 /* Stretching in X direction */
1306 int last_sy = -1;
1307 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1309 sbuf = sbase + (sy >> 16) * slock.Pitch;
1311 if ((sy >> 16) == (last_sy >> 16))
1313 /* this sourcerow is the same as last sourcerow -
1314 * copy already stretched row
1316 memcpy(dbuf, dbuf - dlock.Pitch, width);
1318 else
1320 #define STRETCH_ROW(type) { \
1321 const type *s = (const type *)sbuf; \
1322 type *d = (type *)dbuf; \
1323 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1324 d[x] = s[sx >> 16]; \
1325 break; }
1327 switch(bpp)
1329 case 1: STRETCH_ROW(BYTE)
1330 case 2: STRETCH_ROW(WORD)
1331 case 4: STRETCH_ROW(DWORD)
1332 case 3:
1334 const BYTE *s;
1335 BYTE *d = dbuf;
1336 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1338 DWORD pixel;
1340 s = sbuf+3*(sx>>16);
1341 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1342 d[0] = (pixel )&0xff;
1343 d[1] = (pixel>> 8)&0xff;
1344 d[2] = (pixel>>16)&0xff;
1345 d+=3;
1347 break;
1349 default:
1350 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1351 ret = WINED3DERR_NOTAVAILABLE;
1352 goto error;
1354 #undef STRETCH_ROW
1356 dbuf += dlock.Pitch;
1357 last_sy = sy;
1361 else
1363 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1364 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1365 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1366 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1368 /* The color keying flags are checked for correctness in ddraw */
1369 if (flags & WINEDDBLT_KEYSRC)
1371 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1372 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1374 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
1376 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1377 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1380 if (flags & WINEDDBLT_KEYDEST)
1382 /* Destination color keys are taken from the source surface ! */
1383 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1384 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1386 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
1388 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1389 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1392 if(bpp == 1)
1394 keymask = 0xff;
1396 else
1398 keymask = sEntry->red_mask
1399 | sEntry->green_mask
1400 | sEntry->blue_mask;
1402 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1405 if (flags & WINEDDBLT_DDFX)
1407 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1408 LONG tmpxy;
1409 dTopLeft = dbuf;
1410 dTopRight = dbuf+((dstwidth-1)*bpp);
1411 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1412 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1414 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1416 /* I don't think we need to do anything about this flag */
1417 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1419 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1421 tmp = dTopRight;
1422 dTopRight = dTopLeft;
1423 dTopLeft = tmp;
1424 tmp = dBottomRight;
1425 dBottomRight = dBottomLeft;
1426 dBottomLeft = tmp;
1427 dstxinc = dstxinc *-1;
1429 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1431 tmp = dTopLeft;
1432 dTopLeft = dBottomLeft;
1433 dBottomLeft = tmp;
1434 tmp = dTopRight;
1435 dTopRight = dBottomRight;
1436 dBottomRight = tmp;
1437 dstyinc = dstyinc *-1;
1439 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1441 /* I don't think we need to do anything about this flag */
1442 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1444 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1446 tmp = dBottomRight;
1447 dBottomRight = dTopLeft;
1448 dTopLeft = tmp;
1449 tmp = dBottomLeft;
1450 dBottomLeft = dTopRight;
1451 dTopRight = tmp;
1452 dstxinc = dstxinc * -1;
1453 dstyinc = dstyinc * -1;
1455 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1457 tmp = dTopLeft;
1458 dTopLeft = dBottomLeft;
1459 dBottomLeft = dBottomRight;
1460 dBottomRight = dTopRight;
1461 dTopRight = tmp;
1462 tmpxy = dstxinc;
1463 dstxinc = dstyinc;
1464 dstyinc = tmpxy;
1465 dstxinc = dstxinc * -1;
1467 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1469 tmp = dTopLeft;
1470 dTopLeft = dTopRight;
1471 dTopRight = dBottomRight;
1472 dBottomRight = dBottomLeft;
1473 dBottomLeft = tmp;
1474 tmpxy = dstxinc;
1475 dstxinc = dstyinc;
1476 dstyinc = tmpxy;
1477 dstyinc = dstyinc * -1;
1479 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1481 /* I don't think we need to do anything about this flag */
1482 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1484 dbuf = dTopLeft;
1485 flags &= ~(WINEDDBLT_DDFX);
1488 #define COPY_COLORKEY_FX(type) { \
1489 const type *s; \
1490 type *d = (type *)dbuf, *dx, tmp; \
1491 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1492 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1493 dx = d; \
1494 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1495 tmp = s[sx >> 16]; \
1496 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1497 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1498 dx[0] = tmp; \
1500 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1502 d = (type*)(((LPBYTE)d)+dstyinc); \
1504 break; }
1506 switch (bpp) {
1507 case 1: COPY_COLORKEY_FX(BYTE)
1508 case 2: COPY_COLORKEY_FX(WORD)
1509 case 4: COPY_COLORKEY_FX(DWORD)
1510 case 3:
1512 const BYTE *s;
1513 BYTE *d = dbuf, *dx;
1514 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1516 sbuf = sbase + (sy >> 16) * slock.Pitch;
1517 dx = d;
1518 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1520 DWORD pixel, dpixel = 0;
1521 s = sbuf+3*(sx>>16);
1522 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1523 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1524 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1525 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1527 dx[0] = (pixel )&0xff;
1528 dx[1] = (pixel>> 8)&0xff;
1529 dx[2] = (pixel>>16)&0xff;
1531 dx+= dstxinc;
1533 d += dstyinc;
1535 break;
1537 default:
1538 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1539 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1540 ret = WINED3DERR_NOTAVAILABLE;
1541 goto error;
1542 #undef COPY_COLORKEY_FX
1547 error:
1548 if (flags && FIXME_ON(d3d_surface))
1550 FIXME("\tUnsupported flags: %#x.\n", flags);
1553 release:
1554 IWineD3DSurface_Unmap(iface);
1555 if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1556 /* Release the converted surface if any */
1557 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1558 return ret;
1561 /*****************************************************************************
1562 * IWineD3DSurface::BltFast, SW emulation version
1564 * This is the software implementation of BltFast, as used by GDI surfaces
1565 * and as a fallback for OpenGL surfaces. This code is taken from the old
1566 * DirectDraw code, and was originally written by TransGaming.
1568 * Params:
1569 * dstx:
1570 * dsty:
1571 * src_surface: Source surface to copy from
1572 * rsrc: Source rectangle
1573 * trans: Some flags
1575 * Returns:
1576 * WINED3D_OK on success
1578 *****************************************************************************/
1579 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1580 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1582 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1583 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1585 int bpp, w, h, x, y;
1586 WINED3DLOCKED_RECT dlock,slock;
1587 HRESULT ret = WINED3D_OK;
1588 RECT rsrc2;
1589 RECT lock_src, lock_dst, lock_union;
1590 const BYTE *sbuf;
1591 BYTE *dbuf;
1592 const struct wined3d_format *sEntry, *dEntry;
1594 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1595 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1597 if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
1599 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1600 return WINEDDERR_SURFACEBUSY;
1603 if (!rsrc)
1605 WARN("rsrc is NULL!\n");
1606 rsrc2.left = 0;
1607 rsrc2.top = 0;
1608 rsrc2.right = src->resource.width;
1609 rsrc2.bottom = src->resource.height;
1610 rsrc = &rsrc2;
1613 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1614 if ((rsrc->bottom > src->resource.height) || (rsrc->bottom < 0)
1615 || (rsrc->top > src->resource.height) || (rsrc->top < 0)
1616 || (rsrc->left > src->resource.width) || (rsrc->left < 0)
1617 || (rsrc->right > src->resource.width) || (rsrc->right < 0)
1618 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1620 WARN("Application gave us bad source rectangle for BltFast.\n");
1621 return WINEDDERR_INVALIDRECT;
1624 h = rsrc->bottom - rsrc->top;
1625 if (h > This->resource.height-dsty)
1626 h = This->resource.height-dsty;
1627 if (h > src->resource.height-rsrc->top)
1628 h = src->resource.height-rsrc->top;
1629 if (h <= 0)
1630 return WINEDDERR_INVALIDRECT;
1632 w = rsrc->right - rsrc->left;
1633 if (w > This->resource.width-dstx)
1634 w = This->resource.width-dstx;
1635 if (w > src->resource.width-rsrc->left)
1636 w = src->resource.width-rsrc->left;
1637 if (w <= 0)
1638 return WINEDDERR_INVALIDRECT;
1640 /* Now compute the locking rectangle... */
1641 lock_src.left = rsrc->left;
1642 lock_src.top = rsrc->top;
1643 lock_src.right = lock_src.left + w;
1644 lock_src.bottom = lock_src.top + h;
1646 lock_dst.left = dstx;
1647 lock_dst.top = dsty;
1648 lock_dst.right = dstx + w;
1649 lock_dst.bottom = dsty + h;
1651 bpp = This->resource.format->byte_count;
1653 /* We need to lock the surfaces, or we won't get refreshes when done. */
1654 if (src == This)
1656 int pitch;
1658 UnionRect(&lock_union, &lock_src, &lock_dst);
1660 /* Lock the union of the two rectangles */
1661 ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
1662 if (FAILED(ret)) goto error;
1664 pitch = dlock.Pitch;
1665 slock.Pitch = dlock.Pitch;
1667 /* Since slock was originally copied from this surface's description, we can just reuse it */
1668 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1669 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1670 sEntry = src->resource.format;
1671 dEntry = sEntry;
1673 else
1675 ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1676 if (FAILED(ret)) goto error;
1677 ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
1678 if (FAILED(ret)) goto error;
1680 sbuf = slock.pBits;
1681 dbuf = dlock.pBits;
1682 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1684 sEntry = src->resource.format;
1685 dEntry = This->resource.format;
1688 /* Handle compressed surfaces first... */
1689 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_COMPRESSED)
1691 UINT row_block_count;
1693 TRACE("compressed -> compressed copy\n");
1694 if (trans)
1695 FIXME("trans arg not supported when a compressed surface is involved\n");
1696 if (dstx || dsty)
1697 FIXME("offset for destination surface is not supported\n");
1698 if (src->resource.format->id != This->resource.format->id)
1700 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1701 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1702 goto error;
1705 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1706 for (y = 0; y < h; y += dEntry->block_height)
1708 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1709 dbuf += dlock.Pitch;
1710 sbuf += slock.Pitch;
1713 goto error;
1715 if ((sEntry->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->flags & WINED3DFMT_FLAG_COMPRESSED))
1717 /* TODO: Use the libtxc_dxtn.so shared library to do
1718 * software decompression
1720 ERR("Software decompression not supported.\n");
1721 goto error;
1724 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1726 DWORD keylow, keyhigh;
1727 DWORD mask = src->resource.format->red_mask
1728 | src->resource.format->green_mask
1729 | src->resource.format->blue_mask;
1731 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1732 if(!mask && bpp==1)
1733 mask = 0xff;
1735 TRACE("Color keyed copy\n");
1736 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1738 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1739 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1741 else
1743 /* I'm not sure if this is correct */
1744 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1745 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1746 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1749 #define COPYBOX_COLORKEY(type) { \
1750 const type *s = (const type *)sbuf; \
1751 type *d = (type *)dbuf; \
1752 type tmp; \
1753 for (y = 0; y < h; y++) { \
1754 for (x = 0; x < w; x++) { \
1755 tmp = s[x]; \
1756 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1758 s = (const type *)((const BYTE *)s + slock.Pitch); \
1759 d = (type *)((BYTE *)d + dlock.Pitch); \
1761 break; \
1764 switch (bpp) {
1765 case 1: COPYBOX_COLORKEY(BYTE)
1766 case 2: COPYBOX_COLORKEY(WORD)
1767 case 4: COPYBOX_COLORKEY(DWORD)
1768 case 3:
1770 const BYTE *s;
1771 BYTE *d;
1772 DWORD tmp;
1773 s = sbuf;
1774 d = dbuf;
1775 for (y = 0; y < h; y++)
1777 for (x = 0; x < w * 3; x += 3)
1779 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1780 if (tmp < keylow || tmp > keyhigh)
1782 d[x + 0] = s[x + 0];
1783 d[x + 1] = s[x + 1];
1784 d[x + 2] = s[x + 2];
1787 s += slock.Pitch;
1788 d += dlock.Pitch;
1790 break;
1792 default:
1793 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1794 ret = WINED3DERR_NOTAVAILABLE;
1795 goto error;
1797 #undef COPYBOX_COLORKEY
1798 TRACE("Copy Done\n");
1800 else
1802 int width = w * bpp;
1803 INT sbufpitch, dbufpitch;
1805 TRACE("NO color key copy\n");
1806 /* Handle overlapping surfaces */
1807 if (sbuf < dbuf)
1809 sbuf += (h - 1) * slock.Pitch;
1810 dbuf += (h - 1) * dlock.Pitch;
1811 sbufpitch = -slock.Pitch;
1812 dbufpitch = -dlock.Pitch;
1814 else
1816 sbufpitch = slock.Pitch;
1817 dbufpitch = dlock.Pitch;
1819 for (y = 0; y < h; y++)
1821 /* This is pretty easy, a line for line memcpy */
1822 memmove(dbuf, sbuf, width);
1823 sbuf += sbufpitch;
1824 dbuf += dbufpitch;
1826 TRACE("Copy done\n");
1829 error:
1830 if (src == This)
1832 IWineD3DSurface_Unmap(iface);
1834 else
1836 IWineD3DSurface_Unmap(iface);
1837 IWineD3DSurface_Unmap(src_surface);
1840 return ret;
1843 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
1844 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
1846 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1848 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1849 iface, pLockedRect, wine_dbgstr_rect(pRect), flags);
1851 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1853 if (!pRect)
1855 pLockedRect->pBits = This->resource.allocatedMemory;
1856 This->lockedRect.left = 0;
1857 This->lockedRect.top = 0;
1858 This->lockedRect.right = This->resource.width;
1859 This->lockedRect.bottom = This->resource.height;
1861 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1862 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1863 This->lockedRect.right, This->lockedRect.bottom);
1865 else
1867 const struct wined3d_format *format = This->resource.format;
1869 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1870 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1872 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1874 /* Compressed textures are block based, so calculate the offset of
1875 * the block that contains the top-left pixel of the locked rectangle. */
1876 pLockedRect->pBits = This->resource.allocatedMemory
1877 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1878 + ((pRect->left / format->block_width) * format->block_byte_count);
1880 else
1882 pLockedRect->pBits = This->resource.allocatedMemory +
1883 (pLockedRect->Pitch * pRect->top) +
1884 (pRect->left * format->byte_count);
1886 This->lockedRect.left = pRect->left;
1887 This->lockedRect.top = pRect->top;
1888 This->lockedRect.right = pRect->right;
1889 This->lockedRect.bottom = pRect->bottom;
1892 /* No dirtifying is needed for this surface implementation */
1893 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1895 return WINED3D_OK;