On Thu, Jun 23, 2011 at 5:50 AM, Dylan Smith <dylan.ah.sm...@gmail.com> wrote:
> On Wed, Jun 22, 2011 at 4:08 PM, Stefan Dösinger <stefandoesin...@gmx.at> 
> wrote:
>> I'll have to do some more background reading on the kind of mesh data 
>> structures used here before I can give qualified comments on your patches, 
>> so for now I'll yield to Dylan :-)
>
> I looked over the latest patches, and the code looks good now, but I
> have a couple of nitpicks for the comments.

Sounds good :-)

> +/* ConvertAdjacencyToPointReps helper function.
> + *
> + * Goes around the edges of a face and replaces the vertices in any adjacent
>
> (changed word is in caps, but capitalization not needed)
>  * Goes around the edges of EACH face...

Check.

> + * 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. */
>
> Your example has vertex 5 replacing vertex 3, which doesn't seem
> possible if lower vertex indices always replace higher vertex indices.

You're right it is the other way around. Thanks for reading it thoroughly.

I've change the test a bit. I split up the complex example (mesh6)
into two simpler examples. I also got inspired by your ASCII
illustrations and have added my own in the comments. The examples have
also been updated so that they are easier to draw by hand (except for
mesh5).
From 14c25fde0240779a948dd0382e4ca672b6edbff1 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 |  408 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 408 insertions(+), 0 deletions(-)

diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index 26a0c10..1f5a37e 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -4676,6 +4676,413 @@ cleanup:
     free_test_context(test_context);
 }
 
