D3DXCreateTorus patch... thoughts?
Misha Koshelev
misha680 at gmail.com
Sun Feb 13 15:51:18 CST 2011
This is for
http://bugs.winehq.org/show_bug.cgi?id=23930
Based on my prior mesh patches.
Test bot reports success:
https://testbot.winehq.org/JobDetails.pl?Key=9240
Thank you
Misha
-------------- next part --------------
From c2c3f5299cad1d78cff4457716c550687b818706 Mon Sep 17 00:00:00 2001
From: Misha Koshelev <misha680 at gmail.com>
Date: Sun, 13 Feb 2011 16:44:54 -0500
Subject: d3dx9: Implement D3DXCreateTorus.
To: wine-patches <wine-patches at winehq.org>
Reply-To: wine-devel <wine-devel at winehq.org>
---
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..c548ad4 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 long long 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 5e875bd..6c7a75a 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -1906,6 +1906,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[] =
@@ -2039,6 +2247,7 @@ START_TEST(mesh)
D3DXCreateMeshFVFTest();
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
More information about the wine-devel
mailing list