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