[PATCH] d3dx9_36: Implement ID3DXSkinInfoImpl_UpdateSkinnedMesh.

Christian Costa titan.costa at gmail.com
Wed Jun 5 01:48:59 CDT 2013


This patch fixes last problem of bug 32572.
---
 dlls/d3dx9_36/skin.c |  125 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 123 insertions(+), 2 deletions(-)

diff --git a/dlls/d3dx9_36/skin.c b/dlls/d3dx9_36/skin.c
index c3857d6..4a8b80a 100644
--- a/dlls/d3dx9_36/skin.c
+++ b/dlls/d3dx9_36/skin.c
@@ -2,6 +2,7 @@
  * Skin Info operations specific to D3DX9.
  *
  * Copyright (C) 2011 Dylan Smith
+ * Copyright (C) 2013 Christian Costa
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -42,6 +43,7 @@ typedef struct ID3DXSkinInfoImpl
     DWORD num_vertices;
     DWORD num_bones;
     struct bone *bones;
+    DWORD *vertices_refcounts;
 } ID3DXSkinInfoImpl;
 
 static inline struct ID3DXSkinInfoImpl *impl_from_ID3DXSkinInfo(ID3DXSkinInfo *iface)
@@ -90,6 +92,7 @@ static ULONG WINAPI ID3DXSkinInfoImpl_Release(ID3DXSkinInfo *iface)
             HeapFree(GetProcessHeap(), 0, This->bones[i].weights);
         }
         HeapFree(GetProcessHeap(), 0, This->bones);
+        HeapFree(GetProcessHeap(), 0, This->vertices_refcounts);
         HeapFree(GetProcessHeap(), 0, This);
     }
 
@@ -102,6 +105,7 @@ static HRESULT WINAPI ID3DXSkinInfoImpl_SetBoneInfluence(ID3DXSkinInfo *iface, D
     struct bone *bone;
     DWORD *new_vertices = NULL;
     FLOAT *new_weights = NULL;
+    DWORD i;
 
     TRACE("(%p, %u, %u, %p, %p)\n", This, bone_num, num_influences, vertices, weights);
 
@@ -121,11 +125,21 @@ static HRESULT WINAPI ID3DXSkinInfoImpl_SetBoneInfluence(ID3DXSkinInfo *iface, D
         memcpy(new_weights, weights, num_influences * sizeof(*weights));
     }
     bone = &This->bones[bone_num];
+    /* Decrement refcounts of vertices previously influenced */
+    for (i = 0; i < bone->num_influences; i++)
+        if (bone->vertices[i] < This->num_vertices) /* Ignore out of range value */
+            This->vertices_refcounts[bone->vertices[i]]--;
     bone->num_influences = num_influences;
     HeapFree(GetProcessHeap(), 0, bone->vertices);
     HeapFree(GetProcessHeap(), 0, bone->weights);
     bone->vertices = new_vertices;
     bone->weights = new_weights;
+    /* Increment refcounts of vertices newly influenced */
+    for (i = 0; i < bone->num_influences; i++)
+    {
+        if (bone->vertices[i] < This->num_vertices) /* Ignore out of range value */
+            This->vertices_refcounts[bone->vertices[i]]--;
+    }
 
     return D3D_OK;
 }
