wined3d: Implement more GLSL instructions and a little cleanup.
[wine] / dlls / ddraw / ddraw.c
1 /*
2  * Copyright 1997-2000 Marcus Meissner
3  * Copyright 1998-2000 Lionel Ulmer
4  * Copyright 2000-2001 TransGaming Technologies Inc.
5  * Copyright 2006 Stefan Dösinger
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #define COBJMACROS
31 #define NONAMELESSUNION
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winnls.h"
36 #include "winerror.h"
37 #include "wingdi.h"
38 #include "wine/exception.h"
39 #include "excpt.h"
40
41 #include "ddraw.h"
42 #include "d3d.h"
43
44 #include "ddraw_private.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
48
49 static BOOL IDirectDrawImpl_DDSD_Match(const DDSURFACEDESC2* requested, const DDSURFACEDESC2* provided);
50 static HRESULT WINAPI IDirectDrawImpl_AttachD3DDevice(IDirectDrawImpl *This, IDirectDrawSurfaceImpl *primary);
51 static HRESULT WINAPI IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This, DDSURFACEDESC2 *pDDSD, IDirectDrawSurfaceImpl **ppSurf, UINT level);
52
53 /* Device identifier. Don't relay it to WineD3D */
54 static const DDDEVICEIDENTIFIER2 deviceidentifier =
55 {
56     "display",
57     "DirectDraw HAL",
58     { { 0x00010001, 0x00010001 } },
59     0, 0, 0, 0,
60     /* a8373c10-7ac4-4deb-849a-009844d08b2d */
61     {0xa8373c10,0x7ac4,0x4deb, {0x84,0x9a,0x00,0x98,0x44,0xd0,0x8b,0x2d}},
62     0
63 };
64
65 /* This is for cleanup if a broken app doesn't Release its objects */
66 IDirectDrawImpl *ddraw_list;
67
68 /*****************************************************************************
69  * IUnknown Methods
70  *****************************************************************************/
71
72 /*****************************************************************************
73  * IDirectDraw7::QueryInterface
74  *
75  * Queries different interfaces of the DirectDraw object. It can return
76  * IDirectDraw interfaces in version 1, 2, 4 and 7, and IDirect3D interfaces
77  * in version 1, 2, 3 and 7. An IDirect3DDevice can be created with this
78  * method.
79  * The returned interface is AddRef()-ed before it's returned
80  *
81  * Rules for QueryInterface:
82  *  http://msdn.microsoft.com/library/default.asp? \
83  *    url=/library/en-us/com/html/6db17ed8-06e4-4bae-bc26-113176cc7e0e.asp
84  *
85  * Used for version 1, 2, 4 and 7
86  *
87  * Params:
88  *  refiid: Interface ID asked for
89  *  obj: Used to return the interface pointer
90  *
91  * Returns:
92  *  S_OK if an interface was found
93  *  E_NOINTERFACE if the requested interface wasn't found
94  *
95  *****************************************************************************/
96 static HRESULT WINAPI
97 IDirectDrawImpl_QueryInterface(IDirectDraw7 *iface,
98                                REFIID refiid,
99                                void **obj)
100 {
101     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
102
103     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(refiid), obj);
104
105     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
106     *obj = NULL;
107
108     if(!refiid)
109         return DDERR_INVALIDPARAMS;
110
111     /* Check DirectDraw Interfaces */
112     if ( IsEqualGUID( &IID_IUnknown, refiid ) ||
113          IsEqualGUID( &IID_IDirectDraw7, refiid ) )
114     {
115         *obj = ICOM_INTERFACE(This, IDirectDraw7);
116         TRACE("(%p) Returning IDirectDraw7 interface at %p\n", This, *obj);
117     }
118     else if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) )
119     {
120         *obj = ICOM_INTERFACE(This, IDirectDraw4);
121         TRACE("(%p) Returning IDirectDraw4 interface at %p\n", This, *obj);
122     }
123     else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) )
124     {
125         *obj = ICOM_INTERFACE(This, IDirectDraw2);
126         TRACE("(%p) Returning IDirectDraw2 interface at %p\n", This, *obj);
127     }
128     else if ( IsEqualGUID( &IID_IDirectDraw, refiid ) )
129     {
130         *obj = ICOM_INTERFACE(This, IDirectDraw);
131         TRACE("(%p) Returning IDirectDraw interface at %p\n", This, *obj);
132     }
133
134     /* Direct3D */
135     else if ( IsEqualGUID( &IID_IDirect3D  , refiid ) ||
136               IsEqualGUID( &IID_IDirect3D2 , refiid ) ||
137               IsEqualGUID( &IID_IDirect3D3 , refiid ) ||
138               IsEqualGUID( &IID_IDirect3D7 , refiid ) )
139     {
140         /* Check the surface implementation */
141         if(This->ImplType == SURFACE_UNKNOWN)
142         {
143             /* Apps may create the IDirect3D Interface before the primary surface.
144              * set the surface implementation */
145             This->ImplType = SURFACE_OPENGL;
146             TRACE("(%p) Choosing OpenGL surfaces because a Direct3D interface was requested\n", This);
147         }
148         else if(This->ImplType != SURFACE_OPENGL && DefaultSurfaceType == SURFACE_UNKNOWN)
149         {
150             ERR("(%p) The App is requesting a D3D device, but a non-OpenGL surface type was choosen. Prepare for trouble!\n", This);
151             ERR(" (%p) You may want to contact wine-devel for help\n", This);
152             /* Should I assert(0) here??? */
153         }
154         else if(This->ImplType != SURFACE_OPENGL)
155         {
156             WARN("The app requests a Direct3D interface, but non-opengl surfaces where set in winecfg\n");
157             /* Do not abort here, only reject 3D Device creation */
158         }
159
160         if ( IsEqualGUID( &IID_IDirect3D  , refiid ) )
161         {
162             This->d3dversion = 1;
163             *obj = ICOM_INTERFACE(This, IDirect3D);
164             TRACE(" returning Direct3D interface at %p.\n", *obj);
165         }
166         else if ( IsEqualGUID( &IID_IDirect3D2  , refiid ) )
167         {
168             This->d3dversion = 2;
169             *obj = ICOM_INTERFACE(This, IDirect3D2);
170             TRACE(" returning Direct3D2 interface at %p.\n", *obj);
171         }
172         else if ( IsEqualGUID( &IID_IDirect3D3  , refiid ) )
173         {
174             This->d3dversion = 3;
175             *obj = ICOM_INTERFACE(This, IDirect3D3);
176             TRACE(" returning Direct3D3 interface at %p.\n", *obj);
177         }
178         else if(IsEqualGUID( &IID_IDirect3D7  , refiid ))
179         {
180             This->d3dversion = 7;
181             *obj = ICOM_INTERFACE(This, IDirect3D7);
182             TRACE(" returning Direct3D7 interface at %p.\n", *obj);
183         }
184     }
185
186     /* Unknown interface */
187     else
188     {
189         ERR("(%p)->(%s, %p): No interface found", This, debugstr_guid(refiid), obj);
190         return E_NOINTERFACE;
191     }
192
193     IUnknown_AddRef( (IUnknown *) *obj );
194     return S_OK;
195 }
196
197 /*****************************************************************************
198  * IDirectDraw7::AddRef
199  *
200  * Increases the interfaces refcount. Used for version 1, 2, 4 and 7
201  *
202  * Returns: The new refcount
203  *****************************************************************************/
204 static ULONG WINAPI
205 IDirectDrawImpl_AddRef(IDirectDraw7 *iface)
206 {
207     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
208     ULONG ref = InterlockedIncrement(&This->ref);
209
210     TRACE("(%p) : incrementing from %lu.\n", This, ref -1);
211
212     return ref;
213 }
214
215 /*****************************************************************************
216  * IDirectDrawImpl_Destroy
217  *
218  * Destroys a ddraw object. This is to share code between normal Release
219  * and the dll unload cleanup code
220  *
221  * Params:
222  *  This: DirectDraw object to destroy
223  *
224  *****************************************************************************/
225 void
226 IDirectDrawImpl_Destroy(IDirectDrawImpl *This)
227 {
228         IDirectDrawImpl *prev;
229
230         TRACE("(%p)\n", This);
231
232         /* Destroy the device window if we created one */
233         if(This->devicewindow != 0)
234         {
235             TRACE(" (%p) Destroying the device window %p\n", This, This->devicewindow);
236             DestroyWindow(This->devicewindow);
237             This->devicewindow = 0;
238         }
239
240         /* Unregister the window class */
241         UnregisterClassA(This->classname, 0);
242
243         /* Unchain it from the ddraw list */
244         if(ddraw_list == This)
245         {
246             ddraw_list = This->next;
247             /* No need to search for a predecessor here */
248         }
249         else
250         {
251             for(prev = ddraw_list; prev; prev = prev->next)
252                 if(prev->next == This) break;
253
254             if(prev)
255                 prev->next = This->next;
256             else
257                 ERR("Didn't find the previous ddraw element in the list\n");
258         }
259
260         /* Release the attached WineD3D stuff */
261         IWineD3DDevice_Release(This->wineD3DDevice);
262         IWineD3D_Release(This->wineD3D);
263
264         /* Now free the object */
265         HeapFree(GetProcessHeap(), 0, This);
266 }
267 /*****************************************************************************
268  * IDirectDraw7::Release
269  *
270  * Decreases the refcount. If the refcount falls to 0, the object is destroyed
271  *
272  * Returns: The new refcount
273  *****************************************************************************/
274 static ULONG WINAPI
275 IDirectDrawImpl_Release(IDirectDraw7 *iface)
276 {
277     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
278     ULONG ref = InterlockedDecrement(&This->ref);
279
280     TRACE("(%p)->() decrementing from %lu.\n", This, ref +1);
281
282     if (ref == 0)
283     {
284         /* No need to restore the display mode - it's done by SetCooperativeLevel */
285
286         IDirectDraw7_SetCooperativeLevel(ICOM_INTERFACE(This, IDirectDraw7),
287                                          NULL,
288                                          DDSCL_NORMAL);
289
290         /* This is for the dll cleanup code in DllMain() */
291         if(!This->DoNotDestroy)
292             IDirectDrawImpl_Destroy(This);
293     }
294
295     return ref;
296 }
297
298 /*****************************************************************************
299  * IDirectDraw methods
300  *****************************************************************************/
301
302 /*****************************************************************************
303  * IDirectDrawImpl_SetupExclusiveWindow
304  *
305  * Helper function that modifies a HWND's Style and ExStyle for proper
306  * fullscreen use.
307  *
308  * Params:
309  *  This: Pointer to the DirectDraw implementation
310  *  HWND: Window to setup
311  *
312  *****************************************************************************/
313 static void
314 IDirectDrawImpl_SetupFullscreenWindow(IDirectDrawImpl *This,
315                                       HWND window)
316 {
317     LONG style, exStyle;
318     /* Don't do anything if an original style is stored.
319      * That shouldn't happen
320      */
321     TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
322     if( (This->style != 0) && (This->exStyle != 0) )
323     {
324         ERR("(%p) Want to change the window parameters of HWND %p, but \
325              another style is stored for restauration afterwards\n", This, window);
326     }
327
328     /* Get the parameters and save them */
329     style = GetWindowLongW(window, GWL_STYLE);
330     exStyle = GetWindowLongW(window, GWL_EXSTYLE);
331     This->style = style;
332     This->exStyle = exStyle;
333
334     /* Filter out window decorations */
335     style &= ~WS_CAPTION;
336     style &= ~WS_THICKFRAME;
337     exStyle &= ~WS_EX_WINDOWEDGE;
338     exStyle &= ~WS_EX_CLIENTEDGE;
339
340     /* Make sure the window is managed, otherwise we won't get keyboard input */
341     style |= WS_POPUP | WS_SYSMENU;
342
343     TRACE("Old style was %08lx,%08lx, setting to %08lx,%08lx\n",
344           This->style, This->exStyle, style, exStyle);
345
346     SetWindowLongW(window, GWL_STYLE, style);
347     SetWindowLongW(window, GWL_EXSTYLE, exStyle);
348
349     /* Inform the window about the update.
350      * TODO: Should I move it to 0/0 too?
351      */
352     SetWindowPos(window, 0 /* InsertAfter, ignored */,
353                  0, 0, 0, 0, /* Pos, Size, ignored */
354                  SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER);
355 }
356
357 /*****************************************************************************
358  * IDirectDrawImpl_RestoreWindow
359  *
360  * Helper function that restores a windows' properties when taking it out
361  * of fullscreen mode
362  *
363  * Params:
364  *  This: Pointer to the DirectDraw implementation
365  *  HWND: Window to setup
366  *
367  *****************************************************************************/
368 static void
369 IDirectDrawImpl_RestoreWindow(IDirectDrawImpl *This,
370                               HWND window)
371 {
372     if( (This->style == 0) && (This->exStyle == 0) )
373     {
374         /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
375          * switch, do nothing
376          */
377         return;
378     }
379     TRACE("(%p): Restoring window settings of window %p to %08lx, %08lx\n",
380           This, window, This->style, This->exStyle);
381
382     SetWindowLongW(window, GWL_STYLE, This->style);
383     SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
384
385     /* Delete the old values */
386     This->style = 0;
387     This->exStyle = 0;
388
389     /* Inform the window about the update */
390     SetWindowPos(window, 0 /* InsertAfter, ignored */,
391                  0, 0, 0, 0, /* Pos, Size, ignored */
392                  SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
393 }
394
395 /*****************************************************************************
396  * IDirectDraw7::SetCooperativeLevel
397  *
398  * Sets the cooperative level for the DirectDraw object, and the window
399  * assigned to it. The cooperative level determines the general behavior
400  * of the DirectDraw application
401  *
402  * Warning: This is quite tricky, as it's not really documented which
403  * cooperative levels can be combined with each other. If a game fails
404  * after this function, try to check the cooperative levels passed on
405  * Windows, and if it returns something different.
406  *
407  * If you think that this function caused the failure because it writes a
408  * fixme, be sure to run again with a +ddraw trace.
409  *
410  * What is known about cooperative levels (See the ddraw modes test):
411  * DDSCL_EXCLUSIVE and DDSCL_FULLSCREEN must be used with each other
412  * DDSCL_NORMAL is not compatible with DDSCL_EXCLUSIVE or DDSCL_FULLSCREEN
413  * DDSCL_SETFOCUSWINDOW can be passed only in DDSCL_NORMAL mode, but after that
414  * DDSCL_FULLSCREEN can be activated
415  * DDSCL_SETFOCUSWINDOW may only be used with DDSCL_NOWINDOWCHANGES
416  *
417  * Handled flags: DDSCL_NORMAL, DDSCL_FULLSCREEN, DDSCL_EXCLUSIVE,
418  *                DDSCL_SETFOCUSWINDOW (partially)
419  *
420  * Unhandled flags, which should be implemented
421  *  DDSCL_SETDEVICEWINDOW: Sets a window specially used for rendering (I don't
422  *  expect any difference to a normal window for wine)
423  *  DDSCL_CREATEDEVICEWINDOW: Tells ddraw to create its own window for
424  *  rendering (Possible test case: Half-life)
425  *
426  * Unsure about these: DDSCL_FPUSETUP DDSCL_FPURESERVE
427  *
428  * These seem not really imporant for wine
429  *  DDSCL_ALLOWREBOOT, DDSCL_NOWINDOWCHANGES, DDSCL_ALLOWMODEX,
430  *  DDSCL_MULTITHREDED
431  *
432  * Returns:
433  *  DD_OK if the cooperative level was set successfully
434  *  DDERR_INVALIDPARAMS if the passed cooperative level combination is invalid
435  *  DDERR_HWNDALREADYSET if DDSCL_SETFOCUSWINDOW is passed in exclusive mode
436  *   (Probably others too, have to investigate)
437  *
438  *****************************************************************************/
439 static HRESULT WINAPI
440 IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
441                                     HWND hwnd,
442                                     DWORD cooplevel)
443 {
444     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
445     HWND window;
446     HRESULT hr;
447
448     FIXME("(%p)->(%p,%08lx)\n",This,hwnd,cooplevel);
449     DDRAW_dump_cooperativelevel(cooplevel);
450
451     /* Get the old window */
452     hr = IWineD3DDevice_GetHWND(This->wineD3DDevice, &window);
453     if(hr != D3D_OK)
454     {
455         ERR("IWineD3DDevice::GetHWND failed, hr = %08lx\n", hr);
456         return hr;
457     }
458
459     /* Tests suggest that we need one of them: */
460     if(!(cooplevel & (DDSCL_SETFOCUSWINDOW |
461                       DDSCL_NORMAL         |
462                       DDSCL_EXCLUSIVE      )))
463     {
464         TRACE("Incorrect cooplevel flags, returning DDERR_INVALIDPARAMS\n");
465         return DDERR_INVALIDPARAMS;
466     }
467
468     /* Handle those levels first which set various hwnds */
469     if(cooplevel & DDSCL_SETFOCUSWINDOW)
470     {
471         /* This isn't compatible with a lot of flags */
472         if(cooplevel & ( DDSCL_MULTITHREADED   |
473                          DDSCL_FPUSETUP        |
474                          DDSCL_FPUPRESERVE     |
475                          DDSCL_ALLOWREBOOT     |
476                          DDSCL_ALLOWMODEX      |
477                          DDSCL_SETDEVICEWINDOW |
478                          DDSCL_NORMAL          |
479                          DDSCL_EXCLUSIVE       |
480                          DDSCL_FULLSCREEN      ) )
481         {
482             TRACE("Called with incompatible flags, returning DDERR_INVALIDPARAMS\n");
483             return DDERR_INVALIDPARAMS;
484         }
485         else if( (This->cooperative_level & DDSCL_FULLSCREEN) && window)
486         {
487             TRACE("Setting DDSCL_SETFOCUSWINDOW with an already set window, returning DDERR_HWNDALREADYSET\n");
488             return DDERR_HWNDALREADYSET;
489         }
490
491         This->focuswindow = hwnd;
492         /* Won't use the hwnd param for anything else */
493         hwnd = NULL;
494
495         /* Use the focus window for drawing too */
496         IWineD3DDevice_SetHWND(This->wineD3DDevice, This->focuswindow);
497
498         /* Destroy the device window, if we have one */
499         if(This->devicewindow)
500         {
501             DestroyWindow(This->devicewindow);
502             This->devicewindow = NULL;
503         }
504     }
505     /* DDSCL_NORMAL or DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE */
506     if(cooplevel & DDSCL_NORMAL)
507     {
508         /* Can't coexist with fullscreen or exclusive */
509         if(cooplevel & (DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE) )
510         {
511             TRACE("(%p) DDSCL_NORMAL is not compative with DDSCL_FULLSCREEN or DDSCL_EXCLUSIVE\n", This);
512             return DDERR_INVALIDPARAMS;
513         }
514
515         /* Switching from fullscreen? */
516         if(This->cooperative_level & DDSCL_FULLSCREEN)
517         {
518             /* Restore the display mode */
519             IDirectDraw7_RestoreDisplayMode(iface);
520
521             if(window)
522                 IDirectDrawImpl_RestoreWindow(This, window);
523
524             This->cooperative_level &= ~DDSCL_FULLSCREEN;
525             This->cooperative_level &= ~DDSCL_EXCLUSIVE;
526             This->cooperative_level &= ~DDSCL_ALLOWMODEX;
527         }
528
529         /* Don't override focus windows or private device windows */
530         if( hwnd &&
531             !(This->focuswindow) &&
532             !(This->devicewindow) &&
533             (hwnd != window) )
534         {
535             IWineD3DDevice_SetHWND(This->wineD3DDevice, hwnd);
536         }
537     }
538     else if(cooplevel & DDSCL_FULLSCREEN)
539     {
540         /* Needs DDSCL_EXCLUSIVE */
541         if(!(cooplevel & DDSCL_EXCLUSIVE) )
542         {
543             TRACE("(%p) DDSCL_FULLSCREEN needs DDSCL_EXCLUSIVE\n", This);
544             return DDERR_INVALIDPARAMS;
545         }
546         /* Need a HWND
547         if(hwnd == 0)
548         {
549             TRACE("(%p) DDSCL_FULLSCREEN needs a HWND\n", This);
550             return DDERR_INVALIDPARAMS;
551         }
552         */
553
554         /* Switch from normal to full screen mode? */
555         if(This->cooperative_level & DDSCL_NORMAL)
556         {
557             This->cooperative_level &= ~DDSCL_NORMAL;
558         }
559
560         /* Don't override focus windows or private device windows */
561         if( hwnd &&
562             !(This->focuswindow) &&
563             !(This->devicewindow) &&
564             (hwnd != window) )
565         {
566             /* On a window change, restore the old window and set the new one */
567             if(window != hwnd)
568             {
569                 if(window)
570                     IDirectDrawImpl_RestoreWindow(This, window);
571                 IDirectDrawImpl_SetupFullscreenWindow(This, hwnd);
572             }
573             IWineD3DDevice_SetHWND(This->wineD3DDevice, hwnd);
574         }
575     }
576     else if(cooplevel & DDSCL_EXCLUSIVE)
577     {
578         TRACE("(%p) DDSCL_EXCLUSIVE needs DDSCL_FULLSCREEN\n", This);
579         return DDERR_INVALIDPARAMS;
580     }
581
582     if(cooplevel & DDSCL_CREATEDEVICEWINDOW)
583     {
584         /* Don't create a device window if a focus window is set */
585         if( !(This->focuswindow) )
586         {
587             HWND devicewindow = CreateWindowExA(0, This->classname, "DDraw device window",
588                                                 WS_POPUP, 0, 0,
589                                                 GetSystemMetrics(SM_CXSCREEN),
590                                                 GetSystemMetrics(SM_CYSCREEN),
591                                                 NULL, NULL, GetModuleHandleA(0), NULL);
592
593             ShowWindow(devicewindow, SW_SHOW);   /* Just to be sure */
594             TRACE("(%p) Created a DDraw device window. HWND=%p\n", This, devicewindow);
595
596             IWineD3DDevice_SetHWND(This->wineD3DDevice, devicewindow);
597             This->devicewindow = devicewindow;
598         }
599     }
600
601     /* Unhandled flags */
602     if(cooplevel & DDSCL_ALLOWREBOOT)
603         WARN("(%p) Unhandled flag DDSCL_ALLOWREBOOT, harmless\n", This);
604     if(cooplevel & DDSCL_ALLOWMODEX)
605         WARN("(%p) Unhandled flag DDSCL_ALLOWMODEX, harmless\n", This);
606     if(cooplevel & DDSCL_MULTITHREADED)
607         FIXME("(%p) Unhandled flag DDSCL_MULTITHREADED, Uh Oh...\n", This);
608     if(cooplevel & DDSCL_FPUSETUP)
609         WARN("(%p) Unhandled flag DDSCL_FPUSETUP, harmless\n", This);
610     if(cooplevel & DDSCL_FPUPRESERVE)
611         WARN("(%p) Unhandled flag DDSCL_FPUPRESERVE, harmless\n", This);
612
613     /* Store the cooperative_level */
614     This->cooperative_level |= cooplevel;
615     TRACE("SetCooperativeLevel retuning DD_OK\n");
616     return DD_OK;
617 }
618
619 /*****************************************************************************
620  * IDirectDraw7::SetDisplayMode
621  *
622  * Sets the display screen resolution, color depth and refresh frequency
623  * when in fullscreen mode (in theory).
624  * Possible return values listed in the SDK suggest that this method fails
625  * when not in fullscreen mode, but this is wrong. Windows 2000 happily sets
626  * the display mode in DDSCL_NORMAL mode without an hwnd specified.
627  * It seems to be valid to pass 0 for With and Height, this has to be tested
628  * It could mean that the current video mode should be left as-is. (But why
629  * call it then?)
630  *
631  * Params:
632  *  Height, Width: Screen dimension
633  *  BPP: Color depth in Bits per pixel
634  *  Refreshrate: Screen refresh rate
635  *  Flags: Other stuff
636  *
637  * Returns
638  *  DD_OK on success
639  *
640  *****************************************************************************/
641 static HRESULT WINAPI
642 IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface,
643                                DWORD Width,
644                                DWORD Height,
645                                DWORD BPP,
646                                DWORD RefreshRate,
647                                DWORD Flags)
648 {
649     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
650     WINED3DDISPLAYMODE Mode;
651     TRACE("(%p)->(%ld,%ld,%ld,%ld,%lx: Relay!\n", This, Width, Height, BPP, RefreshRate, Flags);
652
653     if( !Width || !Height )
654     {
655         ERR("Width=%ld, Height=%ld, what to do?\n", Width, Height);
656         /* It looks like Need for Speed Porsche Unleashed expects DD_OK here */
657         return DD_OK;
658     }
659
660     /* Check the exclusive mode
661     if(!(This->cooperative_level & DDSCL_EXCLUSIVE))
662         return DDERR_NOEXCLUSIVEMODE;
663      * This is WRONG. Don't know if the SDK is completely
664      * wrong and if there are any conditions when DDERR_NOEXCLUSIVE
665      * is returned, but Half-Life 1.1.1.1 (Steam version)
666      * depends on this
667      */
668
669     Mode.Width = Width;
670     Mode.Height = Height;
671     Mode.RefreshRate = RefreshRate;
672     switch(BPP)
673     {
674         case 8:  Mode.Format = WINED3DFMT_P8;       break;
675         case 15: Mode.Format = WINED3DFMT_X1R5G5B5; break;
676         case 16: Mode.Format = WINED3DFMT_R5G6B5;   break;
677         case 24: Mode.Format = WINED3DFMT_R8G8B8;   break;
678         case 32: Mode.Format = WINED3DFMT_A8R8G8B8; break;
679     }
680
681     /* TODO: The possible return values from msdn suggest that
682      * the screen mode can't be changed if a surface is locked
683      * or some drawing is in progress
684      */
685
686     /* TODO: Lose the primary surface */
687     return IWineD3DDevice_SetDisplayMode(This->wineD3DDevice,
688                                          0, /* First swapchain */
689                                          &Mode);
690
691 }
692
693 /*****************************************************************************
694  * IDirectDraw7::RestoreDisplayMode
695  *
696  * Restores the display mode to what it was at creation time. Basically.
697  *
698  * A problem arises when there are 2 DirectDraw objects using the same hwnd:
699  *  -> DD_1 finds the screen at 1400x1050x32 when created, sets it to 640x480x16
700  *  -> DD_2 is created, finds the screen at 640x480x16, sets it to 1024x768x32
701  *  -> DD_1 is released. The screen should be left at 1024x768x32.
702  *  -> DD_2 is released. The screen should be set to 1400x1050x32
703  * This case is unhandled right now, but Empire Earth does it this way.
704  * (But perhaps there is something in SetCooperativeLevel to prevent this)
705  *
706  * The msdn says that this method resets the display mode to what it was before
707  * SetDisplayMode was called. What if SetDisplayModes is called 2 times??
708  *
709  * Returns
710  *  DD_OK on success
711  *  DDERR_NOEXCLUSIVE mode if the device isn't in fullscreen mode
712  *
713  *****************************************************************************/
714 static HRESULT WINAPI
715 IDirectDrawImpl_RestoreDisplayMode(IDirectDraw7 *iface)
716 {
717     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
718     TRACE("(%p)\n", This);
719
720     return IDirectDraw7_SetDisplayMode(ICOM_INTERFACE(This, IDirectDraw7),
721                                        This->orig_width,
722                                        This->orig_height,
723                                        This->orig_bpp,
724                                        0,
725                                        0);
726 }
727
728 /*****************************************************************************
729  * IDirectDraw7::GetCaps
730  *
731  * Returns the drives capabilities
732  *
733  * Used for version 1, 2, 4 and 7
734  *
735  * Params:
736  *  DriverCaps: Structure to write the Hardware accelerated caps to
737  *  HelCaps: Structure to write the emulation caps to
738  *
739  * Returns
740  *  This implementation returns DD_OK only
741  *
742  *****************************************************************************/
743 static HRESULT WINAPI
744 IDirectDrawImpl_GetCaps(IDirectDraw7 *iface,
745                         DDCAPS *DriverCaps,
746                         DDCAPS *HELCaps)
747 {
748     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
749     TRACE("(%p)->(%p,%p)\n", This, DriverCaps, HELCaps);
750
751     /* One structure must be != NULL */
752     if( (!DriverCaps) && (!HELCaps) )
753     {
754         ERR("(%p) Invalid params to IDirectDrawImpl_GetCaps\n", This);
755         return DDERR_INVALIDPARAMS;
756     }
757
758     if(DriverCaps)
759     {
760         DD_STRUCT_COPY_BYSIZE(DriverCaps, &This->caps);
761         if (TRACE_ON(ddraw))
762         {
763             TRACE("Driver Caps :\n");
764             DDRAW_dump_DDCAPS(DriverCaps);
765         }
766
767     }
768     if(HELCaps)
769     {
770         DD_STRUCT_COPY_BYSIZE(HELCaps, &This->caps);
771         if (TRACE_ON(ddraw))
772         {
773             TRACE("HEL Caps :\n");
774             DDRAW_dump_DDCAPS(HELCaps);
775         }
776     }
777
778     return DD_OK;
779 }
780
781 /*****************************************************************************
782  * IDirectDraw7::Compact
783  *
784  * No idea what it does, MSDN says it's not implemented.
785  *
786  * Returns
787  *  DD_OK, but this is unchecked
788  *
789  *****************************************************************************/
790 static HRESULT WINAPI
791 IDirectDrawImpl_Compact(IDirectDraw7 *iface)
792 {
793     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
794     TRACE("(%p)\n", This);
795
796     return DD_OK;
797 }
798
799 /*****************************************************************************
800  * IDirectDraw7::GetDisplayMode
801  *
802  * Returns information about the current display mode
803  *
804  * Exists in Version 1, 2, 4 and 7
805  *
806  * Params:
807  *  DDSD: Address of a surface description structure to write the info to
808  *
809  * Returns
810  *  DD_OK
811  *
812  *****************************************************************************/
813 static HRESULT WINAPI
814 IDirectDrawImpl_GetDisplayMode(IDirectDraw7 *iface,
815                                DDSURFACEDESC2 *DDSD)
816 {
817     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
818     HRESULT hr;
819     WINED3DDISPLAYMODE Mode;
820     DWORD Size;
821     TRACE("(%p)->(%p): Relay\n", This, DDSD);
822
823     /* This seems sane */
824     if(!DDSD) 
825     {
826         return DDERR_INVALIDPARAMS;
827     }
828
829     /* The necessary members of LPDDSURFACEDESC and LPDDSURFACEDESC2 are equal,
830      * so one method can be used for all versions (Hopefully)
831      */
832     hr = IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
833                                       0 /* swapchain 0 */,
834                                       &Mode);
835     if( hr != D3D_OK )
836     {
837         ERR(" (%p) IWineD3DDevice::GetDisplayMode returned %08lx\n", This, hr);
838         return hr;
839     }
840
841     Size = DDSD->dwSize;
842     memset(DDSD, 0, Size);
843
844     DDSD->dwSize = Size;
845     DDSD->dwFlags |= DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_REFRESHRATE;
846     DDSD->dwWidth = Mode.Width;
847     DDSD->dwHeight = Mode.Height; 
848     DDSD->u2.dwRefreshRate = 60;
849     DDSD->ddsCaps.dwCaps = 0;
850     DDSD->u4.ddpfPixelFormat.dwSize = sizeof(DDSD->u4.ddpfPixelFormat);
851     PixelFormat_WineD3DtoDD(&DDSD->u4.ddpfPixelFormat, Mode.Format);
852     DDSD->u1.lPitch = Mode.Width * DDSD->u4.ddpfPixelFormat.u1.dwRGBBitCount / 8;
853
854     if(TRACE_ON(ddraw))
855     {
856         TRACE("Returning surface desc :\n");
857         DDRAW_dump_surface_desc(DDSD);
858     }
859
860     return DD_OK;
861 }
862
863 /*****************************************************************************
864  * IDirectDraw7::GetFourCCCodes
865  *
866  * Returns an array of supported FourCC codes.
867  *
868  * Exists in Version 1, 2, 4 and 7
869  *
870  * Params:
871  *  NumCodes: Contains the number of Codes that Codes can carry. Returns the number
872  *            of enumerated codes
873  *  Codes: Pointer to an array of DWORDs where the supported codes are written
874  *         to
875  *
876  * Returns
877  *  Always returns DD_OK, as it's a stub for now
878  *
879  *****************************************************************************/
880 static HRESULT WINAPI
881 IDirectDrawImpl_GetFourCCCodes(IDirectDraw7 *iface,
882                                DWORD *NumCodes, DWORD *Codes)
883 {
884     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
885     FIXME("(%p)->(%p, %p): Stub!\n", This, NumCodes, Codes);
886
887     if(NumCodes) *NumCodes = 0;
888
889     return DD_OK;
890 }
891
892 /*****************************************************************************
893  * IDirectDraw7::GetMonitorFrequency
894  *
895  * Returns the monitor's frequency
896  *
897  * Exists in Version 1, 2, 4 and 7
898  *
899  * Params:
900  *  Freq: Pointer to a DWORD to write the frequency to
901  *
902  * Returns
903  *  Always returns DD_OK
904  *
905  *****************************************************************************/
906 static HRESULT WINAPI
907 IDirectDrawImpl_GetMonitorFrequency(IDirectDraw7 *iface,
908                                     DWORD *Freq)
909 {
910     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
911     TRACE("(%p)->(%p)\n", This, Freq);
912
913     /* Ideally this should be in WineD3D, as it concerns the screen setup,
914      * but for now this should make the games happy
915      */
916     *Freq = 60;
917     return DD_OK;
918 }
919
920 /*****************************************************************************
921  * IDirectDraw7::GetVerticalBlankStatus
922  *
923  * Returns the Vertical blank status of the monitor. This should be in WineD3D
924  * too basically, but as it's a semi stub, I didn't create a function there
925  *
926  * Params:
927  *  status: Pointer to a BOOL to be filled with the vertical blank status
928  *
929  * Returns
930  *  DD_OK on success
931  *  DDERR_INVALIDPARAMS if status is NULL
932  *
933  *****************************************************************************/
934 static HRESULT WINAPI
935 IDirectDrawImpl_GetVerticalBlankStatus(IDirectDraw7 *iface,
936                                        BOOL *status)
937 {
938     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
939     TRACE("(%p)->(%p)\n", This, status);
940
941     /* This looks sane, the MSDN suggests it too */
942     if(!status) return DDERR_INVALIDPARAMS;
943
944     *status = This->fake_vblank;
945     This->fake_vblank = !This->fake_vblank;
946     return DD_OK;
947 }
948
949 /*****************************************************************************
950  * IDirectDraw7::GetAvailableVidMem
951  *
952  * Returns the total and free video memory
953  *
954  * Params:
955  *  Caps: Specifies the memory type asked for
956  *  total: Pointer to a DWORD to be filled with the total memory
957  *  free: Pointer to a DWORD to be filled with the free memory
958  *
959  * Returns
960  *  DD_OK on success
961  *  DDERR_INVALIDPARAMS of free and total are NULL
962  *
963  *****************************************************************************/
964 static HRESULT WINAPI
965 IDirectDrawImpl_GetAvailableVidMem(IDirectDraw7 *iface, DDSCAPS2 *Caps, DWORD *total, DWORD *free)
966 {
967     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
968     TRACE("(%p)->(%p, %p, %p)\n", This, Caps, total, free);
969
970     if(TRACE_ON(ddraw))
971     {
972         TRACE("(%p) Asked for memory with description: ", This);
973         DDRAW_dump_DDSCAPS2(Caps);
974         TRACE("\n");
975     }
976
977     /* Todo: System memory vs local video memory vs non-local video memory
978      * The MSDN also mentions differences between texture memory and other
979      * resources, but that's not important
980      */
981
982     if( (!total) && (!free) ) return DDERR_INVALIDPARAMS;
983
984     if(total) *total = This->total_vidmem;
985     if(free) *free = IWineD3DDevice_GetAvailableTextureMem(This->wineD3DDevice);
986
987     return DD_OK;
988 }
989
990 /*****************************************************************************
991  * IDirectDraw7::Initialize
992  *
993  * Initializes a DirectDraw interface.
994  *
995  * Params:
996  *  GUID: Interface identifier. Well, don't know what this is really good
997  *   for
998  *
999  * Returns
1000  *  Returns DD_OK on the first call,
1001  *  DDERR_ALREADYINITIALIZED on repeated calls
1002  *
1003  *****************************************************************************/
1004 static HRESULT WINAPI
1005 IDirectDrawImpl_Initialize(IDirectDraw7 *iface,
1006                            GUID *Guid)
1007 {
1008     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1009     TRACE("(%p)->(%s): No-op\n", This, debugstr_guid(Guid));
1010
1011     if(This->initialized)
1012     {
1013         return DDERR_ALREADYINITIALIZED;
1014     }
1015     else
1016     {
1017         return DD_OK;
1018     }
1019 }
1020
1021 /*****************************************************************************
1022  * IDirectDraw7::FlipToGDISurface
1023  *
1024  * "Makes the surface that the GDI writes to the primary surface"
1025  * Looks like some windows specific thing we don't have to care about.
1026  * According to MSDN it permits GDI dialog boxes in FULLSCREEN mode. Good to
1027  * show error boxes ;)
1028  * Well, just return DD_OK.
1029  *
1030  * Returns:
1031  *  Always returns DD_OK
1032  *
1033  *****************************************************************************/
1034 static HRESULT WINAPI
1035 IDirectDrawImpl_FlipToGDISurface(IDirectDraw7 *iface)
1036 {
1037     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1038     TRACE("(%p)\n", This);
1039
1040     return DD_OK;
1041 }
1042
1043 /*****************************************************************************
1044  * IDirectDraw7::WaitForVerticalBlank
1045  *
1046  * This method allows applications to get in sync with the vertical blank
1047  * interval.
1048  * The wormhole demo in the DirectX 7 sdk uses this call, and it doesn't
1049  * redraw the screen, most likely because of this stub
1050  *
1051  * Parameters:
1052  *  Flags: one of DDWAITVB_BLOCKBEGIN, DDWAITVB_BLOCKBEGINEVENT
1053  *         or DDWAITVB_BLOCKEND
1054  *  h: Not used, according to MSDN
1055  *
1056  * Returns:
1057  *  Always returns DD_OK
1058  *
1059  *****************************************************************************/ 
1060 static HRESULT WINAPI
1061 IDirectDrawImpl_WaitForVerticalBlank(IDirectDraw7 *iface,
1062                                      DWORD Flags,
1063                                      HANDLE h)
1064 {
1065     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1066     FIXME("(%p)->(%lx,%p): Stub\n", This, Flags, h);
1067
1068     /* MSDN says DDWAITVB_BLOCKBEGINEVENT is not supported */
1069     if(Flags & DDWAITVB_BLOCKBEGINEVENT)
1070         return DDERR_UNSUPPORTED; /* unchecked */
1071
1072     return DD_OK;
1073 }
1074
1075 /*****************************************************************************
1076  * IDirectDraw7::GetScanLine
1077  *
1078  * Returns the scan line that is being drawn on the monitor
1079  *
1080  * Parameters:
1081  *  Scanline: Address to write the scan line value to
1082  *
1083  * Returns:
1084  *  Always returns DD_OK
1085  *
1086  *****************************************************************************/ 
1087 static HRESULT WINAPI IDirectDrawImpl_GetScanLine(IDirectDraw7 *iface, DWORD *Scanline)
1088 {
1089     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1090     static BOOL hide = FALSE;
1091     WINED3DDISPLAYMODE Mode;
1092
1093     /* This function is called often, so print the fixme only once */
1094     if(!hide)
1095     {
1096         FIXME("(%p)->(%p): Semi-Stub\n", This, Scanline);
1097         hide = TRUE;
1098     }
1099
1100     IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
1101                                   0,
1102                                   &Mode);
1103
1104     /* Fake the line sweeping of the monitor */
1105     /* FIXME: We should synchronize with a source to keep the refresh rate */ 
1106     *Scanline = This->cur_scanline++;
1107     /* Assume 20 scan lines in the vertical blank */
1108     if (This->cur_scanline >= Mode.Height + 20)
1109         This->cur_scanline = 0;
1110
1111     return DD_OK;
1112 }
1113
1114 /*****************************************************************************
1115  * IDirectDraw7::TestCooperativeLevel
1116  *
1117  * Informs the application about the state of the video adapter, depending
1118  * on the cooperative level
1119  *
1120  * Returns:
1121  *  DD_OK if the device is in a sane state
1122  *  DDERR_NOEXCLUSIVEMODE or DDERR_EXCLUSIVEMODEALREADYSET
1123  *  if the state is not correct(See below)
1124  *
1125  *****************************************************************************/ 
1126 static HRESULT WINAPI
1127 IDirectDrawImpl_TestCooperativeLevel(IDirectDraw7 *iface)
1128 {
1129     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1130     HRESULT hr;
1131     TRACE("(%p)\n", This);
1132
1133     /* Description from MSDN:
1134      * For fullscreen apps return DDERR_NOEXCLUSIVEMODE if the user switched
1135      * away from the app with e.g. alt-tab. Windowed apps receive 
1136      * DDERR_EXCLUSIVEMODEALREADYSET if another application created a 
1137      * DirectDraw object in exclusive mode. DDERR_WRONGMODE is returned,
1138      * when the video mode has changed
1139      */
1140
1141     hr =  IWineD3DDevice_TestCooperativeLevel(This->wineD3DDevice);
1142
1143     /* Fix the result value. These values are mapped from their
1144      * d3d9 counterpart.
1145      */
1146     switch(hr)
1147     {
1148         case WINED3DERR_DEVICELOST:
1149             if(This->cooperative_level & DDSCL_EXCLUSIVE)
1150             {
1151                 return DDERR_NOEXCLUSIVEMODE;
1152             }
1153             else
1154             {
1155                 return DDERR_EXCLUSIVEMODEALREADYSET;
1156             }
1157
1158         case WINED3DERR_DEVICENOTRESET:
1159             return DD_OK;
1160
1161         case WINED3D_OK:
1162             return DD_OK;
1163
1164         case WINED3DERR_DRIVERINTERNALERROR:
1165         default:
1166             ERR("(%p) Unexpected return value %08lx from wineD3D, " \
1167                 " returning DD_OK\n", This, hr);
1168     }
1169
1170     return DD_OK;
1171 }
1172
1173 /*****************************************************************************
1174  * IDirectDraw7::GetGDISurface
1175  *
1176  * Returns the surface that GDI is treating as the primary surface.
1177  * For Wine this is the front buffer
1178  *
1179  * Params:
1180  *  GDISurface: Address to write the surface pointer to
1181  *
1182  * Returns:
1183  *  DD_OK if the surface was found
1184  *  DDERR_NOTFOUND if the GDI surface wasn't found
1185  *
1186  *****************************************************************************/ 
1187 static HRESULT WINAPI
1188 IDirectDrawImpl_GetGDISurface(IDirectDraw7 *iface,
1189                               IDirectDrawSurface7 **GDISurface)
1190 {
1191     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1192     IWineD3DSurface *Surf;
1193     IDirectDrawSurface7 *ddsurf;
1194     HRESULT hr;
1195     DDSCAPS2 ddsCaps;
1196     TRACE("(%p)->(%p)\n", This, GDISurface);
1197
1198     /* Get the back buffer from the wineD3DDevice and search its
1199      * attached surfaces for the front buffer
1200      */
1201     hr = IWineD3DDevice_GetBackBuffer(This->wineD3DDevice,
1202                                       0, /* SwapChain */
1203                                       0, /* first back buffer*/
1204                                       WINED3DBACKBUFFER_TYPE_MONO,
1205                                       &Surf);
1206
1207     if( (hr != D3D_OK) ||
1208         (!Surf) )
1209     {
1210         ERR("IWineD3DDevice::GetBackBuffer failed\n");
1211         return DDERR_NOTFOUND;
1212     }
1213
1214     /* GetBackBuffer AddRef()ed the surface, release it */
1215     IWineD3DSurface_Release(Surf);
1216
1217     IWineD3DSurface_GetParent(Surf,
1218                               (IUnknown **) &ddsurf);
1219     IDirectDrawSurface7_Release(ddsurf);  /* For the GetParent */
1220
1221     /* Find the front buffer */
1222     ddsCaps.dwCaps = DDSCAPS_FRONTBUFFER;
1223     hr = IDirectDrawSurface7_GetAttachedSurface(ddsurf,
1224                                                 &ddsCaps,
1225                                                 GDISurface);
1226     if(hr != DD_OK)
1227     {
1228         ERR("IDirectDrawSurface7::GetAttachedSurface failed, hr = %lx\n", hr);
1229     }
1230
1231     /* The AddRef is OK this time */
1232     return hr;
1233 }
1234
1235 /*****************************************************************************
1236  * IDirectDrawImpl_EnumDisplayModesCB
1237  *
1238  * Callback function for IDirectDraw7::EnumDisplayModes. Translates
1239  * the wineD3D values to ddraw values and calls the application callback
1240  *
1241  * Params:
1242  *  device: The IDirectDraw7 interface to the current device
1243  *  With, Height, Pixelformat, Refresh: Enumerated display mode
1244  *  context: the context pointer passed to IWineD3DDevice::EnumDisplayModes
1245  *
1246  * Returns:
1247  *  The return value from the application callback
1248  *
1249  *****************************************************************************/ 
1250 static HRESULT WINAPI
1251 IDirectDrawImpl_EnumDisplayModesCB(IUnknown *pDevice,
1252                                    UINT Width,
1253                                    UINT Height,
1254                                    WINED3DFORMAT Pixelformat,
1255                                    FLOAT Refresh,
1256                                    void *context)
1257 {
1258     DDSURFACEDESC2 callback_sd;
1259     EnumDisplayModesCBS *cbs = (EnumDisplayModesCBS *) context;
1260
1261     memset(&callback_sd, 0, sizeof(callback_sd));
1262     callback_sd.dwSize = sizeof(callback_sd);
1263     callback_sd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1264
1265     callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_PITCH;
1266     if(Refresh > 0.0)
1267     {
1268         callback_sd.dwFlags |= DDSD_REFRESHRATE;
1269         callback_sd.u2.dwRefreshRate = 60.0;
1270     }
1271
1272     callback_sd.dwHeight = Height;
1273     callback_sd.dwWidth = Width;
1274
1275     PixelFormat_WineD3DtoDD(&callback_sd.u4.ddpfPixelFormat, Pixelformat);
1276     return cbs->callback(&callback_sd, cbs->context);
1277 }
1278
1279 /*****************************************************************************
1280  * IDirectDraw7::EnumDisplayModes
1281  *
1282  * Enumerates the supported Display modes. The modes can be filtered with
1283  * the DDSD parameter.
1284  *
1285  * Params:
1286  *  Flags: can be DDEDM_REFRESHRATES and DDEDM_STANDARDVGAMODES
1287  *  DDSD: Surface description to filter the modes
1288  *  Context: Pointer passed back to the callback function
1289  *  cb: Application-provided callback function
1290  *
1291  * Returns:
1292  *  DD_OK on success
1293  *  DDERR_INVALIDPARAMS if the callback wasn't set
1294  *
1295  *****************************************************************************/ 
1296 static HRESULT WINAPI
1297 IDirectDrawImpl_EnumDisplayModes(IDirectDraw7 *iface,
1298                                  DWORD Flags,
1299                                  DDSURFACEDESC2 *DDSD,
1300                                  void *Context,
1301                                  LPDDENUMMODESCALLBACK2 cb)
1302 {
1303     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1304     UINT Width = 0, Height = 0;
1305     WINED3DFORMAT pixelformat = WINED3DFMT_UNKNOWN;
1306     EnumDisplayModesCBS cbs;
1307
1308     TRACE("(%p)->(%p,%p,%p): Relay\n", This, DDSD, Context, cb);
1309
1310     /* This looks sane */
1311     if(!cb) return DDERR_INVALIDPARAMS;
1312
1313     /* The private callback structure */
1314     cbs.callback = cb;
1315     cbs.context = Context;
1316
1317     if(DDSD)
1318     {
1319         if (DDSD->dwFlags & DDSD_WIDTH)
1320             Width = DDSD->dwWidth;
1321         if (DDSD->dwFlags & DDSD_HEIGHT)
1322             Height = DDSD->dwHeight;
1323         if ((DDSD->dwFlags & DDSD_PIXELFORMAT) && (DDSD->u4.ddpfPixelFormat.dwFlags & DDPF_RGB) )
1324             pixelformat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
1325     }
1326
1327     return IWineD3DDevice_EnumDisplayModes(This->wineD3DDevice,
1328                                            Flags,
1329                                            Width, Height, pixelformat,
1330                                            &cbs,
1331                                            IDirectDrawImpl_EnumDisplayModesCB);
1332 }
1333
1334 /*****************************************************************************
1335  * IDirectDraw7::EvaluateMode
1336  *
1337  * Used with IDirectDraw7::StartModeTest to test video modes.
1338  * EvaluateMode is used to pass or fail a mode, and continue with the next
1339  * mode
1340  *
1341  * Params:
1342  *  Flags: DDEM_MODEPASSED or DDEM_MODEFAILED
1343  *  Timeout: Returns the amount of seconds left before the mode would have
1344  *           been failed automatically
1345  *
1346  * Returns:
1347  *  This implementation always DD_OK, because it's a stub
1348  *
1349  *****************************************************************************/
1350 static HRESULT WINAPI
1351 IDirectDrawImpl_EvaluateMode(IDirectDraw7 *iface,
1352                              DWORD Flags,
1353                              DWORD *Timeout)
1354 {
1355     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1356     FIXME("(%p)->(%ld,%p): Stub!\n", This, Flags, Timeout);
1357
1358     /* When implementing this, implement it in WineD3D */
1359
1360     return DD_OK;
1361 }
1362
1363 /*****************************************************************************
1364  * IDirectDraw7::GetDeviceIdentifier
1365  *
1366  * Returns the device identifier, which gives information about the driver
1367  * Our device identifier is defined at the beginning of this file.
1368  *
1369  * Params:
1370  *  DDDI: Address for the returned structure
1371  *  Flags: Can be DDGDI_GETHOSTIDENTIFIER
1372  *
1373  * Returns:
1374  *  On success it returns DD_OK
1375  *  DDERR_INVALIDPARAMS if DDDI is NULL
1376  *
1377  *****************************************************************************/
1378 static HRESULT WINAPI
1379 IDirectDrawImpl_GetDeviceIdentifier(IDirectDraw7 *iface,
1380                                     DDDEVICEIDENTIFIER2 *DDDI,
1381                                     DWORD Flags)
1382 {
1383     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1384     TRACE("(%p)->(%p,%08lx)\n", This, DDDI, Flags);
1385
1386     if(!DDDI)
1387         return DDERR_INVALIDPARAMS;
1388
1389     /* The DDGDI_GETHOSTIDENTIFIER returns the information about the 2D
1390      * host adapter, if there's a secondary 3D adapter. This doesn't apply
1391      * to any modern hardware, nor is it interesting for Wine, so ignore it
1392      */
1393
1394     *DDDI = deviceidentifier;
1395     return DD_OK;
1396 }
1397
1398 /*****************************************************************************
1399  * IDirectDraw7::GetSurfaceFromDC
1400  *
1401  * Returns the Surface for a GDI device context handle.
1402  * Is this related to IDirectDrawSurface::GetDC ???
1403  *
1404  * Params:
1405  *  hdc: hdc to return the surface for
1406  *  Surface: Address to write the surface pointer to
1407  *
1408  * Returns:
1409  *  Always returns DD_OK because it's a stub
1410  *
1411  *****************************************************************************/
1412 static HRESULT WINAPI
1413 IDirectDrawImpl_GetSurfaceFromDC(IDirectDraw7 *iface,
1414                                  HDC hdc,
1415                                  IDirectDrawSurface7 **Surface)
1416 {
1417     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1418     FIXME("(%p)->(%p,%p): Stub!\n", This, hdc, Surface);
1419
1420     /* Implementation idea if needed: Loop through all surfaces and compare
1421      * their hdc with hdc. Implement it in WineD3D! */
1422     return DDERR_NOTFOUND;
1423 }
1424
1425 /*****************************************************************************
1426  * IDirectDraw7::RestoreAllSurfaces
1427  *
1428  * Calls the restore method of all surfaces
1429  *
1430  * Params:
1431  *
1432  * Returns:
1433  *  Always returns DD_OK because it's a stub
1434  *
1435  *****************************************************************************/
1436 static HRESULT WINAPI
1437 IDirectDrawImpl_RestoreAllSurfaces(IDirectDraw7 *iface)
1438 {
1439     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1440     FIXME("(%p): Stub\n", This);
1441
1442     /* This isn't hard to implement: Enumerate all WineD3D surfaces,
1443      * get their parent and call their restore method. Do not implement
1444      * it in WineD3D, as restoring a surface means re-creating the
1445      * WineD3DDSurface
1446      */
1447     return DD_OK;
1448 }
1449
1450 /*****************************************************************************
1451  * IDirectDraw7::StartModeTest
1452  *
1453  * Tests the specified video modes to update the system registry with
1454  * refresh rate information. StartModeTest starts the mode test,
1455  * EvaluateMode is used to fail or pass a mode. If EvaluateMode
1456  * isn't called within 15 seconds, the mode is failed automatically
1457  *
1458  * As refresh rates are handled by the X server, I don't think this
1459  * Method is important
1460  *
1461  * Params:
1462  *  Modes: An array of mode specifications
1463  *  NumModes: The number of modes in Modes
1464  *  Flags: Some flags...
1465  *
1466  * Returns:
1467  *  Returns DDERR_TESTFINISHED if flags contains DDSMT_ISTESTREQUIRED,
1468  *  if no modes are passed, DDERR_INVALIDPARAMS is returned,
1469  *  otherwise DD_OK
1470  *
1471  *****************************************************************************/
1472 static HRESULT WINAPI
1473 IDirectDrawImpl_StartModeTest(IDirectDraw7 *iface,
1474                               SIZE *Modes,
1475                               DWORD NumModes,
1476                               DWORD Flags)
1477 {
1478     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1479     WARN("(%p)->(%p, %ld, %lx): Semi-Stub, most likely harmless\n", This, Modes, NumModes, Flags);
1480
1481     /* This looks sane */
1482     if( (!Modes) || (NumModes == 0) ) return DDERR_INVALIDPARAMS;
1483
1484     /* DDSMT_ISTESTREQUIRED asks if a mode test is necessary.
1485      * As it is not, DDERR_TESTFINISHED is returned
1486      * (hopefully that's correct
1487      *
1488     if(Flags & DDSMT_ISTESTREQUIRED) return DDERR_TESTFINISHED;
1489      * well, that value doesn't (yet) exist in the wine headers, so ignore it
1490      */
1491
1492     return DD_OK;
1493 }
1494
1495 /*****************************************************************************
1496  * IDirectDrawImpl_RecreateSurfacesCallback
1497  *
1498  * Enumeration callback for IDirectDrawImpl_RecreateAllSurfaces.
1499  * It re-recreates the WineD3DSurface. It's pretty straightforward
1500  *
1501  *****************************************************************************/
1502 HRESULT WINAPI
1503 IDirectDrawImpl_RecreateSurfacesCallback(IDirectDrawSurface7 *surf,
1504                                          DDSURFACEDESC2 *desc,
1505                                          void *Context)
1506 {
1507     IDirectDrawSurfaceImpl *surfImpl = ICOM_OBJECT(IDirectDrawSurfaceImpl,
1508                                                    IDirectDrawSurface7,
1509                                                    surf);
1510     IDirectDrawImpl *This = surfImpl->ddraw;
1511     IUnknown *Parent;
1512     IParentImpl *parImpl = NULL;
1513     IWineD3DSurface *wineD3DSurface;
1514     HRESULT hr;
1515     void *tmp;
1516
1517     WINED3DSURFACE_DESC     Desc;
1518     WINED3DFORMAT           Format;
1519     WINED3DRESOURCETYPE     Type;
1520     DWORD                   Usage;
1521     WINED3DPOOL             Pool;
1522     UINT                    Size;
1523
1524     WINED3DMULTISAMPLE_TYPE MultiSampleType;
1525     DWORD                   MultiSampleQuality;
1526     UINT                    Width;
1527     UINT                    Height;
1528
1529     TRACE("(%p): Enumerated Surface %p\n", This, surfImpl);
1530
1531     /* For the enumeration */
1532     IDirectDrawSurface7_Release(surf);
1533
1534     if(surfImpl->ImplType == This->ImplType) return DDENUMRET_OK; /* Continue */
1535
1536     /* Get the objects */
1537     wineD3DSurface = surfImpl->WineD3DSurface;
1538     IWineD3DSurface_GetParent(wineD3DSurface, &Parent);
1539     IUnknown_Release(Parent); /* For the getParent */
1540
1541     /* Is the parent an IParent interface? */
1542     if(IUnknown_QueryInterface(Parent, &IID_IParent, &tmp) == S_OK)
1543     {
1544         /* It is a IParent interface! */
1545         IUnknown_Release(Parent); /* For the QueryInterface */
1546         parImpl = ICOM_OBJECT(IParentImpl, IParent, Parent);
1547         /* Release the reference the parent interface is holding */
1548         IWineD3DSurface_Release(wineD3DSurface);
1549     }
1550
1551
1552     /* Get the surface properties */
1553     Desc.Format = &Format;
1554     Desc.Type = &Type;
1555     Desc.Usage = &Usage;
1556     Desc.Pool = &Pool;
1557     Desc.Size = &Size;
1558     Desc.MultiSampleType = &MultiSampleType;
1559     Desc.MultiSampleQuality = &MultiSampleQuality;
1560     Desc.Width = &Width;
1561     Desc.Height = &Height;
1562
1563     hr = IWineD3DSurface_GetDesc(wineD3DSurface, &Desc);
1564     if(hr != D3D_OK) return hr;
1565
1566     /* Create the new surface */
1567     hr = IWineD3DDevice_CreateSurface(This->wineD3DDevice,
1568                                       Width, Height, Format,
1569                                       TRUE /* Lockable */,
1570                                       FALSE /* Discard */,
1571                                       surfImpl->mipmap_level,
1572                                       &surfImpl->WineD3DSurface,
1573                                       Type,
1574                                       Usage,
1575                                       Pool,
1576                                       MultiSampleType,
1577                                       MultiSampleQuality,
1578                                       0 /* SharedHandle */,
1579                                       This->ImplType,
1580                                       Parent);
1581
1582     if(hr != D3D_OK)
1583         return hr;
1584
1585     /* Update the IParent if it exists */
1586     if(parImpl)
1587     {
1588         parImpl->child = (IUnknown *) surfImpl->WineD3DSurface;
1589         /* Add a reference for the IParent */
1590         IWineD3DSurface_AddRef(surfImpl->WineD3DSurface);
1591     }
1592     /* TODO: Copy the surface content, except for render targets */
1593
1594     if(IWineD3DSurface_Release(wineD3DSurface) == 0)
1595         TRACE("Surface released successful, next surface\n");
1596     else
1597         ERR("Something's still holding the old WineD3DSurface\n");
1598
1599     surfImpl->ImplType = This->ImplType;
1600
1601     return DDENUMRET_OK;
1602 }
1603
1604 /*****************************************************************************
1605  * IDirectDrawImpl_RecreateAllSurfaces
1606  *
1607  * A function, that converts all wineD3DSurfaces to the new implementation type
1608  * It enumerates all surfaces with IWineD3DDevice::EnumSurfaces, creates a
1609  * new WineD3DSurface, copies the content and releases the old surface
1610  *
1611  *****************************************************************************/
1612 static HRESULT
1613 IDirectDrawImpl_RecreateAllSurfaces(IDirectDrawImpl *This)
1614 {
1615     DDSURFACEDESC2 desc;
1616     TRACE("(%p): Switch to implementation %d\n", This, This->ImplType);
1617
1618     if(This->ImplType != SURFACE_OPENGL && This->d3d_initialized)
1619     {
1620         /* Should happen almost never */
1621         FIXME("(%p) Switching to non-opengl surfaces with d3d started. Is this a bug?\n", This);
1622         /* Shutdown d3d */
1623         IWineD3DDevice_Uninit3D(This->wineD3DDevice);
1624     }
1625     /* Contrary: D3D starting is handled by the caller, because it knows the render target */
1626
1627     memset(&desc, 0, sizeof(desc));
1628     desc.dwSize = sizeof(desc);
1629
1630     return IDirectDraw7_EnumSurfaces(ICOM_INTERFACE(This, IDirectDraw7),
1631                                      0,
1632                                      &desc,
1633                                      This,
1634                                      IDirectDrawImpl_RecreateSurfacesCallback);
1635 }
1636
1637 /*****************************************************************************
1638  * D3D7CB_CreateSurface
1639  *
1640  * Callback function for IDirect3DDevice_CreateTexture. It searches for the
1641  * correct mipmap sublevel, and returns it to WineD3D.
1642  * The surfaces are created already by IDirectDraw7::CreateSurface
1643  *
1644  * Params:
1645  *  With, Height: With and height of the surface
1646  *  Format: The requested format
1647  *  Usage, Pool: D3DUSAGE and D3DPOOL of the surface
1648  *  level: The mipmap level
1649  *  Surface: Pointer to pass the created surface back at
1650  *  SharedHandle: NULL
1651  *
1652  * Returns:
1653  *  D3D_OK
1654  *
1655  *****************************************************************************/
1656 static HRESULT WINAPI
1657 D3D7CB_CreateSurface(IUnknown *device,
1658                      UINT Width, UINT Height,
1659                      WINED3DFORMAT Format,
1660                      DWORD Usage, WINED3DPOOL Pool, UINT level,
1661                      IWineD3DSurface **Surface,
1662                      HANDLE *SharedHandle)
1663 {
1664     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, device);
1665     IDirectDrawSurfaceImpl *surf = This->tex_root;
1666     int i;
1667     TRACE("(%p) call back. surf=%p\n", device, surf);
1668
1669     /* Find the wanted mipmap. There are enough mipmaps in the chain */
1670     for(i = 0; i < level; i++)
1671         surf = surf->next_complex;
1672
1673     /* Return the surface */
1674     *Surface = surf->WineD3DSurface;
1675
1676     TRACE("Returning wineD3DSurface %p, it belongs to surface %p\n", *Surface, surf);
1677     return D3D_OK;
1678 }
1679
1680 /*****************************************************************************
1681  * IDirectDrawImpl_CreateNewSurface
1682  *
1683  * A helper function for IDirectDraw7::CreateSurface. It creates a new surface
1684  * with the passed parameters.
1685  *
1686  * Params:
1687  *  DDSD: Description of the surface to create
1688  *  Surf: Address to store the interface pointer at
1689  *
1690  * Returns:
1691  *  DD_OK on success
1692  *
1693  *****************************************************************************/
1694 static HRESULT WINAPI
1695 IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This,
1696                                  DDSURFACEDESC2 *pDDSD,
1697                                  IDirectDrawSurfaceImpl **ppSurf,
1698                                  UINT level)
1699 {
1700     HRESULT hr;
1701     UINT Width = 0, Height = 0;
1702     WINED3DFORMAT Format = WINED3DFMT_UNKNOWN;
1703     WINED3DRESOURCETYPE ResType = WINED3DRTYPE_SURFACE;
1704     DWORD Usage = 0;
1705     WINED3DSURFTYPE ImplType = This->ImplType;
1706     WINED3DSURFACE_DESC Desc;
1707     IUnknown *Parent;
1708     IParentImpl *parImpl = NULL;
1709     WINED3DPOOL Pool = WINED3DPOOL_DEFAULT;
1710
1711     /* Dummies for GetDesc */
1712     WINED3DPOOL dummy_d3dpool;
1713     WINED3DMULTISAMPLE_TYPE dummy_mst;
1714     UINT dummy_uint;
1715     DWORD dummy_dword;
1716
1717     if (TRACE_ON(ddraw))
1718     {
1719         TRACE(" (%p) Requesting surface desc :\n", This);
1720         DDRAW_dump_surface_desc(pDDSD);
1721     }
1722
1723     /* Select the surface type, if it wasn't choosen yet */
1724     if(ImplType == SURFACE_UNKNOWN)
1725     {
1726         /* Use GL Surfaces if a D3DDEVICE Surface is requested */
1727         if(pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
1728         {
1729             TRACE("(%p) Choosing GL surfaces because a 3DDEVICE Surface was requested\n", This);
1730             ImplType = SURFACE_OPENGL;
1731         }
1732
1733         /* Otherwise use GDI surfaces for now */
1734         else
1735         {
1736             TRACE("(%p) Choosing GDI surfaces for 2D rendering\n", This);
1737             ImplType = SURFACE_GDI;
1738         }
1739
1740         /* Policy if all surface implementations are available:
1741          * First, check if a default type was set with winecfg. If not,
1742          * try Xrender surfaces, and use them if they work. Next, check if
1743          * accelerated OpenGL is available, and use GL surfaces in this
1744          * case. If all else fails, use GDI surfaces. If a 3DDEVICE surface
1745          * was created, always use OpenGL surfaces.
1746          *
1747          * (Note: Xrender surfaces are not implemented for now, the
1748          * unaccelerated implementation uses GDI to render in Software)
1749          */
1750
1751         /* Store the type. If it needs to be changed, all WineD3DSurfaces have to
1752          * be re-created. This could be done with IDirectDrawSurface7::Restore
1753          */
1754         This->ImplType = ImplType;
1755     }
1756     else
1757     {
1758          if((pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE ) && 
1759             (This->ImplType != SURFACE_OPENGL ) && DefaultSurfaceType == SURFACE_UNKNOWN)
1760         {
1761             /* We have to change to OpenGL,
1762              * and re-create all WineD3DSurfaces
1763              */
1764             ImplType = SURFACE_OPENGL;
1765             This->ImplType = ImplType;
1766             TRACE("(%p) Re-creating all surfaces\n", This);
1767             IDirectDrawImpl_RecreateAllSurfaces(This);
1768             TRACE("(%p) Done recreating all surfaces\n", This);
1769         }
1770         else if(This->ImplType != SURFACE_OPENGL)
1771         {
1772             WARN("The application requests a 3D capable surface, but a non-opengl surface was set in the registry\n");
1773             /* Do not fail surface creation, only fail 3D device creation */
1774         }
1775     }
1776
1777     /* Get the surface parameters */
1778     if ( pDDSD->dwFlags & DDSD_LPSURFACE)
1779     {
1780         ERR("(%p) Using a passed surface pointer is not yet supported\n", This);
1781         assert(0);
1782     }
1783
1784     /* Get the correct wined3d usage */
1785     if (pDDSD->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE |
1786                                  DDSCAPS_BACKBUFFER     |
1787                                  DDSCAPS_3DDEVICE       ) )
1788     {
1789         Usage |= WINED3DUSAGE_RENDERTARGET;
1790
1791         pDDSD->ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY |
1792                                  DDSCAPS_VISIBLE     |
1793                                  DDSCAPS_LOCALVIDMEM;
1794     }
1795     if(This->depthstencil)
1796     {
1797         /* The depth stencil creation callback sets this flag.
1798          * Set the WineD3D usage to let it know that it's a depth
1799          * Stencil surface.
1800          */
1801         Usage |= WINED3DUSAGE_DEPTHSTENCIL;
1802     }
1803     if(pDDSD->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
1804     {
1805         Pool = WINED3DPOOL_SYSTEMMEM;
1806     }
1807
1808     Format = PixelFormat_DD2WineD3D(&pDDSD->u4.ddpfPixelFormat);
1809     if(Format == WINED3DFMT_UNKNOWN)
1810     {
1811         ERR("Unsupported / Unknown pixelformat\n");
1812         return DDERR_INVALIDPIXELFORMAT;
1813     }
1814
1815     /* Create the Surface object */
1816     *ppSurf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectDrawSurfaceImpl));
1817     if(!*ppSurf)
1818     {
1819         ERR("(%p) Error allocating memory for a surface\n", This);
1820         return DDERR_OUTOFVIDEOMEMORY;
1821     }
1822     ICOM_INIT_INTERFACE(*ppSurf, IDirectDrawSurface7, IDirectDrawSurface7_Vtbl);
1823     ICOM_INIT_INTERFACE(*ppSurf, IDirectDrawSurface3, IDirectDrawSurface3_Vtbl);
1824     ICOM_INIT_INTERFACE(*ppSurf, IDirectDrawGammaControl, IDirectDrawGammaControl_Vtbl);
1825     ICOM_INIT_INTERFACE(*ppSurf, IDirect3DTexture2, IDirect3DTexture2_Vtbl);
1826     ICOM_INIT_INTERFACE(*ppSurf, IDirect3DTexture, IDirect3DTexture1_Vtbl);
1827     (*ppSurf)->ref = 1;
1828     (*ppSurf)->version = 7;
1829     (*ppSurf)->ddraw = This;
1830     (*ppSurf)->surface_desc.dwSize = sizeof(DDSURFACEDESC2);
1831     (*ppSurf)->surface_desc.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1832     DD_STRUCT_COPY_BYSIZE(&(*ppSurf)->surface_desc, pDDSD);
1833
1834     /* Surface attachments */
1835     (*ppSurf)->next_attached = NULL;
1836     (*ppSurf)->first_attached = *ppSurf;
1837
1838     (*ppSurf)->next_complex = NULL;
1839     (*ppSurf)->first_complex = *ppSurf;
1840
1841     /* Needed to re-create the surface on an implementation change */
1842     (*ppSurf)->ImplType = ImplType;
1843
1844     /* For D3DDevice creation */
1845     (*ppSurf)->isRenderTarget = FALSE;
1846
1847     /* A trace message for debugging */
1848     TRACE("(%p) Created IDirectDrawSurface implementation structure at %p\n", This, *ppSurf);
1849
1850     if(pDDSD->ddsCaps.dwCaps & ( DDSCAPS_PRIMARYSURFACE | DDSCAPS_TEXTURE | DDSCAPS_3DDEVICE) )
1851     {
1852         /* Render targets and textures need a IParent interface,
1853          * because WineD3D will destroy them when the swapchain
1854          * is released
1855          */
1856         parImpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IParentImpl));
1857         if(!parImpl)
1858         {
1859             ERR("Out of memory when allocating memory for a IParent implementation\n");
1860             return DDERR_OUTOFMEMORY;
1861         }
1862         parImpl->ref = 1;
1863         ICOM_INIT_INTERFACE(parImpl, IParent, IParent_Vtbl);
1864         Parent = (IUnknown *) ICOM_INTERFACE(parImpl, IParent);
1865         TRACE("Using IParent interface %p as parent\n", parImpl);
1866     }
1867     else
1868     {
1869         /* Use the surface as parent */
1870         Parent = (IUnknown *) ICOM_INTERFACE(*ppSurf, IDirectDrawSurface7);
1871         TRACE("Using Surface interface %p as parent\n", *ppSurf);
1872     }
1873
1874     /* Now create the WineD3D Surface */
1875     hr = IWineD3DDevice_CreateSurface(This->wineD3DDevice,
1876                                       pDDSD->dwWidth,
1877                                       pDDSD->dwHeight,
1878                                       Format,
1879                                       TRUE /* Lockable */,
1880                                       FALSE /* Discard */,
1881                                       level,
1882                                       &(*ppSurf)->WineD3DSurface,
1883                                       ResType, Usage,
1884                                       Pool,
1885                                       WINED3DMULTISAMPLE_NONE,
1886                                       0 /* MultiSampleQuality */,
1887                                       0 /* SharedHandle */,
1888                                       ImplType,
1889                                       Parent);
1890
1891     if(hr != D3D_OK)
1892     {
1893         ERR("IWineD3DDevice::CreateSurface failed. hr = %08lx\n", hr);
1894         return hr;
1895     }
1896
1897     /* Set the child of the parent implementation if it exists */
1898     if(parImpl)
1899     {
1900         parImpl->child = (IUnknown *) (*ppSurf)->WineD3DSurface;
1901         /* The IParent releases the WineD3DSurface, and
1902          * the ddraw surface does that too. Hold a reference
1903          */
1904         IWineD3DSurface_AddRef((*ppSurf)->WineD3DSurface);
1905     }
1906
1907     /* Increase the surface counter, and attach the surface */
1908     InterlockedIncrement(&This->surfaces);
1909     if(This->surface_list)
1910     {
1911         This->surface_list->prev = *ppSurf;
1912     }
1913     (*ppSurf)->next = This->surface_list;
1914     This->surface_list = *ppSurf;
1915
1916     /* Here we could store all created surfaces in the DirectDrawImpl structure,
1917      * But this could also be delegated to WineDDraw, as it keeps track of all its
1918      * resources. Not implemented for now, as there are more important things ;)
1919      */
1920
1921     /* Get the pixel format of the WineD3DSurface and store it.
1922      * Don't use the Format choosen above, WineD3D might have
1923      * changed it
1924      */
1925     Desc.Format = &Format;
1926     Desc.Type = &ResType;
1927     Desc.Usage = &Usage;
1928     Desc.Pool = &dummy_d3dpool;
1929     Desc.Size = &dummy_uint;
1930     Desc.MultiSampleType = &dummy_mst;
1931     Desc.MultiSampleQuality = &dummy_dword;
1932     Desc.Width = &Width;
1933     Desc.Height = &Height;
1934
1935     (*ppSurf)->surface_desc.dwFlags |= DDSD_PIXELFORMAT;
1936     hr = IWineD3DSurface_GetDesc((*ppSurf)->WineD3DSurface, &Desc);
1937     if(hr != D3D_OK)
1938     {
1939         ERR("IWineD3DSurface::GetDesc failed\n");
1940         IDirectDrawSurface7_Release( (IDirectDrawSurface7 *) *ppSurf);
1941         return hr;
1942     }
1943
1944     if(Format == WINED3DFMT_UNKNOWN)
1945     {
1946         FIXME("IWineD3DSurface::GetDesc returned WINED3DFMT_UNKNOWN\n");
1947     }
1948     PixelFormat_WineD3DtoDD( &(*ppSurf)->surface_desc.u4.ddpfPixelFormat, Format);
1949
1950     /* Anno 1602 stores the pitch right after surface creation, so make sure it's there.
1951      * I can't LockRect() the surface here because if OpenGL surfaces are in use, the
1952      * WineD3DDevice might not be useable for 3D yet, so an extra method was created
1953      */
1954     (*ppSurf)->surface_desc.dwFlags |= DDSD_PITCH;
1955     (*ppSurf)->surface_desc.u1.lPitch = IWineD3DSurface_GetPitch((*ppSurf)->WineD3DSurface);
1956
1957     /* Application passed a color key? Set it! */
1958     if(pDDSD->dwFlags & DDSD_CKDESTOVERLAY)
1959     {
1960         IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
1961                                     DDCKEY_DESTOVERLAY,
1962                                     &pDDSD->u3.ddckCKDestOverlay);
1963     }
1964     if(pDDSD->dwFlags & DDSD_CKDESTBLT)
1965     {
1966         IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
1967                                     DDCKEY_DESTBLT,
1968                                     &pDDSD->ddckCKDestBlt);
1969     }
1970     if(pDDSD->dwFlags & DDSD_CKSRCOVERLAY)
1971     {
1972         IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
1973                                     DDCKEY_SRCOVERLAY,
1974                                     &pDDSD->ddckCKSrcOverlay);
1975     }
1976     if(pDDSD->dwFlags & DDSD_CKSRCBLT)
1977     {
1978         IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
1979                                     DDCKEY_SRCBLT,
1980                                     &pDDSD->ddckCKSrcBlt);
1981     }
1982
1983     return DD_OK;
1984 }
1985
1986 /*****************************************************************************
1987  * IDirectDraw7::CreateSurface
1988  *
1989  * Creates a new IDirectDrawSurface object and returns its interface.
1990  *
1991  * The surface connections with wined3d are a bit tricky. Basically it works
1992  * like this:
1993  *
1994  * |------------------------|               |-----------------|
1995  * | DDraw surface          |               | WineD3DSurface  |
1996  * |                        |               |                 |
1997  * |        WineD3DSurface  |-------------->|                 |
1998  * |        Child           |<------------->| Parent          |
1999  * |------------------------|               |-----------------|
2000  *
2001  * The DDraw surface is the parent of the wined3d surface, and it releases
2002  * the WineD3DSurface when the ddraw surface is destroyed.
2003  *
2004  * However, for all surfaces which can be in a container in WineD3D,
2005  * we have to do this. These surfaces are ususally complex surfaces,
2006  * so this concerns primary surfaces with a front and a back buffer,
2007  * and textures.
2008  *
2009  * |------------------------|               |-----------------|
2010  * | DDraw surface          |               | Containter      |
2011  * |                        |               |                 |
2012  * |                  Child |<------------->| Parent          |
2013  * |                Texture |<------------->|                 |
2014  * |         WineD3DSurface |<----|         |          Levels |<--|
2015  * | Complex connection     |     |         |                 |   |
2016  * |------------------------|     |         |-----------------|   |
2017  *  ^                             |                               |
2018  *  |                             |                               |
2019  *  |                             |                               |
2020  *  |    |------------------|     |         |-----------------|   |
2021  *  |    | IParent          |     |-------->| WineD3DSurface  |   |
2022  *  |    |                  |               |                 |   |
2023  *  |    |            Child |<------------->| Parent          |   |
2024  *  |    |                  |               |       Container |<--|
2025  *  |    |------------------|               |-----------------|   |
2026  *  |                                                             |
2027  *  |   |----------------------|                                  |
2028  *  |   | DDraw surface 2      |                                  |
2029  *  |   |                      |                                  |
2030  *  |<->| Complex root   Child |                                  |
2031  *  |   |              Texture |                                  |
2032  *  |   |       WineD3DSurface |<----|                            |
2033  *  |   |----------------------|     |                            |
2034  *  |                                |                            |
2035  *  |    |---------------------|     |      |-----------------|   |
2036  *  |    | IParent             |     |----->| WineD3DSurface  |   |
2037  *  |    |                     |            |                 |   |
2038  *  |    |               Child |<---------->| Parent          |   |
2039  *  |    |---------------------|            |       Container |<--|
2040  *  |                                       |-----------------|   |
2041  *  |                                                             |
2042  *  |             ---More surfaces can follow---                  |
2043  *
2044  * The reason is that the IWineD3DSwapchain(render target container)
2045  * and the IWineD3DTexure(Texture container) release the parents
2046  * of their surface's children, but by releasing the complex root
2047  * the surfaces which are complexly attached to it are destroyed
2048  * too. See IDirectDrawSurface::Release for a more detailed
2049  * explanation.
2050  *
2051  * Params:
2052  *  DDSD: Description of the surface to create
2053  *  Surf: Address to store the interface pointer at
2054  *  UnkOuter: Basically for aggregation support, but ddraw doesn't support
2055  *            aggregation, so it has to be NULL
2056  *
2057  * Returns:
2058  *  DD_OK on success
2059  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
2060  *  DDERR_* if an error occurs
2061  *
2062  *****************************************************************************/
2063 static HRESULT WINAPI
2064 IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
2065                               DDSURFACEDESC2 *DDSD,
2066                               IDirectDrawSurface7 **Surf,
2067                               IUnknown *UnkOuter)
2068 {
2069     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
2070     IDirectDrawSurfaceImpl *object = NULL;
2071     HRESULT hr;
2072     LONG extra_surfaces = 0, i;
2073     DDSURFACEDESC2 desc2;
2074     UINT level = 0;
2075     WINED3DDISPLAYMODE Mode;
2076
2077     TRACE("(%p)->(%p,%p,%p)\n", This, DDSD, Surf, UnkOuter);
2078
2079     /* Some checks before we start */
2080     if (TRACE_ON(ddraw))
2081     {
2082         TRACE(" (%p) Requesting surface desc :\n", This);
2083         DDRAW_dump_surface_desc(DDSD);
2084     }
2085
2086     if (UnkOuter != NULL)
2087     {
2088         FIXME("(%p) : outer != NULL?\n", This);
2089         return CLASS_E_NOAGGREGATION; /* unchecked */
2090     }
2091
2092     if (!(DDSD->dwFlags & DDSD_CAPS))
2093     {
2094         /* DVIDEO.DLL does forget the DDSD_CAPS flag ... *sigh* */
2095         DDSD->dwFlags |= DDSD_CAPS;
2096     }
2097     if (DDSD->ddsCaps.dwCaps == 0)
2098     {
2099         /* This has been checked on real Windows */
2100         DDSD->ddsCaps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
2101     }
2102
2103     if (DDSD->ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD)
2104     {
2105         /* If the surface is of the 'alloconload' type, ignore the LPSURFACE field */
2106         DDSD->dwFlags &= ~DDSD_LPSURFACE;
2107     }
2108
2109     if ((DDSD->dwFlags & DDSD_LPSURFACE) && (DDSD->lpSurface == NULL))
2110     {
2111         /* Frank Herbert's Dune specifies a null pointer for the surface, ignore the LPSURFACE field */
2112         WARN("(%p) Null surface pointer specified, ignore it!\n", This);
2113         DDSD->dwFlags &= ~DDSD_LPSURFACE;
2114     }
2115
2116     if (Surf == NULL)
2117     {
2118         FIXME("(%p) You want to get back a surface? Don't give NULL ptrs!\n", This);
2119         return E_POINTER; /* unchecked */
2120     }
2121
2122     /* Modify some flags */
2123     memset(&desc2, 0, sizeof(desc2));
2124     desc2.dwSize = sizeof(desc2);   /* For the struct copy */
2125     DD_STRUCT_COPY_BYSIZE(&desc2, DDSD);
2126     desc2.dwSize = sizeof(desc2);   /* To override a possibly smaller size */
2127     desc2.u4.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT); /* Just to be sure */
2128
2129     /* Get the video mode from WineD3D - we will need it */
2130     hr = IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
2131                                        0, /* Swapchain 0 */
2132                                        &Mode);
2133     if(FAILED(hr))
2134     {
2135         ERR("Failed to read display mode from wined3d\n");
2136         switch(This->orig_bpp)
2137         {
2138             case 8:
2139                 Mode.Format = WINED3DFMT_P8;
2140                 break;
2141
2142             case 15:
2143                 Mode.Format = WINED3DFMT_X1R5G5B5;
2144                 break;
2145
2146             case 16:
2147                 Mode.Format = WINED3DFMT_R5G6B5;
2148                 break;
2149
2150             case 24:
2151                 Mode.Format = WINED3DFMT_R8G8B8;
2152                 break;
2153
2154             case 32:
2155                 Mode.Format = WINED3DFMT_X8R8G8B8;
2156                 break;
2157         }
2158         Mode.Width = This->orig_width;
2159         Mode.Height = This->orig_height;
2160     }
2161
2162     /* No pixelformat given? Use the current screen format */
2163     if(!(desc2.dwFlags & DDSD_PIXELFORMAT))
2164     {
2165         desc2.dwFlags |= DDSD_PIXELFORMAT;
2166         desc2.u4.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT);
2167
2168         /* Wait: It could be a Z buffer */
2169         if(desc2.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
2170         {
2171             switch(desc2.u2.dwMipMapCount) /* Who had this glorious idea? */
2172             {
2173                 case 15:
2174                     PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D15S1);
2175                     break;
2176                 case 16:
2177                     PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D16);
2178                     break;
2179                 case 24:
2180                     PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D24X8);
2181                     break;
2182                 case 32:
2183                     PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D32);
2184                     break;
2185                 default:
2186                     ERR("Unknown Z buffer bit depth\n");
2187             }
2188         }
2189         else
2190         {
2191             PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, Mode.Format);
2192         }
2193     }
2194
2195     /* No Width or no Height? Use the current window size or
2196      * the original screen size
2197      */
2198     if(!(desc2.dwFlags & DDSD_WIDTH) ||
2199        !(desc2.dwFlags & DDSD_HEIGHT) )
2200     {
2201         HWND window;
2202
2203         /* Fallback: From WineD3D / original mode */
2204         desc2.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
2205         desc2.dwWidth = Mode.Width;
2206         desc2.dwHeight = Mode.Height;
2207
2208         hr = IWineD3DDevice_GetHWND(This->wineD3DDevice,
2209                                     &window);
2210         if( (hr == D3D_OK) && (window != 0) )
2211         {
2212             RECT rect;
2213             if(GetWindowRect(window, &rect) )
2214             {
2215                 /* This is a hack until I find a better solution */
2216                 if( (rect.right - rect.left) <= 1 ||
2217                     (rect.bottom - rect.top) <= 1 )
2218                 {
2219                     FIXME("Wanted to get surface dimensions from window %p, but it has only \
2220                            a size of %ldx%ld. Using full screen dimensions\n",
2221                            window, rect.right - rect.left, rect.bottom - rect.top);
2222                 }
2223                 else
2224                 {
2225                     /* Not sure if this is correct */
2226                     desc2.dwWidth = rect.right - rect.left;
2227                     desc2.dwHeight = rect.bottom - rect.top;
2228                     TRACE("Using window %p's dimensions: %ldx%ld\n", window, desc2.dwWidth, desc2.dwHeight);
2229                 }
2230             }
2231         }
2232     }
2233
2234     /* Mipmap count fixes */
2235     if(desc2.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
2236     {
2237         if(desc2.ddsCaps.dwCaps & DDSCAPS_COMPLEX)
2238         {
2239             if(desc2.dwFlags & DDSD_MIPMAPCOUNT)
2240             {
2241                 /* Mipmap count is given, nothing to do */
2242             }
2243             else
2244             {
2245                 /* Undocumented feature: Create sublevels until
2246                  * either the width or the height is 1
2247                  */
2248                 DWORD min = desc2.dwWidth < desc2.dwHeight ?
2249                             desc2.dwWidth : desc2.dwHeight;
2250                 desc2.u2.dwMipMapCount = 0;
2251                 while( min )
2252                 {
2253                     desc2.u2.dwMipMapCount += 1;
2254                     min >>= 1;
2255                 }
2256             }
2257         }
2258         else
2259         {
2260             /* Not-complex mipmap -> Mipmapcount = 1 */
2261             desc2.u2.dwMipMapCount = 1;
2262         }
2263         extra_surfaces = desc2.u2.dwMipMapCount - 1;
2264
2265         /* There's a mipmap count in the created surface in any case */
2266         desc2.dwFlags |= DDSD_MIPMAPCOUNT;
2267     }
2268     /* If no mipmap is given, the texture has only one level */
2269
2270     /* The first surface is a front buffer, the back buffer is created afterwards */
2271     if( (desc2.dwFlags & DDSD_CAPS) && (desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) )
2272     {
2273         desc2.ddsCaps.dwCaps |= DDSCAPS_FRONTBUFFER;
2274     }
2275
2276     /* Create the first surface */
2277     hr = IDirectDrawImpl_CreateNewSurface(This, &desc2, &object, 0);
2278     if( hr != DD_OK)
2279     {
2280         ERR("IDirectDrawImpl_CreateNewSurface failed with %08lx\n", hr);
2281         return hr;
2282     }
2283
2284     *Surf = ICOM_INTERFACE(object, IDirectDrawSurface7);
2285
2286     /* Create Additional surfaces if necessary
2287      * This applies to Primary surfaces which have a back buffer count
2288      * set, but not to mipmap textures. In case of Mipmap textures,
2289      * wineD3D takes care of the creation of additional surfaces
2290      */
2291     if(DDSD->dwFlags & DDSD_BACKBUFFERCOUNT)
2292     {
2293         extra_surfaces = DDSD->dwBackBufferCount;
2294         desc2.ddsCaps.dwCaps &= ~DDSCAPS_FRONTBUFFER; /* It's not a front buffer */
2295         desc2.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER;
2296     }
2297
2298     for(i = 0; i < extra_surfaces; i++)
2299     {
2300         IDirectDrawSurfaceImpl *object2 = NULL;
2301         IDirectDrawSurfaceImpl *iterator;
2302
2303         /* increase the mipmap level, but only if a mipmap is created
2304          * In this case, also halve the size
2305          */
2306         if(DDSD->ddsCaps.dwCaps & DDSCAPS_MIPMAP)
2307         {
2308             level++;
2309             desc2.dwWidth /= 2;
2310             desc2.dwHeight /= 2;
2311         }
2312
2313         hr = IDirectDrawImpl_CreateNewSurface(This,
2314                                               &desc2,
2315                                               &object2,
2316                                               level);
2317         if(hr != DD_OK)
2318         {
2319             /* This destroys and possibly created surfaces too */
2320             IDirectDrawSurface_Release( ICOM_INTERFACE(object, IDirectDrawSurface7) );
2321             return hr;
2322         }
2323
2324         /* Add the new surface to the complex attachment list */
2325         object2->first_complex = object;
2326         object2->next_complex = NULL;
2327         iterator = object;
2328         while(iterator->next_complex) iterator = iterator->next_complex;
2329         iterator->next_complex = object2;
2330
2331         /* Remove the (possible) back buffer cap from the new surface description,
2332          * because only one surface in the flipping chain is a back buffer, one
2333          * is a front buffer, the others are just primary surfaces.
2334          */
2335         desc2.ddsCaps.dwCaps &= ~DDSCAPS_BACKBUFFER;
2336     }
2337
2338     /* Addref the ddraw interface to keep an reference for each surface */
2339     IDirectDraw7_AddRef(iface);
2340
2341     /* If the implementation is OpenGL and there's no d3ddevice, attach a d3ddevice
2342      * But attach the d3ddevice only if the currently created surface was
2343      * a primary surface (2D app in 3D mode) or a 3DDEVICE surface (3D app)
2344      * The only case I can think of where this doesn't apply is when a
2345      * 2D app was configured by the user to run with OpenGL and it didn't create
2346      * the render target as first surface. In this case the render target creation
2347      * will cause the 3D init.
2348      */
2349     if( (This->ImplType == SURFACE_OPENGL) && !(This->d3d_initialized) &&
2350         desc2.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE) )
2351     {
2352         IDirectDrawSurfaceImpl *target = This->surface_list;
2353
2354         /* Search for the primary to use as render target */
2355         while(target)
2356         {
2357             if(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
2358             {
2359                 /* found */
2360                 TRACE("Using primary %p as render target\n", target);
2361                 break;
2362             }
2363             target = target->next;
2364         }
2365         /* If it's not found, use the just created DDSCAPS_3DDEVICE surface */
2366         if(!target)
2367         {
2368             target = object;
2369         }
2370
2371         TRACE("(%p) Attaching a D3DDevice, rendertarget = %p\n", This, target);
2372         hr = IDirectDrawImpl_AttachD3DDevice(This, target->first_complex);
2373         if(hr != D3D_OK)
2374         {
2375             ERR("IDirectDrawImpl_AttachD3DDevice failed, hr = %lx\n", hr);
2376         }
2377     }
2378
2379     /* Create a WineD3DTexture if a texture was requested */
2380     if(DDSD->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
2381     {
2382         UINT levels;
2383         WINED3DFORMAT Format;
2384         WINED3DPOOL Pool = WINED3DPOOL_DEFAULT;
2385
2386         This->tex_root = object;
2387
2388         if(desc2.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
2389         {
2390             /* a mipmap is created, create enough levels */
2391             levels = desc2.u2.dwMipMapCount;
2392         }
2393         else
2394         {
2395             /* No mipmap is created, create one level */
2396             levels = 1;
2397         }
2398
2399         /* DDSCAPS_SYSTEMMEMORY textures are in WINED3DPOOL_SYSTEMMEM */
2400         if(DDSD->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
2401         {
2402             Pool = WINED3DPOOL_SYSTEMMEM;
2403         }
2404         /* Should I forward the MANEGED cap to the managed pool ? */
2405
2406         /* Get the format. It's set already by CreateNewSurface */
2407         Format = PixelFormat_DD2WineD3D(&object->surface_desc.u4.ddpfPixelFormat);
2408
2409         /* The surfaces are already created, the callback only
2410          * passes the IWineD3DSurface to WineD3D
2411          */
2412         hr = IWineD3DDevice_CreateTexture( This->wineD3DDevice,
2413                                            DDSD->dwWidth, DDSD->dwHeight,
2414                                            levels, /* MipMapCount = Levels */
2415                                            0, /* usage */
2416                                            Format,
2417                                            Pool,
2418                                            &object->wineD3DTexture,
2419                                            0, /* SharedHandle */
2420                                            (IUnknown *) ICOM_INTERFACE(object, IDirectDrawSurface7),
2421                                            D3D7CB_CreateSurface );
2422         This->tex_root = NULL;
2423     }
2424
2425     return hr;
2426 }
2427
2428 #define DDENUMSURFACES_SEARCHTYPE (DDENUMSURFACES_CANBECREATED|DDENUMSURFACES_DOESEXIST)
2429 #define DDENUMSURFACES_MATCHTYPE (DDENUMSURFACES_ALL|DDENUMSURFACES_MATCH|DDENUMSURFACES_NOMATCH)
2430
2431 static BOOL
2432 Main_DirectDraw_DDPIXELFORMAT_Match(const DDPIXELFORMAT *requested,
2433                                     const DDPIXELFORMAT *provided)
2434 {
2435     /* Some flags must be present in both or neither for a match. */
2436     static const DWORD must_match = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2
2437         | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_FOURCC
2438         | DDPF_ZBUFFER | DDPF_STENCILBUFFER;
2439
2440     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
2441         return FALSE;
2442
2443     if ((requested->dwFlags & must_match) != (provided->dwFlags & must_match))
2444         return FALSE;
2445
2446     if (requested->dwFlags & DDPF_FOURCC)
2447         if (requested->dwFourCC != provided->dwFourCC)
2448             return FALSE;
2449
2450     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_ALPHA
2451                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
2452         if (requested->u1.dwRGBBitCount != provided->u1.dwRGBBitCount)
2453             return FALSE;
2454
2455     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
2456                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
2457         if (requested->u2.dwRBitMask != provided->u2.dwRBitMask)
2458             return FALSE;
2459
2460     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_BUMPDUDV))
2461         if (requested->u3.dwGBitMask != provided->u3.dwGBitMask)
2462             return FALSE;
2463
2464     /* I could be wrong about the bumpmapping. MSDN docs are vague. */
2465     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
2466                               |DDPF_BUMPDUDV))
2467         if (requested->u4.dwBBitMask != provided->u4.dwBBitMask)
2468             return FALSE;
2469
2470     if (requested->dwFlags & (DDPF_ALPHAPIXELS|DDPF_ZPIXELS))
2471         if (requested->u5.dwRGBAlphaBitMask != provided->u5.dwRGBAlphaBitMask)
2472             return FALSE;
2473
2474     return TRUE;
2475 }
2476
2477 static BOOL
2478 IDirectDrawImpl_DDSD_Match(const DDSURFACEDESC2* requested,
2479                            const DDSURFACEDESC2* provided)
2480 {
2481     struct compare_info
2482     {
2483         DWORD flag;
2484         ptrdiff_t offset;
2485         size_t size;
2486     };
2487
2488 #define CMP(FLAG, FIELD)                                \
2489         { DDSD_##FLAG, offsetof(DDSURFACEDESC2, FIELD), \
2490           sizeof(((DDSURFACEDESC2 *)(NULL))->FIELD) }
2491
2492     static const struct compare_info compare[] =
2493     {
2494         CMP(ALPHABITDEPTH, dwAlphaBitDepth),
2495         CMP(BACKBUFFERCOUNT, dwBackBufferCount),
2496         CMP(CAPS, ddsCaps),
2497         CMP(CKDESTBLT, ddckCKDestBlt),
2498         CMP(CKDESTOVERLAY, u3 /* ddckCKDestOverlay */),
2499         CMP(CKSRCBLT, ddckCKSrcBlt),
2500         CMP(CKSRCOVERLAY, ddckCKSrcOverlay),
2501         CMP(HEIGHT, dwHeight),
2502         CMP(LINEARSIZE, u1 /* dwLinearSize */),
2503         CMP(LPSURFACE, lpSurface),
2504         CMP(MIPMAPCOUNT, u2 /* dwMipMapCount */),
2505         CMP(PITCH, u1 /* lPitch */),
2506         /* PIXELFORMAT: manual */
2507         CMP(REFRESHRATE, u2 /* dwRefreshRate */),
2508         CMP(TEXTURESTAGE, dwTextureStage),
2509         CMP(WIDTH, dwWidth),
2510         /* ZBUFFERBITDEPTH: "obsolete" */
2511     };
2512
2513 #undef CMP
2514
2515     unsigned int i;
2516
2517     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
2518         return FALSE;
2519
2520     for (i=0; i < sizeof(compare)/sizeof(compare[0]); i++)
2521     {
2522         if (requested->dwFlags & compare[i].flag
2523             && memcmp((const char *)provided + compare[i].offset,
2524                       (const char *)requested + compare[i].offset,
2525                       compare[i].size) != 0)
2526             return FALSE;
2527     }
2528
2529     if (requested->dwFlags & DDSD_PIXELFORMAT)
2530     {
2531         if (!Main_DirectDraw_DDPIXELFORMAT_Match(&requested->u4.ddpfPixelFormat,
2532                                                 &provided->u4.ddpfPixelFormat))
2533             return FALSE;
2534     }
2535
2536     return TRUE;
2537 }
2538
2539 #undef DDENUMSURFACES_SEARCHTYPE
2540 #undef DDENUMSURFACES_MATCHTYPE
2541
2542 /*****************************************************************************
2543  * IDirectDraw7::EnumSurfaces
2544  *
2545  * Loops through all surfaces attached to this device and calls the
2546  * application callback. This can't be relayed to WineD3DDevice,
2547  * because some WineD3DSurfaces' parents are IParent objects
2548  *
2549  * Params:
2550  *  Flags: Some filtering flags. See IDirectDrawImpl_EnumSurfacesCallback
2551  *  DDSD: Description to filter for
2552  *  Context: Application-provided pointer, it's passed unmodified to the
2553  *           Callback function
2554  *  Callback: Address to call for each surface
2555  *
2556  * Returns:
2557  *  DDERR_INVALIDPARAMS if the callback is NULL
2558  *  DD_OK on success
2559  *
2560  *****************************************************************************/
2561 static HRESULT WINAPI
2562 IDirectDrawImpl_EnumSurfaces(IDirectDraw7 *iface,
2563                              DWORD Flags,
2564                              DDSURFACEDESC2 *DDSD,
2565                              void *Context,
2566                              LPDDENUMSURFACESCALLBACK7 Callback)
2567 {
2568     /* The surface enumeration is handled by WineDDraw,
2569      * because it keeps track of all surfaces attached to
2570      * it. The filtering is done by our callback function,
2571      * because WineDDraw doesn't handle ddraw-like surface
2572      * caps structures
2573      */
2574     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
2575     IDirectDrawSurfaceImpl *surf;
2576     BOOL all, nomatch;
2577     DDSURFACEDESC2 desc;
2578
2579     all = Flags & DDENUMSURFACES_ALL;
2580     nomatch = Flags & DDENUMSURFACES_NOMATCH;
2581
2582     TRACE("(%p)->(%lx,%p,%p,%p)\n", This, Flags, DDSD, Context, Callback);
2583
2584     if(!Callback)
2585         return DDERR_INVALIDPARAMS;
2586
2587     for(surf = This->surface_list; surf; surf = surf->next)
2588     {
2589         if (all || (nomatch != IDirectDrawImpl_DDSD_Match(DDSD, &surf->surface_desc)))
2590         {
2591             desc = surf->surface_desc;
2592             IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
2593             if(Callback( ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, Context) != DDENUMRET_OK)
2594                 return DD_OK;
2595         }
2596     }
2597     return DD_OK;
2598 }
2599
2600 /*****************************************************************************
2601  * D3D7CB_CreateRenderTarget
2602  *
2603  * Callback called by WineD3D to create Surfaces for render target usage
2604  * This function takes the D3D target from the IDirectDrawImpl structure,
2605  * and returns the WineD3DSurface. To avoid double usage, the surface
2606  * is marked as render target afterwards
2607  *
2608  * Params
2609  *  device: The WineD3DDevice's parent
2610  *  Width, Height, Format: Dimensions and pixelformat of the render target
2611  *                         Ignored, because the surface already exists
2612  *  MultiSample, MultisampleQuality, Lockable: Ignored for the same reason
2613  *  Lockable: ignored
2614  *  ppSurface: Address to pass the surface pointer back at
2615  *  pSharedHandle: Ignored
2616  *
2617  * Returns:
2618  *  Always returns D3D_OK
2619  *
2620  *****************************************************************************/
2621 static HRESULT WINAPI
2622 D3D7CB_CreateRenderTarget(IUnknown *device, UINT Width, UINT Height,
2623                           WINED3DFORMAT Format,
2624                           WINED3DMULTISAMPLE_TYPE MultiSample,
2625                           DWORD MultisampleQuality,
2626                           BOOL Lockable,
2627                           IWineD3DSurface** ppSurface,
2628                           HANDLE* pSharedHandle)
2629 {
2630     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, device);
2631     IDirectDrawSurfaceImpl *d3dSurface = (IDirectDrawSurfaceImpl *) This->d3d_target->first_complex;
2632     TRACE("(%p) call back\n", device);
2633
2634     /* Loop through the complex chain and try to find unused primary surfaces */
2635     while(d3dSurface->isRenderTarget)
2636     {
2637         d3dSurface = d3dSurface->next_complex;
2638         if(!d3dSurface) break;
2639     }
2640     if(!d3dSurface)
2641     {
2642         d3dSurface = This->d3d_target;
2643         ERR(" (%p) : No DirectDrawSurface found to create the back buffer. Using the front buffer as back buffer. Uncertain consequences\n", This);
2644     }
2645
2646     /* TODO: Return failure if the dimensions do not match, but this shouldn't happen */
2647
2648     *ppSurface = d3dSurface->WineD3DSurface;
2649     d3dSurface->isRenderTarget = TRUE;
2650     TRACE("Returning wineD3DSurface %p, it belongs to surface %p\n", *ppSurface, d3dSurface);
2651     return D3D_OK;
2652 }
2653
2654 static HRESULT WINAPI
2655 D3D7CB_CreateDepthStencilSurface(IUnknown *device,
2656                                  UINT Width,
2657                                  UINT Height,
2658                                  WINED3DFORMAT Format,
2659                                  WINED3DMULTISAMPLE_TYPE MultiSample,
2660                                  DWORD MultisampleQuality,
2661                                  BOOL Discard,
2662                                  IWineD3DSurface** ppSurface,
2663                                  HANDLE* pSharedHandle)
2664 {
2665     /* Create a Depth Stencil surface to make WineD3D happy */
2666     HRESULT hr = D3D_OK;
2667     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, device);
2668     DDSURFACEDESC2 ddsd;
2669
2670     TRACE("(%p) call back\n", device);
2671
2672     *ppSurface = NULL;
2673
2674     /* Create a DirectDraw surface */
2675     memset(&ddsd, 0, sizeof(ddsd));
2676     ddsd.dwSize = sizeof(ddsd);
2677     ddsd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
2678     ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
2679     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
2680     ddsd.dwHeight = Height;
2681     ddsd.dwWidth = Width;
2682     if(Format != 0)
2683     {
2684       PixelFormat_WineD3DtoDD(&ddsd.u4.ddpfPixelFormat, Format);
2685     }
2686     else
2687     {
2688       ddsd.dwFlags ^= DDSD_PIXELFORMAT;
2689     }
2690
2691     This->depthstencil = TRUE;
2692     hr = IDirectDraw7_CreateSurface((IDirectDraw7 *) This,
2693                                     &ddsd,
2694                                     (IDirectDrawSurface7 **) &This->DepthStencilBuffer,
2695                                     NULL);
2696     This->depthstencil = FALSE;
2697     if(FAILED(hr))
2698     {
2699         ERR(" (%p) Creating a DepthStencil Surface failed, result = %lx\n", This, hr);
2700         return hr;
2701     }
2702     *ppSurface = This->DepthStencilBuffer->WineD3DSurface;
2703     return D3D_OK;
2704 }
2705
2706 /*****************************************************************************
2707  * D3D7CB_CreateAdditionalSwapChain
2708  *
2709  * Callback function for WineD3D which creates a new WineD3DSwapchain
2710  * interface. It also creates an IParent interface to store that pointer,
2711  * so the WineD3DSwapchain has a parent and can be released when the D3D
2712  * device is destroyed
2713  *****************************************************************************/
2714 static HRESULT WINAPI
2715 D3D7CB_CreateAdditionalSwapChain(IUnknown *device,
2716                                  WINED3DPRESENT_PARAMETERS* pPresentationParameters,
2717                                  IWineD3DSwapChain ** ppSwapChain)
2718 {
2719     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, device);
2720     IParentImpl *object = NULL;
2721     HRESULT res = D3D_OK;
2722     IWineD3DSwapChain *swapchain;
2723     TRACE("(%p) call back\n", device);
2724
2725     object = HeapAlloc(GetProcessHeap(),  HEAP_ZERO_MEMORY, sizeof(IParentImpl));
2726     if (NULL == object)
2727     {
2728         FIXME("Allocation of memory failed\n");
2729         *ppSwapChain = NULL;
2730         return DDERR_OUTOFVIDEOMEMORY;
2731     }
2732
2733     ICOM_INIT_INTERFACE(object, IParent, IParent_Vtbl);
2734     object->ref = 1;
2735
2736     res = IWineD3DDevice_CreateAdditionalSwapChain(This->wineD3DDevice,
2737                                                    pPresentationParameters, 
2738                                                    &swapchain, 
2739                                                    (IUnknown*) ICOM_INTERFACE(object, IParent),
2740                                                    D3D7CB_CreateRenderTarget,
2741                                                    D3D7CB_CreateDepthStencilSurface);
2742     if (res != D3D_OK)
2743     {
2744         FIXME("(%p) call to IWineD3DDevice_CreateAdditionalSwapChain failed\n", This);
2745         HeapFree(GetProcessHeap(), 0 , object);
2746         *ppSwapChain = NULL;
2747     }
2748     else
2749     {
2750         *ppSwapChain = swapchain;
2751         object->child = (IUnknown *) swapchain;
2752     }
2753
2754     return res;
2755 }
2756
2757 /*****************************************************************************
2758  * IDirectDrawImpl_AttachD3DDevice
2759  *
2760  * Initializes the D3D capabilities of WineD3D
2761  *
2762  * Params:
2763  *  primary: The primary surface for D3D
2764  *
2765  * Returns
2766  *  DD_OK on success,
2767  *  DDERR_* otherwise
2768  *
2769  *****************************************************************************/
2770 static HRESULT WINAPI
2771 IDirectDrawImpl_AttachD3DDevice(IDirectDrawImpl *This,
2772                                 IDirectDrawSurfaceImpl *primary)
2773 {
2774     HRESULT hr;
2775     UINT                  BackBufferCount = 0;
2776     HWND                  window;
2777
2778     WINED3DPRESENT_PARAMETERS localParameters;
2779     BOOL isWindowed, EnableAutoDepthStencil;
2780     WINED3DFORMAT AutoDepthStencilFormat;
2781     WINED3DMULTISAMPLE_TYPE MultiSampleType;
2782     WINED3DSWAPEFFECT  SwapEffect;
2783     DWORD Flags, MultiSampleQuality;
2784     UINT FullScreen_RefreshRateInHz, PresentationInterval;
2785     WINED3DDISPLAYMODE Mode;
2786
2787     TRACE("(%p)->(%p)\n", This, primary);
2788
2789     /* Get the window */
2790     hr = IWineD3DDevice_GetHWND(This->wineD3DDevice,
2791                                 &window);
2792     if(hr != D3D_OK)
2793     {
2794         ERR("IWineD3DDevice::GetHWND failed\n");
2795         return hr;
2796     }
2797
2798     /* If there's no window, create a hidden window. WineD3D needs it */
2799     if(window == 0)
2800     {
2801         window = CreateWindowExA(0, This->classname, "Hidden D3D Window",
2802                                  WS_DISABLED, 0, 0,
2803                                  GetSystemMetrics(SM_CXSCREEN),
2804                                  GetSystemMetrics(SM_CYSCREEN),
2805                                  NULL, NULL, GetModuleHandleA(0), NULL);
2806
2807         ShowWindow(window, SW_HIDE);   /* Just to be sure */
2808         WARN("(%p) No window for the Direct3DDevice, created a hidden window. HWND=%p\n", This, window);
2809         This->d3d_window = window;
2810     }
2811     else
2812     {
2813         TRACE("(%p) Using existing window %p for Direct3D rendering\n", This, window);
2814     }
2815
2816     /* use the surface description for the device parameters, not the
2817      * Device settings. The app might render to an offscreen surface
2818      */
2819     Mode.Width = primary->surface_desc.dwWidth;
2820     Mode.Height = primary->surface_desc.dwHeight;
2821     Mode.Format = PixelFormat_DD2WineD3D(&primary->surface_desc.u4.ddpfPixelFormat);
2822
2823     if(primary->surface_desc.dwFlags & DDSD_BACKBUFFERCOUNT)
2824     {
2825         BackBufferCount = primary->surface_desc.dwBackBufferCount;
2826     }
2827
2828     /* Store the future Render Target surface */
2829     This->d3d_target = primary;
2830
2831     isWindowed = !(This->cooperative_level & DDSCL_FULLSCREEN);
2832     EnableAutoDepthStencil = FALSE;
2833     AutoDepthStencilFormat = WINED3DFMT_D16;
2834     MultiSampleType = WINED3DMULTISAMPLE_NONE;
2835     SwapEffect = WINED3DSWAPEFFECT_COPY;
2836     Flags = 0;
2837     MultiSampleQuality = 0;
2838     FullScreen_RefreshRateInHz = WINED3DPRESENT_RATE_DEFAULT; /* Default rate: It's already set */
2839     PresentationInterval = WINED3DPRESENT_INTERVAL_DEFAULT;
2840
2841     TRACE("Passing mode %d\n", Mode.Format);
2842
2843     localParameters.BackBufferWidth                = &Mode.Width;
2844     localParameters.BackBufferHeight               = &Mode.Height;
2845     localParameters.BackBufferFormat               = (WINED3DFORMAT *) &Mode.Format;
2846     localParameters.BackBufferCount                = (UINT *) &BackBufferCount;
2847     localParameters.MultiSampleType                = &MultiSampleType;
2848     localParameters.MultiSampleQuality             = &MultiSampleQuality;
2849     localParameters.SwapEffect                     = &SwapEffect;
2850     localParameters.hDeviceWindow                  = &window;
2851     localParameters.Windowed                       = &isWindowed;
2852     localParameters.EnableAutoDepthStencil         = &EnableAutoDepthStencil;
2853     localParameters.AutoDepthStencilFormat         = &AutoDepthStencilFormat;
2854     localParameters.Flags                          = &Flags;
2855     localParameters.FullScreen_RefreshRateInHz     = &FullScreen_RefreshRateInHz;
2856     localParameters.PresentationInterval           = &PresentationInterval;
2857
2858     /* Set this NOW, otherwise creating the depth stencil surface will cause a
2859      * recursive loop until ram or emulated video memory is full
2860      */
2861     This->d3d_initialized = TRUE;
2862
2863     hr = IWineD3DDevice_Init3D(This->wineD3DDevice,
2864                                &localParameters,
2865                                D3D7CB_CreateAdditionalSwapChain);
2866     if(FAILED(hr))
2867     {
2868         This->wineD3DDevice = NULL;
2869         return hr;
2870     }
2871
2872     /* Create an Index Buffer parent */
2873     TRACE("(%p) Successfully initialized 3D\n", This);
2874     return DD_OK;
2875 }
2876
2877 /*****************************************************************************
2878  * DirectDrawCreateClipper (DDRAW.@)
2879  *
2880  * Creates a new IDirectDrawClipper object.
2881  *
2882  * Params:
2883  *  Clipper: Address to write the interface pointer to
2884  *  UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
2885  *            NULL
2886  *
2887  * Returns:
2888  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
2889  *  E_OUTOFMEMORY if allocating the object failed
2890  *
2891  *****************************************************************************/
2892 HRESULT WINAPI
2893 DirectDrawCreateClipper(DWORD Flags,
2894                         IDirectDrawClipper **Clipper,
2895                         IUnknown *UnkOuter)
2896 {
2897     IDirectDrawClipperImpl* object;
2898     TRACE("(%08lx,%p,%p)\n", Flags, Clipper, UnkOuter);
2899
2900     if (UnkOuter != NULL) return CLASS_E_NOAGGREGATION;
2901
2902     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2903                      sizeof(IDirectDrawClipperImpl));
2904     if (object == NULL) return E_OUTOFMEMORY;
2905
2906     ICOM_INIT_INTERFACE(object, IDirectDrawClipper, IDirectDrawClipper_Vtbl);
2907     object->ref = 1;
2908     object->hWnd = 0;
2909     object->ddraw_owner = NULL;
2910
2911     *Clipper = (IDirectDrawClipper *) object;
2912     return DD_OK;
2913 }
2914
2915 /*****************************************************************************
2916  * IDirectDraw7::CreateClipper
2917  *
2918  * Creates a DDraw clipper. See DirectDrawCreateClipper for details
2919  *
2920  *****************************************************************************/
2921 static HRESULT WINAPI
2922 IDirectDrawImpl_CreateClipper(IDirectDraw7 *iface,
2923                               DWORD Flags,
2924                               IDirectDrawClipper **Clipper,
2925                               IUnknown *UnkOuter)
2926 {
2927     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
2928     TRACE("(%p)->(%lx,%p,%p)\n", This, Flags, Clipper, UnkOuter);
2929     return DirectDrawCreateClipper(Flags, Clipper, UnkOuter);
2930 }
2931
2932 /*****************************************************************************
2933  * IDirectDraw7::CreatePalette
2934  *
2935  * Creates a new IDirectDrawPalette object
2936  *
2937  * Params:
2938  *  Flags: The flags for the new clipper
2939  *  ColorTable: Color table to assign to the new clipper
2940  *  Palette: Address to write the interface pointer to
2941  *  UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
2942  *            NULL
2943  *
2944  * Returns:
2945  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
2946  *  E_OUTOFMEMORY if allocating the object failed
2947  *
2948  *****************************************************************************/
2949 static HRESULT WINAPI
2950 IDirectDrawImpl_CreatePalette(IDirectDraw7 *iface,
2951                               DWORD Flags,
2952                               PALETTEENTRY *ColorTable,
2953                               IDirectDrawPalette **Palette,
2954                               IUnknown *pUnkOuter)
2955 {
2956     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
2957     IDirectDrawPaletteImpl *object;
2958     HRESULT hr = DDERR_GENERIC;
2959     TRACE("(%p)->(%lx,%p,%p,%p)\n", This, Flags, ColorTable, Palette, pUnkOuter);
2960
2961     if(pUnkOuter != NULL)
2962     {
2963         WARN("pUnkOuter is %p, returning CLASS_E_NOAGGREGATION\n", pUnkOuter);
2964         return CLASS_E_NOAGGREGATION;
2965     }
2966
2967     /* The refcount test shows that a cooplevel is required for this */
2968     if(!This->cooperative_level)
2969     {
2970         WARN("No cooperative level set, returning DDERR_NOCOOPERATIVELEVELSET\n");
2971         return DDERR_NOCOOPERATIVELEVELSET;
2972     }
2973
2974     object = HeapAlloc(GetProcessHeap(), 0, sizeof(IDirectDrawPaletteImpl));
2975     if(!object)
2976     {
2977         ERR("Out of memory when allocating memory for a palette implementation\n");
2978         return E_OUTOFMEMORY;
2979     }
2980
2981     ICOM_INIT_INTERFACE(object, IDirectDrawPalette, IDirectDrawPalette_Vtbl);
2982     object->ref = 1;
2983     object->ddraw_owner = This;
2984
2985     hr = IWineD3DDevice_CreatePalette(This->wineD3DDevice, Flags, ColorTable, &object->wineD3DPalette, (IUnknown *) ICOM_INTERFACE(object, IDirectDrawPalette) );
2986     if(hr != DD_OK)
2987     {
2988         HeapFree(GetProcessHeap(), 0, object);
2989         return hr;
2990     }
2991
2992     IDirectDraw7_AddRef(iface);
2993     *Palette = ICOM_INTERFACE(object, IDirectDrawPalette);
2994     return DD_OK;
2995 }
2996
2997 /*****************************************************************************
2998  * IDirectDraw7::DuplicateSurface
2999  *
3000  * Duplicates a surface. The surface memory points to the same memory as
3001  * the original surface, and it's released when the last surface referencing
3002  * it is released. I guess that's beyond Wine's surface management right now
3003  * (Idea: create a new DDraw surface with the same WineD3DSurface. I need a
3004  * test application to implement this)
3005  *
3006  * Params:
3007  *  Src: Address of the source surface
3008  *  Dest: Address to write the new surface pointer to
3009  *
3010  * Returns:
3011  *  See IDirectDraw7::CreateSurface
3012  *
3013  *****************************************************************************/
3014 static HRESULT WINAPI
3015 IDirectDrawImpl_DuplicateSurface(IDirectDraw7 *iface,
3016                                  IDirectDrawSurface7 *Src,
3017                                  IDirectDrawSurface7 **Dest)
3018 {
3019     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
3020     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Src);
3021
3022     FIXME("(%p)->(%p,%p)\n", This, Surf, Dest);
3023
3024     /* For now, simply create a new, independent surface */
3025     return IDirectDraw7_CreateSurface(iface,
3026                                       &Surf->surface_desc,
3027                                       Dest,
3028                                       NULL);
3029 }
3030
3031 /*****************************************************************************
3032  * IDirectDraw7 VTable
3033  *****************************************************************************/
3034 const IDirectDraw7Vtbl IDirectDraw7_Vtbl =
3035 {
3036     /*** IUnknown ***/
3037     IDirectDrawImpl_QueryInterface,
3038     IDirectDrawImpl_AddRef,
3039     IDirectDrawImpl_Release,
3040     /*** IDirectDraw ***/
3041     IDirectDrawImpl_Compact,
3042     IDirectDrawImpl_CreateClipper,
3043     IDirectDrawImpl_CreatePalette,
3044     IDirectDrawImpl_CreateSurface,
3045     IDirectDrawImpl_DuplicateSurface,
3046     IDirectDrawImpl_EnumDisplayModes,
3047     IDirectDrawImpl_EnumSurfaces,
3048     IDirectDrawImpl_FlipToGDISurface,
3049     IDirectDrawImpl_GetCaps,
3050     IDirectDrawImpl_GetDisplayMode,
3051     IDirectDrawImpl_GetFourCCCodes,
3052     IDirectDrawImpl_GetGDISurface,
3053     IDirectDrawImpl_GetMonitorFrequency,
3054     IDirectDrawImpl_GetScanLine,
3055     IDirectDrawImpl_GetVerticalBlankStatus,
3056     IDirectDrawImpl_Initialize,
3057     IDirectDrawImpl_RestoreDisplayMode,
3058     IDirectDrawImpl_SetCooperativeLevel,
3059     IDirectDrawImpl_SetDisplayMode,
3060     IDirectDrawImpl_WaitForVerticalBlank,
3061     /*** IDirectDraw2 ***/
3062     IDirectDrawImpl_GetAvailableVidMem,
3063     /*** IDirectDraw7 ***/
3064     IDirectDrawImpl_GetSurfaceFromDC,
3065     IDirectDrawImpl_RestoreAllSurfaces,
3066     IDirectDrawImpl_TestCooperativeLevel,
3067     IDirectDrawImpl_GetDeviceIdentifier,
3068     /*** IDirectDraw7 ***/
3069     IDirectDrawImpl_StartModeTest,
3070     IDirectDrawImpl_EvaluateMode
3071 };