Dylan Smith : d3dx9: Add support for loading mesh normals from X files.

Alexandre Julliard julliard at winehq.org
Tue May 24 12:53:52 CDT 2011


Module: wine
Branch: master
Commit: 6c9cff2e3f9b1e6fac16b2592080e553f9c38009
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=6c9cff2e3f9b1e6fac16b2592080e553f9c38009

Author: Dylan Smith <dylan.ah.smith at gmail.com>
Date:   Fri May 20 16:25:10 2011 -0400

d3dx9: Add support for loading mesh normals from X files.

---

 dlls/d3dx9_36/mesh.c |  180 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 177 insertions(+), 3 deletions(-)

diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index 69732e3..48ae20e 100644
--- a/dlls/d3dx9_36/mesh.c
+++ b/dlls/d3dx9_36/mesh.c
@@ -36,6 +36,7 @@
 #include "rmxftmpl.h"
 #include "wine/debug.h"
 #include "wine/unicode.h"
+#include "wine/list.h"
 #include "d3dx9_36_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
@@ -1822,6 +1823,12 @@ struct mesh_data {
     DWORD *indices;
 
     DWORD fvf;
+
+    /* optional mesh data */
+
+    DWORD num_normals;
+    D3DXVECTOR3 *normals;
+    DWORD *normal_indices;
 };
 
 static HRESULT get_next_child(IDirectXFileData *filedata, IDirectXFileData **child, const GUID **type)
@@ -1855,6 +1862,95 @@ static HRESULT get_next_child(IDirectXFileData *filedata, IDirectXFileData **chi
     return hr;
 }
 
+static HRESULT parse_normals(IDirectXFileData *filedata, struct mesh_data *mesh)
+{
+    HRESULT hr;
+    DWORD data_size;
+    BYTE *data;
+    DWORD *index_out_ptr;
+    int i;
+    DWORD num_face_indices = mesh->num_poly_faces * 2 + mesh->num_tri_faces;
+
+    HeapFree(GetProcessHeap(), 0, mesh->normals);
+    mesh->num_normals = 0;
+    mesh->normals = NULL;
+    mesh->normal_indices = NULL;
+    mesh->fvf |= D3DFVF_NORMAL;
+
+    hr = IDirectXFileData_GetData(filedata, NULL, &data_size, (void**)&data);
+    if (FAILED(hr)) return hr;
+
+    /* template Vector {
+     *     FLOAT x;
+     *     FLOAT y;
+     *     FLOAT z;
+     * }
+     * template MeshFace {
+     *     DWORD nFaceVertexIndices;
+     *     array DWORD faceVertexIndices[nFaceVertexIndices];
+     * }
+     * template MeshNormals {
+     *     DWORD nNormals;
+     *     array Vector normals[nNormals];
+     *     DWORD nFaceNormals;
+     *     array MeshFace faceNormals[nFaceNormals];
+     * }
+     */
+
+    if (data_size < sizeof(DWORD) * 2)
+        goto truncated_data_error;
+    mesh->num_normals = *(DWORD*)data;
+    data += sizeof(DWORD);
+    if (data_size < sizeof(DWORD) * 2 + mesh->num_normals * sizeof(D3DXVECTOR3) +
+                    num_face_indices * sizeof(DWORD))
+        goto truncated_data_error;
+
+    mesh->normals = HeapAlloc(GetProcessHeap(), 0, mesh->num_normals * sizeof(D3DXVECTOR3));
+    mesh->normal_indices = HeapAlloc(GetProcessHeap(), 0, num_face_indices * sizeof(DWORD));
+    if (!mesh->normals || !mesh->normal_indices)
+        return E_OUTOFMEMORY;
+
+    memcpy(mesh->normals, data, mesh->num_normals * sizeof(D3DXVECTOR3));
+    data += mesh->num_normals * sizeof(D3DXVECTOR3);
+    for (i = 0; i < mesh->num_normals; i++)
+        D3DXVec3Normalize(&mesh->normals[i], &mesh->normals[i]);
+
+    if (*(DWORD*)data != mesh->num_poly_faces) {
+        WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
+             *(DWORD*)data, mesh->num_poly_faces);
+        return E_FAIL;
+    }
+    data += sizeof(DWORD);
+    index_out_ptr = mesh->normal_indices;
+    for (i = 0; i < mesh->num_poly_faces; i++)
+    {
+        DWORD j;
+        DWORD count = *(DWORD*)data;
+        if (count != mesh->num_tri_per_face[i] + 2) {
+            WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
+                 i, count, mesh->num_tri_per_face[i] + 2);
+            return E_FAIL;
+        }
+        data += sizeof(DWORD);
+
+        for (j = 0; j < count; j++) {
+            DWORD normal_index = *(DWORD*)data;
+            if (normal_index >= mesh->num_normals) {
+                WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
+                     i, j, normal_index, mesh->num_normals);
+                return E_FAIL;
+            }
+            *index_out_ptr++ = normal_index;
+            data += sizeof(DWORD);
+        }
+    }
+
+    return D3D_OK;
+truncated_data_error:
+    WARN("truncated data (%u bytes)\n", data_size);
+    return E_FAIL;
+}
+
 /* for provide_flags parameters */
 #define PROVIDE_MATERIALS 0x1
 #define PROVIDE_SKININFO  0x2
