--- a/dlls/d3dx9_36/mesh.c	2018-03-30 19:30:27.000000000 +0200
+++ b/dlls/d3dx9_36/mesh.c	2018-04-13 21:36:14.619201363 +0200
@@ -3739,6 +3739,67 @@ HRESULT WINAPI D3DXLoadMeshHierarchyFrom
     return hr;
 }
 
+static const GUID *xfile_std_GUIDS[49] = {
+    &TID_D3DRMAnimation,
+    &TID_D3DRMAnimationKey,
+    &TID_D3DRMAnimationOptions,
+    &TID_D3DRMAnimationSet,
+    &TID_D3DRMBoolean,
+    &TID_D3DRMBoolean2d,
+    &TID_D3DRMColorRGB,
+    &TID_D3DRMColorRGBA,
+    &TID_D3DRMCoords2d,
+    &TID_D3DRMFloatKeys,
+    &TID_D3DRMFrame,
+    &TID_D3DRMFrameTransformMatrix,
+    &TID_D3DRMGuid,
+    &TID_D3DRMIndexedColor,
+    &TID_D3DRMMaterial,
+    &TID_D3DRMMaterialWrap,
+    &TID_D3DRMMatrix4x4,
+    &TID_D3DRMMesh,
+    &TID_D3DRMMeshFace,
+    &TID_D3DRMMeshFaceWraps,
+    &TID_D3DRMMeshMaterialList,
+    &TID_D3DRMMeshNormals,
+    &TID_D3DRMMeshTextureCoords,
+    &TID_D3DRMMeshVertexColors,
+    &TID_D3DRMTextureFilename,
+    &TID_D3DRMTimedFloatKeys,
+    &TID_D3DRMVector,
+    &DXFILEOBJ_XSkinMeshHeader,
+    &DXFILEOBJ_VertexDuplicationIndices,
+    &DXFILEOBJ_FaceAdjacency,
+    &DXFILEOBJ_SkinWeights,
+    &DXFILEOBJ_Patch,
+    &DXFILEOBJ_PatchMesh,
+    &DXFILEOBJ_PatchMesh9,
+    &DXFILEOBJ_PMInfo,
+    &DXFILEOBJ_PMAttributeRange,
+    &DXFILEOBJ_PMVSplitRecord,
+    &DXFILEOBJ_FVFData,
+    &DXFILEOBJ_VertexElement,
+    &DXFILEOBJ_DeclData,
+    &DXFILEOBJ_EffectFloats,
+    &DXFILEOBJ_EffectString,
+    &DXFILEOBJ_EffectDWord,
+    &DXFILEOBJ_EffectParamFloats,
+    &DXFILEOBJ_EffectParamString,
+    &DXFILEOBJ_EffectParamDWord,
+    &DXFILEOBJ_EffectInstance,
+    &DXFILEOBJ_AnimTicksPerSecond,
+    &DXFILEOBJ_CompressedAnimationSet
+};
+
+static BOOL is_xfile_std_template(GUID *guid)
+{
+    int i;
+    for (i = 0; i < 49; i++)
+        if (IsEqualGUID(xfile_std_GUIDS[i], guid))
+            return TRUE;
+    return FALSE;
+}
+
 static HRESULT filedata_get_name(ID3DXFileData *filedata, char **name)
 {
     HRESULT hr;
@@ -3762,7 +3823,7 @@ static HRESULT filedata_get_name(ID3DXFi
 }
 
 static HRESULT load_mesh_container(struct ID3DXFileData *filedata, DWORD options, struct IDirect3DDevice9 *device,
-        struct ID3DXAllocateHierarchy *alloc_hier, D3DXMESHCONTAINER **mesh_container)
+        struct ID3DXAllocateHierarchy *alloc_hier, struct ID3DXLoadUserData *load_user_data, D3DXMESHCONTAINER **mesh_container)
 {
     HRESULT hr;
     ID3DXBuffer *adjacency = NULL;
@@ -3771,6 +3832,9 @@ static HRESULT load_mesh_container(struc
     ID3DXSkinInfo *skin_info = NULL;
     D3DXMESHDATA mesh_data;
     DWORD num_materials = 0;
+    ID3DXFileData *child;
+    SIZE_T i, nb_children;
+    GUID type;
     char *name = NULL;
 
     mesh_data.Type = D3DXMESHTYPE_MESH;
@@ -3791,6 +3855,31 @@ static HRESULT load_mesh_container(struc
             adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL,
             skin_info, mesh_container);
 
+    if (!(load_user_data))
+        goto cleanup;
+
+    hr = filedata->lpVtbl->GetChildren(filedata, &nb_children);
+    if (FAILED(hr))
+        goto cleanup;
+
+    for (i = 0; i < nb_children; i++)
+    {
+        hr = filedata->lpVtbl->GetChild(filedata, i, &child);
+        if (FAILED(hr))
+            goto cleanup;
+        hr = child->lpVtbl->GetType(child, &type);
+        if (FAILED(hr))
+            goto cleanup;
+
+        if (!is_xfile_std_template(&type))
+        {
+            hr = load_user_data->lpVtbl->LoadMeshChildData(*mesh_container, child);
+            IUnknown_Release(child);
+
+            if (FAILED(hr))
+                goto cleanup;
+        }
+    }
 cleanup:
     if (materials) ID3DXBuffer_Release(materials);
     if (effects) ID3DXBuffer_Release(effects);
@@ -3831,7 +3923,7 @@ static HRESULT parse_transform_matrix(ID
 }
 
 static HRESULT load_frame(struct ID3DXFileData *filedata, DWORD options, struct IDirect3DDevice9 *device,
-        struct ID3DXAllocateHierarchy *alloc_hier, D3DXFRAME **frame_out)
+        struct ID3DXAllocateHierarchy *alloc_hier, struct ID3DXLoadUserData *load_user_data, D3DXFRAME **frame_out)
 {
     HRESULT hr;
     GUID type;
@@ -3868,15 +3960,17 @@ static HRESULT load_frame(struct ID3DXFi
             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, load_user_data, next_container);
             if (SUCCEEDED(hr))
                 next_container = &(*next_container)->pNextMeshContainer;
         } 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, load_user_data, next_child);
             if (SUCCEEDED(hr))
                 next_child = &(*next_child)->pFrameSibling;
+        } else if (load_user_data && !is_xfile_std_template(&type)) {
+            hr = load_user_data->lpVtbl->LoadFrameChildData(frame, child);
         }
         if (FAILED(hr))
             goto err;
@@ -3910,11 +4006,6 @@ HRESULT WINAPI D3DXLoadMeshHierarchyFrom
 
     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;
-    }
 
     hr = D3DXFileCreate(&d3dxfile);
     if (FAILED(hr)) goto cleanup;
@@ -3948,11 +4039,14 @@ HRESULT WINAPI D3DXLoadMeshHierarchyFrom
 
                 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, load_user_data, &(*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, load_user_data, next_frame);
                 if (FAILED(hr)) goto cleanup;
+            } else if (load_user_data && !is_xfile_std_template(&guid)) {
+                hr = load_user_data->lpVtbl->LoadTopLevelData(filedata);
+                if (FAILED(hr)) goto cleanup;
             }
             while (*next_frame)
                 next_frame = &(*next_frame)->pFrameSibling;
