d3dx9_36: Add a few tests for D3DXCreateBox.
[wine] / dlls / d3dx9_36 / tests / mesh.c
1 /*
2  * Copyright 2008 David Adam
3  * Copyright 2008 Luis Busquets
4  * Copyright 2009 Henri Verbeet for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdio.h>
22 #include "wine/test.h"
23 #include "d3dx9.h"
24
25 #define admitted_error 0.0001f
26
27 #define compare_vertex_sizes(type, exp) \
28     got=D3DXGetFVFVertexSize(type); \
29     ok(got==exp, "Expected: %d, Got: %d\n", exp, got);
30
31 static BOOL compare(FLOAT u, FLOAT v)
32 {
33     return (fabs(u-v) < admitted_error);
34 }
35
36 static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v)
37 {
38     return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
39 }
40
41 struct vertex
42 {
43     D3DXVECTOR3 position;
44     D3DXVECTOR3 normal;
45 };
46
47 typedef WORD face[3];
48
49 static BOOL compare_face(face a, face b)
50 {
51     return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
52 }
53
54 struct mesh
55 {
56     DWORD number_of_vertices;
57     struct vertex *vertices;
58
59     DWORD number_of_faces;
60     face *faces;
61
62     DWORD fvf;
63     UINT vertex_size;
64 };
65
66 static void free_mesh(struct mesh *mesh)
67 {
68     HeapFree(GetProcessHeap(), 0, mesh->faces);
69     HeapFree(GetProcessHeap(), 0, mesh->vertices);
70 }
71
72 static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
73 {
74     mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
75     if (!mesh->vertices)
76     {
77         return FALSE;
78     }
79     mesh->number_of_vertices = number_of_vertices;
80
81     mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
82     if (!mesh->faces)
83     {
84         HeapFree(GetProcessHeap(), 0, mesh->vertices);
85         return FALSE;
86     }
87     mesh->number_of_faces = number_of_faces;
88
89     return TRUE;
90 }
91
92 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
93 {
94     HRESULT hr;
95     DWORD number_of_vertices, number_of_faces;
96     IDirect3DVertexBuffer9 *vertex_buffer;
97     IDirect3DIndexBuffer9 *index_buffer;
98     D3DVERTEXBUFFER_DESC vertex_buffer_description;
99     D3DINDEXBUFFER_DESC index_buffer_description;
100     struct vertex *vertices;
101     face *faces;
102     int expected, i;
103
104     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
105     ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
106        name, number_of_vertices, mesh->number_of_vertices);
107
108     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
109     ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
110        name, number_of_faces, mesh->number_of_faces);
111
112     /* vertex buffer */
113     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
114     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
115
116     if (hr != D3D_OK)
117     {
118         skip("Couldn't get vertex buffer\n");
119     }
120     else
121     {
122         hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
123         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
124
125         if (hr != D3D_OK)
126         {
127             skip("Couldn't get vertex buffer description\n");
128         }
129         else
130         {
131             ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
132                name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
133             ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
134                name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
135             ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
136             ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_DEFAULT)\n",
137                name, vertex_buffer_description.Pool, D3DPOOL_DEFAULT);
138             ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
139                name, vertex_buffer_description.FVF, mesh->fvf);
140             if (mesh->fvf == 0)
141             {
142                 expected = number_of_vertices * mesh->vertex_size;
143             }
144             else
145             {
146                 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
147             }
148             ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
149                name, vertex_buffer_description.Size, expected);
150         }
151
152         /* specify offset and size to avoid potential overruns */
153         hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
154                                          (LPVOID *)&vertices, D3DLOCK_DISCARD);
155         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
156
157         if (hr != D3D_OK)
158         {
159             skip("Couldn't lock vertex buffer\n");
160         }
161         else
162         {
163             for (i = 0; i < number_of_vertices; i++)
164             {
165                 ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
166                    "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
167                    vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
168                    mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
169                 ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
170                    "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
171                    vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
172                    mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
173             }
174
175             IDirect3DVertexBuffer9_Unlock(vertex_buffer);
176         }
177
178         IDirect3DVertexBuffer9_Release(vertex_buffer);
179     }
180
181     /* index buffer */
182     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
183     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
184
185     if (!index_buffer)
186     {
187         skip("Couldn't get index buffer\n");
188     }
189     else
190     {
191         hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
192         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
193
194         if (hr != D3D_OK)
195         {
196             skip("Couldn't get index buffer description\n");
197         }
198         else
199         {
200             ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
201                name, index_buffer_description.Format, D3DFMT_INDEX16);
202             ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
203                name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
204             todo_wine ok(index_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, index_buffer_description.Usage, 0);
205             ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_DEFAULT)\n",
206                name, index_buffer_description.Pool, D3DPOOL_DEFAULT);
207             expected = number_of_faces * sizeof(WORD) * 3;
208             ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
209                name, index_buffer_description.Size, expected);
210         }
211
212         /* specify offset and size to avoid potential overruns */
213         hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
214                                         (LPVOID *)&faces, D3DLOCK_DISCARD);
215         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
216
217         if (hr != D3D_OK)
218         {
219             skip("Couldn't lock index buffer\n");
220         }
221         else
222         {
223             for (i = 0; i < number_of_faces; i++)
224             {
225                 ok(compare_face(faces[i], mesh->faces[i]),
226                    "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
227                    faces[i][0], faces[i][1], faces[i][2],
228                    mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
229             }
230
231             IDirect3DIndexBuffer9_Unlock(index_buffer);
232         }
233
234         IDirect3DIndexBuffer9_Release(index_buffer);
235     }
236 }
237
238 static void D3DXBoundProbeTest(void)
239 {
240     BOOL result;
241     D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
242     FLOAT radius;
243
244 /*____________Test the Box case___________________________*/
245     bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
246     top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
247
248     raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
249     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
250     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
251     ok(result == TRUE, "expected TRUE, received FALSE\n");
252
253     raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
254     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
255     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
256     ok(result == FALSE, "expected FALSE, received TRUE\n");
257
258     rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
259     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
260     ok(result == TRUE, "expected TRUE, received FALSE\n");
261
262     bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
263     top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
264     rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
265     raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
266     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
267     ok(result == FALSE, "expected FALSE, received TRUE\n");
268
269     bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
270     top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
271
272     raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
273     rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
274     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
275     ok(result == TRUE, "expected TRUE, received FALSE\n");
276
277     bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
278     top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
279
280     raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
281     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
282     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
283     ok(result == FALSE, "expected FALSE, received TRUE\n");
284
285     raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
286     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
287     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
288     ok(result == TRUE, "expected TRUE, received FALSE\n");
289
290 /*____________Test the Sphere case________________________*/
291     radius = sqrt(77.0f);
292     center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
293     raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
294
295     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
296     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
297     ok(result == TRUE, "expected TRUE, received FALSE\n");
298
299     rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
300     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
301     ok(result == FALSE, "expected FALSE, received TRUE\n");
302
303     rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
304     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
305     ok(result == FALSE, "expected FALSE, received TRUE\n");
306 }
307
308 static void D3DXComputeBoundingBoxTest(void)
309 {
310     D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
311     HRESULT hr;
312
313     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
314     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
315     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
316     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
317     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
318
319     exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
320     exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
321
322     hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
323
324     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
325     ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
326     ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
327
328 /*________________________*/
329
330     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
331     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
332     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
333     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
334     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
335
336     exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
337     exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
338
339     hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
340
341     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
342     ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
343     ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
344
345 /*________________________*/
346
347     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
348     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
349     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
350     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
351     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
352
353     exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
354     exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
355
356     hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
357
358     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
359     ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
360     ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
361
362 /*________________________*/
363     hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
364     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
365
366 /*________________________*/
367     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
368     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
369
370 /*________________________*/
371     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
372     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
373 }
374
375 static void D3DXComputeBoundingSphereTest(void)
376 {
377     D3DXVECTOR3 exp_cen, got_cen, vertex[5];
378     FLOAT exp_rad, got_rad;
379     HRESULT hr;
380
381     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
382     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
383     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
384     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
385     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
386
387     exp_rad = 6.928203f;
388     exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
389
390     hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
391
392     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
393     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
394     ok( compare_vec3(exp_cen,got_cen), "Expected center: (%f, %f, %f), got center: (%f, %f, %f)\n", exp_cen.x,exp_cen.y,exp_cen.z,got_cen.x,got_cen.y,got_cen.z);
395
396 /*________________________*/
397
398     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
399     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
400     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
401     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
402     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
403
404     exp_rad = 13.707883f;
405     exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
406
407     hr = D3DXComputeBoundingSphere(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
408
409     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
410     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
411     ok( compare_vec3(exp_cen,got_cen), "Expected center: (%f, %f, %f), got center: (%f, %f, %f)\n", exp_cen.x,exp_cen.y,exp_cen.z,got_cen.x,got_cen.y,got_cen.z);
412
413 /*________________________*/
414     hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
415     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
416
417 /*________________________*/
418     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
419     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
420
421 /*________________________*/
422     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
423     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
424 }
425
426 static void print_elements(const D3DVERTEXELEMENT9 *elements)
427 {
428     D3DVERTEXELEMENT9 last = D3DDECL_END();
429     const D3DVERTEXELEMENT9 *ptr = elements;
430     int count = 0;
431
432     while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
433     {
434         trace(
435             "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
436              count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
437         ptr++;
438         count++;
439     }
440 }
441
442 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
443         unsigned int line, unsigned int test_id)
444 {
445     D3DVERTEXELEMENT9 last = D3DDECL_END();
446     unsigned int i;
447
448     for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
449     {
450         int end1 = memcmp(&elements[i], &last, sizeof(last));
451         int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
452         int status;
453
454         if (!end1 && !end2) break;
455
456         status = !end1 ^ !end2;
457         ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
458                 line, test_id, end1 ? "shorter" : "longer");
459         if (status)
460         {
461             print_elements(elements);
462             break;
463         }
464
465         status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
466         ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
467         if (status)
468         {
469             print_elements(elements);
470             break;
471         }
472     }
473 }
474
475 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
476         HRESULT expected_hr, unsigned int line, unsigned int test_id)
477 {
478     HRESULT hr;
479     D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
480
481     hr = D3DXDeclaratorFromFVF(test_fvf, decl);
482     ok(hr == expected_hr,
483             "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
484             line, test_id, hr, expected_hr);
485     if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
486 }
487
488 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
489         HRESULT expected_hr, unsigned int line, unsigned int test_id)
490 {
491     HRESULT hr;
492     DWORD result_fvf = 0xdeadbeef;
493
494     hr = D3DXFVFFromDeclarator(decl, &result_fvf);
495     ok(hr == expected_hr,
496        "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
497        line, test_id, hr, expected_hr);
498     if (SUCCEEDED(hr))
499     {
500         ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
501                 line, test_id, result_fvf, expected_fvf);
502     }
503 }
504
505 static void test_fvf_decl_conversion(void)
506 {
507     static const struct
508     {
509         D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
510         DWORD fvf;
511     }
512     test_data[] =
513     {
514         {{
515             D3DDECL_END(),
516         }, 0},
517         {{
518             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
519             D3DDECL_END(),
520         }, D3DFVF_XYZ},
521         {{
522             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
523             D3DDECL_END(),
524         }, D3DFVF_XYZRHW},
525         {{
526             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
527             D3DDECL_END(),
528         }, D3DFVF_XYZRHW},
529         {{
530             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
531             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
532             D3DDECL_END(),
533         }, D3DFVF_XYZB1},
534         {{
535             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
536             {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
537             D3DDECL_END(),
538         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
539         {{
540             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
541             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
542             D3DDECL_END(),
543         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
544         {{
545             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
546             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
547             D3DDECL_END(),
548         }, D3DFVF_XYZB2},
549         {{
550             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
551             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
552             {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
553             D3DDECL_END(),
554         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
555         {{
556             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
557             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
558             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
559             D3DDECL_END(),
560         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
561         {{
562             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
563             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
564             D3DDECL_END(),
565         }, D3DFVF_XYZB3},
566         {{
567             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
568             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
569             {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
570             D3DDECL_END(),
571         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
572         {{
573             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
574             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
575             {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
576             D3DDECL_END(),
577         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
578         {{
579             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
580             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
581             D3DDECL_END(),
582         }, D3DFVF_XYZB4},
583         {{
584             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
585             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
586             {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
587             D3DDECL_END(),
588         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
589         {{
590             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
591             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
592             {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
593             D3DDECL_END(),
594         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
595         {{
596             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
597             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
598             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
599             D3DDECL_END(),
600         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
601         {{
602             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
603             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
604             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
605             D3DDECL_END(),
606         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
607         {{
608             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
609             D3DDECL_END(),
610         }, D3DFVF_NORMAL},
611         {{
612             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
613             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
614             D3DDECL_END(),
615         }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
616         {{
617             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
618             D3DDECL_END(),
619         }, D3DFVF_PSIZE},
620         {{
621             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
622             D3DDECL_END(),
623         }, D3DFVF_DIFFUSE},
624         {{
625             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
626             D3DDECL_END(),
627         }, D3DFVF_SPECULAR},
628         /* Make sure textures of different sizes work. */
629         {{
630             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
631             D3DDECL_END(),
632         }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
633         {{
634             {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
635             D3DDECL_END(),
636         }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
637         {{
638             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
639             D3DDECL_END(),
640         }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
641         {{
642             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
643             D3DDECL_END(),
644         }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
645         /* Make sure the TEXCOORD index works correctly - try several textures. */
646         {{
647             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
648             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
649             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
650             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
651             D3DDECL_END(),
652         }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
653                 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
654         /* Now try some combination tests. */
655         {{
656             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
657             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
658             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
659             {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
660             {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
661             {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
662             D3DDECL_END(),
663         }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
664                 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
665         {{
666             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
667             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
668             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
669             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
670             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
671             {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
672             D3DDECL_END(),
673         }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
674                 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
675     };
676     unsigned int i;
677
678     for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
679     {
680         test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
681         test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
682     }
683
684     /* Usage indices for position and normal are apparently ignored. */
685     {
686         const D3DVERTEXELEMENT9 decl[] =
687         {
688             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
689             D3DDECL_END(),
690         };
691         test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
692     }
693     {
694         const D3DVERTEXELEMENT9 decl[] =
695         {
696             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
697             D3DDECL_END(),
698         };
699         test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
700     }
701     /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
702      * there are no blend matrices. */
703     {
704         const D3DVERTEXELEMENT9 decl[] =
705         {
706             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
707             D3DDECL_END(),
708         };
709         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
710     }
711     {
712         const D3DVERTEXELEMENT9 decl[] =
713         {
714             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
715             D3DDECL_END(),
716         };
717         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
718     }
719     /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
720     {
721         const D3DVERTEXELEMENT9 decl[] =
722         {
723             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
724             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
725             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
726             D3DDECL_END(),
727         };
728         test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
729                 decl, D3D_OK, __LINE__, 0);
730     }
731     /* These are supposed to fail, both ways. */
732     {
733         const D3DVERTEXELEMENT9 decl[] =
734         {
735             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
736             D3DDECL_END(),
737         };
738         test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
739         test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
740     }
741     {
742         const D3DVERTEXELEMENT9 decl[] =
743         {
744             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
745             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
746             D3DDECL_END(),
747         };
748         test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
749         test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
750     }
751     {
752         const D3DVERTEXELEMENT9 decl[] =
753         {
754             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
755             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
756             {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
757             D3DDECL_END(),
758         };
759         test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
760         test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
761     }
762     /* Test a declaration that can't be converted to an FVF. */
763     {
764         const D3DVERTEXELEMENT9 decl[] =
765         {
766             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
767             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
768             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
769             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
770             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
771             /* 8 bytes padding */
772             {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
773             D3DDECL_END(),
774         };
775         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
776     }
777     /* Elements must be ordered by offset. */
778     {
779         const D3DVERTEXELEMENT9 decl[] =
780         {
781             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
782             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
783             D3DDECL_END(),
784         };
785         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
786     }
787     /* Basic tests for element order. */
788     {
789         const D3DVERTEXELEMENT9 decl[] =
790         {
791             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
792             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
793             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
794             D3DDECL_END(),
795         };
796         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
797     }
798     {
799         const D3DVERTEXELEMENT9 decl[] =
800         {
801             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
802             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
803             D3DDECL_END(),
804         };
805         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
806     }
807     {
808         const D3DVERTEXELEMENT9 decl[] =
809         {
810             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
811             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
812             D3DDECL_END(),
813         };
814         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
815     }
816     /* Textures must be ordered by texcoords. */
817     {
818         const D3DVERTEXELEMENT9 decl[] =
819         {
820             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
821             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
822             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
823             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
824             D3DDECL_END(),
825         };
826         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
827     }
828     /* Duplicate elements are not allowed. */
829     {
830         const D3DVERTEXELEMENT9 decl[] =
831         {
832             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
833             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
834             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
835             D3DDECL_END(),
836         };
837         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
838     }
839     /* Invalid FVFs cannot be converted to a declarator. */
840     test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
841 }
842
843 static void D3DXGetFVFVertexSizeTest(void)
844 {
845     UINT got;
846
847     compare_vertex_sizes (D3DFVF_XYZ, 12);
848
849     compare_vertex_sizes (D3DFVF_XYZB3, 24);
850
851     compare_vertex_sizes (D3DFVF_XYZB5, 32);
852
853     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
854
855     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
856
857     compare_vertex_sizes (
858         D3DFVF_XYZ |
859         D3DFVF_TEX1 |
860         D3DFVF_TEXCOORDSIZE1(0), 16);
861     compare_vertex_sizes (
862         D3DFVF_XYZ |
863         D3DFVF_TEX2 |
864         D3DFVF_TEXCOORDSIZE1(0) |
865         D3DFVF_TEXCOORDSIZE1(1), 20);
866
867     compare_vertex_sizes (
868         D3DFVF_XYZ |
869         D3DFVF_TEX1 |
870         D3DFVF_TEXCOORDSIZE2(0), 20);
871
872     compare_vertex_sizes (
873         D3DFVF_XYZ |
874         D3DFVF_TEX2 |
875         D3DFVF_TEXCOORDSIZE2(0) |
876         D3DFVF_TEXCOORDSIZE2(1), 28);
877
878     compare_vertex_sizes (
879         D3DFVF_XYZ |
880         D3DFVF_TEX6 |
881         D3DFVF_TEXCOORDSIZE2(0) |
882         D3DFVF_TEXCOORDSIZE2(1) |
883         D3DFVF_TEXCOORDSIZE2(2) |
884         D3DFVF_TEXCOORDSIZE2(3) |
885         D3DFVF_TEXCOORDSIZE2(4) |
886         D3DFVF_TEXCOORDSIZE2(5), 60);
887
888     compare_vertex_sizes (
889         D3DFVF_XYZ |
890         D3DFVF_TEX8 |
891         D3DFVF_TEXCOORDSIZE2(0) |
892         D3DFVF_TEXCOORDSIZE2(1) |
893         D3DFVF_TEXCOORDSIZE2(2) |
894         D3DFVF_TEXCOORDSIZE2(3) |
895         D3DFVF_TEXCOORDSIZE2(4) |
896         D3DFVF_TEXCOORDSIZE2(5) |
897         D3DFVF_TEXCOORDSIZE2(6) |
898         D3DFVF_TEXCOORDSIZE2(7), 76);
899
900     compare_vertex_sizes (
901         D3DFVF_XYZ |
902         D3DFVF_TEX1 |
903         D3DFVF_TEXCOORDSIZE3(0), 24);
904
905     compare_vertex_sizes (
906         D3DFVF_XYZ |
907         D3DFVF_TEX4 |
908         D3DFVF_TEXCOORDSIZE3(0) |
909         D3DFVF_TEXCOORDSIZE3(1) |
910         D3DFVF_TEXCOORDSIZE3(2) |
911         D3DFVF_TEXCOORDSIZE3(3), 60);
912
913     compare_vertex_sizes (
914         D3DFVF_XYZ |
915         D3DFVF_TEX1 |
916         D3DFVF_TEXCOORDSIZE4(0), 28);
917
918     compare_vertex_sizes (
919         D3DFVF_XYZ |
920         D3DFVF_TEX2 |
921         D3DFVF_TEXCOORDSIZE4(0) |
922         D3DFVF_TEXCOORDSIZE4(1), 44);
923
924     compare_vertex_sizes (
925         D3DFVF_XYZ |
926         D3DFVF_TEX3 |
927         D3DFVF_TEXCOORDSIZE4(0) |
928         D3DFVF_TEXCOORDSIZE4(1) |
929         D3DFVF_TEXCOORDSIZE4(2), 60);
930
931     compare_vertex_sizes (
932         D3DFVF_XYZB5 |
933         D3DFVF_NORMAL |
934         D3DFVF_DIFFUSE |
935         D3DFVF_SPECULAR |
936         D3DFVF_TEX8 |
937         D3DFVF_TEXCOORDSIZE4(0) |
938         D3DFVF_TEXCOORDSIZE4(1) |
939         D3DFVF_TEXCOORDSIZE4(2) |
940         D3DFVF_TEXCOORDSIZE4(3) |
941         D3DFVF_TEXCOORDSIZE4(4) |
942         D3DFVF_TEXCOORDSIZE4(5) |
943         D3DFVF_TEXCOORDSIZE4(6) |
944         D3DFVF_TEXCOORDSIZE4(7), 180);
945 }
946
947 static void D3DXIntersectTriTest(void)
948 {
949     BOOL exp_res, got_res;
950     D3DXVECTOR3 position, ray, vertex[3];
951     FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
952
953     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
954     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
955     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
956
957     position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
958
959     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
960
961     exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
962
963     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
964     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
965     ok( compare(exp_u,got_u), "Expected u = %f, got %f\n",exp_u,got_u);
966     ok( compare(exp_v,got_v), "Expected v = %f, got %f\n",exp_v,got_v);
967     ok( compare(exp_dist,got_dist), "Expected distance = %f, got %f\n",exp_dist,got_dist);
968
969 /*Only positive ray is taken in account*/
970
971     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
972     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
973     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
974
975     position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
976
977     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
978
979     exp_res = FALSE;
980
981     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
982     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
983
984 /*Intersection between ray and triangle in a same plane is considered as empty*/
985
986     vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
987     vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
988     vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
989
990     position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
991
992     ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
993
994     exp_res = FALSE;
995
996     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
997     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
998 }
999
1000 static void D3DXCreateMeshTest(void)
1001 {
1002     HRESULT hr;
1003     HWND wnd;
1004     IDirect3D9 *d3d;
1005     IDirect3DDevice9 *device, *test_device;
1006     D3DPRESENT_PARAMETERS d3dpp;
1007     ID3DXMesh *d3dxmesh;
1008     int i, size;
1009     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1010     DWORD options;
1011     struct mesh mesh;
1012
1013     static const D3DVERTEXELEMENT9 decl1[3] = {
1014         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1015         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1016         D3DDECL_END(), };
1017
1018     static const D3DVERTEXELEMENT9 decl2[] = {
1019         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1020         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1021         {0, 24, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
1022         {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
1023         {0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
1024         /* 8 bytes padding */
1025         {0, 44, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
1026         D3DDECL_END(),
1027     };
1028
1029     hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1030     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1031
1032     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1033     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1034
1035     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1036     if (!wnd)
1037     {
1038         skip("Couldn't create application window\n");
1039         return;
1040     }
1041     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1042     if (!d3d)
1043     {
1044         skip("Couldn't create IDirect3D9 object\n");
1045         DestroyWindow(wnd);
1046         return;
1047     }
1048
1049     ZeroMemory(&d3dpp, sizeof(d3dpp));
1050     d3dpp.Windowed = TRUE;
1051     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1052     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1053     if (FAILED(hr))
1054     {
1055         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1056         IDirect3D9_Release(d3d);
1057         DestroyWindow(wnd);
1058         return;
1059     }
1060
1061     hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1062     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1063
1064     hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1065     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1066
1067     hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
1068     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1069
1070     if (hr == D3D_OK)
1071     {
1072         d3dxmesh->lpVtbl->Release(d3dxmesh);
1073     }
1074
1075     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1076     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1077
1078     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
1079     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1080
1081     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1082     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1083
1084     if (hr == D3D_OK)
1085     {
1086         /* device */
1087         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1088         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1089
1090         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1091         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1092         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1093
1094         if (hr == D3D_OK)
1095         {
1096             IDirect3DDevice9_Release(device);
1097         }
1098
1099         /* declaration */
1100         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1101         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1102
1103         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1104         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1105
1106         if (hr == D3D_OK)
1107         {
1108             size = sizeof(decl1) / sizeof(decl1[0]);
1109             for (i = 0; i < size - 1; i++)
1110             {
1111                 ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1112                 ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1113                 ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1114                 ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1115                 ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1116                 ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1117             }
1118             ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1119         }
1120
1121         /* options */
1122         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1123         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1124
1125         /* rest */
1126         if (!new_mesh(&mesh, 3, 1))
1127         {
1128             skip("Couldn't create mesh\n");
1129         }
1130         else
1131         {
1132             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1133             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1134             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1135
1136             compare_mesh("createmesh1", d3dxmesh, &mesh);
1137
1138             free_mesh(&mesh);
1139         }
1140
1141         d3dxmesh->lpVtbl->Release(d3dxmesh);
1142     }
1143
1144     /* Test a declaration that can't be converted to an FVF. */
1145     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1146     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1147
1148     if (hr == D3D_OK)
1149     {
1150         /* device */
1151         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1152         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1153
1154         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1155         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1156         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1157
1158         if (hr == D3D_OK)
1159         {
1160             IDirect3DDevice9_Release(device);
1161         }
1162
1163         /* declaration */
1164         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1165         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1166
1167         if (hr == D3D_OK)
1168         {
1169             size = sizeof(decl2) / sizeof(decl2[0]);
1170             for (i = 0; i < size - 1; i++)
1171             {
1172                 ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1173                 ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1174                 ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1175                 ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1176                 ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1177                 ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1178             }
1179             ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1180         }
1181
1182         /* options */
1183         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1184         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1185
1186         /* rest */
1187         if (!new_mesh(&mesh, 3, 1))
1188         {
1189             skip("Couldn't create mesh\n");
1190         }
1191         else
1192         {
1193             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1194             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1195             mesh.fvf = 0;
1196             mesh.vertex_size = 60;
1197
1198             compare_mesh("createmesh2", d3dxmesh, &mesh);
1199
1200             free_mesh(&mesh);
1201         }
1202
1203         d3dxmesh->lpVtbl->Release(d3dxmesh);
1204     }
1205
1206     IDirect3DDevice9_Release(device);
1207     IDirect3D9_Release(d3d);
1208     DestroyWindow(wnd);
1209 }
1210
1211 static void D3DXCreateMeshFVFTest(void)
1212 {
1213     HRESULT hr;
1214     HWND wnd;
1215     IDirect3D9 *d3d;
1216     IDirect3DDevice9 *device, *test_device;
1217     D3DPRESENT_PARAMETERS d3dpp;
1218     ID3DXMesh *d3dxmesh;
1219     int i, size;
1220     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1221     DWORD options;
1222     struct mesh mesh;
1223
1224     static const D3DVERTEXELEMENT9 decl[3] = {
1225         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1226         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1227         D3DDECL_END(), };
1228
1229     hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1230     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1231
1232     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, NULL, &d3dxmesh);
1233     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1234
1235     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1236     if (!wnd)
1237     {
1238         skip("Couldn't create application window\n");
1239         return;
1240     }
1241     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1242     if (!d3d)
1243     {
1244         skip("Couldn't create IDirect3D9 object\n");
1245         DestroyWindow(wnd);
1246         return;
1247     }
1248
1249     ZeroMemory(&d3dpp, sizeof(d3dpp));
1250     d3dpp.Windowed = TRUE;
1251     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1252     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1253     if (FAILED(hr))
1254     {
1255         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1256         IDirect3D9_Release(d3d);
1257         DestroyWindow(wnd);
1258         return;
1259     }
1260
1261     hr = D3DXCreateMeshFVF(0, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1262     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1263
1264     hr = D3DXCreateMeshFVF(1, 0, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1265     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1266
1267     hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1268     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1269
1270     if (hr == D3D_OK)
1271     {
1272         d3dxmesh->lpVtbl->Release(d3dxmesh);
1273     }
1274
1275     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1276     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1277
1278     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, NULL);
1279     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1280
1281     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1282     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1283
1284     if (hr == D3D_OK)
1285     {
1286         /* device */
1287         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1288         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1289
1290         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1291         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1292         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1293
1294         if (hr == D3D_OK)
1295         {
1296             IDirect3DDevice9_Release(device);
1297         }
1298
1299         /* declaration */
1300         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1301         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1302
1303         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1304         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1305
1306         if (hr == D3D_OK)
1307         {
1308             size = sizeof(decl) / sizeof(decl[0]);
1309             for (i = 0; i < size - 1; i++)
1310             {
1311                 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1312                 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1313                 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1314                 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1315                 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1316                    test_decl[i].UsageIndex, decl[i].UsageIndex);
1317                 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1318             }
1319             ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1320         }
1321
1322         /* options */
1323         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1324         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1325
1326         /* rest */
1327         if (!new_mesh(&mesh, 3, 1))
1328         {
1329             skip("Couldn't create mesh\n");
1330         }
1331         else
1332         {
1333             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1334             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1335             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1336
1337             compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1338
1339             free_mesh(&mesh);
1340         }
1341
1342         d3dxmesh->lpVtbl->Release(d3dxmesh);
1343     }
1344
1345     IDirect3DDevice9_Release(device);
1346     IDirect3D9_Release(d3d);
1347     DestroyWindow(wnd);
1348 }
1349
1350 static void D3DXCreateBoxTest(void)
1351 {
1352     HRESULT hr;
1353     HWND wnd;
1354     WNDCLASS wc={0};
1355     IDirect3D9* d3d;
1356     IDirect3DDevice9* device;
1357     D3DPRESENT_PARAMETERS d3dpp;
1358     ID3DXMesh* box;
1359     ID3DXBuffer* ppBuffer;
1360
1361     wc.lpfnWndProc = DefWindowProcA;
1362     wc.lpszClassName = "d3dx9_test_wc";
1363     if (!RegisterClass(&wc))
1364     {
1365         skip("RegisterClass failed\n");
1366         return;
1367     }
1368
1369     wnd = CreateWindow("d3dx9_test_wc", "d3dx9_test",
1370                         WS_SYSMENU | WS_POPUP , 0, 0, 640, 480, 0, 0, 0, 0);
1371     ok(wnd != NULL, "Expected to have a window, received NULL");
1372     if (!wnd)
1373     {
1374         skip("Couldn't create application window\n");
1375         return;
1376     }
1377
1378     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1379     if (!d3d)
1380     {
1381         skip("Couldn't create IDirect3D9 object\n");
1382         DestroyWindow(wnd);
1383         return;
1384     }
1385
1386     memset(&d3dpp, 0, sizeof(d3dpp));
1387     d3dpp.Windowed = TRUE;
1388     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1389     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1390     if (FAILED(hr))
1391     {
1392         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1393         IDirect3D9_Release(d3d);
1394         DestroyWindow(wnd);
1395         return;
1396     }
1397
1398     hr = D3DXCreateBuffer(36 * sizeof(DWORD), &ppBuffer);
1399     ok(hr==D3D_OK, "Expected D3D_OK, received %#x", hr);
1400     if (FAILED(hr)) goto end;
1401
1402     hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
1403     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x", hr);
1404
1405     hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
1406     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x", hr);
1407
1408     hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
1409     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x", hr);
1410
1411     hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
1412     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x", hr);
1413
1414     hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
1415     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x", hr);
1416
1417 end:
1418     IDirect3DDevice9_Release(device);
1419     IDirect3D9_Release(d3d);
1420     DestroyWindow(wnd);
1421 }
1422
1423 struct sincos_table
1424 {
1425     float *sin;
1426     float *cos;
1427 };
1428
1429 static void free_sincos_table(struct sincos_table *sincos_table)
1430 {
1431     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
1432     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1433 }
1434
1435 /* pre compute sine and cosine tables; caller must free */
1436 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
1437 {
1438     float angle;
1439     int i;
1440
1441     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
1442     if (!sincos_table->sin)
1443     {
1444         return FALSE;
1445     }
1446     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
1447     if (!sincos_table->cos)
1448     {
1449         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1450         return FALSE;
1451     }
1452
1453     angle = angle_start;
1454     for (i = 0; i < n; i++)
1455     {
1456         sincos_table->sin[i] = sin(angle);
1457         sincos_table->cos[i] = cos(angle);
1458         angle += angle_step;
1459     }
1460
1461     return TRUE;
1462 }
1463
1464 static WORD vertex_index(UINT slices, int slice, int stack)
1465 {
1466     return stack*slices+slice+1;
1467 }
1468
1469 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
1470 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
1471 {
1472     float theta_step, theta_start;
1473     struct sincos_table theta;
1474     float phi_step, phi_start;
1475     struct sincos_table phi;
1476     DWORD number_of_vertices, number_of_faces;
1477     DWORD vertex, face;
1478     int slice, stack;
1479
1480     /* theta = angle on xy plane wrt x axis */
1481     theta_step = M_PI / stacks;
1482     theta_start = theta_step;
1483
1484     /* phi = angle on xz plane wrt z axis */
1485     phi_step = -2 * M_PI / slices;
1486     phi_start = M_PI / 2;
1487
1488     if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
1489     {
1490         return FALSE;
1491     }
1492     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
1493     {
1494         free_sincos_table(&theta);
1495         return FALSE;
1496     }
1497
1498     number_of_vertices = 2 + slices * (stacks-1);
1499     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
1500
1501     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
1502     {
1503         free_sincos_table(&phi);
1504         free_sincos_table(&theta);
1505         return FALSE;
1506     }
1507
1508     vertex = 0;
1509     face = 0;
1510
1511     mesh->vertices[vertex].normal.x = 0.0f;
1512     mesh->vertices[vertex].normal.y = 0.0f;
1513     mesh->vertices[vertex].normal.z = 1.0f;
1514     mesh->vertices[vertex].position.x = 0.0f;
1515     mesh->vertices[vertex].position.y = 0.0f;
1516     mesh->vertices[vertex].position.z = radius;
1517     vertex++;
1518
1519     for (stack = 0; stack < stacks - 1; stack++)
1520     {
1521         for (slice = 0; slice < slices; slice++)
1522         {
1523             mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
1524             mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
1525             mesh->vertices[vertex].normal.z = theta.cos[stack];
1526             mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
1527             mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
1528             mesh->vertices[vertex].position.z = radius * theta.cos[stack];
1529             vertex++;
1530
1531             if (slice > 0)
1532             {
1533                 if (stack == 0)
1534                 {
1535                     /* top stack is triangle fan */
1536                     mesh->faces[face][0] = 0;
1537                     mesh->faces[face][1] = slice + 1;
1538                     mesh->faces[face][2] = slice;
1539                     face++;
1540                 }
1541                 else
1542                 {
1543                     /* stacks in between top and bottom are quad strips */
1544                     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1545                     mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
1546                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
1547                     face++;
1548
1549                     mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
1550                     mesh->faces[face][1] = vertex_index(slices, slice, stack);
1551                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
1552                     face++;
1553                 }
1554             }
1555         }
1556
1557         if (stack == 0)
1558         {
1559             mesh->faces[face][0] = 0;
1560             mesh->faces[face][1] = 1;
1561             mesh->faces[face][2] = slice;
1562             face++;
1563         }
1564         else
1565         {
1566             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1567             mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
1568             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
1569             face++;
1570
1571             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
1572             mesh->faces[face][1] = vertex_index(slices, 0, stack);
1573             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
1574             face++;
1575         }
1576     }
1577
1578     mesh->vertices[vertex].position.x = 0.0f;
1579     mesh->vertices[vertex].position.y = 0.0f;
1580     mesh->vertices[vertex].position.z = -radius;
1581     mesh->vertices[vertex].normal.x = 0.0f;
1582     mesh->vertices[vertex].normal.y = 0.0f;
1583     mesh->vertices[vertex].normal.z = -1.0f;
1584
1585     /* bottom stack is triangle fan */
1586     for (slice = 1; slice < slices; slice++)
1587     {
1588         mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1589         mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
1590         mesh->faces[face][2] = vertex;
1591         face++;
1592     }
1593
1594     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1595     mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
1596     mesh->faces[face][2] = vertex;
1597
1598     free_sincos_table(&phi);
1599     free_sincos_table(&theta);
1600
1601     return TRUE;
1602 }
1603
1604 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
1605 {
1606     HRESULT hr;
1607     ID3DXMesh *sphere;
1608     struct mesh mesh;
1609     char name[256];
1610
1611     hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
1612     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1613     if (hr != D3D_OK)
1614     {
1615         skip("Couldn't create sphere\n");
1616         return;
1617     }
1618
1619     if (!compute_sphere(&mesh, radius, slices, stacks))
1620     {
1621         skip("Couldn't create mesh\n");
1622         sphere->lpVtbl->Release(sphere);
1623         return;
1624     }
1625
1626     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1627
1628     sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
1629     compare_mesh(name, sphere, &mesh);
1630
1631     free_mesh(&mesh);
1632
1633     sphere->lpVtbl->Release(sphere);
1634 }
1635
1636 static void D3DXCreateSphereTest(void)
1637 {
1638     HRESULT hr;
1639     HWND wnd;
1640     IDirect3D9* d3d;
1641     IDirect3DDevice9* device;
1642     D3DPRESENT_PARAMETERS d3dpp;
1643     ID3DXMesh* sphere = NULL;
1644
1645     hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
1646     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1647
1648     hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
1649     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1650
1651     hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
1652     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1653
1654     hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
1655     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1656
1657     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1658     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1659     if (!wnd)
1660     {
1661         skip("Couldn't create application window\n");
1662         return;
1663     }
1664     if (!d3d)
1665     {
1666         skip("Couldn't create IDirect3D9 object\n");
1667         DestroyWindow(wnd);
1668         return;
1669     }
1670
1671     ZeroMemory(&d3dpp, sizeof(d3dpp));
1672     d3dpp.Windowed = TRUE;
1673     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1674     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1675     if (FAILED(hr))
1676     {
1677         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1678         IDirect3D9_Release(d3d);
1679         DestroyWindow(wnd);
1680         return;
1681     }
1682
1683     hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
1684     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1685
1686     hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
1687     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1688
1689     hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
1690     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1691
1692     hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
1693     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1694
1695     test_sphere(device, 0.0f, 2, 2);
1696     test_sphere(device, 1.0f, 2, 2);
1697     test_sphere(device, 1.0f, 3, 2);
1698     test_sphere(device, 1.0f, 4, 4);
1699     test_sphere(device, 1.0f, 3, 4);
1700     test_sphere(device, 5.0f, 6, 7);
1701     test_sphere(device, 10.0f, 11, 12);
1702
1703     IDirect3DDevice9_Release(device);
1704     IDirect3D9_Release(d3d);
1705     DestroyWindow(wnd);
1706 }
1707
1708 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
1709 {
1710     float theta_step, theta_start;
1711     struct sincos_table theta;
1712     FLOAT delta_radius, radius, radius_step;
1713     FLOAT z, z_step, z_normal;
1714     DWORD number_of_vertices, number_of_faces;
1715     DWORD vertex, face;
1716     int slice, stack;
1717
1718     /* theta = angle on xy plane wrt x axis */
1719     theta_step = -2 * M_PI / slices;
1720     theta_start = M_PI / 2;
1721
1722     if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
1723     {
1724         return FALSE;
1725     }
1726
1727     number_of_vertices = 2 + (slices * (3 + stacks));
1728     number_of_faces = 2 * slices + stacks * (2 * slices);
1729
1730     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
1731     {
1732         free_sincos_table(&theta);
1733         return FALSE;
1734     }
1735
1736     vertex = 0;
1737     face = 0;
1738
1739     delta_radius = radius1 - radius2;
1740     radius = radius1;
1741     radius_step = delta_radius / stacks;
1742
1743     z = -length / 2;
1744     z_step = length / stacks;
1745     z_normal = delta_radius / length;
1746     if (isnan(z_normal))
1747     {
1748         z_normal = 0.0f;
1749     }
1750
1751     mesh->vertices[vertex].normal.x = 0.0f;
1752     mesh->vertices[vertex].normal.y = 0.0f;
1753     mesh->vertices[vertex].normal.z = -1.0f;
1754     mesh->vertices[vertex].position.x = 0.0f;
1755     mesh->vertices[vertex].position.y = 0.0f;
1756     mesh->vertices[vertex++].position.z = z;
1757
1758     for (slice = 0; slice < slices; slice++, vertex++)
1759     {
1760         mesh->vertices[vertex].normal.x = 0.0f;
1761         mesh->vertices[vertex].normal.y = 0.0f;
1762         mesh->vertices[vertex].normal.z = -1.0f;
1763         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
1764         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
1765         mesh->vertices[vertex].position.z = z;
1766
1767         if (slice > 0)
1768         {
1769             mesh->faces[face][0] = 0;
1770             mesh->faces[face][1] = slice;
1771             mesh->faces[face++][2] = slice + 1;
1772         }
1773     }
1774
1775     mesh->faces[face][0] = 0;
1776     mesh->faces[face][1] = slice;
1777     mesh->faces[face++][2] = 1;
1778
1779     for (stack = 1; stack <= stacks+1; stack++)
1780     {
1781         for (slice = 0; slice < slices; slice++, vertex++)
1782         {
1783             mesh->vertices[vertex].normal.x = theta.cos[slice];
1784             mesh->vertices[vertex].normal.y = theta.sin[slice];
1785             mesh->vertices[vertex].normal.z = z_normal;
1786             D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
1787             mesh->vertices[vertex].position.x = radius * theta.cos[slice];
1788             mesh->vertices[vertex].position.y = radius * theta.sin[slice];
1789             mesh->vertices[vertex].position.z = z;
1790
1791             if (stack > 1 && slice > 0)
1792             {
1793                 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1794                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
1795                 mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
1796
1797                 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
1798                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
1799                 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
1800             }
1801         }
1802
1803         if (stack > 1)
1804         {
1805             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1806             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
1807             mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
1808
1809             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
1810             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
1811             mesh->faces[face++][2] = vertex_index(slices, 0, stack);
1812         }
1813
1814         if (stack < stacks + 1)
1815         {
1816             z += z_step;
1817             radius -= radius_step;
1818         }
1819     }
1820
1821     for (slice = 0; slice < slices; slice++, vertex++)
1822     {
1823         mesh->vertices[vertex].normal.x = 0.0f;
1824         mesh->vertices[vertex].normal.y = 0.0f;
1825         mesh->vertices[vertex].normal.z = 1.0f;
1826         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
1827         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
1828         mesh->vertices[vertex].position.z = z;
1829
1830         if (slice > 0)
1831         {
1832             mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
1833             mesh->faces[face][1] = number_of_vertices - 1;
1834             mesh->faces[face++][2] = vertex_index(slices, slice, stack);
1835         }
1836     }
1837
1838     mesh->vertices[vertex].position.x = 0.0f;
1839     mesh->vertices[vertex].position.y = 0.0f;
1840     mesh->vertices[vertex].position.z = z;
1841     mesh->vertices[vertex].normal.x = 0.0f;
1842     mesh->vertices[vertex].normal.y = 0.0f;
1843     mesh->vertices[vertex].normal.z = 1.0f;
1844
1845     mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
1846     mesh->faces[face][1] = number_of_vertices - 1;
1847     mesh->faces[face][2] = vertex_index(slices, 0, stack);
1848
1849     free_sincos_table(&theta);
1850
1851     return TRUE;
1852 }
1853
1854 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
1855 {
1856     HRESULT hr;
1857     ID3DXMesh *cylinder;
1858     struct mesh mesh;
1859     char name[256];
1860
1861     hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
1862     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1863     if (hr != D3D_OK)
1864     {
1865         skip("Couldn't create cylinder\n");
1866         return;
1867     }
1868
1869     if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
1870     {
1871         skip("Couldn't create mesh\n");
1872         cylinder->lpVtbl->Release(cylinder);
1873         return;
1874     }
1875
1876     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1877
1878     sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
1879     compare_mesh(name, cylinder, &mesh);
1880
1881     free_mesh(&mesh);
1882
1883     cylinder->lpVtbl->Release(cylinder);
1884 }
1885
1886 static void D3DXCreateCylinderTest(void)
1887 {
1888     HRESULT hr;
1889     HWND wnd;
1890     IDirect3D9* d3d;
1891     IDirect3DDevice9* device;
1892     D3DPRESENT_PARAMETERS d3dpp;
1893     ID3DXMesh* cylinder = NULL;
1894
1895     hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
1896     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1897
1898     hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
1899     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1900
1901     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1902     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1903     if (!wnd)
1904     {
1905         skip("Couldn't create application window\n");
1906         return;
1907     }
1908     if (!d3d)
1909     {
1910         skip("Couldn't create IDirect3D9 object\n");
1911         DestroyWindow(wnd);
1912         return;
1913     }
1914
1915     ZeroMemory(&d3dpp, sizeof(d3dpp));
1916     d3dpp.Windowed = TRUE;
1917     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1918     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1919     if (FAILED(hr))
1920     {
1921         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1922         IDirect3D9_Release(d3d);
1923         DestroyWindow(wnd);
1924         return;
1925     }
1926
1927     hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
1928     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1929
1930     hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
1931     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
1932
1933     if (SUCCEEDED(hr) && cylinder)
1934     {
1935         cylinder->lpVtbl->Release(cylinder);
1936     }
1937
1938     hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
1939     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1940
1941     hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
1942     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
1943
1944     if (SUCCEEDED(hr) && cylinder)
1945     {
1946         cylinder->lpVtbl->Release(cylinder);
1947     }
1948
1949     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
1950     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1951
1952     /* Test with length == 0.0f succeeds */
1953     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
1954     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
1955
1956     if (SUCCEEDED(hr) && cylinder)
1957     {
1958         cylinder->lpVtbl->Release(cylinder);
1959     }
1960
1961     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
1962     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1963
1964     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
1965     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1966
1967     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
1968     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1969
1970     test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
1971     test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
1972     test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
1973     test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
1974     test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
1975     test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
1976
1977     IDirect3DDevice9_Release(device);
1978     IDirect3D9_Release(d3d);
1979     DestroyWindow(wnd);
1980 }
1981
1982 static void test_get_decl_length(void)
1983 {
1984     static const D3DVERTEXELEMENT9 declaration1[] =
1985     {
1986         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1987         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1988         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1989         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1990         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1991         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1992         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1993         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1994         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1995         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1996         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1997         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1998         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1999         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2000         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2001         D3DDECL_END(),
2002     };
2003     static const D3DVERTEXELEMENT9 declaration2[] =
2004     {
2005         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2006         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2007         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2008         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2009         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2010         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2011         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2012         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2013         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2014         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2015         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2016         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2017         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2018         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2019         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2020         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2021         D3DDECL_END(),
2022     };
2023     UINT size;
2024
2025     size = D3DXGetDeclLength(declaration1);
2026     ok(size == 15, "Got size %u, expected 15.\n", size);
2027
2028     size = D3DXGetDeclLength(declaration2);
2029     ok(size == 16, "Got size %u, expected 16.\n", size);
2030 }
2031
2032 static void test_get_decl_vertex_size(void)
2033 {
2034     static const D3DVERTEXELEMENT9 declaration1[] =
2035     {
2036         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2037         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2038         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2039         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2040         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2041         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2042         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2043         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2044         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2045         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2046         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2047         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2048         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2049         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2050         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2051         D3DDECL_END(),
2052     };
2053     static const D3DVERTEXELEMENT9 declaration2[] =
2054     {
2055         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2056         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2057         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2058         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2059         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2060         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2061         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2062         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2063         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2064         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2065         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2066         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2067         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2068         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2069         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2070         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
2071         D3DDECL_END(),
2072     };
2073     static const UINT sizes1[] =
2074     {
2075         4,  8,  12, 16,
2076         4,  4,  4,  8,
2077         4,  4,  8,  4,
2078         4,  4,  8,  0,
2079     };
2080     static const UINT sizes2[] =
2081     {
2082         12, 16, 20, 24,
2083         12, 12, 16, 16,
2084     };
2085     unsigned int i;
2086     UINT size;
2087
2088     size = D3DXGetDeclVertexSize(NULL, 0);
2089     ok(size == 0, "Got size %#x, expected 0.\n", size);
2090
2091     for (i = 0; i < 16; ++i)
2092     {
2093         size = D3DXGetDeclVertexSize(declaration1, i);
2094         ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
2095     }
2096
2097     for (i = 0; i < 8; ++i)
2098     {
2099         size = D3DXGetDeclVertexSize(declaration2, i);
2100         ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
2101     }
2102 }
2103
2104 START_TEST(mesh)
2105 {
2106     D3DXBoundProbeTest();
2107     D3DXComputeBoundingBoxTest();
2108     D3DXComputeBoundingSphereTest();
2109     D3DXGetFVFVertexSizeTest();
2110     D3DXIntersectTriTest();
2111     D3DXCreateMeshTest();
2112     D3DXCreateMeshFVFTest();
2113     D3DXCreateBoxTest();
2114     D3DXCreateSphereTest();
2115     D3DXCreateCylinderTest();
2116     test_get_decl_length();
2117     test_get_decl_vertex_size();
2118     test_fvf_decl_conversion();
2119 }