@@ -1953,8 +2049,7 @@ static HRESULT parse_mesh(IDirectXFileData *filedata, struct mesh_data *mesh_dat
     while (SUCCEEDED(hr = get_next_child(filedata, &child, &type)))
     {
         if (IsEqualGUID(type, &TID_D3DRMMeshNormals)) {
-            FIXME("Mesh normal loading not implemented.\n");
-            hr = E_NOTIMPL;
+            hr = parse_normals(child, mesh_data);
         } else if (IsEqualGUID(type, &TID_D3DRMMeshVertexColors)) {
             FIXME("Mesh vertex color loading not implemented.\n");
             hr = E_NOTIMPL;
@@ -1997,8 +2092,13 @@ static HRESULT load_skin_mesh_from_xof(IDirectXFileData *filedata,
     HRESULT hr;
     DWORD *index_in_ptr;
     struct mesh_data mesh_data;
+    DWORD total_vertices;
     ID3DXMesh *d3dxmesh = NULL;
     ID3DXBuffer *adjacency = NULL;
+    struct vertex_duplication {
+        DWORD normal_index;
+        struct list entry;
+    } *duplications = NULL;
     int i;
     void *vertices = NULL;
     void *indices = NULL;
@@ -2015,7 +2115,54 @@ static HRESULT load_skin_mesh_from_xof(IDirectXFileData *filedata,
     hr = parse_mesh(filedata, &mesh_data, provide_flags);
     if (FAILED(hr)) goto cleanup;
 
-    hr = D3DXCreateMeshFVF(mesh_data.num_tri_faces, mesh_data.num_vertices, D3DXMESH_MANAGED, mesh_data.fvf, device, &d3dxmesh);
+    total_vertices = mesh_data.num_vertices;
+    if (mesh_data.fvf & D3DFVF_NORMAL) {
+        /* duplicate vertices with multiple normals */
+        DWORD num_face_indices = mesh_data.num_poly_faces * 2 + mesh_data.num_tri_faces;
+        duplications = HeapAlloc(GetProcessHeap(), 0, (mesh_data.num_vertices + num_face_indices) * sizeof(*duplications));
+        if (!duplications) {
+            hr = E_OUTOFMEMORY;
+            goto cleanup;
+        }
+        for (i = 0; i < total_vertices; i++)
+        {
+            duplications[i].normal_index = -1;
+            list_init(&duplications[i].entry);
+        }
+        for (i = 0; i < num_face_indices; i++) {
+            DWORD vertex_index = mesh_data.indices[i];
+            DWORD normal_index = mesh_data.normal_indices[i];
+            struct vertex_duplication *dup_ptr = &duplications[vertex_index];
+
+            if (dup_ptr->normal_index == -1) {
+                dup_ptr->normal_index = normal_index;
+            } else {
+                D3DXVECTOR3 *new_normal = &mesh_data.normals[normal_index];
+                struct list *dup_list = &dup_ptr->entry;
+                while (TRUE) {
+                    D3DXVECTOR3 *cur_normal = &mesh_data.normals[dup_ptr->normal_index];
+                    if (new_normal->x == cur_normal->x &&
+                        new_normal->y == cur_normal->y &&
+                        new_normal->z == cur_normal->z)
+                    {
+                        mesh_data.indices[i] = dup_ptr - duplications;
+                        break;
+                    } else if (!list_next(dup_list, &dup_ptr->entry)) {
+                        dup_ptr = &duplications[total_vertices++];
+                        dup_ptr->normal_index = normal_index;
+                        list_add_tail(dup_list, &dup_ptr->entry);
+                        mesh_data.indices[i] = dup_ptr - duplications;
+                        break;
+                    } else {
+                        dup_ptr = LIST_ENTRY(list_next(dup_list, &dup_ptr->entry),
+                                             struct vertex_duplication, entry);
+                    }
+                }
+            }
+        }
+    }
+
+    hr = D3DXCreateMeshFVF(mesh_data.num_tri_faces, total_vertices, D3DXMESH_MANAGED, mesh_data.fvf, device, &d3dxmesh);
     if (FAILED(hr)) goto cleanup;
 
     hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, &vertices);
@@ -2025,6 +2172,30 @@ static HRESULT load_skin_mesh_from_xof(IDirectXFileData *filedata,
     for (i = 0; i < mesh_data.num_vertices; i++) {
         *(D3DXVECTOR3*)out_ptr = mesh_data.vertices[i];
         out_ptr += sizeof(D3DXVECTOR3);
+        if (mesh_data.fvf & D3DFVF_NORMAL) {
+            if (duplications[i].normal_index == -1)
+                ZeroMemory(out_ptr, sizeof(D3DXVECTOR3));
+            else
+                *(D3DXVECTOR3*)out_ptr = mesh_data.normals[duplications[i].normal_index];
+            out_ptr += sizeof(D3DXVECTOR3);
+        }
+    }
+    if (mesh_data.fvf & D3DFVF_NORMAL) {
+        DWORD vertex_size = D3DXGetFVFVertexSize(mesh_data.fvf);
+        out_ptr = vertices;
+        for (i = 0; i < mesh_data.num_vertices; i++) {
+            struct vertex_duplication *dup_ptr;
+            LIST_FOR_EACH_ENTRY(dup_ptr, &duplications[i].entry, struct vertex_duplication, entry)
+            {
+                int j = dup_ptr - duplications;
+                BYTE *dest_vertex = (BYTE*)vertices + j * vertex_size;
+
+                memcpy(dest_vertex, out_ptr, vertex_size);
+                dest_vertex += sizeof(D3DXVECTOR3);
+                *(D3DXVECTOR3*)dest_vertex = mesh_data.normals[dup_ptr->normal_index];
+            }
+            out_ptr += vertex_size;
+        }
     }
     d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
 
@@ -2078,6 +2249,9 @@ cleanup:
     HeapFree(GetProcessHeap(), 0, mesh_data.vertices);
     HeapFree(GetProcessHeap(), 0, mesh_data.num_tri_per_face);
     HeapFree(GetProcessHeap(), 0, mesh_data.indices);
+    HeapFree(GetProcessHeap(), 0, mesh_data.normals);
+    HeapFree(GetProcessHeap(), 0, mesh_data.normal_indices);
+    HeapFree(GetProcessHeap(), 0, duplications);
     return hr;
 }
 




More information about the wine-cvs mailing list