From d7d9cd5eb24bd4b682a6bb3d2b240e0e312c34f0 Mon Sep 17 00:00:00 2001 From: Misha Koshelev Date: Thu, 23 Sep 2010 16:22:34 -0500 Subject: [PATCH] d3dx9_36: Implement D3DXCreateSphere. --- dlls/d3dx9_36/mesh.c | 222 ++++++++++++++++++++++++++++++++++++- dlls/d3dx9_36/tests/mesh.c | 18 +-- 2 files changed, 229 insertions(+), 11 deletions(-) diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index a7ea30acfcc..9cb6e0dd7f9 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -1063,12 +1063,230 @@ HRESULT WINAPI D3DXCreateBox(LPDIRECT3DDEVICE9 device, FLOAT width, FLOAT height return E_NOTIMPL; } +struct vertex +{ + D3DXVECTOR3 position; + D3DXVECTOR3 normal; +}; + +typedef WORD face[3]; + +struct sincos_table +{ + float *sin; + float *cos; +}; + +static void free_sincos_table(struct sincos_table *sincos_table) +{ + HeapFree(GetProcessHeap(), 0, sincos_table->cos); + HeapFree(GetProcessHeap(), 0, sincos_table->sin); +} + +/* pre compute sine and cosine tables; caller must free */ +static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n) +{ + float angle; + int i; + + sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin)); + if (!sincos_table->sin) + { + return FALSE; + } + sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos)); + if (!sincos_table->cos) + { + HeapFree(GetProcessHeap(), 0, sincos_table->sin); + return FALSE; + } + + angle = angle_start; + for (i = 0; i < n; i++) + { + sincos_table->sin[i] = sin(angle); + sincos_table->cos[i] = cos(angle); + angle += angle_step; + } + + return TRUE; +} + +static WORD sphere_vertex(UINT slices, int slice, int stack) +{ + return stack*slices+slice+1; +} + HRESULT WINAPI D3DXCreateSphere(LPDIRECT3DDEVICE9 device, FLOAT radius, UINT slices, UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency) { - FIXME("(%p, %f, %d, %d, %p, %p): stub\n", device, radius, slices, stacks, mesh, adjacency); + DWORD number_of_vertices, number_of_faces; + HRESULT hr; + ID3DXMesh *sphere; + struct vertex *vertices; + face *faces; + float phi_step, phi_start; + struct sincos_table phi; + float theta_step, theta, sin_theta, cos_theta; + DWORD vertex, face; + int slice, stack; - return E_NOTIMPL; + TRACE("(%p, %f, %u, %u, %p, %p)\n", device, radius, slices, stacks, mesh, adjacency); + + if (!device || radius < 0.0f || slices < 2 || stacks < 2 || !mesh) + { + return D3DERR_INVALIDCALL; + } + + if (adjacency) + { + FIXME("Case of adjacency != NULL not implemented.\n"); + return E_NOTIMPL; + } + + number_of_vertices = 2 + slices * (stacks-1); + number_of_faces = 2 * slices + (stacks - 2) * (2 * slices); + + hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED, + D3DFVF_XYZ | D3DFVF_NORMAL, device, &sphere); + if (FAILED(hr)) + { + return hr; + } + + hr = sphere->lpVtbl->LockVertexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&vertices); + if (FAILED(hr)) + { + sphere->lpVtbl->Release(sphere); + return hr; + } + + hr = sphere->lpVtbl->LockIndexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&faces); + if (FAILED(hr)) + { + sphere->lpVtbl->UnlockVertexBuffer(sphere); + sphere->lpVtbl->Release(sphere); + return hr; + } + + /* phi = angle on xz plane wrt z axis */ + phi_step = -2 * M_PI / slices; + phi_start = M_PI / 2; + + if (!compute_sincos_table(&phi, phi_start, phi_step, slices)) + { + sphere->lpVtbl->UnlockIndexBuffer(sphere); + sphere->lpVtbl->UnlockVertexBuffer(sphere); + sphere->lpVtbl->Release(sphere); + return E_OUTOFMEMORY; + } + + /* theta = angle on xy plane wrt x axis */ + theta_step = M_PI / stacks; + theta = theta_step; + + vertex = 0; + face = 0; + stack = 0; + + vertices[vertex].normal.x = 0.0f; + vertices[vertex].normal.y = 0.0f; + vertices[vertex].normal.z = 1.0f; + vertices[vertex].position.x = 0.0f; + vertices[vertex].position.y = 0.0f; + vertices[vertex].position.z = radius; + vertex++; + + for (stack = 0; stack < stacks - 1; stack++) + { + sin_theta = sin(theta); + cos_theta = cos(theta); + + for (slice = 0; slice < slices; slice++) + { + vertices[vertex].normal.x = sin_theta * phi.cos[slice]; + vertices[vertex].normal.y = sin_theta * phi.sin[slice]; + vertices[vertex].normal.z = cos_theta; + vertices[vertex].position.x = radius * sin_theta * phi.cos[slice]; + vertices[vertex].position.y = radius * sin_theta * phi.sin[slice]; + vertices[vertex].position.z = radius * cos_theta; + vertex++; + + if (slice > 0) + { + if (stack == 0) + { + /* top stack is triangle fan */ + faces[face][0] = 0; + faces[face][1] = slice + 1; + faces[face][2] = slice; + face++; + } + else + { + /* stacks in between top and bottom are quad strips */ + faces[face][0] = sphere_vertex(slices, slice-1, stack-1); + faces[face][1] = sphere_vertex(slices, slice, stack-1); + faces[face][2] = sphere_vertex(slices, slice-1, stack); + face++; + + faces[face][0] = sphere_vertex(slices, slice, stack-1); + faces[face][1] = sphere_vertex(slices, slice, stack); + faces[face][2] = sphere_vertex(slices, slice-1, stack); + face++; + } + } + } + + theta += theta_step; + + if (stack == 0) + { + faces[face][0] = 0; + faces[face][1] = 1; + faces[face][2] = slice; + face++; + } + else + { + faces[face][0] = sphere_vertex(slices, slice-1, stack-1); + faces[face][1] = sphere_vertex(slices, 0, stack-1); + faces[face][2] = sphere_vertex(slices, slice-1, stack); + face++; + + faces[face][0] = sphere_vertex(slices, 0, stack-1); + faces[face][1] = sphere_vertex(slices, 0, stack); + faces[face][2] = sphere_vertex(slices, slice-1, stack); + face++; + } + } + + vertices[vertex].position.x = 0.0f; + vertices[vertex].position.y = 0.0f; + vertices[vertex].position.z = -radius; + vertices[vertex].normal.x = 0.0f; + vertices[vertex].normal.y = 0.0f; + vertices[vertex].normal.z = -1.0f; + + /* bottom stack is triangle fan */ + for (slice = 1; slice < slices; slice++) + { + faces[face][0] = sphere_vertex(slices, slice-1, stack-1); + faces[face][1] = sphere_vertex(slices, slice, stack-1); + faces[face][2] = vertex; + face++; + } + + faces[face][0] = sphere_vertex(slices, slice-1, stack-1); + faces[face][1] = sphere_vertex(slices, 0, stack-1); + faces[face][2] = vertex; + + free_sincos_table(&phi); + sphere->lpVtbl->UnlockIndexBuffer(sphere); + sphere->lpVtbl->UnlockVertexBuffer(sphere); + *mesh = sphere; + + return D3D_OK; } HRESULT WINAPI D3DXCreateTeapot(LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh, LPD3DXBUFFER* adjacency) diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index 2404024f273..518a9ac56e1 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -1537,7 +1537,7 @@ static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UIN char name[256]; hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL); - todo_wine ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr); + ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr); if (hr != D3D_OK) { skip("Couldn't create sphere\n"); @@ -1571,16 +1571,16 @@ static void D3DXCreateSphereTest(void) ID3DXMesh* sphere = NULL; hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL); - todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL); - todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL); - todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL); - todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + 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); @@ -1609,16 +1609,16 @@ static void D3DXCreateSphereTest(void) } hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL); - todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL); hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL); hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL); hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL); - todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL); + ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL); test_sphere(device, 0.0f, 2, 2); test_sphere(device, 1.0f, 2, 2);