Here is my test and implementation of ConvertAdjacencyToPointReps.

Note that two of the helper functions and a struct in the test were
also included in my UpdateSemantics patch. I'll remove them once my
UpdateSemantics patch is in the official tree.

Any comments?

Thanks,
Michael Mc Donnell
From 012ccb29ee8360a33e0c6809ab00ab0ff352fb4a 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 |  335 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 335 insertions(+), 0 deletions(-)

diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index 668097f..6275511 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,252 @@ 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;
+    DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
+    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 VERTICES_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) */
+    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},
+    };
+    DWORD indices0[] = {0, 1, 2};
+    const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
+    const unsigned int num_faces0 = num_vertices0 / VERTICES_PER_FACE;
+    DWORD adjacency0[] = {-1, -1, -1};
+    DWORD point_rep0[num_vertices0];
+    DWORD exp_point_rep0[] = {0, 1, 2};
+    /* mesh1 (right) */
+    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},
+    };
+    DWORD indices1[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
+    const unsigned int num_faces1 = num_vertices1 / VERTICES_PER_FACE;
+    DWORD adjacency1[] = {1, -1, -1, -1, -1, 0};
+    DWORD point_rep1[num_vertices1];
+    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},
+    };
+    DWORD indices2[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
+    const unsigned int num_faces2 = num_vertices2 / VERTICES_PER_FACE;
+    DWORD adjacency2[] = {-1, 1, -1, 0, -1, -1};
+    DWORD point_rep2[num_vertices2];
+    DWORD exp_point_rep2[] = {0, 1, 2, 2, 1, 5};
+    /* mesh3 (left) */
+    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},
+    };
+    DWORD indices3[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
+    const unsigned int num_faces3 = num_vertices3 / VERTICES_PER_FACE;
+    DWORD adjacency3[] = {-1, -1, 1, 0, -1, -1};
+    DWORD point_rep3[num_vertices3];
+    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},
+    };
+    DWORD indices4[] = {0, 1, 2, 3, 4, 5};
+    const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
+    const unsigned int num_faces4 = num_vertices4 / VERTICES_PER_FACE;
+    DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
+    DWORD point_rep4[num_vertices4];
+    DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
+    /* mesh5 (complex example) */
+    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},
+    };
+    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 unsigned int num_faces5 = num_vertices5 / VERTICES_PER_FACE;
+    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];
+    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) */
+    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},
+    };
+    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 unsigned int num_faces6 = num_vertices6 / VERTICES_PER_FACE;
+    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];
+    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};
+    /* 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};
+    unsigned int attributes[] = {0};
+
+    test_context = new_test_context();
+    if (!test_context)
+    {
+        skip("Couldn't create test context\n");
+        goto cleanup;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(meshes); i++)
+    {
+        hr = D3DXCreateMesh(num_faces[i], num_vertices[i], options, declaration,
+                            test_context->device, &meshes[i]);
+        if (FAILED(hr))
+        {
+            skip("Couldn't create mesh %#x\n", hr);
+            goto cleanup;
+        }
+
+        meshes[i]->lpVtbl->LockVertexBuffer(meshes[i], 0, &vertex_buffer);
+        memcpy(vertex_buffer, vertices[i], num_vertices[i] * sizeof(*vertices[i]));
+        meshes[i]->lpVtbl->UnlockVertexBuffer(meshes[i]);
+
+        meshes[i]->lpVtbl->LockIndexBuffer(meshes[i], 0, &index_buffer);
+        memcpy(index_buffer, indices[i], num_vertices[i] * sizeof(*indices[i]));
+        meshes[i]->lpVtbl->UnlockIndexBuffer(meshes[i]);
+
+        meshes[i]->lpVtbl->LockAttributeBuffer(meshes[i], 0, &attributes_buffer);
+        memcpy(attributes_buffer, attributes, sizeof(attributes));
+        meshes[i]->lpVtbl->UnlockAttributeBuffer(meshes[i]);
+
+        /* Convert adjacency to point representation */
+        memset(point_reps[i], -1, num_vertices[i] * sizeof(*indices[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);
+        /* Check point representation */
+        for (j=0; j < num_vertices[i]; j++)
+        {
+            todo_wine ok(point_reps[i][j] == exp_point_reps[i][j],
+                         "Unexpected point representation at (%d, %d)."
+                         " Got %d expected %d\n",
+                         i, j, point_reps[i][j], exp_point_reps[i][j]);
+        }
+    }
+
+    /* NULL checks */
+    hr = meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(meshes[0], adjacencies[0], NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
+                 "Got %x expected D3DERR_INVALIDCALL\n", hr);
+    hr = meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(meshes[0], NULL, point_reps[0]);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacencies NULL. "
+                 "Got %x expected D3DERR_INVALIDCALL\n", hr);
+    hr = meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(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(meshes); i++)
+    {
+        if (meshes[i])
+            meshes[i]->lpVtbl->Release(meshes[i]);
+    }
+
+    free_test_context(test_context);
+}
+
 START_TEST(mesh)
 {
     D3DXBoundProbeTest();
@@ -4277,4 +4611,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 a882290efd16e1cc4363ea87b8be0dfd171c8c9f 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       |  130 +++++++++++++++++++++++++++++++++++++++++++-
 dlls/d3dx9_36/tests/mesh.c |   24 ++++----
 2 files changed, 140 insertions(+), 14 deletions(-)

diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index cfadb75..4486118 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,138 @@ 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;
+    DWORD *new_indices = NULL;
+
     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, This->numvertices * sizeof(*indices));
+    if (!new_indices)
+    {
+        hr = E_OUTOFMEMORY;
+        goto cleanup;
+    }
+    hr = iface->lpVtbl->LockIndexBuffer(iface, D3DLOCK_READONLY, (void**)&indices);
+    if (FAILED(hr)) goto cleanup;
+    memcpy(new_indices, indices, This->numvertices * sizeof(*indices));
+
+    /* 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 (new_indices) HeapFree(GetProcessHeap(), 0, new_indices);
+    if (indices) iface->lpVtbl->UnlockIndexBuffer(iface);
+    return hr;
 }
 
 struct vertex_metadata {
diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index 6275511..412cda3 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -4560,28 +4560,28 @@ static void test_convert_adjacency_to_point_reps(void)
         /* Convert adjacency to point representation */
         memset(point_reps[i], -1, num_vertices[i] * sizeof(*indices[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);
+        ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed. "
+           "Got %x expected D3D_OK\n", hr);
         /* Check point representation */
         for (j=0; j < num_vertices[i]; j++)
         {
-            todo_wine ok(point_reps[i][j] == exp_point_reps[i][j],
-                         "Unexpected point representation at (%d, %d)."
-                         " Got %d expected %d\n",
-                         i, j, point_reps[i][j], exp_point_reps[i][j]);
+            ok(point_reps[i][j] == exp_point_reps[i][j],
+               "Unexpected point representation at (%d, %d)."
+               " Got %d expected %d\n",
+               i, j, point_reps[i][j], exp_point_reps[i][j]);
         }
     }
 
     /* NULL checks */
     hr = meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(meshes[0], 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 = meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(meshes[0], NULL, 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 = meshes[0]->lpVtbl->ConvertAdjacencyToPointReps(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(meshes); i++)
-- 
1.7.5.4



Reply via email to