@@ -382,10 +396,110 @@ static HRESULT WINAPI ID3DXSkinInfoImpl_UpdateSkinnedMesh(ID3DXSkinInfo *iface,
         CONST D3DXMATRIX *bone_inv_transpose_transforms, LPCVOID vertices_src, PVOID vertices_dest)
 {
     ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
+    DWORD i, j;
+    DWORD size = D3DXGetFVFVertexSize(This->fvf);
 
-    FIXME("(%p, %p, %p, %p, %p): stub\n", This, bone_transforms, bone_inv_transpose_transforms, vertices_src, vertices_dest);
+    TRACE("(%p, %p, %p, %p, %p)\n", This, bone_transforms, bone_inv_transpose_transforms, vertices_src, vertices_dest);
 
-    return E_NOTIMPL;
+    if (bone_inv_transpose_transforms)
+        FIXME("Skinning vertices with two position elements not supported\n");
+
+    if ((This->fvf & D3DFVF_POSITION_MASK) != D3DFVF_XYZ)
+    {
+        FIXME("Vertex type %#x not supported\n", This->fvf & D3DFVF_POSITION_MASK);
+        return E_FAIL;
+    }
+
+    /* Copy all vertices to destination array for skinning update */
+    if (vertices_dest != vertices_src)
+        memcpy(vertices_dest, vertices_src, size * This->num_vertices);
+
+    /* Reset positions that are influenced by bones */
+    for (i = 0; i < This->num_vertices; i++)
+    {
+        if (This->vertices_refcounts[i])
+        {
+            D3DXVECTOR3 *position = (D3DXVECTOR3*)((BYTE*)vertices_dest + size * i);
+            position->x = 0.0f;
+            position->y = 0.0f;
+            position->z = 0.0f;
+        }
+    }
+
+    /* Update positions that are influenced by bones */
+    for (i = 0; i < This->num_bones; i++)
+    {
+        D3DXMATRIX bone_inverse;
+
+        D3DXMatrixInverse(&bone_inverse, NULL, &This->bones[i].transform);
+
+        for (j = 0; j < This->bones[i].num_influences; j++)
+        {
+            D3DXMATRIX matrix;
+            D3DXVECTOR3 position;
+            D3DXVECTOR3 *position_src = (D3DXVECTOR3*)((BYTE*)vertices_src + size * This->bones[i].vertices[j]);
+            D3DXVECTOR3 *position_dest = (D3DXVECTOR3*)((BYTE*)vertices_dest + size * This->bones[i].vertices[j]);
+            FLOAT weight = This->bones[i].weights[j];
+
+            D3DXVec3TransformCoord(&position, position_src, &bone_inverse);
+            D3DXMatrixMultiply(&matrix, &This->bones[i].transform, &bone_transforms[i]);
+            D3DXVec3TransformCoord(&position, &position, &matrix);
+            position_dest->x += weight * position.x;
+            position_dest->y += weight * position.y;
+            position_dest->z += weight * position.z;
+        }
+    }
+
+    if (This->fvf & D3DFVF_NORMAL)
+    {
+        /* Reset normals that are influenced by bones */
+        for (i = 0; i < This->num_vertices; i++)
+        {
+            if (This->vertices_refcounts[i])
+            {
+                D3DXVECTOR3 *normal = (D3DXVECTOR3*)((BYTE*)vertices_dest + size * i + sizeof(D3DXVECTOR3));
+                normal->x = 0.0f;
+                normal->y = 0.0f;
+                normal->z = 0.0f;
+            }
+        }
+
+        /* Update normals that are influenced by bones */
+        for (i = 0; i < This->num_bones; i++)
+        {
+            D3DXMATRIX bone_inverse;
+
+            D3DXMatrixInverse(&bone_inverse, NULL, &This->bones[i].transform);
+
+            for (j = 0; j < This->bones[i].num_influences; j++)
+            {
+                D3DXMATRIX matrix;
+                D3DXVECTOR3 normal;
+                D3DXVECTOR3 *normal_src = (D3DXVECTOR3*)((BYTE*)vertices_src + size * This->bones[i].vertices[j] + sizeof(D3DXVECTOR3));
+                D3DXVECTOR3 *normal_dest = (D3DXVECTOR3*)((BYTE*)vertices_dest + size * This->bones[i].vertices[j] + sizeof(D3DXVECTOR3));
+                FLOAT weight = This->bones[i].weights[j];
+
+                D3DXVec3TransformCoord(&normal, normal_src, &bone_inverse);
+                D3DXMatrixMultiply(&matrix, &This->bones[i].transform, &bone_transforms[i]);
+                D3DXVec3TransformCoord(&normal, &normal, &matrix);
+                normal_dest->x += weight * normal.x;
+                normal_dest->y += weight * normal.y;
+                normal_dest->z += weight * normal.z;
+            }
+        }
+
+        /* Normalize all normals that are influenced by bones*/
+        for (i = 0; i < This->num_vertices; i++)
+        {
+            if (This->vertices_refcounts[i])
+            {
+                D3DXVECTOR3 *normal_dest = (D3DXVECTOR3*)((BYTE*)vertices_dest + (i * size) + sizeof(D3DXVECTOR3));
+                D3DXVec3Normalize(normal_dest, normal_dest);
+            }
+        }
+    }
+
+    return D3D_OK;
 }
 
 static HRESULT WINAPI ID3DXSkinInfoImpl_ConvertToBlendedMesh(ID3DXSkinInfo *iface, ID3DXMesh *mesh_in,
@@ -478,6 +592,12 @@ HRESULT WINAPI D3DXCreateSkinInfo(DWORD num_vertices, const D3DVERTEXELEMENT9 *d
         goto error;
     }
 
+    object->vertices_refcounts = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_vertices * sizeof(*object->vertices_refcounts));
+    if (!object->bones) {
+        hr = E_OUTOFMEMORY;
+        goto error;
+    }
+
     hr = ID3DXSkinInfoImpl_SetDeclaration(&object->ID3DXSkinInfo_iface, declaration);
     if (FAILED(hr)) goto error;
 
@@ -486,6 +606,7 @@ HRESULT WINAPI D3DXCreateSkinInfo(DWORD num_vertices, const D3DVERTEXELEMENT9 *d
     return D3D_OK;
 error:
     HeapFree(GetProcessHeap(), 0, object->bones);
+    HeapFree(GetProcessHeap(), 0, object->vertices_refcounts);
     HeapFree(GetProcessHeap(), 0, object);
     return hr;
 }




More information about the wine-patches mailing list