+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;
+    enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
+    struct vertex_pnc
+    {
+        D3DXVECTOR3 position;
+        D3DXVECTOR3 normal;
+        enum color color; /* In case of manual visual inspection */
+    };
+    D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
+    /* mesh0 (one face)
+     *
+     * 0--1
+     * | /
+     * |/
+     * 2
+     */
+    const struct vertex_pnc vertices0[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    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)
+     *
+     * 0--1 3
+     * | / /|
+     * |/ / |
+     * 2 5--4
+     */
+    const struct vertex_pnc vertices1[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 3.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 3.0f,  0.0f,  0.f}, up, RED},
+        {{ 1.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    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, 1, 4, 2};
+    /* mesh2 (left)
+     *
+     *    3 0--1
+     *   /| | /
+     *  / | |/
+     * 5--4 2
+     */
+    const struct vertex_pnc vertices2[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{-1.0f,  3.0f,  0.f}, up, RED},
+        {{-1.0f,  0.0f,  0.f}, up, GREEN},
+        {{-3.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    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, 0, 2, 5};
+    /* mesh3 (above)
+     *
+     *    3
+     *   /|
+     *  / |
+     * 5--4
+     * 0--1
+     * | /
+     * |/
+     * 2
+     */
+    struct vertex_pnc vertices3[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 2.0f,  7.0f,  0.f}, up, BLUE},
+        {{ 2.0f,  4.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  4.0f,  0.f}, up, RED},
+    };
+    const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
+    const DWORD adjacency3[] = {1, -1, -1, -1, 0, -1};
+    DWORD point_rep3[num_vertices3];
+    const DWORD exp_point_rep3[] = {0, 1, 2, 3, 1, 0};
+    /* mesh4 (below, tip against tip)
+     *
+     * 0--1
+     * | /
+     * |/
+     * 2
+     * 3
+     * |\
+     * | \
+     * 5--4
+     */
+    struct vertex_pnc vertices4[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 0.0f, -4.0f,  0.f}, up, BLUE},
+        {{ 2.0f, -7.0f,  0.f}, up, GREEN},
+        {{ 0.0f, -7.0f,  0.f}, up, RED},
+    };
+    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 (gap in mesh)
+     *
+     *    0      3-----4  15
+     *   / \      \   /  /  \
+     *  /   \      \ /  /    \
+     * 2-----1      5 17-----16
+     * 6-----7      9 12-----13
+     *  \   /      / \  \    /
+     *   \ /      /   \  \  /
+     *    8     10-----11 14
+     *
+     */
+    const struct vertex_pnc vertices5[] =
+    {
+        {{ 0.0f,  1.0f,  0.f}, up, RED},
+        {{ 1.0f, -1.0f,  0.f}, up, GREEN},
+        {{-1.0f, -1.0f,  0.f}, up, BLUE},
+
+        {{ 0.1f,  1.0f,  0.f}, up, RED},
+        {{ 2.1f,  1.0f,  0.f}, up, BLUE},
+        {{ 1.1f, -1.0f,  0.f}, up, GREEN},
+
+        {{-1.0f, -1.1f,  0.f}, up, BLUE},
+        {{ 1.0f, -1.1f,  0.f}, up, GREEN},
+        {{ 0.0f, -3.1f,  0.f}, up, RED},
+
+        {{ 1.1f, -1.1f,  0.f}, up, GREEN},
+        {{ 2.1f, -3.1f,  0.f}, up, BLUE},
+        {{ 0.1f, -3.1f,  0.f}, up, RED},
+
+        {{ 1.2f, -1.1f,  0.f}, up, GREEN},
+        {{ 3.2f, -1.1f,  0.f}, up, RED},
+        {{ 2.2f, -3.1f,  0.f}, up, BLUE},
+
+        {{ 2.2f,  1.0f,  0.f}, up, BLUE},
+        {{ 3.2f, -1.0f,  0.f}, up, RED},
+        {{ 1.2f, -1.0f,  0.f}, up, GREEN},
+    };
+    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};
+    const WORD indices5_16bit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
+    /* mesh6 (indices re-ordering)
+     *
+     * 0--1 6 3
+     * | / /| |\
+     * |/ / | | \
+     * 2 8--7 5--4
+     */
+    const struct vertex_pnc vertices6[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 3.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 3.0f,  0.0f,  0.f}, up, RED},
+        {{ 1.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 4.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 6.0f,  0.0f,  0.f}, up, BLUE},
+        {{ 4.0f,  0.0f,  0.f}, up, RED},
+    };
+    const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
+    const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
+    const DWORD adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
+    DWORD point_rep6[num_vertices6];
+    const DWORD exp_point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
+    /* mesh7 (expands collapsed triangle)
+     *
+     * 0--1 3
+     * | / /|
+     * |/ / |
+     * 2 5--4
+     */
+    const struct vertex_pnc vertices7[] =
+    {
+        {{ 0.0f,  3.0f,  0.f}, up, RED},
+        {{ 2.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 0.0f,  0.0f,  0.f}, up, BLUE},
+
+        {{ 3.0f,  3.0f,  0.f}, up, GREEN},
+        {{ 3.0f,  0.0f,  0.f}, up, RED},
+        {{ 1.0f,  0.0f,  0.f}, up, BLUE},
+    };
+    const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
+    const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
+    const DWORD adjacency7[] = {-1, -1, -1, -1, -1, -1};
+    DWORD point_rep7[num_vertices7];
+    const DWORD exp_point_rep7[] = {0, 1, 2, 3, 4, 5};
+    /* All mesh data */
+    ID3DXMesh *mesh = NULL;
+    ID3DXMesh *mesh_null_check = NULL;
+    unsigned int attributes[] = {0};
+    struct
+    {
+        const struct vertex_pnc *vertices;
+        const DWORD *indices;
+        const DWORD num_vertices;
+        const DWORD *adjacencies;
+        DWORD *point_reps;
+        const DWORD *exp_point_reps;
+        const DWORD options;
+    }
+    tc[] =
+    {
+        {
+            vertices0,
+            indices0,
+            num_vertices0,
+            adjacency0,
+            point_rep0,
+            exp_point_rep0,
+            options
+        },
+        {
+            vertices1,
+            indices1,
+            num_vertices1,
+            adjacency1,
+            point_rep1,
+            exp_point_rep1,
+            options
+        },
+        {
+            vertices2,
+            indices2,
+            num_vertices2,
+            adjacency2,
+            point_rep2,
+            exp_point_rep2,
+            options
+        },
+        {
+            vertices3,
+            indices3,
+            num_vertices3,
+            adjacency3,
+            point_rep3,
+            exp_point_rep3,
+            options
+        },
+        {
+            vertices4,
+            indices4,
+            num_vertices4,
+            adjacency4,
+            point_rep4,
+            exp_point_rep4,
+            options
+        },
+        {
+            vertices5,
+            indices5,
+            num_vertices5,
+            adjacency5,
+            point_rep5,
+            exp_point_rep5,
+            options
+        },
+        {
+            vertices6,
+            indices6,
+            num_vertices6,
+            adjacency6,
+            point_rep6,
+            exp_point_rep6,
+            options
+        },
+        {
+            vertices7,
+            indices7,
+            num_vertices7,
+            adjacency7,
+            point_rep7,
+            exp_point_rep7,
+            options
+        },
+        {
+            vertices5,
+            (DWORD*)indices5_16bit,
+            num_vertices5,
+            adjacency5,
+            point_rep5,
+            exp_point_rep5,
+            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(tc); i++)
+    {
+        DWORD num_faces = tc[i].num_vertices / VERTS_PER_FACE;
+        hr = D3DXCreateMesh(num_faces, tc[i].num_vertices, tc[i].options, declaration,
+                            test_context->device, &mesh);
+        if (FAILED(hr))
+        {
+            skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
+            goto cleanup;
+        }
+
+        if (i == 0) /* Save first mesh for later NULL checks */
+            mesh_null_check = mesh;
+
+        mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
+        memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
+        mesh->lpVtbl->UnlockVertexBuffer(mesh);
+
+        mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
+        if (tc[i].options & D3DXMESH_32BIT)
+        {
+            memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * num_faces * sizeof(DWORD));
+        }
+        else
+        {
+            memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * num_faces * sizeof(WORD));
+        }
+        mesh->lpVtbl->UnlockIndexBuffer(mesh);
+
+        mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
+        memcpy(attributes_buffer, attributes, sizeof(attributes));
+        mesh->lpVtbl->UnlockAttributeBuffer(mesh);
+
+        /* Convert adjacency to point representation */
+        memset(tc[i].point_reps, -1, tc[i].num_vertices * sizeof(*tc[i].point_reps));
+        hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacencies, tc[i].point_reps);
+        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[i].num_vertices; j++)
+        {
+            todo_wine ok(tc[i].point_reps[j] == tc[i].exp_point_reps[j],
+                         "Unexpected point representation at (%d, %d)."
+                         " Got %d expected %d\n",
+                         i, j, tc[i].point_reps[j], tc[i].exp_point_reps[j]);
+        }
+
+        if (i != 0) /* First mesh will be freed during cleanup */
+            mesh->lpVtbl->Release(mesh);
+    }
+
+    /* NULL checks */
+    hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacencies, NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
+                 "Got %x expected D3DERR_INVALIDCALL\n", hr);
+    hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, tc[0].point_reps);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacencies NULL. "
+                 "Got %x expected D3DERR_INVALIDCALL\n", hr);
+    hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacencies and point_reps NULL. "
+                 "Got %x expected D3DERR_INVALIDCALL\n", hr);
+
+cleanup:
+    if (mesh_null_check)
+        mesh_null_check->lpVtbl->Release(mesh_null_check);
+
+    free_test_context(test_context);
+}
+
 START_TEST(mesh)
 {
     D3DXBoundProbeTest();
@@ -4695,4 +5102,5 @@ START_TEST(mesh)
     test_fvf_decl_conversion();
     D3DXGenerateAdjacencyTest();
     test_update_semantics();
+    test_convert_adjacency_to_point_reps();
 }
