On Tue, Jun 21, 2011 at 5:36 PM, Dylan Smith <dylan.ah.sm...@gmail.com> wrote:
> On Tue, Jun 21, 2011 at 6:32 AM, Michael Mc Donnell
> <mich...@mcdonnell.dk> wrote:
>> Here is my test and implementation of ConvertAdjacencyToPointReps.
>
>
>> +    hr = iface->lpVtbl->LockIndexBuffer(iface, D3DLOCK_READONLY, 
>> (void**)&indices);
>> +    if (FAILED(hr)) goto cleanup;
>> +    memcpy(new_indices, indices, This->numvertices * sizeof(*indices));
>
> I think you want the number of faces * 3 rather than the number of
> vertices.  And the size of an index is not constant, it is 32-bit if
> This->options has the D3DXMESH_32BIT bit set and 16-bit if the bit
> isn't set.

Yes you're right, I'll change that. I had completely forgotten about
16-bit indices, so that required a lot more changes and a test.

>> +static void test_convert_adjacency_to_point_reps(void)
>> +{
> ...
>> +    /* All mesh data */
>> +    struct vertex_pnc *vertices[] = {vertices0, vertices1, vertices2, 
>> vertices3, vertices4, vertices5, vertices6};
>> +    ID3DXMesh *meshes[ARRAY_SIZE(vertices)];
>> +    DWORD *indices[] = {indices0, indices1, indices2, indices3, indices4, 
>> indices5, indices6};
>> +    DWORD num_vertices[] = {num_vertices0, num_vertices1, num_vertices2, 
>> num_vertices3, num_vertices4, num_vertices5, num_vertices6};
>> +    DWORD num_faces[] = {num_faces0, num_faces1, num_faces2, num_faces3, 
>> num_faces4, num_faces5, num_faces6};
>> +    DWORD *adjacencies[] = {adjacency0, adjacency1, adjacency2, adjacency3, 
>> adjacency4, adjacency5, adjacency6};
>> +    DWORD *point_reps[] = {point_rep0, point_rep1, point_rep2, point_rep3, 
>> point_rep4, point_rep5, point_rep6};
>> +    DWORD *exp_point_reps[] = {exp_point_rep0, exp_point_rep1, 
>> exp_point_rep2, exp_point_rep3, exp_point_rep4, exp_point_rep5, 
>> exp_point_rep6};
>
> I think it would make sense to put all these arrays of the same length
> into a structure (e.g. struct test_case) array.  This would make it
> clear what needs to be updated to add another test case, and less
> error prone than making sure each relevant individual array is
> updated.

Ok I've tried to make a struct for them.

> Also, several of these and similar array seem like they can be made constant.

Check, I've const'ified everything I could find.

>> +static void test_convert_adjacency_to_point_reps(void)
>> +{
> ...
>> +    for (i = 0; i < ARRAY_SIZE(meshes); i++)
>> +    {
> ...
>> +        hr = meshes[i]->lpVtbl->ConvertAdjacencyToPointReps(meshes[i], 
>> adjacencies[i], point_reps[i]);
>> +        todo_wine ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed. "
>> +                     "Got %x expected D3D_OK\n", hr);
>
> The value i should probably be printed in this error message.
> Otherwise, if you see a failure on test.winehq.org that you can't
> reproduce, it will be hard to figure out what might have caused the
> failure.

Yes, good idea.

> That's it for now.

Thanks your comments. I've attached an updated version.
From be56fecfb515d3407d7fe133ba00a8463745a973 Mon Sep 17 00:00:00 2001
From: Michael Mc Donnell <mich...@mcdonnell.dk>
Date: Fri, 27 May 2011 16:24:18 +0200
Subject: d3dx9/tests: Implemented ConvertAdjacencyToPointReps test.

---
 dlls/d3dx9_36/tests/mesh.c |  352 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 352 insertions(+), 0 deletions(-)

diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index 668097f..ae4dd26 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -2,6 +2,7 @@
  * Copyright 2008 David Adam
  * Copyright 2008 Luis Busquets
  * Copyright 2009 Henri Verbeet for CodeWeavers
+ * Copyright 2011 Michael Mc Donnell
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -89,6 +90,93 @@ static BOOL compare_face(face a, face b)
     return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
 }
 
+struct test_context
+{
+    HWND hwnd;
+    IDirect3D9 *d3d;
+    IDirect3DDevice9 *device;
+};
+
+/* Initializes a test context struct. Use it to initialize DirectX.
+ *
+ * Returns NULL if an error occured.
+ */
+static struct test_context *new_test_context(void)
+{
+    HRESULT hr;
+    HWND hwnd = NULL;
+    IDirect3D9 *d3d = NULL;
+    IDirect3DDevice9 *device = NULL;
+    D3DPRESENT_PARAMETERS d3dpp = {0};
+    struct test_context *test_context;
+
+    hwnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+    if (!hwnd)
+    {
+        skip("Couldn't create application window\n");
+        goto error;
+    }
+
+    d3d = Direct3DCreate9(D3D_SDK_VERSION);
+    if (!d3d)
+    {
+        skip("Couldn't create IDirect3D9 object\n");
+        goto error;
+    }
+
+    memset(&d3dpp, 0, sizeof(d3dpp));
+    d3dpp.Windowed = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
+                                 D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
+    if (FAILED(hr))
+    {
+        skip("Couldn't create IDirect3DDevice9 object %#x\n", hr);
+        goto error;
+    }
+
+    test_context = HeapAlloc(GetProcessHeap(), 0, sizeof(*test_context));
+    if (!test_context)
+    {
+        skip("Couldn't allocate memory for test_context\n");
+        goto error;
+    }
+    test_context->hwnd = hwnd;
+    test_context->d3d = d3d;
+    test_context->device = device;
+
+    return test_context;
+
+error:
+    if (device)
+        IDirect3DDevice9_Release(device);
+
+    if (d3d)
+        IDirect3D9_Release(d3d);
+
+    if (hwnd)
+        DestroyWindow(hwnd);
+
+    return NULL;
+}
+
+static void free_test_context(struct test_context *test_context)
+{
+    if (!test_context)
+        return;
+
+    if (test_context->device)
+        IDirect3DDevice9_Release(test_context->device);
+
+    if (test_context->d3d)
+        IDirect3D9_Release(test_context->d3d);
+
+    if (test_context->hwnd)
+        DestroyWindow(test_context->hwnd);
+
+    HeapFree(GetProcessHeap(), 0, test_context);
+}
+
 struct mesh
 {
     DWORD number_of_vertices;
@@ -4259,6 +4347,269 @@ static void D3DXGenerateAdjacencyTest(void)
     if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
 }
 
+static void test_convert_adjacency_to_point_reps(void)
+{
+    HRESULT hr;
+    struct test_context *test_context = NULL;
+    const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
+    const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
+    const D3DVERTEXELEMENT9 declaration[] =
+    {
+        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+        {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+        D3DDECL_END()
+    };
+    const unsigned int VERTS_PER_FACE = 3;
+    void *vertex_buffer;
+    void *index_buffer;
+    DWORD *attributes_buffer;
+    int i, j;
+    struct vertex_pnc
+    {
+        FLOAT x, y, z; /* Position */
+        FLOAT nx, ny, nz; /* Normal */
+        DWORD color; /* In case of manual visual inspection */
+    };
+    /* mesh0 (one face) */
+    const struct vertex_pnc vertices0[] =
+    {
+        {0.0f,  1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+        {1.0f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {-1.0f, -1.0f, 0.f, 0.0f, 0.0f, 1.0f, 0xff0000ff},
+    };
+    const DWORD indices0[] = {0, 1, 2};
+    const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
+    const DWORD adjacency0[] = {-1, -1, -1};
+    DWORD point_rep0[num_vertices0];
+    const DWORD exp_point_rep0[] = {0, 1, 2};
+    /* mesh1 (right) */
+    const struct vertex_pnc vertices1[] =
+    {
+        {0.0f,  1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+        {1.0f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {-1.0f, -1.0f, 0.f, 0.0f, 0.0f, 1.0f, 0xff0000ff},
+
+        {0.1f,  1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+        {2.1f, 1.0f, 0.f,   0.0f, 0.0f, 1.0f, 0xff0000ff},
+        {1.1f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+    };
+    const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
+    const DWORD adjacency1[] = {1, -1, -1, -1, -1, 0};
+    DWORD point_rep1[num_vertices1];
+    const DWORD exp_point_rep1[] = {0, 1, 2, 0, 4, 1};
+    /* mesh2 (below) */
+    struct vertex_pnc vertices2[] =
+    {
+        {0.0f,  1.0f, 0.f,   0.0f, 0.0f, 1.0f, 0xffff0000},
+        {1.0f, -1.0f, 0.f,   0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {-1.0f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff0000ff},
+
+        {-1.0f, -1.1f, 0.f,  0.0f, 0.0f, 1.0f, 0xff0000ff},
+        {1.0f, -1.1f, 0.f,   0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {0.0f,  -3.1f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+    };
+    const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
+    const DWORD adjacency2[] = {-1, 1, -1, 0, -1, -1};
+    DWORD point_rep2[num_vertices2];
+    const DWORD exp_point_rep2[] = {0, 1, 2, 2, 1, 5};
+    /* mesh3 (left) */
+    const struct vertex_pnc vertices3[] =
+    {
+        {0.0f,  1.0f, 0.f,   0.0f, 0.0f, 1.0f, 0xffff0000},
+        {1.0f, -1.0f, 0.f,   0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {-1.0f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff0000ff},
+
+        {-2.0f, 1.0f, 0.f,   0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {-0.1f, 1.0f, 0.f,   0.0f, 0.0f, 1.0f, 0xffff0000},
+        {-1.1f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff0000ff},
+    };
+    const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
+    const DWORD adjacency3[] = {-1, -1, 1, 0, -1, -1};
+    DWORD point_rep3[num_vertices3];
+    const DWORD exp_point_rep3[] = {0, 1, 2, 0, 2, 5};
+    /* mesh4 (above, tip against tip) */
+    struct vertex_pnc vertices4[] =
+    {
+        {0.0f,  1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+        {1.0f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {-1.0f, -1.0f, 0.f, 0.0f, 0.0f, 1.0f, 0xff0000ff},
+
+        {0.0f,  1.1f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+        {-1.0f, 3.1f, 0.f,  0.0f, 0.0f, 1.0f, 0xff0000ff},
+        {1.0f, 3.1f, 0.f,   0.0f, 0.0f, 1.0f, 0xff00ff00},
+    };
+    const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
+    const DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
+    DWORD point_rep4[num_vertices4];
+    const DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
+    /* mesh5 (complex example) */
+    const struct vertex_pnc vertices5[] =
+    {
+        {0.0f, 1.0f, 0.f,   0.0f, 0.0f, 1.0f, 0xffff0000},
+        {1.0f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {-1.0f, -1.0f, 0.f, 0.0f, 0.0f, 1.0f, 0xff0000ff},
+
+        {0.1f, 1.0f, 0.f,   0.0f, 0.0f, 1.0f, 0xffff0000},
+        {2.1f, 1.0f, 0.f,   0.0f, 0.0f, 1.0f, 0xff0000ff},
+        {1.1f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+
+        {-1.0f, -1.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xff0000ff},
+        {1.0f, -1.1f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {0.0f,  -3.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xffff0000},
+
+        {1.1f,  -1.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {2.1f,  -3.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xff0000ff},
+        {0.1f,  -3.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xffff0000},
+
+        {1.2f, -1.1f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {3.2f, -1.1f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+        {2.2f,  -3.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xff0000ff},
+
+        {2.2f,  1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff0000ff},
+        {3.2f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+        {1.2f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+    };
+    const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
+    const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
+    const DWORD adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
+    DWORD point_rep5[num_vertices5];
+    const DWORD exp_point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
+    /* mesh6 (complex example) */
+    const struct vertex_pnc vertices6[] =
+    {
+        {0.0f,  1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+        {1.0f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {-1.0f, -1.0f, 0.f, 0.0f, 0.0f, 1.0f, 0xff0000ff},
+
+        {0.1f,  1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+        {2.1f, 1.0f, 0.f,   0.0f, 0.0f, 1.0f, 0xff0000ff},
+        {1.1f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+
+        {-1.0f, -1.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xff0000ff},
+        {1.0f, -1.1f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {0.0f,  -3.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xffff0000},
+
+        {1.1f,  -1.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {2.1f,  -3.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xff0000ff},
+        {0.1f,  -3.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xffff0000},
+
+        {1.2f, -1.1f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+        {3.2f, -1.1f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+        {2.2f,  -3.1f, 0.f, 0.0f, 0.0f, 1.0f, 0xff0000ff},
+
+        {2.2f,  1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff0000ff},
+        {3.2f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xffff0000},
+        {1.2f, -1.0f, 0.f,  0.0f, 0.0f, 1.0f, 0xff00ff00},
+    };
+    const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 18};
+    const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
+    const DWORD adjacency6[] = {-1, 1, -1, 0, -1, -1, -1, 5, -1, 4, -1, -1, 5, -1, 3, -1, 4, 2, -1, -1, -1};
+    DWORD point_rep6[num_vertices6];
+    const DWORD exp_point_rep6[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5, 18, 19, 20};
+    const WORD indices6_16bit[] = {0, 1, 2, 6, 7, 8, 3, 4, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 18};
+    /* All mesh data */
+    unsigned int attributes[] = {0};
+    const struct vertex_pnc *vertices[] = {vertices0, vertices1, vertices2, vertices3, vertices4, vertices5, vertices6, vertices6};
+    struct
+    {
+       ID3DXMesh *meshes[ARRAY_SIZE(vertices)];
+       const DWORD *indices[ARRAY_SIZE(vertices)];
+       const DWORD num_vertices[ARRAY_SIZE(vertices)];
+       const DWORD *adjacencies[ARRAY_SIZE(vertices)];
+       DWORD *point_reps[ARRAY_SIZE(vertices)];
+       const DWORD *exp_point_reps[ARRAY_SIZE(vertices)];
+       const DWORD options[ARRAY_SIZE(vertices)];
+    }
+    tc =
+    {
+        {NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+        {indices0, indices1, indices2, indices3, indices4, indices5, indices6, (DWORD*)indices6_16bit},
+        {num_vertices0, num_vertices1, num_vertices2, num_vertices3, num_vertices4, num_vertices5, num_vertices6, num_vertices6},
+        {adjacency0, adjacency1, adjacency2, adjacency3, adjacency4, adjacency5, adjacency6, adjacency6},
+        {point_rep0, point_rep1, point_rep2, point_rep3, point_rep4, point_rep5, point_rep6, point_rep6},
+        {exp_point_rep0, exp_point_rep1, exp_point_rep2, exp_point_rep3, exp_point_rep4, exp_point_rep5, exp_point_rep6, exp_point_rep6},
+        {options, options, options, options, options, options, options, options_16bit}
+    };
+
+    test_context = new_test_context();
+    if (!test_context)
+    {
+        skip("Couldn't create test context\n");
+        goto cleanup;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(vertices); i++)
+    {
+        DWORD num_faces = tc.num_vertices[i] / VERTS_PER_FACE;
+        hr = D3DXCreateMesh(num_faces, tc.num_vertices[i], tc.options[i], declaration,
+                            test_context->device, &tc.meshes[i]);
+        if (FAILED(hr))
+        {
+            skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
+            goto cleanup;
+        }
+
+        tc.meshes[i]->lpVtbl->LockVertexBuffer(tc.meshes[i], 0, &vertex_buffer);
+        memcpy(vertex_buffer, vertices[i], tc.num_vertices[i] * sizeof(*vertices[i]));
+        tc.meshes[i]->lpVtbl->UnlockVertexBuffer(tc.meshes[i]);
+
+        tc.meshes[i]->lpVtbl->LockIndexBuffer(tc.meshes[i], 0, &index_buffer);
+        if (tc.options[i] & D3DXMESH_32BIT)
+        {
+
+            memcpy(index_buffer, tc.indices[i], VERTS_PER_FACE * num_faces * sizeof(DWORD));
+        }
+        else
+        {
+            memcpy(index_buffer, tc.indices[i], VERTS_PER_FACE * num_faces * sizeof(WORD));
+        }
+        tc.meshes[i]->lpVtbl->UnlockIndexBuffer(tc.meshes[i]);
+
+        tc.meshes[i]->lpVtbl->LockAttributeBuffer(tc.meshes[i], 0, &attributes_buffer);
+        memcpy(attributes_buffer, attributes, sizeof(attributes));
+        tc.meshes[i]->lpVtbl->UnlockAttributeBuffer(tc.meshes[i]);
+
+        /* Convert adjacency to point representation */
+        memset(tc.point_reps[i], -1, tc.num_vertices[i] * sizeof(*tc.point_reps[i]));
+        hr = tc.meshes[i]->lpVtbl->ConvertAdjacencyToPointReps(tc.meshes[i], tc.adjacencies[i], tc.point_reps[i]);
+        todo_wine ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
+                     "Got %x expected D3D_OK\n", i, hr);
+        /* Check point representation */
+        for (j = 0; j < tc.num_vertices[i]; j++)
+        {
+            todo_wine ok(tc.point_reps[i][j] == tc.exp_point_reps[i][j],
+                         "Unexpected point representation at (%d, %d)."
+                         " Got %d expected %d\n",
+                         i, j, tc.point_reps[i][j], tc.exp_point_reps[i][j]);
+        }
+    }
+
+    /* NULL checks */
+    hr = tc.meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(tc.meshes[0], tc.adjacencies[0], NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
+                 "Got %x expected D3DERR_INVALIDCALL\n", hr);
+    hr = tc.meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(tc.meshes[0], NULL, tc.point_reps[0]);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacencies NULL. "
+                 "Got %x expected D3DERR_INVALIDCALL\n", hr);
+    hr = tc.meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(tc.meshes[0], NULL, NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacencies and point_reps NULL. "
+                 "Got %x expected D3DERR_INVALIDCALL\n", hr);
+
+cleanup:
+    for (i = 0; i < ARRAY_SIZE(vertices); i++)
+    {
+        if (tc.meshes[i])
+            tc.meshes[i]->lpVtbl->Release(tc.meshes[i]);
+    }
+
+    free_test_context(test_context);
+}
+
 START_TEST(mesh)
 {
     D3DXBoundProbeTest();
@@ -4277,4 +4628,5 @@ START_TEST(mesh)
     test_get_decl_vertex_size();
     test_fvf_decl_conversion();
     D3DXGenerateAdjacencyTest();
+    test_convert_adjacency_to_point_reps();
 }
-- 
1.7.5.4

From 41be1283d55a40a6dc6dfc57b87866f4aef4fc3e Mon Sep 17 00:00:00 2001
From: Michael Mc Donnell <mich...@mcdonnell.dk>
Date: Tue, 7 Jun 2011 22:37:42 +0200
Subject: d3dx9: Implemented ConvertAdjacencyToPointReps mesh method

---
 dlls/d3dx9_36/mesh.c       |  162 +++++++++++++++++++++++++++++++++++++++++++-
 dlls/d3dx9_36/tests/mesh.c |   24 +++---
 2 files changed, 172 insertions(+), 14 deletions(-)

diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index cfadb75..8b9e804 100644
--- a/dlls/d3dx9_36/mesh.c
+++ b/dlls/d3dx9_36/mesh.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2009 David Adam
  * Copyright (C) 2010 Tony Wasserka
  * Copyright (C) 2011 Dylan Smith
+ * Copyright (C) 2011 Michael Mc Donnell
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -431,13 +432,170 @@ static HRESULT WINAPI ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh *iface
     return E_NOTIMPL;
 }
 
+/* ConvertAdjacencyToPointReps helper function.
+ *
+ * Goes around the edges of a face and replaces the vertices in any adjacent
+ * face's edge with its own vertices(if its vertices have a lower index). This
+ * way as few as possible low index vertices are shared among the faces. The
+ * re-ordered index buffer is stored in new_indices.
+ *
+ * The vertices in a point representation must be ordered sequentially, e.g.
+ * index 3 holds the index of the vertex that replaces vertex 3, i.e. if
+ * vertex 3 is replaced by vertex 5 then index 3 would contain 5. If no vertex
+ * replaces it, then it contains the same number as the index itself, e.g.
+ * index 3 would contain 3. */
+static HRESULT propagate_face_vertices(CONST DWORD *adjacency, DWORD *point_reps,
+                                    CONST DWORD *indices, DWORD *new_indices,
+                                    CONST DWORD face, CONST DWORD numfaces)
+{
+    const unsigned int VERTS_PER_FACE = 3;
+    DWORD edge, opp_edge;
+    DWORD face_base = VERTS_PER_FACE * face;
+
+    for (edge = 0; edge < VERTS_PER_FACE; edge++)
+    {
+        DWORD adj_face = adjacency[face_base + edge];
+        DWORD adj_face_base;
+        DWORD i,j;
+        if (adj_face == -1) /* No adjacent face. */
+            continue;
+        else if (adj_face >= numfaces)
+        {
+            /* This throws exception on Windows */
+            WARN("Index out of bounds. Got %d expected less than %d.\n",
+                adj_face, numfaces);
+            return D3DERR_INVALIDCALL;
+        }
+        adj_face_base = 3 * adj_face;
+
+        /* Find opposite edge in adjacent face. */
+        for (opp_edge = 0; opp_edge < VERTS_PER_FACE; opp_edge++)
+        {
+            DWORD opp_edge_index = adj_face_base + opp_edge;
+            if (adjacency[opp_edge_index] == face)
+                break; /* Found opposite edge. */
+        }
+
+        /* Replaces vertices in opposite edge with vertices from current edge. */
+        for (i = 0, j = 1; i < 2 && (j+1) > 0; i++, j--)
+        {
+            DWORD from = face_base + (edge + j) % VERTS_PER_FACE;
+            DWORD to = adj_face_base + (opp_edge + i) % VERTS_PER_FACE;
+
+            /* Propagate lowest index. */
+            if (new_indices[to] > new_indices[from])
+            {
+                new_indices[to] = new_indices[from];
+                point_reps[indices[to]] = new_indices[from];
+            }
+        }
+    }
+
+    return D3D_OK;
+}
+
 static HRESULT WINAPI ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh *iface, CONST DWORD *adjacency, DWORD *point_reps)
 {
+    HRESULT hr;
+    DWORD face;
+    DWORD i;
+    DWORD *indices = NULL;
+    WORD *indices_16bit = NULL;
+    DWORD *new_indices = NULL;
+    const unsigned int VERTS_PER_FACE = 3;
+
     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
 
-    FIXME("(%p)->(%p,%p): stub\n", This, adjacency, point_reps);
+    TRACE("(%p)->(%p,%p)\n", This, adjacency, point_reps);
 
-    return E_NOTIMPL;
+    if (!adjacency)
+    {
+        WARN("NULL adjacency.\n");
+        hr = D3DERR_INVALIDCALL;
+        goto cleanup;
+    }
+
+    if (!point_reps)
+    {
+        WARN("NULL point_reps.\n");
+        hr = D3DERR_INVALIDCALL;
+        goto cleanup;
+    }
+
+    /* Should never happen as CreateMesh does not allow meshes with 0 faces */
+    if (This->numfaces == 0)
+    {
+        ERR("Number of faces was zero.");
+        hr = D3DERR_INVALIDCALL;
+        goto cleanup;
+    }
+
+    new_indices = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * This->numfaces * sizeof(*indices));
+    if (!new_indices)
+    {
+        hr = E_OUTOFMEMORY;
+        goto cleanup;
+    }
+
+    if (This->options & D3DXMESH_32BIT)
+    {
+        hr = iface->lpVtbl->LockIndexBuffer(iface, D3DLOCK_READONLY, (void**)&indices);
+        if (FAILED(hr)) goto cleanup;
+        memcpy(new_indices, indices, VERTS_PER_FACE * This->numfaces * sizeof(*indices));
+    }
+    else
+    {
+        /* Make a widening copy of indices_16bit into indices and new_indices
+         * in order to re-use the helper function */
+        hr = iface->lpVtbl->LockIndexBuffer(iface, D3DLOCK_READONLY, (void**)&indices_16bit);
+        if (FAILED(hr)) goto cleanup;
+        indices = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * This->numfaces * sizeof(*indices));
+        if (!indices)
+        {
+            hr = E_OUTOFMEMORY;
+            goto cleanup;
+        }
+        for (i = 0; i < VERTS_PER_FACE * This->numfaces; i++)
+        {
+            new_indices[i] = indices_16bit[i];
+            indices[i] = indices_16bit[i];
+        }
+    }
+
+    /* Vertices are ordered sequentially in the point representation. */
+    for (i = 0; i < This->numvertices; i++)
+    {
+        point_reps[i] = i;
+    }
+
+    /* Propagate vertices with low indices so as few vertices as possible
+     * are used in the mesh.
+     */
+    for (face = 0; face < This->numfaces; face++)
+    {
+        hr = propagate_face_vertices(adjacency, point_reps, indices, new_indices, face, This->numfaces);
+        if (FAILED(hr)) goto cleanup;
+    }
+    /* Go in opposite direction to catch all face orderings */
+    for (face = This->numfaces - 1; face + 1 > 0; face--)
+    {
+        hr = propagate_face_vertices(adjacency, point_reps, indices, new_indices, face, This->numfaces);
+        if (FAILED(hr)) goto cleanup;
+    }
+
+    hr = D3D_OK;
+cleanup:
+    if (This->options & D3DXMESH_32BIT)
+    {
+        if (indices) iface->lpVtbl->UnlockIndexBuffer(iface);
+    }
+    else
+    {
+        if (indices_16bit) iface->lpVtbl->UnlockIndexBuffer(iface);
+        if (indices) HeapFree(GetProcessHeap(), 0, indices);
+    }
+    if (new_indices) HeapFree(GetProcessHeap(), 0, new_indices);
+    return hr;
 }
 
 struct vertex_metadata {
diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index ae4dd26..fbb8fc9 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -4577,28 +4577,28 @@ static void test_convert_adjacency_to_point_reps(void)
         /* Convert adjacency to point representation */
         memset(tc.point_reps[i], -1, tc.num_vertices[i] * sizeof(*tc.point_reps[i]));
         hr = tc.meshes[i]->lpVtbl->ConvertAdjacencyToPointReps(tc.meshes[i], tc.adjacencies[i], tc.point_reps[i]);
-        todo_wine ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
-                     "Got %x expected D3D_OK\n", i, hr);
+        ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
+           "Got %x expected D3D_OK\n", i, hr);
         /* Check point representation */
         for (j = 0; j < tc.num_vertices[i]; j++)
         {
-            todo_wine ok(tc.point_reps[i][j] == tc.exp_point_reps[i][j],
-                         "Unexpected point representation at (%d, %d)."
-                         " Got %d expected %d\n",
-                         i, j, tc.point_reps[i][j], tc.exp_point_reps[i][j]);
+            ok(tc.point_reps[i][j] == tc.exp_point_reps[i][j],
+               "Unexpected point representation at (%d, %d)."
+               " Got %d expected %d\n",
+               i, j, tc.point_reps[i][j], tc.exp_point_reps[i][j]);
         }
     }
 
     /* NULL checks */
     hr = tc.meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(tc.meshes[0], tc.adjacencies[0], NULL);
-    todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
-                 "Got %x expected D3DERR_INVALIDCALL\n", hr);
+    ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
+       "Got %x expected D3DERR_INVALIDCALL\n", hr);
     hr = tc.meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(tc.meshes[0], NULL, tc.point_reps[0]);
-    todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacencies NULL. "
-                 "Got %x expected D3DERR_INVALIDCALL\n", hr);
+    ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacencies NULL. "
+       "Got %x expected D3DERR_INVALIDCALL\n", hr);
     hr = tc.meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(tc.meshes[0], NULL, NULL);
-    todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacencies and point_reps NULL. "
-                 "Got %x expected D3DERR_INVALIDCALL\n", hr);
+    ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacencies and point_reps NULL. "
+       "Got %x expected D3DERR_INVALIDCALL\n", hr);
 
 cleanup:
     for (i = 0; i < ARRAY_SIZE(vertices); i++)
-- 
1.7.5.4



Reply via email to