d3dx9: Implemented ConvertPointRepsToAdjacency.

This commit is contained in:
Michael Mc Donnell 2011-06-27 22:44:33 +02:00 committed by Alexandre Julliard
parent 5552613b81
commit 507daa2154
2 changed files with 190 additions and 17 deletions

View File

@ -432,13 +432,186 @@ static HRESULT WINAPI ID3DXMeshImpl_GetAttributeTable(ID3DXMesh *iface, D3DXATTR
return D3D_OK; 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 HRESULT init_edge_face_map(struct edge_face_map *edge_face_map, CONST DWORD *index_buffer, CONST DWORD *point_reps, CONST DWORD num_faces)
{
DWORD face, edge;
DWORD i;
edge_face_map->lists = HeapAlloc(GetProcessHeap(), 0, 3 * num_faces * sizeof(*edge_face_map->lists));
if (!edge_face_map->lists) return E_OUTOFMEMORY;
edge_face_map->entries = HeapAlloc(GetProcessHeap(), 0, 3 * num_faces * sizeof(*edge_face_map->entries));
if (!edge_face_map->entries) return E_OUTOFMEMORY;
/* 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 D3D_OK;
}
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 DWORD *generate_identity_point_reps(DWORD num_vertices)
{
DWORD *id_point_reps;
DWORD i;
id_point_reps = HeapAlloc(GetProcessHeap(), 0, num_vertices * sizeof(*id_point_reps));
if (!id_point_reps)
return NULL;
for (i = 0; i < num_vertices; i++)
{
id_point_reps[i] = i;
}
return id_point_reps;
}
static HRESULT WINAPI ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh *iface, CONST DWORD *point_reps, DWORD *adjacency) static HRESULT WINAPI ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh *iface, CONST DWORD *point_reps, DWORD *adjacency)
{ {
ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface); ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
HRESULT hr;
DWORD num_faces = iface->lpVtbl->GetNumFaces(iface);
DWORD num_vertices = iface->lpVtbl->GetNumVertices(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 = {0};
CONST DWORD *point_reps_ptr = NULL;
DWORD *id_point_reps = 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) /* Identity point reps */
{
id_point_reps = generate_identity_point_reps(num_vertices);
if (!id_point_reps)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
point_reps_ptr = id_point_reps;
}
else
{
point_reps_ptr = point_reps;
}
hr = iface->lpVtbl->LockIndexBuffer(iface, D3DLOCK_READONLY, &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;
}
hr = init_edge_face_map(&edge_face_map, ib, point_reps_ptr, num_faces);
if (FAILED(hr)) 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_ptr[v1];
DWORD new_v2 = point_reps_ptr[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:
HeapFree(GetProcessHeap(), 0, id_point_reps);
if (indices_are_16_bit) HeapFree(GetProcessHeap(), 0, ib);
HeapFree(GetProcessHeap(), 0, edge_face_map.lists);
HeapFree(GetProcessHeap(), 0, edge_face_map.entries);
if(ib_ptr) iface->lpVtbl->UnlockIndexBuffer(iface);
return hr;
} }
/* ConvertAdjacencyToPointReps helper function. /* ConvertAdjacencyToPointReps helper function.

View File

@ -5923,28 +5923,28 @@ static void test_convert_point_reps_to_adjacency(void)
/* Convert point representation to adjacency*/ /* Convert point representation to adjacency*/
memset(adjacency, -2, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency)); memset(adjacency, -2, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency); hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
todo_wine ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. " ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
"Got %x expected D3D_OK\n", i, hr); "Got %x expected D3D_OK\n", i, hr);
/* Check adjacency */ /* Check adjacency */
for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
{ {
todo_wine ok(adjacency[j] == tc[i].exp_adjacency[j], ok(adjacency[j] == tc[i].exp_adjacency[j],
"Unexpected adjacency information at (%d, %d)." "Unexpected adjacency information at (%d, %d)."
" Got %d expected %d\n", " Got %d expected %d\n",
i, j, adjacency[j], tc[i].exp_adjacency[j]); i, j, adjacency[j], tc[i].exp_adjacency[j]);
} }
/* NULL point representation is considered identity. */ /* NULL point representation is considered identity. */
memset(adjacency, -2, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency)); memset(adjacency, -2, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency); hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
todo_wine ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. " ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
"Got %x expected D3D_OK\n", hr); "Got %x expected D3D_OK\n", hr);
for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
{ {
todo_wine ok(adjacency[j] == tc[i].exp_id_adjacency[j], ok(adjacency[j] == tc[i].exp_id_adjacency[j],
"Unexpected adjacency information (id) at (%d, %d)." "Unexpected adjacency information (id) at (%d, %d)."
" Got %d expected %d\n", " Got %d expected %d\n",
i, j, adjacency[j], tc[i].exp_id_adjacency[j]); i, j, adjacency[j], tc[i].exp_id_adjacency[j]);
} }
HeapFree(GetProcessHeap(), 0, adjacency); HeapFree(GetProcessHeap(), 0, adjacency);
@ -5954,11 +5954,11 @@ static void test_convert_point_reps_to_adjacency(void)
/* NULL checks */ /* NULL checks */
hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL); hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. " ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
"Got %x expected D3DERR_INVALIDCALL\n", hr); "Got %x expected D3DERR_INVALIDCALL\n", hr);
hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL); hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
todo_wine ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. " ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
"Got %x expected D3DERR_INVALIDCALL\n", hr); "Got %x expected D3DERR_INVALIDCALL\n", hr);
cleanup: cleanup:
if (mesh_null_check) if (mesh_null_check)