[4/5] d3dx9: Implement D3DXMESHOPT_ATTRSORT vertex reordering.

Dylan Smith dylan.ah.smith at gmail.com
Fri May 6 11:11:09 CDT 2011


---
 dlls/d3dx9_36/mesh.c |  119 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 113 insertions(+), 6 deletions(-)

diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index 59ef997..4887c76 100644
--- a/dlls/d3dx9_36/mesh.c
+++ b/dlls/d3dx9_36/mesh.c
@@ -664,6 +664,21 @@ static int attrib_entry_compare(const DWORD **a, const DWORD **b)
     return delta;
 }
 
+struct vertex_attrib_duplication {
+    DWORD attrib;
+    DWORD vertex_index;
+    struct vertex_attrib_duplication *ptr;
+};
+
+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 = (BYTE*)a->ptr - (BYTE*)b->ptr;
+    return delta;
+}
+
 static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flags, CONST DWORD *adjacency_in, DWORD *adjacency_out,
                                                     DWORD *face_remap_out, LPD3DXBUFFER *vertex_remap_out)
 {
@@ -750,15 +765,107 @@ static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flag
         DWORD last_attribute;
         DWORD min_vertex, max_vertex;
 
+        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;
-        }
+            /* Reorder vertices */
+            BOOL is_splitting = !(flags & D3DXMESHOPT_DONOTSPLIT);
+            DWORD max_entries = is_splitting ? This->numfaces * 3 : This->numvertices;
+            struct vertex_attrib_duplication *next_duplicate = NULL;
+            DWORD num_duplicates = 0;
+            struct vertex_attrib_duplication **heads = NULL; /* head of list for each vertex */
+            struct vertex_attrib_duplication *duplications;
+            DWORD *vertex_remap_ptr;
+
+            heads = HeapAlloc(GetProcessHeap(), 0, This->numvertices * sizeof(*heads) + max_entries * sizeof(*duplications));
+            if (!heads) {
+                hr = E_OUTOFMEMORY;
+                goto cleanup;
+            }
+            duplications = (struct vertex_attrib_duplication *)(heads + This->numvertices);
+            ZeroMemory(heads, This->numvertices * sizeof(*heads));
+            next_duplicate = duplications;
 
-        hr = iface->lpVtbl->LockAttributeBuffer(iface, 0, &attrib_buffer);
-        if (FAILED(hr)) goto cleanup;
+            for (i = 0; i < This->numfaces * 3; i++)
+            {
+                DWORD vertex_index = dword_indices[i];
+                struct vertex_attrib_duplication *dup_ptr = heads[vertex_index];
+                if (!dup_ptr) {
+                    dup_ptr = next_duplicate++;
+                    dup_ptr->attrib = attrib_buffer[i / 3];
+                    dup_ptr->vertex_index = vertex_index;
+                    dup_ptr->ptr = NULL;
+                    heads[vertex_index] = dup_ptr;
+                } else if (is_splitting) {
+                    DWORD attrib = attrib_buffer[i / 3];
+                    while (dup_ptr->attrib != attrib)
+                    {
+                        if (!dup_ptr->ptr) {
+                            num_duplicates++;
+                            dup_ptr->ptr = next_duplicate++;
+                            dup_ptr = dup_ptr->ptr;
+                            dup_ptr->attrib = attrib;
+                            dup_ptr->vertex_index = vertex_index;
+                            dup_ptr->ptr = NULL;
+                            break;
+                        }
+                        dup_ptr = dup_ptr->ptr;
+                    }
+                }
+            }
+            new_num_vertices = next_duplicate - duplications;
+            /* Sorting depends primarily on the attribute value.
+             * Secondarily it depends on the vertex_index or position in
+             * the duplications array for the first instance of a vertex and
+             * their duplications respectively. This secondary value is
+             * stored in the ptr field, since sorting would invalidate it
+             * anyway. */
+            for (i = 0; i < new_num_vertices; i++)
+                duplications[i].ptr = &duplications[i];
+            for (i = 0; i < This->numvertices; i++) {
+                if (heads[i])
+                    heads[i]->ptr = (struct vertex_attrib_duplication*)&heads[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 */
+            ZeroMemory(heads, This->numvertices * sizeof(*heads));
+            for (i = 0; i < new_num_vertices; i++) {
+                DWORD vertex_index = duplications[i].vertex_index;
+                duplications[i].ptr = heads[vertex_index];
+                heads[vertex_index] = &duplications[i];
+            }
+
+            /* convert indices */
+            for (i = 0; i < This->numfaces * 3; i++) {
+                struct vertex_attrib_duplication *dup_ptr = heads[dword_indices[i]];
+                if (dup_ptr->ptr) {
+                    DWORD attrib = attrib_buffer[i / 3];
+                    while (attrib != dup_ptr->attrib)
+                        dup_ptr = dup_ptr->ptr;
+                }
+                dword_indices[i] = dup_ptr - duplications;
+            }
+
+            /* native behaviour is to allocate a buffer this big, even though using new_num_vertices
+             * would make more sense. */
+            new_vertex_buffer_size = This->numvertices + num_duplicates;
+            hr = D3DXCreateBuffer((This->numvertices + num_duplicates) * sizeof(DWORD), &vertex_remap);
+            if (FAILED(hr)) {
+                HeapFree(GetProcessHeap(), 0, heads);
+                goto cleanup;
+            }
+            /* 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, heads);
+        }
 
         /* Reorder faces in order to sort the attribute table */
         face_remap = HeapAlloc(GetProcessHeap(), 0, This->numfaces * sizeof(*face_remap));
-- 
1.7.2.5




More information about the wine-patches mailing list