Moved d3ddevice and direct3d objects files to ddraw root dir.
[wine/wine-kai.git] / dlls / ddraw / ddraw_main.c
blob57c7e330cc206bd33f7901d7d94c7646e67a4bde
1 /* DirectDraw IDirectDraw interface (generic)
3 * Copyright 1997-2000 Marcus Meissner
4 * Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff)
5 * Copyright 2000-2001 TransGaming Technologies Inc.
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * NOTES
23 * WINE currently implements a very basic set of the DirectDraw functionality
24 * in graphics/ddraw.c. This implementation uses either the XFree86-DGA extension
25 * to get very fast access to the graphics card framebuffer and doublebuffering
26 * features or Xlib, which is slower.
27 * The implementation using XFree86-DGA is as fast as the MS equivalent for the
28 * stuff that is implemented.
30 * Several applications already work, see below.
31 * Problems of the implementation using XFree86-DGA:
33 * - XFree86 cannot switch depth on the fly.
34 * This is a problem with X and unavoidable.
35 * Current solution is to pop up a MessageBox with an error for
36 * mismatched parameters and advice the user to restart the X server
37 * with the specified depth.
38 * - The rest of the functionality that has to be implemented will have
39 * to be done in software and will be very slow.
40 * - This requires WINE to be run as root user so XF86DGA can mmap the
41 * framebuffer into the addressspace of the process.
42 * - Blocks all other X windowed applications.
44 * This file contains all the interface functions that are shared between
45 * all interfaces. Or better, it is a "common stub" library for the
46 * IDirectDraw* objects
49 #include "config.h"
50 #include "wine/port.h"
52 #include <assert.h>
53 #include <stdarg.h>
54 #include <string.h>
56 #define NONAMELESSUNION
57 #define NONAMELESSSTRUCT
59 #define CONST_VTABLE
61 #include "winerror.h"
62 #include "windef.h"
63 #include "winbase.h"
64 #include "wingdi.h"
65 #include "ddraw.h"
66 #include "d3d.h"
67 #include "wine/debug.h"
69 #include "ddraw_private.h"
70 #include "opengl_private.h" /* To have the D3D creation function */
72 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
74 extern const IDirectDrawVtbl DDRAW_IDirectDraw_VTable;
75 extern const IDirectDraw2Vtbl DDRAW_IDirectDraw2_VTable;
76 extern const IDirectDraw4Vtbl DDRAW_IDirectDraw4_VTable;
78 static void DDRAW_UnsubclassWindow(IDirectDrawImpl* This);
80 static void Main_DirectDraw_DeleteSurfaces(IDirectDrawImpl* This);
81 static void Main_DirectDraw_DeleteClippers(IDirectDrawImpl* This);
82 static void Main_DirectDraw_DeletePalettes(IDirectDrawImpl* This);
83 static void LosePrimarySurface(IDirectDrawImpl* This);
85 static INT32 allocate_memory(IDirectDrawImpl *This, DWORD mem) ;
86 static void free_memory(IDirectDrawImpl *This, DWORD mem) ;
89 static const char ddProp[] = "WINE_DDRAW_Property";
91 /* Not called from the vtable. */
92 HRESULT Main_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
94 /* NOTE: The creator must use HEAP_ZERO_MEMORY or equivalent. */
95 This->ref = 1;
96 This->ex = ex;
98 if (ex) This->local.dwLocalFlags |= DDRAWILCL_DIRECTDRAW7;
99 This->local.dwProcessId = GetCurrentProcessId();
101 This->final_release = Main_DirectDraw_final_release;
103 This->create_palette = Main_DirectDrawPalette_Create;
105 This->create_offscreen = Main_create_offscreen;
106 This->create_texture = Main_create_texture;
107 This->create_zbuffer = Main_create_zbuffer;
108 /* There are no generic versions of create_{primary,backbuffer}. */
110 ICOM_INIT_INTERFACE(This, IDirectDraw, DDRAW_IDirectDraw_VTable);
111 ICOM_INIT_INTERFACE(This, IDirectDraw2, DDRAW_IDirectDraw2_VTable);
112 ICOM_INIT_INTERFACE(This, IDirectDraw4, DDRAW_IDirectDraw4_VTable);
113 /* There is no generic implementation of IDD7 */
115 /* This is for the moment here... */
116 This->free_memory = free_memory;
117 This->allocate_memory = allocate_memory;
118 This->total_vidmem = 64 * 1024 * 1024;
119 This->available_vidmem = This->total_vidmem;
121 return DD_OK;
124 void Main_DirectDraw_final_release(IDirectDrawImpl* This)
126 if (IsWindow(This->window))
128 if (GetPropA(This->window, ddProp))
129 DDRAW_UnsubclassWindow(This);
130 else
131 FIXME("this shouldn't happen, right?\n");
134 Main_DirectDraw_DeleteSurfaces(This);
135 Main_DirectDraw_DeleteClippers(This);
136 Main_DirectDraw_DeletePalettes(This);
137 if (This->local.lpGbl && This->local.lpGbl->lpExclusiveOwner == &This->local)
139 This->local.lpGbl->lpExclusiveOwner = NULL;
140 if (This->set_exclusive_mode)
141 This->set_exclusive_mode(This, FALSE);
145 /* There is no Main_DirectDraw_Create. */
147 ULONG WINAPI Main_DirectDraw_AddRef(LPDIRECTDRAW7 iface) {
148 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
149 ULONG ref = InterlockedIncrement(&This->ref);
151 TRACE("(%p)->() incrementing from %lu.\n", This, ref -1);
153 return ref;
156 ULONG WINAPI Main_DirectDraw_Release(LPDIRECTDRAW7 iface) {
157 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
158 ULONG ref = InterlockedDecrement(&This->ref);
160 TRACE("(%p)->() decrementing from %lu.\n", This, ref +1);
162 if (ref == 0)
164 if (This->final_release != NULL)
165 This->final_release(This);
167 /* We free the private. This is an artifact of the fact that I don't
168 * have the destructors set up correctly. */
169 if (This->private != (This+1))
170 HeapFree(GetProcessHeap(), 0, This->private);
172 HeapFree(GetProcessHeap(), 0, This);
175 return ref;
178 HRESULT WINAPI Main_DirectDraw_QueryInterface(
179 LPDIRECTDRAW7 iface,REFIID refiid,LPVOID *obj
181 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
182 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(refiid), obj);
184 /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
185 *obj = NULL;
187 if ( IsEqualGUID( &IID_IUnknown, refiid )
188 || IsEqualGUID( &IID_IDirectDraw7, refiid ) )
190 *obj = ICOM_INTERFACE(This, IDirectDraw7);
192 else if ( IsEqualGUID( &IID_IDirectDraw, refiid ) )
194 *obj = ICOM_INTERFACE(This, IDirectDraw);
196 else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) )
198 *obj = ICOM_INTERFACE(This, IDirectDraw2);
200 else if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) )
202 *obj = ICOM_INTERFACE(This, IDirectDraw4);
204 #ifdef HAVE_OPENGL
205 else if ( IsEqualGUID( &IID_IDirect3D , refiid ) ||
206 IsEqualGUID( &IID_IDirect3D2 , refiid ) ||
207 IsEqualGUID( &IID_IDirect3D3 , refiid ) ||
208 IsEqualGUID( &IID_IDirect3D7 , refiid ) )
210 if (opengl_initialized) {
211 HRESULT ret_value;
213 ret_value = direct3d_create(This);
214 if (FAILED(ret_value)) return ret_value;
216 if ( IsEqualGUID( &IID_IDirect3D , refiid ) ) {
217 *obj = ICOM_INTERFACE(This, IDirect3D);
218 TRACE(" returning Direct3D interface at %p.\n", *obj);
219 } else if ( IsEqualGUID( &IID_IDirect3D2 , refiid ) ) {
220 *obj = ICOM_INTERFACE(This, IDirect3D2);
221 TRACE(" returning Direct3D2 interface at %p.\n", *obj);
222 } else if ( IsEqualGUID( &IID_IDirect3D3 , refiid ) ) {
223 *obj = ICOM_INTERFACE(This, IDirect3D3);
224 TRACE(" returning Direct3D3 interface at %p.\n", *obj);
225 } else {
226 *obj = ICOM_INTERFACE(This, IDirect3D7);
227 TRACE(" returning Direct3D7 interface at %p.\n", *obj);
229 } else {
230 ERR("Application requests a Direct3D interface but dynamic OpenGL support loading failed !\n");
231 ERR("(%p)->(%s,%p): no interface\n",This,debugstr_guid(refiid),obj);
232 return E_NOINTERFACE;
235 #else
236 else if ( IsEqualGUID( &IID_IDirect3D , refiid ) ||
237 IsEqualGUID( &IID_IDirect3D2 , refiid ) ||
238 IsEqualGUID( &IID_IDirect3D3 , refiid ) ||
239 IsEqualGUID( &IID_IDirect3D7 , refiid ) )
241 ERR("Application requests a Direct3D interface but OpenGL support not built-in !\n");
242 ERR("(%p)->(%s,%p): no interface\n",This,debugstr_guid(refiid),obj);
243 return E_NOINTERFACE;
245 #endif
246 else
248 FIXME("(%p)->(%s,%p): no interface\n",This,debugstr_guid(refiid),obj);
249 return E_NOINTERFACE;
252 IDirectDraw7_AddRef(iface);
253 return S_OK;
256 /* MSDN: "not currently implemented". */
257 HRESULT WINAPI Main_DirectDraw_Compact(LPDIRECTDRAW7 iface)
259 TRACE("(%p)\n", iface);
261 return DD_OK;
264 HRESULT WINAPI Main_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface,
265 DWORD dwFlags,
266 LPDIRECTDRAWCLIPPER *ppClipper,
267 IUnknown *pUnkOuter)
269 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
270 HRESULT hr;
272 TRACE("(%p)->(0x%lx, %p, %p)\n", iface, dwFlags, ppClipper, pUnkOuter);
274 hr = DirectDrawCreateClipper(dwFlags, ppClipper, pUnkOuter);
275 if (FAILED(hr)) return hr;
277 /* dwFlags is passed twice, apparently an API wart. */
278 hr = IDirectDrawClipper_Initialize(*ppClipper,
279 ICOM_INTERFACE(This, IDirectDraw),
280 dwFlags);
281 if (FAILED(hr))
283 IDirectDrawClipper_Release(*ppClipper);
284 return hr;
287 return DD_OK;
290 HRESULT WINAPI
291 Main_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags,
292 LPPALETTEENTRY palent,
293 LPDIRECTDRAWPALETTE* ppPalette,
294 LPUNKNOWN pUnknown)
296 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
297 LPDIRECTDRAWPALETTE pPalette;
298 HRESULT hr;
300 TRACE("(%p)->(%08lx,%p,%p,%p)\n",This,dwFlags,palent,ppPalette,pUnknown);
302 if (ppPalette == NULL) return E_POINTER; /* unchecked */
303 if (pUnknown != NULL) return CLASS_E_NOAGGREGATION; /* unchecked */
305 hr = This->create_palette(This, dwFlags, &pPalette, pUnknown);
306 if (FAILED(hr)) return hr;
308 hr = IDirectDrawPalette_SetEntries(pPalette, 0, 0,
309 Main_DirectDrawPalette_Size(dwFlags),
310 palent);
311 if (FAILED(hr))
313 IDirectDrawPalette_Release(pPalette);
314 return hr;
316 else
318 *ppPalette = pPalette;
319 return DD_OK;
323 HRESULT
324 Main_create_offscreen(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD,
325 LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter)
327 assert(pOuter == NULL);
329 return DIB_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter);
332 HRESULT
333 Main_create_texture(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD,
334 LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter,
335 DWORD dwMipMapLevel)
337 assert(pOuter == NULL);
339 return DIB_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter);
342 HRESULT
343 Main_create_zbuffer(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD,
344 LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter)
346 assert(pOuter == NULL);
348 return FakeZBuffer_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter);
351 /* Does the texture surface described in pDDSD have any smaller mipmaps? */
352 static BOOL more_mipmaps(const DDSURFACEDESC2 *pDDSD)
354 return ((pDDSD->dwFlags & DDSD_MIPMAPCOUNT) && pDDSD->u2.dwMipMapCount > 1
355 && (pDDSD->dwWidth > 1 || pDDSD->dwHeight > 1));
358 /* Create a texture surface along with any of its mipmaps. */
359 static HRESULT
360 create_texture(IDirectDrawImpl* This, const DDSURFACEDESC2 *pDDSD,
361 LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter)
363 DDSURFACEDESC2 ddsd;
364 DWORD mipmap_level = 0;
365 HRESULT hr;
367 assert(pUnkOuter == NULL);
369 /* is this check right? (pixelformat can be copied from primary) */
370 if ((pDDSD->dwFlags&(DDSD_HEIGHT|DDSD_WIDTH)) != (DDSD_HEIGHT|DDSD_WIDTH))
371 return DDERR_INVALIDPARAMS;
373 ddsd.dwSize = sizeof(ddsd);
374 DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD);
376 if (!(ddsd.dwFlags & DDSD_PIXELFORMAT))
378 ddsd.u4.ddpfPixelFormat = This->pixelformat;
381 #ifdef HAVE_OPENGL
382 /* We support for now only DXT1, DXT3 & DXT5 compressed texture formats... */
383 if ((ddsd.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) &&
384 (ddsd.u4.ddpfPixelFormat.dwFourCC != MAKE_FOURCC('D','X','T','1')) &&
385 (ddsd.u4.ddpfPixelFormat.dwFourCC != MAKE_FOURCC('D','X','T','3')) &&
386 (ddsd.u4.ddpfPixelFormat.dwFourCC != MAKE_FOURCC('D','X','T','5')) )
388 return DDERR_INVALIDPIXELFORMAT;
391 /* Check if we can really support DXT1, DXT3 & DXT5 */
392 if ((ddsd.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) &&
393 !GL_extensions.s3tc_compressed_texture && !s3tc_initialized) {
394 static BOOLEAN user_warned = 0;
395 if (user_warned == 0) {
396 ERR("Trying to create DXT1, DXT3 or DXT5 texture which is not supported by the video card!!!\n");
397 ERR("However there is a library libtxc_dxtn.so that can be used to do the software decompression...\n");
398 user_warned = 1;
400 return DDERR_INVALIDPIXELFORMAT;
402 #else
403 if (ddsd.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
405 return DDERR_INVALIDPIXELFORMAT;
407 #endif
409 if ((ddsd.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) && !(ddsd.dwFlags & DDSD_LINEARSIZE))
411 int size = 0;
412 int width = ddsd.dwWidth;
413 int height = ddsd.dwHeight;
414 switch(ddsd.u4.ddpfPixelFormat.dwFourCC) {
415 case MAKE_FOURCC('D','X','T','1'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 8; break;
416 case MAKE_FOURCC('D','X','T','3'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 16; break;
417 case MAKE_FOURCC('D','X','T','5'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 16; break;
418 default: FIXME("FOURCC not supported\n"); break;
420 ddsd.u1.dwLinearSize = size;
421 ddsd.dwFlags |= DDSD_LINEARSIZE;
422 } else if (!(ddsd.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) && !(ddsd.dwFlags & DDSD_PITCH)) {
423 ddsd.u1.lPitch = DDRAW_width_bpp_to_pitch(ddsd.dwWidth, GET_BPP(ddsd)*8);
424 ddsd.dwFlags |= DDSD_PITCH;
427 if((ddsd.ddsCaps.dwCaps & DDSCAPS_MIPMAP) &&
428 !(ddsd.dwFlags & DDSD_MIPMAPCOUNT))
430 if(ddsd.ddsCaps.dwCaps & DDSCAPS_COMPLEX)
432 /* Undocumented feature: if DDSCAPS_MIPMAP and DDSCAPS_COMPLEX are
433 * both set, but mipmap count isn't given, as many mipmap levels
434 * as necessary are created to get down to a size where either
435 * the width or the height of the texture is 1.
437 * This is needed by Anarchy Online. */
438 DWORD min = ddsd.dwWidth < ddsd.dwHeight ?
439 ddsd.dwWidth : ddsd.dwHeight;
440 ddsd.u2.dwMipMapCount = 0;
441 while( min )
443 ddsd.u2.dwMipMapCount++;
444 min >>= 1;
447 else
448 /* Create a single mipmap. */
449 ddsd.u2.dwMipMapCount = 1;
451 ddsd.dwFlags |= DDSD_MIPMAPCOUNT;
454 ddsd.dwFlags |= DDSD_PIXELFORMAT;
456 hr = This->create_texture(This, &ddsd, ppSurf, pUnkOuter, mipmap_level);
457 if (FAILED(hr)) return hr;
459 if (This->d3d_private) This->d3d_create_texture(This, ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurf), TRUE,
460 ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurf));
462 /* Create attached mipmaps if required. */
463 if (more_mipmaps(&ddsd))
465 LPDIRECTDRAWSURFACE7 mipmap;
466 LPDIRECTDRAWSURFACE7 prev_mipmap;
467 DDSURFACEDESC2 mipmap_surface_desc;
469 prev_mipmap = *ppSurf;
470 IDirectDrawSurface7_AddRef(prev_mipmap);
471 mipmap_surface_desc = ddsd;
472 mipmap_surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
474 while (more_mipmaps(&mipmap_surface_desc))
476 IDirectDrawSurfaceImpl *mipmap_impl;
478 mipmap_level++;
479 mipmap_surface_desc.u2.dwMipMapCount--;
481 if (mipmap_surface_desc.dwWidth > 1)
482 mipmap_surface_desc.dwWidth /= 2;
484 if (mipmap_surface_desc.dwHeight > 1)
485 mipmap_surface_desc.dwHeight /= 2;
487 if (mipmap_surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) {
488 int size = 0;
489 int width = mipmap_surface_desc.dwWidth;
490 int height = mipmap_surface_desc.dwHeight;
491 switch(mipmap_surface_desc.u4.ddpfPixelFormat.dwFourCC) {
492 case MAKE_FOURCC('D','X','T','1'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 8; break;
493 case MAKE_FOURCC('D','X','T','3'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 16; break;
494 case MAKE_FOURCC('D','X','T','5'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 16; break;
495 default: FIXME("FOURCC not supported\n"); break;
497 mipmap_surface_desc.u1.dwLinearSize = size;
498 } else {
499 ddsd.u1.lPitch = DDRAW_width_bpp_to_pitch(ddsd.dwWidth, GET_BPP(ddsd)*8);
500 mipmap_surface_desc.u1.lPitch
501 = DDRAW_width_bpp_to_pitch(mipmap_surface_desc.dwWidth,
502 GET_BPP(ddsd)*8);
505 hr = This->create_texture(This, &mipmap_surface_desc, &mipmap,
506 pUnkOuter, mipmap_level);
507 if (FAILED(hr))
509 IDirectDrawSurface7_Release(prev_mipmap);
510 IDirectDrawSurface7_Release(*ppSurf);
511 return hr;
514 /* This is needed for delayed mipmap creation */
515 mipmap_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, mipmap);
516 mipmap_impl->mip_main = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurf);
517 mipmap_impl->mipmap_level = mipmap_level;
519 if (This->d3d_private) This->d3d_create_texture(This, ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, mipmap), TRUE,
520 ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurf));
522 IDirectDrawSurface7_AddAttachedSurface(prev_mipmap, mipmap);
523 IDirectDrawSurface7_Release(prev_mipmap);
524 prev_mipmap = mipmap;
527 IDirectDrawSurface7_Release(prev_mipmap);
530 return DD_OK;
533 /* Creates a primary surface and any indicated backbuffers. */
534 static HRESULT
535 create_primary(IDirectDrawImpl* This, LPDDSURFACEDESC2 pDDSD,
536 LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter)
538 DDSURFACEDESC2 ddsd;
539 HRESULT hr;
541 assert(pUnkOuter == NULL);
543 if (This->primary_surface != NULL)
544 return DDERR_PRIMARYSURFACEALREADYEXISTS;
546 /* as documented (what about pitch?) */
547 if (pDDSD->dwFlags & (DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT))
548 return DDERR_INVALIDPARAMS;
550 ddsd.dwSize = sizeof(ddsd);
551 DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD);
552 ddsd.dwFlags |= DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT;
553 ddsd.dwHeight = This->height;
554 ddsd.dwWidth = This->width;
555 ddsd.u1.lPitch = This->pitch;
556 ddsd.u4.ddpfPixelFormat = This->pixelformat;
557 ddsd.ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY
558 | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER;
560 if ((ddsd.dwFlags & DDSD_BACKBUFFERCOUNT) && ddsd.dwBackBufferCount > 0)
561 ddsd.ddsCaps.dwCaps |= DDSCAPS_FLIP;
563 hr = This->create_primary(This, &ddsd, ppSurf, pUnkOuter);
564 if (FAILED(hr)) return hr;
566 if (ddsd.dwFlags & DDSD_BACKBUFFERCOUNT)
568 IDirectDrawSurfaceImpl* primary;
569 LPDIRECTDRAWSURFACE7 pPrev;
570 DWORD i;
572 ddsd.dwFlags &= ~DDSD_BACKBUFFERCOUNT;
573 ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE
574 | DDSCAPS_BACKBUFFER | DDSCAPS_FRONTBUFFER);
576 primary = ICOM_OBJECT(IDirectDrawSurfaceImpl,IDirectDrawSurface7,
577 *ppSurf);
578 pPrev = *ppSurf;
579 IDirectDrawSurface7_AddRef(pPrev);
581 for (i=0; i < ddsd.dwBackBufferCount; i++)
583 LPDIRECTDRAWSURFACE7 pBack;
585 if (i == 0)
586 ddsd.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER;
587 else
588 ddsd.ddsCaps.dwCaps &= ~DDSCAPS_BACKBUFFER;
590 hr = This->create_backbuffer(This, &ddsd, &pBack, pUnkOuter,
591 primary);
593 if (FAILED(hr))
595 IDirectDraw7_Release(pPrev);
596 IDirectDraw7_Release(*ppSurf);
597 return hr;
600 IDirectDrawSurface7_AddAttachedSurface(pPrev, pBack);
601 IDirectDrawSurface7_Release(pPrev);
602 pPrev = pBack;
605 IDirectDrawSurface7_Release(pPrev);
608 This->primary_surface = (IDirectDrawSurfaceImpl *)*ppSurf;
610 return DD_OK;
613 static HRESULT
614 create_offscreen(IDirectDrawImpl* This, LPDDSURFACEDESC2 pDDSD,
615 LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter)
617 DDSURFACEDESC2 ddsd;
618 HRESULT hr;
620 /* is this check right? (pixelformat can be copied from primary) */
621 if ((pDDSD->dwFlags&(DDSD_HEIGHT|DDSD_WIDTH)) != (DDSD_HEIGHT|DDSD_WIDTH))
622 return DDERR_INVALIDPARAMS;
624 ddsd.dwSize = sizeof(ddsd);
625 DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD);
627 if (!(ddsd.dwFlags & DDSD_PIXELFORMAT))
629 ddsd.u4.ddpfPixelFormat = This->pixelformat;
632 if (!(ddsd.dwFlags & DDSD_PITCH))
634 ddsd.u1.lPitch = DDRAW_width_bpp_to_pitch(ddsd.dwWidth,
635 GET_BPP(ddsd)*8);
638 ddsd.dwFlags |= DDSD_PITCH | DDSD_PIXELFORMAT;
640 hr = This->create_offscreen(This, &ddsd, ppSurf, pUnkOuter);
641 if (FAILED(hr)) return hr;
643 return hr;
646 HRESULT WINAPI
647 Main_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD,
648 LPDIRECTDRAWSURFACE7 *ppSurf,
649 IUnknown *pUnkOuter)
651 HRESULT hr;
652 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
654 TRACE("(%p)->(%p,%p,%p)\n",This,pDDSD,ppSurf,pUnkOuter);
655 if (TRACE_ON(ddraw)) {
656 TRACE("Requesting surface desc :\n");
657 DDRAW_dump_surface_desc(pDDSD);
660 if (pUnkOuter != NULL) {
661 FIXME("outer != NULL?\n");
662 return CLASS_E_NOAGGREGATION; /* unchecked */
665 if (!(pDDSD->dwFlags & DDSD_CAPS)) {
666 /* DVIDEO.DLL does forget the DDSD_CAPS flag ... *sigh* */
667 pDDSD->dwFlags |= DDSD_CAPS;
669 if (pDDSD->ddsCaps.dwCaps == 0) {
670 /* This has been checked on real Windows */
671 pDDSD->ddsCaps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
674 if (pDDSD->ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD) {
675 /* If the surface is of the 'alloconload' type, ignore the LPSURFACE field */
676 pDDSD->dwFlags &= ~DDSD_LPSURFACE;
679 if ((pDDSD->dwFlags & DDSD_LPSURFACE) && (pDDSD->lpSurface == NULL)) {
680 /* Frank Herbert's Dune specifies a null pointer for the surface, ignore the LPSURFACE field */
681 WARN("Null surface pointer specified, ignore it!\n");
682 pDDSD->dwFlags &= ~DDSD_LPSURFACE;
685 if (ppSurf == NULL) {
686 FIXME("You want to get back a surface? Don't give NULL ptrs!\n");
687 return E_POINTER; /* unchecked */
690 if (pDDSD->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
692 /* create primary surface & backbuffers */
693 hr = create_primary(This, pDDSD, ppSurf, pUnkOuter);
695 else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_BACKBUFFER)
697 /* create backbuffer surface */
698 hr = This->create_backbuffer(This, pDDSD, ppSurf, pUnkOuter, NULL);
700 else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
702 /* create texture */
703 hr = create_texture(This, pDDSD, ppSurf, pUnkOuter);
705 else if ( (pDDSD->ddsCaps.dwCaps & DDSCAPS_ZBUFFER) &&
706 !(pDDSD->ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN)) /* Support DDSCAPS_SYSTEMMEMORY */
708 /* create z-buffer */
709 hr = This->create_zbuffer(This, pDDSD, ppSurf, pUnkOuter);
711 else if ((pDDSD->ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN) ||
712 (pDDSD->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)) /* No difference in Wine right now */
714 /* create offscreenplain surface */
715 hr = create_offscreen(This, pDDSD, ppSurf, pUnkOuter);
717 else
719 /* Otherwise, assume offscreenplain surface */
720 TRACE("App didn't request a valid surface type - assuming offscreenplain\n");
721 hr = create_offscreen(This, pDDSD, ppSurf, pUnkOuter);
724 if (FAILED(hr)) {
725 FIXME("failed surface creation with code 0x%08lx\n",hr);
726 return hr;
729 return DD_OK;
732 HRESULT WINAPI
733 Main_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface, LPDIRECTDRAWSURFACE7 src,
734 LPDIRECTDRAWSURFACE7* dst)
736 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
738 IDirectDrawSurfaceImpl *pSrc = ICOM_OBJECT(IDirectDrawSurfaceImpl,
739 IDirectDrawSurface7, src);
741 TRACE("(%p)->(%p,%p)\n",This,src,dst);
743 return pSrc->duplicate_surface(pSrc, dst);
746 /* EnumDisplayModes */
748 BOOL Main_DirectDraw_DDPIXELFORMAT_Match(const DDPIXELFORMAT *requested,
749 const DDPIXELFORMAT *provided)
751 /* Some flags must be present in both or neither for a match. */
752 static const DWORD must_match = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2
753 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_FOURCC
754 | DDPF_ZBUFFER | DDPF_STENCILBUFFER;
756 if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
757 return FALSE;
759 if ((requested->dwFlags & must_match) != (provided->dwFlags & must_match))
760 return FALSE;
762 if (requested->dwFlags & DDPF_FOURCC)
763 if (requested->dwFourCC != provided->dwFourCC)
764 return FALSE;
766 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_ALPHA
767 |DDPF_LUMINANCE|DDPF_BUMPDUDV))
768 if (requested->u1.dwRGBBitCount != provided->u1.dwRGBBitCount)
769 return FALSE;
771 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
772 |DDPF_LUMINANCE|DDPF_BUMPDUDV))
773 if (requested->u2.dwRBitMask != provided->u2.dwRBitMask)
774 return FALSE;
776 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_BUMPDUDV))
777 if (requested->u3.dwGBitMask != provided->u3.dwGBitMask)
778 return FALSE;
780 /* I could be wrong about the bumpmapping. MSDN docs are vague. */
781 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
782 |DDPF_BUMPDUDV))
783 if (requested->u4.dwBBitMask != provided->u4.dwBBitMask)
784 return FALSE;
786 if (requested->dwFlags & (DDPF_ALPHAPIXELS|DDPF_ZPIXELS))
787 if (requested->u5.dwRGBAlphaBitMask != provided->u5.dwRGBAlphaBitMask)
788 return FALSE;
790 return TRUE;
793 BOOL Main_DirectDraw_DDSD_Match(const DDSURFACEDESC2* requested,
794 const DDSURFACEDESC2* provided)
796 struct compare_info
798 DWORD flag;
799 ptrdiff_t offset;
800 size_t size;
803 #define CMP(FLAG, FIELD) \
804 { DDSD_##FLAG, offsetof(DDSURFACEDESC2, FIELD), \
805 sizeof(((DDSURFACEDESC2 *)(NULL))->FIELD) }
807 static const struct compare_info compare[] = {
808 CMP(ALPHABITDEPTH, dwAlphaBitDepth),
809 CMP(BACKBUFFERCOUNT, dwBackBufferCount),
810 CMP(CAPS, ddsCaps),
811 CMP(CKDESTBLT, ddckCKDestBlt),
812 CMP(CKDESTOVERLAY, u3.ddckCKDestOverlay),
813 CMP(CKSRCBLT, ddckCKSrcBlt),
814 CMP(CKSRCOVERLAY, ddckCKSrcOverlay),
815 CMP(HEIGHT, dwHeight),
816 CMP(LINEARSIZE, u1.dwLinearSize),
817 CMP(LPSURFACE, lpSurface),
818 CMP(MIPMAPCOUNT, u2.dwMipMapCount),
819 CMP(PITCH, u1.lPitch),
820 /* PIXELFORMAT: manual */
821 CMP(REFRESHRATE, u2.dwRefreshRate),
822 CMP(TEXTURESTAGE, dwTextureStage),
823 CMP(WIDTH, dwWidth),
824 /* ZBUFFERBITDEPTH: "obsolete" */
827 #undef CMP
829 unsigned int i;
831 if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
832 return FALSE;
834 for (i=0; i < sizeof(compare)/sizeof(compare[0]); i++)
836 if (requested->dwFlags & compare[i].flag
837 && memcmp((const char *)provided + compare[i].offset,
838 (const char *)requested + compare[i].offset,
839 compare[i].size) != 0)
840 return FALSE;
843 if (requested->dwFlags & DDSD_PIXELFORMAT)
845 if (!Main_DirectDraw_DDPIXELFORMAT_Match(&requested->u4.ddpfPixelFormat,
846 &provided->u4.ddpfPixelFormat))
847 return FALSE;
850 return TRUE;
853 #define DDENUMSURFACES_SEARCHTYPE (DDENUMSURFACES_CANBECREATED|DDENUMSURFACES_DOESEXIST)
854 #define DDENUMSURFACES_MATCHTYPE (DDENUMSURFACES_ALL|DDENUMSURFACES_MATCH|DDENUMSURFACES_NOMATCH)
856 /* This should be extended so that it can be used by
857 * IDirectDrawSurface7::EnumAttachedSurfaces. */
858 HRESULT
859 Main_DirectDraw_EnumExistingSurfaces(IDirectDrawImpl *This, DWORD dwFlags,
860 LPDDSURFACEDESC2 lpDDSD2, LPVOID context,
861 LPDDENUMSURFACESCALLBACK7 callback)
863 IDirectDrawSurfaceImpl *surf;
864 BOOL all, nomatch;
866 /* A NULL lpDDSD2 is permitted if we are enumerating all surfaces anyway */
867 if (lpDDSD2 == NULL && !(dwFlags & DDENUMSURFACES_ALL))
868 return DDERR_INVALIDPARAMS;
870 all = dwFlags & DDENUMSURFACES_ALL;
871 nomatch = dwFlags & DDENUMSURFACES_NOMATCH;
873 for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw)
875 if (all
876 || (nomatch != Main_DirectDraw_DDSD_Match(lpDDSD2,
877 &surf->surface_desc)))
879 LPDIRECTDRAWSURFACE7 surface = ICOM_INTERFACE(surf,
880 IDirectDrawSurface7);
882 /* BOGUS! Violates COM rules, but MSDN says so. */
883 IDirectDrawSurface7_AddRef(surface);
885 if (callback(surface, &surf->surface_desc, context)
886 == DDENUMRET_CANCEL)
887 break;
891 return DD_OK;
894 /* I really don't understand how this is supposed to work.
895 * We only consider dwHeight, dwWidth and ddpfPixelFormat.dwFlags. */
896 HRESULT
897 Main_DirectDraw_EnumCreateableSurfaces(IDirectDrawImpl *This, DWORD dwFlags,
898 LPDDSURFACEDESC2 lpDDSD2,
899 LPVOID context,
900 LPDDENUMSURFACESCALLBACK7 callback)
902 FIXME("This isn't going to work.\n");
904 if ((dwFlags & DDENUMSURFACES_MATCHTYPE) != DDENUMSURFACES_MATCH)
905 return DDERR_INVALIDPARAMS;
907 /* TODO: implement this.
908 * Does this work before SCL is called?
909 * Does it only consider off-screen surfaces?
912 return E_FAIL;
915 /* For unsigned x. 0 is not a power of 2. */
916 #define IS_POW_2(x) (((x) & ((x) - 1)) == 0)
918 HRESULT WINAPI
919 Main_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags,
920 LPDDSURFACEDESC2 lpDDSD2, LPVOID context,
921 LPDDENUMSURFACESCALLBACK7 callback)
923 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
924 TRACE("(%p)->(0x%lx, %p, %p, %p)\n", iface, dwFlags, lpDDSD2, context,
925 callback);
927 if (callback == NULL)
928 return DDERR_INVALIDPARAMS;
930 if (dwFlags & ~(DDENUMSURFACES_SEARCHTYPE|DDENUMSURFACES_MATCHTYPE))
931 return DDERR_INVALIDPARAMS;
933 if (!IS_POW_2(dwFlags & DDENUMSURFACES_SEARCHTYPE)
934 || !IS_POW_2(dwFlags & DDENUMSURFACES_MATCHTYPE))
935 return DDERR_INVALIDPARAMS;
937 if (dwFlags & DDENUMSURFACES_DOESEXIST)
939 return Main_DirectDraw_EnumExistingSurfaces(This, dwFlags, lpDDSD2,
940 context, callback);
942 else
944 return Main_DirectDraw_EnumCreateableSurfaces(This, dwFlags, lpDDSD2,
945 context, callback);
949 HRESULT WINAPI
950 Main_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface,DWORD a,DWORD* b)
952 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
953 FIXME("(%p)->() stub\n", This);
955 return DD_OK;
958 HRESULT WINAPI
959 Main_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface)
961 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
962 TRACE("(%p)->()\n",This);
963 return DD_OK;
966 HRESULT WINAPI
967 Main_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps,
968 LPDDCAPS pHELCaps)
970 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
971 TRACE("(%p,%p,%p)\n",This,pDriverCaps,pHELCaps);
972 if (pDriverCaps != NULL) {
973 DD_STRUCT_COPY_BYSIZE(pDriverCaps,&This->caps);
974 if (TRACE_ON(ddraw)) {
975 TRACE("Driver Caps : \n");
976 DDRAW_dump_DDCAPS(pDriverCaps);
979 if (pHELCaps != NULL) {
980 DD_STRUCT_COPY_BYSIZE(pHELCaps,&This->caps);
981 if (TRACE_ON(ddraw)) {
982 TRACE("HEL Caps : \n");
983 DDRAW_dump_DDCAPS(pHELCaps);
986 return DD_OK;
989 /* GetCaps */
990 /* GetDeviceIdentifier */
991 /* GetDIsplayMode */
993 HRESULT WINAPI
994 Main_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes,
995 LPDWORD pCodes)
997 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
998 if (*pNumCodes) {
999 *pNumCodes=0;
1001 FIXME("(%p,%p,%p), stub\n",This,pNumCodes,pCodes);
1002 return DD_OK;
1005 HRESULT WINAPI
1006 Main_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface,
1007 LPDIRECTDRAWSURFACE7 *lplpGDIDDSSurface)
1009 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1010 TRACE("(%p)->(%p)\n", This, lplpGDIDDSSurface);
1011 TRACE("returning primary (%p)\n", This->primary_surface);
1012 *lplpGDIDDSSurface = ICOM_INTERFACE(This->primary_surface, IDirectDrawSurface7);
1013 if (*lplpGDIDDSSurface)
1014 IDirectDrawSurface7_AddRef(*lplpGDIDDSSurface);
1015 return DD_OK;
1018 HRESULT WINAPI
1019 Main_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface,LPDWORD freq)
1021 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1022 FIXME("(%p)->(%p) returns 60 Hz always\n",This,freq);
1023 *freq = 60*100; /* 60 Hz */
1024 return DD_OK;
1027 HRESULT WINAPI
1028 Main_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD lpdwScanLine)
1030 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1031 static BOOL hide;
1033 /* Since this method is called often, show the fixme only once */
1034 if (!hide) {
1035 FIXME("(%p)->(%p) semi-stub\n", This, lpdwScanLine);
1036 hide = TRUE;
1039 /* Fake the line sweeping of the monitor */
1040 /* FIXME: We should synchronize with a source to keep the refresh rate */
1041 *lpdwScanLine = This->cur_scanline++;
1042 /* Assume 20 scan lines in the vertical blank */
1043 if (This->cur_scanline >= This->height + 20)
1044 This->cur_scanline = 0;
1046 return DD_OK;
1049 HRESULT WINAPI
1050 Main_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hdc,
1051 LPDIRECTDRAWSURFACE7 *lpDDS)
1053 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1054 FIXME("(%p)->(%08ld,%p)\n", This, (DWORD) hdc, lpDDS);
1056 return DD_OK;
1059 HRESULT WINAPI
1060 Main_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, LPBOOL status)
1062 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1063 TRACE("(%p)->(%p)\n",This,status);
1064 *status = TRUE;
1065 return DD_OK;
1068 /* If we were not initialised then Uninit_Main_IDirectDraw7_Initialize would
1069 * have been called instead. */
1070 HRESULT WINAPI
1071 Main_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID lpGuid)
1073 TRACE("(%p)->(%s)\n", iface, debugstr_guid(lpGuid));
1075 return DDERR_ALREADYINITIALIZED;
1078 HRESULT WINAPI
1079 Main_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface)
1081 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1082 IDirectDrawSurfaceImpl* surf;
1084 TRACE("(%p)->()\n", This);
1086 for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw)
1087 IDirectDrawSurface7_Restore(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1089 return DD_OK;
1092 static void DDRAW_SubclassWindow(IDirectDrawImpl* This)
1094 /* Well we don't actually subclass the window yet. */
1095 SetPropA(This->window, ddProp, This);
1098 static void DDRAW_UnsubclassWindow(IDirectDrawImpl* This)
1100 RemovePropA(This->window, ddProp);
1103 HRESULT WINAPI
1104 Main_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hwnd,
1105 DWORD cooplevel)
1107 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1109 FIXME("(%p)->(%08lx,%08lx)\n",This,(DWORD)hwnd,cooplevel);
1110 DDRAW_dump_cooperativelevel(cooplevel);
1112 /* Makes realMYST test happy. */
1113 if (This->cooperative_level == cooplevel
1114 && This->window == hwnd)
1115 return DD_OK;
1117 /* XXX "It cannot be reset while the process has surfaces or palettes
1118 * created." Otherwise the window can be changed???
1120 * This appears to be wrong - comment it out for now.
1121 if (This->window)
1122 return DDERR_HWNDALREADYSET;
1125 if (!(cooplevel & (DDSCL_EXCLUSIVE|DDSCL_NORMAL)))
1126 return DDERR_INVALIDPARAMS;
1128 This->window = hwnd;
1129 This->cooperative_level = cooplevel;
1131 This->local.hWnd = (ULONG_PTR)hwnd;
1132 This->local.dwLocalFlags |= DDRAWILCL_SETCOOPCALLED;
1133 /* not entirely sure about these */
1134 if (cooplevel & DDSCL_EXCLUSIVE) This->local.dwLocalFlags |= DDRAWILCL_HASEXCLUSIVEMODE;
1135 if (cooplevel & DDSCL_FULLSCREEN) This->local.dwLocalFlags |= DDRAWILCL_ISFULLSCREEN;
1136 if (cooplevel & DDSCL_ALLOWMODEX) This->local.dwLocalFlags |= DDRAWILCL_ALLOWMODEX;
1137 if (cooplevel & DDSCL_MULTITHREADED) This->local.dwLocalFlags |= DDRAWILCL_MULTITHREADED;
1138 if (cooplevel & DDSCL_FPUSETUP) This->local.dwLocalFlags |= DDRAWILCL_FPUSETUP;
1139 if (cooplevel & DDSCL_FPUPRESERVE) This->local.dwLocalFlags |= DDRAWILCL_FPUPRESERVE;
1141 if (This->local.lpGbl) {
1142 /* assume that this app is the active app (in wine, there's
1143 * probably only one app per global ddraw object anyway) */
1144 if (cooplevel & DDSCL_EXCLUSIVE) This->local.lpGbl->lpExclusiveOwner = &This->local;
1145 else if (This->local.lpGbl->lpExclusiveOwner == &This->local)
1146 This->local.lpGbl->lpExclusiveOwner = NULL;
1147 if (This->set_exclusive_mode)
1148 This->set_exclusive_mode(This, (cooplevel & DDSCL_EXCLUSIVE) != 0);
1151 ShowWindow(hwnd, SW_SHOW);
1153 DDRAW_SubclassWindow(This);
1155 /* TODO Does it also get resized to the current screen size? */
1157 return DD_OK;
1160 HRESULT WINAPI
1161 Main_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
1162 DWORD dwHeight, LONG lPitch,
1163 DWORD dwRefreshRate, DWORD dwFlags,
1164 const DDPIXELFORMAT* pixelformat)
1166 short screenX;
1167 short screenY;
1169 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1171 TRACE("(%p)->SetDisplayMode(%ld,%ld)\n",This,dwWidth,dwHeight);
1173 if (!(This->cooperative_level & DDSCL_EXCLUSIVE))
1174 return DDERR_NOEXCLUSIVEMODE;
1176 if (!IsWindow(This->window))
1177 return DDERR_GENERIC; /* unchecked */
1179 LosePrimarySurface(This);
1181 screenX = GetSystemMetrics(SM_CXSCREEN);
1182 screenY = GetSystemMetrics(SM_CYSCREEN);
1184 This->width = dwWidth;
1185 This->height = dwHeight;
1186 This->pitch = lPitch;
1187 This->pixelformat = *pixelformat;
1189 /* Position the window in the center of the screen - don't center for now */
1190 /* MoveWindow(This->window, (screenX-dwWidth)/2, (screenY-dwHeight)/2,
1191 dwWidth, dwHeight, TRUE);*/
1192 MoveWindow(This->window, 0, 0, dwWidth, dwHeight, TRUE);
1194 SetFocus(This->window);
1196 return DD_OK;
1199 HRESULT WINAPI
1200 Main_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
1202 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1204 TRACE("(%p)\n",This);
1205 if (!(This->cooperative_level & DDSCL_EXCLUSIVE))
1206 return DDERR_NOEXCLUSIVEMODE;
1208 /* Lose the primary surface if the resolution changes. */
1209 if (This->orig_width != This->width || This->orig_height != This->height
1210 || This->orig_pitch != This->pitch
1211 || This->orig_pixelformat.dwFlags != This->pixelformat.dwFlags
1212 || !Main_DirectDraw_DDPIXELFORMAT_Match(&This->pixelformat,
1213 &This->orig_pixelformat))
1215 LosePrimarySurface(This);
1218 /* TODO Move the window back where it belongs. */
1220 return DD_OK;
1223 HRESULT WINAPI
1224 Main_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags,
1225 HANDLE h)
1227 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1228 FIXME("(%p)->(flags=0x%08lx,handle=%p)\n",This,dwFlags,h);
1229 return DD_OK;
1232 HRESULT WINAPI
1233 Main_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD)
1235 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1236 TRACE("(%p)->GetDisplayMode(%p)\n",This,pDDSD);
1238 pDDSD->dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_PIXELFORMAT|DDSD_REFRESHRATE;
1239 pDDSD->dwHeight = This->height;
1240 pDDSD->dwWidth = This->width;
1241 pDDSD->u1.lPitch = This->pitch;
1242 pDDSD->u2.dwRefreshRate = 60;
1243 pDDSD->u4.ddpfPixelFormat = This->pixelformat;
1244 pDDSD->ddsCaps.dwCaps = 0;
1246 return DD_OK;
1249 static INT32 allocate_memory(IDirectDrawImpl *This, DWORD mem)
1251 if (mem > This->available_vidmem) return -1;
1252 This->available_vidmem -= mem;
1253 return This->available_vidmem;
1256 static void free_memory(IDirectDrawImpl *This, DWORD mem)
1258 This->available_vidmem += mem;
1261 HRESULT WINAPI
1262 Main_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 ddscaps,
1263 LPDWORD total, LPDWORD free)
1265 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1266 TRACE("(%p)->(%p,%p,%p)\n", This,ddscaps,total,free);
1268 if (TRACE_ON(ddraw)) {
1269 TRACE(" Asking for memory of type : ");
1270 DDRAW_dump_DDSCAPS2(ddscaps); TRACE("\n");
1273 /* We have 16 MB videomemory */
1274 if (total) *total= This->total_vidmem;
1275 if (free) *free = This->available_vidmem;
1277 TRACE(" returning (total) %ld / (free) %ld\n",
1278 total != NULL ? *total : 0,
1279 free != NULL ? *free : 0);
1281 return DD_OK;
1284 HRESULT WINAPI Main_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface) {
1285 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1286 TRACE("(%p)->(): stub\n", This);
1288 return DD_OK;
1291 HRESULT WINAPI
1292 Main_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pModes,
1293 DWORD dwNumModes, DWORD dwFlags)
1295 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1296 FIXME("(%p)->() stub\n", This);
1298 return DD_OK;
1301 /*** Owned object management. */
1303 void Main_DirectDraw_AddSurface(IDirectDrawImpl* This,
1304 IDirectDrawSurfaceImpl* surface)
1306 assert(surface->ddraw_owner == NULL || surface->ddraw_owner == This);
1308 surface->ddraw_owner = This;
1310 /* where should it go? */
1311 surface->next_ddraw = This->surfaces;
1312 surface->prev_ddraw = NULL;
1313 if (This->surfaces)
1314 This->surfaces->prev_ddraw = surface;
1315 This->surfaces = surface;
1318 void Main_DirectDraw_RemoveSurface(IDirectDrawImpl* This,
1319 IDirectDrawSurfaceImpl* surface)
1321 assert(surface->ddraw_owner == This);
1323 if (This->surfaces == surface)
1324 This->surfaces = surface->next_ddraw;
1326 if (This->primary_surface == surface)
1327 This->primary_surface = NULL;
1329 if (surface->next_ddraw)
1330 surface->next_ddraw->prev_ddraw = surface->prev_ddraw;
1331 if (surface->prev_ddraw)
1332 surface->prev_ddraw->next_ddraw = surface->next_ddraw;
1335 static void Main_DirectDraw_DeleteSurfaces(IDirectDrawImpl* This)
1337 while (This->surfaces != NULL)
1338 Main_DirectDrawSurface_ForceDestroy(This->surfaces);
1341 void Main_DirectDraw_AddClipper(IDirectDrawImpl* This,
1342 IDirectDrawClipperImpl* clipper)
1344 assert(clipper->ddraw_owner == NULL || clipper->ddraw_owner == This);
1346 clipper->ddraw_owner = This;
1348 clipper->next_ddraw = This->clippers;
1349 clipper->prev_ddraw = NULL;
1350 if (This->clippers)
1351 This->clippers->prev_ddraw = clipper;
1352 This->clippers = clipper;
1355 void Main_DirectDraw_RemoveClipper(IDirectDrawImpl* This,
1356 IDirectDrawClipperImpl* clipper)
1358 assert(clipper->ddraw_owner == This);
1360 if (This->clippers == clipper)
1361 This->clippers = clipper->next_ddraw;
1363 if (clipper->next_ddraw)
1364 clipper->next_ddraw->prev_ddraw = clipper->prev_ddraw;
1365 if (clipper->prev_ddraw)
1366 clipper->prev_ddraw->next_ddraw = clipper->next_ddraw;
1369 static void Main_DirectDraw_DeleteClippers(IDirectDrawImpl* This)
1371 while (This->clippers != NULL)
1372 Main_DirectDrawClipper_ForceDestroy(This->clippers);
1375 void Main_DirectDraw_AddPalette(IDirectDrawImpl* This,
1376 IDirectDrawPaletteImpl* palette)
1378 assert(palette->ddraw_owner == NULL || palette->ddraw_owner == This);
1380 palette->ddraw_owner = This;
1382 /* where should it go? */
1383 palette->next_ddraw = This->palettes;
1384 palette->prev_ddraw = NULL;
1385 if (This->palettes)
1386 This->palettes->prev_ddraw = palette;
1387 This->palettes = palette;
1390 void Main_DirectDraw_RemovePalette(IDirectDrawImpl* This,
1391 IDirectDrawPaletteImpl* palette)
1393 IDirectDrawSurfaceImpl *surf;
1395 assert(palette->ddraw_owner == This);
1397 if (This->palettes == palette)
1398 This->palettes = palette->next_ddraw;
1400 if (palette->next_ddraw)
1401 palette->next_ddraw->prev_ddraw = palette->prev_ddraw;
1402 if (palette->prev_ddraw)
1403 palette->prev_ddraw->next_ddraw = palette->next_ddraw;
1405 /* Here we need also to remove tha palette from any surface which has it as the
1406 * current palette (checked on Windows)
1408 for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw) {
1409 if (surf->palette == palette) {
1410 TRACE("Palette %p attached to surface %p.\n", palette, surf);
1411 surf->palette = NULL;
1412 surf->set_palette(surf, NULL);
1417 static void Main_DirectDraw_DeletePalettes(IDirectDrawImpl* This)
1419 while (This->palettes != NULL)
1420 Main_DirectDrawPalette_ForceDestroy(This->palettes);
1423 /*** ??? */
1425 static void
1426 LoseSurface(IDirectDrawSurfaceImpl *surface)
1428 if (surface != NULL) surface->lose_surface(surface);
1431 static void
1432 LosePrimarySurface(IDirectDrawImpl *This)
1434 /* MSDN: "If another application changes the display mode, the primary
1435 * surface is lost, and the method returns DDERR_SURFACELOST until the
1436 * primary surface is recreated to match the new display mode."
1438 * We mark all the primary surfaces as lost as soon as the display
1439 * mode is changed (by any application). */
1441 LoseSurface(This->primary_surface);
1444 /******************************************************************************
1445 * Uninitialised DirectDraw functions
1447 * This vtable is used when a DirectDraw object is created with
1448 * CoCreateInstance. The only usable method is Initialize.
1451 void Uninit_DirectDraw_final_release(IDirectDrawImpl *This)
1453 Main_DirectDraw_final_release(This);
1456 static const IDirectDraw7Vtbl Uninit_DirectDraw_VTable;
1458 /* Not called from the vtable. */
1459 HRESULT Uninit_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
1461 HRESULT hr;
1463 hr = Main_DirectDraw_Construct(This, ex);
1464 if (FAILED(hr)) return hr;
1466 This->final_release = Uninit_DirectDraw_final_release;
1467 ICOM_INIT_INTERFACE(This, IDirectDraw7, Uninit_DirectDraw_VTable);
1469 return S_OK;
1472 HRESULT Uninit_DirectDraw_Create(const GUID* pGUID,
1473 LPDIRECTDRAW7* pIface,
1474 IUnknown* pUnkOuter, BOOL ex)
1476 HRESULT hr;
1477 IDirectDrawImpl* This;
1479 assert(pUnkOuter == NULL); /* XXX no: we must check this */
1481 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1482 sizeof(IDirectDrawImpl));
1483 if (This == NULL) return E_OUTOFMEMORY;
1485 hr = Uninit_DirectDraw_Construct(This, ex);
1486 if (FAILED(hr))
1487 HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, This);
1488 else
1489 *pIface = ICOM_INTERFACE(This, IDirectDraw7);
1491 return hr;
1494 static HRESULT WINAPI
1495 Uninit_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID pDeviceGuid)
1497 const ddraw_driver* driver;
1498 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1500 TRACE("(%p)->(%p)\n", iface, pDeviceGuid);
1502 driver = DDRAW_FindDriver(pDeviceGuid);
1503 /* XXX This return value is not documented. (Not checked.) */
1504 if (driver == NULL) return DDERR_INVALIDDIRECTDRAWGUID;
1506 return driver->init(This, pDeviceGuid);
1509 static HRESULT WINAPI
1510 Uninit_DirectDraw_Compact(LPDIRECTDRAW7 iface)
1512 return DDERR_NOTINITIALIZED;
1515 static HRESULT WINAPI
1516 Uninit_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface, DWORD dwFlags,
1517 LPDIRECTDRAWCLIPPER *lplpDDClipper,
1518 IUnknown *pUnkOuter)
1521 return DDERR_NOTINITIALIZED;
1524 static HRESULT WINAPI
1525 Uninit_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags,
1526 LPPALETTEENTRY lpColorTable,
1527 LPDIRECTDRAWPALETTE *lplpDDPalette,
1528 IUnknown *pUnkOuter)
1530 return DDERR_NOTINITIALIZED;
1533 static HRESULT WINAPI
1534 Uninit_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface,
1535 LPDDSURFACEDESC2 lpDDSurfaceDesc,
1536 LPDIRECTDRAWSURFACE7 *lplpDDSurface,
1537 IUnknown *pUnkOuter)
1539 return DDERR_NOTINITIALIZED;
1542 static HRESULT WINAPI
1543 Uninit_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface,
1544 LPDIRECTDRAWSURFACE7 pSurf,
1545 LPDIRECTDRAWSURFACE7 *pDupSurf)
1548 return DDERR_NOTINITIALIZED;
1551 static HRESULT WINAPI
1552 Uninit_DirectDraw_EnumDisplayModes(LPDIRECTDRAW7 iface, DWORD dwFlags,
1553 LPDDSURFACEDESC2 lpDDSD,
1554 LPVOID context,
1555 LPDDENUMMODESCALLBACK2 cb)
1557 return DDERR_NOTINITIALIZED;
1560 static HRESULT WINAPI
1561 Uninit_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags,
1562 LPDDSURFACEDESC2 pDDSD, LPVOID context,
1563 LPDDENUMSURFACESCALLBACK7 cb)
1565 return DDERR_NOTINITIALIZED;
1568 static HRESULT WINAPI
1569 Uninit_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface)
1571 return DDERR_NOTINITIALIZED;
1574 static HRESULT WINAPI
1575 Uninit_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps,
1576 LPDDCAPS pHELCaps)
1578 return DDERR_NOTINITIALIZED;
1581 static HRESULT WINAPI
1582 Uninit_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface,
1583 LPDDSURFACEDESC2 pDDSD)
1585 return DDERR_NOTINITIALIZED;
1588 static HRESULT WINAPI
1589 Uninit_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes,
1590 LPDWORD pCodes)
1592 return DDERR_NOTINITIALIZED;
1595 static HRESULT WINAPI
1596 Uninit_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface,
1597 LPDIRECTDRAWSURFACE7 *pGDISurf)
1599 return DDERR_NOTINITIALIZED;
1602 static HRESULT WINAPI
1603 Uninit_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface, LPDWORD pdwFreq)
1605 return DDERR_NOTINITIALIZED;
1608 static HRESULT WINAPI
1609 Uninit_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD pdwScanLine)
1611 return DDERR_NOTINITIALIZED;
1614 static HRESULT WINAPI
1615 Uninit_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, PBOOL pbIsInVB)
1617 return DDERR_NOTINITIALIZED;
1620 static HRESULT WINAPI
1621 Uninit_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
1623 return DDERR_NOTINITIALIZED;
1626 static HRESULT WINAPI
1627 Uninit_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hWnd,
1628 DWORD dwFlags)
1630 return DDERR_NOTINITIALIZED;
1633 static HRESULT WINAPI
1634 Uninit_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
1635 DWORD dwHeight, DWORD dwBPP,
1636 DWORD dwRefreshRate, DWORD dwFlags)
1638 return DDERR_NOTINITIALIZED;
1641 static HRESULT WINAPI
1642 Uninit_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags,
1643 HANDLE hEvent)
1645 return DDERR_NOTINITIALIZED;
1648 static HRESULT WINAPI
1649 Uninit_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 pDDCaps,
1650 LPDWORD pdwTotal, LPDWORD pdwFree)
1652 return DDERR_NOTINITIALIZED;
1655 static HRESULT WINAPI
1656 Uninit_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hDC,
1657 LPDIRECTDRAWSURFACE7 *pSurf)
1659 return DDERR_NOTINITIALIZED;
1662 static HRESULT WINAPI
1663 Uninit_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface)
1665 return DDERR_NOTINITIALIZED;
1668 static HRESULT WINAPI
1669 Uninit_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface)
1671 return DDERR_NOTINITIALIZED;
1674 static HRESULT WINAPI
1675 Uninit_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface,
1676 LPDDDEVICEIDENTIFIER2 pDDDI,
1677 DWORD dwFlags)
1679 return DDERR_NOTINITIALIZED;
1682 static HRESULT WINAPI
1683 Uninit_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pszModes,
1684 DWORD cModes, DWORD dwFlags)
1686 return DDERR_NOTINITIALIZED;
1689 static HRESULT WINAPI
1690 Uninit_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface, DWORD dwFlags,
1691 LPDWORD pTimeout)
1693 return DDERR_NOTINITIALIZED;
1696 static const IDirectDraw7Vtbl Uninit_DirectDraw_VTable =
1698 Main_DirectDraw_QueryInterface,
1699 Main_DirectDraw_AddRef,
1700 Main_DirectDraw_Release,
1701 Uninit_DirectDraw_Compact,
1702 Uninit_DirectDraw_CreateClipper,
1703 Uninit_DirectDraw_CreatePalette,
1704 Uninit_DirectDraw_CreateSurface,
1705 Uninit_DirectDraw_DuplicateSurface,
1706 Uninit_DirectDraw_EnumDisplayModes,
1707 Uninit_DirectDraw_EnumSurfaces,
1708 Uninit_DirectDraw_FlipToGDISurface,
1709 Uninit_DirectDraw_GetCaps,
1710 Uninit_DirectDraw_GetDisplayMode,
1711 Uninit_DirectDraw_GetFourCCCodes,
1712 Uninit_DirectDraw_GetGDISurface,
1713 Uninit_DirectDraw_GetMonitorFrequency,
1714 Uninit_DirectDraw_GetScanLine,
1715 Uninit_DirectDraw_GetVerticalBlankStatus,
1716 Uninit_DirectDraw_Initialize,
1717 Uninit_DirectDraw_RestoreDisplayMode,
1718 Uninit_DirectDraw_SetCooperativeLevel,
1719 Uninit_DirectDraw_SetDisplayMode,
1720 Uninit_DirectDraw_WaitForVerticalBlank,
1721 Uninit_DirectDraw_GetAvailableVidMem,
1722 Uninit_DirectDraw_GetSurfaceFromDC,
1723 Uninit_DirectDraw_RestoreAllSurfaces,
1724 Uninit_DirectDraw_TestCooperativeLevel,
1725 Uninit_DirectDraw_GetDeviceIdentifier,
1726 Uninit_DirectDraw_StartModeTest,
1727 Uninit_DirectDraw_EvaluateMode