|  | /*		DirectDraw IDirectDraw interface (generic) | 
|  | * | 
|  | * Copyright 1997-2000 Marcus Meissner | 
|  | * Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff) | 
|  | * Copyright 2000-2001 TransGaming Technologies Inc. | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | * | 
|  | * NOTES | 
|  | * | 
|  | * WINE currently implements a very basic set of the DirectDraw functionality | 
|  | * in graphics/ddraw.c. This implementation uses either the XFree86-DGA extension | 
|  | * to get very fast access to the graphics card framebuffer and doublebuffering | 
|  | * features or Xlib, which is slower. | 
|  | * The implementation using XFree86-DGA is as fast as the MS equivalent for the | 
|  | * stuff that is implemented. | 
|  | * | 
|  | * Several applications already work, see below. | 
|  | * Problems of the implementation using XFree86-DGA: | 
|  | * | 
|  | *	- XFree86 cannot switch depth on the fly. | 
|  | *	  This is a problem with X and unavoidable. | 
|  | *	  Current solution is to pop up a MessageBox with an error for | 
|  | *	  mismatched parameters and advice the user to restart the X server | 
|  | *	  with the specified depth. | 
|  | *	- The rest of the functionality that has to be implemented will have | 
|  | *	  to be done in software and will be very slow. | 
|  | *	- This requires WINE to be run as root user so XF86DGA can mmap the | 
|  | *	  framebuffer into the addressspace of the process. | 
|  | *	- Blocks all other X windowed applications. | 
|  | * | 
|  | * This file contains all the interface functions that are shared between | 
|  | * all interfaces. Or better, it is a "common stub" library for the | 
|  | * IDirectDraw* objects | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <stdarg.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #define NONAMELESSUNION | 
|  | #define NONAMELESSSTRUCT | 
|  |  | 
|  | #include "winerror.h" | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.h" | 
|  | #include "ddraw.h" | 
|  | #include "d3d.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | #include "ddraw_private.h" | 
|  | #include "opengl_private.h" /* To have the D3D creation function */ | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(ddraw); | 
|  |  | 
|  | extern const IDirectDrawVtbl DDRAW_IDirectDraw_VTable; | 
|  | extern const IDirectDraw2Vtbl DDRAW_IDirectDraw2_VTable; | 
|  | extern const IDirectDraw4Vtbl DDRAW_IDirectDraw4_VTable; | 
|  |  | 
|  | static void DDRAW_UnsubclassWindow(IDirectDrawImpl* This); | 
|  |  | 
|  | static void Main_DirectDraw_DeleteSurfaces(IDirectDrawImpl* This); | 
|  | static void Main_DirectDraw_DeleteClippers(IDirectDrawImpl* This); | 
|  | static void Main_DirectDraw_DeletePalettes(IDirectDrawImpl* This); | 
|  | static void LosePrimarySurface(IDirectDrawImpl* This); | 
|  |  | 
|  | static INT32 allocate_memory(IDirectDrawImpl *This, DWORD mem) ; | 
|  | static void free_memory(IDirectDrawImpl *This, DWORD mem) ; | 
|  |  | 
|  |  | 
|  | static const char ddProp[] = "WINE_DDRAW_Property"; | 
|  |  | 
|  | /* Not called from the vtable. */ | 
|  | HRESULT Main_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex) | 
|  | { | 
|  | /* NOTE: The creator must use HEAP_ZERO_MEMORY or equivalent. */ | 
|  | This->ref = 1; | 
|  | This->ex = ex; | 
|  |  | 
|  | if (ex) This->local.dwLocalFlags |= DDRAWILCL_DIRECTDRAW7; | 
|  | This->local.dwProcessId = GetCurrentProcessId(); | 
|  |  | 
|  | This->final_release = Main_DirectDraw_final_release; | 
|  |  | 
|  | This->create_palette = Main_DirectDrawPalette_Create; | 
|  |  | 
|  | This->create_offscreen = Main_create_offscreen; | 
|  | This->create_texture   = Main_create_texture; | 
|  | This->create_zbuffer   = Main_create_zbuffer; | 
|  | /* There are no generic versions of create_{primary,backbuffer}. */ | 
|  |  | 
|  | ICOM_INIT_INTERFACE(This, IDirectDraw,  DDRAW_IDirectDraw_VTable); | 
|  | ICOM_INIT_INTERFACE(This, IDirectDraw2, DDRAW_IDirectDraw2_VTable); | 
|  | ICOM_INIT_INTERFACE(This, IDirectDraw4, DDRAW_IDirectDraw4_VTable); | 
|  | /* There is no generic implementation of IDD7 */ | 
|  |  | 
|  | /* This is for the moment here... */ | 
|  | This->free_memory = free_memory; | 
|  | This->allocate_memory = allocate_memory; | 
|  | This->total_vidmem = 64 * 1024 * 1024; | 
|  | This->available_vidmem = This->total_vidmem; | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | void Main_DirectDraw_final_release(IDirectDrawImpl* This) | 
|  | { | 
|  | if (IsWindow(This->window)) | 
|  | { | 
|  | if (GetPropA(This->window, ddProp)) | 
|  | DDRAW_UnsubclassWindow(This); | 
|  | else | 
|  | FIXME("this shouldn't happen, right?\n"); | 
|  | } | 
|  |  | 
|  | Main_DirectDraw_DeleteSurfaces(This); | 
|  | Main_DirectDraw_DeleteClippers(This); | 
|  | Main_DirectDraw_DeletePalettes(This); | 
|  | if (This->local.lpGbl && This->local.lpGbl->lpExclusiveOwner == &This->local) | 
|  | { | 
|  | This->local.lpGbl->lpExclusiveOwner = NULL; | 
|  | if (This->set_exclusive_mode) | 
|  | This->set_exclusive_mode(This, FALSE); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* There is no Main_DirectDraw_Create. */ | 
|  |  | 
|  | ULONG WINAPI Main_DirectDraw_AddRef(LPDIRECTDRAW7 iface) { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | ULONG ref = InterlockedIncrement(&This->ref); | 
|  |  | 
|  | TRACE("(%p)->() incrementing from %lu.\n", This, ref -1); | 
|  |  | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | ULONG WINAPI Main_DirectDraw_Release(LPDIRECTDRAW7 iface) { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | ULONG ref = InterlockedDecrement(&This->ref); | 
|  |  | 
|  | TRACE("(%p)->() decrementing from %lu.\n", This, ref +1); | 
|  |  | 
|  | if (ref == 0) | 
|  | { | 
|  | if (This->final_release != NULL) | 
|  | This->final_release(This); | 
|  |  | 
|  | /* We free the private. This is an artifact of the fact that I don't | 
|  | * have the destructors set up correctly. */ | 
|  | if (This->private != (This+1)) | 
|  | HeapFree(GetProcessHeap(), 0, This->private); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, This); | 
|  | } | 
|  |  | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI Main_DirectDraw_QueryInterface( | 
|  | LPDIRECTDRAW7 iface,REFIID refiid,LPVOID *obj | 
|  | ) { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(refiid), obj); | 
|  |  | 
|  | /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */ | 
|  | *obj = NULL; | 
|  |  | 
|  | if ( IsEqualGUID( &IID_IUnknown, refiid ) | 
|  | || IsEqualGUID( &IID_IDirectDraw7, refiid ) ) | 
|  | { | 
|  | *obj = ICOM_INTERFACE(This, IDirectDraw7); | 
|  | } | 
|  | else if ( IsEqualGUID( &IID_IDirectDraw, refiid ) ) | 
|  | { | 
|  | *obj = ICOM_INTERFACE(This, IDirectDraw); | 
|  | } | 
|  | else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) ) | 
|  | { | 
|  | *obj = ICOM_INTERFACE(This, IDirectDraw2); | 
|  | } | 
|  | else if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) ) | 
|  | { | 
|  | *obj = ICOM_INTERFACE(This, IDirectDraw4); | 
|  | } | 
|  | #ifdef HAVE_OPENGL | 
|  | else if ( IsEqualGUID( &IID_IDirect3D  , refiid ) || | 
|  | IsEqualGUID( &IID_IDirect3D2 , refiid ) || | 
|  | IsEqualGUID( &IID_IDirect3D3 , refiid ) || | 
|  | IsEqualGUID( &IID_IDirect3D7 , refiid ) ) | 
|  | { | 
|  | if (opengl_initialized) { | 
|  | HRESULT ret_value; | 
|  |  | 
|  | ret_value = direct3d_create(This); | 
|  | if (FAILED(ret_value)) return ret_value; | 
|  |  | 
|  | if ( IsEqualGUID( &IID_IDirect3D  , refiid ) ) { | 
|  | *obj = ICOM_INTERFACE(This, IDirect3D); | 
|  | TRACE(" returning Direct3D interface at %p.\n", *obj); | 
|  | } else if ( IsEqualGUID( &IID_IDirect3D2  , refiid ) ) { | 
|  | *obj = ICOM_INTERFACE(This, IDirect3D2); | 
|  | TRACE(" returning Direct3D2 interface at %p.\n", *obj); | 
|  | } else if ( IsEqualGUID( &IID_IDirect3D3  , refiid ) ) { | 
|  | *obj = ICOM_INTERFACE(This, IDirect3D3); | 
|  | TRACE(" returning Direct3D3 interface at %p.\n", *obj); | 
|  | } else { | 
|  | *obj = ICOM_INTERFACE(This, IDirect3D7); | 
|  | TRACE(" returning Direct3D7 interface at %p.\n", *obj); | 
|  | } | 
|  | } else { | 
|  | ERR("Application requests a Direct3D interface but dynamic OpenGL support loading failed !\n"); | 
|  | ERR("(%p)->(%s,%p): no interface\n",This,debugstr_guid(refiid),obj); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  | } | 
|  | #else | 
|  | else if ( IsEqualGUID( &IID_IDirect3D  , refiid ) || | 
|  | IsEqualGUID( &IID_IDirect3D2 , refiid ) || | 
|  | IsEqualGUID( &IID_IDirect3D3 , refiid ) || | 
|  | IsEqualGUID( &IID_IDirect3D7 , refiid ) ) | 
|  | { | 
|  | ERR("Application requests a Direct3D interface but OpenGL support not built-in !\n"); | 
|  | ERR("(%p)->(%s,%p): no interface\n",This,debugstr_guid(refiid),obj); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  | #endif | 
|  | else | 
|  | { | 
|  | FIXME("(%p)->(%s,%p): no interface\n",This,debugstr_guid(refiid),obj); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | IDirectDraw7_AddRef(iface); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /* MSDN: "not currently implemented". */ | 
|  | HRESULT WINAPI Main_DirectDraw_Compact(LPDIRECTDRAW7 iface) | 
|  | { | 
|  | TRACE("(%p)\n", iface); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI Main_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface, | 
|  | DWORD dwFlags, | 
|  | LPDIRECTDRAWCLIPPER *ppClipper, | 
|  | IUnknown *pUnkOuter) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)->(0x%lx, %p, %p)\n", iface, dwFlags, ppClipper, pUnkOuter); | 
|  |  | 
|  | hr = DirectDrawCreateClipper(dwFlags, ppClipper, pUnkOuter); | 
|  | if (FAILED(hr)) return hr; | 
|  |  | 
|  | /* dwFlags is passed twice, apparently an API wart. */ | 
|  | hr = IDirectDrawClipper_Initialize(*ppClipper, | 
|  | ICOM_INTERFACE(This, IDirectDraw), | 
|  | dwFlags); | 
|  | if (FAILED(hr)) | 
|  | { | 
|  | IDirectDrawClipper_Release(*ppClipper); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags, | 
|  | LPPALETTEENTRY palent, | 
|  | LPDIRECTDRAWPALETTE* ppPalette, | 
|  | LPUNKNOWN pUnknown) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | LPDIRECTDRAWPALETTE pPalette; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)->(%08lx,%p,%p,%p)\n",This,dwFlags,palent,ppPalette,pUnknown); | 
|  |  | 
|  | if (ppPalette == NULL) return E_POINTER; /* unchecked */ | 
|  | if (pUnknown != NULL) return CLASS_E_NOAGGREGATION; /* unchecked */ | 
|  |  | 
|  | hr = This->create_palette(This, dwFlags, &pPalette, pUnknown); | 
|  | if (FAILED(hr)) return hr; | 
|  |  | 
|  | hr = IDirectDrawPalette_SetEntries(pPalette, 0, 0, | 
|  | Main_DirectDrawPalette_Size(dwFlags), | 
|  | palent); | 
|  | if (FAILED(hr)) | 
|  | { | 
|  | IDirectDrawPalette_Release(pPalette); | 
|  | return hr; | 
|  | } | 
|  | else | 
|  | { | 
|  | *ppPalette = pPalette; | 
|  | return DD_OK; | 
|  | } | 
|  | } | 
|  |  | 
|  | HRESULT | 
|  | Main_create_offscreen(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD, | 
|  | LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter) | 
|  | { | 
|  | assert(pOuter == NULL); | 
|  |  | 
|  | return DIB_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter); | 
|  | } | 
|  |  | 
|  | HRESULT | 
|  | Main_create_texture(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD, | 
|  | LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter, | 
|  | DWORD dwMipMapLevel) | 
|  | { | 
|  | assert(pOuter == NULL); | 
|  |  | 
|  | return DIB_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter); | 
|  | } | 
|  |  | 
|  | HRESULT | 
|  | Main_create_zbuffer(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD, | 
|  | LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter) | 
|  | { | 
|  | assert(pOuter == NULL); | 
|  |  | 
|  | return FakeZBuffer_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter); | 
|  | } | 
|  |  | 
|  | /* Does the texture surface described in pDDSD have any smaller mipmaps? */ | 
|  | static BOOL more_mipmaps(const DDSURFACEDESC2 *pDDSD) | 
|  | { | 
|  | return ((pDDSD->dwFlags & DDSD_MIPMAPCOUNT) && pDDSD->u2.dwMipMapCount > 1 | 
|  | && (pDDSD->dwWidth > 1 || pDDSD->dwHeight > 1)); | 
|  | } | 
|  |  | 
|  | /* Create a texture surface along with any of its mipmaps. */ | 
|  | static HRESULT | 
|  | create_texture(IDirectDrawImpl* This, const DDSURFACEDESC2 *pDDSD, | 
|  | LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter) | 
|  | { | 
|  | DDSURFACEDESC2 ddsd; | 
|  | DWORD mipmap_level = 0; | 
|  | HRESULT hr; | 
|  |  | 
|  | assert(pUnkOuter == NULL); | 
|  |  | 
|  | /* is this check right? (pixelformat can be copied from primary) */ | 
|  | if ((pDDSD->dwFlags&(DDSD_HEIGHT|DDSD_WIDTH)) != (DDSD_HEIGHT|DDSD_WIDTH)) | 
|  | return DDERR_INVALIDPARAMS; | 
|  |  | 
|  | ddsd.dwSize = sizeof(ddsd); | 
|  | DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD); | 
|  |  | 
|  | if (!(ddsd.dwFlags & DDSD_PIXELFORMAT)) | 
|  | { | 
|  | ddsd.u4.ddpfPixelFormat = This->pixelformat; | 
|  | } | 
|  |  | 
|  | #ifdef HAVE_OPENGL | 
|  | /* We support for now only DXT1, DXT3 & DXT5 compressed texture formats... */ | 
|  | if ((ddsd.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) && | 
|  | (ddsd.u4.ddpfPixelFormat.dwFourCC != MAKE_FOURCC('D','X','T','1')) && | 
|  | (ddsd.u4.ddpfPixelFormat.dwFourCC != MAKE_FOURCC('D','X','T','3')) && | 
|  | (ddsd.u4.ddpfPixelFormat.dwFourCC != MAKE_FOURCC('D','X','T','5')) ) | 
|  | { | 
|  | return DDERR_INVALIDPIXELFORMAT; | 
|  | } | 
|  |  | 
|  | /* Check if we can really support DXT1, DXT3 & DXT5 */ | 
|  | if ((ddsd.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) && | 
|  | !GL_extensions.s3tc_compressed_texture && !s3tc_initialized) { | 
|  | static BOOLEAN user_warned = 0; | 
|  | if (user_warned == 0) { | 
|  | ERR("Trying to create DXT1, DXT3 or DXT5 texture which is not supported by the video card!!!\n"); | 
|  | ERR("However there is a library libtxc_dxtn.so that can be used to do the software decompression...\n"); | 
|  | user_warned = 1; | 
|  | } | 
|  | return DDERR_INVALIDPIXELFORMAT; | 
|  | } | 
|  | #else | 
|  | if (ddsd.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) | 
|  | { | 
|  | return DDERR_INVALIDPIXELFORMAT; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if ((ddsd.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) && !(ddsd.dwFlags & DDSD_LINEARSIZE)) | 
|  | { | 
|  | int size = 0; | 
|  | int width = ddsd.dwWidth; | 
|  | int height = ddsd.dwHeight; | 
|  | switch(ddsd.u4.ddpfPixelFormat.dwFourCC) { | 
|  | case MAKE_FOURCC('D','X','T','1'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 8; break; | 
|  | case MAKE_FOURCC('D','X','T','3'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 16; break; | 
|  | case MAKE_FOURCC('D','X','T','5'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 16; break; | 
|  | default: FIXME("FOURCC not supported\n"); break; | 
|  | } | 
|  | ddsd.u1.dwLinearSize = size; | 
|  | ddsd.dwFlags |= DDSD_LINEARSIZE; | 
|  | } else if (!(ddsd.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) && !(ddsd.dwFlags & DDSD_PITCH)) { | 
|  | ddsd.u1.lPitch = DDRAW_width_bpp_to_pitch(ddsd.dwWidth, GET_BPP(ddsd)*8); | 
|  | ddsd.dwFlags |= DDSD_PITCH; | 
|  | } | 
|  |  | 
|  | if((ddsd.ddsCaps.dwCaps & DDSCAPS_MIPMAP) && | 
|  | !(ddsd.dwFlags & DDSD_MIPMAPCOUNT)) | 
|  | { | 
|  | if(ddsd.ddsCaps.dwCaps & DDSCAPS_COMPLEX) | 
|  | { | 
|  | /* Undocumented feature: if DDSCAPS_MIPMAP and DDSCAPS_COMPLEX are | 
|  | * both set, but mipmap count isn't given, as many mipmap levels | 
|  | * as necessary are created to get down to a size where either | 
|  | * the width or the height of the texture is 1. | 
|  | * | 
|  | * This is needed by Anarchy Online. */ | 
|  | DWORD min = ddsd.dwWidth < ddsd.dwHeight ? | 
|  | ddsd.dwWidth : ddsd.dwHeight; | 
|  | ddsd.u2.dwMipMapCount = 0; | 
|  | while( min ) | 
|  | { | 
|  | ddsd.u2.dwMipMapCount++; | 
|  | min >>= 1; | 
|  | } | 
|  | } | 
|  | else | 
|  | /* Create a single mipmap. */ | 
|  | ddsd.u2.dwMipMapCount = 1; | 
|  |  | 
|  | ddsd.dwFlags |= DDSD_MIPMAPCOUNT; | 
|  | } | 
|  |  | 
|  | ddsd.dwFlags |= DDSD_PIXELFORMAT; | 
|  |  | 
|  | hr = This->create_texture(This, &ddsd, ppSurf, pUnkOuter, mipmap_level); | 
|  | if (FAILED(hr)) return hr; | 
|  |  | 
|  | if (This->d3d_private) This->d3d_create_texture(This, ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurf), TRUE, | 
|  | ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurf)); | 
|  |  | 
|  | /* Create attached mipmaps if required. */ | 
|  | if (more_mipmaps(&ddsd)) | 
|  | { | 
|  | LPDIRECTDRAWSURFACE7 mipmap; | 
|  | LPDIRECTDRAWSURFACE7 prev_mipmap; | 
|  | DDSURFACEDESC2 mipmap_surface_desc; | 
|  |  | 
|  | prev_mipmap = *ppSurf; | 
|  | IDirectDrawSurface7_AddRef(prev_mipmap); | 
|  | mipmap_surface_desc = ddsd; | 
|  | mipmap_surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL; | 
|  |  | 
|  | while (more_mipmaps(&mipmap_surface_desc)) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *mipmap_impl; | 
|  |  | 
|  | mipmap_level++; | 
|  | mipmap_surface_desc.u2.dwMipMapCount--; | 
|  |  | 
|  | if (mipmap_surface_desc.dwWidth > 1) | 
|  | mipmap_surface_desc.dwWidth /= 2; | 
|  |  | 
|  | if (mipmap_surface_desc.dwHeight > 1) | 
|  | mipmap_surface_desc.dwHeight /= 2; | 
|  |  | 
|  | if (mipmap_surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) { | 
|  | int size = 0; | 
|  | int width = mipmap_surface_desc.dwWidth; | 
|  | int height = mipmap_surface_desc.dwHeight; | 
|  | switch(mipmap_surface_desc.u4.ddpfPixelFormat.dwFourCC) { | 
|  | case MAKE_FOURCC('D','X','T','1'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 8; break; | 
|  | case MAKE_FOURCC('D','X','T','3'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 16; break; | 
|  | case MAKE_FOURCC('D','X','T','5'): size = ((width+3)&~3) * ((height+3)&~3) / 16 * 16; break; | 
|  | default: FIXME("FOURCC not supported\n"); break; | 
|  | } | 
|  | mipmap_surface_desc.u1.dwLinearSize = size; | 
|  | } else { | 
|  | ddsd.u1.lPitch = DDRAW_width_bpp_to_pitch(ddsd.dwWidth, GET_BPP(ddsd)*8); | 
|  | mipmap_surface_desc.u1.lPitch | 
|  | = DDRAW_width_bpp_to_pitch(mipmap_surface_desc.dwWidth, | 
|  | GET_BPP(ddsd)*8); | 
|  | } | 
|  |  | 
|  | hr = This->create_texture(This, &mipmap_surface_desc, &mipmap, | 
|  | pUnkOuter, mipmap_level); | 
|  | if (FAILED(hr)) | 
|  | { | 
|  | IDirectDrawSurface7_Release(prev_mipmap); | 
|  | IDirectDrawSurface7_Release(*ppSurf); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /* This is needed for delayed mipmap creation */ | 
|  | mipmap_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, mipmap); | 
|  | mipmap_impl->mip_main = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurf); | 
|  | mipmap_impl->mipmap_level = mipmap_level; | 
|  |  | 
|  | if (This->d3d_private) This->d3d_create_texture(This, ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, mipmap), TRUE, | 
|  | ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurf)); | 
|  |  | 
|  | IDirectDrawSurface7_AddAttachedSurface(prev_mipmap, mipmap); | 
|  | IDirectDrawSurface7_Release(prev_mipmap); | 
|  | prev_mipmap = mipmap; | 
|  | } | 
|  |  | 
|  | IDirectDrawSurface7_Release(prev_mipmap); | 
|  | } | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | /* Creates a primary surface and any indicated backbuffers. */ | 
|  | static HRESULT | 
|  | create_primary(IDirectDrawImpl* This, LPDDSURFACEDESC2 pDDSD, | 
|  | LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter) | 
|  | { | 
|  | DDSURFACEDESC2 ddsd; | 
|  | HRESULT hr; | 
|  |  | 
|  | assert(pUnkOuter == NULL); | 
|  |  | 
|  | if (This->primary_surface != NULL) | 
|  | return DDERR_PRIMARYSURFACEALREADYEXISTS; | 
|  |  | 
|  | /* as documented (what about pitch?) */ | 
|  | if (pDDSD->dwFlags & (DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT)) | 
|  | return DDERR_INVALIDPARAMS; | 
|  |  | 
|  | ddsd.dwSize = sizeof(ddsd); | 
|  | DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD); | 
|  | ddsd.dwFlags |= DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT; | 
|  | ddsd.dwHeight = This->height; | 
|  | ddsd.dwWidth = This->width; | 
|  | ddsd.u1.lPitch = This->pitch; | 
|  | ddsd.u4.ddpfPixelFormat = This->pixelformat; | 
|  | ddsd.ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | 
|  | | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER; | 
|  |  | 
|  | if ((ddsd.dwFlags & DDSD_BACKBUFFERCOUNT) && ddsd.dwBackBufferCount > 0) | 
|  | ddsd.ddsCaps.dwCaps |= DDSCAPS_FLIP; | 
|  |  | 
|  | hr = This->create_primary(This, &ddsd, ppSurf, pUnkOuter); | 
|  | if (FAILED(hr)) return hr; | 
|  |  | 
|  | if (ddsd.dwFlags & DDSD_BACKBUFFERCOUNT) | 
|  | { | 
|  | IDirectDrawSurfaceImpl* primary; | 
|  | LPDIRECTDRAWSURFACE7 pPrev; | 
|  | DWORD i; | 
|  |  | 
|  | ddsd.dwFlags &= ~DDSD_BACKBUFFERCOUNT; | 
|  | ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | 
|  | | DDSCAPS_BACKBUFFER | DDSCAPS_FRONTBUFFER); | 
|  |  | 
|  | primary = ICOM_OBJECT(IDirectDrawSurfaceImpl,IDirectDrawSurface7, | 
|  | *ppSurf); | 
|  | pPrev = *ppSurf; | 
|  | IDirectDrawSurface7_AddRef(pPrev); | 
|  |  | 
|  | for (i=0; i < ddsd.dwBackBufferCount; i++) | 
|  | { | 
|  | LPDIRECTDRAWSURFACE7 pBack; | 
|  |  | 
|  | if (i == 0) | 
|  | ddsd.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER; | 
|  | else | 
|  | ddsd.ddsCaps.dwCaps &= ~DDSCAPS_BACKBUFFER; | 
|  |  | 
|  | hr = This->create_backbuffer(This, &ddsd, &pBack, pUnkOuter, | 
|  | primary); | 
|  |  | 
|  | if (FAILED(hr)) | 
|  | { | 
|  | IDirectDraw7_Release(pPrev); | 
|  | IDirectDraw7_Release(*ppSurf); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | IDirectDrawSurface7_AddAttachedSurface(pPrev, pBack); | 
|  | IDirectDrawSurface7_Release(pPrev); | 
|  | pPrev = pBack; | 
|  | } | 
|  |  | 
|  | IDirectDrawSurface7_Release(pPrev); | 
|  | } | 
|  |  | 
|  | This->primary_surface = (IDirectDrawSurfaceImpl *)*ppSurf; | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT | 
|  | create_offscreen(IDirectDrawImpl* This, LPDDSURFACEDESC2 pDDSD, | 
|  | LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter) | 
|  | { | 
|  | DDSURFACEDESC2 ddsd; | 
|  | HRESULT hr; | 
|  |  | 
|  | /* is this check right? (pixelformat can be copied from primary) */ | 
|  | if ((pDDSD->dwFlags&(DDSD_HEIGHT|DDSD_WIDTH)) != (DDSD_HEIGHT|DDSD_WIDTH)) | 
|  | return DDERR_INVALIDPARAMS; | 
|  |  | 
|  | ddsd.dwSize = sizeof(ddsd); | 
|  | DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD); | 
|  |  | 
|  | if (!(ddsd.dwFlags & DDSD_PIXELFORMAT)) | 
|  | { | 
|  | ddsd.u4.ddpfPixelFormat = This->pixelformat; | 
|  | } | 
|  |  | 
|  | if (!(ddsd.dwFlags & DDSD_PITCH)) | 
|  | { | 
|  | ddsd.u1.lPitch = DDRAW_width_bpp_to_pitch(ddsd.dwWidth, | 
|  | GET_BPP(ddsd)*8); | 
|  | } | 
|  |  | 
|  | ddsd.dwFlags |= DDSD_PITCH | DDSD_PIXELFORMAT; | 
|  |  | 
|  | hr = This->create_offscreen(This, &ddsd, ppSurf, pUnkOuter); | 
|  | if (FAILED(hr)) return hr; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD, | 
|  | LPDIRECTDRAWSURFACE7 *ppSurf, | 
|  | IUnknown *pUnkOuter) | 
|  | { | 
|  | HRESULT hr; | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p,%p,%p)\n",This,pDDSD,ppSurf,pUnkOuter); | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE("Requesting surface desc :\n"); | 
|  | DDRAW_dump_surface_desc(pDDSD); | 
|  | } | 
|  |  | 
|  | if (pUnkOuter != NULL) { | 
|  | FIXME("outer != NULL?\n"); | 
|  | return CLASS_E_NOAGGREGATION; /* unchecked */ | 
|  | } | 
|  |  | 
|  | if (!(pDDSD->dwFlags & DDSD_CAPS)) { | 
|  | /* DVIDEO.DLL does forget the DDSD_CAPS flag ... *sigh* */ | 
|  | pDDSD->dwFlags |= DDSD_CAPS; | 
|  | } | 
|  | if (pDDSD->ddsCaps.dwCaps == 0) { | 
|  | /* This has been checked on real Windows */ | 
|  | pDDSD->ddsCaps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY; | 
|  | } | 
|  |  | 
|  | if (pDDSD->ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD) { | 
|  | /* If the surface is of the 'alloconload' type, ignore the LPSURFACE field */ | 
|  | pDDSD->dwFlags &= ~DDSD_LPSURFACE; | 
|  | } | 
|  |  | 
|  | if ((pDDSD->dwFlags & DDSD_LPSURFACE) && (pDDSD->lpSurface == NULL)) { | 
|  | /* Frank Herbert's Dune specifies a null pointer for the surface, ignore the LPSURFACE field */ | 
|  | WARN("Null surface pointer specified, ignore it!\n"); | 
|  | pDDSD->dwFlags &= ~DDSD_LPSURFACE; | 
|  | } | 
|  |  | 
|  | if (ppSurf == NULL) { | 
|  | FIXME("You want to get back a surface? Don't give NULL ptrs!\n"); | 
|  | return E_POINTER; /* unchecked */ | 
|  | } | 
|  |  | 
|  | if (pDDSD->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) | 
|  | { | 
|  | /* create primary surface & backbuffers */ | 
|  | hr = create_primary(This, pDDSD, ppSurf, pUnkOuter); | 
|  | } | 
|  | else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_BACKBUFFER) | 
|  | { | 
|  | /* create backbuffer surface */ | 
|  | hr = This->create_backbuffer(This, pDDSD, ppSurf, pUnkOuter, NULL); | 
|  | } | 
|  | else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_TEXTURE) | 
|  | { | 
|  | /* create texture */ | 
|  | hr = create_texture(This, pDDSD, ppSurf, pUnkOuter); | 
|  | } | 
|  | else if ( (pDDSD->ddsCaps.dwCaps & DDSCAPS_ZBUFFER) && | 
|  | !(pDDSD->ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN)) /* Support DDSCAPS_SYSTEMMEMORY */ | 
|  | { | 
|  | /* create z-buffer */ | 
|  | hr = This->create_zbuffer(This, pDDSD, ppSurf, pUnkOuter); | 
|  | } | 
|  | else if ((pDDSD->ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN) || | 
|  | (pDDSD->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)) /* No difference in Wine right now */ | 
|  | { | 
|  | /* create offscreenplain surface */ | 
|  | hr = create_offscreen(This, pDDSD, ppSurf, pUnkOuter); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Otherwise, assume offscreenplain surface */ | 
|  | TRACE("App didn't request a valid surface type - assuming offscreenplain\n"); | 
|  | hr = create_offscreen(This, pDDSD, ppSurf, pUnkOuter); | 
|  | } | 
|  |  | 
|  | if (FAILED(hr)) { | 
|  | FIXME("failed surface creation with code 0x%08lx\n",hr); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface, LPDIRECTDRAWSURFACE7 src, | 
|  | LPDIRECTDRAWSURFACE7* dst) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  |  | 
|  | IDirectDrawSurfaceImpl *pSrc = ICOM_OBJECT(IDirectDrawSurfaceImpl, | 
|  | IDirectDrawSurface7, src); | 
|  |  | 
|  | TRACE("(%p)->(%p,%p)\n",This,src,dst); | 
|  |  | 
|  | return pSrc->duplicate_surface(pSrc, dst); | 
|  | } | 
|  |  | 
|  | /* EnumDisplayModes */ | 
|  |  | 
|  | BOOL Main_DirectDraw_DDPIXELFORMAT_Match(const DDPIXELFORMAT *requested, | 
|  | const DDPIXELFORMAT *provided) | 
|  | { | 
|  | /* Some flags must be present in both or neither for a match. */ | 
|  | static const DWORD must_match = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 | 
|  | | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_FOURCC | 
|  | | DDPF_ZBUFFER | DDPF_STENCILBUFFER; | 
|  |  | 
|  | if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags) | 
|  | return FALSE; | 
|  |  | 
|  | if ((requested->dwFlags & must_match) != (provided->dwFlags & must_match)) | 
|  | return FALSE; | 
|  |  | 
|  | if (requested->dwFlags & DDPF_FOURCC) | 
|  | if (requested->dwFourCC != provided->dwFourCC) | 
|  | return FALSE; | 
|  |  | 
|  | if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_ALPHA | 
|  | |DDPF_LUMINANCE|DDPF_BUMPDUDV)) | 
|  | if (requested->u1.dwRGBBitCount != provided->u1.dwRGBBitCount) | 
|  | return FALSE; | 
|  |  | 
|  | if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER | 
|  | |DDPF_LUMINANCE|DDPF_BUMPDUDV)) | 
|  | if (requested->u2.dwRBitMask != provided->u2.dwRBitMask) | 
|  | return FALSE; | 
|  |  | 
|  | if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_BUMPDUDV)) | 
|  | if (requested->u3.dwGBitMask != provided->u3.dwGBitMask) | 
|  | return FALSE; | 
|  |  | 
|  | /* I could be wrong about the bumpmapping. MSDN docs are vague. */ | 
|  | if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER | 
|  | |DDPF_BUMPDUDV)) | 
|  | if (requested->u4.dwBBitMask != provided->u4.dwBBitMask) | 
|  | return FALSE; | 
|  |  | 
|  | if (requested->dwFlags & (DDPF_ALPHAPIXELS|DDPF_ZPIXELS)) | 
|  | if (requested->u5.dwRGBAlphaBitMask != provided->u5.dwRGBAlphaBitMask) | 
|  | return FALSE; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | BOOL Main_DirectDraw_DDSD_Match(const DDSURFACEDESC2* requested, | 
|  | const DDSURFACEDESC2* provided) | 
|  | { | 
|  | struct compare_info | 
|  | { | 
|  | DWORD flag; | 
|  | ptrdiff_t offset; | 
|  | size_t size; | 
|  | }; | 
|  |  | 
|  | #define CMP(FLAG, FIELD)				\ | 
|  | { DDSD_##FLAG, offsetof(DDSURFACEDESC2, FIELD),	\ | 
|  | sizeof(((DDSURFACEDESC2 *)(NULL))->FIELD) } | 
|  |  | 
|  | static const struct compare_info compare[] = { | 
|  | CMP(ALPHABITDEPTH, dwAlphaBitDepth), | 
|  | CMP(BACKBUFFERCOUNT, dwBackBufferCount), | 
|  | CMP(CAPS, ddsCaps), | 
|  | CMP(CKDESTBLT, ddckCKDestBlt), | 
|  | CMP(CKDESTOVERLAY, u3.ddckCKDestOverlay), | 
|  | CMP(CKSRCBLT, ddckCKSrcBlt), | 
|  | CMP(CKSRCOVERLAY, ddckCKSrcOverlay), | 
|  | CMP(HEIGHT, dwHeight), | 
|  | CMP(LINEARSIZE, u1.dwLinearSize), | 
|  | CMP(LPSURFACE, lpSurface), | 
|  | CMP(MIPMAPCOUNT, u2.dwMipMapCount), | 
|  | CMP(PITCH, u1.lPitch), | 
|  | /* PIXELFORMAT: manual */ | 
|  | CMP(REFRESHRATE, u2.dwRefreshRate), | 
|  | CMP(TEXTURESTAGE, dwTextureStage), | 
|  | CMP(WIDTH, dwWidth), | 
|  | /* ZBUFFERBITDEPTH: "obsolete" */ | 
|  | }; | 
|  |  | 
|  | #undef CMP | 
|  |  | 
|  | unsigned int i; | 
|  |  | 
|  | if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags) | 
|  | return FALSE; | 
|  |  | 
|  | for (i=0; i < sizeof(compare)/sizeof(compare[0]); i++) | 
|  | { | 
|  | if (requested->dwFlags & compare[i].flag | 
|  | && memcmp((const char *)provided + compare[i].offset, | 
|  | (const char *)requested + compare[i].offset, | 
|  | compare[i].size) != 0) | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if (requested->dwFlags & DDSD_PIXELFORMAT) | 
|  | { | 
|  | if (!Main_DirectDraw_DDPIXELFORMAT_Match(&requested->u4.ddpfPixelFormat, | 
|  | &provided->u4.ddpfPixelFormat)) | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | #define DDENUMSURFACES_SEARCHTYPE (DDENUMSURFACES_CANBECREATED|DDENUMSURFACES_DOESEXIST) | 
|  | #define DDENUMSURFACES_MATCHTYPE (DDENUMSURFACES_ALL|DDENUMSURFACES_MATCH|DDENUMSURFACES_NOMATCH) | 
|  |  | 
|  | /* This should be extended so that it can be used by | 
|  | * IDirectDrawSurface7::EnumAttachedSurfaces. */ | 
|  | HRESULT | 
|  | Main_DirectDraw_EnumExistingSurfaces(IDirectDrawImpl *This, DWORD dwFlags, | 
|  | LPDDSURFACEDESC2 lpDDSD2, LPVOID context, | 
|  | LPDDENUMSURFACESCALLBACK7 callback) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *surf; | 
|  | BOOL all, nomatch; | 
|  |  | 
|  | /* A NULL lpDDSD2 is permitted if we are enumerating all surfaces anyway */ | 
|  | if (lpDDSD2 == NULL && !(dwFlags & DDENUMSURFACES_ALL)) | 
|  | return DDERR_INVALIDPARAMS; | 
|  |  | 
|  | all = dwFlags & DDENUMSURFACES_ALL; | 
|  | nomatch = dwFlags & DDENUMSURFACES_NOMATCH; | 
|  |  | 
|  | for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw) | 
|  | { | 
|  | if (all | 
|  | || (nomatch != Main_DirectDraw_DDSD_Match(lpDDSD2, | 
|  | &surf->surface_desc))) | 
|  | { | 
|  | LPDIRECTDRAWSURFACE7 surface = ICOM_INTERFACE(surf, | 
|  | IDirectDrawSurface7); | 
|  |  | 
|  | /* BOGUS! Violates COM rules, but MSDN says so. */ | 
|  | IDirectDrawSurface7_AddRef(surface); | 
|  |  | 
|  | if (callback(surface, &surf->surface_desc, context) | 
|  | == DDENUMRET_CANCEL) | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | /* I really don't understand how this is supposed to work. | 
|  | * We only consider dwHeight, dwWidth and ddpfPixelFormat.dwFlags. */ | 
|  | HRESULT | 
|  | Main_DirectDraw_EnumCreateableSurfaces(IDirectDrawImpl *This, DWORD dwFlags, | 
|  | LPDDSURFACEDESC2 lpDDSD2, | 
|  | LPVOID context, | 
|  | LPDDENUMSURFACESCALLBACK7 callback) | 
|  | { | 
|  | FIXME("This isn't going to work.\n"); | 
|  |  | 
|  | if ((dwFlags & DDENUMSURFACES_MATCHTYPE) != DDENUMSURFACES_MATCH) | 
|  | return DDERR_INVALIDPARAMS; | 
|  |  | 
|  | /* TODO: implement this. | 
|  | * Does this work before SCL is called? | 
|  | * Does it only consider off-screen surfaces? | 
|  | */ | 
|  |  | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | /* For unsigned x. 0 is not a power of 2. */ | 
|  | #define IS_POW_2(x) (((x) & ((x) - 1)) == 0) | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags, | 
|  | LPDDSURFACEDESC2 lpDDSD2, LPVOID context, | 
|  | LPDDENUMSURFACESCALLBACK7 callback) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | TRACE("(%p)->(0x%lx, %p, %p, %p)\n", iface, dwFlags, lpDDSD2, context, | 
|  | callback); | 
|  |  | 
|  | if (callback == NULL) | 
|  | return DDERR_INVALIDPARAMS; | 
|  |  | 
|  | if (dwFlags & ~(DDENUMSURFACES_SEARCHTYPE|DDENUMSURFACES_MATCHTYPE)) | 
|  | return DDERR_INVALIDPARAMS; | 
|  |  | 
|  | if (!IS_POW_2(dwFlags & DDENUMSURFACES_SEARCHTYPE) | 
|  | || !IS_POW_2(dwFlags & DDENUMSURFACES_MATCHTYPE)) | 
|  | return DDERR_INVALIDPARAMS; | 
|  |  | 
|  | if (dwFlags & DDENUMSURFACES_DOESEXIST) | 
|  | { | 
|  | return Main_DirectDraw_EnumExistingSurfaces(This, dwFlags, lpDDSD2, | 
|  | context, callback); | 
|  | } | 
|  | else | 
|  | { | 
|  | return Main_DirectDraw_EnumCreateableSurfaces(This, dwFlags, lpDDSD2, | 
|  | context, callback); | 
|  | } | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface,DWORD a,DWORD* b) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | FIXME("(%p)->() stub\n", This); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | TRACE("(%p)->()\n",This); | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps, | 
|  | LPDDCAPS pHELCaps) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | TRACE("(%p,%p,%p)\n",This,pDriverCaps,pHELCaps); | 
|  | if (pDriverCaps != NULL) { | 
|  | DD_STRUCT_COPY_BYSIZE(pDriverCaps,&This->caps); | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE("Driver Caps : \n"); | 
|  | DDRAW_dump_DDCAPS(pDriverCaps); | 
|  | } | 
|  | } | 
|  | if (pHELCaps != NULL) { | 
|  | DD_STRUCT_COPY_BYSIZE(pHELCaps,&This->caps); | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE("HEL Caps : \n"); | 
|  | DDRAW_dump_DDCAPS(pHELCaps); | 
|  | } | 
|  | } | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | /* GetCaps */ | 
|  | /* GetDeviceIdentifier */ | 
|  | /* GetDIsplayMode */ | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes, | 
|  | LPDWORD pCodes) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | if (*pNumCodes) { | 
|  | *pNumCodes=0; | 
|  | } | 
|  | FIXME("(%p,%p,%p), stub\n",This,pNumCodes,pCodes); | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface, | 
|  | LPDIRECTDRAWSURFACE7 *lplpGDIDDSSurface) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | TRACE("(%p)->(%p)\n", This, lplpGDIDDSSurface); | 
|  | TRACE("returning primary (%p)\n", This->primary_surface); | 
|  | *lplpGDIDDSSurface = ICOM_INTERFACE(This->primary_surface, IDirectDrawSurface7); | 
|  | if (*lplpGDIDDSSurface) | 
|  | IDirectDrawSurface7_AddRef(*lplpGDIDDSSurface); | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface,LPDWORD freq) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | FIXME("(%p)->(%p) returns 60 Hz always\n",This,freq); | 
|  | *freq = 60*100; /* 60 Hz */ | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD lpdwScanLine) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | static BOOL hide; | 
|  |  | 
|  | /* Since this method is called often, show the fixme only once */ | 
|  | if (!hide) { | 
|  | FIXME("(%p)->(%p) semi-stub\n", This, lpdwScanLine); | 
|  | hide = TRUE; | 
|  | } | 
|  |  | 
|  | /* Fake the line sweeping of the monitor */ | 
|  | /* FIXME: We should synchronize with a source to keep the refresh rate */ | 
|  | *lpdwScanLine = This->cur_scanline++; | 
|  | /* Assume 20 scan lines in the vertical blank */ | 
|  | if (This->cur_scanline >= This->height + 20) | 
|  | This->cur_scanline = 0; | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hdc, | 
|  | LPDIRECTDRAWSURFACE7 *lpDDS) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | FIXME("(%p)->(%p,%p)\n", This, hdc, lpDDS); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, LPBOOL status) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | TRACE("(%p)->(%p)\n",This,status); | 
|  | *status = TRUE; | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | /* If we were not initialised then Uninit_Main_IDirectDraw7_Initialize would | 
|  | * have been called instead. */ | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID lpGuid) | 
|  | { | 
|  | TRACE("(%p)->(%s)\n", iface, debugstr_guid(lpGuid)); | 
|  |  | 
|  | return DDERR_ALREADYINITIALIZED; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | IDirectDrawSurfaceImpl* surf; | 
|  |  | 
|  | TRACE("(%p)->()\n", This); | 
|  |  | 
|  | for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw) | 
|  | IDirectDrawSurface7_Restore(ICOM_INTERFACE(surf, IDirectDrawSurface7)); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | static void DDRAW_SubclassWindow(IDirectDrawImpl* This) | 
|  | { | 
|  | /* Well we don't actually subclass the window yet. */ | 
|  | SetPropA(This->window, ddProp, This); | 
|  | } | 
|  |  | 
|  | static void DDRAW_UnsubclassWindow(IDirectDrawImpl* This) | 
|  | { | 
|  | RemovePropA(This->window, ddProp); | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hwnd, | 
|  | DWORD cooplevel) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  |  | 
|  | FIXME("(%p)->(%p,%08lx)\n",This,hwnd,cooplevel); | 
|  | DDRAW_dump_cooperativelevel(cooplevel); | 
|  |  | 
|  | /* Makes realMYST test happy. */ | 
|  | if (This->cooperative_level == cooplevel | 
|  | && This->window == hwnd) | 
|  | return DD_OK; | 
|  |  | 
|  | /* XXX "It cannot be reset while the process has surfaces or palettes | 
|  | * created." Otherwise the window can be changed??? | 
|  | * | 
|  | * This appears to be wrong - comment it out for now. | 
|  | if (This->window) | 
|  | return DDERR_HWNDALREADYSET; | 
|  | */ | 
|  |  | 
|  | if (!(cooplevel & (DDSCL_EXCLUSIVE|DDSCL_NORMAL))) | 
|  | return DDERR_INVALIDPARAMS; | 
|  |  | 
|  | This->window = hwnd; | 
|  | This->cooperative_level = cooplevel; | 
|  |  | 
|  | This->local.hWnd = (ULONG_PTR)hwnd; | 
|  | This->local.dwLocalFlags |= DDRAWILCL_SETCOOPCALLED; | 
|  | /* not entirely sure about these */ | 
|  | if (cooplevel & DDSCL_EXCLUSIVE)     This->local.dwLocalFlags |= DDRAWILCL_HASEXCLUSIVEMODE; | 
|  | if (cooplevel & DDSCL_FULLSCREEN)    This->local.dwLocalFlags |= DDRAWILCL_ISFULLSCREEN; | 
|  | if (cooplevel & DDSCL_ALLOWMODEX)    This->local.dwLocalFlags |= DDRAWILCL_ALLOWMODEX; | 
|  | if (cooplevel & DDSCL_MULTITHREADED) This->local.dwLocalFlags |= DDRAWILCL_MULTITHREADED; | 
|  | if (cooplevel & DDSCL_FPUSETUP)      This->local.dwLocalFlags |= DDRAWILCL_FPUSETUP; | 
|  | if (cooplevel & DDSCL_FPUPRESERVE)   This->local.dwLocalFlags |= DDRAWILCL_FPUPRESERVE; | 
|  |  | 
|  | if (This->local.lpGbl) { | 
|  | /* assume that this app is the active app (in wine, there's | 
|  | * probably only one app per global ddraw object anyway) */ | 
|  | if (cooplevel & DDSCL_EXCLUSIVE) This->local.lpGbl->lpExclusiveOwner = &This->local; | 
|  | else if (This->local.lpGbl->lpExclusiveOwner == &This->local) | 
|  | This->local.lpGbl->lpExclusiveOwner = NULL; | 
|  | if (This->set_exclusive_mode) | 
|  | This->set_exclusive_mode(This, (cooplevel & DDSCL_EXCLUSIVE) != 0); | 
|  | } | 
|  |  | 
|  | ShowWindow(hwnd, SW_SHOW); | 
|  |  | 
|  | DDRAW_SubclassWindow(This); | 
|  |  | 
|  | /* TODO Does it also get resized to the current screen size? */ | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth, | 
|  | DWORD dwHeight, LONG lPitch, | 
|  | DWORD dwRefreshRate, DWORD dwFlags, | 
|  | const DDPIXELFORMAT* pixelformat) | 
|  | { | 
|  | short screenX; | 
|  | short screenY; | 
|  |  | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->SetDisplayMode(%ld,%ld)\n",This,dwWidth,dwHeight); | 
|  |  | 
|  | if (!(This->cooperative_level & DDSCL_EXCLUSIVE)) | 
|  | return DDERR_NOEXCLUSIVEMODE; | 
|  |  | 
|  | if (!IsWindow(This->window)) | 
|  | return DDERR_GENERIC; /* unchecked */ | 
|  |  | 
|  | LosePrimarySurface(This); | 
|  |  | 
|  | screenX = GetSystemMetrics(SM_CXSCREEN); | 
|  | screenY = GetSystemMetrics(SM_CYSCREEN); | 
|  |  | 
|  | This->width = dwWidth; | 
|  | This->height = dwHeight; | 
|  | This->pitch = lPitch; | 
|  | This->pixelformat = *pixelformat; | 
|  |  | 
|  | /* Position the window in the center of the screen - don't center for now */ | 
|  | /* MoveWindow(This->window, (screenX-dwWidth)/2, (screenY-dwHeight)/2, | 
|  | dwWidth, dwHeight, TRUE);*/ | 
|  | MoveWindow(This->window, 0, 0, dwWidth, dwHeight, TRUE); | 
|  |  | 
|  | SetFocus(This->window); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)\n",This); | 
|  | if (!(This->cooperative_level & DDSCL_EXCLUSIVE)) | 
|  | return DDERR_NOEXCLUSIVEMODE; | 
|  |  | 
|  | /* Lose the primary surface if the resolution changes. */ | 
|  | if (This->orig_width != This->width || This->orig_height != This->height | 
|  | || This->orig_pitch != This->pitch | 
|  | || This->orig_pixelformat.dwFlags != This->pixelformat.dwFlags | 
|  | || !Main_DirectDraw_DDPIXELFORMAT_Match(&This->pixelformat, | 
|  | &This->orig_pixelformat)) | 
|  | { | 
|  | LosePrimarySurface(This); | 
|  | } | 
|  |  | 
|  | /* TODO Move the window back where it belongs. */ | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags, | 
|  | HANDLE h) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | FIXME("(%p)->(flags=0x%08lx,handle=%p)\n",This,dwFlags,h); | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | TRACE("(%p)->GetDisplayMode(%p)\n",This,pDDSD); | 
|  |  | 
|  | pDDSD->dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_PIXELFORMAT|DDSD_REFRESHRATE; | 
|  | pDDSD->dwHeight = This->height; | 
|  | pDDSD->dwWidth = This->width; | 
|  | pDDSD->u1.lPitch = This->pitch; | 
|  | pDDSD->u2.dwRefreshRate = 60; | 
|  | pDDSD->u4.ddpfPixelFormat = This->pixelformat; | 
|  | pDDSD->ddsCaps.dwCaps = 0; | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | static INT32 allocate_memory(IDirectDrawImpl *This, DWORD mem) | 
|  | { | 
|  | if (mem > This->available_vidmem) return -1; | 
|  | This->available_vidmem -= mem; | 
|  | return This->available_vidmem; | 
|  | } | 
|  |  | 
|  | static void free_memory(IDirectDrawImpl *This, DWORD mem) | 
|  | { | 
|  | This->available_vidmem += mem; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 ddscaps, | 
|  | LPDWORD total, LPDWORD free) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | TRACE("(%p)->(%p,%p,%p)\n", This,ddscaps,total,free); | 
|  |  | 
|  | if (TRACE_ON(ddraw)) { | 
|  | TRACE(" Asking for memory of type : "); | 
|  | DDRAW_dump_DDSCAPS2(ddscaps); TRACE("\n"); | 
|  | } | 
|  |  | 
|  | /* We have 16 MB videomemory */ | 
|  | if (total)	*total= This->total_vidmem; | 
|  | if (free)	*free = This->available_vidmem; | 
|  |  | 
|  | TRACE(" returning (total) %ld / (free) %ld\n", | 
|  | total != NULL ? *total : 0, | 
|  | free  != NULL ? *free  : 0); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI Main_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface) { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | TRACE("(%p)->(): stub\n", This); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI | 
|  | Main_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pModes, | 
|  | DWORD dwNumModes, DWORD dwFlags) | 
|  | { | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  | FIXME("(%p)->() stub\n", This); | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | /*** Owned object management. */ | 
|  |  | 
|  | void Main_DirectDraw_AddSurface(IDirectDrawImpl* This, | 
|  | IDirectDrawSurfaceImpl* surface) | 
|  | { | 
|  | assert(surface->ddraw_owner == NULL || surface->ddraw_owner == This); | 
|  |  | 
|  | surface->ddraw_owner = This; | 
|  |  | 
|  | /* where should it go? */ | 
|  | surface->next_ddraw = This->surfaces; | 
|  | surface->prev_ddraw = NULL; | 
|  | if (This->surfaces) | 
|  | This->surfaces->prev_ddraw = surface; | 
|  | This->surfaces = surface; | 
|  | } | 
|  |  | 
|  | void Main_DirectDraw_RemoveSurface(IDirectDrawImpl* This, | 
|  | IDirectDrawSurfaceImpl* surface) | 
|  | { | 
|  | assert(surface->ddraw_owner == This); | 
|  |  | 
|  | if (This->surfaces == surface) | 
|  | This->surfaces = surface->next_ddraw; | 
|  |  | 
|  | if (This->primary_surface == surface) | 
|  | This->primary_surface = NULL; | 
|  |  | 
|  | if (surface->next_ddraw) | 
|  | surface->next_ddraw->prev_ddraw = surface->prev_ddraw; | 
|  | if (surface->prev_ddraw) | 
|  | surface->prev_ddraw->next_ddraw = surface->next_ddraw; | 
|  | } | 
|  |  | 
|  | static void Main_DirectDraw_DeleteSurfaces(IDirectDrawImpl* This) | 
|  | { | 
|  | while (This->surfaces != NULL) | 
|  | Main_DirectDrawSurface_ForceDestroy(This->surfaces); | 
|  | } | 
|  |  | 
|  | void Main_DirectDraw_AddClipper(IDirectDrawImpl* This, | 
|  | IDirectDrawClipperImpl* clipper) | 
|  | { | 
|  | assert(clipper->ddraw_owner == NULL || clipper->ddraw_owner == This); | 
|  |  | 
|  | clipper->ddraw_owner = This; | 
|  |  | 
|  | clipper->next_ddraw = This->clippers; | 
|  | clipper->prev_ddraw = NULL; | 
|  | if (This->clippers) | 
|  | This->clippers->prev_ddraw = clipper; | 
|  | This->clippers = clipper; | 
|  | } | 
|  |  | 
|  | void Main_DirectDraw_RemoveClipper(IDirectDrawImpl* This, | 
|  | IDirectDrawClipperImpl* clipper) | 
|  | { | 
|  | assert(clipper->ddraw_owner == This); | 
|  |  | 
|  | if (This->clippers == clipper) | 
|  | This->clippers = clipper->next_ddraw; | 
|  |  | 
|  | if (clipper->next_ddraw) | 
|  | clipper->next_ddraw->prev_ddraw = clipper->prev_ddraw; | 
|  | if (clipper->prev_ddraw) | 
|  | clipper->prev_ddraw->next_ddraw = clipper->next_ddraw; | 
|  | } | 
|  |  | 
|  | static void Main_DirectDraw_DeleteClippers(IDirectDrawImpl* This) | 
|  | { | 
|  | while (This->clippers != NULL) | 
|  | Main_DirectDrawClipper_ForceDestroy(This->clippers); | 
|  | } | 
|  |  | 
|  | void Main_DirectDraw_AddPalette(IDirectDrawImpl* This, | 
|  | IDirectDrawPaletteImpl* palette) | 
|  | { | 
|  | assert(palette->ddraw_owner == NULL || palette->ddraw_owner == This); | 
|  |  | 
|  | palette->ddraw_owner = This; | 
|  |  | 
|  | /* where should it go? */ | 
|  | palette->next_ddraw = This->palettes; | 
|  | palette->prev_ddraw = NULL; | 
|  | if (This->palettes) | 
|  | This->palettes->prev_ddraw = palette; | 
|  | This->palettes = palette; | 
|  | } | 
|  |  | 
|  | void Main_DirectDraw_RemovePalette(IDirectDrawImpl* This, | 
|  | IDirectDrawPaletteImpl* palette) | 
|  | { | 
|  | IDirectDrawSurfaceImpl *surf; | 
|  |  | 
|  | assert(palette->ddraw_owner == This); | 
|  |  | 
|  | if (This->palettes == palette) | 
|  | This->palettes = palette->next_ddraw; | 
|  |  | 
|  | if (palette->next_ddraw) | 
|  | palette->next_ddraw->prev_ddraw = palette->prev_ddraw; | 
|  | if (palette->prev_ddraw) | 
|  | palette->prev_ddraw->next_ddraw = palette->next_ddraw; | 
|  |  | 
|  | /* Here we need also to remove tha palette from any surface which has it as the | 
|  | * current palette (checked on Windows) | 
|  | */ | 
|  | for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw) { | 
|  | if (surf->palette == palette) { | 
|  | TRACE("Palette %p attached to surface %p.\n", palette, surf); | 
|  | surf->palette = NULL; | 
|  | surf->set_palette(surf, NULL); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void Main_DirectDraw_DeletePalettes(IDirectDrawImpl* This) | 
|  | { | 
|  | while (This->palettes != NULL) | 
|  | Main_DirectDrawPalette_ForceDestroy(This->palettes); | 
|  | } | 
|  |  | 
|  | /*** ??? */ | 
|  |  | 
|  | static void | 
|  | LoseSurface(IDirectDrawSurfaceImpl *surface) | 
|  | { | 
|  | if (surface != NULL) surface->lose_surface(surface); | 
|  | } | 
|  |  | 
|  | static void | 
|  | LosePrimarySurface(IDirectDrawImpl *This) | 
|  | { | 
|  | /* MSDN: "If another application changes the display mode, the primary | 
|  | * surface is lost, and the method returns DDERR_SURFACELOST until the | 
|  | * primary surface is recreated to match the new display mode." | 
|  | * | 
|  | * We mark all the primary surfaces as lost as soon as the display | 
|  | * mode is changed (by any application). */ | 
|  |  | 
|  | LoseSurface(This->primary_surface); | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * Uninitialised DirectDraw functions | 
|  | * | 
|  | * This vtable is used when a DirectDraw object is created with | 
|  | * CoCreateInstance. The only usable method is Initialize. | 
|  | */ | 
|  |  | 
|  | void Uninit_DirectDraw_final_release(IDirectDrawImpl *This) | 
|  | { | 
|  | Main_DirectDraw_final_release(This); | 
|  | } | 
|  |  | 
|  | static const IDirectDraw7Vtbl Uninit_DirectDraw_VTable; | 
|  |  | 
|  | /* Not called from the vtable. */ | 
|  | HRESULT Uninit_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex) | 
|  | { | 
|  | HRESULT hr; | 
|  |  | 
|  | hr = Main_DirectDraw_Construct(This, ex); | 
|  | if (FAILED(hr)) return hr; | 
|  |  | 
|  | This->final_release = Uninit_DirectDraw_final_release; | 
|  | ICOM_INIT_INTERFACE(This, IDirectDraw7, Uninit_DirectDraw_VTable); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | HRESULT Uninit_DirectDraw_Create(const GUID* pGUID, | 
|  | LPDIRECTDRAW7* pIface, | 
|  | IUnknown* pUnkOuter, BOOL ex) | 
|  | { | 
|  | HRESULT hr; | 
|  | IDirectDrawImpl* This; | 
|  |  | 
|  | assert(pUnkOuter == NULL); /* XXX no: we must check this */ | 
|  |  | 
|  | This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | 
|  | sizeof(IDirectDrawImpl)); | 
|  | if (This == NULL) return E_OUTOFMEMORY; | 
|  |  | 
|  | hr = Uninit_DirectDraw_Construct(This, ex); | 
|  | if (FAILED(hr)) | 
|  | HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, This); | 
|  | else | 
|  | *pIface = ICOM_INTERFACE(This, IDirectDraw7); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID pDeviceGuid) | 
|  | { | 
|  | const ddraw_driver* driver; | 
|  | IDirectDrawImpl *This = (IDirectDrawImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n", iface, pDeviceGuid); | 
|  |  | 
|  | driver = DDRAW_FindDriver(pDeviceGuid); | 
|  | /* XXX This return value is not documented. (Not checked.) */ | 
|  | if (driver == NULL) return DDERR_INVALIDDIRECTDRAWGUID; | 
|  |  | 
|  | return driver->init(This, pDeviceGuid); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_Compact(LPDIRECTDRAW7 iface) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface, DWORD dwFlags, | 
|  | LPDIRECTDRAWCLIPPER *lplpDDClipper, | 
|  | IUnknown *pUnkOuter) | 
|  |  | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags, | 
|  | LPPALETTEENTRY lpColorTable, | 
|  | LPDIRECTDRAWPALETTE *lplpDDPalette, | 
|  | IUnknown *pUnkOuter) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface, | 
|  | LPDDSURFACEDESC2 lpDDSurfaceDesc, | 
|  | LPDIRECTDRAWSURFACE7 *lplpDDSurface, | 
|  | IUnknown *pUnkOuter) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface, | 
|  | LPDIRECTDRAWSURFACE7 pSurf, | 
|  | LPDIRECTDRAWSURFACE7 *pDupSurf) | 
|  |  | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_EnumDisplayModes(LPDIRECTDRAW7 iface, DWORD dwFlags, | 
|  | LPDDSURFACEDESC2 lpDDSD, | 
|  | LPVOID context, | 
|  | LPDDENUMMODESCALLBACK2 cb) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags, | 
|  | LPDDSURFACEDESC2 pDDSD, LPVOID context, | 
|  | LPDDENUMSURFACESCALLBACK7 cb) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps, | 
|  | LPDDCAPS pHELCaps) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface, | 
|  | LPDDSURFACEDESC2 pDDSD) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes, | 
|  | LPDWORD pCodes) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface, | 
|  | LPDIRECTDRAWSURFACE7 *pGDISurf) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface, LPDWORD pdwFreq) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD pdwScanLine) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, PBOOL pbIsInVB) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hWnd, | 
|  | DWORD dwFlags) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth, | 
|  | DWORD dwHeight, DWORD dwBPP, | 
|  | DWORD dwRefreshRate, DWORD dwFlags) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags, | 
|  | HANDLE hEvent) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 pDDCaps, | 
|  | LPDWORD pdwTotal, LPDWORD pdwFree) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hDC, | 
|  | LPDIRECTDRAWSURFACE7 *pSurf) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface, | 
|  | LPDDDEVICEIDENTIFIER2 pDDDI, | 
|  | DWORD dwFlags) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pszModes, | 
|  | DWORD cModes, DWORD dwFlags) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | Uninit_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface, DWORD dwFlags, | 
|  | LPDWORD pTimeout) | 
|  | { | 
|  | return DDERR_NOTINITIALIZED; | 
|  | } | 
|  |  | 
|  | static const IDirectDraw7Vtbl Uninit_DirectDraw_VTable = | 
|  | { | 
|  | Main_DirectDraw_QueryInterface, | 
|  | Main_DirectDraw_AddRef, | 
|  | Main_DirectDraw_Release, | 
|  | Uninit_DirectDraw_Compact, | 
|  | Uninit_DirectDraw_CreateClipper, | 
|  | Uninit_DirectDraw_CreatePalette, | 
|  | Uninit_DirectDraw_CreateSurface, | 
|  | Uninit_DirectDraw_DuplicateSurface, | 
|  | Uninit_DirectDraw_EnumDisplayModes, | 
|  | Uninit_DirectDraw_EnumSurfaces, | 
|  | Uninit_DirectDraw_FlipToGDISurface, | 
|  | Uninit_DirectDraw_GetCaps, | 
|  | Uninit_DirectDraw_GetDisplayMode, | 
|  | Uninit_DirectDraw_GetFourCCCodes, | 
|  | Uninit_DirectDraw_GetGDISurface, | 
|  | Uninit_DirectDraw_GetMonitorFrequency, | 
|  | Uninit_DirectDraw_GetScanLine, | 
|  | Uninit_DirectDraw_GetVerticalBlankStatus, | 
|  | Uninit_DirectDraw_Initialize, | 
|  | Uninit_DirectDraw_RestoreDisplayMode, | 
|  | Uninit_DirectDraw_SetCooperativeLevel, | 
|  | Uninit_DirectDraw_SetDisplayMode, | 
|  | Uninit_DirectDraw_WaitForVerticalBlank, | 
|  | Uninit_DirectDraw_GetAvailableVidMem, | 
|  | Uninit_DirectDraw_GetSurfaceFromDC, | 
|  | Uninit_DirectDraw_RestoreAllSurfaces, | 
|  | Uninit_DirectDraw_TestCooperativeLevel, | 
|  | Uninit_DirectDraw_GetDeviceIdentifier, | 
|  | Uninit_DirectDraw_StartModeTest, | 
|  | Uninit_DirectDraw_EvaluateMode | 
|  | }; |