d3dx9: Implement D3DXCreateTorus() + tests (try 3)

Gediminas Jakutis gediminas at varciai.lt
Wed Jul 9 12:05:03 CDT 2014


Supersedes patch 105390.

---
 dlls/d3dx9_36/d3dx9_36.spec |   2 +-
 dlls/d3dx9_36/mesh.c        | 106 +++++++++++++++++++++++++++++
 dlls/d3dx9_36/tests/mesh.c  | 159 ++++++++++++++++++++++++++++++++++++++++++++
 include/d3dx9shape.h        |   2 +
 4 files changed, 268 insertions(+), 1 deletion(-)
-------------- next part --------------
diff --git a/dlls/d3dx9_36/d3dx9_36.spec b/dlls/d3dx9_36/d3dx9_36.spec
index f2c229a..4c72dc2 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(long long ptr long ptr)
 @ stub D3DXCreateTextureShader(ptr ptr)
-@ stub D3DXCreateTorus(ptr long long long long ptr ptr)
+@ stdcall D3DXCreateTorus(ptr long long long long ptr ptr)
 @ stdcall D3DXCreateVolumeTexture(ptr long long long long long long long ptr)
 @ stdcall D3DXCreateVolumeTextureFromFileA(ptr ptr ptr)
 @ stdcall D3DXCreateVolumeTextureFromFileExA(ptr ptr long long long long long long long long long long ptr ptr ptr)
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index 3b3784b..9901e3f 100644
--- a/dlls/d3dx9_36/mesh.c
+++ b/dlls/d3dx9_36/mesh.c
@@ -5068,6 +5068,112 @@ HRESULT WINAPI D3DXCreateTextA(struct IDirect3DDevice9 *device, HDC hdc, const c
     return hr;
 }
 
+HRESULT WINAPI D3DXCreateTorus(struct IDirect3DDevice9 *device,
+        float innerradius, float outerradius, UINT sides, UINT rings, struct ID3DXMesh **mesh, ID3DXBuffer **adjacency)
+{
+    HRESULT hr;
+    ID3DXMesh *torus;
+    WORD (*faces)[3];
+    struct vertex *vertices;
+    float phi, phi_step, sin_phi, cos_phi;
+    float theta, theta_step, sin_theta, cos_theta;
+    unsigned int i, j, numvert, numfaces;
+
+    TRACE("device %p, innerradius %.8e, outerradius %.8e, sides %u, rings %u, mesh %p, adjacency %p.\n",
+            device, innerradius, outerradius, sides, rings, mesh, adjacency);
+
+    numvert = sides * rings;
+    numfaces = numvert * 2;
+
+    if (!device || innerradius < 0.0f || outerradius < 0.0f || sides < 3 || rings < 3 || !mesh)
+    {
+        WARN("Invalid arguments.\n");
+        return D3DERR_INVALIDCALL;
+    }
+
+    if (FAILED(hr = D3DXCreateMeshFVF(numfaces, numvert, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &torus)))
+        return hr;
+
+    if (FAILED(hr = torus->lpVtbl->LockVertexBuffer(torus, 0, (void **)&vertices)))
+    {
+        torus->lpVtbl->Release(torus);
+        return hr;
+    }
+
+    if (FAILED(hr = torus->lpVtbl->LockIndexBuffer(torus, 0, (void **)&faces)))
+    {
+        torus->lpVtbl->UnlockVertexBuffer(torus);
+        torus->lpVtbl->Release(torus);
+        return hr;
+    }
+
+    phi_step = D3DX_PI / sides * 2.0f;
+    phi = 0.0f;
+
+    theta_step = D3DX_PI / rings * -2.0f;
+    theta = theta_step;
+
+    for (i = 0; i < rings; ++i)
+    {
+        cos_theta = cosf(theta);
+        sin_theta = sinf(theta);
+
+        for (j = 0; j < sides; ++j)
+        {
+            sin_phi = sinf(phi);
+            cos_phi = cosf(phi);
+
+            vertices[i * sides + j].position.x = (innerradius * cos_phi + outerradius) * cos_theta;
+            vertices[i * sides + j].position.y = (innerradius * cos_phi + outerradius) * sin_theta;
+            vertices[i * sides + j].position.z = innerradius * sin_phi;
+            vertices[i * sides + j].normal.x = cos_phi * cos_theta;
+            vertices[i * sides + j].normal.y = cos_phi * sin_theta;
+            vertices[i * sides + j].normal.z = sin_phi;
+
+            phi += phi_step;
+        }
+
+        theta += theta_step;
+    }
+
+    for (i = 0; i < numfaces - sides * 2; ++i)
+    {
+        faces[i][0] = i % 2 ? i / 2 + sides : i / 2;
+        faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
+        faces[i][2] = (i + 1) % (sides * 2) ? (i + 1) / 2 + sides : (i + 1) / 2;
+    }
+
+    for (j = 0; i < numfaces; ++i, ++j)
+    {
+        faces[i][0] = i % 2 ? j / 2 : i / 2;
+        faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
+        faces[i][2] = i == numfaces - 1 ? 0 : (j + 1) / 2;
+    }
+
+    torus->lpVtbl->UnlockIndexBuffer(torus);
+    torus->lpVtbl->UnlockVertexBuffer(torus);
+
+    if (adjacency)
+    {
+        if (FAILED(hr = D3DXCreateBuffer(numfaces * sizeof(DWORD) * 3, adjacency)))
+        {
+            torus->lpVtbl->Release(torus);
+            return hr;
+        }
+
+        if (FAILED(hr = torus->lpVtbl->GenerateAdjacency(torus, 0.0f, (*adjacency)->lpVtbl->GetBufferPointer(*adjacency))))
+        {
+            (*adjacency)->lpVtbl->Release(*adjacency);
+            torus->lpVtbl->Release(torus);
+            return hr;
+        }
+    }
+
+    *mesh = torus;
+
+    return D3D_OK;
+}
+
 enum pointtype {
     POINTTYPE_CURVE = 0,
     POINTTYPE_CORNER,
diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index 24bcb82..ec07f28 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -3157,6 +3157,164 @@ static void D3DXCreateCylinderTest(void)
     DestroyWindow(wnd);
 }
 
