[3/5] d3dx9: Implement D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_IGNOREVERTS.
Dylan Smith
dylan.ah.smith at gmail.com
Fri May 6 11:10:59 CDT 2011
---
dlls/d3dx9_36/mesh.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 157 insertions(+), 12 deletions(-)
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index bab3331..59ef997 100644
--- a/dlls/d3dx9_36/mesh.c
+++ b/dlls/d3dx9_36/mesh.c
@@ -651,17 +651,35 @@ static HRESULT WINAPI ID3DXMeshImpl_Optimize(ID3DXMesh *iface, DWORD flags, CONS
return E_NOTIMPL;
}
+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;
+}
+
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_vertex_buffer_size = 0;
IDirect3DVertexBuffer9 *vertex_buffer = NULL;
+ DWORD *sorted_attrib_buffer = NULL;
+ DWORD table_size = 0;
+ D3DXATTRIBUTERANGE *attrib_table = NULL;
DWORD i;
TRACE("(%p)->(%x,%p,%p,%p,%p)\n", This, flags, adjacency_in, adjacency_out, face_remap_out, vertex_remap_out);
@@ -673,10 +691,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)
@@ -697,7 +713,7 @@ 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)
{
/* Remove unused vertices. */
DWORD *vertex_remap_ptr;
@@ -729,6 +745,94 @@ static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flag
}
for (i = new_num_vertices; i < This->numvertices; i++)
vertex_remap_ptr[i] = -1;
+ } else if (flags & D3DXMESHOPT_ATTRSORT) {
+ DWORD **sorted_attrib_ptr_buffer = NULL;
+ DWORD last_attribute;
+ DWORD min_vertex, max_vertex;
+
+ 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;
+
+ /* Reorder faces in order to sort the attribute table */
+ 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);
+ hr = E_OUTOFMEMORY;
+ goto cleanup;
+ }
+ 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;
+ }
+
+ /* create attribute table */
+ last_attribute = *sorted_attrib_ptr_buffer[0];
+ table_size = 1;
+ for (i = 1; i < This->numfaces; i++) {
+ if (*sorted_attrib_ptr_buffer[i] != last_attribute) {
+ last_attribute = *sorted_attrib_ptr_buffer[i];
+ table_size++;
+ }
+ }
+
+ attrib_table = HeapAlloc(GetProcessHeap(), 0, table_size * sizeof(*attrib_table));
+ if (!attrib_table) {
+ hr = E_OUTOFMEMORY;
+ goto cleanup;
+ }
+ table_size = 0;
+ last_attribute = *sorted_attrib_ptr_buffer[0];
+ attrib_table[0].AttribId = last_attribute;
+ attrib_table[0].FaceStart = 0;
+ min_vertex = (DWORD)-1;
+ max_vertex = 0;
+ for (i = 0; i < This->numfaces; i++) {
+ int j;
+ DWORD old_pos;
+ if (*sorted_attrib_ptr_buffer[i] != last_attribute) {
+ last_attribute = *sorted_attrib_ptr_buffer[i];
+ attrib_table[table_size].FaceCount = i - attrib_table[table_size].FaceStart;
+ attrib_table[table_size].VertexStart = min_vertex;
+ attrib_table[table_size].VertexCount = max_vertex - min_vertex + 1;
+ table_size++;
+ attrib_table[table_size].AttribId = *sorted_attrib_ptr_buffer[i];
+ attrib_table[table_size].FaceStart = i;
+ min_vertex = (DWORD)-1;
+ max_vertex = 0;
+ }
+ old_pos = sorted_attrib_ptr_buffer[i] - attrib_buffer;
+ old_pos *= 3;
+ for (j = 0; j < 3; j++) {
+ DWORD vertex_index = dword_indices[old_pos++];
+ if (vertex_index < min_vertex)
+ min_vertex = vertex_index;
+ if (vertex_index > max_vertex)
+ max_vertex = vertex_index;
+ }
+ }
+ attrib_table[table_size].FaceCount = i - attrib_table[table_size].FaceStart;
+ attrib_table[table_size].VertexStart = min_vertex;
+ attrib_table[table_size].VertexCount = max_vertex - min_vertex + 1;
+ table_size++;
+
+ /* 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];
}
if (vertex_remap)
@@ -772,20 +876,57 @@ static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flag
*vertex_remap_ptr++ = i;
}
- if (This->options & D3DXMESH_32BIT) {
- CopyMemory(indices, dword_indices, This->numfaces * 3 * sizeof(DWORD));
+ if (flags & D3DXMESHOPT_ATTRSORT)
+ {
+ hr = iface->lpVtbl->SetAttributeTable(iface, attrib_table, table_size);
+ if (FAILED(hr)) goto cleanup;
+
+ CopyMemory(attrib_buffer, sorted_attrib_buffer, This->numfaces * sizeof(*attrib_buffer));
+
+ if (This->options & D3DXMESH_32BIT) {
+ for (i = 0; i < This->numfaces; i++)
+ CopyMemory((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];
+ }
+ }
} else {
- WORD *word_indices = indices;
- for (i = 0; i < This->numfaces * 3; i++)
- *word_indices++ = dword_indices[i];
+ if (This->options & D3DXMESH_32BIT) {
+ CopyMemory(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) {
- CopyMemory(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 {
+ CopyMemory(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;
@@ -800,9 +941,13 @@ 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);
+ HeapFree(GetProcessHeap(), 0, attrib_table);
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