[2/4] d3dx9: Implement D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_IGNOREVERTS. (try 3)
Dylan Smith
dylan.ah.smith at gmail.com
Wed May 11 04:30:55 CDT 2011
---
try 3:
- remap faces in a helper function.
- use helper functions for creating the attribute table.
---
dlls/d3dx9_36/mesh.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 181 insertions(+), 12 deletions(-)
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index 95b967b..0ed5030 100644
--- a/dlls/d3dx9_36/mesh.c
+++ b/dlls/d3dx9_36/mesh.c
@@ -694,17 +694,120 @@ static HRESULT compact_mesh(ID3DXMeshImpl *This, DWORD *indices, DWORD *new_num_
return D3D_OK;
}
+/* count the number of unique attribute values in a sorted attribute buffer */
+static DWORD count_attributes(const DWORD *attrib_buffer, DWORD numfaces)
+{
+ DWORD last_attribute = attrib_buffer[0];
+ DWORD attrib_table_size = 1;
+ DWORD i;
+ for (i = 1; i < numfaces; i++) {
+ if (attrib_buffer[i] != last_attribute) {
+ last_attribute = attrib_buffer[i];
+ attrib_table_size++;
+ }
+ }
+ return attrib_table_size;
+}
+
+static void fill_attribute_table(DWORD *attrib_buffer, DWORD numfaces, void *indices,
+ BOOL is_32bit_indices, D3DXATTRIBUTERANGE *attrib_table)
+{
+ DWORD attrib_table_size = 0;
+ DWORD last_attribute = attrib_buffer[0];
+ DWORD min_vertex, max_vertex;
+ DWORD i;
+
+ attrib_table[0].AttribId = last_attribute;
+ attrib_table[0].FaceStart = 0;
+ min_vertex = (DWORD)-1;
+ max_vertex = 0;
+ for (i = 0; i < numfaces; i++) {
+ DWORD j;
+
+ if (attrib_buffer[i] != last_attribute) {
+ last_attribute = attrib_buffer[i];
+ attrib_table[attrib_table_size].FaceCount = i - attrib_table[attrib_table_size].FaceStart;
+ attrib_table[attrib_table_size].VertexStart = min_vertex;
+ attrib_table[attrib_table_size].VertexCount = max_vertex - min_vertex + 1;
+ attrib_table_size++;
+ attrib_table[attrib_table_size].AttribId = attrib_buffer[i];
+ attrib_table[attrib_table_size].FaceStart = i;
+ min_vertex = (DWORD)-1;
+ max_vertex = 0;
+ }
+ for (j = 0; j < 3; j++) {
+ DWORD vertex_index = is_32bit_indices ? ((DWORD*)indices)[i * 3 + j] : ((WORD*)indices)[i * 3 + j];
+ if (vertex_index < min_vertex)
+ min_vertex = vertex_index;
+ if (vertex_index > max_vertex)
+ max_vertex = vertex_index;
+ }
+ }
+ attrib_table[attrib_table_size].FaceCount = i - attrib_table[attrib_table_size].FaceStart;
+ attrib_table[attrib_table_size].VertexStart = min_vertex;
+ attrib_table[attrib_table_size].VertexCount = max_vertex - min_vertex + 1;
+ attrib_table_size++;
+}
+
+static int attrib_entry_compare(const DWORD **a, const DWORD **b)
+{
+ const DWORD *ptr_a = *a;
+ const DWORD *ptr_b = *b;
+ int delta = *ptr_a - *ptr_b;
+
+ if (delta)
+ return delta;
+
+ delta = ptr_a - ptr_b; /* for stable sort */
+ return delta;
+}
+
+/* Create face_remap, a new attribute buffer for attribute sort optimization. */
+static HRESULT remap_faces_for_attrsort(ID3DXMeshImpl *This, const DWORD *indices,
+ const DWORD *attrib_buffer, DWORD **sorted_attrib_buffer, DWORD **face_remap)
+{
+ const DWORD **sorted_attrib_ptr_buffer = NULL;
+ DWORD i;
+
+ *face_remap = HeapAlloc(GetProcessHeap(), 0, This->numfaces * sizeof(**face_remap));
+ sorted_attrib_ptr_buffer = HeapAlloc(GetProcessHeap(), 0, This->numfaces * sizeof(*sorted_attrib_ptr_buffer));
+ if (!*face_remap || !sorted_attrib_ptr_buffer) {
+ HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer);
+ return E_OUTOFMEMORY;
+ }
+ for (i = 0; i < This->numfaces; i++)
+ sorted_attrib_ptr_buffer[i] = &attrib_buffer[i];
+ qsort(sorted_attrib_ptr_buffer, This->numfaces, sizeof(*sorted_attrib_ptr_buffer),
+ (int(*)(const void *, const void *))attrib_entry_compare);
+
+ for (i = 0; i < This->numfaces; i++)
+ {
+ DWORD old_face = sorted_attrib_ptr_buffer[i] - attrib_buffer;
+ (*face_remap)[old_face] = i;
+ }
+
+ /* overwrite sorted_attrib_ptr_buffer with the values themselves */
+ *sorted_attrib_buffer = (DWORD*)sorted_attrib_ptr_buffer;
+ for (i = 0; i < This->numfaces; i++)
+ (*sorted_attrib_buffer)[(*face_remap)[i]] = attrib_buffer[i];
+
+ return D3D_OK;
+}
+
static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flags, CONST DWORD *adjacency_in, DWORD *adjacency_out,
DWORD *face_remap_out, LPD3DXBUFFER *vertex_remap_out)
{
ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
void *indices = NULL;
+ DWORD *attrib_buffer = NULL;
HRESULT hr;
ID3DXBuffer *vertex_remap = NULL;
+ DWORD *face_remap = NULL; /* old -> new mapping */
DWORD *dword_indices = NULL;
DWORD new_num_vertices = 0;
DWORD new_num_alloc_vertices = 0;
IDirect3DVertexBuffer9 *vertex_buffer = NULL;
+ DWORD *sorted_attrib_buffer = NULL;
DWORD i;
TRACE("(%p)->(%x,%p,%p,%p,%p)\n", This, flags, adjacency_in, adjacency_out, face_remap_out, vertex_remap_out);
@@ -716,10 +819,8 @@ static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flag
if ((flags & (D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_STRIPREORDER)) == (D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_STRIPREORDER))
return D3DERR_INVALIDCALL;
- if (flags & (D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_STRIPREORDER))
+ if (flags & (D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_STRIPREORDER))
{
- if (flags & D3DXMESHOPT_ATTRSORT)
- FIXME("D3DXMESHOPT_ATTRSORT not implemented.\n");
if (flags & D3DXMESHOPT_VERTEXCACHE)
FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
if (flags & D3DXMESHOPT_STRIPREORDER)
@@ -740,11 +841,24 @@ static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flag
dword_indices[i] = *word_indices++;
}
- if ((flags & (D3DXMESHOPT_COMPACT | D3DXMESHOPT_IGNOREVERTS)) == D3DXMESHOPT_COMPACT)
+ if ((flags & (D3DXMESHOPT_COMPACT | D3DXMESHOPT_IGNOREVERTS | D3DXMESHOPT_ATTRSORT)) == D3DXMESHOPT_COMPACT)
{
new_num_alloc_vertices = This->numvertices;
hr = compact_mesh(This, dword_indices, &new_num_vertices, &vertex_remap);
if (FAILED(hr)) goto cleanup;
+ } else if (flags & D3DXMESHOPT_ATTRSORT) {
+ if (!(flags & D3DXMESHOPT_IGNOREVERTS))
+ {
+ FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
+ hr = E_NOTIMPL;
+ goto cleanup;
+ }
+
+ hr = iface->lpVtbl->LockAttributeBuffer(iface, 0, &attrib_buffer);
+ if (FAILED(hr)) goto cleanup;
+
+ hr = remap_faces_for_attrsort(This, dword_indices, attrib_buffer, &sorted_attrib_buffer, &face_remap);
+ if (FAILED(hr)) goto cleanup;
}
if (vertex_remap)
@@ -787,20 +901,72 @@ static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flag
*vertex_remap_ptr++ = i;
}
- if (This->options & D3DXMESH_32BIT) {
- memcpy(indices, dword_indices, This->numfaces * 3 * sizeof(DWORD));
+ if (flags & D3DXMESHOPT_ATTRSORT)
+ {
+ D3DXATTRIBUTERANGE *attrib_table;
+ DWORD attrib_table_size;
+
+ attrib_table_size = count_attributes(sorted_attrib_buffer, This->numfaces);
+ attrib_table = HeapAlloc(GetProcessHeap(), 0, attrib_table_size * sizeof(*attrib_table));
+ if (!attrib_table) {
+ hr = E_OUTOFMEMORY;
+ goto cleanup;
+ }
+
+ memcpy(attrib_buffer, sorted_attrib_buffer, This->numfaces * sizeof(*attrib_buffer));
+
+ /* reorder the indices using face_remap */
+ if (This->options & D3DXMESH_32BIT) {
+ for (i = 0; i < This->numfaces; i++)
+ memcpy((DWORD*)indices + face_remap[i] * 3, dword_indices + i * 3, 3 * sizeof(DWORD));
+ } else {
+ WORD *word_indices = indices;
+ for (i = 0; i < This->numfaces; i++) {
+ DWORD new_pos = face_remap[i] * 3;
+ DWORD old_pos = i * 3;
+ word_indices[new_pos++] = dword_indices[old_pos++];
+ word_indices[new_pos++] = dword_indices[old_pos++];
+ word_indices[new_pos] = dword_indices[old_pos];
+ }
+ }
+
+ fill_attribute_table(attrib_buffer, This->numfaces, indices,
+ This->options & D3DXMESH_32BIT, attrib_table);
+
+ HeapFree(GetProcessHeap(), 0, This->attrib_table);
+ This->attrib_table = attrib_table;
+ This->attrib_table_size = attrib_table_size;
} else {
- WORD *word_indices = indices;
- for (i = 0; i < This->numfaces * 3; i++)
- *word_indices++ = dword_indices[i];
+ if (This->options & D3DXMESH_32BIT) {
+ memcpy(indices, dword_indices, This->numfaces * 3 * sizeof(DWORD));
+ } else {
+ WORD *word_indices = indices;
+ for (i = 0; i < This->numfaces * 3; i++)
+ *word_indices++ = dword_indices[i];
+ }
}
if (adjacency_out) {
- memcpy(adjacency_out, adjacency_in, This->numfaces * 3 * sizeof(*adjacency_out));
+ if (face_remap) {
+ for (i = 0; i < This->numfaces; i++) {
+ DWORD old_pos = i * 3;
+ DWORD new_pos = face_remap[i] * 3;
+ adjacency_out[new_pos++] = face_remap[adjacency_in[old_pos++]];
+ adjacency_out[new_pos++] = face_remap[adjacency_in[old_pos++]];
+ adjacency_out[new_pos++] = face_remap[adjacency_in[old_pos++]];
+ }
+ } else {
+ memcpy(adjacency_out, adjacency_in, This->numfaces * 3 * sizeof(*adjacency_out));
+ }
}
if (face_remap_out) {
- for (i = 0; i < This->numfaces; i++)
- face_remap_out[i] = i;
+ if (face_remap) {
+ for (i = 0; i < This->numfaces; i++)
+ face_remap_out[face_remap[i]] = i;
+ } else {
+ for (i = 0; i < This->numfaces; i++)
+ face_remap_out[i] = i;
+ }
}
if (vertex_remap_out)
*vertex_remap_out = vertex_remap;
@@ -815,9 +981,12 @@ static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flag
hr = D3D_OK;
cleanup:
+ HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer);
+ HeapFree(GetProcessHeap(), 0, face_remap);
HeapFree(GetProcessHeap(), 0, dword_indices);
if (vertex_remap) ID3DXBuffer_Release(vertex_remap);
if (vertex_buffer) IDirect3DVertexBuffer9_Release(vertex_buffer);
+ if (attrib_buffer) iface->lpVtbl->UnlockAttributeBuffer(iface);
if (indices) iface->lpVtbl->UnlockIndexBuffer(iface);
return hr;
}
--
1.7.2.5
More information about the wine-patches
mailing list