push 3de9b6d6ec9c4ab8dfeeb76c2f7fb86ab1d5c9a7
[wine/hacks.git] / dlls / wined3d / surface_base.c
blob598c93259821de4c200f971a3b52655f47958cd3
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-2007 Stefan Dösinger for CodeWeavers
11 * Copyright 2007 Henri Verbeet
12 * Copyright 2006-2007 Roderick Colenbrander
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 #include <assert.h>
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
37 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
39 /* *******************************************
40 IWineD3DSurface IUnknown parts follow
41 ******************************************* */
42 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
44 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
45 /* Warn ,but be nice about things */
46 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
48 if (IsEqualGUID(riid, &IID_IUnknown)
49 || IsEqualGUID(riid, &IID_IWineD3DBase)
50 || IsEqualGUID(riid, &IID_IWineD3DResource)
51 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
52 IUnknown_AddRef((IUnknown*)iface);
53 *ppobj = This;
54 return S_OK;
56 *ppobj = NULL;
57 return E_NOINTERFACE;
60 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
61 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
62 ULONG ref = InterlockedIncrement(&This->resource.ref);
63 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
64 return ref;
67 /* ****************************************************
68 IWineD3DSurface IWineD3DResource parts follow
69 **************************************************** */
70 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
71 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
74 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
75 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
78 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
79 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
82 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
83 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
86 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
87 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
90 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
91 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
94 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
95 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
96 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
99 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
100 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
101 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
104 /* ******************************************************
105 IWineD3DSurface IWineD3DSurface parts follow
106 ****************************************************** */
108 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
109 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
110 IWineD3DBase *container = 0;
112 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
114 if (!ppContainer) {
115 ERR("Called without a valid ppContainer.\n");
118 /** From MSDN:
119 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
120 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
121 * GetContainer will return the Direct3D device used to create the surface.
123 if (This->container) {
124 container = This->container;
125 } else {
126 container = (IWineD3DBase *)This->resource.wineD3DDevice;
129 TRACE("Relaying to QueryInterface\n");
130 return IUnknown_QueryInterface(container, riid, ppContainer);
133 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
134 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
136 TRACE("(%p) : copying into %p\n", This, pDesc);
137 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
138 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
139 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
140 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
141 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
142 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
143 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
144 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
145 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
146 return WINED3D_OK;
149 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
150 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
151 TRACE("(%p)->(%x)\n", This, Flags);
153 switch (Flags)
155 case WINEDDGBS_CANBLT:
156 case WINEDDGBS_ISBLTDONE:
157 return WINED3D_OK;
159 default:
160 return WINED3DERR_INVALIDCALL;
164 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
165 /* XXX: DDERR_INVALIDSURFACETYPE */
167 TRACE("(%p)->(%08x)\n",iface,Flags);
168 switch (Flags) {
169 case WINEDDGFS_CANFLIP:
170 case WINEDDGFS_ISFLIPDONE:
171 return WINED3D_OK;
173 default:
174 return WINED3DERR_INVALIDCALL;
178 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
179 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
180 TRACE("(%p)\n", This);
182 /* D3D8 and 9 loose full devices, ddraw only surfaces */
183 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
186 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
187 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
188 TRACE("(%p)\n", This);
190 /* So far we don't lose anything :) */
191 This->Flags &= ~SFLAG_LOST;
192 return WINED3D_OK;
195 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
196 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
197 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
198 TRACE("(%p)->(%p)\n", This, Pal);
200 if(This->palette != NULL)
201 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
202 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
204 if(PalImpl != NULL) {
205 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
206 /* Set the device's main palette if the palette
207 * wasn't a primary palette before
209 if(!(PalImpl->Flags & WINEDDPCAPS_PRIMARYSURFACE)) {
210 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
211 unsigned int i;
213 for(i=0; i < 256; i++) {
214 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
218 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
221 This->palette = PalImpl;
223 return IWineD3DSurface_RealizePalette(iface);
226 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, WINEDDCOLORKEY *CKey) {
227 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
228 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
230 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
231 FIXME(" colorkey value not supported (%08x) !\n", Flags);
232 return WINED3DERR_INVALIDCALL;
235 /* Dirtify the surface, but only if a key was changed */
236 if(CKey) {
237 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
238 case WINEDDCKEY_DESTBLT:
239 This->DestBltCKey = *CKey;
240 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
241 break;
243 case WINEDDCKEY_DESTOVERLAY:
244 This->DestOverlayCKey = *CKey;
245 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
246 break;
248 case WINEDDCKEY_SRCOVERLAY:
249 This->SrcOverlayCKey = *CKey;
250 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
251 break;
253 case WINEDDCKEY_SRCBLT:
254 This->SrcBltCKey = *CKey;
255 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
256 break;
259 else {
260 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
261 case WINEDDCKEY_DESTBLT:
262 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
263 break;
265 case WINEDDCKEY_DESTOVERLAY:
266 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
267 break;
269 case WINEDDCKEY_SRCOVERLAY:
270 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
271 break;
273 case WINEDDCKEY_SRCBLT:
274 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
275 break;
279 return WINED3D_OK;
282 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
283 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
284 TRACE("(%p)->(%p)\n", This, Pal);
286 *Pal = (IWineD3DPalette *) This->palette;
287 return WINED3D_OK;
290 HRESULT WINAPI IWineD3DBaseSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
291 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
292 RGBQUAD col[256];
293 IWineD3DPaletteImpl *pal = This->palette;
294 unsigned int n;
295 TRACE("(%p)\n", This);
297 if(This->resource.format == WINED3DFMT_P8 ||
298 This->resource.format == WINED3DFMT_A8P8)
300 if(!This->Flags & SFLAG_INSYSMEM) {
301 FIXME("Palette changed with surface that does not have an up to date system memory copy\n");
303 TRACE("Dirtifying surface\n");
304 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
307 if(This->Flags & SFLAG_DIBSECTION) {
308 TRACE("(%p): Updating the hdc's palette\n", This);
309 for (n=0; n<256; n++) {
310 if(pal) {
311 col[n].rgbRed = pal->palents[n].peRed;
312 col[n].rgbGreen = pal->palents[n].peGreen;
313 col[n].rgbBlue = pal->palents[n].peBlue;
314 } else {
315 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
316 /* Use the default device palette */
317 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
318 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
319 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
321 col[n].rgbReserved = 0;
323 SetDIBColorTable(This->hDC, 0, 256, col);
326 return WINED3D_OK;
329 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
330 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
331 DWORD ret;
332 TRACE("(%p)\n", This);
334 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
335 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
336 ie pitch = (width/4) * bytes per block */
337 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
338 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
339 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
340 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
341 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
342 else {
343 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
344 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
345 ret = (ret + alignment - 1) & ~(alignment - 1);
347 TRACE("(%p) Returning %d\n", This, ret);
348 return ret;
351 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
352 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
354 FIXME("(%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 return WINED3D_OK;
365 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
366 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
368 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
370 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
372 TRACE("(%p): Not an overlay surface\n", This);
373 return WINEDDERR_NOTAOVERLAYSURFACE;
376 return WINED3D_OK;
379 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
380 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
381 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
383 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
385 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
387 TRACE("(%p): Not an overlay surface\n", This);
388 return WINEDDERR_NOTAOVERLAYSURFACE;
391 return WINED3D_OK;
394 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
395 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
396 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
397 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
399 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
401 TRACE("(%p): Not an overlay surface\n", This);
402 return WINEDDERR_NOTAOVERLAYSURFACE;
405 return WINED3D_OK;
408 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
410 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
411 TRACE("(%p)->(%p)\n", This, clipper);
413 This->clipper = clipper;
414 return WINED3D_OK;
417 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
419 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
420 TRACE("(%p)->(%p)\n", This, clipper);
422 *clipper = This->clipper;
423 if(*clipper) {
424 IWineD3DClipper_AddRef(*clipper);
426 return WINED3D_OK;
429 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
430 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
432 TRACE("This %p, container %p\n", This, container);
434 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
436 TRACE("Setting container to %p from %p\n", container, This->container);
437 This->container = container;
439 return WINED3D_OK;
442 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
443 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
444 const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(format, NULL, NULL);
446 if (This->resource.format != WINED3DFMT_UNKNOWN) {
447 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
448 return WINED3DERR_INVALIDCALL;
451 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
452 if (format == WINED3DFMT_UNKNOWN) {
453 This->resource.size = 0;
454 } else if (format == WINED3DFMT_DXT1) {
455 /* DXT1 is half byte per pixel */
456 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
458 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
459 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
460 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
461 } else {
462 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
463 This->resource.size = ((This->pow2Width * formatEntry->bpp) + alignment - 1) & ~(alignment - 1);
464 This->resource.size *= This->pow2Height;
467 if (format != WINED3DFMT_UNKNOWN) {
468 This->bytesPerPixel = formatEntry->bpp;
469 } else {
470 This->bytesPerPixel = 0;
473 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
475 This->resource.format = format;
477 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, This->bytesPerPixel);
479 return WINED3D_OK;
482 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
483 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
484 int extraline = 0;
485 SYSTEM_INFO sysInfo;
486 void *oldmem = This->resource.allocatedMemory;
487 BITMAPINFO* b_info;
488 HDC ddc;
489 DWORD *masks;
490 const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format, NULL, NULL);
491 UINT usage;
493 switch (This->bytesPerPixel) {
494 case 2:
495 case 4:
496 /* Allocate extra space to store the RGB bit masks. */
497 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
498 break;
500 case 3:
501 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
502 break;
504 default:
505 /* Allocate extra space for a palette. */
506 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
507 sizeof(BITMAPINFOHEADER)
508 + sizeof(RGBQUAD)
509 * (1 << (This->bytesPerPixel * 8)));
510 break;
513 if (!b_info)
514 return E_OUTOFMEMORY;
516 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
517 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
518 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
519 * add an extra line to the dib section
521 GetSystemInfo(&sysInfo);
522 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
523 extraline = 1;
524 TRACE("Adding an extra line to the dib section\n");
527 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
528 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
529 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / This->bytesPerPixel;
530 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
531 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
532 b_info->bmiHeader.biPlanes = 1;
533 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
535 b_info->bmiHeader.biXPelsPerMeter = 0;
536 b_info->bmiHeader.biYPelsPerMeter = 0;
537 b_info->bmiHeader.biClrUsed = 0;
538 b_info->bmiHeader.biClrImportant = 0;
540 /* Get the bit masks */
541 masks = (DWORD *) &(b_info->bmiColors);
542 switch (This->resource.format) {
543 case WINED3DFMT_R8G8B8:
544 usage = DIB_RGB_COLORS;
545 b_info->bmiHeader.biCompression = BI_RGB;
546 break;
548 case WINED3DFMT_X1R5G5B5:
549 case WINED3DFMT_A1R5G5B5:
550 case WINED3DFMT_A4R4G4B4:
551 case WINED3DFMT_X4R4G4B4:
552 case WINED3DFMT_R3G3B2:
553 case WINED3DFMT_A8R3G3B2:
554 case WINED3DFMT_A2B10G10R10:
555 case WINED3DFMT_A8B8G8R8:
556 case WINED3DFMT_X8B8G8R8:
557 case WINED3DFMT_A2R10G10B10:
558 case WINED3DFMT_R5G6B5:
559 case WINED3DFMT_A16B16G16R16:
560 usage = 0;
561 b_info->bmiHeader.biCompression = BI_BITFIELDS;
562 masks[0] = formatEntry->redMask;
563 masks[1] = formatEntry->greenMask;
564 masks[2] = formatEntry->blueMask;
565 break;
567 default:
568 /* Don't know palette */
569 b_info->bmiHeader.biCompression = BI_RGB;
570 usage = 0;
571 break;
574 ddc = GetDC(0);
575 if (ddc == 0) {
576 HeapFree(GetProcessHeap(), 0, b_info);
577 return HRESULT_FROM_WIN32(GetLastError());
580 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);
581 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
582 ReleaseDC(0, ddc);
584 if (!This->dib.DIBsection) {
585 ERR("CreateDIBSection failed!\n");
586 HeapFree(GetProcessHeap(), 0, b_info);
587 return HRESULT_FROM_WIN32(GetLastError());
590 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
591 /* copy the existing surface to the dib section */
592 if(This->resource.allocatedMemory) {
593 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
594 } else {
595 /* This is to make LockRect read the gl Texture although memory is allocated */
596 This->Flags &= ~SFLAG_INSYSMEM;
598 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
600 HeapFree(GetProcessHeap(), 0, b_info);
602 /* Now allocate a HDC */
603 This->hDC = CreateCompatibleDC(0);
604 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
605 TRACE("using wined3d palette %p\n", This->palette);
606 SelectPalette(This->hDC,
607 This->palette ? This->palette->hpal : 0,
608 FALSE);
610 This->Flags |= SFLAG_DIBSECTION;
612 HeapFree(GetProcessHeap(), 0, oldmem);
614 return WINED3D_OK;
617 /*****************************************************************************
618 * _Blt_ColorFill
620 * Helper function that fills a memory area with a specific color
622 * Params:
623 * buf: memory address to start filling at
624 * width, height: Dimensions of the area to fill
625 * bpp: Bit depth of the surface
626 * lPitch: pitch of the surface
627 * color: Color to fill with
629 *****************************************************************************/
630 static HRESULT
631 _Blt_ColorFill(BYTE *buf,
632 int width, int height,
633 int bpp, LONG lPitch,
634 DWORD color)
636 int x, y;
637 LPBYTE first;
639 /* Do first row */
641 #define COLORFILL_ROW(type) \
643 type *d = (type *) buf; \
644 for (x = 0; x < width; x++) \
645 d[x] = (type) color; \
646 break; \
648 switch(bpp)
650 case 1: COLORFILL_ROW(BYTE)
651 case 2: COLORFILL_ROW(WORD)
652 case 3:
654 BYTE *d = (BYTE *) buf;
655 for (x = 0; x < width; x++,d+=3)
657 d[0] = (color ) & 0xFF;
658 d[1] = (color>> 8) & 0xFF;
659 d[2] = (color>>16) & 0xFF;
661 break;
663 case 4: COLORFILL_ROW(DWORD)
664 default:
665 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
666 return WINED3DERR_NOTAVAILABLE;
669 #undef COLORFILL_ROW
671 /* Now copy first row */
672 first = buf;
673 for (y = 1; y < height; y++)
675 buf += lPitch;
676 memcpy(buf, first, width * bpp);
678 return WINED3D_OK;
681 /*****************************************************************************
682 * IWineD3DSurface::Blt, SW emulation version
684 * Performs blits to a surface, eigher from a source of source-less blts
685 * This is the main functionality of DirectDraw
687 * Params:
688 * DestRect: Destination rectangle to write to
689 * SrcSurface: Source surface, can be NULL
690 * SrcRect: Source rectangle
691 *****************************************************************************/
692 HRESULT WINAPI
693 IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface,
694 RECT *DestRect,
695 IWineD3DSurface *SrcSurface,
696 RECT *SrcRect,
697 DWORD Flags,
698 WINEDDBLTFX *DDBltFx,
699 WINED3DTEXTUREFILTERTYPE Filter)
701 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
702 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
703 RECT xdst,xsrc;
704 HRESULT ret = WINED3D_OK;
705 WINED3DLOCKED_RECT dlock, slock;
706 WINED3DFORMAT dfmt = WINED3DFMT_UNKNOWN, sfmt = WINED3DFMT_UNKNOWN;
707 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
708 int x, y;
709 const StaticPixelFormatDesc *sEntry, *dEntry;
710 LPBYTE dbuf, sbuf;
711 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
713 if (TRACE_ON(d3d_surface))
715 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
716 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
717 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
718 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
719 #if 0
720 TRACE("\tflags: ");
721 DDRAW_dump_DDBLT(Flags);
722 if (Flags & WINEDDBLT_DDFX)
724 TRACE("\tblitfx: ");
725 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
727 #endif
730 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
732 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
733 return WINEDDERR_SURFACEBUSY;
736 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
737 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
738 FIXME("Filters not supported in software blit\n");
741 if (Src == This)
743 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
744 dfmt = This->resource.format;
745 slock = dlock;
746 sfmt = dfmt;
747 sEntry = getFormatDescEntry(sfmt, NULL, NULL);
748 dEntry = sEntry;
750 else
752 if (Src)
754 IWineD3DSurface_LockRect(SrcSurface, &slock, NULL, WINED3DLOCK_READONLY);
755 sfmt = Src->resource.format;
757 sEntry = getFormatDescEntry(sfmt, NULL, NULL);
758 dfmt = This->resource.format;
759 dEntry = getFormatDescEntry(dfmt, NULL, NULL);
760 IWineD3DSurface_LockRect(iface, &dlock,NULL,0);
763 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
765 if (sEntry->isFourcc && dEntry->isFourcc)
767 if (sfmt != dfmt)
769 FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
770 ret = WINED3DERR_WRONGTEXTUREFORMAT;
771 goto release;
773 memcpy(dlock.pBits, slock.pBits, This->resource.size);
774 goto release;
777 if (sEntry->isFourcc && !dEntry->isFourcc)
779 FIXME("DXTC decompression not supported right now\n");
780 goto release;
783 if (DestRect)
785 memcpy(&xdst,DestRect,sizeof(xdst));
787 else
789 xdst.top = 0;
790 xdst.bottom = This->currentDesc.Height;
791 xdst.left = 0;
792 xdst.right = This->currentDesc.Width;
795 if (SrcRect)
797 memcpy(&xsrc,SrcRect,sizeof(xsrc));
799 else
801 if (Src)
803 xsrc.top = 0;
804 xsrc.bottom = Src->currentDesc.Height;
805 xsrc.left = 0;
806 xsrc.right = Src->currentDesc.Width;
808 else
810 memset(&xsrc,0,sizeof(xsrc));
814 /* First check for the validity of source / destination rectangles. This was
815 * verified using a test application + by MSDN.
817 if ((Src != NULL) &&
818 ((xsrc.bottom > Src->currentDesc.Height) || (xsrc.bottom < 0) ||
819 (xsrc.top > Src->currentDesc.Height) || (xsrc.top < 0) ||
820 (xsrc.left > Src->currentDesc.Width) || (xsrc.left < 0) ||
821 (xsrc.right > Src->currentDesc.Width) || (xsrc.right < 0) ||
822 (xsrc.right < xsrc.left) || (xsrc.bottom < xsrc.top)))
824 WARN("Application gave us bad source rectangle for Blt.\n");
825 ret = WINEDDERR_INVALIDRECT;
826 goto release;
828 /* For the Destination rect, it can be out of bounds on the condition that a clipper
829 * is set for the given surface.
831 if ((/*This->clipper == NULL*/ TRUE) &&
832 ((xdst.bottom > This->currentDesc.Height) || (xdst.bottom < 0) ||
833 (xdst.top > This->currentDesc.Height) || (xdst.top < 0) ||
834 (xdst.left > This->currentDesc.Width) || (xdst.left < 0) ||
835 (xdst.right > This->currentDesc.Width) || (xdst.right < 0) ||
836 (xdst.right < xdst.left) || (xdst.bottom < xdst.top)))
838 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
839 ret = WINEDDERR_INVALIDRECT;
840 goto release;
843 /* Now handle negative values in the rectangles. Warning: only supported for now
844 in the 'simple' cases (ie not in any stretching / rotation cases).
846 First, the case where nothing is to be done.
848 if (((xdst.bottom <= 0) || (xdst.right <= 0) ||
849 (xdst.top >= (int) This->currentDesc.Height) ||
850 (xdst.left >= (int) This->currentDesc.Width)) ||
851 ((Src != NULL) &&
852 ((xsrc.bottom <= 0) || (xsrc.right <= 0) ||
853 (xsrc.top >= (int) Src->currentDesc.Height) ||
854 (xsrc.left >= (int) Src->currentDesc.Width)) ))
856 TRACE("Nothing to be done !\n");
857 goto release;
860 /* The easy case : the source-less blits.... */
861 if (Src == NULL)
863 RECT full_rect;
864 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
866 full_rect.left = 0;
867 full_rect.top = 0;
868 full_rect.right = This->currentDesc.Width;
869 full_rect.bottom = This->currentDesc.Height;
870 IntersectRect(&temp_rect, &full_rect, &xdst);
871 xdst = temp_rect;
873 else
875 /* Only handle clipping on the destination rectangle */
876 int clip_horiz = (xdst.left < 0) || (xdst.right > (int) This->currentDesc.Width );
877 int clip_vert = (xdst.top < 0) || (xdst.bottom > (int) This->currentDesc.Height);
878 if (clip_vert || clip_horiz)
880 /* Now check if this is a special case or not... */
881 if ((((xdst.bottom - xdst.top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
882 (((xdst.right - xdst.left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
883 (Flags & WINEDDBLT_DDFX))
885 WARN("Out of screen rectangle in special case. Not handled right now.\n");
886 goto release;
889 if (clip_horiz)
891 if (xdst.left < 0) { xsrc.left -= xdst.left; xdst.left = 0; }
892 if (xdst.right > This->currentDesc.Width)
894 xsrc.right -= (xdst.right - (int) This->currentDesc.Width);
895 xdst.right = (int) This->currentDesc.Width;
898 if (clip_vert)
900 if (xdst.top < 0)
902 xsrc.top -= xdst.top;
903 xdst.top = 0;
905 if (xdst.bottom > This->currentDesc.Height)
907 xsrc.bottom -= (xdst.bottom - (int) This->currentDesc.Height);
908 xdst.bottom = (int) This->currentDesc.Height;
911 /* And check if after clipping something is still to be done... */
912 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
913 (xdst.top >= (int) This->currentDesc.Height) ||
914 (xdst.left >= (int) This->currentDesc.Width) ||
915 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
916 (xsrc.top >= (int) Src->currentDesc.Height) ||
917 (xsrc.left >= (int) Src->currentDesc.Width))
919 TRACE("Nothing to be done after clipping !\n");
920 goto release;
925 bpp = This->bytesPerPixel;
926 srcheight = xsrc.bottom - xsrc.top;
927 srcwidth = xsrc.right - xsrc.left;
928 dstheight = xdst.bottom - xdst.top;
929 dstwidth = xdst.right - xdst.left;
930 width = (xdst.right - xdst.left) * bpp;
932 assert(width <= dlock.Pitch);
934 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
936 if (Flags & WINEDDBLT_WAIT)
938 Flags &= ~WINEDDBLT_WAIT;
940 if (Flags & WINEDDBLT_ASYNC)
942 static BOOL displayed = FALSE;
943 if (!displayed)
944 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
945 displayed = TRUE;
946 Flags &= ~WINEDDBLT_ASYNC;
948 if (Flags & WINEDDBLT_DONOTWAIT)
950 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
951 static BOOL displayed = FALSE;
952 if (!displayed)
953 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
954 displayed = TRUE;
955 Flags &= ~WINEDDBLT_DONOTWAIT;
958 /* First, all the 'source-less' blits */
959 if (Flags & WINEDDBLT_COLORFILL)
961 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
962 dlock.Pitch, DDBltFx->u5.dwFillColor);
963 Flags &= ~WINEDDBLT_COLORFILL;
966 if (Flags & WINEDDBLT_DEPTHFILL)
968 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
970 if (Flags & WINEDDBLT_ROP)
972 /* Catch some degenerate cases here */
973 switch(DDBltFx->dwROP)
975 case BLACKNESS:
976 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
977 break;
978 case 0xAA0029: /* No-op */
979 break;
980 case WHITENESS:
981 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
982 break;
983 case SRCCOPY: /* well, we do that below ? */
984 break;
985 default:
986 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
987 goto error;
989 Flags &= ~WINEDDBLT_ROP;
991 if (Flags & WINEDDBLT_DDROPS)
993 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
995 /* Now the 'with source' blits */
996 if (Src)
998 LPBYTE sbase;
999 int sx, xinc, sy, yinc;
1001 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1002 goto release;
1003 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1004 xinc = (srcwidth << 16) / dstwidth;
1005 yinc = (srcheight << 16) / dstheight;
1007 if (!Flags)
1009 /* No effects, we can cheat here */
1010 if (dstwidth == srcwidth)
1012 if (dstheight == srcheight)
1014 /* No stretching in either direction. This needs to be as
1015 * fast as possible */
1016 sbuf = sbase;
1018 /* check for overlapping surfaces */
1019 if (SrcSurface != iface || xdst.top < xsrc.top ||
1020 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1022 /* no overlap, or dst above src, so copy from top downwards */
1023 for (y = 0; y < dstheight; y++)
1025 memcpy(dbuf, sbuf, width);
1026 sbuf += slock.Pitch;
1027 dbuf += dlock.Pitch;
1030 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1032 sbuf += (slock.Pitch*dstheight);
1033 dbuf += (dlock.Pitch*dstheight);
1034 for (y = 0; y < dstheight; y++)
1036 sbuf -= slock.Pitch;
1037 dbuf -= dlock.Pitch;
1038 memcpy(dbuf, sbuf, width);
1041 else /* src and dst overlapping on the same line, use memmove */
1043 for (y = 0; y < dstheight; y++)
1045 memmove(dbuf, sbuf, width);
1046 sbuf += slock.Pitch;
1047 dbuf += dlock.Pitch;
1050 } else {
1051 /* Stretching in Y direction only */
1052 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1053 sbuf = sbase + (sy >> 16) * slock.Pitch;
1054 memcpy(dbuf, sbuf, width);
1055 dbuf += dlock.Pitch;
1059 else
1061 /* Stretching in X direction */
1062 int last_sy = -1;
1063 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1065 sbuf = sbase + (sy >> 16) * slock.Pitch;
1067 if ((sy >> 16) == (last_sy >> 16))
1069 /* this sourcerow is the same as last sourcerow -
1070 * copy already stretched row
1072 memcpy(dbuf, dbuf - dlock.Pitch, width);
1074 else
1076 #define STRETCH_ROW(type) { \
1077 type *s = (type *) sbuf, *d = (type *) dbuf; \
1078 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1079 d[x] = s[sx >> 16]; \
1080 break; }
1082 switch(bpp)
1084 case 1: STRETCH_ROW(BYTE)
1085 case 2: STRETCH_ROW(WORD)
1086 case 4: STRETCH_ROW(DWORD)
1087 case 3:
1089 LPBYTE s,d = dbuf;
1090 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1092 DWORD pixel;
1094 s = sbuf+3*(sx>>16);
1095 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1096 d[0] = (pixel )&0xff;
1097 d[1] = (pixel>> 8)&0xff;
1098 d[2] = (pixel>>16)&0xff;
1099 d+=3;
1101 break;
1103 default:
1104 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1105 ret = WINED3DERR_NOTAVAILABLE;
1106 goto error;
1108 #undef STRETCH_ROW
1110 dbuf += dlock.Pitch;
1111 last_sy = sy;
1115 else
1117 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1118 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1119 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1120 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1122 /* The color keying flags are checked for correctness in ddraw */
1123 if (Flags & WINEDDBLT_KEYSRC)
1125 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1126 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1128 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1130 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1131 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1134 if (Flags & WINEDDBLT_KEYDEST)
1136 /* Destination color keys are taken from the source surface ! */
1137 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1138 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1140 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1142 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1143 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1146 if(bpp == 1)
1148 keymask = 0xff;
1150 else
1152 keymask = sEntry->redMask |
1153 sEntry->greenMask |
1154 sEntry->blueMask;
1156 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1159 if (Flags & WINEDDBLT_DDFX)
1161 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1162 LONG tmpxy;
1163 dTopLeft = dbuf;
1164 dTopRight = dbuf+((dstwidth-1)*bpp);
1165 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1166 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1168 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1170 /* I don't think we need to do anything about this flag */
1171 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1173 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1175 tmp = dTopRight;
1176 dTopRight = dTopLeft;
1177 dTopLeft = tmp;
1178 tmp = dBottomRight;
1179 dBottomRight = dBottomLeft;
1180 dBottomLeft = tmp;
1181 dstxinc = dstxinc *-1;
1183 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1185 tmp = dTopLeft;
1186 dTopLeft = dBottomLeft;
1187 dBottomLeft = tmp;
1188 tmp = dTopRight;
1189 dTopRight = dBottomRight;
1190 dBottomRight = tmp;
1191 dstyinc = dstyinc *-1;
1193 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1195 /* I don't think we need to do anything about this flag */
1196 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1198 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1200 tmp = dBottomRight;
1201 dBottomRight = dTopLeft;
1202 dTopLeft = tmp;
1203 tmp = dBottomLeft;
1204 dBottomLeft = dTopRight;
1205 dTopRight = tmp;
1206 dstxinc = dstxinc * -1;
1207 dstyinc = dstyinc * -1;
1209 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1211 tmp = dTopLeft;
1212 dTopLeft = dBottomLeft;
1213 dBottomLeft = dBottomRight;
1214 dBottomRight = dTopRight;
1215 dTopRight = tmp;
1216 tmpxy = dstxinc;
1217 dstxinc = dstyinc;
1218 dstyinc = tmpxy;
1219 dstxinc = dstxinc * -1;
1221 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1223 tmp = dTopLeft;
1224 dTopLeft = dTopRight;
1225 dTopRight = dBottomRight;
1226 dBottomRight = dBottomLeft;
1227 dBottomLeft = tmp;
1228 tmpxy = dstxinc;
1229 dstxinc = dstyinc;
1230 dstyinc = tmpxy;
1231 dstyinc = dstyinc * -1;
1233 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1235 /* I don't think we need to do anything about this flag */
1236 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1238 dbuf = dTopLeft;
1239 Flags &= ~(WINEDDBLT_DDFX);
1242 #define COPY_COLORKEY_FX(type) { \
1243 type *s, *d = (type *) dbuf, *dx, tmp; \
1244 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1245 s = (type*)(sbase + (sy >> 16) * slock.Pitch); \
1246 dx = d; \
1247 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1248 tmp = s[sx >> 16]; \
1249 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1250 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1251 dx[0] = tmp; \
1253 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1255 d = (type*)(((LPBYTE)d)+dstyinc); \
1257 break; }
1259 switch (bpp) {
1260 case 1: COPY_COLORKEY_FX(BYTE)
1261 case 2: COPY_COLORKEY_FX(WORD)
1262 case 4: COPY_COLORKEY_FX(DWORD)
1263 case 3:
1265 LPBYTE s,d = dbuf, dx;
1266 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1268 sbuf = sbase + (sy >> 16) * slock.Pitch;
1269 dx = d;
1270 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1272 DWORD pixel, dpixel = 0;
1273 s = sbuf+3*(sx>>16);
1274 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1275 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1276 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1277 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1279 dx[0] = (pixel )&0xff;
1280 dx[1] = (pixel>> 8)&0xff;
1281 dx[2] = (pixel>>16)&0xff;
1283 dx+= dstxinc;
1285 d += dstyinc;
1287 break;
1289 default:
1290 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1291 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1292 ret = WINED3DERR_NOTAVAILABLE;
1293 goto error;
1294 #undef COPY_COLORKEY_FX
1299 error:
1300 if (Flags && FIXME_ON(d3d_surface))
1302 FIXME("\tUnsupported flags: %08x\n", Flags);
1305 release:
1306 IWineD3DSurface_UnlockRect(iface);
1307 if (SrcSurface && SrcSurface != iface) IWineD3DSurface_UnlockRect(SrcSurface);
1308 return ret;
1311 /*****************************************************************************
1312 * IWineD3DSurface::BltFast, SW emulation version
1314 * This is the software implementation of BltFast, as used by GDI surfaces
1315 * and as a fallback for OpenGL surfaces. This code is taken from the old
1316 * DirectDraw code, and was originally written by TransGaming.
1318 * Params:
1319 * dstx:
1320 * dsty:
1321 * Source: Source surface to copy from
1322 * rsrc: Source rectangle
1323 * trans: Some Flags
1325 * Returns:
1326 * WINED3D_OK on success
1328 *****************************************************************************/
1329 HRESULT WINAPI
1330 IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface,
1331 DWORD dstx,
1332 DWORD dsty,
1333 IWineD3DSurface *Source,
1334 RECT *rsrc,
1335 DWORD trans)
1337 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1338 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1340 int bpp, w, h, x, y;
1341 WINED3DLOCKED_RECT dlock,slock;
1342 HRESULT ret = WINED3D_OK;
1343 RECT rsrc2;
1344 RECT lock_src, lock_dst, lock_union;
1345 BYTE *sbuf, *dbuf;
1346 const StaticPixelFormatDesc *sEntry, *dEntry;
1348 if (TRACE_ON(d3d_surface))
1350 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1352 if (rsrc)
1354 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1355 rsrc->right,rsrc->bottom);
1357 else
1359 TRACE(" srcrect: NULL\n");
1363 if ((This->Flags & SFLAG_LOCKED) ||
1364 ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
1366 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1367 return WINEDDERR_SURFACEBUSY;
1370 if (!rsrc)
1372 WARN("rsrc is NULL!\n");
1373 rsrc = &rsrc2;
1374 rsrc->left = 0;
1375 rsrc->top = 0;
1376 rsrc->right = Src->currentDesc.Width;
1377 rsrc->bottom = Src->currentDesc.Height;
1380 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1381 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1382 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1383 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1384 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1385 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1387 WARN("Application gave us bad source rectangle for BltFast.\n");
1388 return WINEDDERR_INVALIDRECT;
1391 h = rsrc->bottom - rsrc->top;
1392 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1393 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1394 if (h <= 0) return WINEDDERR_INVALIDRECT;
1396 w = rsrc->right - rsrc->left;
1397 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1398 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1399 if (w <= 0) return WINEDDERR_INVALIDRECT;
1401 /* Now compute the locking rectangle... */
1402 lock_src.left = rsrc->left;
1403 lock_src.top = rsrc->top;
1404 lock_src.right = lock_src.left + w;
1405 lock_src.bottom = lock_src.top + h;
1407 lock_dst.left = dstx;
1408 lock_dst.top = dsty;
1409 lock_dst.right = dstx + w;
1410 lock_dst.bottom = dsty + h;
1412 bpp = This->bytesPerPixel;
1414 /* We need to lock the surfaces, or we won't get refreshes when done. */
1415 if (Src == This)
1417 int pitch;
1419 UnionRect(&lock_union, &lock_src, &lock_dst);
1421 /* Lock the union of the two rectangles */
1422 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1423 if(ret != WINED3D_OK) goto error;
1425 pitch = dlock.Pitch;
1426 slock.Pitch = dlock.Pitch;
1428 /* Since slock was originally copied from this surface's description, we can just reuse it */
1429 assert(This->resource.allocatedMemory != NULL);
1430 sbuf = (BYTE *)This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1431 dbuf = (BYTE *)This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1432 sEntry = getFormatDescEntry(Src->resource.format, NULL, NULL);
1433 dEntry = sEntry;
1435 else
1437 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1438 if(ret != WINED3D_OK) goto error;
1439 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1440 if(ret != WINED3D_OK) goto error;
1442 sbuf = slock.pBits;
1443 dbuf = dlock.pBits;
1444 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1446 sEntry = getFormatDescEntry(Src->resource.format, NULL, NULL);
1447 dEntry = getFormatDescEntry(This->resource.format, NULL, NULL);
1450 /* Handle first the FOURCC surfaces... */
1451 if (sEntry->isFourcc && dEntry->isFourcc)
1453 TRACE("Fourcc -> Fourcc copy\n");
1454 if (trans)
1455 FIXME("trans arg not supported when a FOURCC surface is involved\n");
1456 if (dstx || dsty)
1457 FIXME("offset for destination surface is not supported\n");
1458 if (Src->resource.format != This->resource.format)
1460 FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1461 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1462 goto error;
1464 /* FIXME: Watch out that the size is correct for FOURCC surfaces */
1465 memcpy(dbuf, sbuf, This->resource.size);
1466 goto error;
1468 if (sEntry->isFourcc && !dEntry->isFourcc)
1470 /* TODO: Use the libtxc_dxtn.so shared library to do
1471 * software decompression
1473 ERR("DXTC decompression not supported by now\n");
1474 goto error;
1477 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1479 DWORD keylow, keyhigh;
1480 TRACE("Color keyed copy\n");
1481 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1483 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1484 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1486 else
1488 /* I'm not sure if this is correct */
1489 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1490 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1491 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1494 #define COPYBOX_COLORKEY(type) { \
1495 type *d, *s, tmp; \
1496 s = (type *) sbuf; \
1497 d = (type *) dbuf; \
1498 for (y = 0; y < h; y++) { \
1499 for (x = 0; x < w; x++) { \
1500 tmp = s[x]; \
1501 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1503 s = (type *)((BYTE *)s + slock.Pitch); \
1504 d = (type *)((BYTE *)d + dlock.Pitch); \
1506 break; \
1509 switch (bpp) {
1510 case 1: COPYBOX_COLORKEY(BYTE)
1511 case 2: COPYBOX_COLORKEY(WORD)
1512 case 4: COPYBOX_COLORKEY(DWORD)
1513 case 3:
1515 BYTE *d, *s;
1516 DWORD tmp;
1517 s = (BYTE *) sbuf;
1518 d = (BYTE *) dbuf;
1519 for (y = 0; y < h; y++)
1521 for (x = 0; x < w * 3; x += 3)
1523 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1524 if (tmp < keylow || tmp > keyhigh)
1526 d[x + 0] = s[x + 0];
1527 d[x + 1] = s[x + 1];
1528 d[x + 2] = s[x + 2];
1531 s += slock.Pitch;
1532 d += dlock.Pitch;
1534 break;
1536 default:
1537 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1538 ret = WINED3DERR_NOTAVAILABLE;
1539 goto error;
1541 #undef COPYBOX_COLORKEY
1542 TRACE("Copy Done\n");
1544 else
1546 int width = w * bpp;
1547 TRACE("NO color key copy\n");
1548 for (y = 0; y < h; y++)
1550 /* This is pretty easy, a line for line memcpy */
1551 memcpy(dbuf, sbuf, width);
1552 sbuf += slock.Pitch;
1553 dbuf += dlock.Pitch;
1555 TRACE("Copy done\n");
1558 error:
1559 if (Src == This)
1561 IWineD3DSurface_UnlockRect(iface);
1563 else
1565 IWineD3DSurface_UnlockRect(iface);
1566 IWineD3DSurface_UnlockRect(Source);
1569 return ret;