-- 
1.7.5.4

From 5fe36b7c1a4eef4868d7b81984baade64ea70026 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       |  161 +++++++++++++++++++++++++++++++++++++++++++-
 dlls/d3dx9_36/tests/mesh.c |   24 +++---
 2 files changed, 171 insertions(+), 14 deletions(-)

diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index 0455ea7..ece5f25 100644
--- a/dlls/d3dx9_36/mesh.c
+++ b/dlls/d3dx9_36/mesh.c
@@ -441,13 +441,170 @@ static HRESULT WINAPI ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh *iface
     return E_NOTIMPL;
 }
 
+/* ConvertAdjacencyToPointReps helper function.
+ *
+ * Goes around the edges of each 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 5 holds the index of the vertex that replaces vertex 5, i.e. if
+ * vertex 5 is replaced by vertex 3 then index 5 would contain 3. If no vertex
+ * replaces it, then it contains the same number as the index itself, e.g.
+ * index 5 would contain 5. */
+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);
+        HeapFree(GetProcessHeap(), 0, 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 1f5a37e..23af5bb 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -5050,15 +5050,15 @@ static void test_convert_adjacency_to_point_reps(void)
         /* Convert adjacency to point representation */
         memset(tc[i].point_reps, -1, tc[i].num_vertices * sizeof(*tc[i].point_reps));
         hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacencies, tc[i].point_reps);
-        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[i].num_vertices; j++)
         {
-            todo_wine ok(tc[i].point_reps[j] == tc[i].exp_point_reps[j],
-                         "Unexpected point representation at (%d, %d)."
-                         " Got %d expected %d\n",
-                         i, j, tc[i].point_reps[j], tc[i].exp_point_reps[j]);
+            ok(tc[i].point_reps[j] == tc[i].exp_point_reps[j],
+               "Unexpected point representation at (%d, %d)."
+               " Got %d expected %d\n",
+               i, j, tc[i].point_reps[j], tc[i].exp_point_reps[j]);
         }
 
         if (i != 0) /* First mesh will be freed during cleanup */
@@ -5067,14 +5067,14 @@ static void test_convert_adjacency_to_point_reps(void)
 
     /* NULL checks */
     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacencies, 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 = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, tc[0].point_reps);
-    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 = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, 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:
     if (mesh_null_check)
-- 
1.7.5.4



Reply via email to