VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/surface_base.c@ 29710

Last change on this file since 29710 was 28475, checked in by vboxsync, 15 years ago

crOpenGL: update to wine 1.1.43

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette