Module: wine Branch: master Commit: ea5ed35edfa56d1259edebe9a74af00b29906789 URL: http://source.winehq.org/git/wine.git/?a=commit;h=ea5ed35edfa56d1259edebe9a7...
Author: Michael Mc Donnell michael@mcdonnell.dk Date: Tue Jun 7 22:37:42 2011 +0200
d3dx9: Implemented ConvertAdjacencyToPointReps mesh method.
---
dlls/d3dx9_36/mesh.c | 161 +++++++++++++++++++++++++++++++++++++++++++- dlls/d3dx9_36/tests/mesh.c | 18 +++--- 2 files changed, 168 insertions(+), 11 deletions(-)
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index dfe6a35..717c356 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 b3aed39..6522ff1 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -5386,16 +5386,16 @@ static void test_convert_adjacency_to_point_reps(void) /* Convert adjacency to point representation */ memset(point_reps, -1, tc[i].num_vertices * sizeof(*point_reps)); hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacency, point_reps); - todo_wine ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. " + 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(point_reps[j] == tc[i].exp_point_reps[j], - "Unexpected point representation at (%d, %d)." - " Got %d expected %d\n", - i, j, point_reps[j], tc[i].exp_point_reps[j]); + ok(point_reps[j] == tc[i].exp_point_reps[j], + "Unexpected point representation at (%d, %d)." + " Got %d expected %d\n", + i, j, point_reps[j], tc[i].exp_point_reps[j]); }
HeapFree(GetProcessHeap(), 0, point_reps); @@ -5406,11 +5406,11 @@ static void test_convert_adjacency_to_point_reps(void)
/* NULL checks */ hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacency, 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, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. " - "Got %x expected D3DERR_INVALIDCALL\n", hr); + ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. " + "Got %x expected D3DERR_INVALIDCALL\n", hr);
cleanup: if (mesh_null_check)