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