[WINED3D 7] Implement FVF to DECL9 conversion (with tests)

Ivan Gyurdiev ivg231 at gmail.com
Tue Jul 4 03:53:13 CDT 2006


In d3d9, SetFVF automatically converts old-style FVF to new-style 
VertexDeclaration (and does so in an application-visible way). It does 
the opposite conversion as well in certain cases, but that's a todo_wine 
for now.

The 0-ing of declarations in SetFVF was removed (since clearly you can't 
zero and convert at the same time).
However, that caused regression in d3d8 apps. Investigation shows that 
SetVertexShader should not be setting the device vertex declaration - 
that overwrites the converted one, and doesn't make sense, since d3d8 
has no way to access that field. Internally we don't need it either, 
since drawprim will find a declaration inside the shader just fine.

=========
This fixes demos:
dx9_hlsl_simple_vs2ps
dx9_hlsl_fx_simple
@codesampler.org

I think Jason Green had another demo that will get fixed (the one with 
the car picture).

-------------- next part --------------
>From 94c227e491c620506703c3786d1711dcff11a7b0 Mon Sep 17 00:00:00 2001
From: root <root at shark.bluenet>
Date: Tue, 4 Jul 2006 02:50:28 -0600
Subject: [PATCH] Implement FVF -> DECL9 conversion (with tests)

In d3d9, SetFVF automatically converts old-style FVF to new-style VertexDeclaration (and does so in an application-visible way). It does the opposite conversion as well in certain cases, but that's a todo_wine for now.

The 0-ing of declarations in SetFVF was removed (since clearly you can't zero and convert at the same time).
However, that caused regression in d3d8 apps. Investigation shows that SetVertexShader should not be setting the device vertex declaration - that overwrites the converted one, and doesn't make sense, since d3d8 has no way to access that field. Internally we don't need it either, since drawprim will find a declaration inside the shader just fine.
---
 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 bf96731..2d6397e 100644
--- a/dlls/d3d9/d3d9_private.h
+++ b/dlls/d3d9/d3d9_private.h
@@ -40,6 +40,13 @@ #include "ddraw.h"
 #include "wine/wined3d_interface.h"
 
 /* ===========================================================================
+   Internal use
+   =========================================================================== */
+extern HRESULT vdecl_convert_fvf(
+    DWORD FVF,
+    D3DVERTEXELEMENT9** ppVertexElements);
+
+/* ===========================================================================
     Macros
    =========================================================================== */
 /* Not nice, but it lets wined3d support different versions of directx */
diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c
index 725a1b0..7aac0e4 100644
--- a/dlls/d3d9/device.c
+++ b/dlls/d3d9/device.c
@@ -713,6 +713,28 @@ static HRESULT  WINAPI  IDirect3DDevice9
 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 229b4a0..999b5a9 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 @@ #include "wine/test.h"
 
 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(IDirect
     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 9417b27..1903091 100644
--- a/dlls/d3d9/vertexdeclaration.c
+++ b/dlls/d3d9/vertexdeclaration.c
@@ -24,6 +24,162 @@ #include "d3d9_private.h"
 
 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 860eba5..714bb1d 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -2355,15 +2355,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     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
         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
-- 
1.4.0



More information about the wine-patches mailing list