[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