From 1309844913ddca81ca0ead2b8a040de9766225d8 Mon Sep 17 00:00:00 2001 From: Ivan Gyurdiev Date: Tue, 4 Jul 2006 02:53:13 -0600 Subject: [PATCH] wined3d: Implement FVF to DECL9 conversion (with tests). --- dlls/d3d9/d3d9_private.h | 7 + dlls/d3d9/device.c | 22 ++ dlls/d3d9/tests/vertexdeclaration.c | 473 +++++++++++++++++++++++++++- dlls/d3d9/vertexdeclaration.c | 156 +++++++++ dlls/wined3d/device.c | 14 - 5 files changed, 657 insertions(+), 15 deletions(-) diff --git a/dlls/d3d9/d3d9_private.h b/dlls/d3d9/d3d9_private.h index bf967313327..2d6397e07ec 100644 --- a/dlls/d3d9/d3d9_private.h +++ b/dlls/d3d9/d3d9_private.h @@ -39,6 +39,13 @@ #include "ddraw.h" #include "wine/wined3d_interface.h" +/* =========================================================================== + Internal use + =========================================================================== */ +extern HRESULT vdecl_convert_fvf( + DWORD FVF, + D3DVERTEXELEMENT9** ppVertexElements); + /* =========================================================================== Macros =========================================================================== */ diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index 725a1b04843..7aac0e44a46 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -713,6 +713,28 @@ static HRESULT WINAPI IDirect3DDevice9Impl_ProcessVertices(LPDIRECT3DDEVICE9 i HRESULT WINAPI IDirect3DDevice9Impl_SetFVF(LPDIRECT3DDEVICE9 iface, DWORD FVF) { IDirect3DDevice9Impl *This = (IDirect3DDevice9Impl *)iface; TRACE("(%p) Relay\n" , This); + + if (0 != FVF) { + HRESULT hr; + D3DVERTEXELEMENT9* elements = NULL; + IDirect3DVertexDeclaration9* pDecl = NULL; + + hr = vdecl_convert_fvf(FVF, &elements); + if (hr != S_OK) goto exit; + + hr = IDirect3DDevice9Impl_CreateVertexDeclaration(iface, elements, &pDecl); + if (hr != S_OK) goto exit; + + hr = IDirect3DDevice9Impl_SetVertexDeclaration(iface, pDecl); + if (hr != S_OK) goto exit; + pDecl = NULL; + + exit: + HeapFree(GetProcessHeap(), 0, elements); + if (pDecl) IUnknown_Release(pDecl); + if (hr != S_OK) return hr; + } + return IWineD3DDevice_SetFVF(This->WineD3DDevice, FVF); } diff --git a/dlls/d3d9/tests/vertexdeclaration.c b/dlls/d3d9/tests/vertexdeclaration.c index 229b4a0d67b..999b5a98932 100644 --- a/dlls/d3d9/tests/vertexdeclaration.c +++ b/dlls/d3d9/tests/vertexdeclaration.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2005 Henri Verbeet + * Copyright (C) 2006 Ivan Gyurdiev * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,6 +23,10 @@ static HMODULE d3d9_handle = 0; +#define VDECL_CHECK(fcall) \ + if(fcall != S_OK) \ + trace(" Test failed on line #%d\n", __LINE__); + static HWND create_window(void) { WNDCLASS wc = {0}; @@ -144,6 +149,472 @@ static void test_get_declaration(IDirect3DVertexDeclaration9 *decl_ptr, D3DVERTE HeapFree(GetProcessHeap(), 0, decl); } +/* FIXME: also write a test, which shows that attempting to set + * an invalid vertex declaration returns E_FAIL */ + +static HRESULT test_fvf_to_decl( + IDirect3DDevice9* device, + IDirect3DVertexDeclaration9* default_decl, + DWORD test_fvf, + CONST D3DVERTEXELEMENT9 expected_elements[], + D3DVERTEXELEMENT9* result_elements_ptr, + UINT expected_size, + char object_should_change) +{ + + HRESULT hr; + IDirect3DVertexDeclaration9 *result_decl = NULL; + UINT result_size = 12345; + + /* Set a default declaration to make sure it is changed */ + hr = IDirect3DDevice9_SetVertexDeclaration ( device, default_decl ); + ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#lx, expected %#lx\n", hr, D3D_OK); + if (FAILED(hr)) goto fail; + + /* Set an FVF */ + hr = IDirect3DDevice9_SetFVF( device, test_fvf); + ok(SUCCEEDED(hr), "SetFVF returned %#lx, expected %#lx\n", hr, D3D_OK); + if (FAILED(hr)) goto fail; + + /* Check if the declaration object changed underneath */ + hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl); + ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#lx, expected %#lx\n", hr, D3D_OK); + if (FAILED(hr)) goto fail; + if (object_should_change) { + ok(result_decl != default_decl, "result declaration matches original\n"); + if (result_decl == default_decl) goto fail; + } else { + ok(result_decl == default_decl, "result declaration does not match original\n"); + if (result_decl != default_decl) goto fail; + } + + /* Declaration content/size test */ + ok(result_decl != NULL, "result declaration was null\n"); + if (result_decl == NULL) + goto fail; + else { + + int status; + + /* Check if the size changed, and abort if it did */ + hr = IDirect3DVertexDeclaration9_GetDeclaration( result_decl, NULL, &result_size ); + ok(SUCCEEDED(hr), "GetDeclaration returned %#lx, expected %#lx\n", hr, D3D_OK); + if (FAILED(hr)) goto fail; + ok(result_size == expected_size, "result declaration size: %d, " + "expected: %d\n", result_size, expected_size); + if (result_size != expected_size) goto fail; + + /* Check the actual elements. Write it them in a caller-allocated array of the correct size + * That's fine, since we aborted above if the size didn't match the caller's expectations */ + hr = IDirect3DVertexDeclaration9_GetDeclaration( result_decl, result_elements_ptr, &result_size ); + ok(SUCCEEDED(hr), "GetDeclaration returned %#lx, expected %#lx\n", hr, D3D_OK); + if (FAILED(hr)) goto fail; + + ok(result_size == expected_size, "result declaration size: %d, " + "expected: %d\n", result_size, expected_size); + if (result_size != expected_size) goto fail; + + status = memcmp(expected_elements, result_elements_ptr, expected_size * sizeof(D3DVERTEXELEMENT9)); + ok(!status, "result declaration differs from expected\n"); + if (status) { + unsigned int i; + + for (i = 0; i < expected_size; i++) { + + trace( + "Stream = %d, Offset = %d, Type = %d, " + "Method = %d, Usage = %d, UsageIndex = %d\n", + result_elements_ptr[i].Stream, + result_elements_ptr[i].Offset, + result_elements_ptr[i].Type, + result_elements_ptr[i].Method, + result_elements_ptr[i].Usage, + result_elements_ptr[i].UsageIndex); + } + goto fail; + } + } + + if (result_decl) IUnknown_Release( result_decl ); + return S_OK; + + fail: + if (result_decl) IUnknown_Release( result_decl ); + return E_FAIL; +} + +static HRESULT test_decl_to_fvf( + IDirect3DDevice9* device, + DWORD default_fvf, + CONST D3DVERTEXELEMENT9 test_decl[], + DWORD test_fvf) +{ + + HRESULT hr; + IDirect3DVertexDeclaration9 *vdecl = NULL; + + DWORD result_fvf = 0xdeadbeef; + + /* Set a default FVF of SPECULAR and DIFFUSE to make sure it is changed back to 0 */ + hr = IDirect3DDevice9_SetFVF( device, default_fvf); + ok(SUCCEEDED(hr), "SetFVF returned %#lx, expected %#lx\n", hr, D3D_OK); + if (FAILED(hr)) goto fail; + + /* Create a testing declaration */ + hr = IDirect3DDevice9_CreateVertexDeclaration( device, test_decl, &vdecl ); + ok(SUCCEEDED(hr), "CreateVertexDeclaration returned %#lx, expected %#lx\n", hr, D3D_OK); + if (FAILED(hr)) goto fail; + + /* Set the declaration */ + hr = IDirect3DDevice9_SetVertexDeclaration ( device, vdecl ); + ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#lx, expected %#lx\n", hr, D3D_OK); + if (FAILED(hr)) goto fail; + + /* Check the FVF */ + hr = IDirect3DDevice9_GetFVF( device, &result_fvf); + ok(SUCCEEDED(hr), "GetFVF returned %#lx, expected %#lx\n", hr, D3D_OK); + if (FAILED(hr)) goto fail; + todo_wine { + ok(test_fvf == result_fvf, "result FVF was: %#lx, expected: %#lx\n", result_fvf, test_fvf); + } + if (test_fvf != result_fvf) goto fail; + + IDirect3DDevice9_SetVertexDeclaration ( device, NULL ); + if (vdecl) IUnknown_Release( vdecl ); + return S_OK; + + fail: + IDirect3DDevice9_SetVertexDeclaration ( device, NULL ); + if (vdecl) IUnknown_Release( vdecl ); + return E_FAIL; +} + +static void test_fvf_decl_conversion(IDirect3DDevice9 *pDevice) +{ + + HRESULT hr; + D3DVERTEXELEMENT9 result_buffer[MAXD3DDECLLENGTH]; + unsigned int i; + + IDirect3DVertexDeclaration9* default_decl = NULL; + DWORD default_fvf = D3DFVF_SPECULAR | D3DFVF_DIFFUSE; + D3DVERTEXELEMENT9 default_elements[] = + { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, + { 0, 4, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() }; + + /* Create a default declaration and FVF that does not match any of the tests */ + hr = IDirect3DDevice9_CreateVertexDeclaration( pDevice, default_elements, &default_decl ); + ok(SUCCEEDED(hr), "CreateVertexDeclaration returned %#lx, expected %#lx\n", hr, D3D_OK); + if (FAILED(hr)) goto cleanup; + + /* Test conversions from vertex declaration to an FVF. + * For some reason those seem to occur only for POSITION/POSITIONT, + * Otherwise the FVF is forced to 0 - maybe this is configuration specific */ + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, D3DFVF_XYZ)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, D3DFVF_XYZRHW)); + } + for (i = 0; i < 4; i++) { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT1+i, 0, D3DDECLUSAGE_BLENDWEIGHT, 0}, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0}, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + + /* Make sure textures of different sizes work */ + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + + /* Make sure the TEXCOORD index works correctly - try several textures */ + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 }, + { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2 }, + { 0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + + /* No FVF mapping available */ + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + + /* Try empty declaration */ + { + CONST D3DVERTEXELEMENT9 test_buffer[] = { D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + + /* Now try a combination test */ + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITIONT, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, + { 0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 }, + { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, + { 0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1 }, D3DDECL_END() }; + VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0)); + } + + /* Test conversions from FVF to a vertex declaration + * These seem to always occur internally. A new declaration object is created if necessary */ + + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZ, test_buffer, result_buffer, 2, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZRHW, test_buffer, result_buffer, 2, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, + { 0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4, + test_buffer, result_buffer, 4, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, + { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR, + test_buffer, result_buffer, 4, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, + { 0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB5, test_buffer, result_buffer, 4, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB1, test_buffer, result_buffer, 3, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4, + test_buffer, result_buffer, 3, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR, + test_buffer, result_buffer, 3, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB2, test_buffer, result_buffer, 3, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, + { 0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4, + test_buffer, result_buffer, 4, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, + { 0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR, + test_buffer, result_buffer, 4, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB3, test_buffer, result_buffer, 3, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, + { 0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4, + test_buffer, result_buffer, 4, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, + { 0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR, + test_buffer, result_buffer, 4, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4, test_buffer, result_buffer, 3, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, + { 0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4, + test_buffer, result_buffer, 4, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, + { 0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR, + test_buffer, result_buffer, 4, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_NORMAL, test_buffer, result_buffer, 2, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_PSIZE, test_buffer, result_buffer, 2, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_DIFFUSE, test_buffer, result_buffer, 2, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_SPECULAR, test_buffer, result_buffer, 2, 1)); + } + + /* Make sure textures of different sizes work */ + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1, + test_buffer, result_buffer, 2, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1, + test_buffer, result_buffer, 2, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1, + test_buffer, result_buffer, 2, 1)); + } + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1, + test_buffer, result_buffer, 2, 1)); + } + + /* Make sure the TEXCOORD index works correctly - try several textures */ + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 }, + { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2 }, + { 0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, + D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_TEXCOORDSIZE2(2) | + D3DFVF_TEXCOORDSIZE4(3) | D3DFVF_TEX4, test_buffer, result_buffer, 5, 1)); + } + + /* Now try a combination test */ + { + CONST D3DVERTEXELEMENT9 test_buffer[] = + { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, + { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, + { 0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, + { 0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 }, D3DDECL_END() }; + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4 | D3DFVF_SPECULAR | D3DFVF_DIFFUSE | + D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_TEX2, test_buffer, result_buffer, 7, 1)); + } + + /* Setting the FVF to 0 should result in no change to the default decl */ + VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, 0, default_elements, result_buffer, 3, 0)); + + cleanup: + IDirect3DDevice9_SetVertexDeclaration ( pDevice, NULL ); + if ( default_decl ) IUnknown_Release (default_decl); +} + START_TEST(vertexdeclaration) { static D3DVERTEXELEMENT9 simple_decl[] = { @@ -175,6 +646,6 @@ START_TEST(vertexdeclaration) } test_get_set_vertex_declaration(device_ptr, decl_ptr); - test_get_declaration(decl_ptr, simple_decl, simple_decl_num_elements); + test_fvf_decl_conversion(device_ptr); } diff --git a/dlls/d3d9/vertexdeclaration.c b/dlls/d3d9/vertexdeclaration.c index 9417b279ca6..1903091517b 100644 --- a/dlls/d3d9/vertexdeclaration.c +++ b/dlls/d3d9/vertexdeclaration.c @@ -24,6 +24,162 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d9); +typedef struct _D3DDECLTYPE_INFO { + D3DDECLTYPE d3dType; + int size; + int typesize; +} D3DDECLTYPE_INFO; + +D3DDECLTYPE_INFO static const d3d_dtype_lookup[D3DDECLTYPE_UNUSED] = { + {D3DDECLTYPE_FLOAT1, 1, sizeof(float)}, + {D3DDECLTYPE_FLOAT2, 2, sizeof(float)}, + {D3DDECLTYPE_FLOAT3, 3, sizeof(float)}, + {D3DDECLTYPE_FLOAT4, 4, sizeof(float)}, + {D3DDECLTYPE_D3DCOLOR, 4, sizeof(BYTE)}, + {D3DDECLTYPE_UBYTE4, 4, sizeof(BYTE)}, + {D3DDECLTYPE_SHORT2, 2, sizeof(short int)}, + {D3DDECLTYPE_SHORT4, 4, sizeof(short int)}, + {D3DDECLTYPE_UBYTE4N, 4, sizeof(BYTE)}, + {D3DDECLTYPE_SHORT2N, 2, sizeof(short int)}, + {D3DDECLTYPE_SHORT4N, 4, sizeof(short int)}, + {D3DDECLTYPE_USHORT2N, 2, sizeof(short int)}, + {D3DDECLTYPE_USHORT4N, 4, sizeof(short int)}, + {D3DDECLTYPE_UDEC3, 3, sizeof(short int)}, + {D3DDECLTYPE_DEC3N, 3, sizeof(short int)}, + {D3DDECLTYPE_FLOAT16_2, 2, sizeof(short int)}, + {D3DDECLTYPE_FLOAT16_4, 4, sizeof(short int)}}; + +#define D3D_DECL_SIZE(type) d3d_dtype_lookup[type].size +#define D3D_DECL_TYPESIZE(type) d3d_dtype_lookup[type].typesize + +HRESULT vdecl_convert_fvf( + DWORD fvf, + D3DVERTEXELEMENT9** ppVertexElements) { + + unsigned int idx, idx2; + unsigned int offset; + BOOL has_pos = (fvf & D3DFVF_POSITION_MASK) != 0; + BOOL has_blend = (fvf & D3DFVF_XYZB5) > D3DFVF_XYZRHW; + BOOL has_blend_idx = has_blend && + (((fvf & D3DFVF_XYZB5) == D3DFVF_XYZB5) || + (fvf & D3DFVF_LASTBETA_D3DCOLOR) || + (fvf & D3DFVF_LASTBETA_UBYTE4)); + BOOL has_normal = (fvf & D3DFVF_NORMAL) != 0; + BOOL has_psize = (fvf & D3DFVF_PSIZE) != 0; + BOOL has_diffuse = (fvf & D3DFVF_DIFFUSE) != 0; + BOOL has_specular = (fvf & D3DFVF_SPECULAR) !=0; + + DWORD num_textures = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT; + DWORD texcoords = (fvf & 0x00FF0000) >> 16; + + D3DVERTEXELEMENT9 end_element = D3DDECL_END(); + D3DVERTEXELEMENT9 *elements = NULL; + + unsigned int size; + DWORD num_blends = 1 + (((fvf & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1); + if (has_blend_idx) num_blends--; + + /* Compute declaration size */ + size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal + + has_psize + has_diffuse + has_specular + num_textures + 1; + + /* convert the declaration */ + elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(D3DVERTEXELEMENT9)); + if (!elements) + return D3DERR_OUTOFVIDEOMEMORY; + + memcpy(&elements[size-1], &end_element, sizeof(D3DVERTEXELEMENT9)); + idx = 0; + if (has_pos) { + if (!has_blend && (fvf & D3DFVF_XYZRHW)) { + elements[idx].Type = D3DDECLTYPE_FLOAT4; + elements[idx].Usage = D3DDECLUSAGE_POSITIONT; + } + else { + elements[idx].Type = D3DDECLTYPE_FLOAT3; + elements[idx].Usage = D3DDECLUSAGE_POSITION; + } + elements[idx].UsageIndex = 0; + idx++; + } + if (has_blend && (num_blends > 0)) { + if (((fvf & D3DFVF_XYZB5) == D3DFVF_XYZB2) && (fvf & D3DFVF_LASTBETA_D3DCOLOR)) + elements[idx].Type = D3DDECLTYPE_D3DCOLOR; + else + elements[idx].Type = D3DDECLTYPE_FLOAT1 + num_blends - 1; + elements[idx].Usage = D3DDECLUSAGE_BLENDWEIGHT; + elements[idx].UsageIndex = 0; + idx++; + } + if (has_blend_idx) { + if (fvf & D3DFVF_LASTBETA_UBYTE4 || + (((fvf & D3DFVF_XYZB5) == D3DFVF_XYZB2) && (fvf & D3DFVF_LASTBETA_D3DCOLOR))) + elements[idx].Type = D3DDECLTYPE_UBYTE4; + else if (fvf & D3DFVF_LASTBETA_D3DCOLOR) + elements[idx].Type = D3DDECLTYPE_D3DCOLOR; + else + elements[idx].Type = D3DDECLTYPE_FLOAT1; + elements[idx].Usage = D3DDECLUSAGE_BLENDINDICES; + elements[idx].UsageIndex = 0; + idx++; + } + if (has_normal) { + elements[idx].Type = D3DDECLTYPE_FLOAT3; + elements[idx].Usage = D3DDECLUSAGE_NORMAL; + elements[idx].UsageIndex = 0; + idx++; + } + if (has_psize) { + elements[idx].Type = D3DDECLTYPE_FLOAT1; + elements[idx].Usage = D3DDECLUSAGE_PSIZE; + elements[idx].UsageIndex = 0; + idx++; + } + if (has_diffuse) { + elements[idx].Type = D3DDECLTYPE_D3DCOLOR; + elements[idx].Usage = D3DDECLUSAGE_COLOR; + elements[idx].UsageIndex = 0; + idx++; + } + if (has_specular) { + elements[idx].Type = D3DDECLTYPE_D3DCOLOR; + elements[idx].Usage = D3DDECLUSAGE_COLOR; + elements[idx].UsageIndex = 1; + idx++; + } + for (idx2 = 0; idx2 < num_textures; idx2++) { + unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03; + switch (numcoords) { + case D3DFVF_TEXTUREFORMAT1: + elements[idx].Type = D3DDECLTYPE_FLOAT1; + break; + case D3DFVF_TEXTUREFORMAT2: + elements[idx].Type = D3DDECLTYPE_FLOAT2; + break; + case D3DFVF_TEXTUREFORMAT3: + elements[idx].Type = D3DDECLTYPE_FLOAT3; + break; + case D3DFVF_TEXTUREFORMAT4: + elements[idx].Type = D3DDECLTYPE_FLOAT4; + break; + } + elements[idx].Usage = D3DDECLUSAGE_TEXCOORD; + elements[idx].UsageIndex = idx2; + idx++; + } + + /* Now compute offsets, and initialize the rest of the fields */ + for (idx = 0, offset = 0; idx < size-1; idx++) { + elements[idx].Stream = 0; + elements[idx].Method = D3DDECLMETHOD_DEFAULT; + elements[idx].Offset = offset; + offset += D3D_DECL_SIZE(elements[idx].Type) * D3D_DECL_TYPESIZE(elements[idx].Type); + } + + *ppVertexElements = elements; + return D3D_OK; +} + /* IDirect3DVertexDeclaration9 IUnknown parts follow: */ static HRESULT WINAPI IDirect3DVertexDeclaration9Impl_QueryInterface(LPDIRECT3DVERTEXDECLARATION9 iface, REFIID riid, LPVOID* ppobj) { IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface; diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 860eba5ddbf..714bb1dd50e 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -2355,15 +2355,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf This->updateStateBlock->set.fvf = TRUE; TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf); - - if (0 != fvf) { - /* clear down the vertex declaration - NOTE: Axis and Allies doesn't work properly otherwise - (may be a stateblock problem though!) - */ - hr = IWineD3DDevice_SetVertexDeclaration(iface, NULL); - } - return hr; } @@ -4641,11 +4632,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader_Release(oldShader); } - if (pShader != NULL && ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration != NULL) { - TRACE("(%p) : setting vertexDeclaration(%p)\n", This, ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration); - IWineD3DDevice_SetVertexDeclaration(iface, ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration); - } - TRACE("(%p) : setting pShader(%p)\n", This, pShader); /** * TODO: merge HAL shaders context switching from prototype