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