[prev in list] [next in list] [prev in thread] [next in thread]
List: wine-devel
Subject: =?windows-1252?Q?Re=3A_GSoC=2D2011=3A_Implement_Missing_Mesh_Functions_in_W?=
From: Michael Mc Donnell <michael () mcdonnell ! dk>
Date: 2011-06-30 19:50:45
Message-ID: BANLkTi=5APWY-0ZhsN3HtS_GA4h69tH4aA () mail ! gmail ! com
[Download RAW message or body]
On Thu, Jun 30, 2011 at 6:42 PM, Michael Mc Donnell
<michael@mcdonnell.dk> wrote:
> On Thu, Jun 30, 2011 at 4:10 PM, Henri Verbeet <hverbeet@gmail.com> wrote:
>> On 30 June 2011 14:49, Michael Mc Donnell <michael@mcdonnell.dk> wrote:
>>> In init_edge_face_map I initialize an array of edge_face structs, and
>>> in find_adjacent_face I do a linear search through that array. I would
>>> like to replace the array with a hash table, so that the search time
>>> becomes constant. I've found a standard list (wine/list.h) and
>>> red-black tree implementation (wine/rbtree.h), but not a standard hash
>>> table implementation. Is there a standard hash table implementation,
>>> should I roll my own or find an LGPL'ed one?
>>>
>> I'm not sure if a hash table would be faster and how much, but an easy
>> way to make the lookup cheaper would be to store the edge -> face map
>> as a list for each vertex.
>>
>> ...
>>
>> It's then mostly trivial to determine adjacency. This assumes most
>> vertices are only part of a handful of edges, but I don't think that's
>> unreasonable in practice.
>
> Thanks for your suggestion. I think you're right that it is safe to
> assume that most vertices will only be a part of a few edges. I'll
> implement that for now.
I've implemented the look-up scheme that you described.
I have another question about my test. I've basically copied all the
test data from my ConvertAdjacencyToPointReps test, and then just
inverted the conditions. Should I merge the two tests, put the test
data in a separate function, or just ignore the duplication?
["0001-d3dx9-test-Implemented-ConvertPointRepsToAdjacency-t.patch" (text/x-patch)]
From 549a95e2f8f218541d3f54afd08ee522e4e27e3e Mon Sep 17 00:00:00 2001
From: Michael Mc Donnell <michael@mcdonnell.dk>
Date: Thu, 23 Jun 2011 17:46:51 +0200
Subject: d3dx9/test: Implemented ConvertPointRepsToAdjacency test.
---
dlls/d3dx9_36/tests/mesh.c | 452 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 452 insertions(+), 0 deletions(-)
diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index 98d77d9..1da6ed0 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -4904,6 +4904,457 @@ static void test_create_skin_info(void)
ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
}
+static void test_convert_point_reps_to_adjacency(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 exp_adjacency0[] = {-1, -1, -1};
+ const DWORD 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 exp_adjacency1[] = {-1, 1, -1, -1, -1, 0};
+ const DWORD 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 exp_adjacency2[] = {-1, -1, 1, 0, -1, -1};
+ const DWORD 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 exp_adjacency3[] = {1, -1, -1, -1, 0, -1};
+ const DWORD 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 exp_adjacency4[] = {-1, -1, -1, -1, -1, -1};
+ const DWORD 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 exp_adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
+ const DWORD point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
+ /* 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 exp_adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
+ const DWORD 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 exp_adjacency7[] = {-1, -1, -1, -1, -1, -1};
+ const DWORD point_rep7[] = {0, 1, 2, 3, 4, 5};
+ /* mesh8 (indices re-ordering and double replacement)
+ *
+ * 0--1 9 6
+ * | / /| |\
+ * |/ / | | \
+ * 2 11-10 8--7
+ * 3--4
+ * | /
+ * |/
+ * 5
+ */
+ const struct vertex_pnc vertices8[] =
+ {
+ {{ 0.0f, 3.0f, 0.f}, up, RED},
+ {{ 2.0f, 3.0f, 0.f}, up, GREEN},
+ {{ 0.0f, 0.0f, 0.f}, up, BLUE},
+
+ {{ 4.0, -4.0, 0.f}, up, RED},
+ {{ 6.0, -4.0, 0.f}, up, BLUE},
+ {{ 4.0, -7.0, 0.f}, up, GREEN},
+
+ {{ 4.0f, 3.0f, 0.f}, up, GREEN},
+ {{ 6.0f, 0.0f, 0.f}, up, BLUE},
+ {{ 4.0f, 0.0f, 0.f}, up, RED},
+
+ {{ 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 indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
+ const WORD indices8_16bit[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
+ const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
+ const DWORD exp_adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
+ const DWORD point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
+ /* 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 *point_reps;
+ const DWORD *exp_adjacency;
+ const DWORD options;
+ }
+ tc[] =
+ {
+ {
+ vertices0,
+ indices0,
+ num_vertices0,
+ point_rep0,
+ exp_adjacency0,
+ options
+ },
+ {
+ vertices1,
+ indices1,
+ num_vertices1,
+ point_rep1,
+ exp_adjacency1,
+ options
+ },
+ {
+ vertices2,
+ indices2,
+ num_vertices2,
+ point_rep2,
+ exp_adjacency2,
+ options
+ },
+ {
+ vertices3,
+ indices3,
+ num_vertices3,
+ point_rep3,
+ exp_adjacency3,
+ options
+ },
+ {
+ vertices4,
+ indices4,
+ num_vertices4,
+ point_rep4,
+ exp_adjacency4,
+ options
+ },
+ {
+ vertices5,
+ indices5,
+ num_vertices5,
+ point_rep5,
+ exp_adjacency5,
+ options
+ },
+ {
+ vertices6,
+ indices6,
+ num_vertices6,
+ point_rep6,
+ exp_adjacency6,
+ options
+ },
+ {
+ vertices7,
+ indices7,
+ num_vertices7,
+ point_rep7,
+ exp_adjacency7,
+ options
+ },
+ {
+ vertices8,
+ indices8,
+ num_vertices8,
+ point_rep8,
+ exp_adjacency8,
+ options
+ },
+ {
+ vertices8,
+ (DWORD*)indices8_16bit,
+ num_vertices8,
+ point_rep8,
+ exp_adjacency8,
+ options_16bit
+ },
+ };
+ DWORD *adjacency = NULL;
+
+ 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;
+
+ adjacency = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * num_faces * sizeof(*adjacency));
+ if (!adjacency) { skip("Couldn't allocate adjacency array.\n"); goto cleanup; }
+
+ hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
+ if (FAILED(hr)) { skip("Couldn't lock vertex buffer.\n"); goto cleanup; }
+ memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
+ hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
+ if (FAILED(hr)) { skip("Couldn't unlock vertex buffer.\n"); goto cleanup; }
+
+ hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
+ if (FAILED(hr)) { skip("Couldn't lock index buffer.\n"); goto cleanup; }
+ 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));
+ }
+ hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
+ if (FAILED(hr)) { skip("Couldn't unlock index buffer.\n"); goto cleanup; }
+
+ hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
+ if (FAILED(hr)) { skip("Couldn't lock attributes buffer.\n"); goto cleanup; }
+ memcpy(attributes_buffer, attributes, sizeof(attributes));
+ hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
+ if (FAILED(hr)) { skip("Couldn't unlock attributes buffer.\n"); goto cleanup; }
+
+ /* Convert point representation to adjacency*/
+ memset(adjacency, -2, tc[i].num_vertices * sizeof(*adjacency));
+ hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
+ todo_wine ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
+ "Got %x expected D3D_OK\n", i, hr);
+ /* Check adjacency */
+ for (j = 0; j < tc[i].num_vertices; j++)
+ {
+ todo_wine ok(adjacency[j] == tc[i].exp_adjacency[j],
+ "Unexpected adjacency information at (%d, %d)."
+ " Got %d expected %d\n",
+ i, j, adjacency[j], tc[i].exp_adjacency[j]);
+ }
+
+ /* NULL point representation is considered identity. */
+ memset(adjacency, -2, tc[i].num_vertices * sizeof(*adjacency));
+ hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
+ todo_wine ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
+ "Got %x expected D3D_OK\n", hr);
+ for (j = 0; j < tc[i].num_vertices; j++)
+ {
+ todo_wine ok(adjacency[j] == -1,
+ "Unexpected adjacency information (id) at (%d, %d)."
+ " Got %d expected %d\n",
+ i, j, adjacency[j], -1);
+ }
+
+ HeapFree(GetProcessHeap(), 0, adjacency);
+ if (i != 0) /* First mesh will be freed during cleanup */
+ mesh->lpVtbl->Release(mesh);
+ }
+
+ /* NULL checks */
+ hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
+ todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
+ "Got %x expected D3DERR_INVALIDCALL\n", hr);
+ hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
+ todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
+ "Got %x expected D3DERR_INVALIDCALL\n", hr);
+
+cleanup:
+ if (mesh_null_check)
+ mesh_null_check->lpVtbl->Release(mesh_null_check);
+ HeapFree(GetProcessHeap(), 0, adjacency);
+ free_test_context(test_context);
+}
+
START_TEST(mesh)
{
D3DXBoundProbeTest();
@@ -4924,4 +5375,5 @@ START_TEST(mesh)
D3DXGenerateAdjacencyTest();
test_update_semantics();
test_create_skin_info();
+ test_convert_point_reps_to_adjacency();
}
--
1.7.5.4
["0002-d3dx9-Implemented-ConvertPointRepsToAdjacency.patch" (text/x-patch)]
From 99165650f10b5ec00e1cb525449956421423a66b Mon Sep 17 00:00:00 2001
From: Michael Mc Donnell <michael@mcdonnell.dk>
Date: Mon, 27 Jun 2011 22:44:33 +0200
Subject: d3dx9: Implemented ConvertPointRepsToAdjacency.
Faster lookup of edge_face.
---
dlls/d3dx9_36/mesh.c | 161 +++++++++++++++++++++++++++++++++++++++++++-
dlls/d3dx9_36/tests/mesh.c | 32 +++++-----
2 files changed, 175 insertions(+), 18 deletions(-)
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index 2807150..62df0a3 100644
--- a/dlls/d3dx9_36/mesh.c
+++ b/dlls/d3dx9_36/mesh.c
@@ -432,13 +432,170 @@ static HRESULT WINAPI \
ID3DXMeshImpl_GetAttributeTable(ID3DXMesh *iface, D3DXATTR return D3D_OK;
}
+struct edge_face
+{
+ struct list entry;
+ DWORD v2;
+ DWORD face;
+};
+
+struct edge_face_map
+{
+ struct list *lists;
+ struct edge_face *entries;
+};
+
+/* Builds up a map of which face a new edge belongs to. That way the adjacency
+ * of another edge can be looked up. An edge has an adjacent face if there
+ * is an edge going in the opposite direction in the map. For example if the
+ * edge (v1, v2) belongs to face 4, and there is a mapping (v2, v1)->7, then
+ * face 4 and 7 are adjacent.
+ *
+ * Each edge might have been replaced with another edge, or none at all. There
+ * is at most one edge to face mapping, i.e. an edge can only belong to one
+ * face.
+ */
+static struct edge_face_map *init_edge_face_map(CONST DWORD *index_buffer, CONST \
DWORD *point_reps, CONST DWORD num_faces) +{
+ DWORD face, edge;
+ DWORD i;
+ struct edge_face_map *edge_face_map;
+
+ edge_face_map = HeapAlloc(GetProcessHeap(), 0, sizeof(*edge_face_map));
+ if (!edge_face_map) return NULL;
+
+ edge_face_map->lists = HeapAlloc(GetProcessHeap(), 0, 3 * num_faces * \
sizeof(*edge_face_map->lists)); + if (!edge_face_map->lists) return NULL;
+
+ edge_face_map->entries = HeapAlloc(GetProcessHeap(), 0, 3 * num_faces * \
sizeof(*edge_face_map->entries)); + if (!edge_face_map->entries) return NULL;
+
+ /* Initialize all lists */
+ for (i = 0; i < 3 * num_faces; i++)
+ {
+ list_init(&edge_face_map->lists[i]);
+ }
+ /* Build edge face mapping */
+ for (face = 0; face < num_faces; face++)
+ {
+ for (edge = 0; edge < 3; edge++)
+ {
+ DWORD v1 = index_buffer[3*face + edge];
+ DWORD v2 = index_buffer[3*face + (edge+1)%3];
+ DWORD new_v1 = point_reps[v1]; /* What v1 has been replaced with */
+ DWORD new_v2 = point_reps[v2];
+
+ if (v1 != v2) /* Only map non-collapsed edges */
+ {
+ i = 3*face + edge;
+ edge_face_map->entries[i].v2 = new_v2;
+ edge_face_map->entries[i].face = face;
+ list_add_head(&edge_face_map->lists[new_v1], \
&edge_face_map->entries[i].entry); + }
+ }
+ }
+
+ return edge_face_map;
+}
+
+static void free_edge_face_map(struct edge_face_map *edge_face_map)
+{
+ if (!edge_face_map)
+ return;
+
+ HeapFree(GetProcessHeap(), 0, edge_face_map->lists);
+ HeapFree(GetProcessHeap(), 0, edge_face_map->entries);
+}
+
+static DWORD find_adjacent_face(struct edge_face_map *edge_face_map, DWORD vertex1, \
DWORD vertex2, CONST DWORD num_faces) +{
+ struct edge_face *edge_face_ptr;
+
+ LIST_FOR_EACH_ENTRY(edge_face_ptr, &edge_face_map->lists[vertex2], struct \
edge_face, entry) + {
+ if (edge_face_ptr->v2 == vertex1)
+ return edge_face_ptr->face;
+ }
+
+ return -1;
+}
+
static HRESULT WINAPI ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh *iface, \
CONST DWORD *point_reps, DWORD *adjacency) {
ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
+ HRESULT hr;
+ DWORD num_faces = iface->lpVtbl->GetNumFaces(iface);
+ DWORD options = iface->lpVtbl->GetOptions(iface);
+ BOOL indices_are_16_bit = !(options & D3DXMESH_32BIT);
+ DWORD *ib = NULL;
+ void *ib_ptr = NULL;
+ DWORD face;
+ DWORD edge;
+ struct edge_face_map *edge_face_map = NULL;
- FIXME("(%p)->(%p,%p): stub\n", This, point_reps, adjacency);
+ TRACE("(%p)->(%p,%p)\n", This, point_reps, adjacency);
- return E_NOTIMPL;
+ if (!adjacency) return D3DERR_INVALIDCALL;
+
+ if (!point_reps) /* Indentity point reps */
+ {
+ memset(adjacency, -1, 3 * num_faces * sizeof(*adjacency));
+ return D3D_OK;
+ }
+
+ hr = iface->lpVtbl->LockIndexBuffer(iface, 0, &ib_ptr);
+ if (FAILED(hr)) goto cleanup;
+
+ if (indices_are_16_bit)
+ {
+ /* Widen 16 bit to 32 bit */
+ DWORD i;
+ WORD *ib_16bit = ib_ptr;
+ ib = HeapAlloc(GetProcessHeap(), 0, 3 * num_faces * sizeof(DWORD));
+ if (!ib)
+ {
+ hr = E_OUTOFMEMORY;
+ goto cleanup;
+ }
+ for (i = 0; i < 3 * num_faces; i++)
+ {
+ ib[i] = ib_16bit[i];
+ }
+ }
+ else
+ {
+ ib = ib_ptr;
+ }
+
+ edge_face_map = init_edge_face_map(ib, point_reps, num_faces);
+ if (!edge_face_map)
+ {
+ hr = E_OUTOFMEMORY;
+ goto cleanup;
+ }
+
+ /* Create adjacency */
+ for (face = 0; face < num_faces; face++)
+ {
+ for (edge = 0; edge < 3; edge++)
+ {
+ DWORD v1 = ib[3*face + edge];
+ DWORD v2 = ib[3*face + (edge+1)%3];
+ DWORD new_v1 = point_reps[v1];
+ DWORD new_v2 = point_reps[v2];
+ DWORD adj_face;
+
+ adj_face = find_adjacent_face(edge_face_map, new_v1, new_v2, num_faces);
+ adjacency[3*face + edge] = adj_face;
+ }
+ }
+
+ hr = D3D_OK;
+cleanup:
+ if (indices_are_16_bit) HeapFree(GetProcessHeap(), 0, ib);
+ free_edge_face_map(edge_face_map);
+ iface->lpVtbl->UnlockIndexBuffer(iface);
+ return hr;
}
static HRESULT WINAPI ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh *iface, \
CONST DWORD *adjacency, DWORD *point_reps)
diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index 1da6ed0..e94acd9 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -5311,28 +5311,28 @@ static void test_convert_point_reps_to_adjacency(void)
/* Convert point representation to adjacency*/
memset(adjacency, -2, tc[i].num_vertices * sizeof(*adjacency));
hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, \
adjacency);
- todo_wine ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
- "Got %x expected D3D_OK\n", i, hr);
+ ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
+ "Got %x expected D3D_OK\n", i, hr);
/* Check adjacency */
for (j = 0; j < tc[i].num_vertices; j++)
{
- todo_wine ok(adjacency[j] == tc[i].exp_adjacency[j],
- "Unexpected adjacency information at (%d, %d)."
- " Got %d expected %d\n",
- i, j, adjacency[j], tc[i].exp_adjacency[j]);
+ ok(adjacency[j] == tc[i].exp_adjacency[j],
+ "Unexpected adjacency information at (%d, %d)."
+ " Got %d expected %d\n",
+ i, j, adjacency[j], tc[i].exp_adjacency[j]);
}
/* NULL point representation is considered identity. */
memset(adjacency, -2, tc[i].num_vertices * sizeof(*adjacency));
hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, \
adjacency);
- todo_wine ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
- "Got %x expected D3D_OK\n", hr);
+ ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
+ "Got %x expected D3D_OK\n", hr);
for (j = 0; j < tc[i].num_vertices; j++)
{
- todo_wine ok(adjacency[j] == -1,
- "Unexpected adjacency information (id) at (%d, %d)."
- " Got %d expected %d\n",
- i, j, adjacency[j], -1);
+ ok(adjacency[j] == -1,
+ "Unexpected adjacency information (id) at (%d, %d)."
+ " Got %d expected %d\n",
+ i, j, adjacency[j], -1);
}
HeapFree(GetProcessHeap(), 0, adjacency);
@@ -5342,11 +5342,11 @@ static void test_convert_point_reps_to_adjacency(void)
/* NULL checks */
hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, \
tc[0].point_reps, NULL);
- todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL \
adjacency. "
- "Got %x expected D3DERR_INVALIDCALL\n", hr);
+ ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
+ "Got %x expected D3DERR_INVALIDCALL\n", hr);
hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, \
NULL);
- todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL \
point_reps and adjacency. "
- "Got %x expected D3DERR_INVALIDCALL\n", hr);
+ ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and \
adjacency. " + "Got %x expected D3DERR_INVALIDCALL\n", hr);
cleanup:
if (mesh_null_check)
--
1.7.5.4
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic