[PATCH 4/4] d3dx9/tests: Add tests for normals computation. (try 2)

Józef Kucia joseph.kucia at gmail.com
Wed Jul 29 15:17:00 CDT 2015


---
 dlls/d3dx9_36/tests/mesh.c | 573 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 573 insertions(+)

diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index 2da077a..0243a61 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -65,6 +65,11 @@ static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v)
     return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
 }
 
+static BOOL compare_vec4(D3DXVECTOR4 u, D3DXVECTOR4 v)
+{
+    return compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) && compare(u.w, v.w);
+}
+
 #define check_floats(got, exp, dim) check_floats_(__LINE__, "", got, exp, dim)
 static void check_floats_(int line, const char *prefix, const float *got, const float *exp, int dim)
 {
@@ -10373,6 +10378,573 @@ static void test_optimize_faces(void)
     "faces when using 16-bit indices. Got %x\n, expected D3DERR_INVALIDCALL\n", hr);
 }
 
+static HRESULT clear_normals(ID3DXMesh *mesh)
+{
+    HRESULT hr;
+    BYTE *vertices;
+    size_t normal_size;
+    DWORD i, num_vertices, vertex_stride;
+    const D3DXVECTOR4 normal = {NAN, NAN, NAN, NAN};
+    D3DVERTEXELEMENT9 *normal_declaration = NULL;
+    D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
+
+    if (FAILED(hr = mesh->lpVtbl->GetDeclaration(mesh, declaration)))
+        return hr;
+
+    for (i = 0; declaration[i].Stream != 0xff; i++)
+    {
+        if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
+        {
+            normal_declaration = &declaration[i];
+            break;
+        }
+    }
+
+    if (!normal_declaration)
+        return D3DERR_INVALIDCALL;
+
+    if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
+    {
+        normal_size = sizeof(D3DXVECTOR3);
+    }
+    else if (normal_declaration->Type == D3DDECLTYPE_FLOAT4)
+    {
+        normal_size = sizeof(D3DXVECTOR4);
+    }
+    else
+    {
+        trace("Cannot clear normals\n");
+        return E_NOTIMPL;
+    }
+
+    num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
+    vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
+
+    if (FAILED(hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
+        return hr;
+
+    vertices += normal_declaration->Offset;
+
+    for (i = 0; i < num_vertices; i++, vertices += vertex_stride)
+        memcpy(vertices, &normal, normal_size);
+
+    return mesh->lpVtbl->UnlockVertexBuffer(mesh);
+}
+
+static void compare_normals(unsigned int line, const char *test_name,
+        ID3DXMesh *mesh, const D3DXVECTOR3 *normals, unsigned int num_normals)
+{
+    unsigned int i;
+    BYTE *vertices;
+    DWORD num_vertices, vertex_stride;
+    D3DVERTEXELEMENT9 *normal_declaration = NULL;
+    D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
+
+    if (FAILED(mesh->lpVtbl->GetDeclaration(mesh, declaration)))
+    {
+        ok_(__FILE__, line)(0, "%s: Failed to get declaration\n", test_name);
+        return;
+    }
+
+    for (i = 0; declaration[i].Stream != 0xff; i++)
+    {
+        if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
+        {
+            normal_declaration = &declaration[i];
+            break;
+        }
+    }
+
+    if (!normal_declaration)
+    {
+        ok_(__FILE__, line)(0, "%s: Mesh has no normals\n", test_name);
+        return;
+    }
+
+    if (normal_declaration->Type != D3DDECLTYPE_FLOAT3 && normal_declaration->Type != D3DDECLTYPE_FLOAT4)
+    {
+        ok_(__FILE__, line)(0, "%s: Mesh has invalid normals type\n", test_name);
+        return;
+    }
+
+    num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
+    vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
+
+    ok_(__FILE__, line)(num_vertices == num_normals, "%s: Expected %u vertices, got %u\n", test_name,
+            num_normals, num_vertices);
+
+    if (FAILED(mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
+    {
+        ok_(__FILE__, line)(0, "%s: Failed to compare normals\n", test_name);
+        return;
+    }
+
+    vertices += normal_declaration->Offset;
+
+    for (i = 0; i < min(num_vertices, num_normals); i++, vertices += vertex_stride)
+    {
+        if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
+        {
+            const D3DXVECTOR3 *n = (D3DXVECTOR3 *)vertices;
+            ok_(__FILE__, line)(compare_vec3(*n, normals[i]),
+                    "%s: normal %2u, expected (%f, %f, %f), got (%f, %f, %f)\n",
+                    test_name, i, normals[i].x, normals[i].y, normals[i].z, n->x, n->y, n->z);
+        }
+        else
+        {
+            const D3DXVECTOR4 *n = (D3DXVECTOR4 *)vertices;
+            const D3DXVECTOR4 normal = {normals[i].x, normals[i].y, normals[i].z, 1.0f};
+            ok_(__FILE__, line)(compare_vec4(*n, normal),
+                    "%s: normal %2u, expected (%f, %f, %f, %f), got (%f, %f, %f, %f)\n",
+                    test_name, i, normals[i].x, normals[i].y, normals[i].z, 1.0f,
+                    n->x, n->y, n->z, n->w);
+        }
+    }
+
+    mesh->lpVtbl->UnlockVertexBuffer(mesh);
+}
+
+static HRESULT compute_normals_D3DXComputeNormals(ID3DXMesh *mesh, const DWORD *adjacency)
+{
+    return D3DXComputeNormals((ID3DXBaseMesh *)mesh, adjacency);
+}
+
+static HRESULT compute_normals_D3DXComputeTangentFrameEx(ID3DXMesh *mesh, const DWORD *adjacency)
+{
+    return D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
+            adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL);
+}
+
+static void test_compute_normals(void)
+{
+    HRESULT hr;
+    ULONG refcount;
+    ID3DXMesh *mesh, *cloned_mesh;
+    ID3DXBuffer *adjacency;
+    IDirect3DDevice9 *device;
+    struct test_context *test_context;
+    unsigned int i;
+
+    static const struct compute_normals_func
+    {
+        const char *name;
+        HRESULT (*apply)(ID3DXMesh *mesh, const DWORD *adjacency);
+    }
+    compute_normals_funcs[] =
+    {
+        {"D3DXComputeNormals",        compute_normals_D3DXComputeNormals       },
+        {"D3DXComputeTangentFrameEx", compute_normals_D3DXComputeTangentFrameEx}
+    };
+
+    static const D3DXVECTOR3 box_normals[24] =
+    {
+        {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f},
+        { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f},
+        { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f},
+        { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f},
+        { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f},
+        { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}
+    };
+    const float box_normal_component = 1.0f / sqrtf(3.0f);
+    const D3DXVECTOR3 box_normals_adjacency[24] =
+    {
+        {-box_normal_component, -box_normal_component, -box_normal_component},
+        {-box_normal_component, -box_normal_component,  box_normal_component},
+        {-box_normal_component,  box_normal_component,  box_normal_component},
+        {-box_normal_component,  box_normal_component, -box_normal_component},
+        {-box_normal_component,  box_normal_component, -box_normal_component},
+        {-box_normal_component,  box_normal_component,  box_normal_component},
+        { box_normal_component,  box_normal_component,  box_normal_component},
+        { box_normal_component,  box_normal_component, -box_normal_component},
+        { box_normal_component,  box_normal_component, -box_normal_component},
+        { box_normal_component,  box_normal_component,  box_normal_component},
+        { box_normal_component, -box_normal_component,  box_normal_component},
+        { box_normal_component, -box_normal_component, -box_normal_component},
+        {-box_normal_component, -box_normal_component,  box_normal_component},
+        {-box_normal_component, -box_normal_component, -box_normal_component},
+        { box_normal_component, -box_normal_component, -box_normal_component},
+        { box_normal_component, -box_normal_component,  box_normal_component},
+        {-box_normal_component, -box_normal_component,  box_normal_component},
+        { box_normal_component, -box_normal_component,  box_normal_component},
+        { box_normal_component,  box_normal_component,  box_normal_component},
+        {-box_normal_component,  box_normal_component,  box_normal_component},
+        {-box_normal_component, -box_normal_component, -box_normal_component},
+        {-box_normal_component,  box_normal_component, -box_normal_component},
+        { box_normal_component,  box_normal_component, -box_normal_component},
+        { box_normal_component, -box_normal_component, -box_normal_component}
+    };
+    static const D3DXVECTOR3 box_normals_adjacency_area[24] =
+    {
+        {-0.666667f, -0.333333f, -0.666667f}, {-0.333333f, -0.666667f,  0.666667f},
+        {-0.816496f,  0.408248f,  0.408248f}, {-0.408248f,  0.816496f, -0.408248f},
+        {-0.408248f,  0.816496f, -0.408248f}, {-0.816496f,  0.408248f,  0.408248f},
+        { 0.333333f,  0.666667f,  0.666667f}, { 0.666667f,  0.333333f, -0.666667f},
+        { 0.666667f,  0.333333f, -0.666667f}, { 0.333333f,  0.666667f,  0.666667f},
+        { 0.816496f, -0.408248f,  0.408248f}, { 0.408248f, -0.816496f, -0.408248f},
+        {-0.333333f, -0.666667f,  0.666667f}, {-0.666667f, -0.333333f, -0.666667f},
+        { 0.408248f, -0.816496f, -0.408248f}, { 0.816496f, -0.408248f,  0.408248f},
+        {-0.333333f, -0.666667f,  0.666667f}, { 0.816497f, -0.408248f,  0.408248f},
+        { 0.333333f,  0.666667f,  0.666667f}, {-0.816497f,  0.408248f,  0.408248f},
+        {-0.666667f, -0.333333f, -0.666667f}, {-0.408248f,  0.816497f, -0.408248f},
+        { 0.666667f,  0.333333f, -0.666667f}, { 0.408248f, -0.816496f, -0.408248f}
+    };
+    static const D3DXVECTOR3 box_normals_position1f[24] = {{0}};
+    static const D3DXVECTOR3 box_normals_position2f[24] =
+    {
+        {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
+        {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f},
+        {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
+        {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
+        {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
+        {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
+        {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
+        {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}
+    };
+
+    static const D3DXVECTOR3 sphere_normals[22] =
+    {
+        { 0.000000f, -0.000000f,  1.000000f}, { 0.000000f,  0.582244f,  0.813014f},
+        { 0.582244f, -0.000000f,  0.813014f}, {-0.000000f, -0.582244f,  0.813014f},
+        {-0.582244f,  0.000000f,  0.813014f}, {-0.000000f,  0.890608f,  0.454772f},
+        { 0.890608f,  0.000000f,  0.454772f}, { 0.000000f, -0.890608f,  0.454772f},
+        {-0.890608f, -0.000000f,  0.454772f}, { 0.000000f,  1.000000f, -0.000000f},
+        { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
+        {-1.000000f,  0.000000f, -0.000000f}, { 0.000000f,  0.890608f, -0.454773f},
+        { 0.890608f, -0.000000f, -0.454772f}, {-0.000000f, -0.890608f, -0.454773f},
+        {-0.890608f,  0.000000f, -0.454773f}, { 0.000000f,  0.582244f, -0.813015f},
+        { 0.582244f, -0.000000f, -0.813015f}, { 0.000000f, -0.582244f, -0.813015f},
+        {-0.582243f,  0.000000f, -0.813015f}, { 0.000000f,  0.000000f, -1.000000f}
+    };
+    static const D3DXVECTOR3 sphere_normals_area[22] =
+    {
+        { 0.000000f, -0.000000f,  1.000000f}, {-0.215311f,  0.554931f,  0.803550f},
+        { 0.554931f,  0.215311f,  0.803550f}, { 0.215311f, -0.554931f,  0.803550f},
+        {-0.554931f, -0.215311f,  0.803550f}, {-0.126638f,  0.872121f,  0.472618f},
+        { 0.872121f,  0.126638f,  0.472618f}, { 0.126638f, -0.872121f,  0.472618f},
+        {-0.872121f, -0.126637f,  0.472618f}, { 0.000000f,  1.000000f, -0.000000f},
+        { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
+        {-1.000000f,  0.000000f, -0.000000f}, { 0.126638f,  0.872121f, -0.472618f},
+        { 0.872121f, -0.126638f, -0.472618f}, {-0.126638f, -0.872121f, -0.472618f},
+        {-0.872121f,  0.126638f, -0.472618f}, { 0.215311f,  0.554931f, -0.803550f},
+        { 0.554931f, -0.215311f, -0.803550f}, {-0.215311f, -0.554931f, -0.803550f},
+        {-0.554931f,  0.215311f, -0.803550f}, { 0.000000f,  0.000000f, -1.000000f}
+    };
+    static const D3DXVECTOR3 sphere_normals_equal[22] =
+    {
+        { 0.000000f, -0.000000f,  1.000000f}, {-0.134974f,  0.522078f,  0.842150f},
+        { 0.522078f,  0.134974f,  0.842150f}, { 0.134974f, -0.522078f,  0.842150f},
+        {-0.522078f, -0.134974f,  0.842150f}, {-0.026367f,  0.857121f,  0.514440f},
+        { 0.857121f,  0.026367f,  0.514440f}, { 0.026367f, -0.857121f,  0.514440f},
+        {-0.857121f, -0.026367f,  0.514440f}, { 0.000000f,  1.000000f, -0.000000f},
+        { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
+        {-1.000000f,  0.000000f, -0.000000f}, { 0.026367f,  0.857121f, -0.514440f},
+        { 0.857121f, -0.026367f, -0.514440f}, {-0.026367f, -0.857121f, -0.514440f},
+        {-0.857121f,  0.026367f, -0.514440f}, { 0.134975f,  0.522078f, -0.842150f},
+        { 0.522078f, -0.134975f, -0.842150f}, {-0.134974f, -0.522078f, -0.842150f},
+        {-0.522078f,  0.134974f, -0.842150f}, { 0.000000f,  0.000000f, -1.000000f}
+    };
+
+    static const D3DVERTEXELEMENT9 position3f_normal1f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 position3f_normal2f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 normal4f_position3f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 position1f_normal3f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, sizeof(float),       D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 position2f_normal3f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, sizeof(D3DXVECTOR2), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 position4f_normal3f_declaration[] =
+    {
+        {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
+        D3DDECL_END()
+    };
+
+    for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
+    {
+        hr = compute_normals_funcs[i].apply(NULL, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", compute_normals_funcs[i].name, hr);
+    }
+
+    if (!(test_context = new_test_context()))
+    {
+        skip("Couldn't create test context\n");
+        return;
+    }
+    device = test_context->device;
+
+    hr = D3DXCreateBox(device, 1.0f, 1.0f, 1.0f, &mesh, &adjacency);
+    ok(SUCCEEDED(hr), "D3DXCreateBox failed %#x\n", hr);
+
+    /* Check wrong input */
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DDECLUSAGE_NORMAL, 0,
+            D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA | D3DXTANGENT_WEIGHT_EQUAL,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, 0, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 1, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DX_DEFAULT, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_CALCULATE_NORMALS,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
+
+    for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
+    {
+        const struct compute_normals_func *func = &compute_normals_funcs[i];
+
+        /* Mesh without normals */
+        hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_XYZ, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh without positions */
+        hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_NORMAL, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh with D3DDECLTYPE_FLOAT1 normals */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal1f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh with D3DDECLTYPE_FLOAT2 normals */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal2f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, NULL);
+        ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh without adjacency data */
+        hr = clear_normals(mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(mesh, NULL);
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, mesh, box_normals, ARRAY_SIZE(box_normals));
+
+        /* Mesh with adjacency data */
+        hr = clear_normals(mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
+
+        /* Mesh with custom vertex format, D3DDECLTYPE_FLOAT4 normals and adjacency */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, normal4f_position3f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = clear_normals(cloned_mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh with D3DDECLTYPE_FLOAT1 positions and D3DDECLTYPE_FLOAT3 normals */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, position1f_normal3f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = clear_normals(cloned_mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position1f, ARRAY_SIZE(box_normals_position1f));
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh with D3DDECLTYPE_FLOAT2 positions and D3DDECLTYPE_FLOAT3 normals */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, position2f_normal3f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = clear_normals(cloned_mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position2f, ARRAY_SIZE(box_normals_position2f));
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+
+        /* Mesh with D3DDECLTYPE_FLOAT4 positions and D3DDECLTYPE_FLOAT3 normals */
+        hr = mesh->lpVtbl->CloneMesh(mesh, 0, position4f_normal3f_declaration, device, &cloned_mesh);
+        ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
+
+        hr = clear_normals(cloned_mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
+
+        refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
+        ok(!refcount, "Mesh has %u references left\n", refcount);
+    }
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
+            ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
+            ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
+
+    refcount = mesh->lpVtbl->Release(mesh);
+    ok(!refcount, "Mesh has %u references left\n", refcount);
+    refcount = ID3DXBuffer_Release(adjacency);
+    ok(!refcount, "Buffer has %u references left\n", refcount);
+
+    hr = D3DXCreateSphere(device, 1.0f, 4, 6, &mesh, &adjacency);
+    ok(SUCCEEDED(hr), "D3DXCreateSphere failed %#x\n", hr);
+
+    for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
+    {
+        const struct compute_normals_func *func = &compute_normals_funcs[i];
+
+        /* Sphere without adjacency data */
+        hr = clear_normals(mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(mesh, NULL);
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
+
+        /* Sphere with adjacency data */
+        hr = clear_normals(mesh);
+        ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
+
+        hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
+        ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
+
+        compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
+    }
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
+            ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
+            NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
+
+    hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
+            D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
+            ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
+    ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
+
+    compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
+
+    refcount = mesh->lpVtbl->Release(mesh);
+    ok(!refcount, "Mesh has %u references left\n", refcount);
+    refcount = ID3DXBuffer_Release(adjacency);
+    ok(!refcount, "Buffer has %u references left\n", refcount);
+
+    free_test_context(test_context);
+}
+
 START_TEST(mesh)
 {
     D3DXBoundProbeTest();
@@ -10401,4 +10973,5 @@ START_TEST(mesh)
     test_clone_mesh();
     test_valid_mesh();
     test_optimize_faces();
+    test_compute_normals();
 }
-- 
2.3.6




More information about the wine-patches mailing list