+static BOOL compute_torus(struct mesh *mesh, float innerradius, float outerradius, UINT sides, UINT rings)
+{
+    float phi, phi_step, sin_phi, cos_phi;
+    float theta, theta_step, sin_theta, cos_theta;
+    unsigned int numvert, numfaces, i, j;
+
+    numvert = sides * rings;
+    numfaces = numvert * 2;
+
+    if (!new_mesh(mesh, numvert, numfaces))
+        return FALSE;
+
+    phi_step = D3DX_PI / sides * 2.0f;
+    phi = 0.0f;
+
+    theta_step = D3DX_PI / rings * -2.0f;
+    theta = theta_step;
+
+    for (i = 0; i < rings; ++i)
+    {
+        cos_theta = cosf(theta);
+        sin_theta = sinf(theta);
+
+        for (j = 0; j < sides; ++j)
+        {
+            sin_phi = sinf(phi);
+            cos_phi = cosf(phi);
+
+            mesh->vertices[i * sides + j].position.x = (innerradius * cos_phi + outerradius) * cos_theta;
+            mesh->vertices[i * sides + j].position.y = (innerradius * cos_phi + outerradius) * sin_theta;
+            mesh->vertices[i * sides + j].position.z = innerradius * sin_phi;
+            mesh->vertices[i * sides + j].normal.x = cos_phi * cos_theta;
+            mesh->vertices[i * sides + j].normal.y = cos_phi * sin_theta;
+            mesh->vertices[i * sides + j].normal.z = sin_phi;
+
+            phi += phi_step;
+        }
+
+        theta += theta_step;
+    }
+
+    for (i = 0; i < numfaces - sides * 2; ++i)
+    {
+        mesh->faces[i][0] = i % 2 ? i / 2 + sides : i / 2;
+        mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
+        mesh->faces[i][2] = (i + 1) % (sides * 2) ? (i + 1) / 2 + sides : (i + 1) / 2;
+    }
+
+    for (j = 0; i < numfaces; ++i, ++j)
+    {
+        mesh->faces[i][0] = i % 2 ? j / 2 : i / 2;
+        mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
+        mesh->faces[i][2] = i == numfaces - 1 ? 0 : (j + 1) / 2;
+    }
+
+    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;
+
+    if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
+            640, 480, NULL, NULL, NULL, NULL)))
+    {
+        skip("Couldn't create application window\n");
+        return;
+    }
+
+    if (!(d3d = Direct3DCreate9(D3D_SDK_VERSION)))
+    {
+        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_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
+    if (FAILED(hr))
+    {
+        skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(wnd);
+        return;
+    }
+
+    hr = D3DXCreateTorus(NULL, 0.0f, 0.0f, 3, 3, &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, 3, &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, 3, &torus, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTorus(device, 0.0f, 0.0f, 2, 3, &torus, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 2, &torus, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
+
+    hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 3, 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, 3);
+    test_torus(device, 1.0f, 1.0f, 3, 3);
+    test_torus(device, 1.0f, 1.0f, 32, 64);
+    test_torus(device, 0.0f, 1.0f, 5, 5);
+    test_torus(device, 1.0f, 0.0f, 5, 5);
+    test_torus(device, 5.0f, 0.2f, 8, 8);
+    test_torus(device, 0.2f, 1.0f, 60, 3);
+    test_torus(device, 0.2f, 1.0f, 8, 70);
+
+    IDirect3DDevice9_Release(device);
+    IDirect3D9_Release(d3d);
+    DestroyWindow(wnd);
+}
+
 struct dynamic_array
 {
     int count, capacity;
@@ -10302,6 +10460,7 @@ START_TEST(mesh)
     D3DXCreateSphereTest();
     D3DXCreateCylinderTest();
     D3DXCreateTextTest();
+    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 1d2667d..0d24032 100644
--- a/include/d3dx9shape.h
+++ b/include/d3dx9shape.h
@@ -37,6 +37,8 @@ HRESULT WINAPI D3DXCreateTextA(struct IDirect3DDevice9 *device, HDC hdc, const c
         float extrusion, struct ID3DXMesh **mesh, struct ID3DXBuffer **adjacency, GLYPHMETRICSFLOAT *glyphmetrics);
 HRESULT WINAPI D3DXCreateTextW(struct IDirect3DDevice9 *device, HDC hdc, const WCHAR *text, float deviation,
         FLOAT extrusion, struct ID3DXMesh **mesh, struct ID3DXBuffer **adjacency, GLYPHMETRICSFLOAT *glyphmetrics);
+HRESULT WINAPI D3DXCreateTorus(struct IDirect3DDevice9 *device,
+        float innerradius, float outerradius, UINT sides, UINT rings, struct ID3DXMesh **mesh, ID3DXBuffer **adjacency);
 #define D3DXCreateText WINELIB_NAME_AW(D3DXCreateText)
 
 #ifdef __cplusplus
-- 
1.9.1



More information about the wine-patches mailing list