From fdb0abe017a084194ec70636b2c24de063112569 Mon Sep 17 00:00:00 2001 From: Misha Koshelev Date: Tue, 15 Feb 2011 16:21:43 -0500 Subject: d3dx9: Implement D3DXCreateTorus. To: wine-patches Reply-To: wine-devel --- dlls/d3dx9_36/d3dx9_36.spec | 2 +- dlls/d3dx9_36/mesh.c | 133 +++++++++++++++++++++++++++ dlls/d3dx9_36/tests/mesh.c | 209 +++++++++++++++++++++++++++++++++++++++++++ include/d3dx9shape.h | 8 ++ 4 files changed, 351 insertions(+), 1 deletions(-) diff --git a/dlls/d3dx9_36/d3dx9_36.spec b/dlls/d3dx9_36/d3dx9_36.spec index cbb6d20..f06a32f 100644 --- a/dlls/d3dx9_36/d3dx9_36.spec +++ b/dlls/d3dx9_36/d3dx9_36.spec @@ -105,7 +105,7 @@ @ stdcall D3DXCreateTextureFromResourceW(ptr ptr wstr ptr) @ stub D3DXCreateTextureGutterHelper @ stub D3DXCreateTextureShader -@ stub D3DXCreateTorus +@ stdcall D3DXCreateTorus(ptr float float long long ptr ptr) @ stdcall D3DXCreateVolumeTexture(ptr long long long long long long long ptr) @ stub D3DXCreateVolumeTextureFromFileA @ stub D3DXCreateVolumeTextureFromFileExA diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index 6a74442..6323e11 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -1501,3 +1501,136 @@ HRESULT WINAPI D3DXCreateTeapot(LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh, LPD3 return E_NOTIMPL; } + +static WORD torus_vertex_index(UINT sides, int side, int ring) +{ + return ring*sides+side; +} + +HRESULT WINAPI D3DXCreateTorus(LPDIRECT3DDEVICE9 device, FLOAT innerradius, FLOAT outerradius, UINT sides, + UINT rings, LPD3DXMESH *mesh, LPD3DXBUFFER *adjacency) +{ + DWORD number_of_vertices, number_of_faces; + HRESULT hr; + ID3DXMesh *torus; + struct vertex *vertices; + face *faces; + float theta_step, theta_start; + struct sincos_table theta; + D3DXVECTOR3 tangent_large, tangent_small; + float phi_step, phi, sin_phi, cos_phi; + DWORD vertex, face; + int side, ring, ringplusone_wrap; + + TRACE("(%p, %f, %f, %u, %u, %p, %p)\n", device, innerradius, outerradius, sides, rings, mesh, adjacency); + + if (!device || innerradius < 0.0f || outerradius < 0.0f || sides < 3 || rings < 3 || !mesh) + { + return D3DERR_INVALIDCALL; + } + + if (adjacency) + { + FIXME("Case of adjacency != NULL not implemented.\n"); + return E_NOTIMPL; + } + + number_of_vertices = sides * rings; + number_of_faces = 2 * sides * rings; + + hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED, + D3DFVF_XYZ | D3DFVF_NORMAL, device, &torus); + if (FAILED(hr)) + { + return hr; + } + + hr = torus->lpVtbl->LockVertexBuffer(torus, D3DLOCK_DISCARD, (LPVOID *)&vertices); + if (FAILED(hr)) + { + torus->lpVtbl->Release(torus); + return hr; + } + + hr = torus->lpVtbl->LockIndexBuffer(torus, D3DLOCK_DISCARD, (LPVOID *)&faces); + if (FAILED(hr)) + { + torus->lpVtbl->UnlockVertexBuffer(torus); + torus->lpVtbl->Release(torus); + return hr; + } + + theta_step = 2 * M_PI / sides; + theta_start = 0; + + if (!compute_sincos_table(&theta, theta_start, theta_step, rings)) + { + torus->lpVtbl->UnlockIndexBuffer(torus); + torus->lpVtbl->UnlockVertexBuffer(torus); + torus->lpVtbl->Release(torus); + return E_OUTOFMEMORY; + } + + phi_step = 2 * M_PI / rings; + phi = 0; + + vertex = 0; + face = 0; + + for (ring = 0, ringplusone_wrap = 1; ring < rings; ring++, ringplusone_wrap++) + { + if (ringplusone_wrap == rings) ringplusone_wrap = 0; + + sin_phi = sin(phi); + cos_phi = cos(phi); + + for (side = 0; side < sides; side++, vertex++) + { + vertices[vertex].position.x = (outerradius + innerradius * theta.cos[side]) * cos_phi; + vertices[vertex].position.y = -(outerradius + innerradius * theta.cos[side]) * sin_phi; + vertices[vertex].position.z = innerradius * theta.sin[side]; + + /* tangent wrt large circle */ + tangent_large.x = -sin_phi; + tangent_large.y = -cos_phi; + tangent_large.z = 0; + + /* tangent wrt small circle */ + tangent_small.x = -theta.sin[side] * cos_phi; + tangent_small.y = theta.sin[side] * sin_phi; + tangent_small.z = theta.cos[side]; + + /* normal is normalized cross product */ + D3DXVec3Cross(&vertices[vertex].normal, &tangent_small, &tangent_large); + D3DXVec3Normalize(&vertices[vertex].normal, &vertices[vertex].normal); + + if (side > 0) + { + faces[face][0] = torus_vertex_index(sides, side-1, ring); + faces[face][1] = torus_vertex_index(sides, side, ring); + faces[face++][2] = torus_vertex_index(sides, side-1, ringplusone_wrap); + + faces[face][0] = torus_vertex_index(sides, side-1, ringplusone_wrap); + faces[face][1] = torus_vertex_index(sides, side, ring); + faces[face++][2] = torus_vertex_index(sides, side, ringplusone_wrap); + } + } + + phi += phi_step; + + faces[face][0] = torus_vertex_index(sides, side-1, ring); + faces[face][1] = torus_vertex_index(sides, 0, ring); + faces[face++][2] = torus_vertex_index(sides, side-1, ringplusone_wrap); + + faces[face][0] = torus_vertex_index(sides, side-1, ringplusone_wrap); + faces[face][1] = torus_vertex_index(sides, 0, ring); + faces[face++][2] = torus_vertex_index(sides, 0, ringplusone_wrap); + } + + free_sincos_table(&theta); + torus->lpVtbl->UnlockIndexBuffer(torus); + torus->lpVtbl->UnlockVertexBuffer(torus); + *mesh = torus; + + return D3D_OK; +} diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index 5d1425b..dae7c67 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -1979,6 +1979,214 @@ static void D3DXCreateCylinderTest(void) DestroyWindow(wnd); } +static WORD torus_vertex_index(UINT sides, int side, int ring) +{ + return ring*sides+side; +} + +static BOOL compute_torus(struct mesh *mesh, FLOAT innerradius, FLOAT outerradius, UINT sides, UINT rings) +{ + float theta_step, theta_start; + struct sincos_table theta; + float phi_step, phi, sin_phi, cos_phi; + D3DXVECTOR3 tangent_large, tangent_small; + DWORD number_of_vertices, number_of_faces; + DWORD vertex, face; + int side, ring, ringplusone_wrap; + + phi_step = 2 * M_PI / rings; + phi = 0; + + theta_step = 2 * M_PI / sides; + theta_start = 0; + + if (!compute_sincos_table(&theta, theta_start, theta_step, sides)) + { + return FALSE; + } + + number_of_vertices = sides * rings; + number_of_faces = 2 * sides * rings; + + if (!new_mesh(mesh, number_of_vertices, number_of_faces)) + { + free_sincos_table(&theta); + return FALSE; + } + + vertex = 0; + face = 0; + + for (ring = 0, ringplusone_wrap = 1; ring < rings; ring++, ringplusone_wrap++) + { + if (ringplusone_wrap == rings) ringplusone_wrap = 0; + + sin_phi = sin(phi); + cos_phi = cos(phi); + + for (side = 0; side < sides; side++, vertex++) + { + mesh->vertices[vertex].position.x = (outerradius + innerradius * theta.cos[side]) * cos_phi; + mesh->vertices[vertex].position.y = -(outerradius + innerradius * theta.cos[side]) * sin_phi; + mesh->vertices[vertex].position.z = innerradius * theta.sin[side]; + + /* tangent wrt large circle */ + tangent_large.x = -sin_phi; + tangent_large.y = -cos_phi; + tangent_large.z = 0; + + /* tangent wrt small circle */ + tangent_small.x = -theta.sin[side] * cos_phi; + tangent_small.y = theta.sin[side] * sin_phi; + tangent_small.z = theta.cos[side]; + + /* normal is normalized cross product */ + D3DXVec3Cross(&mesh->vertices[vertex].normal, &tangent_small, &tangent_large); + D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal); + + if (side > 0) + { + mesh->faces[face][0] = torus_vertex_index(sides, side-1, ring); + mesh->faces[face][1] = torus_vertex_index(sides, side, ring); + mesh->faces[face++][2] = torus_vertex_index(sides, side-1, ringplusone_wrap); + + mesh->faces[face][0] = torus_vertex_index(sides, side-1, ringplusone_wrap); + mesh->faces[face][1] = torus_vertex_index(sides, side, ring); + mesh->faces[face++][2] = torus_vertex_index(sides, side, ringplusone_wrap); + } + } + + phi += phi_step; + + mesh->faces[face][0] = torus_vertex_index(sides, side-1, ring); + mesh->faces[face][1] = torus_vertex_index(sides, 0, ring); + mesh->faces[face++][2] = torus_vertex_index(sides, side-1, ringplusone_wrap); + + mesh->faces[face][0] = torus_vertex_index(sides, side-1, ringplusone_wrap); + mesh->faces[face][1] = torus_vertex_index(sides, 0, ring); + mesh->faces[face++][2] = torus_vertex_index(sides, 0, ringplusone_wrap); + } + + free_sincos_table(&theta); + + return TRUE; +} + +static void test_torus(IDirect3DDevice9 *device, FLOAT innerradius, FLOAT outerradius, UINT sides, UINT rings) +{ + HRESULT hr; + ID3DXMesh *torus; + struct mesh mesh; + char name[256]; + + hr = D3DXCreateTorus(device, innerradius, outerradius, sides, rings, &torus, NULL); + ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr); + if (hr != D3D_OK) + { + skip("Couldn't create torus\n"); + return; + } + + if (!compute_torus(&mesh, innerradius, outerradius, sides, rings)) + { + skip("Couldn't create mesh\n"); + torus->lpVtbl->Release(torus); + return; + } + + mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL; + + sprintf(name, "torus (%g, %g, %u, %u)", innerradius, outerradius, sides, rings); + compare_mesh(name, torus, &mesh); + + free_mesh(&mesh); + + torus->lpVtbl->Release(torus); +} + +static void D3DXCreateTorusTest(void) +{ + HRESULT hr; + HWND wnd; + IDirect3D9* d3d; + IDirect3DDevice9* device; + D3DPRESENT_PARAMETERS d3dpp; + ID3DXMesh* torus = NULL; + + hr = D3DXCreateTorus(NULL, 0.0f, 0.0f, 0, 0, NULL, NULL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + + hr = D3DXCreateTorus(NULL, 1.0f, 1.0f, 3, 4, &torus, NULL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + + wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + d3d = Direct3DCreate9(D3D_SDK_VERSION); + if (!wnd) + { + skip("Couldn't create application window\n"); + return; + } + if (!d3d) + { + skip("Couldn't create IDirect3D9 object\n"); + DestroyWindow(wnd); + return; + } + + ZeroMemory(&d3dpp, sizeof(d3dpp)); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device); + if (FAILED(hr)) + { + skip("Failed to create IDirect3DDevice9 object %#x\n", hr); + IDirect3D9_Release(d3d); + DestroyWindow(wnd); + return; + } + + hr = D3DXCreateTorus(device, -0.1f, 1.0f, 3, 4, &torus, NULL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + + hr = D3DXCreateTorus(device, 0.0f, 1.0f, 3, 4, &torus, NULL); + ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr); + + if (SUCCEEDED(hr) && torus) + { + torus->lpVtbl->Release(torus); + } + + hr = D3DXCreateTorus(device, 1.0f, -0.1f, 3, 4, &torus, NULL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + + hr = D3DXCreateTorus(device, 1.0f, 0.0f, 3, 4, &torus, NULL); + ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr); + + if (SUCCEEDED(hr) && torus) + { + torus->lpVtbl->Release(torus); + } + + hr = D3DXCreateTorus(device, 1.0f, 1.0f, 2, 2, &torus, NULL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + + hr = D3DXCreateTorus(device, 1.0f, 1.0f, 2, 0, &torus, NULL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + + hr = D3DXCreateTorus(device, 1.0f, 1.0f, 3, 4, NULL, NULL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + + test_torus(device, 0.0f, 0.0f, 3, 4); + test_torus(device, 1.0f, 1.0f, 3, 4); + test_torus(device, 3.0f, 2.0f, 3, 4); + test_torus(device, 2.0f, 3.0f, 5, 6); + test_torus(device, 3.0f, 4.0f, 11, 20); + + IDirect3DDevice9_Release(device); + IDirect3D9_Release(d3d); + DestroyWindow(wnd); +} + static void test_get_decl_length(void) { static const D3DVERTEXELEMENT9 declaration1[] = @@ -2113,6 +2321,7 @@ START_TEST(mesh) D3DXCreateBoxTest(); D3DXCreateSphereTest(); D3DXCreateCylinderTest(); + D3DXCreateTorusTest(); test_get_decl_length(); test_get_decl_vertex_size(); test_fvf_decl_conversion(); diff --git a/include/d3dx9shape.h b/include/d3dx9shape.h index 1a521de..fe2f6f9 100644 --- a/include/d3dx9shape.h +++ b/include/d3dx9shape.h @@ -52,6 +52,14 @@ HRESULT WINAPI D3DXCreateTeapot(LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh, LPD3DXBUFFER *adjacency); +HRESULT WINAPI D3DXCreateTorus(LPDIRECT3DDEVICE9 device, + FLOAT innerradius, + FLOAT outerradius, + UINT sides, + UINT rings, + LPD3DXMESH *mesh, + LPD3DXBUFFER *adjacency); + #ifdef __cplusplus } #endif -- 1.7.4