d3dx9_36/tests: Cleanup / simplify test_fvf_decl_conversion().
[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     todo_wine 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     todo_wine 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_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
517             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
518             D3DDECL_END(),
519         }, D3DFVF_XYZB1},
520         {{
521             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
522             {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
523             D3DDECL_END(),
524         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
525         {{
526             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
527             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
528             D3DDECL_END(),
529         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
530         {{
531             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
532             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
533             D3DDECL_END(),
534         }, D3DFVF_XYZB2},
535         {{
536             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
537             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
538             {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
539             D3DDECL_END(),
540         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
541         {{
542             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
543             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
544             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
545             D3DDECL_END(),
546         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
547         {{
548             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
549             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
550             D3DDECL_END(),
551         }, D3DFVF_XYZB3},
552         {{
553             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
554             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
555             {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
556             D3DDECL_END(),
557         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
558         {{
559             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
560             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
561             {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
562             D3DDECL_END(),
563         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
564         {{
565             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
566             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
567             D3DDECL_END(),
568         }, D3DFVF_XYZB4},
569         {{
570             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
571             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
572             {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
573             D3DDECL_END(),
574         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
575         {{
576             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
577             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
578             {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
579             D3DDECL_END(),
580         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
581         {{
582             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
583             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
584             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
585             D3DDECL_END(),
586         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
587         {{
588             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
589             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
590             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
591             D3DDECL_END(),
592         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
593         {{
594             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
595             D3DDECL_END(),
596         }, D3DFVF_NORMAL},
597         {{
598             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
599             D3DDECL_END(),
600         }, D3DFVF_PSIZE},
601         {{
602             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
603             D3DDECL_END(),
604         }, D3DFVF_DIFFUSE},
605         {{
606             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
607             D3DDECL_END(),
608         }, D3DFVF_SPECULAR},
609         /* Make sure textures of different sizes work. */
610         {{
611             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
612             D3DDECL_END(),
613         }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
614         {{
615             {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
616             D3DDECL_END(),
617         }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
618         {{
619             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
620             D3DDECL_END(),
621         }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
622         {{
623             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
624             D3DDECL_END(),
625         }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
626         /* Make sure the TEXCOORD index works correctly - try several textures. */
627         {{
628             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
629             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
630             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
631             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
632             D3DDECL_END(),
633         }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
634                 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
635         /* Now try some combination tests. */
636         {{
637             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
638             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
639             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
640             {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
641             {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
642             {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
643             D3DDECL_END(),
644         }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
645                 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
646         {{
647             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
648             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
649             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
650             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
651             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
652             {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
653             D3DDECL_END(),
654         }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
655                 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
656     };
657     unsigned int i;
658
659     for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
660     {
661         test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
662         test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
663     }
664
665     /* Usage indices for position and normal are apparently ignored. */
666     {
667         const D3DVERTEXELEMENT9 decl[] =
668         {
669             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
670             D3DDECL_END(),
671         };
672         test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
673     }
674     {
675         const D3DVERTEXELEMENT9 decl[] =
676         {
677             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
678             D3DDECL_END(),
679         };
680         test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
681     }
682     /* These are supposed to fail, both ways. */
683     {
684         const D3DVERTEXELEMENT9 decl[] =
685         {
686             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
687             D3DDECL_END(),
688         };
689         test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
690         test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
691     }
692     {
693         const D3DVERTEXELEMENT9 decl[] =
694         {
695             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
696             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
697             {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
698             D3DDECL_END(),
699         };
700         test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
701         test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
702     }
703     /* Test a declaration that can't be converted to an FVF. */
704     {
705         const D3DVERTEXELEMENT9 decl[] =
706         {
707             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
708             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
709             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
710             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
711             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
712             /* 8 bytes padding */
713             {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
714             D3DDECL_END(),
715         };
716         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
717     }
718 }
719
720 static void D3DXGetFVFVertexSizeTest(void)
721 {
722     UINT got;
723
724     compare_vertex_sizes (D3DFVF_XYZ, 12);
725
726     compare_vertex_sizes (D3DFVF_XYZB3, 24);
727
728     compare_vertex_sizes (D3DFVF_XYZB5, 32);
729
730     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
731
732     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
733
734     compare_vertex_sizes (
735         D3DFVF_XYZ |
736         D3DFVF_TEX1 |
737         D3DFVF_TEXCOORDSIZE1(0), 16);
738     compare_vertex_sizes (
739         D3DFVF_XYZ |
740         D3DFVF_TEX2 |
741         D3DFVF_TEXCOORDSIZE1(0) |
742         D3DFVF_TEXCOORDSIZE1(1), 20);
743
744     compare_vertex_sizes (
745         D3DFVF_XYZ |
746         D3DFVF_TEX1 |
747         D3DFVF_TEXCOORDSIZE2(0), 20);
748
749     compare_vertex_sizes (
750         D3DFVF_XYZ |
751         D3DFVF_TEX2 |
752         D3DFVF_TEXCOORDSIZE2(0) |
753         D3DFVF_TEXCOORDSIZE2(1), 28);
754
755     compare_vertex_sizes (
756         D3DFVF_XYZ |
757         D3DFVF_TEX6 |
758         D3DFVF_TEXCOORDSIZE2(0) |
759         D3DFVF_TEXCOORDSIZE2(1) |
760         D3DFVF_TEXCOORDSIZE2(2) |
761         D3DFVF_TEXCOORDSIZE2(3) |
762         D3DFVF_TEXCOORDSIZE2(4) |
763         D3DFVF_TEXCOORDSIZE2(5), 60);
764
765     compare_vertex_sizes (
766         D3DFVF_XYZ |
767         D3DFVF_TEX8 |
768         D3DFVF_TEXCOORDSIZE2(0) |
769         D3DFVF_TEXCOORDSIZE2(1) |
770         D3DFVF_TEXCOORDSIZE2(2) |
771         D3DFVF_TEXCOORDSIZE2(3) |
772         D3DFVF_TEXCOORDSIZE2(4) |
773         D3DFVF_TEXCOORDSIZE2(5) |
774         D3DFVF_TEXCOORDSIZE2(6) |
775         D3DFVF_TEXCOORDSIZE2(7), 76);
776
777     compare_vertex_sizes (
778         D3DFVF_XYZ |
779         D3DFVF_TEX1 |
780         D3DFVF_TEXCOORDSIZE3(0), 24);
781
782     compare_vertex_sizes (
783         D3DFVF_XYZ |
784         D3DFVF_TEX4 |
785         D3DFVF_TEXCOORDSIZE3(0) |
786         D3DFVF_TEXCOORDSIZE3(1) |
787         D3DFVF_TEXCOORDSIZE3(2) |
788         D3DFVF_TEXCOORDSIZE3(3), 60);
789
790     compare_vertex_sizes (
791         D3DFVF_XYZ |
792         D3DFVF_TEX1 |
793         D3DFVF_TEXCOORDSIZE4(0), 28);
794
795     compare_vertex_sizes (
796         D3DFVF_XYZ |
797         D3DFVF_TEX2 |
798         D3DFVF_TEXCOORDSIZE4(0) |
799         D3DFVF_TEXCOORDSIZE4(1), 44);
800
801     compare_vertex_sizes (
802         D3DFVF_XYZ |
803         D3DFVF_TEX3 |
804         D3DFVF_TEXCOORDSIZE4(0) |
805         D3DFVF_TEXCOORDSIZE4(1) |
806         D3DFVF_TEXCOORDSIZE4(2), 60);
807
808     compare_vertex_sizes (
809         D3DFVF_XYZB5 |
810         D3DFVF_NORMAL |
811         D3DFVF_DIFFUSE |
812         D3DFVF_SPECULAR |
813         D3DFVF_TEX8 |
814         D3DFVF_TEXCOORDSIZE4(0) |
815         D3DFVF_TEXCOORDSIZE4(1) |
816         D3DFVF_TEXCOORDSIZE4(2) |
817         D3DFVF_TEXCOORDSIZE4(3) |
818         D3DFVF_TEXCOORDSIZE4(4) |
819         D3DFVF_TEXCOORDSIZE4(5) |
820         D3DFVF_TEXCOORDSIZE4(6) |
821         D3DFVF_TEXCOORDSIZE4(7), 180);
822 }
823
824 static void D3DXIntersectTriTest(void)
825 {
826     BOOL exp_res, got_res;
827     D3DXVECTOR3 position, ray, vertex[3];
828     FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
829
830     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
831     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
832     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
833
834     position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
835
836     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
837
838     exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
839
840     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
841     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
842     ok( compare(exp_u,got_u), "Expected u = %f, got %f\n",exp_u,got_u);
843     ok( compare(exp_v,got_v), "Expected v = %f, got %f\n",exp_v,got_v);
844     ok( compare(exp_dist,got_dist), "Expected distance = %f, got %f\n",exp_dist,got_dist);
845
846 /*Only positive ray is taken in account*/
847
848     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
849     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
850     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
851
852     position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
853
854     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
855
856     exp_res = FALSE;
857
858     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
859     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
860
861 /*Intersection between ray and triangle in a same plane is considered as empty*/
862
863     vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
864     vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
865     vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
866
867     position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
868
869     ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
870
871     exp_res = FALSE;
872
873     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
874     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
875 }
876
877 static void D3DXCreateMeshTest(void)
878 {
879     HRESULT hr;
880     HWND wnd;
881     IDirect3D9 *d3d;
882     IDirect3DDevice9 *device, *test_device;
883     D3DPRESENT_PARAMETERS d3dpp;
884     ID3DXMesh *d3dxmesh;
885     int i, size;
886     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
887     DWORD fvf, options;
888     struct mesh mesh;
889
890     static const D3DVERTEXELEMENT9 decl[3] = {
891         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
892         {0, 0xC, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
893         D3DDECL_END(), };
894
895     hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
896     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
897
898     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, (LPD3DVERTEXELEMENT9 *)&decl, NULL, &d3dxmesh);
899     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
900
901     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
902     if (!wnd)
903     {
904         skip("Couldn't create application window\n");
905         return;
906     }
907     d3d = Direct3DCreate9(D3D_SDK_VERSION);
908     if (!d3d)
909     {
910         skip("Couldn't create IDirect3D9 object\n");
911         DestroyWindow(wnd);
912         return;
913     }
914
915     ZeroMemory(&d3dpp, sizeof(d3dpp));
916     d3dpp.Windowed = TRUE;
917     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
918     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
919     if (FAILED(hr))
920     {
921         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
922         IDirect3D9_Release(d3d);
923         DestroyWindow(wnd);
924         return;
925     }
926
927     hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, (LPD3DVERTEXELEMENT9 *)&decl, device, &d3dxmesh);
928     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
929
930     hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, (LPD3DVERTEXELEMENT9 *)&decl, device, &d3dxmesh);
931     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
932
933     hr = D3DXCreateMesh(1, 3, 0, (LPD3DVERTEXELEMENT9 *)&decl, device, &d3dxmesh);
934     todo_wine ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
935
936     if (hr == D3D_OK)
937     {
938         d3dxmesh->lpVtbl->Release(d3dxmesh);
939     }
940
941     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
942     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
943
944     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, (LPD3DVERTEXELEMENT9 *)&decl, device, NULL);
945     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
946
947     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, (LPD3DVERTEXELEMENT9 *)&decl, device, &d3dxmesh);
948     todo_wine ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
949
950     if (hr == D3D_OK)
951     {
952         /* device */
953         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
954         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
955
956         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
957         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
958         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
959
960         if (hr == D3D_OK)
961         {
962             IDirect3DDevice9_Release(device);
963         }
964
965         /* declaration */
966         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
967         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
968
969         if (hr == D3D_OK)
970         {
971             size = sizeof(decl) / sizeof(decl[0]);
972             for (i = 0; i < size - 1; i++)
973             {
974                 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
975                 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
976                 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
977                 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
978                 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl[i].UsageIndex);
979                 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", decl[1].Offset, decl[i].Offset);
980             }
981             ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
982         }
983
984         /* FVF */
985         fvf = d3dxmesh->lpVtbl->GetFVF(d3dxmesh);
986         ok(fvf == (D3DFVF_XYZ | D3DFVF_NORMAL), "Got result %x, expected %x (D3DFVF_XYZ | D3DFVF_NORMAL)\n", fvf, D3DFVF_XYZ | D3DFVF_NORMAL);
987
988         /* options */
989         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
990         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
991
992         /* rest */
993         if (!new_mesh(&mesh, 3, 1))
994         {
995             skip("Couldn't create mesh\n");
996         }
997         else
998         {
999             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1000             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1001
1002             compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1003
1004             free_mesh(&mesh);
1005         }
1006
1007         d3dxmesh->lpVtbl->Release(d3dxmesh);
1008     }
1009
1010     IDirect3DDevice9_Release(device);
1011     IDirect3D9_Release(d3d);
1012     DestroyWindow(wnd);
1013 }
1014
1015 struct sincos_table
1016 {
1017     float *sin;
1018     float *cos;
1019 };
1020
1021 static void free_sincos_table(struct sincos_table *sincos_table)
1022 {
1023     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
1024     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1025 }
1026
1027 /* pre compute sine and cosine tables; caller must free */
1028 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
1029 {
1030     float angle;
1031     int i;
1032
1033     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
1034     if (!sincos_table->sin)
1035     {
1036         return FALSE;
1037     }
1038     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
1039     if (!sincos_table->cos)
1040     {
1041         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1042         return FALSE;
1043     }
1044
1045     angle = angle_start;
1046     for (i = 0; i < n; i++)
1047     {
1048         sincos_table->sin[i] = sin(angle);
1049         sincos_table->cos[i] = cos(angle);
1050         angle += angle_step;
1051     }
1052
1053     return TRUE;
1054 }
1055
1056 static WORD sphere_vertex(UINT slices, int slice, int stack)
1057 {
1058     return stack*slices+slice+1;
1059 }
1060
1061 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
1062 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
1063 {
1064     float theta_step, theta_start;
1065     struct sincos_table theta;
1066     float phi_step, phi_start;
1067     struct sincos_table phi;
1068     DWORD number_of_vertices, number_of_faces;
1069     DWORD vertex, face;
1070     int slice, stack;
1071
1072     /* theta = angle on xy plane wrt x axis */
1073     theta_step = M_PI / stacks;
1074     theta_start = theta_step;
1075
1076     /* phi = angle on xz plane wrt z axis */
1077     phi_step = -2 * M_PI / slices;
1078     phi_start = M_PI / 2;
1079
1080     if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
1081     {
1082         return FALSE;
1083     }
1084     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
1085     {
1086         free_sincos_table(&theta);
1087         return FALSE;
1088     }
1089
1090     number_of_vertices = 2 + slices * (stacks-1);
1091     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
1092
1093     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
1094     {
1095         free_sincos_table(&phi);
1096         free_sincos_table(&theta);
1097         return FALSE;
1098     }
1099
1100     vertex = 0;
1101     face = 0;
1102     stack = 0;
1103
1104     mesh->vertices[vertex].normal.x = 0.0f;
1105     mesh->vertices[vertex].normal.y = 0.0f;
1106     mesh->vertices[vertex].normal.z = 1.0f;
1107     mesh->vertices[vertex].position.x = 0.0f;
1108     mesh->vertices[vertex].position.y = 0.0f;
1109     mesh->vertices[vertex].position.z = radius;
1110     vertex++;
1111
1112     for (stack = 0; stack < stacks - 1; stack++)
1113     {
1114         for (slice = 0; slice < slices; slice++)
1115         {
1116             mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
1117             mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
1118             mesh->vertices[vertex].normal.z = theta.cos[stack];
1119             mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
1120             mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
1121             mesh->vertices[vertex].position.z = radius * theta.cos[stack];
1122             vertex++;
1123
1124             if (slice > 0)
1125             {
1126                 if (stack == 0)
1127                 {
1128                     /* top stack is triangle fan */
1129                     mesh->faces[face][0] = 0;
1130                     mesh->faces[face][1] = slice + 1;
1131                     mesh->faces[face][2] = slice;
1132                     face++;
1133                 }
1134                 else
1135                 {
1136                     /* stacks in between top and bottom are quad strips */
1137                     mesh->faces[face][0] = sphere_vertex(slices, slice-1, stack-1);
1138                     mesh->faces[face][1] = sphere_vertex(slices, slice, stack-1);
1139                     mesh->faces[face][2] = sphere_vertex(slices, slice-1, stack);
1140                     face++;
1141
1142                     mesh->faces[face][0] = sphere_vertex(slices, slice, stack-1);
1143                     mesh->faces[face][1] = sphere_vertex(slices, slice, stack);
1144                     mesh->faces[face][2] = sphere_vertex(slices, slice-1, stack);
1145                     face++;
1146                 }
1147             }
1148         }
1149
1150         if (stack == 0)
1151         {
1152             mesh->faces[face][0] = 0;
1153             mesh->faces[face][1] = 1;
1154             mesh->faces[face][2] = slice;
1155             face++;
1156         }
1157         else
1158         {
1159             mesh->faces[face][0] = sphere_vertex(slices, slice-1, stack-1);
1160             mesh->faces[face][1] = sphere_vertex(slices, 0, stack-1);
1161             mesh->faces[face][2] = sphere_vertex(slices, slice-1, stack);
1162             face++;
1163
1164             mesh->faces[face][0] = sphere_vertex(slices, 0, stack-1);
1165             mesh->faces[face][1] = sphere_vertex(slices, 0, stack);
1166             mesh->faces[face][2] = sphere_vertex(slices, slice-1, stack);
1167             face++;
1168         }
1169     }
1170
1171     mesh->vertices[vertex].position.x = 0.0f;
1172     mesh->vertices[vertex].position.y = 0.0f;
1173     mesh->vertices[vertex].position.z = -radius;
1174     mesh->vertices[vertex].normal.x = 0.0f;
1175     mesh->vertices[vertex].normal.y = 0.0f;
1176     mesh->vertices[vertex].normal.z = -1.0f;
1177
1178     /* bottom stack is triangle fan */
1179     for (slice = 1; slice < slices; slice++)
1180     {
1181         mesh->faces[face][0] = sphere_vertex(slices, slice-1, stack-1);
1182         mesh->faces[face][1] = sphere_vertex(slices, slice, stack-1);
1183         mesh->faces[face][2] = vertex;
1184         face++;
1185     }
1186
1187     mesh->faces[face][0] = sphere_vertex(slices, slice-1, stack-1);
1188     mesh->faces[face][1] = sphere_vertex(slices, 0, stack-1);
1189     mesh->faces[face][2] = vertex;
1190
1191     free_sincos_table(&phi);
1192     free_sincos_table(&theta);
1193
1194     return TRUE;
1195 }
1196
1197 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
1198 {
1199     HRESULT hr;
1200     ID3DXMesh *sphere;
1201     struct mesh mesh;
1202     char name[256];
1203
1204     hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
1205     todo_wine ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1206     if (hr != D3D_OK)
1207     {
1208         skip("Couldn't create sphere\n");
1209         return;
1210     }
1211
1212     if (!compute_sphere(&mesh, radius, slices, stacks))
1213     {
1214         skip("Couldn't create mesh\n");
1215         sphere->lpVtbl->Release(sphere);
1216         return;
1217     }
1218
1219     sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
1220     compare_mesh(name, sphere, &mesh);
1221
1222     free_mesh(&mesh);
1223
1224     sphere->lpVtbl->Release(sphere);
1225 }
1226
1227 static void D3DXCreateSphereTest(void)
1228 {
1229     HRESULT hr;
1230     HWND wnd;
1231     IDirect3D9* d3d;
1232     IDirect3DDevice9* device;
1233     D3DPRESENT_PARAMETERS d3dpp;
1234     ID3DXMesh* sphere = NULL;
1235
1236     hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
1237     todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1238
1239     hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
1240     todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1241
1242     hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
1243     todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1244
1245     hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
1246     todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1247
1248     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1249     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1250     if (!wnd)
1251     {
1252         skip("Couldn't create application window\n");
1253         return;
1254     }
1255     if (!d3d)
1256     {
1257         skip("Couldn't create IDirect3D9 object\n");
1258         DestroyWindow(wnd);
1259         return;
1260     }
1261
1262     ZeroMemory(&d3dpp, sizeof(d3dpp));
1263     d3dpp.Windowed = TRUE;
1264     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1265     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1266     if (FAILED(hr))
1267     {
1268         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1269         IDirect3D9_Release(d3d);
1270         DestroyWindow(wnd);
1271         return;
1272     }
1273
1274     hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
1275     todo_wine ok( hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1276
1277     hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
1278     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1279
1280     hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
1281     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1282
1283     hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
1284     todo_wine ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1285
1286     test_sphere(device, 0.0f, 2, 2);
1287     test_sphere(device, 1.0f, 2, 2);
1288     test_sphere(device, 1.0f, 3, 2);
1289     test_sphere(device, 1.0f, 4, 4);
1290     test_sphere(device, 1.0f, 3, 4);
1291     test_sphere(device, 5.0f, 6, 7);
1292     test_sphere(device, 10.0f, 11, 12);
1293
1294     IDirect3DDevice9_Release(device);
1295     IDirect3D9_Release(d3d);
1296     DestroyWindow(wnd);
1297 }
1298
1299 static void test_get_decl_vertex_size(void)
1300 {
1301     static const D3DVERTEXELEMENT9 declaration1[] =
1302     {
1303         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1304         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1305         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1306         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1307         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1308         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1309         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1310         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1311         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1312         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1313         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1314         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1315         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1316         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1317         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1318         D3DDECL_END(),
1319     };
1320     static const D3DVERTEXELEMENT9 declaration2[] =
1321     {
1322         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1323         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1324         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1325         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1326         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1327         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1328         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1329         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1330         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1331         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1332         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1333         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1334         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1335         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1336         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1337         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1338         D3DDECL_END(),
1339     };
1340     static const UINT sizes1[] =
1341     {
1342         4,  8,  12, 16,
1343         4,  4,  4,  8,
1344         4,  4,  8,  4,
1345         4,  4,  8,  0,
1346     };
1347     static const UINT sizes2[] =
1348     {
1349         12, 16, 20, 24,
1350         12, 12, 16, 16,
1351     };
1352     unsigned int i;
1353     UINT size;
1354
1355     size = D3DXGetDeclVertexSize(NULL, 0);
1356     ok(size == 0, "Got size %#x, expected 0.\n", size);
1357
1358     for (i = 0; i < 16; ++i)
1359     {
1360         size = D3DXGetDeclVertexSize(declaration1, i);
1361         ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
1362     }
1363
1364     for (i = 0; i < 8; ++i)
1365     {
1366         size = D3DXGetDeclVertexSize(declaration2, i);
1367         ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
1368     }
1369 }
1370
1371 START_TEST(mesh)
1372 {
1373     D3DXBoundProbeTest();
1374     D3DXComputeBoundingBoxTest();
1375     D3DXComputeBoundingSphereTest();
1376     D3DXGetFVFVertexSizeTest();
1377     D3DXIntersectTriTest();
1378     D3DXCreateMeshTest();
1379     D3DXCreateSphereTest();
1380     test_get_decl_vertex_size();
1381     test_fvf_decl_conversion();
1382 }