diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index e59a7ee3773..3f8cea8b322 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -246,6 +246,14 @@ IDirectDrawImpl_AddRef(IDirectDraw7 *iface) void IDirectDrawImpl_Destroy(IDirectDrawImpl *This) { + int i; + + for(i = 0; i < This->numConvertedDecls; i++) + { + IWineD3DVertexDeclaration_Release(This->decls[i].decl); + } + HeapFree(GetProcessHeap(), 0, This->decls); + /* Clear the cooplevel to restore window and display mode */ IDirectDraw7_SetCooperativeLevel(ICOM_INTERFACE(This, IDirectDraw7), NULL, @@ -3014,3 +3022,78 @@ const IDirectDraw7Vtbl IDirectDraw7_Vtbl = IDirectDrawImpl_StartModeTest, IDirectDrawImpl_EvaluateMode }; + +/***************************************************************************** + * IDirectDrawImpl_FindDecl + * + * Finds the WineD3D vertex declaration for a specific fvf, and creates one + * if none was found. + * + * This function is in ddraw.c and the DDraw object space because D3D7 + * vertex buffers are created using the IDirect3D interface to the ddraw + * object, so they can be valid accross D3D devices(theoretically. The ddraw + * object also owns the wined3d device + * + * Parameters: + * This: Device + * fvf: Fvf to find the decl for + * + * Returns: + * NULL in case of an error, the IWineD3DVertexDeclaration interface for the + * fvf otherwise. + * + *****************************************************************************/ +IWineD3DVertexDeclaration * +IDirectDrawImpl_FindDecl(IDirectDrawImpl *This, + DWORD fvf) +{ + HRESULT hr; + IWineD3DVertexDeclaration* pDecl = NULL; + int p, low, high; /* deliberately signed */ + struct FvfToDecl *convertedDecls = This->decls; + + TRACE("Searching for declaration for fvf %08x... ", fvf); + + low = 0; + high = This->numConvertedDecls - 1; + while(low <= high) { + p = (low + high) >> 1; + TRACE("%d ", p); + if(convertedDecls[p].fvf == fvf) { + TRACE("found %p\n", convertedDecls[p].decl); + return convertedDecls[p].decl; + } else if(convertedDecls[p].fvf < fvf) { + low = p + 1; + } else { + high = p - 1; + } + } + TRACE("not found. Creating and inserting at position %d.\n", low); + + hr = IWineD3DDevice_CreateVertexDeclarationFromFVF(This->wineD3DDevice, + &pDecl, + (IUnknown *) ICOM_INTERFACE(This, IDirectDraw7), + fvf); + if (hr != S_OK) return NULL; + + if(This->declArraySize == This->numConvertedDecls) { + int grow = max(This->declArraySize / 2, 8); + convertedDecls = HeapReAlloc(GetProcessHeap(), 0, convertedDecls, + sizeof(convertedDecls[0]) * (This->numConvertedDecls + grow)); + if(!convertedDecls) { + /* This will destroy it */ + IWineD3DVertexDeclaration_Release(pDecl); + return NULL; + } + This->decls = convertedDecls; + This->declArraySize += grow; + } + + memmove(convertedDecls + low + 1, convertedDecls + low, sizeof(convertedDecls[0]) * (This->numConvertedDecls - low)); + convertedDecls[low].decl = pDecl; + convertedDecls[low].fvf = fvf; + This->numConvertedDecls++; + + TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls); + return pDecl; +} diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index b04c0630deb..14db3c39aac 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -83,6 +83,11 @@ extern ULONG WINAPI D3D7CB_DestroyDepthStencilSurface(IWineD3DSurface *pSurface) /***************************************************************************** * IDirectDraw implementation structure *****************************************************************************/ +struct FvfToDecl +{ + DWORD fvf; + IWineD3DVertexDeclaration *decl; +}; struct IDirectDrawImpl { @@ -149,6 +154,10 @@ struct IDirectDrawImpl */ struct list surface_list; LONG surfaces; + + /* FVF management */ + struct FvfToDecl *decls; + UINT numConvertedDecls, declArraySize; }; /* Declare the VTables. They can be found ddraw.c */ @@ -187,6 +196,10 @@ HRESULT WINAPI IDirectDrawImpl_RecreateSurfacesCallback(IDirectDrawSurface7 *surf, DDSURFACEDESC2 *desc, void *Context); +IWineD3DVertexDeclaration * +IDirectDrawImpl_FindDecl(IDirectDrawImpl *This, + DWORD fvf); + void remove_ddraw_object(IDirectDrawImpl *ddraw); @@ -577,6 +590,7 @@ struct IDirect3DVertexBufferImpl /*** WineD3D and ddraw links ***/ IWineD3DVertexBuffer *wineD3DVertexBuffer; + IWineD3DVertexDeclaration *wineD3DVertexDeclaration; IDirectDrawImpl *ddraw; /*** Storage for D3D7 specific things ***/ diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c index 2e260567dae..14866f3614a 100644 --- a/dlls/ddraw/device.c +++ b/dlls/ddraw/device.c @@ -2963,7 +2963,8 @@ IDirect3DDeviceImpl_7_DrawPrimitive(IDirect3DDevice7 *iface, stride = get_flexible_vertex_size(VertexType); /* Set the FVF */ - hr = IWineD3DDevice_SetFVF(This->wineD3DDevice, VertexType); + hr = IWineD3DDevice_SetVertexDeclaration(This->wineD3DDevice, + IDirectDrawImpl_FindDecl(This->ddraw, VertexType)); if(hr != D3D_OK) return hr; /* This method translates to the user pointer draw of WineD3D */ @@ -3091,7 +3092,8 @@ IDirect3DDeviceImpl_7_DrawIndexedPrimitive(IDirect3DDevice7 *iface, } /* Set the D3DDevice's FVF */ - hr = IWineD3DDevice_SetFVF(This->wineD3DDevice, VertexType); + hr = IWineD3DDevice_SetVertexDeclaration(This->wineD3DDevice, + IDirectDrawImpl_FindDecl(This->ddraw, VertexType)); if(FAILED(hr)) { ERR(" (%p) Setting the FVF failed, hr = %x!\n", This, hr); @@ -3381,9 +3383,7 @@ IDirect3DDeviceImpl_7_DrawPrimitiveStrided(IDirect3DDevice7 *iface, default: return DDERR_INVALIDPARAMS; } - IWineD3DDevice_SetFVF(This->wineD3DDevice, - VertexType); - + /* WineD3D doesn't need the FVF here */ return IWineD3DDevice_DrawPrimitiveStrided(This->wineD3DDevice, PrimitiveType, PrimitiveCount, @@ -3549,7 +3549,8 @@ IDirect3DDeviceImpl_7_DrawPrimitiveVB(IDirect3DDevice7 *iface, } stride = get_flexible_vertex_size(Desc.FVF); - hr = IWineD3DDevice_SetFVF(This->wineD3DDevice, Desc.FVF); + hr = IWineD3DDevice_SetVertexDeclaration(This->wineD3DDevice, + vb->wineD3DVertexDeclaration); if(FAILED(hr)) { ERR(" (%p) Setting the FVF failed, hr = %x!\n", This, hr); @@ -3681,7 +3682,8 @@ IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface, stride = get_flexible_vertex_size(Desc.FVF); TRACE("Vertex buffer FVF = %08x, stride=%d\n", Desc.FVF, stride); - hr = IWineD3DDevice_SetFVF(This->wineD3DDevice, Desc.FVF); + hr = IWineD3DDevice_SetVertexDeclaration(This->wineD3DDevice, + vb->wineD3DVertexDeclaration); if(FAILED(hr)) { ERR(" (%p) Setting the FVF failed, hr = %x!\n", This, hr); diff --git a/dlls/ddraw/direct3d.c b/dlls/ddraw/direct3d.c index 3047f1db69c..927dcd30a90 100644 --- a/dlls/ddraw/direct3d.c +++ b/dlls/ddraw/direct3d.c @@ -1021,6 +1021,17 @@ IDirect3DImpl_7_CreateVertexBuffer(IDirect3D7 *iface, return hr; } + object->wineD3DVertexDeclaration = IDirectDrawImpl_FindDecl(This, + Desc->dwFVF); + if(!object->wineD3DVertexDeclaration) + { + ERR("Cannot find the vertex declaration for fvf %08x\n", Desc->dwFVF); + IWineD3DVertexBuffer_Release(object->wineD3DVertexBuffer); + HeapFree(GetProcessHeap(), 0, object); + return DDERR_INVALIDPARAMS; + } + IWineD3DVertexDeclaration_AddRef(object->wineD3DVertexDeclaration); + /* Return the interface */ *VertexBuffer = ICOM_INTERFACE(object, IDirect3DVertexBuffer7); diff --git a/dlls/ddraw/main.c b/dlls/ddraw/main.c index c89afbf77b8..cfe069ca65f 100644 --- a/dlls/ddraw/main.c +++ b/dlls/ddraw/main.c @@ -322,6 +322,13 @@ DDRAW_Create(const GUID *guid, list_add_head(&global_ddraw_list, &This->ddraw_list_entry); LeaveCriticalSection(&ddraw_list_cs); + This->decls = HeapAlloc(GetProcessHeap(), 0, 0); + if(!This->decls) + { + ERR("Error allocating an empty array for the converted vertex decls\n"); + goto err_out; + } + /* Call QueryInterface to get the pointer to the requested interface. This also initializes * The required refcount */ @@ -332,6 +339,7 @@ err_out: /* Let's hope we never need this ;) */ if(wineD3DDevice) IWineD3DDevice_Release(wineD3DDevice); if(wineD3D) IWineD3D_Release(wineD3D); + if(This) HeapFree(GetProcessHeap(), 0, This->decls); HeapFree(GetProcessHeap(), 0, This); return hr; } diff --git a/dlls/ddraw/vertexbuffer.c b/dlls/ddraw/vertexbuffer.c index 46a9c312ae9..9fa2da9ed53 100644 --- a/dlls/ddraw/vertexbuffer.c +++ b/dlls/ddraw/vertexbuffer.c @@ -189,7 +189,7 @@ IDirect3DVertexBufferImpl_Release(IDirect3DVertexBuffer7 *iface) IWineD3DVertexBuffer_Release(curVB); /* For the GetStreamSource */ } - + IWineD3DVertexDeclaration_Release(This->wineD3DVertexDeclaration); IWineD3DVertexBuffer_Release(This->wineD3DVertexBuffer); HeapFree(GetProcessHeap(), 0, This); return 0;