On Wed, Jun 22, 2011 at 4:53 PM, Dylan Smith <dylan.ah.sm...@gmail.com> wrote:
> On Wed, Jun 22, 2011 at 10:12 AM, Michael Mc Donnell
> <mich...@mcdonnell.dk> wrote:
>> Thanks your comments. I've attached an updated version.
>
>> +        if (indices) HeapFree(GetProcessHeap(), 0, indices);
>> +    }
>> +    if (new_indices) HeapFree(GetProcessHeap(), 0, new_indices);
>
> HeapFree checks for NULL for you, so remove the NULL check before
> calling HeapFree.

Ok. I see that now in the Wine source. That's a lot nicer than on Windows.

>> +    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}
>> +    };
>
> I actually meant something more like:
>
> --- snip ---
> struct {
>    const DWORD *indices,
>    const DWORD num_vertices,
>    const DWORD *adjacencies,
>    DWORD *point_reps,
>    const DWORD *exp_point_reps,
>    const DWORD options,
> } tc[] = {
>    {indices0, num_vertices0, adjacency0, point_rep0, exp_point_rep0, options},
>    {indices1, num_vertices1, adjacency1, point_rep1, exp_point_rep1, options},
>    ...
> }

Ah ok :-) That makes more sense.

> ...
>
> for (i = 0; i < ARRAY_SIZE(tc); i++)
> {
>    ...
> }
> --- snip ---
>
> I don't think storing an array of meshes is necessary.  You can just
> release the mesh and set the mesh variable to NULL (as needed to avoid
> re-releasing) before creating another one.

I've changed it so that it only keeps the first mesh around for the NULL checks.

My UpdateSemantics patch finally got applied so I've removed the
duplicate functions too.
From 039b27048842da6823f5f8a621cbd22a3c632c6c 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 |  332 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 332 insertions(+), 0 deletions(-)

diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index 26a0c10..ee9ad67 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -4676,6 +4676,337 @@ 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;
+    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 */
+    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
+        },
+        {
+            vertices6,
+            (DWORD*)indices6_16bit,
+            num_vertices6,
+            adjacency6,
+            point_rep6,
+            exp_point_rep6,
+            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 +5026,5 @@ START_TEST(mesh)
     test_fvf_decl_conversion();
     D3DXGenerateAdjacencyTest();
     test_update_semantics();
+    test_convert_adjacency_to_point_reps();
 }
-- 
1.7.5.4

From 570a2ef8504cad352c8dc9678fb945342b14798c 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..f996b2a 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 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);
+        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 ee9ad67..bee9279 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -4974,15 +4974,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 */
@@ -4991,14 +4991,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