d3dx9: Fix D3DXAssembleShader tests.
[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
63 static void free_mesh(struct mesh *mesh)
64 {
65     HeapFree(GetProcessHeap(), 0, mesh->faces);
66     HeapFree(GetProcessHeap(), 0, mesh->vertices);
67 }
68
69 static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
70 {
71     mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
72     if (!mesh->vertices)
73     {
74         return FALSE;
75     }
76     mesh->number_of_vertices = number_of_vertices;
77
78     mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
79     if (!mesh->faces)
80     {
81         HeapFree(GetProcessHeap(), 0, mesh->vertices);
82         return FALSE;
83     }
84     mesh->number_of_faces = number_of_faces;
85
86     return TRUE;
87 }
88
89 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
90 {
91     HRESULT hr;
92     DWORD number_of_vertices, number_of_faces;
93     IDirect3DVertexBuffer9 *vertex_buffer;
94     IDirect3DIndexBuffer9 *index_buffer;
95     D3DVERTEXBUFFER_DESC vertex_buffer_description;
96     D3DINDEXBUFFER_DESC index_buffer_description;
97     struct vertex *vertices;
98     face *faces;
99     int expected, i;
100
101     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
102     ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
103        name, number_of_vertices, mesh->number_of_vertices);
104
105     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
106     ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
107        name, number_of_faces, mesh->number_of_faces);
108
109     /* vertex buffer */
110     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
111     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
112
113     if (hr != D3D_OK)
114     {
115         skip("Couldn't get vertex buffer\n");
116     }
117     else
118     {
119         hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
120         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
121
122         if (hr != D3D_OK)
123         {
124             skip("Couldn't get vertex buffer description\n");
125         }
126         else
127         {
128             ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
129                name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
130             ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
131                name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
132             ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
133             ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_DEFAULT)\n",
134                name, vertex_buffer_description.Pool, D3DPOOL_DEFAULT);
135             expected = number_of_vertices * sizeof(D3DXVECTOR3) * 2;
136             ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
137                name, vertex_buffer_description.Size, expected);
138             ok(vertex_buffer_description.FVF == (D3DFVF_XYZ | D3DFVF_NORMAL), "Test %s, result %x, expected %x (D3DFVF_XYZ | D3DFVF_NORMAL)\n",
139                name, vertex_buffer_description.FVF, D3DFVF_XYZ | D3DFVF_NORMAL);
140         }
141
142         /* specify offset and size to avoid potential overruns */
143         hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
144                                          (LPVOID *)&vertices, D3DLOCK_DISCARD);
145         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
146
147         if (hr != D3D_OK)
148         {
149             skip("Couldn't lock vertex buffer\n");
150         }
151         else
152         {
153             for (i = 0; i < number_of_vertices; i++)
154             {
155                 ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
156                    "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
157                    vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
158                    mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
159                 ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
160                    "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
161                    vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
162                    mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
163             }
164
165             IDirect3DVertexBuffer9_Unlock(vertex_buffer);
166         }
167
168         IDirect3DVertexBuffer9_Release(vertex_buffer);
169     }
170
171     /* index buffer */
172     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
173     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
174
175     if (!index_buffer)
176     {
177         skip("Couldn't get index buffer\n");
178     }
179     else
180     {
181         hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
182         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
183
184         if (hr != D3D_OK)
185         {
186             skip("Couldn't get index buffer description\n");
187         }
188         else
189         {
190             ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
191                name, index_buffer_description.Format, D3DFMT_INDEX16);
192             ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
193                name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
194             ok(index_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, index_buffer_description.Usage, 0);
195             ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_DEFAULT)\n",
196                name, index_buffer_description.Pool, D3DPOOL_DEFAULT);
197             expected = number_of_faces * sizeof(WORD) * 3;
198             ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
199                name, index_buffer_description.Size, expected);
200         }
201
202         /* specify offset and size to avoid potential overruns */
203         hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
204                                         (LPVOID *)&faces, D3DLOCK_DISCARD);
205         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
206
207         if (hr != D3D_OK)
208         {
209             skip("Couldn't lock index buffer\n");
210         }
211         else
212         {
213             for (i = 0; i < number_of_faces; i++)
214             {
215                 ok(compare_face(faces[i], mesh->faces[i]),
216                    "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
217                    faces[i][0], faces[i][1], faces[i][2],
218                    mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
219             }
220
221             IDirect3DIndexBuffer9_Unlock(index_buffer);
222         }
223
224         IDirect3DIndexBuffer9_Release(index_buffer);
225     }
226 }
227
228 static void D3DXBoundProbeTest(void)
229 {
230     BOOL result;
231     D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
232     FLOAT radius;
233
234 /*____________Test the Box case___________________________*/
235     bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
236     top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
237
238     raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
239     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
240     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
241     ok(result == TRUE, "expected TRUE, received FALSE\n");
242
243     raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
244     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
245     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
246     ok(result == FALSE, "expected FALSE, received TRUE\n");
247
248     rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
249     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
250     ok(result == TRUE, "expected TRUE, received FALSE\n");
251
252     bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
253     top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
254     rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
255     raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
256     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
257     ok(result == FALSE, "expected FALSE, received TRUE\n");
258
259     bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
260     top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
261
262     raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
263     rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
264     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
265     ok(result == TRUE, "expected TRUE, received FALSE\n");
266
267     bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
268     top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
269
270     raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
271     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
272     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
273     ok(result == FALSE, "expected FALSE, received TRUE\n");
274
275     raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
276     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
277     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
278     ok(result == TRUE, "expected TRUE, received FALSE\n");
279
280 /*____________Test the Sphere case________________________*/
281     radius = sqrt(77.0f);
282     center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
283     raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
284
285     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
286     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
287     ok(result == TRUE, "expected TRUE, received FALSE\n");
288
289     rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
290     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
291     ok(result == FALSE, "expected FALSE, received TRUE\n");
292
293     rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
294     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
295     ok(result == FALSE, "expected FALSE, received TRUE\n");
296 }
297
298 static void D3DXComputeBoundingBoxTest(void)
299 {
300     D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
301     HRESULT hr;
302
303     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
304     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
305     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
306     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
307     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
308
309     exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
310     exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
311
312     hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
313
314     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
315     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);
316     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);
317
318 /*________________________*/
319
320     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
321     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
322     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
323     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
324     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
325
326     exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
327     exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
328
329     hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
330
331     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
332     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);
333     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);
334
335 /*________________________*/
336
337     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
338     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
339     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
340     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
341     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
342
343     exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
344     exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
345
346     hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
347
348     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
349     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);
350     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);
351
352 /*________________________*/
353     hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
354     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
355
356 /*________________________*/
357     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
358     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
359
360 /*________________________*/
361     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
362     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
363 }
364
365 static void D3DXComputeBoundingSphereTest(void)
366 {
367     D3DXVECTOR3 exp_cen, got_cen, vertex[5];
368     FLOAT exp_rad, got_rad;
369     HRESULT hr;
370
371     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
372     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
373     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
374     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
375     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
376
377     exp_rad = 6.928203f;
378     exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
379
380     hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
381
382     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
383     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
384     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);
385
386 /*________________________*/
387
388     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
389     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
390     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
391     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
392     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
393
394     exp_rad = 13.707883f;
395     exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
396
397     hr = D3DXComputeBoundingSphere(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
398
399     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
400     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
401     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);
402
403 /*________________________*/
404     hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
405     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
406
407 /*________________________*/
408     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
409     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
410
411 /*________________________*/
412     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
413     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
414 }
415
416 static void print_elements(const D3DVERTEXELEMENT9 *elements)
417 {
418     D3DVERTEXELEMENT9 last = D3DDECL_END();
419     const D3DVERTEXELEMENT9 *ptr = elements;
420     int count = 0;
421
422     while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
423     {
424         trace(
425             "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
426              count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
427         ptr++;
428         count++;
429     }
430 }
431
432 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
433         unsigned int line, unsigned int test_id)
434 {
435     D3DVERTEXELEMENT9 last = D3DDECL_END();
436     unsigned int i;
437
438     for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
439     {
440         int end1 = memcmp(&elements[i], &last, sizeof(last));
441         int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
442         int status;
443
444         if (!end1 && !end2) break;
445
446         status = !end1 ^ !end2;
447         ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
448                 line, test_id, end1 ? "shorter" : "longer");
449         if (status)
450         {
451             print_elements(elements);
452             break;
453         }
454
455         status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
456         ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
457         if (status)
458         {
459             print_elements(elements);
460             break;
461         }
462     }
463 }
464
465 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
466         HRESULT expected_hr, unsigned int line, unsigned int test_id)
467 {
468     HRESULT hr;
469     D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
470
471     hr = D3DXDeclaratorFromFVF(test_fvf, decl);
472     ok(hr == expected_hr,
473             "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
474             line, test_id, hr, expected_hr);
475     if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
476 }
477
478 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
479         HRESULT expected_hr, unsigned int line, unsigned int test_id)
480 {
481     HRESULT hr;
482     DWORD result_fvf = 0xdeadbeef;
483
484     hr = D3DXFVFFromDeclarator(decl, &result_fvf);
485     ok(hr == expected_hr,
486        "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
487        line, test_id, hr, expected_hr);
488     if (SUCCEEDED(hr))
489     {
490         ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
491                 line, test_id, result_fvf, expected_fvf);
492     }
493 }
494
495 static void test_fvf_decl_conversion(void)
496 {
497     static const struct
498     {
499         D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
500         DWORD fvf;
501     }
502     test_data[] =
503     {
504         {{
505             D3DDECL_END(),
506         }, 0},
507         {{
508             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
509             D3DDECL_END(),
510         }, D3DFVF_XYZ},
511         {{
512             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
513             D3DDECL_END(),
514         }, D3DFVF_XYZRHW},
515         {{
516             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
517             D3DDECL_END(),
518         }, D3DFVF_XYZRHW},
519         {{
520             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
521             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
522             D3DDECL_END(),
523         }, D3DFVF_XYZB1},
524         {{
525             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
526             {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
527             D3DDECL_END(),
528         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
529         {{
530             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
531             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
532             D3DDECL_END(),
533         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
534         {{
535             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
536             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
537             D3DDECL_END(),
538         }, D3DFVF_XYZB2},
539         {{
540             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
541             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
542             {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
543             D3DDECL_END(),
544         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
545         {{
546             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
547             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
548             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
549             D3DDECL_END(),
550         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
551         {{
552             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
553             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
554             D3DDECL_END(),
555         }, D3DFVF_XYZB3},
556         {{
557             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
558             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
559             {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
560             D3DDECL_END(),
561         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
562         {{
563             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
564             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
565             {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
566             D3DDECL_END(),
567         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
568         {{
569             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
570             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
571             D3DDECL_END(),
572         }, D3DFVF_XYZB4},
573         {{
574             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
575             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
576             {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
577             D3DDECL_END(),
578         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
579         {{
580             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
581             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
582             {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
583             D3DDECL_END(),
584         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
585         {{
586             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
587             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
588             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
589             D3DDECL_END(),
590         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
591         {{
592             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
593             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
594             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
595             D3DDECL_END(),
596         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
597         {{
598             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
599             D3DDECL_END(),
600         }, D3DFVF_NORMAL},
601         {{
602             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
603             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
604             D3DDECL_END(),
605         }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
606         {{
607             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
608             D3DDECL_END(),
609         }, D3DFVF_PSIZE},
610         {{
611             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
612             D3DDECL_END(),
613         }, D3DFVF_DIFFUSE},
614         {{
615             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
616             D3DDECL_END(),
617         }, D3DFVF_SPECULAR},
618         /* Make sure textures of different sizes work. */
619         {{
620             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
621             D3DDECL_END(),
622         }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
623         {{
624             {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
625             D3DDECL_END(),
626         }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
627         {{
628             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
629             D3DDECL_END(),
630         }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
631         {{
632             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
633             D3DDECL_END(),
634         }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
635         /* Make sure the TEXCOORD index works correctly - try several textures. */
636         {{
637             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
638             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
639             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
640             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
641             D3DDECL_END(),
642         }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
643                 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
644         /* Now try some combination tests. */
645         {{
646             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
647             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
648             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
649             {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
650             {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
651             {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
652             D3DDECL_END(),
653         }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
654                 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
655         {{
656             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
657             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
658             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
659             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
660             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
661             {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
662             D3DDECL_END(),
663         }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
664                 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
665     };
666     unsigned int i;
667
668     for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
669     {
670         test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
671         test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
672     }
673
674     /* Usage indices for position and normal are apparently ignored. */
675     {
676         const D3DVERTEXELEMENT9 decl[] =
677         {
678             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
679             D3DDECL_END(),
680         };
681         test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
682     }
683     {
684         const D3DVERTEXELEMENT9 decl[] =
685         {
686             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
687             D3DDECL_END(),
688         };
689         test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
690     }
691     /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
692      * there are no blend matrices. */
693     {
694         const D3DVERTEXELEMENT9 decl[] =
695         {
696             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
697             D3DDECL_END(),
698         };
699         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
700     }
701     {
702         const D3DVERTEXELEMENT9 decl[] =
703         {
704             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
705             D3DDECL_END(),
706         };
707         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
708     }
709     /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
710     {
711         const D3DVERTEXELEMENT9 decl[] =
712         {
713             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
714             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
715             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
716             D3DDECL_END(),
717         };
718         test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
719                 decl, D3D_OK, __LINE__, 0);
720     }
721     /* These are supposed to fail, both ways. */
722     {
723         const D3DVERTEXELEMENT9 decl[] =
724         {
725             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
726             D3DDECL_END(),
727         };
728         test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
729         test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
730     }
731     {
732         const D3DVERTEXELEMENT9 decl[] =
733         {
734             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
735             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
736             D3DDECL_END(),
737         };
738         test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
739         test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
740     }
741     {
742         const D3DVERTEXELEMENT9 decl[] =
743         {
744             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
745             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
746             {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
747             D3DDECL_END(),
748         };
749         test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
750         test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
751     }
752     /* Test a declaration that can't be converted to an FVF. */
753     {
754         const D3DVERTEXELEMENT9 decl[] =
755         {
756             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
757             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
758             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
759             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
760             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
761             /* 8 bytes padding */
762             {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
763             D3DDECL_END(),
764         };
765         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
766     }
767     /* Elements must be ordered by offset. */
768     {
769         const D3DVERTEXELEMENT9 decl[] =
770         {
771             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
772             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
773             D3DDECL_END(),
774         };
775         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
776     }
777     /* Basic tests for element order. */
778     {
779         const D3DVERTEXELEMENT9 decl[] =
780         {
781             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
782             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
783             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
784             D3DDECL_END(),
785         };
786         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
787     }
788     {
789         const D3DVERTEXELEMENT9 decl[] =
790         {
791             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
792             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
793             D3DDECL_END(),
794         };
795         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
796     }
797     {
798         const D3DVERTEXELEMENT9 decl[] =
799         {
800             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
801             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
802             D3DDECL_END(),
803         };
804         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
805     }
806     /* Textures must be ordered by texcoords. */
807     {
808         const D3DVERTEXELEMENT9 decl[] =
809         {
810             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
811             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
812             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
813             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
814             D3DDECL_END(),
815         };
816         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
817     }
818     /* Duplicate elements are not allowed. */
819     {
820         const D3DVERTEXELEMENT9 decl[] =
821         {
822             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
823             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
824             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
825             D3DDECL_END(),
826         };
827         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
828     }
829 }
830
831 static void D3DXGetFVFVertexSizeTest(void)
832 {
833     UINT got;
834
835     compare_vertex_sizes (D3DFVF_XYZ, 12);
836
837     compare_vertex_sizes (D3DFVF_XYZB3, 24);
838
839     compare_vertex_sizes (D3DFVF_XYZB5, 32);
840
841     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
842
843     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
844
845     compare_vertex_sizes (
846         D3DFVF_XYZ |
847         D3DFVF_TEX1 |
848         D3DFVF_TEXCOORDSIZE1(0), 16);
849     compare_vertex_sizes (
850         D3DFVF_XYZ |
851         D3DFVF_TEX2 |
852         D3DFVF_TEXCOORDSIZE1(0) |
853         D3DFVF_TEXCOORDSIZE1(1), 20);
854
855     compare_vertex_sizes (
856         D3DFVF_XYZ |
857         D3DFVF_TEX1 |
858         D3DFVF_TEXCOORDSIZE2(0), 20);
859
860     compare_vertex_sizes (
861         D3DFVF_XYZ |
862         D3DFVF_TEX2 |
863         D3DFVF_TEXCOORDSIZE2(0) |
864         D3DFVF_TEXCOORDSIZE2(1), 28);
865
866     compare_vertex_sizes (
867         D3DFVF_XYZ |
868         D3DFVF_TEX6 |
869         D3DFVF_TEXCOORDSIZE2(0) |
870         D3DFVF_TEXCOORDSIZE2(1) |
871         D3DFVF_TEXCOORDSIZE2(2) |
872         D3DFVF_TEXCOORDSIZE2(3) |
873         D3DFVF_TEXCOORDSIZE2(4) |
874         D3DFVF_TEXCOORDSIZE2(5), 60);
875
876     compare_vertex_sizes (
877         D3DFVF_XYZ |
878         D3DFVF_TEX8 |
879         D3DFVF_TEXCOORDSIZE2(0) |
880         D3DFVF_TEXCOORDSIZE2(1) |
881         D3DFVF_TEXCOORDSIZE2(2) |
882         D3DFVF_TEXCOORDSIZE2(3) |
883         D3DFVF_TEXCOORDSIZE2(4) |
884         D3DFVF_TEXCOORDSIZE2(5) |
885         D3DFVF_TEXCOORDSIZE2(6) |
886         D3DFVF_TEXCOORDSIZE2(7), 76);
887
888     compare_vertex_sizes (
889         D3DFVF_XYZ |
890         D3DFVF_TEX1 |
891         D3DFVF_TEXCOORDSIZE3(0), 24);
892
893     compare_vertex_sizes (
894         D3DFVF_XYZ |
895         D3DFVF_TEX4 |
896         D3DFVF_TEXCOORDSIZE3(0) |
897         D3DFVF_TEXCOORDSIZE3(1) |
898         D3DFVF_TEXCOORDSIZE3(2) |
899         D3DFVF_TEXCOORDSIZE3(3), 60);
900
901     compare_vertex_sizes (
902         D3DFVF_XYZ |
903         D3DFVF_TEX1 |
904         D3DFVF_TEXCOORDSIZE4(0), 28);
905
906     compare_vertex_sizes (
907         D3DFVF_XYZ |
908         D3DFVF_TEX2 |
909         D3DFVF_TEXCOORDSIZE4(0) |
910         D3DFVF_TEXCOORDSIZE4(1), 44);
911
912     compare_vertex_sizes (
913         D3DFVF_XYZ |
914         D3DFVF_TEX3 |
915         D3DFVF_TEXCOORDSIZE4(0) |
916         D3DFVF_TEXCOORDSIZE4(1) |
917         D3DFVF_TEXCOORDSIZE4(2), 60);
918
919     compare_vertex_sizes (
920         D3DFVF_XYZB5 |
921         D3DFVF_NORMAL |
922         D3DFVF_DIFFUSE |
923         D3DFVF_SPECULAR |
924         D3DFVF_TEX8 |
925         D3DFVF_TEXCOORDSIZE4(0) |
926         D3DFVF_TEXCOORDSIZE4(1) |
927         D3DFVF_TEXCOORDSIZE4(2) |
928         D3DFVF_TEXCOORDSIZE4(3) |
929         D3DFVF_TEXCOORDSIZE4(4) |
930         D3DFVF_TEXCOORDSIZE4(5) |
931         D3DFVF_TEXCOORDSIZE4(6) |
932         D3DFVF_TEXCOORDSIZE4(7), 180);
933 }
934
935 static void D3DXIntersectTriTest(void)
936 {
937     BOOL exp_res, got_res;
938     D3DXVECTOR3 position, ray, vertex[3];
939     FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
940
941     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
942     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
943     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
944
945     position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
946
947     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
948
949     exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
950
951     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
952     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
953     ok( compare(exp_u,got_u), "Expected u = %f, got %f\n",exp_u,got_u);
954     ok( compare(exp_v,got_v), "Expected v = %f, got %f\n",exp_v,got_v);
955     ok( compare(exp_dist,got_dist), "Expected distance = %f, got %f\n",exp_dist,got_dist);
956
957 /*Only positive ray is taken in account*/
958
959     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
960     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
961     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
962
963     position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
964
965     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
966
967     exp_res = FALSE;
968
969     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
970     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
971
972 /*Intersection between ray and triangle in a same plane is considered as empty*/
973
974     vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
975     vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
976     vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
977
978     position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
979
980     ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
981
982     exp_res = FALSE;
983
984     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
985     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
986 }
987
988 static void D3DXCreateMeshTest(void)
989 {
990     HRESULT hr;
991     HWND wnd;
992     IDirect3D9 *d3d;
993     IDirect3DDevice9 *device, *test_device;
994     D3DPRESENT_PARAMETERS d3dpp;
995     ID3DXMesh *d3dxmesh;
996     int i, size;
997     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
998     DWORD fvf, options;
999     struct mesh mesh;
1000
1001     static const D3DVERTEXELEMENT9 decl[3] = {
1002         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1003         {0, 0xC, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1004         D3DDECL_END(), };
1005
1006     hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1007     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1008
1009     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl, NULL, &d3dxmesh);
1010     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1011
1012     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1013     if (!wnd)
1014     {
1015         skip("Couldn't create application window\n");
1016         return;
1017     }
1018     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1019     if (!d3d)
1020     {
1021         skip("Couldn't create IDirect3D9 object\n");
1022         DestroyWindow(wnd);
1023         return;
1024     }
1025
1026     ZeroMemory(&d3dpp, sizeof(d3dpp));
1027     d3dpp.Windowed = TRUE;
1028     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1029     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1030     if (FAILED(hr))
1031     {
1032         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1033         IDirect3D9_Release(d3d);
1034         DestroyWindow(wnd);
1035         return;
1036     }
1037
1038     hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl, device, &d3dxmesh);
1039     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1040
1041     hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl, device, &d3dxmesh);
1042     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1043
1044     hr = D3DXCreateMesh(1, 3, 0, decl, device, &d3dxmesh);
1045     todo_wine ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1046
1047     if (hr == D3D_OK)
1048     {
1049         d3dxmesh->lpVtbl->Release(d3dxmesh);
1050     }
1051
1052     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1053     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1054
1055     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl, device, NULL);
1056     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1057
1058     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl, device, &d3dxmesh);
1059     todo_wine ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1060
1061     if (hr == D3D_OK)
1062     {
1063         /* device */
1064         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1065         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1066
1067         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1068         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1069         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1070
1071         if (hr == D3D_OK)
1072         {
1073             IDirect3DDevice9_Release(device);
1074         }
1075
1076         /* declaration */
1077         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1078         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1079
1080         if (hr == D3D_OK)
1081         {
1082             size = sizeof(decl) / sizeof(decl[0]);
1083             for (i = 0; i < size - 1; i++)
1084             {
1085                 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1086                 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1087                 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1088                 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1089                 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl[i].UsageIndex);
1090                 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", decl[1].Offset, decl[i].Offset);
1091             }
1092             ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1093         }
1094
1095         /* FVF */
1096         fvf = d3dxmesh->lpVtbl->GetFVF(d3dxmesh);
1097         ok(fvf == (D3DFVF_XYZ | D3DFVF_NORMAL), "Got result %x, expected %x (D3DFVF_XYZ | D3DFVF_NORMAL)\n", fvf, D3DFVF_XYZ | D3DFVF_NORMAL);
1098
1099         /* options */
1100         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1101         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1102
1103         /* rest */
1104         if (!new_mesh(&mesh, 3, 1))
1105         {
1106             skip("Couldn't create mesh\n");
1107         }
1108         else
1109         {
1110             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1111             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1112
1113             compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1114
1115             free_mesh(&mesh);
1116         }
1117
1118         d3dxmesh->lpVtbl->Release(d3dxmesh);
1119     }
1120
1121     IDirect3DDevice9_Release(device);
1122     IDirect3D9_Release(d3d);
1123     DestroyWindow(wnd);
1124 }
1125
1126 struct sincos_table
1127 {
1128     float *sin;
1129     float *cos;
1130 };
1131
1132 static void free_sincos_table(struct sincos_table *sincos_table)
1133 {
1134     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
1135     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1136 }
1137
1138 /* pre compute sine and cosine tables; caller must free */
1139 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
1140 {
1141     float angle;
1142     int i;
1143
1144     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
1145     if (!sincos_table->sin)
1146     {
1147         return FALSE;
1148     }
1149     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
1150     if (!sincos_table->cos)
1151     {
1152         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1153         return FALSE;
1154     }
1155
1156     angle = angle_start;
1157     for (i = 0; i < n; i++)
1158     {
1159         sincos_table->sin[i] = sin(angle);
1160         sincos_table->cos[i] = cos(angle);
1161         angle += angle_step;
1162     }
1163
1164     return TRUE;
1165 }
1166
1167 static WORD sphere_vertex(UINT slices, int slice, int stack)
1168 {
1169     return stack*slices+slice+1;
1170 }
1171
1172 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
1173 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
1174 {
1175     float theta_step, theta_start;
1176     struct sincos_table theta;
1177     float phi_step, phi_start;
1178     struct sincos_table phi;
1179     DWORD number_of_vertices, number_of_faces;
1180     DWORD vertex, face;
1181     int slice, stack;
1182
1183     /* theta = angle on xy plane wrt x axis */
1184     theta_step = M_PI / stacks;
1185     theta_start = theta_step;
1186
1187     /* phi = angle on xz plane wrt z axis */
1188     phi_step = -2 * M_PI / slices;
1189     phi_start = M_PI / 2;
1190
1191     if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
1192     {
1193         return FALSE;
1194     }
1195     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
1196     {
1197         free_sincos_table(&theta);
1198         return FALSE;
1199     }
1200
1201     number_of_vertices = 2 + slices * (stacks-1);
1202     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
1203
1204     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
1205     {
1206         free_sincos_table(&phi);
1207         free_sincos_table(&theta);
1208         return FALSE;
1209     }
1210
1211     vertex = 0;
1212     face = 0;
1213     stack = 0;
1214
1215     mesh->vertices[vertex].normal.x = 0.0f;
1216     mesh->vertices[vertex].normal.y = 0.0f;
1217     mesh->vertices[vertex].normal.z = 1.0f;
1218     mesh->vertices[vertex].position.x = 0.0f;
1219     mesh->vertices[vertex].position.y = 0.0f;
1220     mesh->vertices[vertex].position.z = radius;
1221     vertex++;
1222
1223     for (stack = 0; stack < stacks - 1; stack++)
1224     {
1225         for (slice = 0; slice < slices; slice++)
1226         {
1227             mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
1228             mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
1229             mesh->vertices[vertex].normal.z = theta.cos[stack];
1230             mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
1231             mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
1232             mesh->vertices[vertex].position.z = radius * theta.cos[stack];
1233             vertex++;
1234
1235             if (slice > 0)
1236             {
1237                 if (stack == 0)
1238                 {
1239                     /* top stack is triangle fan */
1240                     mesh->faces[face][0] = 0;
1241                     mesh->faces[face][1] = slice + 1;
1242                     mesh->faces[face][2] = slice;
1243                     face++;
1244                 }
1245                 else
1246                 {
1247                     /* stacks in between top and bottom are quad strips */
1248                     mesh->faces[face][0] = sphere_vertex(slices, slice-1, stack-1);
1249                     mesh->faces[face][1] = sphere_vertex(slices, slice, stack-1);
1250                     mesh->faces[face][2] = sphere_vertex(slices, slice-1, stack);
1251                     face++;
1252
1253                     mesh->faces[face][0] = sphere_vertex(slices, slice, stack-1);
1254                     mesh->faces[face][1] = sphere_vertex(slices, slice, stack);
1255                     mesh->faces[face][2] = sphere_vertex(slices, slice-1, stack);
1256                     face++;
1257                 }
1258             }
1259         }
1260
1261         if (stack == 0)
1262         {
1263             mesh->faces[face][0] = 0;
1264             mesh->faces[face][1] = 1;
1265             mesh->faces[face][2] = slice;
1266             face++;
1267         }
1268         else
1269         {
1270             mesh->faces[face][0] = sphere_vertex(slices, slice-1, stack-1);
1271             mesh->faces[face][1] = sphere_vertex(slices, 0, stack-1);
1272             mesh->faces[face][2] = sphere_vertex(slices, slice-1, stack);
1273             face++;
1274
1275             mesh->faces[face][0] = sphere_vertex(slices, 0, stack-1);
1276             mesh->faces[face][1] = sphere_vertex(slices, 0, stack);
1277             mesh->faces[face][2] = sphere_vertex(slices, slice-1, stack);
1278             face++;
1279         }
1280     }
1281
1282     mesh->vertices[vertex].position.x = 0.0f;
1283     mesh->vertices[vertex].position.y = 0.0f;
1284     mesh->vertices[vertex].position.z = -radius;
1285     mesh->vertices[vertex].normal.x = 0.0f;
1286     mesh->vertices[vertex].normal.y = 0.0f;
1287     mesh->vertices[vertex].normal.z = -1.0f;
1288
1289     /* bottom stack is triangle fan */
1290     for (slice = 1; slice < slices; slice++)
1291     {
1292         mesh->faces[face][0] = sphere_vertex(slices, slice-1, stack-1);
1293         mesh->faces[face][1] = sphere_vertex(slices, slice, stack-1);
1294         mesh->faces[face][2] = vertex;
1295         face++;
1296     }
1297
1298     mesh->faces[face][0] = sphere_vertex(slices, slice-1, stack-1);
1299     mesh->faces[face][1] = sphere_vertex(slices, 0, stack-1);
1300     mesh->faces[face][2] = vertex;
1301
1302     free_sincos_table(&phi);
1303     free_sincos_table(&theta);
1304
1305     return TRUE;
1306 }
1307
1308 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
1309 {
1310     HRESULT hr;
1311     ID3DXMesh *sphere;
1312     struct mesh mesh;
1313     char name[256];
1314
1315     hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
1316     todo_wine ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1317     if (hr != D3D_OK)
1318     {
1319         skip("Couldn't create sphere\n");
1320         return;
1321     }
1322
1323     if (!compute_sphere(&mesh, radius, slices, stacks))
1324     {
1325         skip("Couldn't create mesh\n");
1326         sphere->lpVtbl->Release(sphere);
1327         return;
1328     }
1329
1330     sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
1331     compare_mesh(name, sphere, &mesh);
1332
1333     free_mesh(&mesh);
1334
1335     sphere->lpVtbl->Release(sphere);
1336 }
1337
1338 static void D3DXCreateSphereTest(void)
1339 {
1340     HRESULT hr;
1341     HWND wnd;
1342     IDirect3D9* d3d;
1343     IDirect3DDevice9* device;
1344     D3DPRESENT_PARAMETERS d3dpp;
1345     ID3DXMesh* sphere = NULL;
1346
1347     hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
1348     todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1349
1350     hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
1351     todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1352
1353     hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
1354     todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1355
1356     hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
1357     todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1358
1359     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1360     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1361     if (!wnd)
1362     {
1363         skip("Couldn't create application window\n");
1364         return;
1365     }
1366     if (!d3d)
1367     {
1368         skip("Couldn't create IDirect3D9 object\n");
1369         DestroyWindow(wnd);
1370         return;
1371     }
1372
1373     ZeroMemory(&d3dpp, sizeof(d3dpp));
1374     d3dpp.Windowed = TRUE;
1375     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1376     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1377     if (FAILED(hr))
1378     {
1379         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1380         IDirect3D9_Release(d3d);
1381         DestroyWindow(wnd);
1382         return;
1383     }
1384
1385     hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
1386     todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1387
1388     hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
1389     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1390
1391     hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
1392     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1393
1394     hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
1395     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1396
1397     test_sphere(device, 0.0f, 2, 2);
1398     test_sphere(device, 1.0f, 2, 2);
1399     test_sphere(device, 1.0f, 3, 2);
1400     test_sphere(device, 1.0f, 4, 4);
1401     test_sphere(device, 1.0f, 3, 4);
1402     test_sphere(device, 5.0f, 6, 7);
1403     test_sphere(device, 10.0f, 11, 12);
1404
1405     IDirect3DDevice9_Release(device);
1406     IDirect3D9_Release(d3d);
1407     DestroyWindow(wnd);
1408 }
1409
1410 static void test_get_decl_vertex_size(void)
1411 {
1412     static const D3DVERTEXELEMENT9 declaration1[] =
1413     {
1414         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1415         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1416         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1417         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1418         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1419         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1420         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1421         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1422         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1423         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1424         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1425         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1426         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1427         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1428         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1429         D3DDECL_END(),
1430     };
1431     static const D3DVERTEXELEMENT9 declaration2[] =
1432     {
1433         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1434         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1435         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1436         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1437         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1438         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1439         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1440         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1441         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1442         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1443         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1444         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1445         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1446         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1447         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1448         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1449         D3DDECL_END(),
1450     };
1451     static const UINT sizes1[] =
1452     {
1453         4,  8,  12, 16,
1454         4,  4,  4,  8,
1455         4,  4,  8,  4,
1456         4,  4,  8,  0,
1457     };
1458     static const UINT sizes2[] =
1459     {
1460         12, 16, 20, 24,
1461         12, 12, 16, 16,
1462     };
1463     unsigned int i;
1464     UINT size;
1465
1466     size = D3DXGetDeclVertexSize(NULL, 0);
1467     ok(size == 0, "Got size %#x, expected 0.\n", size);
1468
1469     for (i = 0; i < 16; ++i)
1470     {
1471         size = D3DXGetDeclVertexSize(declaration1, i);
1472         ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
1473     }
1474
1475     for (i = 0; i < 8; ++i)
1476     {
1477         size = D3DXGetDeclVertexSize(declaration2, i);
1478         ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
1479     }
1480 }
1481
1482 START_TEST(mesh)
1483 {
1484     D3DXBoundProbeTest();
1485     D3DXComputeBoundingBoxTest();
1486     D3DXComputeBoundingSphereTest();
1487     D3DXGetFVFVertexSizeTest();
1488     D3DXIntersectTriTest();
1489     D3DXCreateMeshTest();
1490     D3DXCreateSphereTest();
1491     test_get_decl_vertex_size();
1492     test_fvf_decl_conversion();
1493 }