diff --git a/dll/directx/wine/d3dx9_36/skin.c b/dll/directx/wine/d3dx9_36/skin.c index ea4f45d9b4f..e45d0cb40cf 100644 --- a/dll/directx/wine/d3dx9_36/skin.c +++ b/dll/directx/wine/d3dx9_36/skin.c @@ -5,6 +5,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 @@ -403,10 +404,89 @@ static HRESULT WINAPI d3dx9_skin_info_GetDeclaration(ID3DXSkinInfo *iface, static HRESULT WINAPI d3dx9_skin_info_UpdateSkinnedMesh(ID3DXSkinInfo *iface, const D3DXMATRIX *bone_transforms, const D3DXMATRIX *bone_inv_transpose_transforms, const void *src_vertices, void *dst_vertices) { - FIXME("iface %p, bone_transforms %p, bone_inv_transpose_transforms %p, src_vertices %p, dst_vertices %p stub!\n", - iface, bone_transforms, bone_inv_transpose_transforms, src_vertices, dst_vertices); + struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface); + DWORD size = D3DXGetFVFVertexSize(skin->fvf); + DWORD i, j; - return E_NOTIMPL; + TRACE("iface %p, bone_transforms %p, bone_inv_transpose_transforms %p, src_vertices %p, dst_vertices %p\n", + skin, bone_transforms, bone_inv_transpose_transforms, src_vertices, dst_vertices); + + if (bone_inv_transpose_transforms) + FIXME("Skinning vertices with two position elements not supported\n"); + + if ((skin->fvf & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) { + FIXME("Vertex type %#x not supported\n", skin->fvf & D3DFVF_POSITION_MASK); + return E_FAIL; + } + + /* Reset all positions */ + for (i = 0; i < skin->num_vertices; i++) { + D3DXVECTOR3 *position = (D3DXVECTOR3*)((BYTE*)dst_vertices + 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 < skin->num_bones; i++) { + D3DXMATRIX bone_inverse, matrix; + + D3DXMatrixInverse(&bone_inverse, NULL, &skin->bones[i].transform); + D3DXMatrixMultiply(&matrix, &bone_transforms[i], &bone_inverse); + D3DXMatrixMultiply(&matrix, &matrix, &skin->bones[i].transform); + + for (j = 0; j < skin->bones[i].num_influences; j++) { + D3DXVECTOR3 position; + D3DXVECTOR3 *position_src = (D3DXVECTOR3*)((BYTE*)src_vertices + size * skin->bones[i].vertices[j]); + D3DXVECTOR3 *position_dest = (D3DXVECTOR3*)((BYTE*)dst_vertices + size * skin->bones[i].vertices[j]); + FLOAT weight = skin->bones[i].weights[j]; + + D3DXVec3TransformCoord(&position, position_src, &matrix); + position_dest->x += weight * position.x; + position_dest->y += weight * position.y; + position_dest->z += weight * position.z; + } + } + + if (skin->fvf & D3DFVF_NORMAL) { + /* Reset all normals */ + for (i = 0; i < skin->num_vertices; i++) { + D3DXVECTOR3 *normal = (D3DXVECTOR3*)((BYTE*)dst_vertices + 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 < skin->num_bones; i++) { + D3DXMATRIX bone_inverse, matrix; + + D3DXMatrixInverse(&bone_inverse, NULL, &skin->bones[i].transform); + D3DXMatrixMultiply(&matrix, &skin->bones[i].transform, &bone_transforms[i]); + + for (j = 0; j < skin->bones[i].num_influences; j++) { + D3DXVECTOR3 normal; + D3DXVECTOR3 *normal_src = (D3DXVECTOR3*)((BYTE*)src_vertices + size * skin->bones[i].vertices[j] + sizeof(D3DXVECTOR3)); + D3DXVECTOR3 *normal_dest = (D3DXVECTOR3*)((BYTE*)dst_vertices + size * skin->bones[i].vertices[j] + sizeof(D3DXVECTOR3)); + FLOAT weight = skin->bones[i].weights[j]; + + D3DXVec3TransformNormal(&normal, normal_src, &bone_inverse); + D3DXVec3TransformNormal(&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 < skin->num_vertices; i++) { + D3DXVECTOR3 *normal_dest = (D3DXVECTOR3*)((BYTE*)dst_vertices + (i * size) + sizeof(D3DXVECTOR3)); + if ((normal_dest->x != 0.0f) && (normal_dest->y != 0.0f) && (normal_dest->z != 0.0f)) + D3DXVec3Normalize(normal_dest, normal_dest); + } + } + + return D3D_OK; } static HRESULT WINAPI d3dx9_skin_info_ConvertToBlendedMesh(ID3DXSkinInfo *iface, ID3DXMesh *mesh_in, diff --git a/modules/rostests/winetests/d3dx9_36/mesh.c b/modules/rostests/winetests/d3dx9_36/mesh.c index 3118a7d443f..eef408e2366 100644 --- a/modules/rostests/winetests/d3dx9_36/mesh.c +++ b/modules/rostests/winetests/d3dx9_36/mesh.c @@ -5265,6 +5265,88 @@ static void test_create_skin_info(void) ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr); } +static void test_update_skinned_mesh(void) +{ + static DWORD bone0_vertices[2] = { 1, 3 }; + static FLOAT bone0_weights[2] = { 1.0f, 0.5f }; + static DWORD bone1_vertices[2] = { 2, 3 }; + static FLOAT bone1_weights[2] = { 1.0f, 0.5f }; + static D3DMATRIX bones_matrix[2] = + { { { { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 2.0f, 2.0f, 4.0f, 1.0f + } } }, + { { { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + -4.0f, -4.0f, 4.0f, 1.0f + } } } }; + static D3DVECTOR vertices_src[] = {{ 1.0f, 1.0f, 1.0f }, + { 1.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, -1.0f }, + { 0.0f, 1.0f, 0.0f }, + { -1.0f, -1.0f, 1.0f }, + { 0.0f, 0.0f, 1.0f }, + { -1.0f, -1.0f, -1.0f }, + { -1.0f, 0.0f, 0.0f }, + }; + static D3DVECTOR vertices_ref[] = {{ 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 3.0f, 3.0f, 3.0f }, + { 0.0f, 1.0f, 0.0f }, + { -5.0f, -5.0f, 5.0f }, + { 0.0f, 0.0f, 1.0f }, + { -2.0f, -2.0f, 3.0f }, + { -1.0f, 0.0f, 0.0f }, + }; + D3DVECTOR vertices_dest[8]; + HRESULT hr; + ID3DXSkinInfo *skin_info; + D3DXMATRIX matrix; + int i; + + D3DXMatrixIdentity(&matrix); + for (i = 0; i < 8; i++) + { + vertices_dest[i].x = 10000.0f; + vertices_dest[i].y = 10000.0f; + vertices_dest[i].z = 10000.0f; + } + + hr = D3DXCreateSkinInfoFVF(4, D3DFVF_XYZ | D3DFVF_NORMAL, 2, &skin_info); + ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); + + skin_info->lpVtbl->SetBoneInfluence(skin_info, 0, 2, bone0_vertices, bone0_weights); + ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); + skin_info->lpVtbl->SetBoneOffsetMatrix(skin_info, 0, &matrix); + ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); + skin_info->lpVtbl->SetBoneInfluence(skin_info, 1, 2, bone1_vertices, bone1_weights); + ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); + skin_info->lpVtbl->SetBoneOffsetMatrix(skin_info, 1, &matrix); + ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); + skin_info->lpVtbl->UpdateSkinnedMesh(skin_info, bones_matrix, NULL, vertices_src, vertices_dest); + ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); + for (i = 0; i < 4; i++) + { + ok(compare(vertices_dest[i*2].x, vertices_ref[i*2].x), "Vertex[%d].position.x: got %g, expected %g\n", + i, vertices_dest[i*2].x, vertices_ref[i*2].x); + ok(compare(vertices_dest[i*2].y, vertices_ref[i*2].y), "Vertex[%d].position.y: got %g, expected %g\n", + i, vertices_dest[i*2].y, vertices_ref[i*2].y); + ok(compare(vertices_dest[i*2].z, vertices_ref[i*2].z), "Vertex[%d].position.z: got %g, expected %g\n", + i, vertices_dest[i*2].z, vertices_ref[i*2].z); + ok(compare(vertices_dest[i*2+1].x, vertices_ref[i*2+1].x), "Vertex[%d].normal.x: got %g, expected %g\n", + i, vertices_dest[i*2+1].x, vertices_ref[i*2+1].x); + ok(compare(vertices_dest[i*2+1].y, vertices_ref[i*2+1].y), "Vertex[%d].normal.y: got %g, expected %g\n", + i, vertices_dest[i*2+1].y, vertices_ref[i*2+1].y); + ok(compare(vertices_dest[i*2+1].z, vertices_ref[i*2+1].z), "Vertex[%d].normal.z: got %g, expected %g\n", + i, vertices_dest[i*2+1].z, vertices_ref[i*2+1].z); + } + skin_info->lpVtbl->Release(skin_info); +} + static void test_convert_adjacency_to_point_reps(void) { HRESULT hr; @@ -11540,6 +11622,7 @@ START_TEST(mesh) D3DXGenerateAdjacencyTest(); test_update_semantics(); test_create_skin_info(); + test_update_skinned_mesh(); test_convert_adjacency_to_point_reps(); test_convert_point_reps_to_adjacency(); test_weld_vertices(); diff --git a/sdk/tools/winesync/d3dx9_staging/0013-d3dx9_36__Implement_ID3DXSkinInfoImpl_UpdateSkinnedMesh.diff b/sdk/tools/winesync/d3dx9_staging/0013-d3dx9_36__Implement_ID3DXSkinInfoImpl_UpdateSkinnedMesh.diff new file mode 100644 index 00000000000..32962427aa8 --- /dev/null +++ b/sdk/tools/winesync/d3dx9_staging/0013-d3dx9_36__Implement_ID3DXSkinInfoImpl_UpdateSkinnedMesh.diff @@ -0,0 +1,206 @@ +diff --git a/dll/directx/wine/d3dx9_36/skin.c b/dll/directx/wine/d3dx9_36/skin.c +index ffc89f0..0fea1ac 100644 +--- a/dll/directx/wine/d3dx9_36/skin.c ++++ b/dll/directx/wine/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 +@@ -399,10 +400,89 @@ static HRESULT WINAPI d3dx9_skin_info_GetDeclaration(ID3DXSkinInfo *iface, + static HRESULT WINAPI d3dx9_skin_info_UpdateSkinnedMesh(ID3DXSkinInfo *iface, const D3DXMATRIX *bone_transforms, + const D3DXMATRIX *bone_inv_transpose_transforms, const void *src_vertices, void *dst_vertices) + { +- FIXME("iface %p, bone_transforms %p, bone_inv_transpose_transforms %p, src_vertices %p, dst_vertices %p stub!\n", +- iface, bone_transforms, bone_inv_transpose_transforms, src_vertices, dst_vertices); ++ struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface); ++ DWORD size = D3DXGetFVFVertexSize(skin->fvf); ++ DWORD i, j; + +- return E_NOTIMPL; ++ TRACE("iface %p, bone_transforms %p, bone_inv_transpose_transforms %p, src_vertices %p, dst_vertices %p\n", ++ skin, bone_transforms, bone_inv_transpose_transforms, src_vertices, dst_vertices); ++ ++ if (bone_inv_transpose_transforms) ++ FIXME("Skinning vertices with two position elements not supported\n"); ++ ++ if ((skin->fvf & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) { ++ FIXME("Vertex type %#x not supported\n", skin->fvf & D3DFVF_POSITION_MASK); ++ return E_FAIL; ++ } ++ ++ /* Reset all positions */ ++ for (i = 0; i < skin->num_vertices; i++) { ++ D3DXVECTOR3 *position = (D3DXVECTOR3*)((BYTE*)dst_vertices + 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 < skin->num_bones; i++) { ++ D3DXMATRIX bone_inverse, matrix; ++ ++ D3DXMatrixInverse(&bone_inverse, NULL, &skin->bones[i].transform); ++ D3DXMatrixMultiply(&matrix, &bone_transforms[i], &bone_inverse); ++ D3DXMatrixMultiply(&matrix, &matrix, &skin->bones[i].transform); ++ ++ for (j = 0; j < skin->bones[i].num_influences; j++) { ++ D3DXVECTOR3 position; ++ D3DXVECTOR3 *position_src = (D3DXVECTOR3*)((BYTE*)src_vertices + size * skin->bones[i].vertices[j]); ++ D3DXVECTOR3 *position_dest = (D3DXVECTOR3*)((BYTE*)dst_vertices + size * skin->bones[i].vertices[j]); ++ FLOAT weight = skin->bones[i].weights[j]; ++ ++ D3DXVec3TransformCoord(&position, position_src, &matrix); ++ position_dest->x += weight * position.x; ++ position_dest->y += weight * position.y; ++ position_dest->z += weight * position.z; ++ } ++ } ++ ++ if (skin->fvf & D3DFVF_NORMAL) { ++ /* Reset all normals */ ++ for (i = 0; i < skin->num_vertices; i++) { ++ D3DXVECTOR3 *normal = (D3DXVECTOR3*)((BYTE*)dst_vertices + 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 < skin->num_bones; i++) { ++ D3DXMATRIX bone_inverse, matrix; ++ ++ D3DXMatrixInverse(&bone_inverse, NULL, &skin->bones[i].transform); ++ D3DXMatrixMultiply(&matrix, &skin->bones[i].transform, &bone_transforms[i]); ++ ++ for (j = 0; j < skin->bones[i].num_influences; j++) { ++ D3DXVECTOR3 normal; ++ D3DXVECTOR3 *normal_src = (D3DXVECTOR3*)((BYTE*)src_vertices + size * skin->bones[i].vertices[j] + sizeof(D3DXVECTOR3)); ++ D3DXVECTOR3 *normal_dest = (D3DXVECTOR3*)((BYTE*)dst_vertices + size * skin->bones[i].vertices[j] + sizeof(D3DXVECTOR3)); ++ FLOAT weight = skin->bones[i].weights[j]; ++ ++ D3DXVec3TransformNormal(&normal, normal_src, &bone_inverse); ++ D3DXVec3TransformNormal(&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 < skin->num_vertices; i++) { ++ D3DXVECTOR3 *normal_dest = (D3DXVECTOR3*)((BYTE*)dst_vertices + (i * size) + sizeof(D3DXVECTOR3)); ++ if ((normal_dest->x != 0.0f) && (normal_dest->y != 0.0f) && (normal_dest->z != 0.0f)) ++ D3DXVec3Normalize(normal_dest, normal_dest); ++ } ++ } ++ ++ return D3D_OK; + } + + static HRESULT WINAPI d3dx9_skin_info_ConvertToBlendedMesh(ID3DXSkinInfo *iface, ID3DXMesh *mesh_in, +diff --git a/modules/rostests/winetests/d3dx9_36/mesh.c b/modules/rostests/winetests/d3dx9_36/mesh.c +index e46e38d..78f95a6 100644 +--- a/modules/rostests/winetests/d3dx9_36/mesh.c ++++ b/modules/rostests/winetests/d3dx9_36/mesh.c +@@ -5265,6 +5265,88 @@ static void test_create_skin_info(void) + ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr); + } + ++static void test_update_skinned_mesh(void) ++{ ++ static DWORD bone0_vertices[2] = { 1, 3 }; ++ static FLOAT bone0_weights[2] = { 1.0f, 0.5f }; ++ static DWORD bone1_vertices[2] = { 2, 3 }; ++ static FLOAT bone1_weights[2] = { 1.0f, 0.5f }; ++ static D3DMATRIX bones_matrix[2] = ++ { { { { ++ 1.0f, 0.0f, 0.0f, 0.0f, ++ 0.0f, 1.0f, 0.0f, 0.0f, ++ 0.0f, 0.0f, 1.0f, 0.0f, ++ 2.0f, 2.0f, 4.0f, 1.0f ++ } } }, ++ { { { ++ 1.0f, 0.0f, 0.0f, 0.0f, ++ 0.0f, 1.0f, 0.0f, 0.0f, ++ 0.0f, 0.0f, 1.0f, 0.0f, ++ -4.0f, -4.0f, 4.0f, 1.0f ++ } } } }; ++ static D3DVECTOR vertices_src[] = {{ 1.0f, 1.0f, 1.0f }, ++ { 1.0f, 0.0f, 0.0f }, ++ { 1.0f, 1.0f, -1.0f }, ++ { 0.0f, 1.0f, 0.0f }, ++ { -1.0f, -1.0f, 1.0f }, ++ { 0.0f, 0.0f, 1.0f }, ++ { -1.0f, -1.0f, -1.0f }, ++ { -1.0f, 0.0f, 0.0f }, ++ }; ++ static D3DVECTOR vertices_ref[] = {{ 0.0f, 0.0f, 0.0f }, ++ { 0.0f, 0.0f, 0.0f }, ++ { 3.0f, 3.0f, 3.0f }, ++ { 0.0f, 1.0f, 0.0f }, ++ { -5.0f, -5.0f, 5.0f }, ++ { 0.0f, 0.0f, 1.0f }, ++ { -2.0f, -2.0f, 3.0f }, ++ { -1.0f, 0.0f, 0.0f }, ++ }; ++ D3DVECTOR vertices_dest[8]; ++ HRESULT hr; ++ ID3DXSkinInfo *skin_info; ++ D3DXMATRIX matrix; ++ int i; ++ ++ D3DXMatrixIdentity(&matrix); ++ for (i = 0; i < 8; i++) ++ { ++ vertices_dest[i].x = 10000.0f; ++ vertices_dest[i].y = 10000.0f; ++ vertices_dest[i].z = 10000.0f; ++ } ++ ++ hr = D3DXCreateSkinInfoFVF(4, D3DFVF_XYZ | D3DFVF_NORMAL, 2, &skin_info); ++ ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); ++ ++ skin_info->lpVtbl->SetBoneInfluence(skin_info, 0, 2, bone0_vertices, bone0_weights); ++ ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); ++ skin_info->lpVtbl->SetBoneOffsetMatrix(skin_info, 0, &matrix); ++ ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); ++ skin_info->lpVtbl->SetBoneInfluence(skin_info, 1, 2, bone1_vertices, bone1_weights); ++ ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); ++ skin_info->lpVtbl->SetBoneOffsetMatrix(skin_info, 1, &matrix); ++ ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); ++ skin_info->lpVtbl->UpdateSkinnedMesh(skin_info, bones_matrix, NULL, vertices_src, vertices_dest); ++ ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr); ++ for (i = 0; i < 4; i++) ++ { ++ ok(compare(vertices_dest[i*2].x, vertices_ref[i*2].x), "Vertex[%d].position.x: got %g, expected %g\n", ++ i, vertices_dest[i*2].x, vertices_ref[i*2].x); ++ ok(compare(vertices_dest[i*2].y, vertices_ref[i*2].y), "Vertex[%d].position.y: got %g, expected %g\n", ++ i, vertices_dest[i*2].y, vertices_ref[i*2].y); ++ ok(compare(vertices_dest[i*2].z, vertices_ref[i*2].z), "Vertex[%d].position.z: got %g, expected %g\n", ++ i, vertices_dest[i*2].z, vertices_ref[i*2].z); ++ ok(compare(vertices_dest[i*2+1].x, vertices_ref[i*2+1].x), "Vertex[%d].normal.x: got %g, expected %g\n", ++ i, vertices_dest[i*2+1].x, vertices_ref[i*2+1].x); ++ ok(compare(vertices_dest[i*2+1].y, vertices_ref[i*2+1].y), "Vertex[%d].normal.y: got %g, expected %g\n", ++ i, vertices_dest[i*2+1].y, vertices_ref[i*2+1].y); ++ ok(compare(vertices_dest[i*2+1].z, vertices_ref[i*2+1].z), "Vertex[%d].normal.z: got %g, expected %g\n", ++ i, vertices_dest[i*2+1].z, vertices_ref[i*2+1].z); ++ } ++ skin_info->lpVtbl->Release(skin_info); ++} ++ + static void test_convert_adjacency_to_point_reps(void) + { + HRESULT hr; +@@ -11509,6 +11591,7 @@ START_TEST(mesh) + D3DXGenerateAdjacencyTest(); + test_update_semantics(); + test_create_skin_info(); ++ test_update_skinned_mesh(); + test_convert_adjacency_to_point_reps(); + test_convert_point_reps_to_adjacency(); + test_weld_vertices();