[3/4] d3dx9: Implement D3DXMESHOPT_ATTRSORT vertex reordering. (try 3)
Dylan Smith
dylan.ah.smith at gmail.com
Wed May 11 04:31:03 CDT 2011
---
try 3: remap vertices in a helper function.
---
dlls/d3dx9_36/mesh.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 133 insertions(+), 6 deletions(-)
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index 0ed5030..650686a 100644
--- a/dlls/d3dx9_36/mesh.c
+++ b/dlls/d3dx9_36/mesh.c
@@ -32,6 +32,7 @@
#include "d3dx9.h"
#include "wine/debug.h"
#include "wine/unicode.h"
+#include "wine/list.h"
#include "d3dx9_36_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
@@ -694,6 +695,131 @@ static HRESULT compact_mesh(ID3DXMeshImpl *This, DWORD *indices, DWORD *new_num_
return D3D_OK;
}
+struct vertex_attrib_duplication {
+ DWORD attrib;
+ DWORD vertex_index;
+ union {
+ int orig_order;
+ struct list entry;
+ } u;
+};
+
+static int vertex_attrib_compare(const struct vertex_attrib_duplication *a,
+ const struct vertex_attrib_duplication *b)
+{
+ int delta = a->attrib - b->attrib;
+ if (delta) return delta;
+ delta = a->u.orig_order - b->u.orig_order;
+ return delta;
+}
+
+/* Creates vertex_remap for attribute sort optimization.
+ * Indices are updated according to the vertex_remap. */
+static HRESULT remap_vertices_for_attrsort(ID3DXMeshImpl *This, DWORD *indices,
+ const DWORD *attrib_buffer, BOOL split_vertices, DWORD *new_num_vertices,
+ DWORD *new_num_alloc_vertices, ID3DXBuffer **vertex_remap)
+{
+ HRESULT hr;
+ DWORD max_entries = split_vertices ? This->numfaces * 3 : This->numvertices;
+ struct vertex_attrib_duplication *next_duplicate = NULL;
+ DWORD num_duplicates = 0;
+ struct list *heads = NULL; /* head of list for each vertex */
+ struct vertex_attrib_duplication *duplications;
+ DWORD *vertex_remap_ptr;
+ DWORD i;
+
+ heads = HeapAlloc(GetProcessHeap(), 0, This->numvertices * sizeof(*heads));
+ if (!heads) return E_OUTOFMEMORY;
+ duplications = HeapAlloc(GetProcessHeap(), 0, max_entries * sizeof(*duplications));
+ if (!duplications) {
+ HeapFree(GetProcessHeap(), 0, heads);
+ return E_OUTOFMEMORY;
+ }
+ for (i = 0; i < This->numvertices; i++)
+ list_init(&heads[i]);
+ next_duplicate = duplications;
+
+ for (i = 0; i < This->numfaces * 3; i++)
+ {
+ DWORD vertex_index = indices[i];
+ struct list *vertex_list = &heads[vertex_index];
+ struct vertex_attrib_duplication *dup_ptr;
+ if (list_empty(vertex_list)) {
+ dup_ptr = next_duplicate++;
+ dup_ptr->attrib = attrib_buffer[i / 3];
+ dup_ptr->vertex_index = vertex_index;
+ list_add_tail(vertex_list, &dup_ptr->u.entry);
+ } else if (split_vertices) {
+ DWORD attrib = attrib_buffer[i / 3];
+ BOOL found = FALSE;
+ LIST_FOR_EACH_ENTRY(dup_ptr, vertex_list, struct vertex_attrib_duplication, u.entry)
+ {
+ if (dup_ptr->attrib == attrib) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found) {
+ num_duplicates++;
+ dup_ptr = next_duplicate++;
+ dup_ptr->attrib = attrib;
+ dup_ptr->vertex_index = vertex_index;
+ list_add_tail(vertex_list, &dup_ptr->u.entry);
+ }
+ }
+ }
+ *new_num_vertices = next_duplicate - duplications;
+ /* Sorting must be a stable sort to match native behaviour.
+ * The orig_order field mimics the desired relative original order
+ * for use in vertex_attrib_compare. */
+ for (i = 0; i < *new_num_vertices; i++)
+ duplications[i].u.orig_order = This->numvertices + i;
+ for (i = 0; i < This->numvertices; i++) {
+ if (!list_empty(&heads[i]))
+ LIST_ENTRY(list_head(&heads[i]), struct vertex_attrib_duplication, u.entry)->u.orig_order = i;
+ }
+ qsort(duplications, *new_num_vertices, sizeof(*duplications),
+ (int(*)(const void *, const void *))vertex_attrib_compare);
+ /* reconstruct the list of duplications for each vertex index */
+ for (i = 0; i < This->numvertices; i++)
+ list_init(&heads[i]);
+ for (i = 0; i < *new_num_vertices; i++)
+ list_add_tail(&heads[duplications[i].vertex_index], &duplications[i].u.entry);
+
+ /* convert indices */
+ for (i = 0; i < This->numfaces * 3; i++) {
+ struct list *vertex_list = &heads[indices[i]];
+ struct vertex_attrib_duplication *dup_ptr;
+ DWORD attrib = attrib_buffer[i / 3];
+
+ LIST_FOR_EACH_ENTRY(dup_ptr, vertex_list, struct vertex_attrib_duplication, u.entry)
+ {
+ if (attrib == dup_ptr->attrib)
+ indices[i] = dup_ptr - duplications;
+ }
+ }
+
+ HeapFree(GetProcessHeap(), 0, heads);
+
+ /* native behaviour is to allocate a buffer this big, even though using new_num_vertices
+ * would make more sense. */
+ *new_num_alloc_vertices = This->numvertices + num_duplicates;
+ hr = D3DXCreateBuffer(*new_num_alloc_vertices * sizeof(DWORD), vertex_remap);
+ if (FAILED(hr)) {
+ HeapFree(GetProcessHeap(), 0, duplications);
+ return hr;
+ }
+ /* create new->old vertex map */
+ vertex_remap_ptr = ID3DXBuffer_GetBufferPointer(*vertex_remap);
+ for (i = 0; i < *new_num_vertices; i++)
+ *vertex_remap_ptr++ = duplications[i].vertex_index;
+ for (; i < This->numvertices + num_duplicates; i++)
+ *vertex_remap_ptr++ = -1;
+
+ HeapFree(GetProcessHeap(), 0, duplications);
+ 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)
{
@@ -847,16 +973,17 @@ static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flag
hr = compact_mesh(This, dword_indices, &new_num_vertices, &vertex_remap);
if (FAILED(hr)) goto cleanup;
} else if (flags & D3DXMESHOPT_ATTRSORT) {
+ hr = iface->lpVtbl->LockAttributeBuffer(iface, 0, &attrib_buffer);
+ if (FAILED(hr)) goto cleanup;
+
if (!(flags & D3DXMESHOPT_IGNOREVERTS))
{
- FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
- hr = E_NOTIMPL;
- goto cleanup;
+ BOOL split_vertices = !(flags & D3DXMESHOPT_DONOTSPLIT);
+ hr = remap_vertices_for_attrsort(This, dword_indices, attrib_buffer, split_vertices,
+ &new_num_vertices, &new_num_alloc_vertices, &vertex_remap);
+ if (FAILED(hr)) 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;
}
--
1.7.2.5
More information about the wine-patches
mailing list