-- v4: d3dx9: Support loading mesh user data in D3DXLoadMeshHierarchyFromXInMemory(). d3dx9: Factor out mesh_get_parse_func(). d3dx9: Unify calling parse_mesh helper functions. d3dx9: Implement loading top and frame user data in D3DXLoadMeshHierarchyFromXInMemory(). d3dx9/tests: Add test for user data in D3DXLoadMeshHierarchyFromXInMemory().
From: Paul Gofman pgofman@codeweavers.com
--- include/d3dx9anim.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/include/d3dx9anim.h b/include/d3dx9anim.h index 81b8e2f6b2c..5ce57734d6a 100644 --- a/include/d3dx9anim.h +++ b/include/d3dx9anim.h @@ -183,23 +183,25 @@ DECLARE_INTERFACE(ID3DXAllocateHierarchy) #define INTERFACE ID3DXLoadUserData DECLARE_INTERFACE(ID3DXLoadUserData) { - STDMETHOD(LoadTopLevelData)(ID3DXFileData *child_data) PURE; - STDMETHOD(LoadFrameChildData)(D3DXFRAME *frame, ID3DXFileData *child_data) PURE; - STDMETHOD(LoadMeshChildData)(D3DXMESHCONTAINER *mesh_container, ID3DXFileData *child_data) PURE; + /* MS DirectX SDK headers define these methodes without 'this' parameter but tests show that it is wrong. */ + STDMETHOD(LoadTopLevelData)(THIS_ ID3DXFileData *child_data) PURE; + STDMETHOD(LoadFrameChildData)(THIS_ D3DXFRAME *frame, ID3DXFileData *child_data) PURE; + STDMETHOD(LoadMeshChildData)(THIS_ D3DXMESHCONTAINER *mesh_container, ID3DXFileData *child_data) PURE; }; #undef INTERFACE
#define INTERFACE ID3DXSaveUserData DECLARE_INTERFACE(ID3DXSaveUserData) { - STDMETHOD(AddFrameChildData)(const D3DXFRAME *frame, + /* MS DirectX SDK headers define these methodes without 'this' parameter. */ + STDMETHOD(AddFrameChildData)(THIS_ const D3DXFRAME *frame, ID3DXFileSaveObject *save_obj, ID3DXFileSaveData *frame_data) PURE; - STDMETHOD(AddMeshChildData)(const D3DXMESHCONTAINER *mesh_container, + STDMETHOD(AddMeshChildData)(THIS_ const D3DXMESHCONTAINER *mesh_container, ID3DXFileSaveObject *save_obj, ID3DXFileSaveData *mesh_data) PURE; - STDMETHOD(AddTopLevelDataObjectsPre)(ID3DXFileSaveObject *save_obj) PURE; - STDMETHOD(AddTopLevelDataObjectsPost)(ID3DXFileSaveObject *save_obj) PURE; - STDMETHOD(RegisterTemplates)(ID3DXFile *file) PURE; - STDMETHOD(SaveTemplates)(ID3DXFileSaveObject *save_obj) PURE; + STDMETHOD(AddTopLevelDataObjectsPre)(THIS_ ID3DXFileSaveObject *save_obj) PURE; + STDMETHOD(AddTopLevelDataObjectsPost)(THIS_ ID3DXFileSaveObject *save_obj) PURE; + STDMETHOD(RegisterTemplates)(THIS_ ID3DXFile *file) PURE; + STDMETHOD(SaveTemplates)(THIS_ ID3DXFileSaveObject *save_obj) PURE; }; #undef INTERFACE
From: Paul Gofman pgofman@codeweavers.com
--- dlls/d3dx9_36/tests/mesh.c | 215 ++++++++++++++++++++++++++++++++++++- 1 file changed, 214 insertions(+), 1 deletion(-)
diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index ce68903572b..e4d65569850 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -23,6 +23,7 @@ #include <stdio.h> #include <float.h> #include <limits.h> +#include <assert.h> #include "wine/test.h" #include "d3dx9.h" #include "initguid.h" @@ -2030,6 +2031,134 @@ static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char * } }
+#define MAX_USER_DATA_COUNT 32 +enum user_data_type +{ + USER_DATA_TYPE_TOP, + USER_DATA_TYPE_FRAME_CHILD, + USER_DATA_TYPE_MESH_CHILD, +}; + +struct test_user_data +{ + enum user_data_type data_type; + const GUID *type; + SIZE_T size; + unsigned int value; + BOOL mesh_container; + unsigned int num_materials; +}; + +struct test_load_user_data +{ + ID3DXLoadUserData iface; + + unsigned int data_count; + struct test_user_data data[MAX_USER_DATA_COUNT]; + GUID guids[MAX_USER_DATA_COUNT]; +}; + +static void record_common_user_data(struct test_load_user_data *data, ID3DXFileData *filedata, + enum user_data_type data_type) +{ + struct test_user_data *d = &data->data[data->data_count]; + const void *ptr; + HRESULT hr; + SIZE_T sz; + + assert(data->data_count < MAX_USER_DATA_COUNT); + + d->data_type = data_type; + hr = filedata->lpVtbl->GetType(filedata, &data->guids[data->data_count]); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = filedata->lpVtbl->Lock(filedata, &sz, &ptr); + ok(hr == S_OK, "got %#lx.\n", hr); + d->size = sz; + ok(sz >= sizeof(int), "got %Iu.\n", sz); + d->value = *(unsigned int *)ptr; + hr = filedata->lpVtbl->Unlock(filedata); + ok(hr == S_OK, "got %#lx.\n", hr); + ++data->data_count; +} + +static struct test_load_user_data *impl_from_ID3DXLoadUserData(ID3DXLoadUserData *iface) +{ + return CONTAINING_RECORD(iface, struct test_load_user_data, iface); +} + +static HRESULT STDMETHODCALLTYPE load_top_level_data(ID3DXLoadUserData *iface, ID3DXFileData *filedata) +{ + struct test_load_user_data *user_data = impl_from_ID3DXLoadUserData(iface); + + record_common_user_data(user_data, filedata, USER_DATA_TYPE_TOP); + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE load_frame_child_data(ID3DXLoadUserData *iface, D3DXFRAME *frame, + ID3DXFileData *filedata) +{ + struct test_load_user_data *user_data = impl_from_ID3DXLoadUserData(iface); + + ok(!frame->pFrameSibling, "got %p.\n", frame->pFrameSibling); + ok(!frame->pFrameFirstChild, "got %p.\n", frame->pFrameFirstChild); + + user_data->data[user_data->data_count].mesh_container = !!frame->pMeshContainer; + record_common_user_data(user_data, filedata, USER_DATA_TYPE_FRAME_CHILD); + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE load_mesh_child_data(ID3DXLoadUserData *iface, D3DXMESHCONTAINER *mesh_container, + ID3DXFileData *filedata) +{ + struct test_load_user_data *user_data = impl_from_ID3DXLoadUserData(iface); + + user_data->data[user_data->data_count].num_materials = mesh_container->NumMaterials; + + record_common_user_data(user_data, filedata, USER_DATA_TYPE_MESH_CHILD); + return S_OK; +} + +static const struct ID3DXLoadUserDataVtbl load_user_data_vtbl = +{ + load_top_level_data, + load_frame_child_data, + load_mesh_child_data, +}; + +static void init_load_user_data(struct test_load_user_data *data) +{ + memset(data, 0, sizeof(*data)); + data->iface.lpVtbl = &load_user_data_vtbl; +} + +static void check_user_data(struct test_load_user_data *user_data, unsigned int expected_count, + const struct test_user_data *expected) +{ + unsigned int i; + + ok(user_data->data_count == expected_count, "got %u, expected %u.\n", user_data->data_count, expected_count); + expected_count = min(expected_count, user_data->data_count); + for (i = 0; i < expected_count; ++i) + { + winetest_push_context("i %u", i); + ok(user_data->data[i].data_type == expected[i].data_type, "got %u, expected %u.\n", + user_data->data[i].data_type, expected[i].data_type); + ok(IsEqualGUID(&user_data->guids[i], expected[i].type), "got %s, expected %s.\n", + debugstr_guid(&user_data->guids[i]), debugstr_guid(expected[i].type)); + ok(user_data->data[i].size == expected[i].size, "got %Iu, expected %Iu.\n", + user_data->data[i].size, expected[i].size); + ok(user_data->data[i].value == expected[i].value, "got %u, expected %u.\n", + user_data->data[i].value, expected[i].value); + ok(user_data->data[i].mesh_container == expected[i].mesh_container, "got %u, expected %u.\n", + user_data->data[i].mesh_container, expected[i].mesh_container); + ok(user_data->data[i].num_materials == expected[i].num_materials, "got %u, expected %u.\n", + user_data->data[i].num_materials, expected[i].num_materials); + winetest_pop_context(); + } +} + +DEFINE_GUID(TID_TestDataGuid, 0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11); + static void D3DXLoadMeshTest(void) { static const char empty_xfile[] = "xof 0303txt 0032"; @@ -2051,14 +2180,42 @@ static void D3DXLoadMeshTest(void) const DWORD simple_fvf = D3DFVF_XYZ; static const char framed_xfile[] = "xof 0303txt 0032" + "template TestData {" + "<12345678-1234-1234-1234-111111111111>" + "DWORD value;" + "}" + "TestData {" + "1;;" + "}" + "Material {" + /* ColorRGBA faceColor; */ + "0.0; 0.0; 1.0; 1.0;;" + /* FLOAT power; */ + "0.5;" + /* ColorRGB specularColor; */ + "1.0; 1.0; 1.0;;" + /* ColorRGB emissiveColor; */ + "0.0; 0.0; 0.0;;" + "}" + "Frame {" - "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 1.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }" + "TestData {" + "2;;" + "}" + "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 1.0; 1.0; 0.0;; 1; 3; 0, 1, 2;;" + "TestData {" + "3;;" + "}" + "}" "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */ "1.0, 0.0, 0.0, 0.0," "0.0, 1.0, 0.0, 0.0," "0.0, 0.0, 1.0, 0.0," "0.0, 0.0, 2.0, 1.0;;" "}" + "TestData {" + "4;;" + "}" "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 2.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }" "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */ "1.0, 0.0, 0.0, 0.0," @@ -2068,6 +2225,16 @@ static void D3DXLoadMeshTest(void) "}" "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 3.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }" "}"; + + static const struct test_user_data framed_xfile_expected_user_data[] = + { + { USER_DATA_TYPE_TOP, &TID_TestDataGuid, 4, 1, 0, 0}, + { USER_DATA_TYPE_TOP, &TID_D3DRMMaterial, 44, 0, 0, 0}, + { USER_DATA_TYPE_FRAME_CHILD, &TID_TestDataGuid, 4, 2, 0, 0}, + { USER_DATA_TYPE_MESH_CHILD, &TID_TestDataGuid, 4, 3, 0, 0}, + { USER_DATA_TYPE_FRAME_CHILD, &TID_TestDataGuid, 4, 4, 1, 0}, + }; + static const char framed_xfile_empty[] = "xof 0303txt 0032" "Frame Box01 {" @@ -2093,6 +2260,10 @@ static void D3DXLoadMeshTest(void) /*________________________*/ static const char box_xfile[] = "xof 0303txt 0032" + "template TestData {" + "<12345678-1234-1234-1234-111111111111>" + "DWORD value;" + "}" "Mesh {" "8;" /* DWORD nVertices; */ /* array Vector vertices[nVertices]; */ @@ -2130,6 +2301,9 @@ static void D3DXLoadMeshTest(void) "4; 4, 4, 4, 4;," "4; 5, 5, 5, 5;;" "}" + "TestData {" + "1;;" + "}" "MeshMaterialList materials {" "2;" /* DWORD nMaterials; */ "6;" /* DWORD nFaceIndexes; */ @@ -2157,6 +2331,10 @@ static void D3DXLoadMeshTest(void) "TextureFilename { "texture.jpg"; }" "}" "}" + "TestData {" + "2;;" + "}" + "MeshVertexColors {" "8;" /* DWORD nVertexColors; */ /* array IndexedColor vertexColors[nVertexColors]; */ @@ -2182,6 +2360,12 @@ static void D3DXLoadMeshTest(void) "0.0; 0.0;;" "}" "}"; + static const struct test_user_data box_xfile_expected_user_data[] = + { + { USER_DATA_TYPE_MESH_CHILD, &TID_TestDataGuid, 4, 1, 0, 2}, + { USER_DATA_TYPE_MESH_CHILD, &TID_TestDataGuid, 4, 2, 0, 2}, + }; + static const WORD box_index_buffer[] = { 0, 1, 3, 0, 3, 2, @@ -2393,6 +2577,7 @@ static void D3DXLoadMeshTest(void) ID3DXAnimationController *controller; D3DXMESHCONTAINER *container; unsigned int i; + struct test_load_user_data load_user_data;
if (!(test_context = new_test_context())) { @@ -2487,6 +2672,20 @@ static void D3DXLoadMeshTest(void) ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); frame_hier = NULL;
+ init_load_user_data(&load_user_data); + hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1, + D3DXMESH_MANAGED, device, &alloc_hier, &load_user_data.iface, &frame_hier, &controller); + todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + if (SUCCEEDED(hr)) + { + winetest_push_context("box_xfile"); + check_user_data(&load_user_data, ARRAY_SIZE(box_xfile_expected_user_data), box_xfile_expected_user_data); + winetest_pop_context(); + hr = D3DXFrameDestroy(frame_hier, &alloc_hier); + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + } + frame_hier = NULL; + hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1, D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL); ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); @@ -2516,6 +2715,20 @@ static void D3DXLoadMeshTest(void) ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); frame_hier = NULL;
+ init_load_user_data(&load_user_data); + hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1, + D3DXMESH_MANAGED, device, &alloc_hier, &load_user_data.iface, &frame_hier, NULL); + todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + if (SUCCEEDED(hr)) + { + hr = D3DXFrameDestroy(frame_hier, &alloc_hier); + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + winetest_push_context("framed_xfile"); + check_user_data(&load_user_data, ARRAY_SIZE(framed_xfile_expected_user_data), framed_xfile_expected_user_data); + winetest_pop_context(); + } + frame_hier = NULL; + hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile_empty, sizeof(framed_xfile_empty) - 1, D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL); ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
From: Paul Gofman pgofman@codeweavers.com
--- dlls/d3dx9_36/mesh.c | 17 ++++++++++------- dlls/d3dx9_36/tests/mesh.c | 38 ++++++++++++++++---------------------- 2 files changed, 26 insertions(+), 29 deletions(-)
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index d6c13007126..7b2b91c0590 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -3880,7 +3880,7 @@ static HRESULT parse_transform_matrix(ID3DXFileData *filedata, D3DXMATRIX *trans }
static HRESULT load_frame(struct ID3DXFileData *filedata, DWORD options, struct IDirect3DDevice9 *device, - struct ID3DXAllocateHierarchy *alloc_hier, D3DXFRAME **frame_out) + struct ID3DXAllocateHierarchy *alloc_hier, D3DXFRAME **frame_out, struct ID3DXLoadUserData *load_user_data) { HRESULT hr; GUID type; @@ -3923,9 +3923,12 @@ static HRESULT load_frame(struct ID3DXFileData *filedata, DWORD options, struct } else if (IsEqualGUID(&type, &TID_D3DRMFrameTransformMatrix)) { hr = parse_transform_matrix(child, &frame->TransformationMatrix); } else if (IsEqualGUID(&type, &TID_D3DRMFrame)) { - hr = load_frame(child, options, device, alloc_hier, next_child); + hr = load_frame(child, options, device, alloc_hier, next_child, load_user_data); if (SUCCEEDED(hr)) next_child = &(*next_child)->pFrameSibling; + } else if (load_user_data) { + TRACE("Loading %s as user data.\n", debugstr_guid(&type)); + hr = load_user_data->lpVtbl->LoadFrameChildData(load_user_data, frame, child); } if (FAILED(hr)) goto err; @@ -3961,10 +3964,7 @@ HRESULT WINAPI D3DXLoadMeshHierarchyFromXInMemory(const void *memory, DWORD memo if (!memory || !memory_size || !device || !frame_hierarchy || !alloc_hier) return D3DERR_INVALIDCALL; if (load_user_data) - { - FIXME("Loading user data not implemented.\n"); - return E_NOTIMPL; - } + FIXME("Loading mesh user data not implemented for mesh.\n");
hr = D3DXFileCreate(&d3dxfile); if (FAILED(hr)) goto cleanup; @@ -4001,8 +4001,11 @@ HRESULT WINAPI D3DXLoadMeshHierarchyFromXInMemory(const void *memory, DWORD memo hr = load_mesh_container(filedata, options, device, alloc_hier, &(*next_frame)->pMeshContainer); if (FAILED(hr)) goto cleanup; } else if (IsEqualGUID(&guid, &TID_D3DRMFrame)) { - hr = load_frame(filedata, options, device, alloc_hier, next_frame); + hr = load_frame(filedata, options, device, alloc_hier, next_frame, load_user_data); if (FAILED(hr)) goto cleanup; + } else if (load_user_data) { + TRACE("Loading %s as user data.\n", debugstr_guid(&guid)); + hr = load_user_data->lpVtbl->LoadTopLevelData(load_user_data, filedata); } while (*next_frame) next_frame = &(*next_frame)->pFrameSibling; diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index e4d65569850..d46b984be84 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -2136,20 +2136,20 @@ static void check_user_data(struct test_load_user_data *user_data, unsigned int { unsigned int i;
- ok(user_data->data_count == expected_count, "got %u, expected %u.\n", user_data->data_count, expected_count); + todo_wine ok(user_data->data_count == expected_count, "got %u, expected %u.\n", user_data->data_count, expected_count); expected_count = min(expected_count, user_data->data_count); for (i = 0; i < expected_count; ++i) { winetest_push_context("i %u", i); - ok(user_data->data[i].data_type == expected[i].data_type, "got %u, expected %u.\n", + todo_wine_if(i == 3) ok(user_data->data[i].data_type == expected[i].data_type, "got %u, expected %u.\n", user_data->data[i].data_type, expected[i].data_type); ok(IsEqualGUID(&user_data->guids[i], expected[i].type), "got %s, expected %s.\n", debugstr_guid(&user_data->guids[i]), debugstr_guid(expected[i].type)); ok(user_data->data[i].size == expected[i].size, "got %Iu, expected %Iu.\n", user_data->data[i].size, expected[i].size); - ok(user_data->data[i].value == expected[i].value, "got %u, expected %u.\n", + todo_wine_if(i == 3) ok(user_data->data[i].value == expected[i].value, "got %u, expected %u.\n", user_data->data[i].value, expected[i].value); - ok(user_data->data[i].mesh_container == expected[i].mesh_container, "got %u, expected %u.\n", + todo_wine_if(i == 3) ok(user_data->data[i].mesh_container == expected[i].mesh_container, "got %u, expected %u.\n", user_data->data[i].mesh_container, expected[i].mesh_container); ok(user_data->data[i].num_materials == expected[i].num_materials, "got %u, expected %u.\n", user_data->data[i].num_materials, expected[i].num_materials); @@ -2675,15 +2675,12 @@ static void D3DXLoadMeshTest(void) init_load_user_data(&load_user_data); hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1, D3DXMESH_MANAGED, device, &alloc_hier, &load_user_data.iface, &frame_hier, &controller); - todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); - if (SUCCEEDED(hr)) - { - winetest_push_context("box_xfile"); - check_user_data(&load_user_data, ARRAY_SIZE(box_xfile_expected_user_data), box_xfile_expected_user_data); - winetest_pop_context(); - hr = D3DXFrameDestroy(frame_hier, &alloc_hier); - ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); - } + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + winetest_push_context("box_xfile"); + check_user_data(&load_user_data, ARRAY_SIZE(box_xfile_expected_user_data), box_xfile_expected_user_data); + winetest_pop_context(); + hr = D3DXFrameDestroy(frame_hier, &alloc_hier); + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); frame_hier = NULL;
hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1, @@ -2718,15 +2715,12 @@ static void D3DXLoadMeshTest(void) init_load_user_data(&load_user_data); hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1, D3DXMESH_MANAGED, device, &alloc_hier, &load_user_data.iface, &frame_hier, NULL); - todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); - if (SUCCEEDED(hr)) - { - hr = D3DXFrameDestroy(frame_hier, &alloc_hier); - ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); - winetest_push_context("framed_xfile"); - check_user_data(&load_user_data, ARRAY_SIZE(framed_xfile_expected_user_data), framed_xfile_expected_user_data); - winetest_pop_context(); - } + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + hr = D3DXFrameDestroy(frame_hier, &alloc_hier); + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + winetest_push_context("framed_xfile"); + check_user_data(&load_user_data, ARRAY_SIZE(framed_xfile_expected_user_data), framed_xfile_expected_user_data); + winetest_pop_context(); frame_hier = NULL;
hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile_empty, sizeof(framed_xfile_empty) - 1,
From: Paul Gofman pgofman@codeweavers.com
--- dlls/d3dx9_36/mesh.c | 92 ++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 42 deletions(-)
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index 7b2b91c0590..3a35a4caa91 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -37,6 +37,11 @@
WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
+/* for provide_flags parameters */ +#define PROVIDE_MATERIALS 0x1 +#define PROVIDE_SKININFO 0x2 +#define PROVIDE_ADJACENCY 0x4 + struct d3dx9_mesh { ID3DXMesh ID3DXMesh_iface; @@ -2611,6 +2616,7 @@ struct mesh_data {
struct ID3DXSkinInfo *skin_info; unsigned int bone_count; + unsigned int skin_weights_info_count; };
static HRESULT parse_texture_filename(ID3DXFileData *filedata, char **filename_out) @@ -2752,7 +2758,7 @@ static void destroy_materials(struct mesh_data *mesh) mesh->material_indices = NULL; }
-static HRESULT parse_material_list(ID3DXFileData *filedata, struct mesh_data *mesh) +static HRESULT parse_material_list(ID3DXFileData *filedata, struct mesh_data *mesh, DWORD flags) { ID3DXFileData *child = NULL; unsigned int material_count; @@ -2764,6 +2770,9 @@ static HRESULT parse_material_list(ID3DXFileData *filedata, struct mesh_data *me HRESULT hr; GUID type;
+ if (!(flags & PROVIDE_MATERIALS)) + return S_OK; + destroy_materials(mesh);
hr = filedata->lpVtbl->Lock(filedata, &data_size, &data); @@ -2867,7 +2876,7 @@ end: return hr; }
-static HRESULT parse_texture_coords(ID3DXFileData *filedata, struct mesh_data *mesh) +static HRESULT parse_texture_coords(ID3DXFileData *filedata, struct mesh_data *mesh, DWORD flags) { const uint32_t *data; SIZE_T data_size; @@ -2925,7 +2934,7 @@ end: return hr; }
-static HRESULT parse_vertex_colors(ID3DXFileData *filedata, struct mesh_data *mesh) +static HRESULT parse_vertex_colors(ID3DXFileData *filedata, struct mesh_data *mesh, DWORD flags) { unsigned int color_count, i; const uint32_t *data; @@ -3004,7 +3013,7 @@ end: return hr; }
-static HRESULT parse_normals(ID3DXFileData *filedata, struct mesh_data *mesh) +static HRESULT parse_normals(ID3DXFileData *filedata, struct mesh_data *mesh, DWORD flags) { unsigned int num_face_indices = mesh->num_poly_faces * 2 + mesh->num_tri_faces; DWORD *index_out_ptr; @@ -3110,7 +3119,7 @@ end: return hr; }
-static HRESULT parse_skin_mesh_header(ID3DXFileData *filedata, struct mesh_data *mesh_data) +static HRESULT parse_skin_mesh_header(ID3DXFileData *filedata, struct mesh_data *mesh_data, DWORD flags) { const BYTE *data; SIZE_T data_size; @@ -3118,6 +3127,15 @@ static HRESULT parse_skin_mesh_header(ID3DXFileData *filedata, struct mesh_data
TRACE("filedata %p, mesh_data %p.\n", filedata, mesh_data);
+ if (!(flags & PROVIDE_SKININFO)) + return S_OK; + + if (mesh_data->skin_info) + { + WARN("Skin mesh header already encountered\n"); + return E_FAIL; + } + if (FAILED(hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void **)&data))) return hr;
@@ -3136,8 +3154,9 @@ static HRESULT parse_skin_mesh_header(ID3DXFileData *filedata, struct mesh_data return hr; }
-static HRESULT parse_skin_weights_info(ID3DXFileData *filedata, struct mesh_data *mesh_data, unsigned int index) +static HRESULT parse_skin_weights_info(ID3DXFileData *filedata, struct mesh_data *mesh_data, DWORD flags) { + unsigned int index = mesh_data->skin_weights_info_count; unsigned int influence_count; const char *name; const BYTE *data; @@ -3146,6 +3165,15 @@ static HRESULT parse_skin_weights_info(ID3DXFileData *filedata, struct mesh_data
TRACE("filedata %p, mesh_data %p, index %u.\n", filedata, mesh_data, index);
+ if (!(flags & PROVIDE_SKININFO)) + return S_OK; + + if (!mesh_data->skin_info) + { + WARN("Skin weights found but skin mesh header not encountered yet.\n"); + return E_FAIL; + } + if (FAILED(hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void **)&data))) return hr;
@@ -3173,17 +3201,13 @@ static HRESULT parse_skin_weights_info(ID3DXFileData *filedata, struct mesh_data hr = mesh_data->skin_info->lpVtbl->SetBoneOffsetMatrix(mesh_data->skin_info, index, (const D3DMATRIX *)(data + influence_count * (sizeof(uint32_t) + sizeof(float))));
+ if (SUCCEEDED(hr)) + ++mesh_data->skin_weights_info_count; return hr; }
-/* for provide_flags parameters */ -#define PROVIDE_MATERIALS 0x1 -#define PROVIDE_SKININFO 0x2 -#define PROVIDE_ADJACENCY 0x4 - static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, DWORD provide_flags) { - unsigned int skin_weights_info_count = 0; ID3DXFileData *child = NULL; const BYTE *data, *in_ptr; DWORD *index_out_ptr; @@ -3203,6 +3227,8 @@ static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, * } */
+ mesh_data->skin_weights_info_count = 0; + hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void **)&data); if (FAILED(hr)) return hr;
@@ -3308,37 +3334,19 @@ static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, goto end;
if (IsEqualGUID(&type, &TID_D3DRMMeshNormals)) { - hr = parse_normals(child, mesh_data); + hr = parse_normals(child, mesh_data, provide_flags); } else if (IsEqualGUID(&type, &TID_D3DRMMeshVertexColors)) { - hr = parse_vertex_colors(child, mesh_data); + hr = parse_vertex_colors(child, mesh_data, provide_flags); } else if (IsEqualGUID(&type, &TID_D3DRMMeshTextureCoords)) { - hr = parse_texture_coords(child, mesh_data); - } else if (IsEqualGUID(&type, &TID_D3DRMMeshMaterialList) && - (provide_flags & PROVIDE_MATERIALS)) - { - hr = parse_material_list(child, mesh_data); - } else if (provide_flags & PROVIDE_SKININFO) { - if (IsEqualGUID(&type, &DXFILEOBJ_XSkinMeshHeader)) { - if (mesh_data->skin_info) { - WARN("Skin mesh header already encountered\n"); - hr = E_FAIL; - goto end; - } - hr = parse_skin_mesh_header(child, mesh_data); - if (FAILED(hr)) - goto end; - } else if (IsEqualGUID(&type, &DXFILEOBJ_SkinWeights)) { - if (!mesh_data->skin_info) { - WARN("Skin weights found but skin mesh header not encountered yet\n"); - hr = E_FAIL; - goto end; - } - hr = parse_skin_weights_info(child, mesh_data, skin_weights_info_count); - if (FAILED(hr)) - goto end; - skin_weights_info_count++; - } + hr = parse_texture_coords(child, mesh_data, provide_flags); + } else if (IsEqualGUID(&type, &TID_D3DRMMeshMaterialList)) { + hr = parse_material_list(child, mesh_data, provide_flags); + } else if (IsEqualGUID(&type, &DXFILEOBJ_XSkinMeshHeader)) { + hr = parse_skin_mesh_header(child, mesh_data, provide_flags); + } else if (IsEqualGUID(&type, &DXFILEOBJ_SkinWeights)) { + hr = parse_skin_weights_info(child, mesh_data, provide_flags); } + if (FAILED(hr)) goto end;
@@ -3346,10 +3354,10 @@ static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, child = NULL; }
- if (mesh_data->skin_info && (skin_weights_info_count != mesh_data->bone_count)) + if (mesh_data->skin_info && (mesh_data->skin_weights_info_count != mesh_data->bone_count)) { WARN("Mismatch between skin weights info count %u and bones count %u from skin mesh header.\n", - skin_weights_info_count, mesh_data->bone_count); + mesh_data->skin_weights_info_count, mesh_data->bone_count); hr = E_FAIL; goto end; }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/d3dx9_36/mesh.c | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-)
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index 3a35a4caa91..338ca1eaefe 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -3206,9 +3206,37 @@ static HRESULT parse_skin_weights_info(ID3DXFileData *filedata, struct mesh_data return hr; }
+typedef HRESULT (*mesh_parse_func)(ID3DXFileData *, struct mesh_data *, DWORD); + +static mesh_parse_func mesh_get_parse_func(const GUID *type) +{ + static const struct + { + const GUID *type; + mesh_parse_func func; + } + funcs[] = + { + {&TID_D3DRMMeshNormals, parse_normals}, + {&TID_D3DRMMeshVertexColors, parse_vertex_colors}, + {&TID_D3DRMMeshTextureCoords, parse_texture_coords}, + {&TID_D3DRMMeshMaterialList, parse_material_list}, + {&DXFILEOBJ_XSkinMeshHeader, parse_skin_mesh_header}, + {&DXFILEOBJ_SkinWeights, parse_skin_weights_info}, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(funcs); ++i) + if (IsEqualGUID(type, funcs[i].type)) + return funcs[i].func; + + return NULL; +} + static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, DWORD provide_flags) { ID3DXFileData *child = NULL; + mesh_parse_func parse_func; const BYTE *data, *in_ptr; DWORD *index_out_ptr; SIZE_T child_count; @@ -3333,20 +3361,8 @@ static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, if (FAILED(hr)) goto end;
- if (IsEqualGUID(&type, &TID_D3DRMMeshNormals)) { - hr = parse_normals(child, mesh_data, provide_flags); - } else if (IsEqualGUID(&type, &TID_D3DRMMeshVertexColors)) { - hr = parse_vertex_colors(child, mesh_data, provide_flags); - } else if (IsEqualGUID(&type, &TID_D3DRMMeshTextureCoords)) { - hr = parse_texture_coords(child, mesh_data, provide_flags); - } else if (IsEqualGUID(&type, &TID_D3DRMMeshMaterialList)) { - hr = parse_material_list(child, mesh_data, provide_flags); - } else if (IsEqualGUID(&type, &DXFILEOBJ_XSkinMeshHeader)) { - hr = parse_skin_mesh_header(child, mesh_data, provide_flags); - } else if (IsEqualGUID(&type, &DXFILEOBJ_SkinWeights)) { - hr = parse_skin_weights_info(child, mesh_data, provide_flags); - } - + if ((parse_func = mesh_get_parse_func(&type))) + hr = parse_func(child, mesh_data, provide_flags); if (FAILED(hr)) goto end;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/d3dx9_36/mesh.c | 49 ++++++++++++++++++++++++++++---------- dlls/d3dx9_36/tests/mesh.c | 9 ++++--- 2 files changed, 41 insertions(+), 17 deletions(-)
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index 338ca1eaefe..7d2b2c0071d 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -3830,7 +3830,8 @@ static HRESULT filedata_get_name(ID3DXFileData *filedata, char **name) }
static HRESULT load_mesh_container(struct ID3DXFileData *filedata, DWORD options, struct IDirect3DDevice9 *device, - struct ID3DXAllocateHierarchy *alloc_hier, D3DXMESHCONTAINER **mesh_container) + struct ID3DXAllocateHierarchy *alloc_hier, D3DXMESHCONTAINER **mesh_container, + struct ID3DXLoadUserData *load_user_data) { HRESULT hr; ID3DXBuffer *adjacency = NULL; @@ -3840,6 +3841,10 @@ static HRESULT load_mesh_container(struct ID3DXFileData *filedata, DWORD options D3DXMESHDATA mesh_data; DWORD num_materials = 0; char *name = NULL; + SIZE_T child_count; + ID3DXFileData *child = NULL; + GUID type; + unsigned int i;
mesh_data.Type = D3DXMESHTYPE_MESH; mesh_data.pMesh = NULL; @@ -3852,17 +3857,38 @@ static HRESULT load_mesh_container(struct ID3DXFileData *filedata, DWORD options hr = filedata_get_name(filedata, &name); if (FAILED(hr)) goto cleanup;
- if (mesh_data.pMesh) + if (!mesh_data.pMesh) + goto cleanup; + hr = alloc_hier->lpVtbl->CreateMeshContainer(alloc_hier, name, &mesh_data, + materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL, + effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL, + num_materials, + adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL, + skin_info, mesh_container); + if (FAILED(hr) || !load_user_data) + goto cleanup; + + hr = filedata->lpVtbl->GetChildren(filedata, &child_count); + if (FAILED(hr)) + goto cleanup; + + for (i = 0; i < child_count; i++) { - hr = alloc_hier->lpVtbl->CreateMeshContainer(alloc_hier, name, &mesh_data, - materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL, - effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL, - num_materials, - adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL, - skin_info, mesh_container); + if (FAILED(hr = filedata->lpVtbl->GetChild(filedata, i, &child))) + goto cleanup; + if (FAILED(hr = child->lpVtbl->GetType(child, &type))) + goto cleanup; + + if (!mesh_get_parse_func(&type) + && FAILED(hr = load_user_data->lpVtbl->LoadMeshChildData(load_user_data, *mesh_container, child))) + goto cleanup; + + IUnknown_Release(child); + child = NULL; }
cleanup: + if (child) IUnknown_Release(child); if (materials) ID3DXBuffer_Release(materials); if (effects) ID3DXBuffer_Release(effects); if (adjacency) ID3DXBuffer_Release(adjacency); @@ -3941,7 +3967,7 @@ static HRESULT load_frame(struct ID3DXFileData *filedata, DWORD options, struct goto err;
if (IsEqualGUID(&type, &TID_D3DRMMesh)) { - hr = load_mesh_container(child, options, device, alloc_hier, next_container); + hr = load_mesh_container(child, options, device, alloc_hier, next_container, load_user_data); if (SUCCEEDED(hr)) next_container = &(*next_container)->pNextMeshContainer; } else if (IsEqualGUID(&type, &TID_D3DRMFrameTransformMatrix)) { @@ -3987,8 +4013,6 @@ HRESULT WINAPI D3DXLoadMeshHierarchyFromXInMemory(const void *memory, DWORD memo
if (!memory || !memory_size || !device || !frame_hierarchy || !alloc_hier) return D3DERR_INVALIDCALL; - if (load_user_data) - FIXME("Loading mesh user data not implemented for mesh.\n");
hr = D3DXFileCreate(&d3dxfile); if (FAILED(hr)) goto cleanup; @@ -4022,7 +4046,8 @@ HRESULT WINAPI D3DXLoadMeshHierarchyFromXInMemory(const void *memory, DWORD memo
D3DXMatrixIdentity(&(*next_frame)->TransformationMatrix);
- hr = load_mesh_container(filedata, options, device, alloc_hier, &(*next_frame)->pMeshContainer); + hr = load_mesh_container(filedata, options, device, alloc_hier, &(*next_frame)->pMeshContainer, + load_user_data); if (FAILED(hr)) goto cleanup; } else if (IsEqualGUID(&guid, &TID_D3DRMFrame)) { hr = load_frame(filedata, options, device, alloc_hier, next_frame, load_user_data); diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index d46b984be84..1af4532790a 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -2136,20 +2136,19 @@ static void check_user_data(struct test_load_user_data *user_data, unsigned int { unsigned int i;
- todo_wine ok(user_data->data_count == expected_count, "got %u, expected %u.\n", user_data->data_count, expected_count); - expected_count = min(expected_count, user_data->data_count); + ok(user_data->data_count == expected_count, "got %u, expected %u.\n", user_data->data_count, expected_count); for (i = 0; i < expected_count; ++i) { winetest_push_context("i %u", i); - todo_wine_if(i == 3) ok(user_data->data[i].data_type == expected[i].data_type, "got %u, expected %u.\n", + ok(user_data->data[i].data_type == expected[i].data_type, "got %u, expected %u.\n", user_data->data[i].data_type, expected[i].data_type); ok(IsEqualGUID(&user_data->guids[i], expected[i].type), "got %s, expected %s.\n", debugstr_guid(&user_data->guids[i]), debugstr_guid(expected[i].type)); ok(user_data->data[i].size == expected[i].size, "got %Iu, expected %Iu.\n", user_data->data[i].size, expected[i].size); - todo_wine_if(i == 3) ok(user_data->data[i].value == expected[i].value, "got %u, expected %u.\n", + ok(user_data->data[i].value == expected[i].value, "got %u, expected %u.\n", user_data->data[i].value, expected[i].value); - todo_wine_if(i == 3) ok(user_data->data[i].mesh_container == expected[i].mesh_container, "got %u, expected %u.\n", + ok(user_data->data[i].mesh_container == expected[i].mesh_container, "got %u, expected %u.\n", user_data->data[i].mesh_container, expected[i].mesh_container); ok(user_data->data[i].num_materials == expected[i].num_materials, "got %u, expected %u.\n", user_data->data[i].num_materials, expected[i].num_materials);
Looks good to me, again :sweat_smile: Should I explicitly unapprove and approve it or is this fine?
On Fri Nov 24 16:13:22 2023 +0000, Alexandre Julliard wrote:
You should probably fix ID3DXSaveUserData too while you're at it.
Good catch, I'll send that fix in a followup (unless Paul wants to take care of it as well).