ddraw: Exclude unused headers.
[wine] / dlls / ddraw / surface.c
1 /* DirectDraw Surface Implementation
2  *
3  * Copyright (c) 1997-2000 Marcus Meissner
4  * Copyright (c) 1998-2000 Lionel Ulmer
5  * Copyright (c) 2000-2001 TransGaming Technologies Inc.
6  * Copyright (c) 2006 Stefan Dösinger
7  *
8  * This file contains the (internal) driver registration functions,
9  * driver enumeration APIs and DirectDraw creation functions.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <assert.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 #define COBJMACROS
35 #define NONAMELESSUNION
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40 #include "wingdi.h"
41 #include "wine/exception.h"
42
43 #include "ddraw.h"
44 #include "d3d.h"
45
46 #include "ddraw_private.h"
47 #include "wine/debug.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
50
51 /*****************************************************************************
52  * IUnknown parts follow
53  *****************************************************************************/
54
55 /*****************************************************************************
56  * IDirectDrawSurface7::QueryInterface
57  *
58  * A normal QueryInterface implementation. For QueryInterface rules
59  * see ddraw.c, IDirectDraw7::QueryInterface. This method
60  * can Query IDirectDrawSurface interfaces in all version, IDirect3DTexture
61  * in all versions, the IDirectDrawGammaControl interface and it can
62  * create an IDirect3DDevice. (Uses IDirect3D7::CreateDevice)
63  *
64  * Params:
65  *  riid: The interface id queried for
66  *  obj: Address to write the pointer to
67  *
68  * Returns:
69  *  S_OK on success
70  *  E_NOINTERFACE if the requested interface wasn't found
71  *
72  *****************************************************************************/
73 static HRESULT WINAPI
74 IDirectDrawSurfaceImpl_QueryInterface(IDirectDrawSurface7 *iface,
75                                       REFIID riid,
76                                       void **obj)
77 {
78     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
79
80     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
81     *obj = NULL;
82
83     if(!riid)
84         return DDERR_INVALIDPARAMS;
85
86     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),obj);
87     if (IsEqualGUID(riid, &IID_IUnknown)
88      || IsEqualGUID(riid, &IID_IDirectDrawSurface7)
89      || IsEqualGUID(riid, &IID_IDirectDrawSurface4) )
90     {
91         IUnknown_AddRef(iface);
92         *obj = ICOM_INTERFACE(This, IDirectDrawSurface7);
93         TRACE("(%p) returning IDirectDrawSurface7 interface at %p\n", This, *obj);
94         return S_OK;
95     }
96     else if( IsEqualGUID(riid, &IID_IDirectDrawSurface3)
97           || IsEqualGUID(riid, &IID_IDirectDrawSurface2)
98           || IsEqualGUID(riid, &IID_IDirectDrawSurface) )
99     {
100         IUnknown_AddRef(iface);
101         *obj = ICOM_INTERFACE(This, IDirectDrawSurface3);
102         TRACE("(%p) returning IDirectDrawSurface3 interface at %p\n", This, *obj);
103         return S_OK;
104     }
105     else if( IsEqualGUID(riid, &IID_IDirectDrawGammaControl) )
106     {
107         IUnknown_AddRef(iface);
108         *obj = ICOM_INTERFACE(This, IDirectDrawGammaControl);
109         TRACE("(%p) returning IDirectDrawGammaControl interface at %p\n", This, *obj);
110         return S_OK;
111     }
112     else if( IsEqualGUID(riid, &IID_D3DDEVICE_WineD3D) ||
113              IsEqualGUID(riid, &IID_IDirect3DHALDevice) )
114     {
115         IDirect3DDevice7 *d3d;
116
117         /* Call into IDirect3D7 for creation */
118         IDirect3D7_CreateDevice(ICOM_INTERFACE(This->ddraw, IDirect3D7),
119                                 riid,
120                                 ICOM_INTERFACE(This, IDirectDrawSurface7),
121                                 &d3d);
122
123         *obj = COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice7, IDirect3DDevice, d3d);
124         TRACE("(%p) Returning IDirect3DDevice interface at %p\n", This, *obj);
125
126         return S_OK;
127     }
128     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
129              IsEqualGUID( &IID_IDirect3DTexture2, riid ))
130     {
131         if (IsEqualGUID( &IID_IDirect3DTexture, riid ))
132         {
133             *obj = ICOM_INTERFACE(This, IDirect3DTexture);
134             TRACE(" returning Direct3DTexture interface at %p.\n", *obj);
135         }
136         else
137         {
138             *obj = ICOM_INTERFACE(This, IDirect3DTexture2);
139             TRACE(" returning Direct3DTexture2 interface at %p.\n", *obj);
140         }
141         IUnknown_AddRef( (IUnknown *) *obj);
142         return S_OK;
143     }
144
145     ERR("No interface\n");
146     return E_NOINTERFACE;
147 }
148
149 /*****************************************************************************
150  * IDirectDrawSurface7::AddRef
151  *
152  * A normal addref implementation
153  *
154  * Returns:
155  *  The new refcount
156  *
157  *****************************************************************************/
158 static ULONG WINAPI
159 IDirectDrawSurfaceImpl_AddRef(IDirectDrawSurface7 *iface)
160 {
161     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
162     ULONG refCount = InterlockedIncrement(&This->ref);
163
164     TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
165     return refCount;
166 }
167
168 /*****************************************************************************
169  * IDirectDrawSurfaceImpl_Destroy
170  *
171  * A helper function for IDirectDrawSurface7::Release
172  *
173  * Frees the surface, regardless of its refcount.
174  *  See IDirectDrawSurface7::Release for more information
175  *
176  * Params:
177  *  This: Surface to free
178  *
179  *****************************************************************************/
180 static void IDirectDrawSurfaceImpl_Destroy(IDirectDrawSurfaceImpl *This)
181 {
182     TRACE("(%p)\n", This);
183
184     /* Check the refcount and give a warning */
185     if(This->ref > 1)
186     {
187         /* This can happen when a complex surface is destroyed,
188          * because the 2nd surface was addref()ed when the app
189          * called GetAttachedSurface
190          */
191         WARN("(%p): Destroying surface with refount %d\n", This, This->ref);
192     }
193
194     /* Check for attached surfaces and detach them */
195     if(This->first_attached != This)
196     {
197         /* Well, this shouldn't happen: The surface being attached is addref()ed
198           * in AddAttachedSurface, so it shouldn't be released until DeleteAttachedSurface
199           * is called, because the refcount is held. It looks like the app released()
200           * it often enough to force this
201           */
202         IDirectDrawSurface7 *root = ICOM_INTERFACE(This->first_attached, IDirectDrawSurface7);
203         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This, IDirectDrawSurface7);
204
205         FIXME("(%p) Freeing a surface that is attached to surface %p\n", This, This->first_attached);
206
207         /* The refcount will drop to -1 here */
208         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
209         {
210             ERR("(%p) DeleteAttachedSurface failed!\n", This);
211         }
212     }
213
214     while(This->next_attached != NULL)
215     {
216         IDirectDrawSurface7 *root = ICOM_INTERFACE(This, IDirectDrawSurface7);
217         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This->next_attached, IDirectDrawSurface7);
218
219         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
220         {
221             ERR("(%p) DeleteAttachedSurface failed!\n", This);
222             assert(0);
223         }
224     }
225
226     /* Now destroy the surface. Wait: It could have been released if we are a texture */
227     if(This->WineD3DSurface)
228         IWineD3DSurface_Release(This->WineD3DSurface);
229
230     /* Having a texture handle set implies that the device still exists */
231     if(This->Handle)
232     {
233         This->ddraw->d3ddevice->Handles[This->Handle - 1].ptr = NULL;
234         This->ddraw->d3ddevice->Handles[This->Handle - 1].type = DDrawHandle_Unknown;
235     }
236
237     /* Reduce the ddraw surface count */
238     InterlockedDecrement(&This->ddraw->surfaces);
239     list_remove(&This->surface_list_entry);
240
241     HeapFree(GetProcessHeap(), 0, This);
242 }
243
244 /*****************************************************************************
245  * IDirectDrawSurface7::Release
246  *
247  * Reduces the surface's refcount by 1. If the refcount falls to 0, the
248  * surface is destroyed.
249  *
250  * Destroying the surface is a bit tricky. For the connection between
251  * WineD3DSurfaces and DirectDrawSurfaces see IDirectDraw7::CreateSurface
252  * It has a nice graph explaining the connection.
253  *
254  * What happens here is basically this:
255  * When a surface is destroyed, its WineD3DSurface is released,
256  * and the refcount of the DirectDraw interface is reduced by 1. If it has
257  * complex surfaces attached to it, then these surfaces are destroyed too,
258  * regardless of their refcount. If any surface being destroyed has another
259  * surface attached to it (with a "soft" attachment, not complex), then
260  * this surface is detached with DeleteAttachedSurface.
261  *
262  * When the surface is a texture, the WineD3DTexture is released.
263  * If the surface is the Direct3D render target, then the D3D
264  * capabilities of the WineD3DDevice are uninitialized, which causes the
265  * swapchain to be released.
266  *
267  * When a complex sublevel falls to ref zero, then this is ignored.
268  *
269  * Returns:
270  *  The new refcount
271  *
272  *****************************************************************************/
273 static ULONG WINAPI
274 IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
275 {
276     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
277     ULONG ref;
278     TRACE("(%p) : Releasing from %d\n", This, This->ref);
279     ref = InterlockedDecrement(&This->ref);
280
281     if (ref == 0)
282     {
283
284         IDirectDrawSurfaceImpl *surf;
285         IDirectDrawImpl *ddraw;
286         IUnknown *ifaceToRelease = This->ifaceToRelease;
287         int i;
288
289         /* Complex attached surfaces are destroyed implicitely when the root is released */
290         if(!This->is_complex_root)
291         {
292             WARN("(%p) Attempt to destroy a surface that is not a complex root\n", This);
293             return ref;
294         }
295         ddraw = This->ddraw;
296
297         /* If it's a texture, destroy the WineD3DTexture.
298          * WineD3D will destroy the IParent interfaces
299          * of the sublevels, which destroys the WineD3DSurfaces.
300          * Set the surfaces to NULL to avoid destroying them again later
301          */
302         if(This->wineD3DTexture)
303         {
304             IWineD3DTexture_Release(This->wineD3DTexture);
305         }
306         /* If it's the RenderTarget, destroy the d3ddevice */
307         else if( (ddraw->d3d_initialized) && (This == ddraw->d3d_target))
308         {
309             TRACE("(%p) Destroying the render target, uninitializing D3D\n", This);
310
311             /* Unset any index buffer, just to be sure */
312             IWineD3DDevice_SetIndices(ddraw->wineD3DDevice, NULL, 0);
313             IWineD3DDevice_SetDepthStencilSurface(ddraw->wineD3DDevice, NULL);
314
315             if(IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice, D3D7CB_DestroyDepthStencilSurface, D3D7CB_DestroySwapChain) != D3D_OK)
316             {
317                 /* Not good */
318                 ERR("(%p) Failed to uninit 3D\n", This);
319             }
320             else
321             {
322                 /* Free the d3d window if one was created */
323                 if(ddraw->d3d_window != 0)
324                 {
325                     TRACE(" (%p) Destroying the hidden render window %p\n", This, ddraw->d3d_window);
326                     DestroyWindow(ddraw->d3d_window);
327                     ddraw->d3d_window = 0;
328                 }
329                 /* Unset the pointers */
330             }
331
332             ddraw->d3d_initialized = FALSE;
333             ddraw->d3d_target = NULL;
334
335             /* Write a trace because D3D unloading was the reason for many
336              * crashes during development.
337              */
338             TRACE("(%p) D3D unloaded\n", This);
339         }
340         else if(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE |
341                                                      DDSCAPS_3DDEVICE       |
342                                                      DDSCAPS_TEXTURE        ) )
343         {
344             /* It's a render target, but no swapchain was created.
345              * The IParent interfaces have to be released manually.
346              * The same applies for textures without an
347              * IWineD3DTexture object attached
348              */
349             IParent *Parent;
350
351             for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
352             {
353                 if(This->complex_array[i])
354                 {
355                     /* Only the topmost level can have more than 1 surfaces in the complex
356                      * attachment array(Cube texture roots), for all others there is only
357                      * one
358                      */
359                     surf = This->complex_array[i];
360                     while(surf)
361                     {
362                         IWineD3DSurface_GetParent(surf->WineD3DSurface,
363                                                   (IUnknown **) &Parent);
364                         IParent_Release(Parent);  /* For the getParent */
365                         IParent_Release(Parent);  /* To release it */
366                         surf = surf->complex_array[0];
367                     }
368                 }
369             }
370
371             /* Now the top-level surface */
372             IWineD3DSurface_GetParent(This->WineD3DSurface,
373                                       (IUnknown **) &Parent);
374             IParent_Release(Parent);  /* For the getParent */
375             IParent_Release(Parent);  /* To release it */
376         }
377
378         /* The refcount test shows that the palette is detached when the surface is destroyed */
379         IDirectDrawSurface7_SetPalette(ICOM_INTERFACE(This, IDirectDrawSurface7),
380                                                       NULL);
381
382         /* Loop through all complex attached surfaces,
383          * and destroy them.
384          *
385          * Yet again, only the root can have more than one complexly attached surface, all the others
386          * have a total of one;
387          */
388         for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
389         {
390             if(!This->complex_array[i]) break;
391
392             surf = This->complex_array[i];
393             This->complex_array[i] = NULL;
394             while(surf)
395             {
396                 IDirectDrawSurfaceImpl *destroy = surf;
397                 surf = surf->complex_array[0];              /* Iterate through the "tree" */
398                 IDirectDrawSurfaceImpl_Destroy(destroy);    /* Destroy it */
399             }
400         }
401
402         /* Destroy the root surface.
403          */
404         IDirectDrawSurfaceImpl_Destroy(This);
405
406         /* Reduce the ddraw refcount */
407         if(ifaceToRelease) IUnknown_Release(ifaceToRelease);
408     }
409
410     return ref;
411 }
412
413 /*****************************************************************************
414  * IDirectDrawSurface7::GetAttachedSurface
415  *
416  * Returns an attached surface with the requested caps. Surface attachment
417  * and complex surfaces are not clearly described by the MSDN or sdk,
418  * so this method is tricky and likely to contain problems.
419  * This implementation searches the complex list first, then the
420  * attachment chain.
421  *
422  * The chains are searched from This down to the last surface in the chain,
423  * not from the first element in the chain. The first surface found is
424  * returned. The MSDN says that this method fails if more than one surface
425  * matches the caps, but it is not sure if that is right. The attachment
426  * structure may not even allow two matching surfaces.
427  *
428  * The found surface is AddRef-ed before it is returned.
429  *
430  * Params:
431  *  Caps: Pointer to a DDCAPS2 structure describing the caps asked for
432  *  Surface: Address to store the found surface
433  *
434  * Returns:
435  *  DD_OK on success
436  *  DDERR_INVALIDPARAMS if Caps or Surface is NULL
437  *  DDERR_NOTFOUND if no surface was found
438  *
439  *****************************************************************************/
440 static HRESULT WINAPI
441 IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
442                                           DDSCAPS2 *Caps,
443                                           IDirectDrawSurface7 **Surface)
444 {
445     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
446     IDirectDrawSurfaceImpl *surf;
447     DDSCAPS2 our_caps;
448     int i;
449
450     TRACE("(%p)->(%p,%p)\n", This, Caps, Surface);
451
452     our_caps = *Caps;
453
454     if(This->version < 7)
455     {
456         /* Earlier dx apps put garbage into these members, clear them */
457         our_caps.dwCaps2 = 0;
458         our_caps.dwCaps3 = 0;
459         our_caps.dwCaps4 = 0;
460     }
461
462     TRACE("(%p): Looking for caps: %x,%x,%x,%x\n", This, our_caps.dwCaps, our_caps.dwCaps2, our_caps.dwCaps3, our_caps.dwCaps4); /* FIXME: Better debugging */
463
464     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
465     {
466         surf = This->complex_array[i];
467         if(!surf) break;
468
469         if (TRACE_ON(ddraw))
470         {
471             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
472                    surf->surface_desc.ddsCaps.dwCaps,
473                    surf->surface_desc.ddsCaps.dwCaps2,
474                    surf->surface_desc.ddsCaps.dwCaps3,
475                    surf->surface_desc.ddsCaps.dwCaps4);
476         }
477
478         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
479             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
480
481             /* MSDN: "This method fails if more than one surface is attached
482              * that matches the capabilities requested."
483              *
484              * Not sure how to test this.
485              */
486
487             TRACE("(%p): Returning surface %p\n", This, surf);
488             TRACE("(%p): mipmapcount=%d\n", This, surf->mipmap_level);
489             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
490             IDirectDrawSurface7_AddRef(*Surface);
491             return DD_OK;
492         }
493     }
494
495     /* Next, look at the attachment chain */
496     surf = This;
497
498     while( (surf = surf->next_attached) )
499     {
500         if (TRACE_ON(ddraw))
501         {
502             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
503                    surf->surface_desc.ddsCaps.dwCaps,
504                    surf->surface_desc.ddsCaps.dwCaps2,
505                    surf->surface_desc.ddsCaps.dwCaps3,
506                    surf->surface_desc.ddsCaps.dwCaps4);
507         }
508
509         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
510             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
511
512             TRACE("(%p): Returning surface %p\n", This, surf);
513             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
514             IDirectDrawSurface7_AddRef(*Surface);
515             return DD_OK;
516         }
517     }
518
519     TRACE("(%p) Didn't find a valid surface\n", This);
520     return DDERR_NOTFOUND;
521 }
522
523 /*****************************************************************************
524  * IDirectDrawSurface7::Lock
525  *
526  * Locks the surface and returns a pointer to the surface's memory
527  *
528  * Params:
529  *  Rect: Rectangle to lock. If NULL, the whole surface is locked
530  *  DDSD: Pointer to a DDSURFACEDESC2 which shall receive the surface's desc.
531  *  Flags: Locking flags, e.g Read only or write only
532  *  h: An event handle that's not used and must be NULL
533  *
534  * Returns:
535  *  DD_OK on success
536  *  DDERR_INVALIDPARAMS if DDSD is NULL
537  *  For more details, see IWineD3DSurface::LockRect
538  *
539  *****************************************************************************/
540 static HRESULT WINAPI
541 IDirectDrawSurfaceImpl_Lock(IDirectDrawSurface7 *iface,
542                             RECT *Rect,
543                             DDSURFACEDESC2 *DDSD,
544                             DWORD Flags,
545                             HANDLE h)
546 {
547     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
548     WINED3DLOCKED_RECT LockedRect;
549     HRESULT hr;
550     TRACE("(%p)->(%p,%p,%x,%p)\n", This, Rect, DDSD, Flags, h);
551
552     if(!DDSD)
553         return DDERR_INVALIDPARAMS;
554
555     /* Should I check for the handle to be NULL?
556      *
557      * The DDLOCK flags and the D3DLOCK flags are equal
558      * for the supported values. The others are ignored by WineD3D
559      */
560
561     /* Hmm. Anarchy online passes an uninitialized surface descriptor,
562      * that means it doesn't have dwSize set. Init it to some sane
563      * value
564      */
565     if(DDSD->dwSize <= sizeof(DDSURFACEDESC))
566     {
567         DDSD->dwSize = sizeof(DDSURFACEDESC);
568     }
569     else
570     {
571         DDSD->dwSize = sizeof(DDSURFACEDESC2);
572     }
573
574     DD_STRUCT_COPY_BYSIZE(DDSD,&(This->surface_desc));
575     hr = IWineD3DSurface_LockRect(This->WineD3DSurface,
576                                   &LockedRect,
577                                   Rect,
578                                   Flags);
579     if(hr != D3D_OK) return hr;
580
581     /* Override the memory area and the pitch */
582     DDSD->dwFlags |= DDSD_LPSURFACE;
583     DDSD->lpSurface = LockedRect.pBits;
584     DDSD->dwFlags |= DDSD_PITCH;
585     DDSD->u1.lPitch = LockedRect.Pitch;
586
587     TRACE("locked surface returning description :\n");
588     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
589
590     return DD_OK;
591 }
592
593 /*****************************************************************************
594  * IDirectDrawSurface7::Unlock
595  *
596  * Unlocks an locked surface
597  *
598  * Params:
599  *  Rect: Not used by this implementation
600  *
601  * Returns:
602  *  D3D_OK on success
603  *  For more details, see IWineD3DSurface::UnlockRect
604  *
605  *****************************************************************************/
606 static HRESULT WINAPI
607 IDirectDrawSurfaceImpl_Unlock(IDirectDrawSurface7 *iface,
608                               RECT *pRect)
609 {
610     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
611     TRACE("(%p)->(%p)\n", This, pRect);
612
613     return IWineD3DSurface_UnlockRect(This->WineD3DSurface);
614 }
615
616 /*****************************************************************************
617  * IDirectDrawSurface7::Flip
618  *
619  * Flips a surface with the DDSCAPS_FLIP flag. The flip is relayed to
620  * IWineD3DSurface::Flip. Because WineD3D doesn't handle attached surfaces,
621  * the flip target is passed to WineD3D, even if the app didn't specify one
622  *
623  * Params:
624  *  DestOverride: Specifies the surface that will become the new front
625  *                buffer. If NULL, the current back buffer is used
626  *  Flags: some DirectDraw flags, see include/ddraw.h
627  *
628  * Returns:
629  *  DD_OK on success
630  *  DDERR_NOTFLIPPABLE if no flip target could be found
631  *  DDERR_INVALIDOBJECT if the surface isn't a front buffer
632  *  For more details, see IWineD3DSurface::Flip
633  *
634  *****************************************************************************/
635 static HRESULT WINAPI
636 IDirectDrawSurfaceImpl_Flip(IDirectDrawSurface7 *iface,
637                             IDirectDrawSurface7 *DestOverride,
638                             DWORD Flags)
639 {
640     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
641     IDirectDrawSurfaceImpl *Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DestOverride);
642     IDirectDrawSurface7 *Override7;
643     HRESULT hr;
644     TRACE("(%p)->(%p,%x)\n", This, DestOverride, Flags);
645
646     /* Flip has to be called from a front buffer
647      * What about overlay surfaces, AFAIK they can flip too?
648      */
649     if( !(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER) )
650         return DDERR_INVALIDOBJECT; /* Unckecked */
651
652     /* WineD3D doesn't keep track of attached surface, so find the target */
653     if(!Override)
654     {
655         DDSCAPS2 Caps;
656
657         memset(&Caps, 0, sizeof(Caps));
658         Caps.dwCaps |= DDSCAPS_BACKBUFFER;
659         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &Caps, &Override7);
660         if(hr != DD_OK)
661         {
662             ERR("Can't find a flip target\n");
663             return DDERR_NOTFLIPPABLE; /* Unchecked */
664         }
665         Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Override7);
666
667         /* For the GetAttachedSurface */
668         IDirectDrawSurface7_Release(Override7);
669     }
670
671     return  IWineD3DSurface_Flip(This->WineD3DSurface,
672                                  Override->WineD3DSurface,
673                                  Flags);
674 }
675
676 /*****************************************************************************
677  * IDirectDrawSurface7::Blt
678  *
679  * Performs a blit on the surface
680  *
681  * Params:
682  *  DestRect: Destination rectangle, can be NULL
683  *  SrcSurface: Source surface, can be NULL
684  *  SrcRect: Source rectange, can be NULL
685  *  Flags: Blt flags
686  *  DDBltFx: Some extended blt parameters, connected to the flags
687  *
688  * Returns:
689  *  D3D_OK on success
690  *  See IWineD3DSurface::Blt for more details
691  *
692  *****************************************************************************/
693 static HRESULT WINAPI
694 IDirectDrawSurfaceImpl_Blt(IDirectDrawSurface7 *iface,
695                            RECT *DestRect,
696                            IDirectDrawSurface7 *SrcSurface,
697                            RECT *SrcRect,
698                            DWORD Flags,
699                            DDBLTFX *DDBltFx)
700 {
701     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
702     HRESULT hr;
703     IDirectDrawSurfaceImpl *Src = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, SrcSurface);
704     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
705
706     /* Check for validity of the flags here. WineD3D Has the software-opengl selection path and would have
707      * to check at 2 places, and sometimes do double checks. This also saves the call to wined3d :-)
708      */
709     if((Flags & DDBLT_KEYSRCOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYSRC)) {
710         WARN("Invalid source color key parameters, returning DDERR_INVALIDPARAMS\n");
711         return DDERR_INVALIDPARAMS;
712     }
713
714     if((Flags & DDBLT_KEYDESTOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYDEST)) {
715         WARN("Invalid destination color key parameters, returning DDERR_INVALIDPARAMS\n");
716         return DDERR_INVALIDPARAMS;
717     }
718
719     if(Flags & DDBLT_KEYSRC && (!Src || !(Src->surface_desc.dwFlags & DDSD_CKSRCBLT))) {
720         WARN("DDBLT_KEYDEST blit without color key in surface, returning DDERR_INVALIDPARAMS\n");
721         return DDERR_INVALIDPARAMS;
722     }
723
724     /* TODO: Check if the DDBltFx contains any ddraw surface pointers. If it does, copy the struct,
725      * and replace the ddraw surfaces with the wined3d surfaces
726      * So far no blitting operations using surfaces in the bltfx struct are supported anyway.
727      */
728     hr = IWineD3DSurface_Blt(This->WineD3DSurface,
729                              DestRect,
730                              Src ? Src->WineD3DSurface : NULL,
731                              SrcRect,
732                              Flags,
733                              (WINEDDBLTFX *) DDBltFx,
734                              WINED3DTEXF_NONE);
735     switch(hr)
736     {
737         case WINED3DERR_NOTAVAILABLE:       return DDERR_UNSUPPORTED;
738         case WINED3DERR_WRONGTEXTUREFORMAT: return DDERR_INVALIDPIXELFORMAT;
739         default:                            return hr;
740     }
741 }
742
743 /*****************************************************************************
744  * IDirectDrawSurface7::AddAttachedSurface
745  *
746  * Attaches a surface to another surface. How the surface attachments work
747  * is not totally understood yet, and this method is prone to problems.
748  * he surface that is attached is AddRef-ed.
749  *
750  * Tests with complex surfaces suggest that the surface attachments form a
751  * tree, but no method to test this has been found yet.
752  *
753  * The attachment list consists of a first surface (first_attached) and
754  * for each surface a pointer to the next attached surface (next_attached).
755  * For the first surface, and a surface that has no attachments
756  * first_attached points to the surface itself. A surface that has
757  * no successors in the chain has next_attached set to NULL.
758  *
759  * Newly attached surfaces are attached right after the root surface.
760  * If a surface is attached to a complex surface compound, it's attached to
761  * the surface that the app requested, not the complex root. See
762  * GetAttachedSurface for a description how surfaces are found.
763  *
764  * This is how the current implementation works, and it was coded by looking
765  * at the needs of the applications.
766  *
767  * So far only Z-Buffer attachments are tested, and they are activated in
768  * WineD3D. Mipmaps could be tricky to activate in WineD3D.
769  * Back buffers should work in 2D mode, but they are not tested(Not sure if
770  * they can be attached at all). Rendering to the primary surface and
771  * switching between that and double buffering is not yet implemented in
772  * WineD3D, so for 3D it might have unexpected results.
773  *
774  * Params:
775  *  Attach: Surface to attach to iface
776  *
777  * Returns:
778  *  DD_OK on success
779  *  DDERR_CANNOTATTACHSURFACE if the surface can't be attached for some reason
780  *
781  *****************************************************************************/
782 static HRESULT WINAPI
783 IDirectDrawSurfaceImpl_AddAttachedSurface(IDirectDrawSurface7 *iface,
784                                           IDirectDrawSurface7 *Attach)
785 {
786     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
787     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Attach);
788     TRACE("(%p)->(%p)\n", This, Surf);
789
790     /* Should I make sure to add it to the first complex surface? */
791
792     if(Surf == This)
793         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
794
795     /* MSDN: Only Z buffer surfaces can be attached. An old comment said that apparently
796      * mipmaps and back buffers can be attached too, although our tests say no.
797      */
798     if(!(Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
799     {
800         /* Write a fixme until we know for sure what is going on */
801         FIXME("Application tries to attach a non Z buffer surface. caps %08x\n",
802               Surf->surface_desc.ddsCaps.dwCaps);
803         return DDERR_CANNOTATTACHSURFACE;
804     }
805
806     /* Set MIPMAPSUBLEVEL if this seems to be one */
807     if (This->surface_desc.ddsCaps.dwCaps &
808         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
809     {
810         Surf->surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
811         /* FIXME: we should probably also add to dwMipMapCount of this
812           * and all parent surfaces (update create_texture if you do) */
813     }
814
815     /* Check if the surface is already attached somewhere */
816     if( (Surf->next_attached != NULL) ||
817         (Surf->first_attached != Surf) )
818     {
819          ERR("(%p) The Surface %p is already attached somewhere else: next_attached = %p, first_attached = %p, can't handle by now\n", This, Surf, Surf->next_attached, Surf->first_attached);
820         return DDERR_CANNOTATTACHSURFACE;
821     }
822
823     /* This inserts the new surface at the 2nd position in the chain, right after the root surface */
824     Surf->next_attached = This->next_attached;
825     Surf->first_attached = This->first_attached;
826     This->next_attached = Surf;
827
828     /* Check if we attach a back buffer to the primary */
829     if(Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER &&
830        This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
831     {
832         IWineD3DDevice_SetDepthStencilSurface(This->ddraw->wineD3DDevice,
833                                               Surf->WineD3DSurface);
834     }
835
836     /* MSDN: 
837      * "This method increments the reference count of the surface being attached."
838      */
839     IDirectDrawSurface7_AddRef(Attach);
840     return DD_OK;
841 }
842
843 /*****************************************************************************
844  * IDirectDrawSurface7::DeleteAttachedSurface
845  *
846  * Removes a surface from the attachment chain. The surface's refcount
847  * is decreased by one after it has been removed
848  *
849  * Params:
850  *  Flags: Some flags, not used by this implementation
851  *  Attach: Surface to detach
852  *
853  * Returns:
854  *  DD_OK on success
855  *  DDERR_SURFACENOTATTACHED if the surface isn't attached to
856  *
857  *****************************************************************************/
858 static HRESULT WINAPI
859 IDirectDrawSurfaceImpl_DeleteAttachedSurface(IDirectDrawSurface7 *iface,
860                                              DWORD Flags,
861                                              IDirectDrawSurface7 *Attach)
862 {
863     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
864     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Attach);
865     IDirectDrawSurfaceImpl *Prev = This;
866     TRACE("(%p)->(%08x,%p)\n", This, Flags, Surf);
867
868     if (!Surf || (Surf->first_attached != This) || (Surf == This) )
869         return DDERR_SURFACENOTATTACHED; /* unchecked */
870
871     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
872     if (This->surface_desc.ddsCaps.dwCaps &
873         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
874     {
875         Surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
876         /* FIXME: we should probably also subtract from dwMipMapCount of this
877          * and all parent surfaces */
878     }
879
880     /* Find the predecessor of the detached surface */
881     while(Prev)
882     {
883         if(Prev->next_attached == Surf) break;
884         Prev = Prev->next_attached;
885     }
886
887     /* There must be a surface, otherwise there's a bug */
888     assert(Prev != NULL);
889
890     /* Unchain the surface */
891     Prev->next_attached = Surf->next_attached;
892     Surf->next_attached = NULL;
893     Surf->first_attached = Surf;
894
895     /* Check if we attach a back buffer to the primary */
896     if(Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER &&
897        This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
898     {
899         IWineD3DDevice_SetDepthStencilSurface(This->ddraw->wineD3DDevice,
900                                               NULL);
901     }
902
903     IDirectDrawSurface7_Release(Attach);
904     return DD_OK;
905 }
906
907 /*****************************************************************************
908  * IDirectDrawSurface7::AddOverlayDirtyRect
909  *
910  * "This method is not currently implemented"
911  *
912  * Params:
913  *  Rect: ?
914  *
915  * Returns:
916  *  DDERR_UNSUPPORTED
917  *
918  *****************************************************************************/
919 static HRESULT WINAPI
920 IDirectDrawSurfaceImpl_AddOverlayDirtyRect(IDirectDrawSurface7 *iface,
921                                            LPRECT Rect)
922 {
923     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
924     TRACE("(%p)->(%p)\n",This,Rect);
925
926     /* MSDN says it's not implemented. I could forward it to WineD3D, 
927      * then we'd implement it, but I don't think that's a good idea
928      * (Stefan Dösinger)
929      */
930 #if 0
931     return IWineD3DSurface_AddOverlayDirtyRect(This->WineD3DSurface, pRect);
932 #endif
933     return DDERR_UNSUPPORTED; /* unchecked */
934 }
935
936 /*****************************************************************************
937  * IDirectDrawSurface7::GetDC
938  *
939  * Returns a GDI device context for the surface
940  *
941  * Params:
942  *  hdc: Address of a HDC variable to store the dc to
943  *
944  * Returns:
945  *  DD_OK on success
946  *  DDERR_INVALIDPARAMS if hdc is NULL
947  *  For details, see IWineD3DSurface::GetDC
948  *
949  *****************************************************************************/
950 static HRESULT WINAPI
951 IDirectDrawSurfaceImpl_GetDC(IDirectDrawSurface7 *iface,
952                              HDC *hdc)
953 {
954     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
955     TRACE("(%p)->(%p): Relay\n", This, hdc);
956
957     if(!hdc)
958         return DDERR_INVALIDPARAMS;
959
960     return IWineD3DSurface_GetDC(This->WineD3DSurface,
961                                  hdc);
962 }
963
964 /*****************************************************************************
965  * IDirectDrawSurface7::ReleaseDC
966  *
967  * Releases the DC that was constructed with GetDC
968  *
969  * Params:
970  *  hdc: HDC to release
971  *
972  * Returns:
973  *  DD_OK on success
974  *  For more details, see IWineD3DSurface::ReleaseDC
975  *
976  *****************************************************************************/
977 static HRESULT WINAPI
978 IDirectDrawSurfaceImpl_ReleaseDC(IDirectDrawSurface7 *iface,
979                                  HDC hdc)
980 {
981     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
982     TRACE("(%p)->(%p): Relay\n", This, hdc);
983
984     return IWineD3DSurface_ReleaseDC(This->WineD3DSurface, hdc);
985 }
986
987 /*****************************************************************************
988  * IDirectDrawSurface7::GetCaps
989  *
990  * Returns the surface's caps
991  *
992  * Params:
993  *  Caps: Address to write the caps to
994  *
995  * Returns:
996  *  DD_OK on success
997  *  DDERR_INVALIDPARAMS if Caps is NULL
998  *
999  *****************************************************************************/
1000 static HRESULT WINAPI
1001 IDirectDrawSurfaceImpl_GetCaps(IDirectDrawSurface7 *iface,
1002                                DDSCAPS2 *Caps)
1003 {
1004     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1005     TRACE("(%p)->(%p)\n",This,Caps);
1006
1007     if(!Caps)
1008         return DDERR_INVALIDPARAMS;
1009
1010     *Caps = This->surface_desc.ddsCaps;
1011     return DD_OK;
1012 }
1013
1014 /*****************************************************************************
1015  * IDirectDrawSurface7::SetPriority
1016  *
1017  * Sets a texture priority for managed textures.
1018  *
1019  * Params:
1020  *  Priority: The new priority
1021  *
1022  * Returns:
1023  *  DD_OK on success
1024  *  For more details, see IWineD3DSurface::SetPriority
1025  *
1026  *****************************************************************************/
1027 static HRESULT WINAPI
1028 IDirectDrawSurfaceImpl_SetPriority(IDirectDrawSurface7 *iface, DWORD Priority)
1029 {
1030     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1031     TRACE("(%p)->(%d): Relay!\n",This,Priority);
1032
1033     return IWineD3DSurface_SetPriority(This->WineD3DSurface, Priority);
1034 }
1035
1036 /*****************************************************************************
1037  * IDirectDrawSurface7::GetPriority
1038  *
1039  * Returns the surface's priority
1040  *
1041  * Params:
1042  *  Priority: Address of a variable to write the priority to
1043  *
1044  * Returns:
1045  *  D3D_OK on success
1046  *  DDERR_INVALIDPARAMS if Priority == NULL
1047  *  For more details, see IWineD3DSurface::GetPriority
1048  *
1049  *****************************************************************************/
1050 static HRESULT WINAPI
1051 IDirectDrawSurfaceImpl_GetPriority(IDirectDrawSurface7 *iface,
1052                                    DWORD *Priority)
1053 {
1054     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1055     TRACE("(%p)->(%p): Relay\n",This,Priority);
1056
1057     if(!Priority)
1058         return DDERR_INVALIDPARAMS;
1059
1060     *Priority = IWineD3DSurface_GetPriority(This->WineD3DSurface);
1061     return DD_OK;
1062 }
1063
1064 /*****************************************************************************
1065  * IDirectDrawSurface7::SetPrivateData
1066  *
1067  * Stores some data in the surface that is intended for the application's
1068  * use.
1069  *
1070  * Params:
1071  *  tag: GUID that identifies the data
1072  *  Data: Pointer to the private data
1073  *  Size: Size of the private data
1074  *  Flags: Some flags
1075  *
1076  * Returns:
1077  *  D3D_OK on success
1078  *  For more details, see IWineD3DSurface::SetPrivateData
1079  *
1080  *****************************************************************************/
1081 static HRESULT WINAPI
1082 IDirectDrawSurfaceImpl_SetPrivateData(IDirectDrawSurface7 *iface,
1083                                       REFGUID tag,
1084                                       void *Data,
1085                                       DWORD Size,
1086                                       DWORD Flags)
1087 {
1088     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1089     TRACE("(%p)->(%s,%p,%d,%x): Relay\n", This, debugstr_guid(tag), Data, Size, Flags);
1090
1091     return IWineD3DSurface_SetPrivateData(This->WineD3DSurface,
1092                                           tag,
1093                                           Data,
1094                                           Size,
1095                                           Flags);
1096 }
1097
1098 /*****************************************************************************
1099  * IDirectDrawSurface7::GetPrivateData
1100  *
1101  * Returns the private data set with IDirectDrawSurface7::SetPrivateData
1102  *
1103  * Params:
1104  *  tag: GUID of the data to return
1105  *  Data: Address where to write the data to
1106  *  Size: Size of the buffer at Data
1107  *
1108  * Returns:
1109  *  DD_OK on success
1110  *  DDERR_INVALIDPARAMS if Data is NULL
1111  *  For more details, see IWineD3DSurface::GetPrivateData
1112  *
1113  *****************************************************************************/
1114 static HRESULT WINAPI
1115 IDirectDrawSurfaceImpl_GetPrivateData(IDirectDrawSurface7 *iface,
1116                                       REFGUID tag,
1117                                       void *Data,
1118                                       DWORD *Size)
1119 {
1120     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1121     TRACE("(%p)->(%s,%p,%p): Relay\n", This, debugstr_guid(tag), Data, Size);
1122
1123     if(!Data)
1124         return DDERR_INVALIDPARAMS;
1125
1126     return IWineD3DSurface_GetPrivateData(This->WineD3DSurface,
1127                                           tag,
1128                                           Data,
1129                                           Size);
1130 }
1131
1132 /*****************************************************************************
1133  * IDirectDrawSurface7::FreePrivateData
1134  *
1135  * Frees private data stored in the surface
1136  *
1137  * Params:
1138  *  tag: Tag of the data to free
1139  *
1140  * Returns:
1141  *  D3D_OK on success
1142  *  For more details, see IWineD3DSurface::FreePrivateData
1143  *
1144  *****************************************************************************/
1145 static HRESULT WINAPI
1146 IDirectDrawSurfaceImpl_FreePrivateData(IDirectDrawSurface7 *iface,
1147                                        REFGUID tag)
1148 {
1149     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1150     TRACE("(%p)->(%s): Relay\n", This, debugstr_guid(tag));
1151
1152     return IWineD3DSurface_FreePrivateData(This->WineD3DSurface, tag);
1153 }
1154
1155 /*****************************************************************************
1156  * IDirectDrawSurface7::PageLock
1157  *
1158  * Prevents a sysmem surface from being paged out
1159  *
1160  * Params:
1161  *  Flags: Not used, must be 0(unchecked)
1162  *
1163  * Returns:
1164  *  DD_OK, because it's a stub
1165  *
1166  *****************************************************************************/
1167 static HRESULT WINAPI
1168 IDirectDrawSurfaceImpl_PageLock(IDirectDrawSurface7 *iface,
1169                                 DWORD Flags)
1170 {
1171     TRACE("(%p)->(%x)\n", iface, Flags);
1172
1173     /* This is Windows memory management related - we don't need this */
1174     return DD_OK;
1175 }
1176
1177 /*****************************************************************************
1178  * IDirectDrawSurface7::PageUnlock
1179  *
1180  * Allows a sysmem surface to be paged out
1181  *
1182  * Params:
1183  *  Flags: Not used, must be 0(unckeched)
1184  *
1185  * Returns:
1186  *  DD_OK, because it's a stub
1187  *
1188  *****************************************************************************/
1189 static HRESULT WINAPI
1190 IDirectDrawSurfaceImpl_PageUnlock(IDirectDrawSurface7 *iface,
1191                                   DWORD Flags)
1192 {
1193     TRACE("(%p)->(%x)\n", iface, Flags);
1194
1195     return DD_OK;
1196 }
1197
1198 /*****************************************************************************
1199  * IDirectDrawSurface7::BltBatch
1200  *
1201  * An unimplemented function
1202  *
1203  * Params:
1204  *  ?
1205  *
1206  * Returns:
1207  *  DDERR_UNSUPPORTED
1208  *
1209  *****************************************************************************/
1210 static HRESULT WINAPI IDirectDrawSurfaceImpl_BltBatch(IDirectDrawSurface7 *iface, DDBLTBATCH *Batch, DWORD Count, DWORD Flags)
1211 {
1212     TRACE("(%p)->(%p,%d,%08x)\n",iface,Batch,Count,Flags);
1213
1214     /* MSDN: "not currently implemented" */
1215     return DDERR_UNSUPPORTED;
1216 }
1217
1218 /*****************************************************************************
1219  * IDirectDrawSurface7::EnumAttachedSurfaces
1220  *
1221  * Enumerates all surfaces attached to this surface
1222  *
1223  * Params:
1224  *  context: Pointer to pass unmodified to the callback
1225  *  cb: Callback function to call for each surface
1226  *
1227  * Returns:
1228  *  DD_OK on success
1229  *  DDERR_INVALIDPARAMS if cb is NULL
1230  *
1231  *****************************************************************************/
1232 static HRESULT WINAPI
1233 IDirectDrawSurfaceImpl_EnumAttachedSurfaces(IDirectDrawSurface7 *iface,
1234                                             void *context,
1235                                             LPDDENUMSURFACESCALLBACK7 cb)
1236 {
1237     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1238     IDirectDrawSurfaceImpl *surf;
1239     DDSURFACEDESC2 desc;
1240     int i;
1241
1242     /* Attached surfaces aren't handled in WineD3D */
1243     TRACE("(%p)->(%p,%p)\n",This,context,cb);
1244
1245     if(!cb)
1246         return DDERR_INVALIDPARAMS;
1247
1248     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
1249     {
1250         surf = This->complex_array[i];
1251         if(!surf) break;
1252
1253         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1254         desc = surf->surface_desc;
1255         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1256         if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
1257             return DD_OK;
1258     }
1259
1260     for (surf = This->next_attached; surf != NULL; surf = surf->next_attached)
1261     {
1262         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1263         desc = surf->surface_desc;
1264         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1265         if (cb( ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
1266             return DD_OK;
1267     }
1268
1269     TRACE(" end of enumeration.\n");
1270
1271     return DD_OK;
1272 }
1273
1274 /*****************************************************************************
1275  * IDirectDrawSurface7::EnumOverlayZOrders
1276  *
1277  * "Enumerates the overlay surfaces on the specified destination"
1278  *
1279  * Params:
1280  *  Flags: DDENUMOVERLAYZ_BACKTOFRONT  or DDENUMOVERLAYZ_FRONTTOBACK
1281  *  context: context to pass back to the callback
1282  *  cb: callback function to call for each enumerated surface
1283  *
1284  * Returns:
1285  *  DD_OK, because it's a stub
1286  *
1287  *****************************************************************************/
1288 static HRESULT WINAPI
1289 IDirectDrawSurfaceImpl_EnumOverlayZOrders(IDirectDrawSurface7 *iface,
1290                                           DWORD Flags,
1291                                           void *context,
1292                                           LPDDENUMSURFACESCALLBACK7 cb)
1293 {
1294      FIXME("(%p)->(%x,%p,%p): Stub!\n", iface, Flags, context, cb);
1295
1296     return DD_OK;
1297 }
1298
1299 /*****************************************************************************
1300  * IDirectDrawSurface7::GetBltStatus
1301  *
1302  * Returns the blitting status
1303  *
1304  * Params:
1305  *  Flags: DDGBS_CANBLT or DDGBS_ISBLTDONE
1306  *
1307  * Returns:
1308  *  See IWineD3DSurface::Blt
1309  *
1310  *****************************************************************************/
1311 static HRESULT WINAPI
1312 IDirectDrawSurfaceImpl_GetBltStatus(IDirectDrawSurface7 *iface,
1313                                     DWORD Flags)
1314 {
1315     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1316     HRESULT hr;
1317     TRACE("(%p)->(%x): Relay\n", This, Flags);
1318
1319     hr = IWineD3DSurface_GetBltStatus(This->WineD3DSurface, Flags);
1320     switch(hr)
1321     {
1322         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1323         default:                            return hr;
1324     }
1325 }
1326
1327 /*****************************************************************************
1328  * IDirectDrawSurface7::GetColorKey
1329  *
1330  * Returns the color key assigned to the surface
1331  *
1332  * Params:
1333  *  Flags: Some flags
1334  *  CKey: Address to store the key to
1335  *
1336  * Returns:
1337  *  DD_OK on success
1338  *  DDERR_INVALIDPARAMS if CKey is NULL
1339  *
1340  *****************************************************************************/
1341 static HRESULT WINAPI
1342 IDirectDrawSurfaceImpl_GetColorKey(IDirectDrawSurface7 *iface,
1343                                    DWORD Flags,
1344                                    DDCOLORKEY *CKey)
1345 {
1346     /* There is a DDERR_NOCOLORKEY error, but how do we know if a color key
1347      * isn't there? That's like saying that an int isn't there. (Which MS
1348      * has done in other docs.) */
1349     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1350     TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
1351
1352     if(!CKey)
1353         return DDERR_INVALIDPARAMS;
1354
1355     switch (Flags)
1356     {
1357     case DDCKEY_DESTBLT:
1358         *CKey = This->surface_desc.ddckCKDestBlt;
1359         break;
1360
1361     case DDCKEY_DESTOVERLAY:
1362         *CKey = This->surface_desc.u3.ddckCKDestOverlay;
1363         break;
1364
1365     case DDCKEY_SRCBLT:
1366         *CKey = This->surface_desc.ddckCKSrcBlt;
1367         break;
1368
1369     case DDCKEY_SRCOVERLAY:
1370         *CKey = This->surface_desc.ddckCKSrcOverlay;
1371         break;
1372
1373     default:
1374         return DDERR_INVALIDPARAMS;
1375     }
1376
1377     return DD_OK;
1378 }
1379
1380 /*****************************************************************************
1381  * IDirectDrawSurface7::GetFlipStatus
1382  *
1383  * Returns the flipping status of the surface
1384  *
1385  * Params:
1386  *  Flags: DDGFS_CANFLIP of DDGFS_ISFLIPDONE
1387  *
1388  * Returns:
1389  *  See IWineD3DSurface::GetFlipStatus
1390  *
1391  *****************************************************************************/
1392 static HRESULT WINAPI
1393 IDirectDrawSurfaceImpl_GetFlipStatus(IDirectDrawSurface7 *iface,
1394                                      DWORD Flags)
1395 {
1396     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1397     HRESULT hr;
1398     TRACE("(%p)->(%x): Relay\n", This, Flags);
1399
1400     hr = IWineD3DSurface_GetFlipStatus(This->WineD3DSurface, Flags);
1401     switch(hr)
1402     {
1403         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1404         default:                            return hr;
1405     }
1406 }
1407
1408 /*****************************************************************************
1409  * IDirectDrawSurface7::GetOverlayPosition
1410  *
1411  * Returns the display coordinates of a visible and active overlay surface
1412  *
1413  * Params:
1414  *  X
1415  *  Y
1416  *
1417  * Returns:
1418  *  DDERR_NOTAOVERLAYSURFACE, because it's a stub
1419  *****************************************************************************/
1420 static HRESULT WINAPI
1421 IDirectDrawSurfaceImpl_GetOverlayPosition(IDirectDrawSurface7 *iface,
1422                                           LONG *X,
1423                                           LONG *Y) {
1424     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1425     TRACE("(%p)->(%p,%p): Relay\n", This, X, Y);
1426
1427     return IWineD3DSurface_GetOverlayPosition(This->WineD3DSurface,
1428                                               X,
1429                                               Y);
1430 }
1431
1432 /*****************************************************************************
1433  * IDirectDrawSurface7::GetPixelFormat
1434  *
1435  * Returns the pixel format of the Surface
1436  *
1437  * Params:
1438  *  PixelFormat: Pointer to a DDPIXELFORMAT structure to which the pixel
1439  *               format should be written
1440  *
1441  * Returns:
1442  *  DD_OK on success
1443  *  DDERR_INVALIDPARAMS if PixelFormat is NULL
1444  *
1445  *****************************************************************************/
1446 static HRESULT WINAPI
1447 IDirectDrawSurfaceImpl_GetPixelFormat(IDirectDrawSurface7 *iface,
1448                                       DDPIXELFORMAT *PixelFormat)
1449 {
1450     /* What is DDERR_INVALIDSURFACETYPE for here? */
1451     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1452     TRACE("(%p)->(%p)\n",This,PixelFormat);
1453
1454     if(!PixelFormat)
1455         return DDERR_INVALIDPARAMS;
1456
1457     DD_STRUCT_COPY_BYSIZE(PixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
1458
1459     return DD_OK;
1460 }
1461
1462
1463 /*****************************************************************************
1464  * IDirectDrawSurface7::GetSurfaceDesc
1465  *
1466  * Returns the description of this surface
1467  *
1468  * Params:
1469  *  DDSD: Address of a DDSURFACEDESC2 structure that is to be filled with the
1470  *        surface desc
1471  *
1472  * Returns:
1473  *  DD_OK on success
1474  *  DDERR_INVALIDPARAMS if DDSD is NULL
1475  *
1476  *****************************************************************************/
1477 static HRESULT WINAPI
1478 IDirectDrawSurfaceImpl_GetSurfaceDesc(IDirectDrawSurface7 *iface,
1479                                       DDSURFACEDESC2 *DDSD)
1480 {
1481     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1482
1483     TRACE("(%p)->(%p)\n",This,DDSD);
1484
1485     if(!DDSD)
1486         return DDERR_INVALIDPARAMS;
1487
1488     if ((DDSD->dwSize < sizeof(DDSURFACEDESC)) ||
1489         (DDSD->dwSize > sizeof(DDSURFACEDESC2)))
1490     {
1491         ERR("Impossible/Strange struct size %d.\n",DDSD->dwSize);
1492         return DDERR_GENERIC;
1493     }
1494
1495     DD_STRUCT_COPY_BYSIZE(DDSD,&This->surface_desc);
1496     TRACE("Returning surface desc:\n");
1497     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
1498
1499     return DD_OK;
1500 }
1501
1502 /*****************************************************************************
1503  * IDirectDrawSurface7::Initialize
1504  *
1505  * Initializes the surface. This is a no-op in Wine
1506  *
1507  * Params:
1508  *  DD: Pointer to an DirectDraw interface
1509  *  DDSD: Surface description for initialization
1510  *
1511  * Returns:
1512  *  DDERR_ALREADYINITIALIZED
1513  *
1514  *****************************************************************************/
1515 static HRESULT WINAPI
1516 IDirectDrawSurfaceImpl_Initialize(IDirectDrawSurface7 *iface,
1517                                   IDirectDraw *DD,
1518                                   DDSURFACEDESC2 *DDSD)
1519 {
1520     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1521     IDirectDrawImpl *ddimpl = ICOM_OBJECT(IDirectDrawImpl, IDirectDraw, DD);
1522     TRACE("(%p)->(%p,%p)\n",This,ddimpl,DDSD);
1523
1524     return DDERR_ALREADYINITIALIZED;
1525 }
1526
1527 /*****************************************************************************
1528  * IDirectDrawSurface7::IsLost
1529  *
1530  * Checks if the surface is lost
1531  *
1532  * Returns:
1533  *  DD_OK, if the surface is useable
1534  *  DDERR_ISLOST if the surface is lost
1535  *  See IWineD3DSurface::IsLost for more details
1536  *
1537  *****************************************************************************/
1538 static HRESULT WINAPI
1539 IDirectDrawSurfaceImpl_IsLost(IDirectDrawSurface7 *iface)
1540 {
1541     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1542     HRESULT hr;
1543     TRACE("(%p)\n", This);
1544
1545     /* We lose the surface if the implementation was changed */
1546     if(This->ImplType != This->ddraw->ImplType)
1547     {
1548         /* But this shouldn't happen. When we change the implementation,
1549          * all surfaces are re-created automatically, and their content
1550          * is copied
1551          */
1552         ERR(" (%p) Implementation was changed from %d to %d\n", This, This->ImplType, This->ddraw->ImplType);
1553         return DDERR_SURFACELOST;
1554     }
1555
1556     hr = IWineD3DSurface_IsLost(This->WineD3DSurface);
1557     switch(hr)
1558     {
1559         /* D3D8 and 9 loose full devices, thus there's only a DEVICELOST error.
1560          * WineD3D uses the same error for surfaces
1561          */
1562         case WINED3DERR_DEVICELOST:         return DDERR_SURFACELOST;
1563         default:                            return hr;
1564     }
1565 }
1566
1567 /*****************************************************************************
1568  * IDirectDrawSurface7::Restore
1569  *
1570  * Restores a lost surface. This makes the surface usable again, but
1571  * doesn't reload its old contents
1572  *
1573  * Returns:
1574  *  DD_OK on success
1575  *  See IWineD3DSurface::Restore for more details
1576  *
1577  *****************************************************************************/
1578 static HRESULT WINAPI
1579 IDirectDrawSurfaceImpl_Restore(IDirectDrawSurface7 *iface)
1580 {
1581     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1582     TRACE("(%p)\n", This);
1583
1584     if(This->ImplType != This->ddraw->ImplType)
1585     {
1586         /* Call the recreation callback. Make sure to AddRef first */
1587         IDirectDrawSurface_AddRef(iface);
1588         IDirectDrawImpl_RecreateSurfacesCallback(iface,
1589                                                  &This->surface_desc,
1590                                                  NULL /* Not needed */);
1591     }
1592     return IWineD3DSurface_Restore(This->WineD3DSurface);
1593 }
1594
1595 /*****************************************************************************
1596  * IDirectDrawSurface7::SetOverlayPosition
1597  *
1598  * Changes the display coordinates of an overlay surface
1599  *
1600  * Params:
1601  *  X:
1602  *  Y:
1603  *
1604  * Returns:
1605  *   DDERR_NOTAOVERLAYSURFACE, because we don't support overlays right now
1606  *****************************************************************************/
1607 static HRESULT WINAPI
1608 IDirectDrawSurfaceImpl_SetOverlayPosition(IDirectDrawSurface7 *iface,
1609                                           LONG X,
1610                                           LONG Y)
1611 {
1612     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1613     TRACE("(%p)->(%d,%d): Relay\n", This, X, Y);
1614
1615     return IWineD3DSurface_SetOverlayPosition(This->WineD3DSurface,
1616                                               X,
1617                                               Y);
1618 }
1619
1620 /*****************************************************************************
1621  * IDirectDrawSurface7::UpdateOverlay
1622  *
1623  * Modifies the attributes of an overlay surface.
1624  *
1625  * Params:
1626  *  SrcRect: The section of the source being used for the overlay
1627  *  DstSurface: Address of the surface that is overlaid
1628  *  DstRect: Place of the overlay
1629  *  Flags: some DDOVER_* flags
1630  *
1631  * Returns:
1632  *  DDERR_UNSUPPORTED, because we don't support overlays
1633  *
1634  *****************************************************************************/
1635 static HRESULT WINAPI
1636 IDirectDrawSurfaceImpl_UpdateOverlay(IDirectDrawSurface7 *iface,
1637                                      LPRECT SrcRect,
1638                                      IDirectDrawSurface7 *DstSurface,
1639                                      LPRECT DstRect,
1640                                      DWORD Flags,
1641                                      LPDDOVERLAYFX FX)
1642 {
1643     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1644     IDirectDrawSurfaceImpl *Dst = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DstSurface);
1645     TRACE("(%p)->(%p,%p,%p,%x,%p): Relay\n", This, SrcRect, Dst, DstRect, Flags, FX);
1646
1647     return IWineD3DSurface_UpdateOverlay(This->WineD3DSurface,
1648                                          SrcRect,
1649                                          Dst ? Dst->WineD3DSurface : NULL,
1650                                          DstRect,
1651                                          Flags,
1652                                          (WINEDDOVERLAYFX *) FX);
1653 }
1654
1655 /*****************************************************************************
1656  * IDirectDrawSurface7::UpdateOverlayDisplay
1657  *
1658  * The DX7 sdk says that it's not implemented
1659  *
1660  * Params:
1661  *  Flags: ?
1662  *
1663  * Returns: DDERR_UNSUPPORTED, because we don't support overlays
1664  *
1665  *****************************************************************************/
1666 static HRESULT WINAPI
1667 IDirectDrawSurfaceImpl_UpdateOverlayDisplay(IDirectDrawSurface7 *iface,
1668                                             DWORD Flags)
1669 {
1670     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1671     TRACE("(%p)->(%x)\n", This, Flags);
1672     return DDERR_UNSUPPORTED;
1673 }
1674
1675 /*****************************************************************************
1676  * IDirectDrawSurface7::UpdateOverlayZOrder
1677  *
1678  * Sets an overlay's Z order
1679  *
1680  * Params:
1681  *  Flags: DDOVERZ_* flags
1682  *  DDSRef: Defines the relative position in the overlay chain
1683  *
1684  * Returns:
1685  *  DDERR_NOTOVERLAYSURFACE, because we don't support overlays
1686  *
1687  *****************************************************************************/
1688 static HRESULT WINAPI
1689 IDirectDrawSurfaceImpl_UpdateOverlayZOrder(IDirectDrawSurface7 *iface,
1690                                            DWORD Flags,
1691                                            IDirectDrawSurface7 *DDSRef)
1692 {
1693     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1694     IDirectDrawSurfaceImpl *Ref = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DDSRef);
1695
1696     TRACE("(%p)->(%x,%p): Relay\n", This, Flags, Ref);
1697     return IWineD3DSurface_UpdateOverlayZOrder(This->WineD3DSurface,
1698                                                Flags,
1699                                                Ref ? Ref->WineD3DSurface : NULL);
1700 }
1701
1702 /*****************************************************************************
1703  * IDirectDrawSurface7::GetDDInterface
1704  *
1705  * Returns the IDirectDraw7 interface pointer of the DirectDraw object this
1706  * surface belongs to
1707  *
1708  * Params:
1709  *  DD: Address to write the interface pointer to
1710  *
1711  * Returns:
1712  *  DD_OK on success
1713  *  DDERR_INVALIDPARAMS if DD is NULL
1714  *
1715  *****************************************************************************/
1716 static HRESULT WINAPI
1717 IDirectDrawSurfaceImpl_GetDDInterface(IDirectDrawSurface7 *iface,
1718                                       void **DD)
1719 {
1720     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1721
1722     TRACE("(%p)->(%p)\n",This,DD);
1723
1724     if(!DD)
1725         return DDERR_INVALIDPARAMS;
1726
1727     switch(This->version)
1728     {
1729         case 7:
1730             *((IDirectDraw7 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw7);
1731             IDirectDraw7_AddRef(*(IDirectDraw7 **) DD);
1732             break;
1733
1734         case 4:
1735             *((IDirectDraw4 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw4);
1736             IDirectDraw4_AddRef(*(IDirectDraw4 **) DD);
1737             break;
1738
1739         case 2:
1740             *((IDirectDraw2 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw2);
1741             IDirectDraw_AddRef( *(IDirectDraw2 **) DD);
1742             break;
1743
1744         case 1:
1745             *((IDirectDraw **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw);
1746             IDirectDraw_AddRef( *(IDirectDraw **) DD);
1747             break;
1748
1749     }
1750
1751     return DD_OK;
1752 }
1753
1754 /* This seems also windows implementation specific - I don't think WineD3D needs this */
1755 static HRESULT WINAPI IDirectDrawSurfaceImpl_ChangeUniquenessValue(IDirectDrawSurface7 *iface)
1756 {
1757     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1758     volatile IDirectDrawSurfaceImpl* vThis = This;
1759
1760     TRACE("(%p)\n",This);
1761     /* A uniqueness value of 0 is apparently special.
1762     * This needs to be checked. */
1763     while (1) {
1764         DWORD old_uniqueness_value = vThis->uniqueness_value;
1765         DWORD new_uniqueness_value = old_uniqueness_value+1;
1766
1767         if (old_uniqueness_value == 0) break;
1768         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
1769
1770         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
1771                                       old_uniqueness_value,
1772                                       new_uniqueness_value)
1773             == old_uniqueness_value)
1774             break;
1775     }
1776
1777     return DD_OK;
1778 }
1779
1780 static HRESULT WINAPI IDirectDrawSurfaceImpl_GetUniquenessValue(IDirectDrawSurface7 *iface, LPDWORD pValue)
1781 {
1782     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1783
1784     TRACE("(%p)->(%p)\n",This,pValue);
1785     *pValue = This->uniqueness_value;
1786     return DD_OK;
1787 }
1788
1789 /*****************************************************************************
1790  * IDirectDrawSurface7::SetLOD
1791  *
1792  * Sets the level of detail of a texture
1793  *
1794  * Params:
1795  *  MaxLOD: LOD to set
1796  *
1797  * Returns:
1798  *  DD_OK on success
1799  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
1800  *
1801  *****************************************************************************/
1802 static HRESULT WINAPI
1803 IDirectDrawSurfaceImpl_SetLOD(IDirectDrawSurface7 *iface,
1804                               DWORD MaxLOD)
1805 {
1806     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1807     TRACE("(%p)->(%d)\n", This, MaxLOD);
1808
1809     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
1810         return DDERR_INVALIDOBJECT;
1811
1812     if(!This->wineD3DTexture)
1813     {
1814         ERR("(%p) The DirectDraw texture has no WineD3DTexture!\n", This);
1815         return DDERR_INVALIDOBJECT;
1816     }
1817
1818     return IWineD3DTexture_SetLOD(This->wineD3DTexture,
1819                                   MaxLOD);
1820 }
1821
1822 /*****************************************************************************
1823  * IDirectDrawSurface7::GetLOD
1824  *
1825  * Returns the level of detail of a Direct3D texture
1826  *
1827  * Params:
1828  *  MaxLOD: Address to write the LOD to
1829  *
1830  * Returns:
1831  *  DD_OK on success
1832  *  DDERR_INVALIDPARAMS if MaxLOD is NULL
1833  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
1834  *
1835  *****************************************************************************/
1836 static HRESULT WINAPI
1837 IDirectDrawSurfaceImpl_GetLOD(IDirectDrawSurface7 *iface,
1838                               DWORD *MaxLOD)
1839 {
1840     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1841     TRACE("(%p)->(%p)\n", This, MaxLOD);
1842
1843     if(!MaxLOD)
1844         return DDERR_INVALIDPARAMS;
1845
1846     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
1847         return DDERR_INVALIDOBJECT;
1848
1849     *MaxLOD = IWineD3DTexture_GetLOD(This->wineD3DTexture);
1850     return DD_OK;
1851 }
1852
1853 /*****************************************************************************
1854  * IDirectDrawSurface7::BltFast
1855  *
1856  * Performs a fast Blit.
1857  *
1858  * Params:
1859  *  dstx: The x coordinate to blit to on the destination
1860  *  dsty: The y coordinate to blit to on the destination
1861  *  Source: The source surface
1862  *  rsrc: The source rectangle
1863  *  trans: Type of transfer. Some DDBLTFAST_* flags
1864  *
1865  * Returns:
1866  *  DD_OK on success
1867  *  For more details, see IWineD3DSurface::BltFast
1868  *
1869  *****************************************************************************/
1870 static HRESULT WINAPI
1871 IDirectDrawSurfaceImpl_BltFast(IDirectDrawSurface7 *iface,
1872                                DWORD dstx,
1873                                DWORD dsty,
1874                                IDirectDrawSurface7 *Source,
1875                                RECT *rsrc,
1876                                DWORD trans)
1877 {
1878     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1879     HRESULT hr;
1880     IDirectDrawSurfaceImpl *src = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Source);
1881     TRACE("(%p)->(%d,%d,%p,%p,%d): Relay\n", This, dstx, dsty, Source, rsrc, trans);
1882
1883     hr = IWineD3DSurface_BltFast(This->WineD3DSurface,
1884                                  dstx, dsty,
1885                                  src ? src->WineD3DSurface : NULL,
1886                                  rsrc,
1887                                  trans);
1888     switch(hr)
1889     {
1890         case WINED3DERR_NOTAVAILABLE:           return DDERR_UNSUPPORTED;
1891         case WINED3DERR_WRONGTEXTUREFORMAT:     return DDERR_INVALIDPIXELFORMAT;
1892         default:                                return hr;
1893     }
1894 }
1895
1896 /*****************************************************************************
1897  * IDirectDrawSurface7::GetClipper
1898  *
1899  * Returns the IDirectDrawClipper interface of the clipper assigned to this
1900  * surface
1901  *
1902  * Params:
1903  *  Clipper: Address to store the interface pointer at
1904  *
1905  * Returns:
1906  *  DD_OK on success
1907  *  DDERR_INVALIDPARAMS if Clipper is NULL
1908  *  DDERR_NOCLIPPERATTACHED if there's no clipper attached
1909  *
1910  *****************************************************************************/
1911 static HRESULT WINAPI
1912 IDirectDrawSurfaceImpl_GetClipper(IDirectDrawSurface7 *iface,
1913                                   IDirectDrawClipper **Clipper)
1914 {
1915     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1916     TRACE("(%p)->(%p)\n", This, Clipper);
1917
1918     if(!Clipper)
1919         return DDERR_INVALIDPARAMS;
1920
1921     if(This->clipper == NULL)
1922         return DDERR_NOCLIPPERATTACHED;
1923
1924     *Clipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper);
1925     IDirectDrawClipper_AddRef(*Clipper);
1926     return DD_OK;
1927 }
1928
1929 /*****************************************************************************
1930  * IDirectDrawSurface7::SetClipper
1931  *
1932  * Sets a clipper for the surface
1933  *
1934  * Params:
1935  *  Clipper: IDirectDrawClipper interface of the clipper to set
1936  *
1937  * Returns:
1938  *  DD_OK on success
1939  *
1940  *****************************************************************************/
1941 static HRESULT WINAPI
1942 IDirectDrawSurfaceImpl_SetClipper(IDirectDrawSurface7 *iface,
1943                                   IDirectDrawClipper *Clipper)
1944 {
1945     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1946     IDirectDrawClipperImpl *oldClipper = This->clipper;
1947
1948     TRACE("(%p)->(%p)\n",This,Clipper);
1949     if (ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper) == This->clipper)
1950         return DD_OK;
1951
1952     This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper);
1953
1954     if (Clipper != NULL)
1955         IDirectDrawClipper_AddRef(Clipper);
1956     if(oldClipper)
1957         IDirectDrawClipper_Release(ICOM_INTERFACE(oldClipper, IDirectDrawClipper));
1958
1959     return DD_OK;
1960 }
1961
1962 /*****************************************************************************
1963  * IDirectDrawSurface7::SetSurfaceDesc
1964  *
1965  * Sets the surface description. It can override the pixel format, the surface
1966  * memory, ...
1967  * It's not really tested.
1968  *
1969  * Params:
1970  * DDSD: Pointer to the new surface description to set
1971  * Flags: Some flags
1972  *
1973  * Returns:
1974  *  DD_OK on success
1975  *  DDERR_INVALIDPARAMS if DDSD is NULL
1976  *
1977  *****************************************************************************/
1978 static HRESULT WINAPI
1979 IDirectDrawSurfaceImpl_SetSurfaceDesc(IDirectDrawSurface7 *iface,
1980                                       DDSURFACEDESC2 *DDSD,
1981                                       DWORD Flags)
1982 {
1983     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1984     WINED3DFORMAT newFormat = WINED3DFMT_UNKNOWN;
1985     HRESULT hr;
1986     TRACE("(%p)->(%p,%x)\n", This, DDSD, Flags);
1987
1988     if(!DDSD)
1989         return DDERR_INVALIDPARAMS;
1990
1991     if (DDSD->dwFlags & DDSD_LPSURFACE && DDSD->lpSurface)
1992     {
1993         ERR("Setting the surface memory isn't supported yet\n");
1994         return DDERR_INVALIDPARAMS;
1995
1996     }
1997     if (DDSD->dwFlags & DDSD_PIXELFORMAT)
1998     {
1999         newFormat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
2000
2001         if(newFormat == WINED3DFMT_UNKNOWN)
2002         {
2003             ERR("Requested to set an unknown pixelformat\n");
2004             return DDERR_INVALIDPARAMS;
2005         }
2006         if(newFormat != PixelFormat_DD2WineD3D(&This->surface_desc.u4.ddpfPixelFormat) )
2007         {
2008             hr = IWineD3DSurface_SetFormat(This->WineD3DSurface,
2009                                            newFormat);
2010             if(hr != DD_OK) return hr;
2011         }
2012     }
2013     if (DDSD->dwFlags & DDSD_CKDESTOVERLAY)
2014     {
2015         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2016                                     DDCKEY_DESTOVERLAY,
2017                                     (WINEDDCOLORKEY *) &DDSD->u3.ddckCKDestOverlay);
2018     }
2019     if (DDSD->dwFlags & DDSD_CKDESTBLT)
2020     {
2021         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2022                                     DDCKEY_DESTBLT,
2023                                     (WINEDDCOLORKEY *) &DDSD->ddckCKDestBlt);
2024     }
2025     if (DDSD->dwFlags & DDSD_CKSRCOVERLAY)
2026     {
2027         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2028                                     DDCKEY_SRCOVERLAY,
2029                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcOverlay);
2030     }
2031     if (DDSD->dwFlags & DDSD_CKSRCBLT)
2032     {
2033         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2034                                     DDCKEY_SRCBLT,
2035                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcBlt);
2036     }
2037     if (DDSD->dwFlags & DDSD_LPSURFACE)
2038     {
2039         hr = IWineD3DSurface_SetMem(This->WineD3DSurface, DDSD->lpSurface);
2040         if(hr != WINED3D_OK)
2041         {
2042             /* No need for a trace here, wined3d does that for us */
2043             return hr;
2044         }
2045     }
2046
2047     This->surface_desc = *DDSD;
2048
2049     return DD_OK;
2050 }
2051
2052 /*****************************************************************************
2053  * IDirectDrawSurface7::GetPalette
2054  *
2055  * Returns the IDirectDrawPalette interface of the palette currently assigned
2056  * to the surface
2057  *
2058  * Params:
2059  *  Pal: Address to write the interface pointer to
2060  *
2061  * Returns:
2062  *  DD_OK on success
2063  *  DDERR_INVALIDPARAMS if Pal is NULL
2064  *
2065  *****************************************************************************/
2066 static HRESULT WINAPI
2067 IDirectDrawSurfaceImpl_GetPalette(IDirectDrawSurface7 *iface,
2068                                   IDirectDrawPalette **Pal)
2069 {
2070     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2071     IWineD3DPalette *wPal;
2072     HRESULT hr;
2073     TRACE("(%p)->(%p): Relay\n", This, Pal);
2074
2075     if(!Pal)
2076         return DDERR_INVALIDPARAMS;
2077
2078     hr = IWineD3DSurface_GetPalette(This->WineD3DSurface, &wPal);
2079     if(hr != DD_OK) return hr;
2080
2081     if(wPal)
2082     {
2083         hr = IWineD3DPalette_GetParent(wPal, (IUnknown **) Pal);
2084     }
2085     else
2086     {
2087         *Pal = NULL;
2088         hr = DDERR_NOPALETTEATTACHED;
2089     }
2090
2091     return hr;
2092 }
2093
2094 /*****************************************************************************
2095  * SetColorKeyEnum
2096  *
2097  * EnumAttachedSurface callback for SetColorKey. Used to set color keys
2098  * recursively in the surface tree
2099  *
2100  *****************************************************************************/
2101 struct SCKContext
2102 {
2103     HRESULT ret;
2104     WINEDDCOLORKEY *CKey;
2105     DWORD Flags;
2106 };
2107
2108 static HRESULT WINAPI
2109 SetColorKeyEnum(IDirectDrawSurface7 *surface,
2110                 DDSURFACEDESC2 *desc,
2111                 void *context)
2112 {
2113     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, surface);
2114     struct SCKContext *ctx = context;
2115     HRESULT hr;
2116
2117     hr = IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2118                                      ctx->Flags,
2119                                      ctx->CKey);
2120     if(hr != DD_OK)
2121     {
2122         WARN("IWineD3DSurface_SetColorKey failed, hr = %08x\n", hr);
2123         ctx->ret = hr;
2124     }
2125
2126     IDirectDrawSurface7_EnumAttachedSurfaces(surface,
2127                                              context,
2128                                              SetColorKeyEnum);
2129     IDirectDrawSurface7_Release(surface);
2130     return DDENUMRET_OK;
2131 }
2132
2133 /*****************************************************************************
2134  * IDirectDrawSurface7::SetColorKey
2135  *
2136  * Sets the color keying options for the surface. Observations showed that
2137  * in case of complex surfaces the color key has to be assigned to all
2138  * sublevels.
2139  *
2140  * Params:
2141  *  Flags: DDCKEY_*
2142  *  CKey: The new color key
2143  *
2144  * Returns:
2145  *  DD_OK on success
2146  *  See IWineD3DSurface::SetColorKey for details
2147  *
2148  *****************************************************************************/
2149 static HRESULT WINAPI
2150 IDirectDrawSurfaceImpl_SetColorKey(IDirectDrawSurface7 *iface,
2151                                    DWORD Flags,
2152                                    DDCOLORKEY *CKey)
2153 {
2154     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2155     struct SCKContext ctx = { DD_OK, (WINEDDCOLORKEY *) CKey, Flags };
2156     TRACE("(%p)->(%x,%p)\n", This, Flags, CKey);
2157
2158     if (CKey)
2159     {
2160         switch (Flags & ~DDCKEY_COLORSPACE)
2161         {
2162         case DDCKEY_DESTBLT:
2163             This->surface_desc.ddckCKDestBlt = *CKey;
2164             This->surface_desc.dwFlags |= DDSD_CKDESTBLT;
2165             break;
2166
2167         case DDCKEY_DESTOVERLAY:
2168             This->surface_desc.u3.ddckCKDestOverlay = *CKey;
2169             This->surface_desc.dwFlags |= DDSD_CKDESTOVERLAY;
2170             break;
2171
2172         case DDCKEY_SRCOVERLAY:
2173             This->surface_desc.ddckCKSrcOverlay = *CKey;
2174             This->surface_desc.dwFlags |= DDSD_CKSRCOVERLAY;
2175             break;
2176
2177         case DDCKEY_SRCBLT:
2178             This->surface_desc.ddckCKSrcBlt = *CKey;
2179             This->surface_desc.dwFlags |= DDSD_CKSRCBLT;
2180             break;
2181
2182         default:
2183             return DDERR_INVALIDPARAMS;
2184         }
2185     }
2186     else
2187     {
2188         switch (Flags & ~DDCKEY_COLORSPACE)
2189         {
2190         case DDCKEY_DESTBLT:
2191             This->surface_desc.dwFlags &= ~DDSD_CKDESTBLT;
2192             break;
2193
2194         case DDCKEY_DESTOVERLAY:
2195             This->surface_desc.dwFlags &= ~DDSD_CKDESTOVERLAY;
2196             break;
2197
2198         case DDCKEY_SRCOVERLAY:
2199             This->surface_desc.dwFlags &= ~DDSD_CKSRCOVERLAY;
2200             break;
2201
2202         case DDCKEY_SRCBLT:
2203             This->surface_desc.dwFlags &= ~DDSD_CKSRCBLT;
2204             break;
2205
2206         default:
2207             return DDERR_INVALIDPARAMS;
2208         }
2209     }
2210     ctx.ret = IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2211                                           Flags,
2212                                           ctx.CKey);
2213     IDirectDrawSurface7_EnumAttachedSurfaces(iface,
2214                                              (void *) &ctx,
2215                                              SetColorKeyEnum);
2216     switch(ctx.ret)
2217     {
2218         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
2219         default:                            return ctx.ret;
2220     }
2221 }
2222
2223 /*****************************************************************************
2224  * IDirectDrawSurface7::SetPalette
2225  *
2226  * Assigns a DirectDrawPalette object to the surface
2227  *
2228  * Params:
2229  *  Pal: Interface to the palette to set
2230  *
2231  * Returns:
2232  *  DD_OK on success
2233  *
2234  *****************************************************************************/
2235 static HRESULT WINAPI
2236 IDirectDrawSurfaceImpl_SetPalette(IDirectDrawSurface7 *iface,
2237                                   IDirectDrawPalette *Pal)
2238 {
2239     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2240     IDirectDrawPalette *oldPal;
2241     IDirectDrawSurfaceImpl *surf;
2242     IDirectDrawPaletteImpl *PalImpl = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette, Pal);
2243     HRESULT hr;
2244     TRACE("(%p)->(%p)\n", This, Pal);
2245
2246     /* Find the old palette */
2247     hr = IDirectDrawSurface_GetPalette(iface, &oldPal);
2248     if(hr != DD_OK && hr != DDERR_NOPALETTEATTACHED) return hr;
2249     if(oldPal) IDirectDrawPalette_Release(oldPal);  /* For the GetPalette */
2250
2251     /* Set the new Palette */
2252     IWineD3DSurface_SetPalette(This->WineD3DSurface,
2253                                PalImpl ? PalImpl->wineD3DPalette : NULL);
2254     /* AddRef the Palette */
2255     if(Pal) IDirectDrawPalette_AddRef(Pal);
2256
2257     /* Release the old palette */
2258     if(oldPal) IDirectDrawPalette_Release(oldPal);
2259
2260     /* If this is a front buffer, also update the back buffers
2261      * TODO: How do things work for palettized cube textures?
2262      */
2263     if(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)
2264     {
2265         /* For primary surfaces the tree is just a list, so the simpler scheme fits too */
2266         DDSCAPS2 caps2 = { DDSCAPS_PRIMARYSURFACE, 0, 0, 0 };
2267
2268         surf = This;
2269         while(1)
2270         {
2271             IDirectDrawSurface7 *attach;
2272             HRESULT hr;
2273             hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(surf, IDirectDrawSurface7),
2274                                                         &caps2, &attach);
2275             if(hr != DD_OK)
2276             {
2277                 break;
2278             }
2279
2280             TRACE("Setting palette on %p\n", attach);
2281             IDirectDrawSurface7_SetPalette(attach,
2282                                            Pal);
2283             surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, attach);
2284             IDirectDrawSurface7_Release(attach);
2285         }
2286     }
2287
2288     return DD_OK;
2289 }
2290
2291 /*****************************************************************************
2292  * The VTable
2293  *****************************************************************************/
2294
2295 const IDirectDrawSurface7Vtbl IDirectDrawSurface7_Vtbl =
2296 {
2297     /*** IUnknown ***/
2298     IDirectDrawSurfaceImpl_QueryInterface,
2299     IDirectDrawSurfaceImpl_AddRef,
2300     IDirectDrawSurfaceImpl_Release,
2301     /*** IDirectDrawSurface ***/
2302     IDirectDrawSurfaceImpl_AddAttachedSurface,
2303     IDirectDrawSurfaceImpl_AddOverlayDirtyRect,
2304     IDirectDrawSurfaceImpl_Blt,
2305     IDirectDrawSurfaceImpl_BltBatch,
2306     IDirectDrawSurfaceImpl_BltFast,
2307     IDirectDrawSurfaceImpl_DeleteAttachedSurface,
2308     IDirectDrawSurfaceImpl_EnumAttachedSurfaces,
2309     IDirectDrawSurfaceImpl_EnumOverlayZOrders,
2310     IDirectDrawSurfaceImpl_Flip,
2311     IDirectDrawSurfaceImpl_GetAttachedSurface,
2312     IDirectDrawSurfaceImpl_GetBltStatus,
2313     IDirectDrawSurfaceImpl_GetCaps,
2314     IDirectDrawSurfaceImpl_GetClipper,
2315     IDirectDrawSurfaceImpl_GetColorKey,
2316     IDirectDrawSurfaceImpl_GetDC,
2317     IDirectDrawSurfaceImpl_GetFlipStatus,
2318     IDirectDrawSurfaceImpl_GetOverlayPosition,
2319     IDirectDrawSurfaceImpl_GetPalette,
2320     IDirectDrawSurfaceImpl_GetPixelFormat,
2321     IDirectDrawSurfaceImpl_GetSurfaceDesc,
2322     IDirectDrawSurfaceImpl_Initialize,
2323     IDirectDrawSurfaceImpl_IsLost,
2324     IDirectDrawSurfaceImpl_Lock,
2325     IDirectDrawSurfaceImpl_ReleaseDC,
2326     IDirectDrawSurfaceImpl_Restore,
2327     IDirectDrawSurfaceImpl_SetClipper,
2328     IDirectDrawSurfaceImpl_SetColorKey,
2329     IDirectDrawSurfaceImpl_SetOverlayPosition,
2330     IDirectDrawSurfaceImpl_SetPalette,
2331     IDirectDrawSurfaceImpl_Unlock,
2332     IDirectDrawSurfaceImpl_UpdateOverlay,
2333     IDirectDrawSurfaceImpl_UpdateOverlayDisplay,
2334     IDirectDrawSurfaceImpl_UpdateOverlayZOrder,
2335     /*** IDirectDrawSurface2 ***/
2336     IDirectDrawSurfaceImpl_GetDDInterface,
2337     IDirectDrawSurfaceImpl_PageLock,
2338     IDirectDrawSurfaceImpl_PageUnlock,
2339     /*** IDirectDrawSurface3 ***/
2340     IDirectDrawSurfaceImpl_SetSurfaceDesc,
2341     /*** IDirectDrawSurface4 ***/
2342     IDirectDrawSurfaceImpl_SetPrivateData,
2343     IDirectDrawSurfaceImpl_GetPrivateData,
2344     IDirectDrawSurfaceImpl_FreePrivateData,
2345     IDirectDrawSurfaceImpl_GetUniquenessValue,
2346     IDirectDrawSurfaceImpl_ChangeUniquenessValue,
2347     /*** IDirectDrawSurface7 ***/
2348     IDirectDrawSurfaceImpl_SetPriority,
2349     IDirectDrawSurfaceImpl_GetPriority,
2350     IDirectDrawSurfaceImpl_SetLOD,
2351     IDirectDrawSurfaceImpl_GetLOD
2352 };