[PATCH v3 0/2] MR11482: d3dx9: Implement D3DXIntersect() and D3DXIntersectSubset()
Needed for EEP16 (and presumably every other program in that series) to allow placing models and rotating the camera correctly in 3D. I'm unsure whether the implementation is efficient or if there's a better way. It does work however. -- v3: d3dx9: Implement D3DXIntersect() and D3DXIntersectSubset() d3dx9/tests: Add tests for D3DXIntersect() and D3DXIntersectSubset() https://gitlab.winehq.org/wine/wine/-/merge_requests/11482
From: Jannis Lübke <luebke.jannis@t-online.de> --- dlls/d3dx9_24/d3dx9_24.spec | 2 +- dlls/d3dx9_25/d3dx9_25.spec | 2 +- dlls/d3dx9_26/d3dx9_26.spec | 2 +- dlls/d3dx9_27/d3dx9_27.spec | 2 +- dlls/d3dx9_28/d3dx9_28.spec | 2 +- dlls/d3dx9_29/d3dx9_29.spec | 2 +- dlls/d3dx9_30/d3dx9_30.spec | 2 +- dlls/d3dx9_31/d3dx9_31.spec | 2 +- dlls/d3dx9_32/d3dx9_32.spec | 2 +- dlls/d3dx9_33/d3dx9_33.spec | 2 +- dlls/d3dx9_34/d3dx9_34.spec | 2 +- dlls/d3dx9_35/d3dx9_35.spec | 2 +- dlls/d3dx9_36/d3dx9_36.spec | 2 +- dlls/d3dx9_36/mesh.c | 14 ++ dlls/d3dx9_36/tests/mesh.c | 292 ++++++++++++++++++++++++++++++++++++ dlls/d3dx9_37/d3dx9_37.spec | 2 +- dlls/d3dx9_38/d3dx9_38.spec | 2 +- dlls/d3dx9_39/d3dx9_39.spec | 2 +- dlls/d3dx9_40/d3dx9_40.spec | 2 +- dlls/d3dx9_41/d3dx9_41.spec | 2 +- dlls/d3dx9_42/d3dx9_42.spec | 2 +- dlls/d3dx9_43/d3dx9_43.spec | 2 +- 22 files changed, 326 insertions(+), 20 deletions(-) diff --git a/dlls/d3dx9_24/d3dx9_24.spec b/dlls/d3dx9_24/d3dx9_24.spec index 1c15a450ecf..f5e3a2c5d15 100644 --- a/dlls/d3dx9_24/d3dx9_24.spec +++ b/dlls/d3dx9_24/d3dx9_24.spec @@ -163,7 +163,7 @@ @ stub D3DXGetTargetDescByVersion @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_25/d3dx9_25.spec b/dlls/d3dx9_25/d3dx9_25.spec index 6fa19bf30af..d6dba64009f 100644 --- a/dlls/d3dx9_25/d3dx9_25.spec +++ b/dlls/d3dx9_25/d3dx9_25.spec @@ -163,7 +163,7 @@ @ stub D3DXGetTargetDescByVersion @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_26/d3dx9_26.spec b/dlls/d3dx9_26/d3dx9_26.spec index 3c1eadbe7a5..378eabc917d 100644 --- a/dlls/d3dx9_26/d3dx9_26.spec +++ b/dlls/d3dx9_26/d3dx9_26.spec @@ -167,7 +167,7 @@ @ stub D3DXGetTargetDescByVersion @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_27/d3dx9_27.spec b/dlls/d3dx9_27/d3dx9_27.spec index 3c1eadbe7a5..378eabc917d 100644 --- a/dlls/d3dx9_27/d3dx9_27.spec +++ b/dlls/d3dx9_27/d3dx9_27.spec @@ -167,7 +167,7 @@ @ stub D3DXGetTargetDescByVersion @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_28/d3dx9_28.spec b/dlls/d3dx9_28/d3dx9_28.spec index 48c143b97b0..d1fabdf62ab 100644 --- a/dlls/d3dx9_28/d3dx9_28.spec +++ b/dlls/d3dx9_28/d3dx9_28.spec @@ -167,7 +167,7 @@ @ stub D3DXGetTargetDescByVersion @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_29/d3dx9_29.spec b/dlls/d3dx9_29/d3dx9_29.spec index 48c143b97b0..d1fabdf62ab 100644 --- a/dlls/d3dx9_29/d3dx9_29.spec +++ b/dlls/d3dx9_29/d3dx9_29.spec @@ -167,7 +167,7 @@ @ stub D3DXGetTargetDescByVersion @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_30/d3dx9_30.spec b/dlls/d3dx9_30/d3dx9_30.spec index 48c143b97b0..d1fabdf62ab 100644 --- a/dlls/d3dx9_30/d3dx9_30.spec +++ b/dlls/d3dx9_30/d3dx9_30.spec @@ -167,7 +167,7 @@ @ stub D3DXGetTargetDescByVersion @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_31/d3dx9_31.spec b/dlls/d3dx9_31/d3dx9_31.spec index 6bc1471da2d..2ee8a408d4f 100644 --- a/dlls/d3dx9_31/d3dx9_31.spec +++ b/dlls/d3dx9_31/d3dx9_31.spec @@ -164,7 +164,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_32/d3dx9_32.spec b/dlls/d3dx9_32/d3dx9_32.spec index 04abf61ee9d..b46431f09ed 100644 --- a/dlls/d3dx9_32/d3dx9_32.spec +++ b/dlls/d3dx9_32/d3dx9_32.spec @@ -164,7 +164,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_33/d3dx9_33.spec b/dlls/d3dx9_33/d3dx9_33.spec index 04abf61ee9d..b46431f09ed 100644 --- a/dlls/d3dx9_33/d3dx9_33.spec +++ b/dlls/d3dx9_33/d3dx9_33.spec @@ -164,7 +164,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_34/d3dx9_34.spec b/dlls/d3dx9_34/d3dx9_34.spec index 04abf61ee9d..b46431f09ed 100644 --- a/dlls/d3dx9_34/d3dx9_34.spec +++ b/dlls/d3dx9_34/d3dx9_34.spec @@ -164,7 +164,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_35/d3dx9_35.spec b/dlls/d3dx9_35/d3dx9_35.spec index 04abf61ee9d..b46431f09ed 100644 --- a/dlls/d3dx9_35/d3dx9_35.spec +++ b/dlls/d3dx9_35/d3dx9_35.spec @@ -164,7 +164,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_36/d3dx9_36.spec b/dlls/d3dx9_36/d3dx9_36.spec index e4304261fa3..40e70be2134 100644 --- a/dlls/d3dx9_36/d3dx9_36.spec +++ b/dlls/d3dx9_36/d3dx9_36.spec @@ -166,7 +166,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index e425ef40f4b..462b6bfca7c 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -7662,6 +7662,20 @@ HRESULT WINAPI D3DXIntersect(ID3DXBaseMesh *mesh, const D3DXVECTOR3 *ray_pos, co return E_NOTIMPL; } +/************************************************************************* + * D3DXIntersectSubset (D3DX9_36.@) + */ +HRESULT WINAPI D3DXIntersectSubset(ID3DXBaseMesh *mesh, DWORD attrib_id, const D3DXVECTOR3 *ray_pos, + const D3DXVECTOR3 *ray_dir, BOOL *hit, DWORD *face_index, float *u, float *v, float *distance, + ID3DXBuffer **all_hits, DWORD *count_of_hits) +{ + FIXME("mesh %p, attrib_id %lu, ray_pos %p, ray_dir %p, hit %p, face_index %p, u %p, v %p, distance %p, " + "all_hits %p, count_of_hits %p stub!\n", mesh, attrib_id, ray_pos, ray_dir, hit, face_index, u, v, + distance, all_hits, count_of_hits); + + return E_NOTIMPL; +} + HRESULT WINAPI D3DXTessellateNPatches(ID3DXMesh *mesh, const DWORD *adjacency_in, float num_segs, BOOL quadratic_normals, ID3DXMesh **mesh_out, ID3DXBuffer **adjacency_out) { diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index e3bee171fb3..d1510704558 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -11966,6 +11966,297 @@ static void test_mesh_optimize(void) free_test_context(test_context); } +static void test_intersect(void) +{ + /* Two quads facing the ray: faces 0 and 1 at z = 1.0 (attribute group 0), + * faces 2 and 3 at z = 2.0 (attribute group 1). */ + static const D3DXVECTOR3 vertices[] = + { + {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 1.0f}, {0.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f}, + {0.0f, 0.0f, 2.0f}, {1.0f, 0.0f, 2.0f}, {0.0f, 1.0f, 2.0f}, {1.0f, 1.0f, 2.0f}, + }; + static const DWORD indices[] = {0, 1, 2, 3, 2, 1, 4, 5, 6, 7, 6, 5}; + static const DWORD attributes[] = {0, 0, 1, 1}; + static const DWORD options[] = {D3DXMESH_MANAGED, D3DXMESH_MANAGED | D3DXMESH_32BIT}; + static const D3DVERTEXELEMENT9 decl_no_position[] = + { + {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, + D3DDECL_END() + }; + static const D3DVERTEXELEMENT9 decl_position4[] = + { + {0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, + D3DDECL_END() + }; + static const D3DVERTEXELEMENT9 *position_decls[] = {decl_no_position, decl_position4}; + static const D3DXVECTOR3 ray_dir = {0.0f, 0.0f, 1.0f}; + static const D3DXVECTOR3 ray_pos = {0.25f, 0.25f, 0.0f}; + static const D3DXVECTOR3 ray_pos_second = {0.75f, 0.75f, 0.0f}; + static const D3DXVECTOR3 ray_pos_miss = {2.0f, 2.0f, 0.0f}; + const D3DXINTERSECTINFO *hit_info; + struct test_context *test_context; + IDirect3DDevice9 *device; + DWORD face_index, count, attrib_table_size; + D3DXATTRIBUTERANGE attrib_ranges[3]; + ID3DXBuffer *all_hits; + DWORD *attribute_data; + float u, v, dist; + void *vertex_data; + void *index_data; + unsigned int i, j; + ID3DXMesh *mesh; + HRESULT hr; + BOOL hit; + + if (!(test_context = new_test_context())) + { + skip("Couldn't create test context.\n"); + return; + } + device = test_context->device; + + for (i = 0; i < ARRAY_SIZE(options); i++) + { + winetest_push_context("options %#lx", options[i]); + + hr = D3DXCreateMeshFVF(ARRAY_SIZE(attributes), ARRAY_SIZE(vertices), options[i], + D3DFVF_XYZ, device, &mesh); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_data); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + memcpy(vertex_data, vertices, sizeof(vertices)); + hr = mesh->lpVtbl->UnlockVertexBuffer(mesh); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_data); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + if (options[i] & D3DXMESH_32BIT) + { + memcpy(index_data, indices, sizeof(indices)); + } + else + { + WORD *indices_16bit = index_data; + + for (j = 0; j < ARRAY_SIZE(indices); j++) + indices_16bit[j] = indices[j]; + } + hr = mesh->lpVtbl->UnlockIndexBuffer(mesh); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attribute_data); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + memcpy(attribute_data, attributes, sizeof(attributes)); + hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = D3DXIntersect(NULL, &ray_pos, &ray_dir, &hit, &face_index, &u, &v, &dist, NULL, NULL); + todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + hr = D3DXIntersect((ID3DXBaseMesh *)mesh, NULL, &ray_dir, &hit, &face_index, &u, &v, &dist, NULL, NULL); + todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, NULL, &hit, &face_index, &u, &v, &dist, NULL, NULL); + todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, NULL, &face_index, NULL, NULL, NULL, NULL, NULL); + todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, NULL, NULL, NULL, NULL, NULL, NULL, &count); + todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, NULL, NULL, NULL, NULL, NULL, &all_hits, NULL); + todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, &hit, NULL, NULL, NULL, NULL, NULL, NULL); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hit = FALSE; + face_index = 0xdeadbeef; + count = 0xdeadbeef; + u = v = dist = -1.0f; + all_hits = NULL; + hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, &hit, &face_index, + &u, &v, &dist, &all_hits, &count); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(hit, "Expected a hit.\n"); + todo_wine ok(!face_index, "Got unexpected face index %lu.\n", face_index); + todo_wine ok(compare(u, 0.25f), "Got unexpected u %.8e.\n", u); + todo_wine ok(compare(v, 0.25f), "Got unexpected v %.8e.\n", v); + todo_wine ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); + todo_wine ok(count == 2, "Got unexpected hit count %lu.\n", count); + todo_wine ok(!!all_hits, "Expected a hit buffer.\n"); + if (all_hits) + { + ok(ID3DXBuffer_GetBufferSize(all_hits) == 2 * sizeof(*hit_info), + "Got unexpected buffer size %lu.\n", ID3DXBuffer_GetBufferSize(all_hits)); + hit_info = ID3DXBuffer_GetBufferPointer(all_hits); + ok(!hit_info[0].FaceIndex, "Got unexpected face index %lu.\n", hit_info[0].FaceIndex); + ok(compare(hit_info[0].U, 0.25f), "Got unexpected u %.8e.\n", hit_info[0].U); + ok(compare(hit_info[0].V, 0.25f), "Got unexpected v %.8e.\n", hit_info[0].V); + ok(compare(hit_info[0].Dist, 1.0f), "Got unexpected distance %.8e.\n", hit_info[0].Dist); + ok(hit_info[1].FaceIndex == 2, "Got unexpected face index %lu.\n", hit_info[1].FaceIndex); + ok(compare(hit_info[1].U, 0.25f), "Got unexpected u %.8e.\n", hit_info[1].U); + ok(compare(hit_info[1].V, 0.25f), "Got unexpected v %.8e.\n", hit_info[1].V); + ok(compare(hit_info[1].Dist, 2.0f), "Got unexpected distance %.8e.\n", hit_info[1].Dist); + ID3DXBuffer_Release(all_hits); + } + + hit = FALSE; + face_index = 0xdeadbeef; + count = 0xdeadbeef; + dist = -1.0f; + hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos_second, &ray_dir, &hit, &face_index, + &u, &v, &dist, NULL, &count); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(hit, "Expected a hit.\n"); + todo_wine ok(face_index == 1, "Got unexpected face index %lu.\n", face_index); + todo_wine ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); + todo_wine ok(count == 2, "Got unexpected hit count %lu.\n", count); + + hit = TRUE; + face_index = 0xdeadbeef; + count = 0xdeadbeef; + u = v = dist = -1.0f; + all_hits = NULL; + hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos_miss, &ray_dir, &hit, &face_index, + &u, &v, &dist, &all_hits, &count); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(!hit, "Expected no hit.\n"); + todo_wine ok(!count, "Got unexpected hit count %lu.\n", count); + ok(!all_hits, "Expected no hit buffer.\n"); + ok(face_index == 0xdeadbeef, "Got unexpected face index %lu.\n", face_index); + ok(u == -1.0f, "Got unexpected u %.8e.\n", u); + ok(v == -1.0f, "Got unexpected v %.8e.\n", v); + ok(dist == -1.0f, "Got unexpected distance %.8e.\n", dist); + + hr = D3DXIntersectSubset(NULL, 0, &ray_pos, &ray_dir, &hit, NULL, NULL, NULL, NULL, NULL, NULL); + todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + hr = D3DXIntersectSubset((ID3DXBaseMesh *)mesh, 0, &ray_pos, &ray_dir, &hit, NULL, + NULL, NULL, NULL, NULL, NULL); + todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + + hr = mesh->lpVtbl->OptimizeInplace(mesh, D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + attrib_table_size = 0; + hr = mesh->lpVtbl->GetAttributeTable(mesh, NULL, &attrib_table_size); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(attrib_table_size == 2, "Got unexpected attribute table size %lu.\n", attrib_table_size); + + hit = FALSE; + face_index = 0xdeadbeef; + count = 0xdeadbeef; + u = v = dist = -1.0f; + all_hits = NULL; + hr = D3DXIntersectSubset((ID3DXBaseMesh *)mesh, 0, &ray_pos, &ray_dir, &hit, &face_index, + &u, &v, &dist, &all_hits, &count); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(hit, "Expected a hit.\n"); + todo_wine ok(!face_index, "Got unexpected face index %lu.\n", face_index); + todo_wine ok(compare(u, 0.25f), "Got unexpected u %.8e.\n", u); + todo_wine ok(compare(v, 0.25f), "Got unexpected v %.8e.\n", v); + todo_wine ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); + todo_wine ok(count == 1, "Got unexpected hit count %lu.\n", count); + todo_wine ok(!!all_hits, "Expected a hit buffer.\n"); + if (all_hits) + { + ok(ID3DXBuffer_GetBufferSize(all_hits) == sizeof(*hit_info), + "Got unexpected buffer size %lu.\n", ID3DXBuffer_GetBufferSize(all_hits)); + hit_info = ID3DXBuffer_GetBufferPointer(all_hits); + ok(!hit_info[0].FaceIndex, "Got unexpected face index %lu.\n", hit_info[0].FaceIndex); + ok(compare(hit_info[0].U, 0.25f), "Got unexpected u %.8e.\n", hit_info[0].U); + ok(compare(hit_info[0].V, 0.25f), "Got unexpected v %.8e.\n", hit_info[0].V); + ok(compare(hit_info[0].Dist, 1.0f), "Got unexpected distance %.8e.\n", hit_info[0].Dist); + ID3DXBuffer_Release(all_hits); + } + + hit = FALSE; + face_index = 0xdeadbeef; + count = 0xdeadbeef; + dist = -1.0f; + u = v = -1.0f; + hr = D3DXIntersectSubset((ID3DXBaseMesh *)mesh, 1, &ray_pos, &ray_dir, &hit, &face_index, + &u, &v, &dist, NULL, &count); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(hit, "Expected a hit.\n"); + todo_wine ok(face_index == 2, "Got unexpected face index %lu.\n", face_index); + todo_wine ok(compare(u, 0.25f), "Got unexpected u %.8e.\n", u); + todo_wine ok(compare(v, 0.25f), "Got unexpected v %.8e.\n", v); + todo_wine ok(compare(dist, 2.0f), "Got unexpected distance %.8e.\n", dist); + todo_wine ok(count == 1, "Got unexpected hit count %lu.\n", count); + + hit = TRUE; + face_index = 0xdeadbeef; + count = 0xdeadbeef; + u = v = dist = -1.0f; + all_hits = NULL; + hr = D3DXIntersectSubset((ID3DXBaseMesh *)mesh, 2, &ray_pos, &ray_dir, &hit, &face_index, + &u, &v, &dist, &all_hits, &count); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(!hit, "Expected no hit.\n"); + ok(face_index == 0xdeadbeef, "Got unexpected face index %lu.\n", face_index); + ok(u == -1.0f, "Got unexpected u %.8e.\n", u); + ok(v == -1.0f, "Got unexpected v %.8e.\n", v); + ok(dist == -1.0f, "Got unexpected distance %.8e.\n", dist); + ok(count == 0xdeadbeef, "Got unexpected hit count %lu.\n", count); + ok(!all_hits, "Expected no hit buffer.\n"); + + attrib_ranges[0].AttribId = 0; + attrib_ranges[0].FaceStart = 0; + attrib_ranges[0].FaceCount = 1; + attrib_ranges[0].VertexStart = 0; + attrib_ranges[0].VertexCount = ARRAY_SIZE(vertices); + attrib_ranges[1].AttribId = 1; + attrib_ranges[1].FaceStart = 1; + attrib_ranges[1].FaceCount = 1; + attrib_ranges[1].VertexStart = 0; + attrib_ranges[1].VertexCount = ARRAY_SIZE(vertices); + attrib_ranges[2].AttribId = 0; + attrib_ranges[2].FaceStart = 2; + attrib_ranges[2].FaceCount = 1; + attrib_ranges[2].VertexStart = 0; + attrib_ranges[2].VertexCount = ARRAY_SIZE(vertices); + hr = mesh->lpVtbl->SetAttributeTable(mesh, attrib_ranges, ARRAY_SIZE(attrib_ranges)); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hit = FALSE; + face_index = 0xdeadbeef; + count = 0xdeadbeef; + dist = -1.0f; + hr = D3DXIntersectSubset((ID3DXBaseMesh *)mesh, 0, &ray_pos, &ray_dir, &hit, &face_index, + &u, &v, &dist, NULL, &count); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(hit, "Expected a hit.\n"); + todo_wine ok(!face_index, "Got unexpected face index %lu.\n", face_index); + todo_wine ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); + todo_wine ok(count == 1, "Got unexpected hit count %lu.\n", count); + + mesh->lpVtbl->Release(mesh); + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(position_decls); i++) + { + ID3DXMesh *decl_mesh; + + winetest_push_context("decl %u", i); + + hr = D3DXCreateMesh(ARRAY_SIZE(attributes), ARRAY_SIZE(vertices), D3DXMESH_MANAGED, + position_decls[i], device, &decl_mesh); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hit = TRUE; + face_index = 0xdeadbeef; + count = 0xdeadbeef; + hr = D3DXIntersect((ID3DXBaseMesh *)decl_mesh, &ray_pos, &ray_dir, &hit, &face_index, + &u, &v, &dist, NULL, &count); + todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + + decl_mesh->lpVtbl->Release(decl_mesh); + winetest_pop_context(); + } + + free_test_context(test_context); +} + START_TEST(mesh) { D3DXBoundProbeTest(); @@ -11973,6 +12264,7 @@ START_TEST(mesh) D3DXComputeBoundingSphereTest(); D3DXGetFVFVertexSizeTest(); D3DXIntersectTriTest(); + test_intersect(); D3DXCreateMeshTest(); D3DXCreateMeshFVFTest(); D3DXLoadMeshTest(); diff --git a/dlls/d3dx9_37/d3dx9_37.spec b/dlls/d3dx9_37/d3dx9_37.spec index e4304261fa3..40e70be2134 100644 --- a/dlls/d3dx9_37/d3dx9_37.spec +++ b/dlls/d3dx9_37/d3dx9_37.spec @@ -166,7 +166,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_38/d3dx9_38.spec b/dlls/d3dx9_38/d3dx9_38.spec index e4304261fa3..40e70be2134 100644 --- a/dlls/d3dx9_38/d3dx9_38.spec +++ b/dlls/d3dx9_38/d3dx9_38.spec @@ -166,7 +166,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_39/d3dx9_39.spec b/dlls/d3dx9_39/d3dx9_39.spec index e4304261fa3..40e70be2134 100644 --- a/dlls/d3dx9_39/d3dx9_39.spec +++ b/dlls/d3dx9_39/d3dx9_39.spec @@ -166,7 +166,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_40/d3dx9_40.spec b/dlls/d3dx9_40/d3dx9_40.spec index e4304261fa3..40e70be2134 100644 --- a/dlls/d3dx9_40/d3dx9_40.spec +++ b/dlls/d3dx9_40/d3dx9_40.spec @@ -166,7 +166,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_41/d3dx9_41.spec b/dlls/d3dx9_41/d3dx9_41.spec index e4304261fa3..40e70be2134 100644 --- a/dlls/d3dx9_41/d3dx9_41.spec +++ b/dlls/d3dx9_41/d3dx9_41.spec @@ -166,7 +166,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_42/d3dx9_42.spec b/dlls/d3dx9_42/d3dx9_42.spec index b857564b2b3..b8efa3d91d4 100644 --- a/dlls/d3dx9_42/d3dx9_42.spec +++ b/dlls/d3dx9_42/d3dx9_42.spec @@ -159,7 +159,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_43/d3dx9_43.spec b/dlls/d3dx9_43/d3dx9_43.spec index b857564b2b3..b8efa3d91d4 100644 --- a/dlls/d3dx9_43/d3dx9_43.spec +++ b/dlls/d3dx9_43/d3dx9_43.spec @@ -159,7 +159,7 @@ @ stdcall D3DXGetShaderVersion(ptr) @ stdcall D3DXGetVertexShaderProfile(ptr) @ stdcall D3DXIntersect(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) +@ stdcall D3DXIntersectSubset(ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXIntersectTri(ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXA(str long ptr ptr ptr ptr ptr ptr) @ stdcall D3DXLoadMeshFromXInMemory(ptr long long ptr ptr ptr ptr ptr ptr) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11482
From: Jannis Lübke <luebke.jannis@t-online.de> Some applications use this for hit-testing. Wine already largely provides the base for this since hit-testing a single triangle was already implemented, only hit-testing a mesh was missing. --- dlls/d3dx9_36/mesh.c | 193 +++++++++++++++++++++++++++++++++++-- dlls/d3dx9_36/tests/mesh.c | 98 +++++++++---------- 2 files changed, 236 insertions(+), 55 deletions(-) diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index 462b6bfca7c..d67a5528f31 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -7650,16 +7650,196 @@ HRESULT WINAPI D3DXComputeNormals(struct ID3DXBaseMesh *mesh, const DWORD *adjac adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL); } +static HRESULT d3dx_intersect(ID3DXBaseMesh *mesh, BOOL filter_by_attribute, DWORD attrib_id, + const D3DXVECTOR3 *ray_pos, const D3DXVECTOR3 *ray_dir, BOOL *hit, DWORD *face_index, + float *u, float *v, float *distance, ID3DXBuffer **all_hits, DWORD *count_of_hits) +{ + D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE]; + DWORD pos_offset = 0, vertex_size, num_faces, hit_count = 0; + struct dynamic_array hits = { 0 }; + D3DXINTERSECTINFO nearest_hit = { 0 }; + DWORD face_start = 0, face_end, i; + BOOL found_position = FALSE, indices_32bit; + ID3DXBuffer *buffer = NULL; + const BYTE *vertices = NULL; + const void *indices = NULL; + HRESULT hr; + + if (!mesh || !ray_pos || !ray_dir) + return D3DERR_INVALIDCALL; + + if (!hit) + return D3DERR_INVALIDCALL; + + if (FAILED(hr = mesh->lpVtbl->GetDeclaration(mesh, declaration))) + return hr; + + for (i = 0; i < MAX_FVF_DECL_SIZE && declaration[i].Stream != 0xff; i++) + { + if (declaration[i].Usage == D3DDECLUSAGE_POSITION && !declaration[i].UsageIndex + && declaration[i].Type == D3DDECLTYPE_FLOAT3) + { + pos_offset = declaration[i].Offset; + found_position = TRUE; + break; + } + } + + if (!found_position) + { + WARN("Mesh has no float3 position element.\n"); + return D3DERR_INVALIDCALL; + } + + num_faces = mesh->lpVtbl->GetNumFaces(mesh); + vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh); + indices_32bit = !!(mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT); + face_end = num_faces; + + if (filter_by_attribute) + { + D3DXATTRIBUTERANGE *attrib_table; + DWORD attrib_table_size = 0; + + if (FAILED(hr = mesh->lpVtbl->GetAttributeTable(mesh, NULL, &attrib_table_size))) + return hr; + + if (!attrib_table_size) + { + WARN("Mesh has no attribute table.\n"); + return D3DERR_INVALIDCALL; + } + + if (!(attrib_table = malloc(attrib_table_size * sizeof(*attrib_table)))) + return E_OUTOFMEMORY; + + if (SUCCEEDED(hr = mesh->lpVtbl->GetAttributeTable(mesh, attrib_table, &attrib_table_size))) + { + for (i = 0; i < attrib_table_size; i++) + { + if (attrib_table[i].AttribId != attrib_id) + continue; + + face_start = attrib_table[i].FaceStart; + face_end = min(num_faces, face_start + attrib_table[i].FaceCount); + break; + } + } + free(attrib_table); + + if (FAILED(hr)) + return hr; + + if (i == attrib_table_size) + { + *hit = FALSE; + return D3D_OK; + } + } + + if (FAILED(hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void **)&vertices))) + goto done; + if (FAILED(hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void **)&indices))) + goto done; + + for (i = face_start; i < face_end; i++) + { + const D3DXVECTOR3 *vertex[3]; + float face_u, face_v, face_dist; + unsigned int j; + + for (j = 0; j < 3; j++) + { + DWORD index = indices_32bit ? ((const DWORD *)indices)[i * 3 + j] + : ((const WORD *)indices)[i * 3 + j]; + + vertex[j] = (const D3DXVECTOR3 *)(vertices + index * vertex_size + pos_offset); + } + + if (!D3DXIntersectTri(vertex[0], vertex[1], vertex[2], ray_pos, ray_dir, &face_u, &face_v, &face_dist)) + continue; + + if (all_hits) + { + D3DXINTERSECTINFO *info; + + if (!reserve(&hits, hit_count + 1, sizeof(*info))) + { + hr = E_OUTOFMEMORY; + goto done; + } + info = &((D3DXINTERSECTINFO *)hits.items)[hit_count]; + info->FaceIndex = i; + info->U = face_u; + info->V = face_v; + info->Dist = face_dist; + } + + if (!hit_count || face_dist < nearest_hit.Dist) + { + nearest_hit.FaceIndex = i; + nearest_hit.U = face_u; + nearest_hit.V = face_v; + nearest_hit.Dist = face_dist; + } + + hit_count++; + } + + if (all_hits && hit_count) + { + if (FAILED(hr = D3DXCreateBuffer(hit_count * sizeof(D3DXINTERSECTINFO), &buffer))) + goto done; + memcpy(ID3DXBuffer_GetBufferPointer(buffer), hits.items, hit_count * sizeof(D3DXINTERSECTINFO)); + } + + *hit = !!hit_count; + if (count_of_hits) + *count_of_hits = hit_count; + + if (hit_count) + { + if (face_index) + *face_index = nearest_hit.FaceIndex; + if (u) + *u = nearest_hit.U; + if (v) + *v = nearest_hit.V; + if (distance) + *distance = nearest_hit.Dist; + } + + if (all_hits) + { + *all_hits = buffer; + buffer = NULL; + } + + hr = D3D_OK; + +done: + if (buffer) + ID3DXBuffer_Release(buffer); + if (indices) + mesh->lpVtbl->UnlockIndexBuffer(mesh); + if (vertices) + mesh->lpVtbl->UnlockVertexBuffer(mesh); + free(hits.items); + + return hr; +} + /************************************************************************* * D3DXIntersect (D3DX9_36.@) */ HRESULT WINAPI D3DXIntersect(ID3DXBaseMesh *mesh, const D3DXVECTOR3 *ray_pos, const D3DXVECTOR3 *ray_dir, BOOL *hit, DWORD *face_index, float *u, float *v, float *distance, ID3DXBuffer **all_hits, DWORD *count_of_hits) { - FIXME("mesh %p, ray_pos %p, ray_dir %p, hit %p, face_index %p, u %p, v %p, distance %p, all_hits %p, " - "count_of_hits %p stub!\n", mesh, ray_pos, ray_dir, hit, face_index, u, v, distance, all_hits, count_of_hits); + TRACE("mesh %p, ray_pos %p, ray_dir %p, hit %p, face_index %p, u %p, v %p, distance %p, all_hits %p, " + "count_of_hits %p.\n", mesh, ray_pos, ray_dir, hit, face_index, u, v, distance, all_hits, count_of_hits); - return E_NOTIMPL; + return d3dx_intersect(mesh, FALSE, 0, ray_pos, ray_dir, hit, face_index, u, v, distance, + all_hits, count_of_hits); } /************************************************************************* @@ -7669,11 +7849,12 @@ HRESULT WINAPI D3DXIntersectSubset(ID3DXBaseMesh *mesh, DWORD attrib_id, const D const D3DXVECTOR3 *ray_dir, BOOL *hit, DWORD *face_index, float *u, float *v, float *distance, ID3DXBuffer **all_hits, DWORD *count_of_hits) { - FIXME("mesh %p, attrib_id %lu, ray_pos %p, ray_dir %p, hit %p, face_index %p, u %p, v %p, distance %p, " - "all_hits %p, count_of_hits %p stub!\n", mesh, attrib_id, ray_pos, ray_dir, hit, face_index, u, v, + TRACE("mesh %p, attrib_id %lu, ray_pos %p, ray_dir %p, hit %p, face_index %p, u %p, v %p, distance %p, " + "all_hits %p, count_of_hits %p.\n", mesh, attrib_id, ray_pos, ray_dir, hit, face_index, u, v, distance, all_hits, count_of_hits); - return E_NOTIMPL; + return d3dx_intersect(mesh, TRUE, attrib_id, ray_pos, ray_dir, hit, face_index, u, v, distance, + all_hits, count_of_hits); } HRESULT WINAPI D3DXTessellateNPatches(ID3DXMesh *mesh, const DWORD *adjacency_in, float num_segs, diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index d1510704558..38c3b10d775 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -12052,22 +12052,22 @@ static void test_intersect(void) ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); hr = D3DXIntersect(NULL, &ray_pos, &ray_dir, &hit, &face_index, &u, &v, &dist, NULL, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); hr = D3DXIntersect((ID3DXBaseMesh *)mesh, NULL, &ray_dir, &hit, &face_index, &u, &v, &dist, NULL, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, NULL, &hit, &face_index, &u, &v, &dist, NULL, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, NULL, &face_index, NULL, NULL, NULL, NULL, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, NULL, NULL, NULL, NULL, NULL, NULL, &count); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, NULL, NULL, NULL, NULL, NULL, &all_hits, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, &hit, NULL, NULL, NULL, NULL, NULL, NULL); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); hit = FALSE; face_index = 0xdeadbeef; @@ -12076,14 +12076,14 @@ static void test_intersect(void) all_hits = NULL; hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos, &ray_dir, &hit, &face_index, &u, &v, &dist, &all_hits, &count); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(hit, "Expected a hit.\n"); - todo_wine ok(!face_index, "Got unexpected face index %lu.\n", face_index); - todo_wine ok(compare(u, 0.25f), "Got unexpected u %.8e.\n", u); - todo_wine ok(compare(v, 0.25f), "Got unexpected v %.8e.\n", v); - todo_wine ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); - todo_wine ok(count == 2, "Got unexpected hit count %lu.\n", count); - todo_wine ok(!!all_hits, "Expected a hit buffer.\n"); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(hit, "Expected a hit.\n"); + ok(!face_index, "Got unexpected face index %lu.\n", face_index); + ok(compare(u, 0.25f), "Got unexpected u %.8e.\n", u); + ok(compare(v, 0.25f), "Got unexpected v %.8e.\n", v); + ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); + ok(count == 2, "Got unexpected hit count %lu.\n", count); + ok(!!all_hits, "Expected a hit buffer.\n"); if (all_hits) { ok(ID3DXBuffer_GetBufferSize(all_hits) == 2 * sizeof(*hit_info), @@ -12106,11 +12106,11 @@ static void test_intersect(void) dist = -1.0f; hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos_second, &ray_dir, &hit, &face_index, &u, &v, &dist, NULL, &count); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(hit, "Expected a hit.\n"); - todo_wine ok(face_index == 1, "Got unexpected face index %lu.\n", face_index); - todo_wine ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); - todo_wine ok(count == 2, "Got unexpected hit count %lu.\n", count); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(hit, "Expected a hit.\n"); + ok(face_index == 1, "Got unexpected face index %lu.\n", face_index); + ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); + ok(count == 2, "Got unexpected hit count %lu.\n", count); hit = TRUE; face_index = 0xdeadbeef; @@ -12119,9 +12119,9 @@ static void test_intersect(void) all_hits = NULL; hr = D3DXIntersect((ID3DXBaseMesh *)mesh, &ray_pos_miss, &ray_dir, &hit, &face_index, &u, &v, &dist, &all_hits, &count); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(!hit, "Expected no hit.\n"); - todo_wine ok(!count, "Got unexpected hit count %lu.\n", count); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(!hit, "Expected no hit.\n"); + ok(!count, "Got unexpected hit count %lu.\n", count); ok(!all_hits, "Expected no hit buffer.\n"); ok(face_index == 0xdeadbeef, "Got unexpected face index %lu.\n", face_index); ok(u == -1.0f, "Got unexpected u %.8e.\n", u); @@ -12129,10 +12129,10 @@ static void test_intersect(void) ok(dist == -1.0f, "Got unexpected distance %.8e.\n", dist); hr = D3DXIntersectSubset(NULL, 0, &ray_pos, &ray_dir, &hit, NULL, NULL, NULL, NULL, NULL, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); hr = D3DXIntersectSubset((ID3DXBaseMesh *)mesh, 0, &ray_pos, &ray_dir, &hit, NULL, NULL, NULL, NULL, NULL, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); hr = mesh->lpVtbl->OptimizeInplace(mesh, D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL); ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); @@ -12148,14 +12148,14 @@ static void test_intersect(void) all_hits = NULL; hr = D3DXIntersectSubset((ID3DXBaseMesh *)mesh, 0, &ray_pos, &ray_dir, &hit, &face_index, &u, &v, &dist, &all_hits, &count); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(hit, "Expected a hit.\n"); - todo_wine ok(!face_index, "Got unexpected face index %lu.\n", face_index); - todo_wine ok(compare(u, 0.25f), "Got unexpected u %.8e.\n", u); - todo_wine ok(compare(v, 0.25f), "Got unexpected v %.8e.\n", v); - todo_wine ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); - todo_wine ok(count == 1, "Got unexpected hit count %lu.\n", count); - todo_wine ok(!!all_hits, "Expected a hit buffer.\n"); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(hit, "Expected a hit.\n"); + ok(!face_index, "Got unexpected face index %lu.\n", face_index); + ok(compare(u, 0.25f), "Got unexpected u %.8e.\n", u); + ok(compare(v, 0.25f), "Got unexpected v %.8e.\n", v); + ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); + ok(count == 1, "Got unexpected hit count %lu.\n", count); + ok(!!all_hits, "Expected a hit buffer.\n"); if (all_hits) { ok(ID3DXBuffer_GetBufferSize(all_hits) == sizeof(*hit_info), @@ -12175,13 +12175,13 @@ static void test_intersect(void) u = v = -1.0f; hr = D3DXIntersectSubset((ID3DXBaseMesh *)mesh, 1, &ray_pos, &ray_dir, &hit, &face_index, &u, &v, &dist, NULL, &count); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(hit, "Expected a hit.\n"); - todo_wine ok(face_index == 2, "Got unexpected face index %lu.\n", face_index); - todo_wine ok(compare(u, 0.25f), "Got unexpected u %.8e.\n", u); - todo_wine ok(compare(v, 0.25f), "Got unexpected v %.8e.\n", v); - todo_wine ok(compare(dist, 2.0f), "Got unexpected distance %.8e.\n", dist); - todo_wine ok(count == 1, "Got unexpected hit count %lu.\n", count); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(hit, "Expected a hit.\n"); + ok(face_index == 2, "Got unexpected face index %lu.\n", face_index); + ok(compare(u, 0.25f), "Got unexpected u %.8e.\n", u); + ok(compare(v, 0.25f), "Got unexpected v %.8e.\n", v); + ok(compare(dist, 2.0f), "Got unexpected distance %.8e.\n", dist); + ok(count == 1, "Got unexpected hit count %lu.\n", count); hit = TRUE; face_index = 0xdeadbeef; @@ -12190,8 +12190,8 @@ static void test_intersect(void) all_hits = NULL; hr = D3DXIntersectSubset((ID3DXBaseMesh *)mesh, 2, &ray_pos, &ray_dir, &hit, &face_index, &u, &v, &dist, &all_hits, &count); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(!hit, "Expected no hit.\n"); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(!hit, "Expected no hit.\n"); ok(face_index == 0xdeadbeef, "Got unexpected face index %lu.\n", face_index); ok(u == -1.0f, "Got unexpected u %.8e.\n", u); ok(v == -1.0f, "Got unexpected v %.8e.\n", v); @@ -12223,11 +12223,11 @@ static void test_intersect(void) dist = -1.0f; hr = D3DXIntersectSubset((ID3DXBaseMesh *)mesh, 0, &ray_pos, &ray_dir, &hit, &face_index, &u, &v, &dist, NULL, &count); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(hit, "Expected a hit.\n"); - todo_wine ok(!face_index, "Got unexpected face index %lu.\n", face_index); - todo_wine ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); - todo_wine ok(count == 1, "Got unexpected hit count %lu.\n", count); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(hit, "Expected a hit.\n"); + ok(!face_index, "Got unexpected face index %lu.\n", face_index); + ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); + ok(count == 1, "Got unexpected hit count %lu.\n", count); mesh->lpVtbl->Release(mesh); winetest_pop_context(); @@ -12248,7 +12248,7 @@ static void test_intersect(void) count = 0xdeadbeef; hr = D3DXIntersect((ID3DXBaseMesh *)decl_mesh, &ray_pos, &ray_dir, &hit, &face_index, &u, &v, &dist, NULL, &count); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); decl_mesh->lpVtbl->Release(decl_mesh); winetest_pop_context(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11482
On Sun Aug 2 15:36:54 2026 +0000, Jannis Lübke wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/11482/diffs?diff_id=286595&start_sha=d04ded2b9e7621c56e7c17c28709fd7350661f0e#b48c701e07d39941b85fcae58b68319b4685310c_12105_12120) Done, and turns out that was actually a problem, should be fixed now
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11482#note_147610
On Sun Aug 2 15:39:56 2026 +0000, Henri Verbeet wrote:
I'm unsure whether the implementation is efficient or if there's a better way. Would it make sense to test against the (axis-aligned) bounding box first, before testing each face? I think so, yes. I played around with that idea initially, but I'm not too well versed in 3D graphics, so I ended up with the simple implementation that just iterates everything.
(My absolutely not scientific test was running EEP with that implementation, which seems to call it a few thousand times and then decide "Eh I get enough frames per second, more than on my VM, seems fine") -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11482#note_147612
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/mesh.c:
- todo_wine ok(!face_index, "Got unexpected face index %lu.\n", face_index); - todo_wine ok(compare(u, 0.25f), "Got unexpected u %.8e.\n", u); - todo_wine ok(compare(v, 0.25f), "Got unexpected v %.8e.\n", v); - todo_wine ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); - todo_wine ok(count == 2, "Got unexpected hit count %lu.\n", count); - todo_wine ok(!!all_hits, "Expected a hit buffer.\n"); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(hit, "Expected a hit.\n"); + ok(!face_index, "Got unexpected face index %lu.\n", face_index); + ok(compare(u, 0.25f), "Got unexpected u %.8e.\n", u); + ok(compare(v, 0.25f), "Got unexpected v %.8e.\n", v); + ok(compare(dist, 1.0f), "Got unexpected distance %.8e.\n", dist); + ok(count == 2, "Got unexpected hit count %lu.\n", count); + ok(!!all_hits, "Expected a hit buffer.\n"); if (all_hits) { The `if` should be dropped as well, since at this point there is no expectation of ever getting `!all_hits` anymore.
Same for the other similar cases below. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11482#note_147829
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/mesh.c:
adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL); }
+static HRESULT d3dx_intersect(ID3DXBaseMesh *mesh, BOOL filter_by_attribute, DWORD attrib_id, + const D3DXVECTOR3 *ray_pos, const D3DXVECTOR3 *ray_dir, BOOL *hit, DWORD *face_index, + float *u, float *v, float *distance, ID3DXBuffer **all_hits, DWORD *count_of_hits)
Very insignificant nitpick, we usually name these output arguments that clash with local variables like `out_hits` or something like that. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11482#note_147830
On Tue Aug 4 11:31:57 2026 +0000, Jannis Lübke wrote:
I think so, yes. I played around with that idea initially, but I'm not too well versed in 3D graphics, so I ended up with the simple implementation that just iterates everything. (My absolutely not scientific test was running EEP with that implementation, which seems to call it a few thousand times and then decide "Eh I get enough frames per second, more than on my VM, seems fine") Yeah, I think this is good enough until we get evidence that it's not :slight_smile:
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11482#note_147831
This merge request was approved by Matteo Bruni. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11482
I left a couple of further comments, just for reference in case you end up with more d3dx MRs. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11482#note_147832
participants (3)
-
Jannis Lübke -
Jannis Lübke (@Janrupf) -
Matteo Bruni (@Mystral)