From: Elizabeth Figura zfigura@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=32572 --- dlls/d3dx9_36/d3dx9_private.h | 2 + dlls/d3dx9_36/mesh.c | 2 +- dlls/d3dx9_36/skin.c | 102 +++++++++++++++++++++++++++++-- dlls/d3dx9_36/tests/mesh.c | 109 ++++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+), 7 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 655529b004b..a52636298be 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -347,6 +347,8 @@ struct d3dx_parameters_store unsigned int full_name_tmp_size; };
+extern const unsigned int d3dx_decltype_size[]; + HRESULT d3dx_init_parameters_store(struct d3dx_parameters_store *store, unsigned int count); void d3dx_parameters_store_cleanup(struct d3dx_parameters_store *store); struct d3dx_parameter *get_parameter_by_name(struct d3dx_parameters_store *store, diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index 23ab7b59708..e425ef40f4b 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -64,7 +64,7 @@ struct d3dx9_mesh D3DXATTRIBUTERANGE *attrib_table; };
-static const UINT d3dx_decltype_size[] = +const unsigned int d3dx_decltype_size[] = { /* D3DDECLTYPE_FLOAT1 */ sizeof(FLOAT), /* D3DDECLTYPE_FLOAT2 */ sizeof(D3DXVECTOR2), diff --git a/dlls/d3dx9_36/skin.c b/dlls/d3dx9_36/skin.c index 294c652c273..ffd8783b7a2 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 @@ -39,7 +40,7 @@ struct d3dx9_skin_info
DWORD fvf; D3DVERTEXELEMENT9 vertex_declaration[MAX_FVF_DECL_SIZE]; - DWORD num_vertices; + DWORD vertex_count; DWORD num_bones; struct bone *bones; }; @@ -301,7 +302,7 @@ static HRESULT WINAPI d3dx9_skin_info_Clone(ID3DXSkinInfo *iface, ID3DXSkinInfo
TRACE("iface %p, skin_info %p.\n", iface, skin_info);
- if (FAILED(hr = D3DXCreateSkinInfo(skin->num_vertices, skin->vertex_declaration, skin->num_bones, skin_info))) + if (FAILED(hr = D3DXCreateSkinInfo(skin->vertex_count, skin->vertex_declaration, skin->num_bones, skin_info))) return hr;
for (i = 0; i < skin->num_bones; ++i) @@ -396,10 +397,99 @@ 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 vertex_size = D3DXGetDeclVertexSize(skin->vertex_declaration, 0);
- 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 is not supported.\n"); + return E_NOTIMPL; + } + + for (unsigned int i = 0; i < skin->vertex_count; ++i) + { + for (const D3DVERTEXELEMENT9 *element = skin->vertex_declaration; element->Stream != 0xff; ++element) + { + const void *src_element = (uint8_t *)src_vertices + (i * vertex_size) + element->Offset; + void *dst_element = (uint8_t *)dst_vertices + (i * vertex_size) + element->Offset; + unsigned int element_size = d3dx_decltype_size[element->Type]; + + switch (element->Usage) + { + case D3DDECLUSAGE_POSITION: + case D3DDECLUSAGE_NORMAL: + memset(dst_element, 0, element_size); + break; + + default: + FIXME("Unhandled usage %#x.\n", element->Usage); + /* fall through */ + case D3DDECLUSAGE_TEXCOORD: + memcpy(dst_element, src_element, element_size); + break; + } + } + } + + for (unsigned int i = 0; i < skin->num_bones; ++i) + { + const struct bone *bone = &skin->bones[i]; + + for (unsigned int j = 0; j < bone->num_influences; ++j) + { + unsigned int vertex_idx = bone->vertices[j]; + float weight = bone->weights[j]; + + for (const D3DVERTEXELEMENT9 *element = skin->vertex_declaration; element->Stream != 0xff; ++element) + { + const void *src_element = (uint8_t *)src_vertices + (vertex_idx * vertex_size) + element->Offset; + void *dst_element = (uint8_t *)dst_vertices + (vertex_idx * vertex_size) + element->Offset; + D3DXVECTOR3 *dst_vec3 = dst_element; + + switch (element->Usage) + { + case D3DDECLUSAGE_POSITION: + if (element->Type == D3DDECLTYPE_FLOAT3) + { + D3DXVECTOR3 position; + + D3DXVec3TransformCoord(&position, src_element, &bone_transforms[i]); + dst_vec3->x += weight * position.x; + dst_vec3->y += weight * position.y; + dst_vec3->z += weight * position.z; + } + else + { + FIXME("Unhandled position type %#x.\n", element->Type); + return E_NOTIMPL; + } + break; + + case D3DDECLUSAGE_NORMAL: + { + D3DXVECTOR3 normal; + + if (element->Type != D3DDECLTYPE_FLOAT3) + { + FIXME("Unhandled normal type %#x.\n", element->Type); + return E_NOTIMPL; + } + + D3DXVec3TransformNormal(&normal, src_element, &bone_transforms[i]); + dst_vec3->x += weight * normal.x; + dst_vec3->y += weight * normal.y; + dst_vec3->z += weight * normal.z; + break; + } + } + } + } + } + + return D3D_OK; }
static HRESULT WINAPI d3dx9_skin_info_ConvertToBlendedMesh(ID3DXSkinInfo *iface, ID3DXMesh *mesh_in, @@ -479,7 +569,7 @@ HRESULT WINAPI D3DXCreateSkinInfo(DWORD vertex_count, const D3DVERTEXELEMENT9 *d
object->ID3DXSkinInfo_iface.lpVtbl = &d3dx9_skin_info_vtbl; object->ref = 1; - object->num_vertices = vertex_count; + object->vertex_count = vertex_count; object->num_bones = bone_count; object->vertex_declaration[0] = empty_declaration; object->fvf = 0; diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index 23597dc2d56..8dcf5075466 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -52,6 +52,11 @@ static BOOL compare(FLOAT u, FLOAT v) return (fabs(u-v) < admitted_error); }
+static BOOL compare_vec2(D3DXVECTOR2 u, D3DXVECTOR2 v) +{ + return compare(u.x, v.x) && compare(u.y, v.y); +} + static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v) { return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) ); @@ -5460,6 +5465,109 @@ static void test_create_skin_info(void) ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#lx\n", hr); }
+static void test_update_skinned_mesh(void) +{ + static const float bone0_weights[2] = {1.0f, 0.5f}, bone1_weights[2] = {1.0f, 0.5f}; + static const DWORD bone0_vertices[2] = {1, 3}, bone1_vertices[2] = {2, 3}; + static const D3DXMATRIX bone_matrices[2] = + { + {{{ + 2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.1f, 0.2f, 0.3f, 1.0f, + }}}, + {{{ + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + -0.5f, 0.4f, 0.5f, 1.0f, + }}}, + }; + static const D3DXMATRIX update_matrices[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, + }}}, + {{{ + 2.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 const struct vertex + { + D3DXVECTOR3 position; + D3DXVECTOR3 normal; + D3DXVECTOR2 texcoord; + } + src_vertices[4] = + { + {{ 1.0f, 1.0f, 1.0f}, { 1.0f, 0.0f, 0.0f}, { 0.2f, 0.2f}}, + {{ 1.0f, 1.0f, -1.0f}, { 0.0f, 1.0f, 0.0f}, { 0.2f, 0.4f}}, + {{-1.0f, -1.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.4f, 0.2f}}, + {{-1.0f, -1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}, { 0.4f, 0.4f}}, + }, + expect_vertices[4] = + { + {{ 0.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 0.0f}, { 0.2f, 0.2f}}, + {{ 3.0f, 3.0f, 3.0f}, { 0.0f, 1.0f, 0.0f}, { 0.2f, 0.4f}}, + {{-6.0f, -5.0f, 5.0f}, { 0.0f, 0.0f, 1.0f}, { 0.4f, 0.2f}}, + {{-2.5f, -2.0f, 3.0f}, {-1.5f, 0.0f, 0.0f}, { 0.4f, 0.4f}}, + }; + + struct vertex dst_vertices[4]; + ID3DXSkinInfo *skin_info; + HRESULT hr; + + static const D3DVERTEXELEMENT9 decl_elements[] = + { + {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0}, + {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0}, + {0, 24, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0}, + D3DDECL_END() + }; + + memset(dst_vertices, 0xcc, sizeof(dst_vertices)); + + hr = D3DXCreateSkinInfo(4, decl_elements, 2, &skin_info); + ok(hr == D3D_OK, "Got hr %#lx.\n", hr); + + skin_info->lpVtbl->SetBoneInfluence(skin_info, 0, 2, bone0_vertices, bone0_weights); + ok(hr == D3D_OK, "Got hr %#lx.\n", hr); + skin_info->lpVtbl->SetBoneOffsetMatrix(skin_info, 0, &bone_matrices[0]); + ok(hr == D3D_OK, "Got hr %#lx.\n", hr); + skin_info->lpVtbl->SetBoneInfluence(skin_info, 1, 2, bone1_vertices, bone1_weights); + ok(hr == D3D_OK, "Got hr %#lx.\n", hr); + skin_info->lpVtbl->SetBoneOffsetMatrix(skin_info, 1, &bone_matrices[1]); + ok(hr == D3D_OK, "Got hr %#lx.\n", hr); + skin_info->lpVtbl->UpdateSkinnedMesh(skin_info, update_matrices, NULL, src_vertices, dst_vertices); + ok(hr == D3D_OK, "Got hr %#lx.\n", hr); + for (unsigned int i = 0; i < 4; ++i) + { + winetest_push_context("vertex %u", i); + ok(compare_vec3(dst_vertices[i].position, expect_vertices[i].position), + "Expected position (%.8e, %.8e, %.8e), got (%.8e, %.8e, %.8e).\n", + expect_vertices[i].position.x, expect_vertices[i].position.y, expect_vertices[i].position.z, + dst_vertices[i].position.x, dst_vertices[i].position.y, dst_vertices[i].position.z); + ok(compare_vec3(dst_vertices[i].normal, expect_vertices[i].normal), + "Expected normal (%.8e, %.8e, %.8e), got (%.8e, %.8e, %.8e).\n", + expect_vertices[i].normal.x, expect_vertices[i].normal.y, expect_vertices[i].normal.z, + dst_vertices[i].normal.x, dst_vertices[i].normal.y, dst_vertices[i].normal.z); + ok(compare_vec2(dst_vertices[i].texcoord, expect_vertices[i].texcoord), + "Expected texcoord (%.8e, %.8e), got (%.8e, %.8e).\n", + expect_vertices[i].texcoord.x, expect_vertices[i].texcoord.y, + dst_vertices[i].texcoord.x, dst_vertices[i].texcoord.y); + winetest_pop_context(); + } + skin_info->lpVtbl->Release(skin_info); +} + static void test_convert_adjacency_to_point_reps(void) { HRESULT hr; @@ -11854,6 +11962,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();