1 /*
2  * Copyright 2008 David Adam
3  * Copyright 2008 Luis Busquets
4  * Copyright 2009 Henri Verbeet for CodeWeavers
5  * Copyright 2011 Michael Mc Donnell
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #define COBJMACROS
23 #include <stdio.h>
24 #include <float.h>
25 #include <limits.h>
26 #include "wine/test.h"
27 #include "d3dx9.h"
28 #include "initguid.h"
29 #include "rmxftmpl.h"
30 #include "rmxfguid.h"
31 
32 #ifndef NAN
33 /* From wine/port.h */
34 static inline float __port_nan(void)
35 {
36     static const unsigned __nan_bytes = 0x7fc00000;
37     return *(const float *)&__nan_bytes;
38 }
39 #define NAN __port_nan()
40 #endif
41 
42 /* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose
43  * function call traces of ID3DXAllocateHierarchy callbacks. */
44 #define TRACECALLBACK if(winetest_debug > 1) trace
45 
46 #define admitted_error 0.0001f
47 
48 #define compare_vertex_sizes(type, exp) \
49     got=D3DXGetFVFVertexSize(type); \
50     ok(got==exp, "Expected: %d, Got: %d\n", exp, got);
51 
52 #define compare_float(got, exp) \
53     do { \
54         float _got = (got); \
55         float _exp = (exp); \
56         ok(_got == _exp, "Expected: %g, Got: %g\n", _exp, _got); \
57     } while (0)
58 
59 static BOOL compare(FLOAT u, FLOAT v)
60 {
61     return (fabs(u-v) < admitted_error);
62 }
63 
64 static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v)
65 {
66     return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
67 }
68 
69 static BOOL compare_vec4(D3DXVECTOR4 u, D3DXVECTOR4 v)
70 {
71     return compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) && compare(u.w, v.w);
72 }
73 
74 #define check_floats(got, exp, dim) check_floats_(__LINE__, "", got, exp, dim)
75 static void check_floats_(int line, const char *prefix, const float *got, const float *exp, int dim)
76 {
77     int i;
78     char exp_buffer[256] = "";
79     char got_buffer[256] = "";
80     char *exp_buffer_ptr = exp_buffer;
81     char *got_buffer_ptr = got_buffer;
82     BOOL equal = TRUE;
83 
84     for (i = 0; i < dim; i++) {
85         if (i) {
86             exp_buffer_ptr += sprintf(exp_buffer_ptr, ", ");
87             got_buffer_ptr += sprintf(got_buffer_ptr, ", ");
88         }
89         equal = equal && compare(*exp, *got);
90         exp_buffer_ptr += sprintf(exp_buffer_ptr, "%g", *exp);
91         got_buffer_ptr += sprintf(got_buffer_ptr, "%g", *got);
92         exp++, got++;
93     }
94     ok_(__FILE__,line)(equal, "%sExpected (%s), got (%s)", prefix, exp_buffer, got_buffer);
95 }
96 
97 struct vertex
98 {
99     D3DXVECTOR3 position;
100     D3DXVECTOR3 normal;
101 };
102 
103 typedef WORD face[3];
104 
105 static BOOL compare_face(face a, face b)
106 {
107     return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
108 }
109 
110 struct test_context
111 {
112     HWND hwnd;
113     IDirect3D9 *d3d;
114     IDirect3DDevice9 *device;
115 };
116 
117 /* Initializes a test context struct. Use it to initialize DirectX.
118  *
119  * Returns NULL if an error occurred.
120  */
121 static struct test_context *new_test_context(void)
122 {
123     HRESULT hr;
124     HWND hwnd = NULL;
125     IDirect3D9 *d3d = NULL;
126     IDirect3DDevice9 *device = NULL;
127     D3DPRESENT_PARAMETERS d3dpp = {0};
128     struct test_context *test_context;
129 
130     if (!(hwnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
131             640, 480, NULL, NULL, NULL, NULL)))
132     {
133         skip("Couldn't create application window\n");
134         goto error;
135     }
136 
137     d3d = Direct3DCreate9(D3D_SDK_VERSION);
138     if (!d3d)
139     {
140         skip("Couldn't create IDirect3D9 object\n");
141         goto error;
142     }
143 
144     memset(&d3dpp, 0, sizeof(d3dpp));
145     d3dpp.Windowed = TRUE;
146     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
147     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
148                                  D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
149     if (FAILED(hr))
150     {
151         skip("Couldn't create IDirect3DDevice9 object %#x\n", hr);
152         goto error;
153     }
154 
155     test_context = HeapAlloc(GetProcessHeap(), 0, sizeof(*test_context));
156     if (!test_context)
157     {
158         skip("Couldn't allocate memory for test_context\n");
159         goto error;
160     }
161     test_context->hwnd = hwnd;
162     test_context->d3d = d3d;
163     test_context->device = device;
164 
165     return test_context;
166 
167 error:
168     if (device)
169         IDirect3DDevice9_Release(device);
170 
171     if (d3d)
172         IDirect3D9_Release(d3d);
173 
174     if (hwnd)
175         DestroyWindow(hwnd);
176 
177     return NULL;
178 }
179 
180 static void free_test_context(struct test_context *test_context)
181 {
182     if (!test_context)
183         return;
184 
185     if (test_context->device)
186         IDirect3DDevice9_Release(test_context->device);
187 
188     if (test_context->d3d)
189         IDirect3D9_Release(test_context->d3d);
190 
191     if (test_context->hwnd)
192         DestroyWindow(test_context->hwnd);
193 
194     HeapFree(GetProcessHeap(), 0, test_context);
195 }
196 
197 struct mesh
198 {
199     DWORD number_of_vertices;
200     struct vertex *vertices;
201 
202     DWORD number_of_faces;
203     face *faces;
204 
205     DWORD fvf;
206     UINT vertex_size;
207 };
208 
209 static void free_mesh(struct mesh *mesh)
210 {
211     HeapFree(GetProcessHeap(), 0, mesh->faces);
212     HeapFree(GetProcessHeap(), 0, mesh->vertices);
213 }
214 
215 static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
216 {
217     mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
218     if (!mesh->vertices)
219     {
220         return FALSE;
221     }
222     mesh->number_of_vertices = number_of_vertices;
223 
224     mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
225     if (!mesh->faces)
226     {
227         HeapFree(GetProcessHeap(), 0, mesh->vertices);
228         return FALSE;
229     }
230     mesh->number_of_faces = number_of_faces;
231 
232     return TRUE;
233 }
234 
235 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
236 {
237     HRESULT hr;
238     DWORD number_of_vertices, number_of_faces;
239     IDirect3DVertexBuffer9 *vertex_buffer;
240     IDirect3DIndexBuffer9 *index_buffer;
241     D3DVERTEXBUFFER_DESC vertex_buffer_description;
242     D3DINDEXBUFFER_DESC index_buffer_description;
243     struct vertex *vertices;
244     face *faces;
245     int expected, i;
246 
247     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
248     ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
249        name, number_of_vertices, mesh->number_of_vertices);
250 
251     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
252     ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
253        name, number_of_faces, mesh->number_of_faces);
254 
255     /* vertex buffer */
256     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
257     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
258 
259     if (hr != D3D_OK)
260     {
261         skip("Couldn't get vertex buffer\n");
262     }
263     else
264     {
265         hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
266         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
267 
268         if (hr != D3D_OK)
269         {
270             skip("Couldn't get vertex buffer description\n");
271         }
272         else
273         {
274             ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
275                name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
276             ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
277                name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
278             ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
279             ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
280                name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
281             ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
282                name, vertex_buffer_description.FVF, mesh->fvf);
283             if (mesh->fvf == 0)
284             {
285                 expected = number_of_vertices * mesh->vertex_size;
286             }
287             else
288             {
289                 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
290             }
291             ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
292                name, vertex_buffer_description.Size, expected);
293         }
294 
295         /* specify offset and size to avoid potential overruns */
296         hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
297                 (void **)&vertices, D3DLOCK_DISCARD);
298         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
299 
300         if (hr != D3D_OK)
301         {
302             skip("Couldn't lock vertex buffer\n");
303         }
304         else
305         {
306             for (i = 0; i < number_of_vertices; i++)
307             {
308                 ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
309                    "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
310                    vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
311                    mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
312                 ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
313                    "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
314                    vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
315                    mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
316             }
317 
318             IDirect3DVertexBuffer9_Unlock(vertex_buffer);
319         }
320 
321         IDirect3DVertexBuffer9_Release(vertex_buffer);
322     }
323 
324     /* index buffer */
325     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
326     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
327 
328     if (!index_buffer)
329     {
330         skip("Couldn't get index buffer\n");
331     }
332     else
333     {
334         hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
335         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
336 
337         if (hr != D3D_OK)
338         {
339             skip("Couldn't get index buffer description\n");
340         }
341         else
342         {
343             ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
344                name, index_buffer_description.Format, D3DFMT_INDEX16);
345             ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
346                name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
347             ok(index_buffer_description.Usage == 0, "Test %s, result %#x, expected %#x.\n",
348                     name, index_buffer_description.Usage, 0);
349             ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
350                name, index_buffer_description.Pool, D3DPOOL_MANAGED);
351             expected = number_of_faces * sizeof(WORD) * 3;
352             ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
353                name, index_buffer_description.Size, expected);
354         }
355 
356         /* specify offset and size to avoid potential overruns */
357         hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
358                 (void **)&faces, D3DLOCK_DISCARD);
359         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
360 
361         if (hr != D3D_OK)
362         {
363             skip("Couldn't lock index buffer\n");
364         }
365         else
366         {
367             for (i = 0; i < number_of_faces; i++)
368             {
369                 ok(compare_face(faces[i], mesh->faces[i]),
370                    "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
371                    faces[i][0], faces[i][1], faces[i][2],
372                    mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
373             }
374 
375             IDirect3DIndexBuffer9_Unlock(index_buffer);
376         }
377 
378         IDirect3DIndexBuffer9_Release(index_buffer);
379     }
380 }
381 
382 static void D3DXBoundProbeTest(void)
383 {
384     BOOL result;
385     D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
386     FLOAT radius;
387 
388 /*____________Test the Box case___________________________*/
389     bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
390     top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
391 
392     raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
393     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
394     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
395     ok(result == TRUE, "expected TRUE, received FALSE\n");
396 
397     raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
398     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
399     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
400     ok(result == FALSE, "expected FALSE, received TRUE\n");
401 
402     rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
403     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
404     ok(result == TRUE, "expected TRUE, received FALSE\n");
405 
406     bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
407     top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
408     rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
409     raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
410     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
411     ok(result == FALSE, "expected FALSE, received TRUE\n");
412 
413     bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
414     top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
415 
416     raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
417     rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
418     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
419     ok(result == TRUE, "expected TRUE, received FALSE\n");
420 
421     bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
422     top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
423 
424     raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
425     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
426     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
427     ok(result == FALSE, "expected FALSE, received TRUE\n");
428 
429     raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
430     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
431     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
432     ok(result == TRUE, "expected TRUE, received FALSE\n");
433 
434 /*____________Test the Sphere case________________________*/
435     radius = sqrt(77.0f);
436     center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
437     raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
438 
439     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
440     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
441     ok(result == TRUE, "expected TRUE, received FALSE\n");
442 
443     rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
444     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
445     ok(result == FALSE, "expected FALSE, received TRUE\n");
446 
447     rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
448     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
449     ok(result == FALSE, "expected FALSE, received TRUE\n");
450 }
451 
452 static void D3DXComputeBoundingBoxTest(void)
453 {
454     D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
455     HRESULT hr;
456 
457     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
458     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
459     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
460     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
461     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
462 
463     exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
464     exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
465 
466     hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
467 
468     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
469     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);
470     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);
471 
472 /*________________________*/
473 
474     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
475     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
476     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
477     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
478     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
479 
480     exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
481     exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
482 
483     hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
484 
485     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
486     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);
487     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);
488 
489 /*________________________*/
490 
491     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
492     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
493     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
494     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
495     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
496 
497     exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
498     exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
499 
500     hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
501 
502     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
503     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);
504     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);
505 
506 /*________________________*/
507     hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
508     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
509 
510 /*________________________*/
511     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
512     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
513 
514 /*________________________*/
515     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
516     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
517 }
518 
519 static void D3DXComputeBoundingSphereTest(void)
520 {
521     D3DXVECTOR3 exp_cen, got_cen, vertex[5];
522     FLOAT exp_rad, got_rad;
523     HRESULT hr;
524 
525     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
526     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
527     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
528     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
529     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
530 
531     exp_rad = 6.928203f;
532     exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
533 
534     hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
535 
536     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
537     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
538     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);
539 
540 /*________________________*/
541 
542     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
543     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
544     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
545     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
546     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
547 
548     exp_rad = 13.707883f;
549     exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
550 
551     hr = D3DXComputeBoundingSphere(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
552 
553     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
554     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
555     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);
556 
557 /*________________________*/
558     hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
559     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
560 
561 /*________________________*/
562     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
563     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
564 
565 /*________________________*/
566     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
567     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
568 }
569 
570 static void print_elements(const D3DVERTEXELEMENT9 *elements)
571 {
572     D3DVERTEXELEMENT9 last = D3DDECL_END();
573     const D3DVERTEXELEMENT9 *ptr = elements;
574     int count = 0;
575 
576     while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
577     {
578         trace(
579             "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
580              count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
581         ptr++;
582         count++;
583     }
584 }
585 
586 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
587         unsigned int line, unsigned int test_id)
588 {
589     D3DVERTEXELEMENT9 last = D3DDECL_END();
590     unsigned int i;
591 
592     for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
593     {
594         int end1 = memcmp(&elements[i], &last, sizeof(last));
595         int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
596         int status;
597 
598         if (!end1 && !end2) break;
599 
600         status = !end1 ^ !end2;
601         ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
602                 line, test_id, end1 ? "shorter" : "longer");
603         if (status)
604         {
605             print_elements(elements);
606             break;
607         }
608 
609         status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
610         ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
611         if (status)
612         {
613             print_elements(elements);
614             break;
615         }
616     }
617 }
618 
619 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
620         HRESULT expected_hr, unsigned int line, unsigned int test_id)
621 {
622     HRESULT hr;
623     D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
624 
625     hr = D3DXDeclaratorFromFVF(test_fvf, decl);
626     ok(hr == expected_hr,
627             "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
628             line, test_id, hr, expected_hr);
629     if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
630 }
631 
632 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
633         HRESULT expected_hr, unsigned int line, unsigned int test_id)
634 {
635     HRESULT hr;
636     DWORD result_fvf = 0xdeadbeef;
637 
638     hr = D3DXFVFFromDeclarator(decl, &result_fvf);
639     ok(hr == expected_hr,
640        "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
641        line, test_id, hr, expected_hr);
642     if (SUCCEEDED(hr))
643     {
644         ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
645                 line, test_id, result_fvf, expected_fvf);
646     }
647 }
648 
649 static void test_fvf_decl_conversion(void)
650 {
651     static const struct
652     {
653         D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
654         DWORD fvf;
655     }
656     test_data[] =
657     {
658         {{
659             D3DDECL_END(),
660         }, 0},
661         {{
662             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
663             D3DDECL_END(),
664         }, D3DFVF_XYZ},
665         {{
666             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
667             D3DDECL_END(),
668         }, D3DFVF_XYZRHW},
669         {{
670             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
671             D3DDECL_END(),
672         }, D3DFVF_XYZRHW},
673         {{
674             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
675             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
676             D3DDECL_END(),
677         }, D3DFVF_XYZB1},
678         {{
679             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
680             {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
681             D3DDECL_END(),
682         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
683         {{
684             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
685             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
686             D3DDECL_END(),
687         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
688         {{
689             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
690             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
691             D3DDECL_END(),
692         }, D3DFVF_XYZB2},
693         {{
694             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
695             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
696             {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
697             D3DDECL_END(),
698         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
699         {{
700             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
701             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
702             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
703             D3DDECL_END(),
704         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
705         {{
706             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
707             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
708             D3DDECL_END(),
709         }, D3DFVF_XYZB3},
710         {{
711             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
712             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
713             {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
714             D3DDECL_END(),
715         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
716         {{
717             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
718             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
719             {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
720             D3DDECL_END(),
721         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
722         {{
723             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
724             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
725             D3DDECL_END(),
726         }, D3DFVF_XYZB4},
727         {{
728             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
729             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
730             {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
731             D3DDECL_END(),
732         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
733         {{
734             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
735             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
736             {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
737             D3DDECL_END(),
738         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
739         {{
740             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
741             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
742             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
743             D3DDECL_END(),
744         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
745         {{
746             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
747             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
748             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
749             D3DDECL_END(),
750         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
751         {{
752             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
753             D3DDECL_END(),
754         }, D3DFVF_NORMAL},
755         {{
756             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
757             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
758             D3DDECL_END(),
759         }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
760         {{
761             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
762             D3DDECL_END(),
763         }, D3DFVF_PSIZE},
764         {{
765             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
766             D3DDECL_END(),
767         }, D3DFVF_DIFFUSE},
768         {{
769             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
770             D3DDECL_END(),
771         }, D3DFVF_SPECULAR},
772         /* Make sure textures of different sizes work. */
773         {{
774             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
775             D3DDECL_END(),
776         }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
777         {{
778             {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
779             D3DDECL_END(),
780         }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
781         {{
782             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
783             D3DDECL_END(),
784         }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
785         {{
786             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
787             D3DDECL_END(),
788         }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
789         /* Make sure the TEXCOORD index works correctly - try several textures. */
790         {{
791             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
792             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
793             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
794             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
795             D3DDECL_END(),
796         }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
797                 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
798         /* Now try some combination tests. */
799         {{
800             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
801             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
802             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
803             {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
804             {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
805             {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
806             D3DDECL_END(),
807         }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
808                 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
809         {{
810             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
811             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
812             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
813             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
814             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
815             {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
816             D3DDECL_END(),
817         }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
818                 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
819     };
820     unsigned int i;
821 
822     for (i = 0; i < ARRAY_SIZE(test_data); ++i)
823     {
824         test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
825         test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
826     }
827 
828     /* Usage indices for position and normal are apparently ignored. */
829     {
830         const D3DVERTEXELEMENT9 decl[] =
831         {
832             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
833             D3DDECL_END(),
834         };
835         test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
836     }
837     {
838         const D3DVERTEXELEMENT9 decl[] =
839         {
840             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
841             D3DDECL_END(),
842         };
843         test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
844     }
845     /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
846      * there are no blend matrices. */
847     {
848         const D3DVERTEXELEMENT9 decl[] =
849         {
850             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
851             D3DDECL_END(),
852         };
853         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
854     }
855     {
856         const D3DVERTEXELEMENT9 decl[] =
857         {
858             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
859             D3DDECL_END(),
860         };
861         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
862     }
863     /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
864     {
865         const D3DVERTEXELEMENT9 decl[] =
866         {
867             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
868             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
869             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
870             D3DDECL_END(),
871         };
872         test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
873                 decl, D3D_OK, __LINE__, 0);
874     }
875     /* These are supposed to fail, both ways. */
876     {
877         const D3DVERTEXELEMENT9 decl[] =
878         {
879             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
880             D3DDECL_END(),
881         };
882         test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
883         test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
884     }
885     {
886         const D3DVERTEXELEMENT9 decl[] =
887         {
888             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
889             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
890             D3DDECL_END(),
891         };
892         test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
893         test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
894     }
895     {
896         const D3DVERTEXELEMENT9 decl[] =
897         {
898             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
899             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
900             {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
901             D3DDECL_END(),
902         };
903         test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
904         test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
905     }
906     /* Test a declaration that can't be converted to an FVF. */
907     {
908         const D3DVERTEXELEMENT9 decl[] =
909         {
910             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
911             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
912             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
913             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
914             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
915             /* 8 bytes padding */
916             {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
917             D3DDECL_END(),
918         };
919         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
920     }
921     /* Elements must be ordered by offset. */
922     {
923         const D3DVERTEXELEMENT9 decl[] =
924         {
925             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
926             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
927             D3DDECL_END(),
928         };
929         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
930     }
931     /* Basic tests for element order. */
932     {
933         const D3DVERTEXELEMENT9 decl[] =
934         {
935             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
936             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
937             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
938             D3DDECL_END(),
939         };
940         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
941     }
942     {
943         const D3DVERTEXELEMENT9 decl[] =
944         {
945             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
946             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
947             D3DDECL_END(),
948         };
949         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
950     }
951     {
952         const D3DVERTEXELEMENT9 decl[] =
953         {
954             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
955             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
956             D3DDECL_END(),
957         };
958         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
959     }
960     /* Textures must be ordered by texcoords. */
961     {
962         const D3DVERTEXELEMENT9 decl[] =
963         {
964             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
965             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
966             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
967             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
968             D3DDECL_END(),
969         };
970         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
971     }
972     /* Duplicate elements are not allowed. */
973     {
974         const D3DVERTEXELEMENT9 decl[] =
975         {
976             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
977             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
978             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
979             D3DDECL_END(),
980         };
981         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
982     }
983     /* Invalid FVFs cannot be converted to a declarator. */
984     test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
985 }
986 
987 static void D3DXGetFVFVertexSizeTest(void)
988 {
989     UINT got;
990 
991     compare_vertex_sizes (D3DFVF_XYZ, 12);
992 
993     compare_vertex_sizes (D3DFVF_XYZB3, 24);
994 
995     compare_vertex_sizes (D3DFVF_XYZB5, 32);
996 
997     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
998 
999     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
1000 
1001     compare_vertex_sizes (
1002         D3DFVF_XYZ |
1003         D3DFVF_TEX1 |
1004         D3DFVF_TEXCOORDSIZE1(0), 16);
1005     compare_vertex_sizes (
1006         D3DFVF_XYZ |
1007         D3DFVF_TEX2 |
1008         D3DFVF_TEXCOORDSIZE1(0) |
1009         D3DFVF_TEXCOORDSIZE1(1), 20);
1010 
1011     compare_vertex_sizes (
1012         D3DFVF_XYZ |
1013         D3DFVF_TEX1 |
1014         D3DFVF_TEXCOORDSIZE2(0), 20);
1015 
1016     compare_vertex_sizes (
1017         D3DFVF_XYZ |
1018         D3DFVF_TEX2 |
1019         D3DFVF_TEXCOORDSIZE2(0) |
1020         D3DFVF_TEXCOORDSIZE2(1), 28);
1021 
1022     compare_vertex_sizes (
1023         D3DFVF_XYZ |
1024         D3DFVF_TEX6 |
1025         D3DFVF_TEXCOORDSIZE2(0) |
1026         D3DFVF_TEXCOORDSIZE2(1) |
1027         D3DFVF_TEXCOORDSIZE2(2) |
1028         D3DFVF_TEXCOORDSIZE2(3) |
1029         D3DFVF_TEXCOORDSIZE2(4) |
1030         D3DFVF_TEXCOORDSIZE2(5), 60);
1031 
1032     compare_vertex_sizes (
1033         D3DFVF_XYZ |
1034         D3DFVF_TEX8 |
1035         D3DFVF_TEXCOORDSIZE2(0) |
1036         D3DFVF_TEXCOORDSIZE2(1) |
1037         D3DFVF_TEXCOORDSIZE2(2) |
1038         D3DFVF_TEXCOORDSIZE2(3) |
1039         D3DFVF_TEXCOORDSIZE2(4) |
1040         D3DFVF_TEXCOORDSIZE2(5) |
1041         D3DFVF_TEXCOORDSIZE2(6) |
1042         D3DFVF_TEXCOORDSIZE2(7), 76);
1043 
1044     compare_vertex_sizes (
1045         D3DFVF_XYZ |
1046         D3DFVF_TEX1 |
1047         D3DFVF_TEXCOORDSIZE3(0), 24);
1048 
1049     compare_vertex_sizes (
1050         D3DFVF_XYZ |
1051         D3DFVF_TEX4 |
1052         D3DFVF_TEXCOORDSIZE3(0) |
1053         D3DFVF_TEXCOORDSIZE3(1) |
1054         D3DFVF_TEXCOORDSIZE3(2) |
1055         D3DFVF_TEXCOORDSIZE3(3), 60);
1056 
1057     compare_vertex_sizes (
1058         D3DFVF_XYZ |
1059         D3DFVF_TEX1 |
1060         D3DFVF_TEXCOORDSIZE4(0), 28);
1061 
1062     compare_vertex_sizes (
1063         D3DFVF_XYZ |
1064         D3DFVF_TEX2 |
1065         D3DFVF_TEXCOORDSIZE4(0) |
1066         D3DFVF_TEXCOORDSIZE4(1), 44);
1067 
1068     compare_vertex_sizes (
1069         D3DFVF_XYZ |
1070         D3DFVF_TEX3 |
1071         D3DFVF_TEXCOORDSIZE4(0) |
1072         D3DFVF_TEXCOORDSIZE4(1) |
1073         D3DFVF_TEXCOORDSIZE4(2), 60);
1074 
1075     compare_vertex_sizes (
1076         D3DFVF_XYZB5 |
1077         D3DFVF_NORMAL |
1078         D3DFVF_DIFFUSE |
1079         D3DFVF_SPECULAR |
1080         D3DFVF_TEX8 |
1081         D3DFVF_TEXCOORDSIZE4(0) |
1082         D3DFVF_TEXCOORDSIZE4(1) |
1083         D3DFVF_TEXCOORDSIZE4(2) |
1084         D3DFVF_TEXCOORDSIZE4(3) |
1085         D3DFVF_TEXCOORDSIZE4(4) |
1086         D3DFVF_TEXCOORDSIZE4(5) |
1087         D3DFVF_TEXCOORDSIZE4(6) |
1088         D3DFVF_TEXCOORDSIZE4(7), 180);
1089 }
1090 
1091 static void D3DXIntersectTriTest(void)
1092 {
1093     BOOL exp_res, got_res;
1094     D3DXVECTOR3 position, ray, vertex[3];
1095     FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
1096 
1097     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1098     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1099     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1100 
1101     position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
1102 
1103     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1104 
1105     exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
1106 
1107     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1108     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1109     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1110     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1111     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1112 
1113     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1114     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1115 
1116     vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1117     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1118     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 0.0f;
1119 
1120     got_u = got_v = got_dist = 0.0f;
1121     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1122     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1123     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1124     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1125     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1126 
1127     vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1128     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = -0.5f;
1129     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = -1.0f;
1130     exp_u = 0.375f;
1131     exp_v = 0.5625f;
1132     exp_dist = 7.9375f;
1133     got_u = got_v = got_dist = 0.0f;
1134     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1135     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1136     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1137     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1138     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1139 
1140 
1141 /*Only positive ray is taken in account*/
1142 
1143     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1144     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1145     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1146 
1147     position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
1148 
1149     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1150 
1151     exp_res = FALSE;
1152 
1153     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1154     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1155 
1156     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1157     ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1158 
1159 /*Intersection between ray and triangle in a same plane is considered as empty*/
1160 
1161     vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1162     vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1163     vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
1164 
1165     position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
1166 
1167     ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
1168 
1169     exp_res = FALSE;
1170 
1171     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1172     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1173 
1174     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1175     ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1176 }
1177 
1178 static void D3DXCreateMeshTest(void)
1179 {
1180     HRESULT hr;
1181     IDirect3DDevice9 *device, *test_device;
1182     ID3DXMesh *d3dxmesh;
1183     int i, size;
1184     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1185     DWORD options;
1186     struct mesh mesh;
1187     struct test_context *test_context;
1188 
1189     static const D3DVERTEXELEMENT9 decl1[] =
1190     {
1191         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1192         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1193         D3DDECL_END(),
1194     };
1195 
1196     static const D3DVERTEXELEMENT9 decl2[] =
1197     {
1198         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1199         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1200         {0, 24, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
1201         {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
1202         {0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
1203         /* 8 bytes padding */
1204         {0, 44, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
1205         D3DDECL_END(),
1206     };
1207 
1208     static const D3DVERTEXELEMENT9 decl3[] =
1209     {
1210         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1211         {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1212         D3DDECL_END(),
1213     };
1214 
1215     hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1216     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1217 
1218     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1219     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1220 
1221     test_context = new_test_context();
1222     if (!test_context)
1223     {
1224         skip("Couldn't create test context\n");
1225         return;
1226     }
1227     device = test_context->device;
1228 
1229     hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1230     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1231 
1232     hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1233     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1234 
1235     hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
1236     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1237 
1238     if (hr == D3D_OK)
1239     {
1240         d3dxmesh->lpVtbl->Release(d3dxmesh);
1241     }
1242 
1243     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1244     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1245 
1246     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
1247     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1248 
1249     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1250     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1251 
1252     if (hr == D3D_OK)
1253     {
1254         /* device */
1255         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1256         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1257 
1258         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1259         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1260         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1261 
1262         if (hr == D3D_OK)
1263         {
1264             IDirect3DDevice9_Release(device);
1265         }
1266 
1267         /* declaration */
1268         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1269         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1270 
1271         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1272         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1273 
1274         if (hr == D3D_OK)
1275         {
1276             size = ARRAY_SIZE(decl1);
1277             for (i = 0; i < size - 1; i++)
1278             {
1279                 ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1280                 ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1281                 ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1282                 ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1283                 ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1284                 ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1285             }
1286             ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1287         }
1288 
1289         /* options */
1290         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1291         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1292 
1293         /* rest */
1294         if (!new_mesh(&mesh, 3, 1))
1295         {
1296             skip("Couldn't create mesh\n");
1297         }
1298         else
1299         {
1300             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1301             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1302             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1303 
1304             compare_mesh("createmesh1", d3dxmesh, &mesh);
1305 
1306             free_mesh(&mesh);
1307         }
1308 
1309         d3dxmesh->lpVtbl->Release(d3dxmesh);
1310     }
1311 
1312     /* Test a declaration that can't be converted to an FVF. */
1313     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1314     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1315 
1316     if (hr == D3D_OK)
1317     {
1318         /* device */
1319         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1320         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1321 
1322         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1323         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1324         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1325 
1326         if (hr == D3D_OK)
1327         {
1328             IDirect3DDevice9_Release(device);
1329         }
1330 
1331         /* declaration */
1332         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1333         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1334 
1335         if (hr == D3D_OK)
1336         {
1337             size = ARRAY_SIZE(decl2);
1338             for (i = 0; i < size - 1; i++)
1339             {
1340                 ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1341                 ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1342                 ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1343                 ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1344                 ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1345                 ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1346             }
1347             ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1348         }
1349 
1350         /* options */
1351         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1352         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1353 
1354         /* rest */
1355         if (!new_mesh(&mesh, 3, 1))
1356         {
1357             skip("Couldn't create mesh\n");
1358         }
1359         else
1360         {
1361             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1362             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1363             mesh.fvf = 0;
1364             mesh.vertex_size = 60;
1365 
1366             compare_mesh("createmesh2", d3dxmesh, &mesh);
1367 
1368             free_mesh(&mesh);
1369         }
1370 
1371         mesh.vertex_size = d3dxmesh->lpVtbl->GetNumBytesPerVertex(d3dxmesh);
1372         ok(mesh.vertex_size == 60, "Got vertex size %u, expected %u\n", mesh.vertex_size, 60);
1373 
1374         d3dxmesh->lpVtbl->Release(d3dxmesh);
1375     }
1376 
1377     /* Test a declaration with multiple streams. */
1378     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
1379     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1380 
1381     free_test_context(test_context);
1382 }
1383 
1384 static void D3DXCreateMeshFVFTest(void)
1385 {
1386     HRESULT hr;
1387     IDirect3DDevice9 *device, *test_device;
1388     ID3DXMesh *d3dxmesh;
1389     int i, size;
1390     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1391     DWORD options;
1392     struct mesh mesh;
1393     struct test_context *test_context;
1394 
1395     static const D3DVERTEXELEMENT9 decl[] =
1396     {
1397         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1398         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1399         D3DDECL_END(),
1400     };
1401 
1402     hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1403     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1404 
1405     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, NULL, &d3dxmesh);
1406     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1407 
1408     test_context = new_test_context();
1409     if (!test_context)
1410     {
1411         skip("Couldn't create test context\n");
1412         return;
1413     }
1414     device = test_context->device;
1415 
1416     hr = D3DXCreateMeshFVF(0, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1417     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1418 
1419     hr = D3DXCreateMeshFVF(1, 0, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1420     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1421 
1422     hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1423     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1424 
1425     if (hr == D3D_OK)
1426     {
1427         d3dxmesh->lpVtbl->Release(d3dxmesh);
1428     }
1429 
1430     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1431     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1432 
1433     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, NULL);
1434     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1435 
1436     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1437     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1438 
1439     if (hr == D3D_OK)
1440     {
1441         /* device */
1442         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1443         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1444 
1445         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1446         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1447         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1448 
1449         if (hr == D3D_OK)
1450         {
1451             IDirect3DDevice9_Release(device);
1452         }
1453 
1454         /* declaration */
1455         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1456         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1457 
1458         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1459         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1460 
1461         if (hr == D3D_OK)
1462         {
1463             size = ARRAY_SIZE(decl);
1464             for (i = 0; i < size - 1; i++)
1465             {
1466                 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1467                 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1468                 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1469                 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1470                 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1471                    test_decl[i].UsageIndex, decl[i].UsageIndex);
1472                 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1473             }
1474             ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1475         }
1476 
1477         /* options */
1478         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1479         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1480 
1481         /* rest */
1482         if (!new_mesh(&mesh, 3, 1))
1483         {
1484             skip("Couldn't create mesh\n");
1485         }
1486         else
1487         {
1488             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1489             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1490             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1491 
1492             compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1493 
1494             free_mesh(&mesh);
1495         }
1496 
1497         d3dxmesh->lpVtbl->Release(d3dxmesh);
1498     }
1499 
1500     free_test_context(test_context);
1501 }
1502 
1503 #define check_vertex_buffer(mesh, vertices, num_vertices, fvf) \
1504     check_vertex_buffer_(__LINE__, mesh, vertices, num_vertices, fvf)
1505 static void check_vertex_buffer_(int line, ID3DXMesh *mesh, const void *vertices, DWORD num_vertices, DWORD fvf)
1506 {
1507     DWORD mesh_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
1508     DWORD mesh_fvf = mesh->lpVtbl->GetFVF(mesh);
1509     const void *mesh_vertices;
1510     HRESULT hr;
1511 
1512     ok_(__FILE__,line)(fvf == mesh_fvf, "expected FVF %x, got %x\n", fvf, mesh_fvf);
1513     ok_(__FILE__,line)(num_vertices == mesh_num_vertices,
1514        "Expected %u vertices, got %u\n", num_vertices, mesh_num_vertices);
1515 
1516     hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
1517     ok_(__FILE__,line)(hr == D3D_OK, "LockVertexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1518     if (FAILED(hr))
1519         return;
1520 
1521     if (mesh_fvf == fvf) {
1522         DWORD vertex_size = D3DXGetFVFVertexSize(fvf), i;
1523 
1524         for (i = 0; i < min(num_vertices, mesh_num_vertices); i++)
1525         {
1526             const FLOAT *exp_float = vertices;
1527             const FLOAT *got_float = mesh_vertices;
1528             DWORD texcount;
1529             DWORD pos_dim = 0;
1530             int j;
1531             BOOL last_beta_dword = FALSE;
1532             char prefix[128];
1533 
1534             switch (fvf & D3DFVF_POSITION_MASK) {
1535                 case D3DFVF_XYZ: pos_dim = 3; break;
1536                 case D3DFVF_XYZRHW: pos_dim = 4; break;
1537                 case D3DFVF_XYZB1:
1538                 case D3DFVF_XYZB2:
1539                 case D3DFVF_XYZB3:
1540                 case D3DFVF_XYZB4:
1541                 case D3DFVF_XYZB5:
1542                     pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
1543                     if (fvf & (D3DFVF_LASTBETA_UBYTE4 | D3DFVF_LASTBETA_D3DCOLOR))
1544                     {
1545                         pos_dim--;
1546                         last_beta_dword = TRUE;
1547                     }
1548                     break;
1549                 case D3DFVF_XYZW: pos_dim = 4; break;
1550             }
1551             sprintf(prefix, "vertex[%u] position, ", i);
1552             check_floats_(line, prefix, got_float, exp_float, pos_dim);
1553             exp_float += pos_dim;
1554             got_float += pos_dim;
1555 
1556             if (last_beta_dword) {
1557                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1558                     "Vertex[%u]: Expected last beta %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1559                 exp_float++;
1560                 got_float++;
1561             }
1562 
1563             if (fvf & D3DFVF_NORMAL) {
1564                 sprintf(prefix, "vertex[%u] normal, ", i);
1565                 check_floats_(line, prefix, got_float, exp_float, 3);
1566                 exp_float += 3;
1567                 got_float += 3;
1568             }
1569             if (fvf & D3DFVF_PSIZE) {
1570                 ok_(__FILE__,line)(compare(*exp_float, *got_float),
1571                         "Vertex[%u]: Expected psize %g, got %g\n", i, *exp_float, *got_float);
1572                 exp_float++;
1573                 got_float++;
1574             }
1575             if (fvf & D3DFVF_DIFFUSE) {
1576                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1577                     "Vertex[%u]: Expected diffuse %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1578                 exp_float++;
1579                 got_float++;
1580             }
1581             if (fvf & D3DFVF_SPECULAR) {
1582                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1583                     "Vertex[%u]: Expected specular %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1584                 exp_float++;
1585                 got_float++;
1586             }
1587 
1588             texcount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
1589             for (j = 0; j < texcount; j++) {
1590                 DWORD dim = (((fvf >> (16 + 2 * j)) + 1) & 0x03) + 1;
1591                 sprintf(prefix, "vertex[%u] texture, ", i);
1592                 check_floats_(line, prefix, got_float, exp_float, dim);
1593                 exp_float += dim;
1594                 got_float += dim;
1595             }
1596 
1597             vertices = (BYTE*)vertices + vertex_size;
1598             mesh_vertices = (BYTE*)mesh_vertices + vertex_size;
1599         }
1600     }
1601 
1602     mesh->lpVtbl->UnlockVertexBuffer(mesh);
1603 }
1604 
1605 #define check_index_buffer(mesh, indices, num_indices, index_size) \
1606     check_index_buffer_(__LINE__, mesh, indices, num_indices, index_size)
1607 static void check_index_buffer_(int line, ID3DXMesh *mesh, const void *indices, DWORD num_indices, DWORD index_size)
1608 {
1609     DWORD mesh_index_size = (mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT) ? 4 : 2;
1610     DWORD mesh_num_indices = mesh->lpVtbl->GetNumFaces(mesh) * 3;
1611     const void *mesh_indices;
1612     HRESULT hr;
1613     DWORD i;
1614 
1615     ok_(__FILE__,line)(index_size == mesh_index_size,
1616         "Expected index size %u, got %u\n", index_size, mesh_index_size);
1617     ok_(__FILE__,line)(num_indices == mesh_num_indices,
1618         "Expected %u indices, got %u\n", num_indices, mesh_num_indices);
1619 
1620     hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
1621     ok_(__FILE__,line)(hr == D3D_OK, "LockIndexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1622     if (FAILED(hr))
1623         return;
1624 
1625     if (mesh_index_size == index_size) {
1626         for (i = 0; i < min(num_indices, mesh_num_indices); i++)
1627         {
1628             if (index_size == 4)
1629                 ok_(__FILE__,line)(*(DWORD*)indices == *(DWORD*)mesh_indices,
1630                     "Index[%u]: expected %u, got %u\n", i, *(DWORD*)indices, *(DWORD*)mesh_indices);
1631             else
1632                 ok_(__FILE__,line)(*(WORD*)indices == *(WORD*)mesh_indices,
1633                     "Index[%u]: expected %u, got %u\n", i, *(WORD*)indices, *(WORD*)mesh_indices);
1634             indices = (BYTE*)indices + index_size;
1635             mesh_indices = (BYTE*)mesh_indices + index_size;
1636         }
1637     }
1638     mesh->lpVtbl->UnlockIndexBuffer(mesh);
1639 }
1640 
1641 #define check_matrix(got, expected) check_matrix_(__LINE__, got, expected)
1642 static void check_matrix_(int line, const D3DXMATRIX *got, const D3DXMATRIX *expected)
1643 {
1644     int i, j;
1645     for (i = 0; i < 4; i++) {
1646         for (j = 0; j < 4; j++) {
1647             ok_(__FILE__,line)(compare(U(*expected).m[i][j], U(*got).m[i][j]),
1648                     "matrix[%u][%u]: expected %g, got %g\n",
1649                     i, j, U(*expected).m[i][j], U(*got).m[i][j]);
1650         }
1651     }
1652 }
1653 
1654 static void check_colorvalue_(int line, const char *prefix, const D3DCOLORVALUE got, const D3DCOLORVALUE expected)
1655 {
1656     ok_(__FILE__,line)(expected.r == got.r && expected.g == got.g && expected.b == got.b && expected.a == got.a,
1657             "%sExpected (%g, %g, %g, %g), got (%g, %g, %g, %g)\n", prefix,
1658             expected.r, expected.g, expected.b, expected.a, got.r, got.g, got.b, got.a);
1659 }
1660 
1661 #define check_materials(got, got_count, expected, expected_count) \
1662     check_materials_(__LINE__, got, got_count, expected, expected_count)
1663 static void check_materials_(int line, const D3DXMATERIAL *got, DWORD got_count, const D3DXMATERIAL *expected, DWORD expected_count)
1664 {
1665     int i;
1666     ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
1667     if (!expected) {
1668         ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
1669         return;
1670     }
1671     for (i = 0; i < min(expected_count, got_count); i++)
1672     {
1673         if (!expected[i].pTextureFilename)
1674             ok_(__FILE__,line)(got[i].pTextureFilename == NULL,
1675                     "Expected NULL pTextureFilename, got %p\n", got[i].pTextureFilename);
1676         else
1677             ok_(__FILE__,line)(!strcmp(expected[i].pTextureFilename, got[i].pTextureFilename),
1678                     "Expected '%s' for pTextureFilename, got '%s'\n", expected[i].pTextureFilename, got[i].pTextureFilename);
1679         check_colorvalue_(line, "Diffuse: ", got[i].MatD3D.Diffuse, expected[i].MatD3D.Diffuse);
1680         check_colorvalue_(line, "Ambient: ", got[i].MatD3D.Ambient, expected[i].MatD3D.Ambient);
1681         check_colorvalue_(line, "Specular: ", got[i].MatD3D.Specular, expected[i].MatD3D.Specular);
1682         check_colorvalue_(line, "Emissive: ", got[i].MatD3D.Emissive, expected[i].MatD3D.Emissive);
1683         ok_(__FILE__,line)(expected[i].MatD3D.Power == got[i].MatD3D.Power,
1684                 "Power: Expected %g, got %g\n", expected[i].MatD3D.Power, got[i].MatD3D.Power);
1685     }
1686 }
1687 
1688 #define check_generated_adjacency(mesh, got, epsilon) check_generated_adjacency_(__LINE__, mesh, got, epsilon)
1689 static void check_generated_adjacency_(int line, ID3DXMesh *mesh, const DWORD *got, FLOAT epsilon)
1690 {
1691     DWORD *expected;
1692     DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
1693     HRESULT hr;
1694 
1695     expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
1696     if (!expected) {
1697         skip_(__FILE__, line)("Out of memory\n");
1698         return;
1699     }
1700     hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
1701     ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1702     if (SUCCEEDED(hr))
1703     {
1704         int i;
1705         for (i = 0; i < num_faces; i++)
1706         {
1707             ok_(__FILE__, line)(expected[i * 3] == got[i * 3] &&
1708                     expected[i * 3 + 1] == got[i * 3 + 1] &&
1709                     expected[i * 3 + 2] == got[i * 3 + 2],
1710                     "Face %u adjacencies: Expected (%u, %u, %u), got (%u, %u, %u)\n", i,
1711                     expected[i * 3], expected[i * 3 + 1], expected[i * 3 + 2],
1712                     got[i * 3], got[i * 3 + 1], got[i * 3 + 2]);
1713         }
1714     }
1715     HeapFree(GetProcessHeap(), 0, expected);
1716 }
1717 
1718 #define check_generated_effects(materials, num_materials, effects) \
1719     check_generated_effects_(__LINE__, materials, num_materials, effects)
1720 static void check_generated_effects_(int line, const D3DXMATERIAL *materials, DWORD num_materials, const D3DXEFFECTINSTANCE *effects)
1721 {
1722     int i;
1723     static const struct {
1724         const char *name;
1725         DWORD name_size;
1726         DWORD num_bytes;
1727         DWORD value_offset;
1728     } params[] = {
1729 #define EFFECT_TABLE_ENTRY(str, field) \
1730     {str, sizeof(str), sizeof(materials->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
1731         EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
1732         EFFECT_TABLE_ENTRY("Power", Power),
1733         EFFECT_TABLE_ENTRY("Specular", Specular),
1734         EFFECT_TABLE_ENTRY("Emissive", Emissive),
1735         EFFECT_TABLE_ENTRY("Ambient", Ambient),
1736 #undef EFFECT_TABLE_ENTRY
1737     };
1738 
1739     if (!num_materials) {
1740         ok_(__FILE__, line)(effects == NULL, "Expected NULL effects, got %p\n", effects);
1741         return;
1742     }
1743     for (i = 0; i < num_materials; i++)
1744     {
1745         int j;
1746         DWORD expected_num_defaults = ARRAY_SIZE(params) + (materials[i].pTextureFilename ? 1 : 0);
1747 
1748         ok_(__FILE__,line)(expected_num_defaults == effects[i].NumDefaults,
1749                 "effect[%u] NumDefaults: Expected %u, got %u\n", i,
1750                 expected_num_defaults, effects[i].NumDefaults);
1751         for (j = 0; j < min(ARRAY_SIZE(params), effects[i].NumDefaults); j++)
1752         {
1753             int k;
1754             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1755             ok_(__FILE__,line)(!strcmp(params[j].name, got_param->pParamName),
1756                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1757                params[j].name, got_param->pParamName);
1758             ok_(__FILE__,line)(D3DXEDT_FLOATS == got_param->Type,
1759                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1760                D3DXEDT_FLOATS, got_param->Type);
1761             ok_(__FILE__,line)(params[j].num_bytes == got_param->NumBytes,
1762                "effect[%u].pDefaults[%u].NumBytes: Expected %u, got %u\n", i, j,
1763                params[j].num_bytes, got_param->NumBytes);
1764             for (k = 0; k < min(params[j].num_bytes, got_param->NumBytes) / 4; k++)
1765             {
1766                 FLOAT expected = ((FLOAT*)((BYTE*)&materials[i] + params[j].value_offset))[k];
1767                 FLOAT got = ((FLOAT*)got_param->pValue)[k];
1768                 ok_(__FILE__,line)(compare(expected, got),
1769                    "effect[%u].pDefaults[%u] float value %u: Expected %g, got %g\n", i, j, k, expected, got);
1770             }
1771         }
1772         if (effects[i].NumDefaults > ARRAY_SIZE(params)) {
1773             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1774             static const char *expected_name = "Texture0@Name";
1775 
1776             ok_(__FILE__,line)(!strcmp(expected_name, got_param->pParamName),
1777                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1778                expected_name, got_param->pParamName);
1779             ok_(__FILE__,line)(D3DXEDT_STRING == got_param->Type,
1780                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1781                D3DXEDT_STRING, got_param->Type);
1782             if (materials[i].pTextureFilename) {
1783                 ok_(__FILE__,line)(strlen(materials[i].pTextureFilename) + 1 == got_param->NumBytes,
1784                    "effect[%u] texture filename length: Expected %u, got %u\n", i,
1785                    (DWORD)strlen(materials[i].pTextureFilename) + 1, got_param->NumBytes);
1786                 ok_(__FILE__,line)(!strcmp(materials[i].pTextureFilename, got_param->pValue),
1787                    "effect[%u] texture filename: Expected '%s', got '%s'\n", i,
1788                    materials[i].pTextureFilename, (char*)got_param->pValue);
1789             }
1790         }
1791     }
1792 }
1793 
1794 static char *strdupA(const char *p)
1795 {
1796     char *ret;
1797     if (!p) return NULL;
1798     ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
1799     if (ret) strcpy(ret, p);
1800     return ret;
1801 }
1802 
1803 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
1804 {
1805     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
1806     if (frame) {
1807         HeapFree(GetProcessHeap(), 0, frame->Name);
1808         HeapFree(GetProcessHeap(), 0, frame);
1809     }
1810     return D3D_OK;
1811 }
1812 
1813 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface,
1814         const char *name, D3DXFRAME **new_frame)
1815 {
1816     D3DXFRAME *frame;
1817 
1818     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
1819     frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
1820     if (!frame)
1821         return E_OUTOFMEMORY;
1822     if (name) {
1823         frame->Name = strdupA(name);
1824         if (!frame->Name) {
1825             HeapFree(GetProcessHeap(), 0, frame);
1826             return E_OUTOFMEMORY;
1827         }
1828     }
1829     *new_frame = frame;
1830     return D3D_OK;
1831 }
1832 
1833 static HRESULT destroy_mesh_container(LPD3DXMESHCONTAINER mesh_container)
1834 {
1835     int i;
1836 
1837     if (!mesh_container)
1838         return D3D_OK;
1839     HeapFree(GetProcessHeap(), 0, mesh_container->Name);
1840     if (U(mesh_container->MeshData).pMesh)
1841         IUnknown_Release(U(mesh_container->MeshData).pMesh);
1842     if (mesh_container->pMaterials) {
1843         for (i = 0; i < mesh_container->NumMaterials; i++)
1844             HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials[i].pTextureFilename);
1845         HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials);
1846     }
1847     if (mesh_container->pEffects) {
1848         for (i = 0; i < mesh_container->NumMaterials; i++) {
1849             HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pEffectFilename);
1850             if (mesh_container->pEffects[i].pDefaults) {
1851                 int j;
1852                 for (j = 0; j < mesh_container->pEffects[i].NumDefaults; j++) {
1853                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pParamName);
1854                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pValue);
1855                 }
1856                 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults);
1857             }
1858         }
1859         HeapFree(GetProcessHeap(), 0, mesh_container->pEffects);
1860     }
1861     HeapFree(GetProcessHeap(), 0, mesh_container->pAdjacency);
1862     if (mesh_container->pSkinInfo)
1863         IUnknown_Release(mesh_container->pSkinInfo);
1864     HeapFree(GetProcessHeap(), 0, mesh_container);
1865     return D3D_OK;
1866 }
1867 
1868 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyMeshContainer(ID3DXAllocateHierarchy *iface, LPD3DXMESHCONTAINER mesh_container)
1869 {
1870     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyMeshContainer(%p, %p)\n", iface, mesh_container);
1871     return destroy_mesh_container(mesh_container);
1872 }
1873 
1874 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateMeshContainer(ID3DXAllocateHierarchy *iface,
1875         const char *name, const D3DXMESHDATA *mesh_data, const D3DXMATERIAL *materials,
1876         const D3DXEFFECTINSTANCE *effects, DWORD num_materials, const DWORD *adjacency,
1877         ID3DXSkinInfo *skin_info, D3DXMESHCONTAINER **new_mesh_container)
1878 {
1879     LPD3DXMESHCONTAINER mesh_container = NULL;
1880     int i;
1881 
1882     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateMeshContainer(%p, '%s', %u, %p, %p, %p, %d, %p, %p, %p)\n",
1883             iface, name, mesh_data->Type, U(*mesh_data).pMesh, materials, effects,
1884             num_materials, adjacency, skin_info, *new_mesh_container);
1885 
1886     mesh_container = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mesh_container));
1887     if (!mesh_container)
1888         return E_OUTOFMEMORY;
1889 
1890     if (name) {
1891         mesh_container->Name = strdupA(name);
1892         if (!mesh_container->Name)
1893             goto error;
1894     }
1895 
1896     mesh_container->NumMaterials = num_materials;
1897     if (num_materials) {
1898         mesh_container->pMaterials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*materials));
1899         if (!mesh_container->pMaterials)
1900             goto error;
1901 
1902         memcpy(mesh_container->pMaterials, materials, num_materials * sizeof(*materials));
1903         for (i = 0; i < num_materials; i++)
1904             mesh_container->pMaterials[i].pTextureFilename = NULL;
1905         for (i = 0; i < num_materials; i++) {
1906             if (materials[i].pTextureFilename) {
1907                 mesh_container->pMaterials[i].pTextureFilename = strdupA(materials[i].pTextureFilename);
1908                 if (!mesh_container->pMaterials[i].pTextureFilename)
1909                     goto error;
1910             }
1911         }
1912 
1913         mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
1914         if (!mesh_container->pEffects)
1915             goto error;
1916         for (i = 0; i < num_materials; i++) {
1917             int j;
1918             const D3DXEFFECTINSTANCE *effect_src = &effects[i];
1919             D3DXEFFECTINSTANCE *effect_dest = &mesh_container->pEffects[i];
1920 
1921             if (effect_src->pEffectFilename) {
1922                 effect_dest->pEffectFilename = strdupA(effect_src->pEffectFilename);
1923                 if (!effect_dest->pEffectFilename)
1924                     goto error;
1925             }
1926             effect_dest->pDefaults = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1927                     effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
1928             if (!effect_dest->pDefaults)
1929                 goto error;
1930             effect_dest->NumDefaults = effect_src->NumDefaults;
1931             for (j = 0; j < effect_src->NumDefaults; j++) {
1932                 const D3DXEFFECTDEFAULT *default_src = &effect_src->pDefaults[j];
1933                 D3DXEFFECTDEFAULT *default_dest = &effect_dest->pDefaults[j];
1934 
1935                 if (default_src->pParamName) {
1936                     default_dest->pParamName = strdupA(default_src->pParamName);
1937                     if (!default_dest->pParamName)
1938                         goto error;
1939                 }
1940                 default_dest->NumBytes = default_src->NumBytes;
1941                 default_dest->Type = default_src->Type;
1942                 default_dest->pValue = HeapAlloc(GetProcessHeap(), 0, default_src->NumBytes);
1943                 memcpy(default_dest->pValue, default_src->pValue, default_src->NumBytes);
1944             }
1945         }
1946     }
1947 
1948     ok(adjacency != NULL, "Expected non-NULL adjacency, got NULL\n");
1949     if (adjacency) {
1950         if (mesh_data->Type == D3DXMESHTYPE_MESH || mesh_data->Type == D3DXMESHTYPE_PMESH) {
1951             ID3DXBaseMesh *basemesh = (ID3DXBaseMesh*)U(*mesh_data).pMesh;
1952             DWORD num_faces = basemesh->lpVtbl->GetNumFaces(basemesh);
1953             size_t size = num_faces * sizeof(DWORD) * 3;
1954             mesh_container->pAdjacency = HeapAlloc(GetProcessHeap(), 0, size);
1955             if (!mesh_container->pAdjacency)
1956                 goto error;
1957             memcpy(mesh_container->pAdjacency, adjacency, size);
1958         } else {
1959             ok(mesh_data->Type == D3DXMESHTYPE_PATCHMESH, "Unknown mesh type %u\n", mesh_data->Type);
1960             if (mesh_data->Type == D3DXMESHTYPE_PATCHMESH)
1961                 trace("FIXME: copying adjacency data for patch mesh not implemented\n");
1962         }
1963     }
1964 
1965     memcpy(&mesh_container->MeshData, mesh_data, sizeof(*mesh_data));
1966     if (U(*mesh_data).pMesh)
1967         IUnknown_AddRef(U(*mesh_data).pMesh);
1968     if (skin_info) {
1969         mesh_container->pSkinInfo = skin_info;
1970         skin_info->lpVtbl->AddRef(skin_info);
1971     }
1972     *new_mesh_container = mesh_container;
1973 
1974     return S_OK;
1975 error:
1976     destroy_mesh_container(mesh_container);
1977     return E_OUTOFMEMORY;
1978 }
1979 
1980 static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
1981     ID3DXAllocateHierarchyImpl_CreateFrame,
1982     ID3DXAllocateHierarchyImpl_CreateMeshContainer,
1983     ID3DXAllocateHierarchyImpl_DestroyFrame,
1984     ID3DXAllocateHierarchyImpl_DestroyMeshContainer,
1985 };
1986 static ID3DXAllocateHierarchy alloc_hier = { &ID3DXAllocateHierarchyImpl_Vtbl };
1987 
1988 #define test_LoadMeshFromX(device, xfile_str, vertex_array, fvf, index_array, materials_array, check_adjacency) \
1989     test_LoadMeshFromX_(__LINE__, device, xfile_str, sizeof(xfile_str) - 1, vertex_array, ARRAY_SIZE(vertex_array), fvf, \
1990             index_array, ARRAY_SIZE(index_array), sizeof(*index_array), materials_array, ARRAY_SIZE(materials_array), \
1991             check_adjacency);
1992 static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char *xfile_str, size_t xfile_strlen,
1993         const void *vertices, DWORD num_vertices, DWORD fvf, const void *indices, DWORD num_indices, size_t index_size,
1994         const D3DXMATERIAL *expected_materials, DWORD expected_num_materials, BOOL check_adjacency)
1995 {
1996     HRESULT hr;
1997     ID3DXBuffer *materials = NULL;
1998     ID3DXBuffer *effects = NULL;
1999     ID3DXBuffer *adjacency = NULL;
2000     ID3DXMesh *mesh = NULL;
2001     DWORD num_materials = 0;
2002 
2003     /* Adjacency is not checked when the X file contains multiple meshes,
2004      * since calling GenerateAdjacency on the merged mesh is not equivalent
2005      * to calling GenerateAdjacency on the individual meshes and then merging
2006      * the adjacency data. */
2007     hr = D3DXLoadMeshFromXInMemory(xfile_str, xfile_strlen, D3DXMESH_MANAGED, device,
2008             check_adjacency ? &adjacency : NULL, &materials, &effects, &num_materials, &mesh);
2009     ok_(__FILE__,line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2010     if (SUCCEEDED(hr)) {
2011         D3DXMATERIAL *materials_ptr = materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL;
2012         D3DXEFFECTINSTANCE *effects_ptr = effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL;
2013         DWORD *adjacency_ptr = check_adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL;
2014 
2015         check_vertex_buffer_(line, mesh, vertices, num_vertices, fvf);
2016         check_index_buffer_(line, mesh, indices, num_indices, index_size);
2017         check_materials_(line, materials_ptr, num_materials, expected_materials, expected_num_materials);
2018         check_generated_effects_(line, materials_ptr, num_materials, effects_ptr);
2019         if (check_adjacency)
2020             check_generated_adjacency_(line, mesh, adjacency_ptr, 0.0f);
2021 
2022         if (materials) ID3DXBuffer_Release(materials);
2023         if (effects) ID3DXBuffer_Release(effects);
2024         if (adjacency) ID3DXBuffer_Release(adjacency);
2025         IUnknown_Release(mesh);
2026     }
2027 }
2028 
2029 static void D3DXLoadMeshTest(void)
2030 {
2031     static const char empty_xfile[] = "xof 0303txt 0032";
2032     /*________________________*/
2033     static const char simple_xfile[] =
2034         "xof 0303txt 0032"
2035         "Mesh {"
2036             "3;"
2037             "0.0; 0.0; 0.0;,"
2038             "0.0; 1.0; 0.0;,"
2039             "1.0; 1.0; 0.0;;"
2040             "1;"
2041             "3; 0, 1, 2;;"
2042         "}";
2043     static const WORD simple_index_buffer[] = {0, 1, 2};
2044     static const D3DXVECTOR3 simple_vertex_buffer[] = {
2045         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}
2046     };
2047     const DWORD simple_fvf = D3DFVF_XYZ;
2048     static const char framed_xfile[] =
2049         "xof 0303txt 0032"
2050         "Frame {"
2051             "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 1.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2052             "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */
2053               "1.0, 0.0, 0.0, 0.0,"
2054               "0.0, 1.0, 0.0, 0.0,"
2055               "0.0, 0.0, 1.0, 0.0,"
2056               "0.0, 0.0, 2.0, 1.0;;"
2057             "}"
2058             "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 2.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2059             "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */
2060               "1.0, 0.0, 0.0, 0.0,"
2061               "0.0, 1.0, 0.0, 0.0,"
2062               "0.0, 0.0, 1.0, 0.0,"
2063               "0.0, 0.0, 3.0, 1.0;;"
2064             "}"
2065             "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 3.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2066         "}";
2067     static const WORD framed_index_buffer[] = { 0, 1, 2 };
2068     static const D3DXVECTOR3 framed_vertex_buffers[3][3] = {
2069         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}},
2070         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}},
2071         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {3.0, 1.0, 0.0}},
2072     };
2073     static const WORD merged_index_buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
2074     /* frame transforms accumulates for D3DXLoadMeshFromX */
2075     static const D3DXVECTOR3 merged_vertex_buffer[] = {
2076         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0},
2077         {0.0, 0.0, 2.0}, {0.0, 1.0, 2.0}, {2.0, 1.0, 2.0},
2078         {0.0, 0.0, 5.0}, {0.0, 1.0, 5.0}, {3.0, 1.0, 5.0},
2079     };
2080     const DWORD framed_fvf = D3DFVF_XYZ;
2081     /*________________________*/
2082     static const char box_xfile[] =
2083         "xof 0303txt 0032"
2084         "Mesh {"
2085             "8;" /* DWORD nVertices; */
2086             /* array Vector vertices[nVertices]; */
2087             "0.0; 0.0; 0.0;,"
2088             "0.0; 0.0; 1.0;,"
2089             "0.0; 1.0; 0.0;,"
2090             "0.0; 1.0; 1.0;,"
2091             "1.0; 0.0; 0.0;,"
2092             "1.0; 0.0; 1.0;,"
2093             "1.0; 1.0; 0.0;,"
2094             "1.0; 1.0; 1.0;;"
2095             "6;" /* DWORD nFaces; */
2096             /* array MeshFace faces[nFaces]; */
2097             "4; 0, 1, 3, 2;," /* (left side) */
2098             "4; 2, 3, 7, 6;," /* (top side) */
2099             "4; 6, 7, 5, 4;," /* (right side) */
2100             "4; 1, 0, 4, 5;," /* (bottom side) */
2101             "4; 1, 5, 7, 3;," /* (back side) */
2102             "4; 0, 2, 6, 4;;" /* (front side) */
2103             "MeshNormals {"
2104               "6;" /* DWORD nNormals; */
2105               /* array Vector normals[nNormals]; */
2106               "-1.0; 0.0; 0.0;,"
2107               "0.0; 1.0; 0.0;,"
2108               "1.0; 0.0; 0.0;,"
2109               "0.0; -1.0; 0.0;,"
2110               "0.0; 0.0; 1.0;,"
2111               "0.0; 0.0; -1.0;;"
2112               "6;" /* DWORD nFaceNormals; */
2113               /* array MeshFace faceNormals[nFaceNormals]; */
2114               "4; 0, 0, 0, 0;,"
2115               "4; 1, 1, 1, 1;,"
2116               "4; 2, 2, 2, 2;,"
2117               "4; 3, 3, 3, 3;,"
2118               "4; 4, 4, 4, 4;,"
2119               "4; 5, 5, 5, 5;;"
2120             "}"
2121             "MeshMaterialList materials {"
2122               "2;" /* DWORD nMaterials; */
2123               "6;" /* DWORD nFaceIndexes; */
2124               /* array DWORD faceIndexes[nFaceIndexes]; */
2125               "0, 0, 0, 1, 1, 1;;"
2126               "Material {"
2127                 /* ColorRGBA faceColor; */
2128                 "0.0; 0.0; 1.0; 1.0;;"
2129                 /* FLOAT power; */
2130                 "0.5;"
2131                 /* ColorRGB specularColor; */
2132                 "1.0; 1.0; 1.0;;"
2133                 /* ColorRGB emissiveColor; */
2134                 "0.0; 0.0; 0.0;;"
2135               "}"
2136               "Material {"
2137                 /* ColorRGBA faceColor; */
2138                 "1.0; 1.0; 1.0; 1.0;;"
2139                 /* FLOAT power; */
2140                 "1.0;"
2141                 /* ColorRGB specularColor; */
2142                 "1.0; 1.0; 1.0;;"
2143                 /* ColorRGB emissiveColor; */
2144                 "0.0; 0.0; 0.0;;"
2145                 "TextureFilename { \"texture.jpg\"; }"
2146               "}"
2147             "}"
2148             "MeshVertexColors {"
2149               "8;" /* DWORD nVertexColors; */
2150               /* array IndexedColor vertexColors[nVertexColors]; */
2151               "0; 0.0; 0.0; 0.0; 0.0;;"
2152               "1; 0.0; 0.0; 1.0; 0.1;;"
2153               "2; 0.0; 1.0; 0.0; 0.2;;"
2154               "3; 0.0; 1.0; 1.0; 0.3;;"
2155               "4; 1.0; 0.0; 0.0; 0.4;;"
2156               "5; 1.0; 0.0; 1.0; 0.5;;"
2157               "6; 1.0; 1.0; 0.0; 0.6;;"
2158               "7; 1.0; 1.0; 1.0; 0.7;;"
2159             "}"
2160             "MeshTextureCoords {"
2161               "8;" /* DWORD nTextureCoords; */
2162               /* array Coords2d textureCoords[nTextureCoords]; */
2163               "0.0; 1.0;,"
2164               "1.0; 1.0;,"
2165               "0.0; 0.0;,"
2166               "1.0; 0.0;,"
2167               "1.0; 1.0;,"
2168               "0.0; 1.0;,"
2169               "1.0; 0.0;,"
2170               "0.0; 0.0;;"
2171             "}"
2172           "}";
2173     static const WORD box_index_buffer[] = {
2174         0, 1, 3,
2175         0, 3, 2,
2176         8, 9, 7,
2177         8, 7, 6,
2178         10, 11, 5,
2179         10, 5, 4,
2180         12, 13, 14,
2181         12, 14, 15,
2182         16, 17, 18,
2183         16, 18, 19,
2184         20, 21, 22,
2185         20, 22, 23,
2186     };
2187     static const struct {
2188         D3DXVECTOR3 position;
2189         D3DXVECTOR3 normal;
2190         D3DCOLOR diffuse;
2191         D3DXVECTOR2 tex_coords;
2192     } box_vertex_buffer[] = {
2193         {{0.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, 0x00000000, {0.0, 1.0}},
2194         {{0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2195         {{0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2196         {{0.0, 1.0, 1.0}, {-1.0, 0.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2197         {{1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2198         {{1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2199         {{1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2200         {{1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2201         {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2202         {{0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2203         {{1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2204         {{1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2205         {{0.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2206         {{0.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x00000000, {0.0, 1.0}},
2207         {{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2208         {{1.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2209         {{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x1a0000ff, {1.0, 1.0}},
2210         {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x80ff00ff, {0.0, 1.0}},
2211         {{1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0xb3ffffff, {0.0, 0.0}},
2212         {{0.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0x4d00ffff, {1.0, 0.0}},
2213         {{0.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x00000000, {0.0, 1.0}},
2214         {{0.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x3300ff00, {0.0, 0.0}},
2215         {{1.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x99ffff00, {1.0, 0.0}},
2216         {{1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x66ff0000, {1.0, 1.0}},
2217     };
2218     static const D3DXMATERIAL box_materials[] = {
2219         {
2220             {
2221                 {0.0, 0.0, 1.0, 1.0}, /* Diffuse */
2222                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2223                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2224                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2225                 0.5, /* Power */
2226             },
2227             NULL, /* pTextureFilename */
2228         },
2229         {
2230             {
2231                 {1.0, 1.0, 1.0, 1.0}, /* Diffuse */
2232                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2233                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2234                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2235                 1.0, /* Power */
2236             },
2237             (char *)"texture.jpg", /* pTextureFilename */
2238         },
2239     };
2240     static const char box_anim_xfile[] =
2241         "xof 0303txt 0032"
2242         "Mesh CubeMesh {"
2243         "8;" /* DWORD nVertices; */
2244         /* array Vector vertices[nVertices]; */
2245         "0.0; 0.0; 0.0;,"
2246         "0.0; 0.0; 1.0;,"
2247         "0.0; 1.0; 0.0;,"
2248         "0.0; 1.0; 1.0;,"
2249         "1.0; 0.0; 0.0;,"
2250         "1.0; 0.0; 1.0;,"
2251         "1.0; 1.0; 0.0;,"
2252         "1.0; 1.0; 1.0;;"
2253         "6;" /* DWORD nFaces; */
2254         /* array MeshFace faces[nFaces]; */
2255         "4; 0, 1, 3, 2;," /* left side */
2256         "4; 2, 3, 7, 6;," /* top side */
2257         "4; 6, 7, 5, 4;," /* right side */
2258         "4; 1, 0, 4, 5;," /* bottom side */
2259         "4; 1, 5, 7, 3;," /* back side */
2260         "4; 0, 2, 6, 4;;" /* front side */
2261         "MeshNormals {"
2262         "6;" /* DWORD nNormals; */
2263         /* array Vector normals[nNormals]; */
2264         "-1.0; 0.0; 0.0;,"
2265         "0.0; 1.0; 0.0;,"
2266         "1.0; 0.0; 0.0;,"
2267         "0.0; -1.0; 0.0;,"
2268         "0.0; 0.0; 1.0;,"
2269         "0.0; 0.0; -1.0;;"
2270         "6;" /* DWORD nFaceNormals; */
2271         /* array MeshFace faceNormals[nFaceNormals]; */
2272         "4; 0, 0, 0, 0;,"
2273         "4; 1, 1, 1, 1;,"
2274         "4; 2, 2, 2, 2;,"
2275         "4; 3, 3, 3, 3;,"
2276         "4; 4, 4, 4, 4;,"
2277         "4; 5, 5, 5, 5;;"
2278         "}"
2279         "MeshMaterialList materials {"
2280         "2;" /* DWORD nMaterials; */
2281         "6;" /* DWORD nFaceIndexes; */
2282         /* array DWORD faceIndexes[nFaceIndexes]; */
2283         "0, 0, 0, 1, 1, 1;;"
2284         "Material {"
2285         /* ColorRGBA faceColor; */
2286         "0.0; 0.0; 1.0; 1.0;;"
2287         /* FLOAT power; */
2288         "0.5;"
2289         /* ColorRGB specularColor; */
2290         "1.0; 1.0; 1.0;;"
2291         /* ColorRGB emissiveColor; */
2292         "0.0; 0.0; 0.0;;"
2293         "}"
2294         "Material {"
2295         /* ColorRGBA faceColor; */
2296         "1.0; 1.0; 1.0; 1.0;;"
2297         /* FLOAT power; */
2298         "1.0;"
2299         /* ColorRGB specularColor; */
2300         "1.0; 1.0; 1.0;;"
2301         /* ColorRGB emissiveColor; */
2302         "0.0; 0.0; 0.0;;"
2303         "TextureFilename { \"texture.jpg\"; }"
2304         "}"
2305         "}"
2306         "MeshVertexColors {"
2307         "8;" /* DWORD nVertexColors; */
2308         /* array IndexedColor vertexColors[nVertexColors]; */
2309         "0; 0.0; 0.0; 0.0; 0.0;;"
2310         "1; 0.0; 0.0; 1.0; 0.1;;"
2311         "2; 0.0; 1.0; 0.0; 0.2;;"
2312         "3; 0.0; 1.0; 1.0; 0.3;;"
2313         "4; 1.0; 0.0; 0.0; 0.4;;"
2314         "5; 1.0; 0.0; 1.0; 0.5;;"
2315         "6; 1.0; 1.0; 0.0; 0.6;;"
2316         "7; 1.0; 1.0; 1.0; 0.7;;"
2317         "}"
2318         "MeshTextureCoords {"
2319         "8;" /* DWORD nTextureCoords; */
2320         /* array Coords2d textureCoords[nTextureCoords]; */
2321         "0.0; 1.0;,"
2322         "1.0; 1.0;,"
2323         "0.0; 0.0;,"
2324         "1.0; 0.0;,"
2325         "1.0; 1.0;,"
2326         "0.0; 1.0;,"
2327         "1.0; 0.0;,"
2328         "0.0; 0.0;;"
2329         "}"
2330         "}"
2331         "Frame CubeFrame {"
2332         "FrameTransformMatrix {"
2333         /* Matrix4x4 frameMatrix; */
2334         "1.0, 0.0, 0.0, 0.0,"
2335         "0.0, 1.0, 0.0, 0.0,"
2336         "0.0, 0.0, 1.0, 0.0,"
2337         "0.0, 0.0, 0.0, 1.0;;"
2338         "}"
2339         "{CubeMesh}"
2340         "}"
2341         "AnimationSet AnimationSet0 {"
2342         "Animation Animation0 {"
2343         "{CubeFrame}"
2344         "AnimationKey {"
2345         "2;" /* DWORD keyType; */
2346         "9;" /* DWORD nKeys; */
2347         /* array TimedFloatKeys keys[nKeys]; */
2348         "10; 3; -100.0, 0.0, 0.0;;,"
2349         "20; 3; -75.0,  0.0, 0.0;;,"
2350         "30; 3; -50.0,  0.0, 0.0;;,"
2351         "40; 3; -25.5,  0.0, 0.0;;,"
2352         "50; 3; 0.0,    0.0, 0.0;;,"
2353         "60; 3; 25.5,   0.0, 0.0;;,"
2354         "70; 3; 50.0,   0.0, 0.0;;,"
2355         "80; 3; 75.5,   0.0, 0.0;;,"
2356         "90; 3; 100.0,  0.0, 0.0;;;"
2357         "}"
2358         "}"
2359         "}";
2360 
2361     const DWORD box_fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
2362     /*________________________*/
2363     static const D3DXMATERIAL default_materials[] = {
2364         {
2365             {
2366                 {0.5, 0.5, 0.5, 0.0}, /* Diffuse */
2367                 {0.0, 0.0, 0.0, 0.0}, /* Ambient */
2368                 {0.5, 0.5, 0.5, 0.0}, /* Specular */
2369                 {0.0, 0.0, 0.0, 0.0}, /* Emissive */
2370                 0.0, /* Power */
2371             },
2372             NULL, /* pTextureFilename */
2373         }
2374     };
2375     HRESULT hr;
2376     IDirect3DDevice9 *device = NULL;
2377     ID3DXMesh *mesh = NULL;
2378     D3DXFRAME *frame_hier = NULL;
2379     D3DXMATRIX transform;
2380     struct test_context *test_context;
2381     ID3DXAnimationController *controller;
2382 
2383     if (!(test_context = new_test_context()))
2384     {
2385         skip("Couldn't create test context\n");
2386         return;
2387     }
2388     device = test_context->device;
2389 
2390     hr = D3DXLoadMeshHierarchyFromXInMemory(NULL, sizeof(simple_xfile) - 1,
2391             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2392     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2393 
2394     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, 0,
2395             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2396     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2397 
2398     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2399             D3DXMESH_MANAGED, NULL, &alloc_hier, NULL, &frame_hier, NULL);
2400     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2401 
2402     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2403             D3DXMESH_MANAGED, device, NULL, NULL, &frame_hier, NULL);
2404     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2405 
2406     hr = D3DXLoadMeshHierarchyFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1,
2407             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2408     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2409 
2410     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2411             D3DXMESH_MANAGED, device, &alloc_hier, NULL, NULL, NULL);
2412     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2413 
2414     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2415             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2416     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2417     if (SUCCEEDED(hr)) {
2418         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2419 
2420         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2421         D3DXMatrixIdentity(&transform);
2422         check_matrix(&frame_hier->TransformationMatrix, &transform);
2423 
2424         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2425         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2426            D3DXMESHTYPE_MESH, container->MeshData.Type);
2427         mesh = U(container->MeshData).pMesh;
2428         check_vertex_buffer(mesh, simple_vertex_buffer, ARRAY_SIZE(simple_vertex_buffer), simple_fvf);
2429         check_index_buffer(mesh, simple_index_buffer, ARRAY_SIZE(simple_index_buffer), sizeof(*simple_index_buffer));
2430         check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2431         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2432         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2433         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2434         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2435         frame_hier = NULL;
2436     }
2437 
2438     controller = (ID3DXAnimationController *)0xdeadbeef;
2439     hr = D3DXLoadMeshHierarchyFromXInMemory(box_anim_xfile, sizeof(box_anim_xfile) - 1,
2440             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2441     todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2442     if (SUCCEEDED(hr))
2443     {
2444         ok(controller != NULL, "Animation Controller NULL.\n");
2445 
2446         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2447         ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2448         if (controller)
2449             controller->lpVtbl->Release(controller);
2450 
2451         frame_hier = NULL;
2452     }
2453 
2454     controller = (ID3DXAnimationController *)0xdeadbeef;
2455     hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1,
2456             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2457     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2458     if (SUCCEEDED(hr))
2459     {
2460         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2461 
2462         ok(!controller, "Animation Controller returned.\n");
2463         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2464         D3DXMatrixIdentity(&transform);
2465         check_matrix(&frame_hier->TransformationMatrix, &transform);
2466 
2467         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2468         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2469            D3DXMESHTYPE_MESH, container->MeshData.Type);
2470         mesh = U(container->MeshData).pMesh;
2471         check_vertex_buffer(mesh, box_vertex_buffer, ARRAY_SIZE(box_vertex_buffer), box_fvf);
2472         check_index_buffer(mesh, box_index_buffer, ARRAY_SIZE(box_index_buffer), sizeof(*box_index_buffer));
2473         check_materials(container->pMaterials, container->NumMaterials, box_materials, ARRAY_SIZE(box_materials));
2474         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2475         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2476         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2477         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2478         frame_hier = NULL;
2479     }
2480 
2481     hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1,
2482             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2483     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2484     if (SUCCEEDED(hr)) {
2485         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2486         int i;
2487 
2488         ok(!strcmp(frame_hier->Name, ""), "Expected '', got '%s'\n", frame_hier->Name);
2489         /* last frame transform replaces the first */
2490         D3DXMatrixIdentity(&transform);
2491         U(transform).m[3][2] = 3.0;
2492         check_matrix(&frame_hier->TransformationMatrix, &transform);
2493 
2494         for (i = 0; i < 3; i++) {
2495             ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2496             ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2497                D3DXMESHTYPE_MESH, container->MeshData.Type);
2498             mesh = U(container->MeshData).pMesh;
2499             check_vertex_buffer(mesh, framed_vertex_buffers[i], ARRAY_SIZE(framed_vertex_buffers[0]), framed_fvf);
2500             check_index_buffer(mesh, framed_index_buffer, ARRAY_SIZE(framed_index_buffer), sizeof(*framed_index_buffer));
2501             check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2502             check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2503             check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2504             container = container->pNextMeshContainer;
2505         }
2506         ok(container == NULL, "Expected NULL, got %p\n", container);
2507         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2508         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2509         frame_hier = NULL;
2510     }
2511 
2512 
2513     hr = D3DXLoadMeshFromXInMemory(NULL, 0, D3DXMESH_MANAGED,
2514                                    device, NULL, NULL, NULL, NULL, &mesh);
2515     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2516 
2517     hr = D3DXLoadMeshFromXInMemory(NULL, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2518                                    device, NULL, NULL, NULL, NULL, &mesh);
2519     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2520 
2521     hr = D3DXLoadMeshFromXInMemory(simple_xfile, 0, D3DXMESH_MANAGED,
2522                                    device, NULL, NULL, NULL, NULL, &mesh);
2523     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2524 
2525     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2526                                    device, NULL, NULL, NULL, NULL, NULL);
2527     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2528 
2529     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2530                                    NULL, NULL, NULL, NULL, NULL, &mesh);
2531     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2532 
2533     hr = D3DXLoadMeshFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1, D3DXMESH_MANAGED,
2534                                    device, NULL, NULL, NULL, NULL, &mesh);
2535     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2536 
2537     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2538                                    device, NULL, NULL, NULL, NULL, &mesh);
2539     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2540     if (SUCCEEDED(hr))
2541         IUnknown_Release(mesh);
2542 
2543     test_LoadMeshFromX(device, simple_xfile, simple_vertex_buffer, simple_fvf, simple_index_buffer, default_materials, TRUE);
2544     test_LoadMeshFromX(device, box_xfile, box_vertex_buffer, box_fvf, box_index_buffer, box_materials, TRUE);
2545     test_LoadMeshFromX(device, framed_xfile, merged_vertex_buffer, framed_fvf, merged_index_buffer, default_materials, FALSE);
2546 
2547     free_test_context(test_context);
2548 }
2549 
2550 static ID3DXFileData *get_mesh_data(const char *memory, SIZE_T length)
2551 {
2552     D3DXF_FILELOADMEMORY source;
2553     ID3DXFileEnumObject *enumobj = NULL;
2554     ID3DXFileData *filedata = NULL;
2555     ID3DXFileData *ret = NULL;
2556     ID3DXFile *d3dxfile = NULL;
2557     SIZE_T i, nb_children;
2558     HRESULT hr;
2559     GUID guid;
2560 
2561     hr = D3DXFileCreate(&d3dxfile);
2562     if (FAILED(hr)) return NULL;
2563 
2564     hr = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES);
2565     if (FAILED(hr)) goto cleanup;
2566 
2567     source.lpMemory = (void *)memory;
2568     source.dSize    = length;
2569 
2570     hr = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &source, D3DXF_FILELOAD_FROMMEMORY, &enumobj);
2571     if (FAILED(hr)) goto cleanup;
2572 
2573     hr = enumobj->lpVtbl->GetChildren(enumobj, &nb_children);
2574     if (FAILED(hr)) goto cleanup;
2575 
2576     for (i = 0; i < nb_children; i++)
2577     {
2578         hr = enumobj->lpVtbl->GetChild(enumobj, i, &filedata);
2579         if (FAILED(hr)) goto cleanup;
2580 
2581         hr = filedata->lpVtbl->GetType(filedata, &guid);
2582         if (SUCCEEDED(hr) && IsEqualGUID(&guid, &TID_D3DRMMesh))
2583         {
2584             ret = filedata;
2585             break;
2586         }
2587         else
2588             filedata->lpVtbl->Release(filedata);
2589     }
2590 
2591 cleanup:
2592     if (enumobj) enumobj->lpVtbl->Release(enumobj);
2593     if (d3dxfile) d3dxfile->lpVtbl->Release(d3dxfile);
2594 
2595     return ret;
2596 }
2597 
2598 static void D3DXLoadSkinMeshFromXofTest(void)
2599 {
2600     static const char simple_xfile[] =
2601         "xof 0303txt 0032"
2602         "Mesh {"
2603             "3;"
2604             "0.0; 0.0; 0.0;,"
2605             "0.0; 1.0; 0.0;,"
2606             "1.0; 1.0; 0.0;;"
2607             "1;"
2608             "3; 0, 1, 2;;"
2609         "}";
2610     ID3DXBuffer *adjacency, *materials, *effects;
2611     D3DPRESENT_PARAMETERS d3dpp;
2612     IDirect3DDevice9 *device;
2613     ID3DXFileData *filedata;
2614     ID3DXSkinInfo *skininfo;
2615     ID3DXMesh *mesh;
2616     IDirect3D9 *d3d;
2617     DWORD mat_count;
2618     HRESULT hr;
2619     HWND hwnd;
2620 
2621     if (!(hwnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
2622             640, 480, NULL, NULL, NULL, NULL)))
2623     {
2624         skip("Couldn't create application window\n");
2625         return;
2626     }
2627 
2628     d3d = Direct3DCreate9(D3D_SDK_VERSION);
2629     if (!d3d)
2630     {
2631         skip("Couldn't create IDirect3D9 object\n");
2632         DestroyWindow(hwnd);
2633         return;
2634     }
2635 
2636     ZeroMemory(&d3dpp, sizeof(d3dpp));
2637     d3dpp.Windowed   = TRUE;
2638     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2639 
2640     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
2641     IDirect3D9_Release(d3d);
2642     if (FAILED(hr))
2643     {
2644         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2645         DestroyWindow(hwnd);
2646         return;
2647     }
2648 
2649     filedata = get_mesh_data(simple_xfile, sizeof(simple_xfile) - 1);
2650     ok(filedata != NULL, "Failed to load mesh data\n");
2651 
2652     adjacency = materials = effects = NULL;
2653     skininfo = NULL;
2654     mesh = NULL;
2655 
2656     hr = D3DXLoadSkinMeshFromXof(filedata, 0, device, &adjacency, &materials, &effects, &mat_count, &skininfo, &mesh);
2657     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2658     ok(skininfo != NULL, "Expected non-null skininfo\n");
2659 
2660     /* FIXME: Add additional tests for skininfo interface. */
2661 
2662     if (adjacency) adjacency->lpVtbl->Release(adjacency);
2663     if (materials) materials->lpVtbl->Release(materials);
2664     if (effects) effects->lpVtbl->Release(effects);
2665     if (skininfo) skininfo->lpVtbl->Release(skininfo);
2666     if (mesh) mesh->lpVtbl->Release(mesh);
2667 
2668     filedata->lpVtbl->Release(filedata);
2669     IDirect3DDevice9_Release(device);
2670     DestroyWindow(hwnd);
2671 }
2672 
2673 static BOOL compute_box(struct mesh *mesh, float width, float height, float depth)
2674 {
2675     unsigned int i, face;
2676     static const D3DXVECTOR3 unit_box[] =
2677     {
2678         {-1.0f, -1.0f, -1.0f}, {-1.0f, -1.0f,  1.0f}, {-1.0f,  1.0f,  1.0f}, {-1.0f,  1.0f, -1.0f},
2679         {-1.0f,  1.0f, -1.0f}, {-1.0f,  1.0f,  1.0f}, { 1.0f,  1.0f,  1.0f}, { 1.0f,  1.0f, -1.0f},
2680         { 1.0f,  1.0f, -1.0f}, { 1.0f,  1.0f,  1.0f}, { 1.0f, -1.0f,  1.0f}, { 1.0f, -1.0f, -1.0f},
2681         {-1.0f, -1.0f,  1.0f}, {-1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f,  1.0f},
2682         {-1.0f, -1.0f,  1.0f}, { 1.0f, -1.0f,  1.0f}, { 1.0f,  1.0f,  1.0f}, {-1.0f,  1.0f,  1.0f},
2683         {-1.0f, -1.0f, -1.0f}, {-1.0f,  1.0f, -1.0f}, { 1.0f,  1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}
2684     };
2685     static const D3DXVECTOR3 normals[] =
2686     {
2687         {-1.0f,  0.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f,  0.0f},
2688         { 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, -1.0f}
2689     };
2690 
2691     if (!new_mesh(mesh, 24, 12))
2692     {
2693         return FALSE;
2694     }
2695 
2696     width /= 2.0f;
2697     height /= 2.0f;
2698     depth /= 2.0f;
2699 
2700     for (i = 0; i < 24; i++)
2701     {
2702         mesh->vertices[i].position.x = width * unit_box[i].x;
2703         mesh->vertices[i].position.y = height * unit_box[i].y;
2704         mesh->vertices[i].position.z = depth * unit_box[i].z;
2705         mesh->vertices[i].normal.x = normals[i / 4].x;
2706         mesh->vertices[i].normal.y = normals[i / 4].y;
2707         mesh->vertices[i].normal.z = normals[i / 4].z;
2708     }
2709 
2710     face = 0;
2711     for (i = 0; i < 12; i++)
2712     {
2713         mesh->faces[i][0] = face++;
2714         mesh->faces[i][1] = face++;
2715         mesh->faces[i][2] = (i % 2) ? face - 4 : face;
2716     }
2717 
2718     return TRUE;
2719 }
2720 
2721 static void test_box(IDirect3DDevice9 *device, float width, float height, float depth)
2722 {
2723     HRESULT hr;
2724     ID3DXMesh *box;
2725     struct mesh mesh;
2726     char name[256];
2727 
2728     hr = D3DXCreateBox(device, width, height, depth, &box, NULL);
2729     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2730     if (hr != D3D_OK)
2731     {
2732         skip("Couldn't create box\n");
2733         return;
2734     }
2735 
2736     if (!compute_box(&mesh, width, height, depth))
2737     {
2738         skip("Couldn't create mesh\n");
2739         box->lpVtbl->Release(box);
2740         return;
2741     }
2742 
2743     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2744 
2745     sprintf(name, "box (%g, %g, %g)", width, height, depth);
2746     compare_mesh(name, box, &mesh);
2747 
2748     free_mesh(&mesh);
2749 
2750     box->lpVtbl->Release(box);
2751 }
2752 static void D3DXCreateBoxTest(void)
2753 {
2754     HRESULT hr;
2755     IDirect3DDevice9* device;
2756     ID3DXMesh* box;
2757     ID3DXBuffer* ppBuffer;
2758     DWORD *buffer;
2759     static const DWORD adjacency[36]=
2760         {6, 9, 1, 2, 10, 0,
2761          1, 9, 3, 4, 10, 2,
2762          3, 8, 5, 7, 11, 4,
2763          0, 11, 7, 5, 8, 6,
2764          7, 4, 9, 2, 0, 8,
2765          1, 3, 11, 5, 6, 10};
2766     unsigned int i;
2767     struct test_context *test_context;
2768 
2769     if (!(test_context = new_test_context()))
2770     {
2771         skip("Couldn't create test context\n");
2772         return;
2773     }
2774     device = test_context->device;
2775 
2776     hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
2777     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2778 
2779     hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
2780     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2781 
2782     hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
2783     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2784 
2785     hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
2786     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2787 
2788     hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
2789     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2790 
2791     ppBuffer = NULL;
2792     hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
2793     ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2794 
2795     buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
2796     for(i=0; i<36; i++)
2797         ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
2798 
2799     box->lpVtbl->Release(box);
2800     ID3DXBuffer_Release(ppBuffer);
2801 
2802     test_box(device, 10.9f, 20.0f, 4.9f);
2803 
2804     free_test_context(test_context);
2805 }
2806 
2807 static BOOL compute_polygon(struct mesh *mesh, float length, unsigned int sides)
2808 {
2809     unsigned int i;
2810     float angle, scale;
2811 
2812     if (!new_mesh(mesh, sides + 1, sides))
2813         return FALSE;
2814 
2815     angle = D3DX_PI / sides;
2816     scale = 0.5f * length / sinf(angle);
2817     angle *= 2.0f;
2818 
2819     mesh->vertices[0].position.x = 0.0f;
2820     mesh->vertices[0].position.y = 0.0f;
2821     mesh->vertices[0].position.z = 0.0f;
2822     mesh->vertices[0].normal.x = 0.0f;
2823     mesh->vertices[0].normal.y = 0.0f;
2824     mesh->vertices[0].normal.z = 1.0f;
2825 
2826     for (i = 0; i < sides; ++i)
2827     {
2828         mesh->vertices[i + 1].position.x = cosf(angle * i) * scale;
2829         mesh->vertices[i + 1].position.y = sinf(angle * i) * scale;
2830         mesh->vertices[i + 1].position.z = 0.0f;
2831         mesh->vertices[i + 1].normal.x = 0.0f;
2832         mesh->vertices[i + 1].normal.y = 0.0f;
2833         mesh->vertices[i + 1].normal.z = 1.0f;
2834 
2835         mesh->faces[i][0] = 0;
2836         mesh->faces[i][1] = i + 1;
2837         mesh->faces[i][2] = i + 2;
2838     }
2839 
2840     mesh->faces[sides - 1][2] = 1;
2841 
2842     return TRUE;
2843 }
2844 
2845 static void test_polygon(IDirect3DDevice9 *device, float length, unsigned int sides)
2846 {
2847     HRESULT hr;
2848     ID3DXMesh *polygon;
2849     struct mesh mesh;
2850     char name[64];
2851 
2852     hr = D3DXCreatePolygon(device, length, sides, &polygon, NULL);
2853     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2854     if (hr != D3D_OK)
2855     {
2856         skip("Couldn't create polygon\n");
2857         return;
2858     }
2859 
2860     if (!compute_polygon(&mesh, length, sides))
2861     {
2862         skip("Couldn't create mesh\n");
2863         polygon->lpVtbl->Release(polygon);
2864         return;
2865     }
2866 
2867     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2868 
2869     sprintf(name, "polygon (%g, %u)", length, sides);
2870     compare_mesh(name, polygon, &mesh);
2871 
2872     free_mesh(&mesh);
2873 
2874     polygon->lpVtbl->Release(polygon);
2875 }
2876 
2877 static void D3DXCreatePolygonTest(void)
2878 {
2879     HRESULT hr;
2880     IDirect3DDevice9 *device;
2881     ID3DXMesh *polygon;
2882     ID3DXBuffer *adjacency;
2883     DWORD (*buffer)[3], buffer_size;
2884     unsigned int i;
2885     struct test_context *test_context;
2886 
2887     if (!(test_context = new_test_context()))
2888     {
2889         skip("Couldn't create test context\n");
2890         return;
2891     }
2892     device = test_context->device;
2893 
2894     hr = D3DXCreatePolygon(device, 2.0f, 11, NULL, &adjacency);
2895     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2896 
2897     hr = D3DXCreatePolygon(NULL, 2.0f, 11, &polygon, &adjacency);
2898     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2899 
2900     hr = D3DXCreatePolygon(device, -2.0f, 11, &polygon, &adjacency);
2901     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2902 
2903     polygon = (void *)0xdeadbeef;
2904     adjacency = (void *)0xdeadbeef;
2905     hr = D3DXCreatePolygon(device, 2.0f, 0, &polygon, &adjacency);
2906     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2907     ok(polygon == (void *)0xdeadbeef, "Polygon was changed to %p\n", polygon);
2908     ok(adjacency == (void *)0xdeadbeef, "Adjacency was changed to %p\n", adjacency);
2909 
2910     hr = D3DXCreatePolygon(device, 2.0f, 2, &polygon, &adjacency);
2911     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2912 
2913     adjacency = NULL;
2914     hr = D3DXCreatePolygon(device, 3.0f, 11, &polygon, &adjacency);
2915     ok(hr == D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2916 
2917     buffer_size = ID3DXBuffer_GetBufferSize(adjacency);
2918     ok(buffer_size == 33 * sizeof(DWORD), "Wrong adjacency buffer size %u\n", buffer_size);
2919 
2920     buffer = ID3DXBuffer_GetBufferPointer(adjacency);
2921     for (i = 0; i < 11; ++i)
2922     {
2923         ok(buffer[i][0] == (i + 10) % 11, "Wrong adjacency[%d][0] = %u\n", i, buffer[i][0]);
2924         ok(buffer[i][1] == ~0U, "Wrong adjacency[%d][1] = %u\n", i, buffer[i][1]);
2925         ok(buffer[i][2] == (i + 1) % 11, "Wrong adjacency[%d][2] = %u\n", i, buffer[i][2]);
2926     }
2927 
2928     polygon->lpVtbl->Release(polygon);
2929     ID3DXBuffer_Release(adjacency);
2930 
2931     test_polygon(device, 2.0f, 3);
2932     test_polygon(device, 10.0f, 3);
2933     test_polygon(device, 10.0f, 5);
2934     test_polygon(device, 10.0f, 10);
2935     test_polygon(device, 20.0f, 10);
2936     test_polygon(device, 20.0f, 32000);
2937 
2938     free_test_context(test_context);
2939 }
2940 
2941 struct sincos_table
2942 {
2943     float *sin;
2944     float *cos;
2945 };
2946 
2947 static void free_sincos_table(struct sincos_table *sincos_table)
2948 {
2949     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
2950     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2951 }
2952 
2953 /* pre compute sine and cosine tables; caller must free */
2954 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
2955 {
2956     float angle;
2957     int i;
2958 
2959     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2960     if (!sincos_table->sin)
2961     {
2962         return FALSE;
2963     }
2964     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2965     if (!sincos_table->cos)
2966     {
2967         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2968         return FALSE;
2969     }
2970 
2971     angle = angle_start;
2972     for (i = 0; i < n; i++)
2973     {
2974         sincos_table->sin[i] = sin(angle);
2975         sincos_table->cos[i] = cos(angle);
2976         angle += angle_step;
2977     }
2978 
2979     return TRUE;
2980 }
2981 
2982 static WORD vertex_index(UINT slices, int slice, int stack)
2983 {
2984     return stack*slices+slice+1;
2985 }
2986 
2987 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
2988 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
2989 {
2990     float theta_step, theta_start;
2991     struct sincos_table theta;
2992     float phi_step, phi_start;
2993     struct sincos_table phi;
2994     DWORD number_of_vertices, number_of_faces;
2995     DWORD vertex, face;
2996     int slice, stack;
2997 
2998     /* theta = angle on xy plane wrt x axis */
2999     theta_step = D3DX_PI / stacks;
3000     theta_start = theta_step;
3001 
3002     /* phi = angle on xz plane wrt z axis */
3003     phi_step = -2 * D3DX_PI / slices;
3004     phi_start = D3DX_PI / 2;
3005 
3006     if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
3007     {
3008         return FALSE;
3009     }
3010     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
3011     {
3012         free_sincos_table(&theta);
3013         return FALSE;
3014     }
3015 
3016     number_of_vertices = 2 + slices * (stacks-1);
3017     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
3018 
3019     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
3020     {
3021         free_sincos_table(&phi);
3022         free_sincos_table(&theta);
3023         return FALSE;
3024     }
3025 
3026     vertex = 0;
3027     face = 0;
3028 
3029     mesh->vertices[vertex].normal.x = 0.0f;
3030     mesh->vertices[vertex].normal.y = 0.0f;
3031     mesh->vertices[vertex].normal.z = 1.0f;
3032     mesh->vertices[vertex].position.x = 0.0f;
3033     mesh->vertices[vertex].position.y = 0.0f;
3034     mesh->vertices[vertex].position.z = radius;
3035     vertex++;
3036 
3037     for (stack = 0; stack < stacks - 1; stack++)
3038     {
3039         for (slice = 0; slice < slices; slice++)
3040         {
3041             mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
3042             mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
3043             mesh->vertices[vertex].normal.z = theta.cos[stack];
3044             mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
3045             mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
3046             mesh->vertices[vertex].position.z = radius * theta.cos[stack];
3047             vertex++;
3048 
3049             if (slice > 0)
3050             {
3051                 if (stack == 0)
3052                 {
3053                     /* top stack is triangle fan */
3054                     mesh->faces[face][0] = 0;
3055                     mesh->faces[face][1] = slice + 1;
3056                     mesh->faces[face][2] = slice;
3057                     face++;
3058                 }
3059                 else
3060                 {
3061                     /* stacks in between top and bottom are quad strips */
3062                     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3063                     mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
3064                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
3065                     face++;
3066 
3067                     mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
3068                     mesh->faces[face][1] = vertex_index(slices, slice, stack);
3069                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
3070                     face++;
3071                 }
3072             }
3073         }
3074 
3075         if (stack == 0)
3076         {
3077             mesh->faces[face][0] = 0;
3078             mesh->faces[face][1] = 1;
3079             mesh->faces[face][2] = slice;
3080             face++;
3081         }
3082         else
3083         {
3084             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3085             mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
3086             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
3087             face++;
3088 
3089             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
3090             mesh->faces[face][1] = vertex_index(slices, 0, stack);
3091             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
3092             face++;
3093         }
3094     }
3095 
3096     mesh->vertices[vertex].position.x = 0.0f;
3097     mesh->vertices[vertex].position.y = 0.0f;
3098     mesh->vertices[vertex].position.z = -radius;
3099     mesh->vertices[vertex].normal.x = 0.0f;
3100     mesh->vertices[vertex].normal.y = 0.0f;
3101     mesh->vertices[vertex].normal.z = -1.0f;
3102 
3103     /* bottom stack is triangle fan */
3104     for (slice = 1; slice < slices; slice++)
3105     {
3106         mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3107         mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
3108         mesh->faces[face][2] = vertex;
3109         face++;
3110     }
3111 
3112     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3113     mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
3114     mesh->faces[face][2] = vertex;
3115 
3116     free_sincos_table(&phi);
3117     free_sincos_table(&theta);
3118 
3119     return TRUE;
3120 }
3121 
3122 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
3123 {
3124     HRESULT hr;
3125     ID3DXMesh *sphere;
3126     struct mesh mesh;
3127     char name[256];
3128 
3129     hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
3130     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3131     if (hr != D3D_OK)
3132     {
3133         skip("Couldn't create sphere\n");
3134         return;
3135     }
3136 
3137     if (!compute_sphere(&mesh, radius, slices, stacks))
3138     {
3139         skip("Couldn't create mesh\n");
3140         sphere->lpVtbl->Release(sphere);
3141         return;
3142     }
3143 
3144     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3145 
3146     sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
3147     compare_mesh(name, sphere, &mesh);
3148 
3149     free_mesh(&mesh);
3150 
3151     sphere->lpVtbl->Release(sphere);
3152 }
3153 
3154 static void D3DXCreateSphereTest(void)
3155 {
3156     HRESULT hr;
3157     IDirect3DDevice9* device;
3158     ID3DXMesh* sphere = NULL;
3159     struct test_context *test_context;
3160 
3161     hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
3162     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3163 
3164     hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
3165     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3166 
3167     hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
3168     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3169 
3170     hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
3171     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3172 
3173     if (!(test_context = new_test_context()))
3174     {
3175         skip("Couldn't create test context\n");
3176         return;
3177     }
3178     device = test_context->device;
3179 
3180     hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
3181     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3182 
3183     hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
3184     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3185 
3186     hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
3187     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3188 
3189     hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
3190     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3191 
3192     test_sphere(device, 0.0f, 2, 2);
3193     test_sphere(device, 1.0f, 2, 2);
3194     test_sphere(device, 1.0f, 3, 2);
3195     test_sphere(device, 1.0f, 4, 4);
3196     test_sphere(device, 1.0f, 3, 4);
3197     test_sphere(device, 5.0f, 6, 7);
3198     test_sphere(device, 10.0f, 11, 12);
3199 
3200     free_test_context(test_context);
3201 }
3202 
3203 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3204 {
3205     float theta_step, theta_start;
3206     struct sincos_table theta;
3207     FLOAT delta_radius, radius, radius_step;
3208     FLOAT z, z_step, z_normal;
3209     DWORD number_of_vertices, number_of_faces;
3210     DWORD vertex, face;
3211     int slice, stack;
3212 
3213     /* theta = angle on xy plane wrt x axis */
3214     theta_step = -2 * D3DX_PI / slices;
3215     theta_start = D3DX_PI / 2;
3216 
3217     if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
3218     {
3219         return FALSE;
3220     }
3221 
3222     number_of_vertices = 2 + (slices * (3 + stacks));
3223     number_of_faces = 2 * slices + stacks * (2 * slices);
3224 
3225     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
3226     {
3227         free_sincos_table(&theta);
3228         return FALSE;
3229     }
3230 
3231     vertex = 0;
3232     face = 0;
3233 
3234     delta_radius = radius1 - radius2;
3235     radius = radius1;
3236     radius_step = delta_radius / stacks;
3237 
3238     z = -length / 2;
3239     z_step = length / stacks;
3240     z_normal = delta_radius / length;
3241     if (isnan(z_normal))
3242     {
3243         z_normal = 0.0f;
3244     }
3245 
3246     mesh->vertices[vertex].normal.x = 0.0f;
3247     mesh->vertices[vertex].normal.y = 0.0f;
3248     mesh->vertices[vertex].normal.z = -1.0f;
3249     mesh->vertices[vertex].position.x = 0.0f;
3250     mesh->vertices[vertex].position.y = 0.0f;
3251     mesh->vertices[vertex++].position.z = z;
3252 
3253     for (slice = 0; slice < slices; slice++, vertex++)
3254     {
3255         mesh->vertices[vertex].normal.x = 0.0f;
3256         mesh->vertices[vertex].normal.y = 0.0f;
3257         mesh->vertices[vertex].normal.z = -1.0f;
3258         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3259         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3260         mesh->vertices[vertex].position.z = z;
3261 
3262         if (slice > 0)
3263         {
3264             mesh->faces[face][0] = 0;
3265             mesh->faces[face][1] = slice;
3266             mesh->faces[face++][2] = slice + 1;
3267         }
3268     }
3269 
3270     mesh->faces[face][0] = 0;
3271     mesh->faces[face][1] = slice;
3272     mesh->faces[face++][2] = 1;
3273 
3274     for (stack = 1; stack <= stacks+1; stack++)
3275     {
3276         for (slice = 0; slice < slices; slice++, vertex++)
3277         {
3278             mesh->vertices[vertex].normal.x = theta.cos[slice];
3279             mesh->vertices[vertex].normal.y = theta.sin[slice];
3280             mesh->vertices[vertex].normal.z = z_normal;
3281             D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
3282             mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3283             mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3284             mesh->vertices[vertex].position.z = z;
3285 
3286             if (stack > 1 && slice > 0)
3287             {
3288                 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3289                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3290                 mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
3291 
3292                 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
3293                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3294                 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3295             }
3296         }
3297 
3298         if (stack > 1)
3299         {
3300             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3301             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3302             mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
3303 
3304             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
3305             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3306             mesh->faces[face++][2] = vertex_index(slices, 0, stack);
3307         }
3308 
3309         if (stack < stacks + 1)
3310         {
3311             z += z_step;
3312             radius -= radius_step;
3313         }
3314     }
3315 
3316     for (slice = 0; slice < slices; slice++, vertex++)
3317     {
3318         mesh->vertices[vertex].normal.x = 0.0f;
3319         mesh->vertices[vertex].normal.y = 0.0f;
3320         mesh->vertices[vertex].normal.z = 1.0f;
3321         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3322         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3323         mesh->vertices[vertex].position.z = z;
3324 
3325         if (slice > 0)
3326         {
3327             mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3328             mesh->faces[face][1] = number_of_vertices - 1;
3329             mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3330         }
3331     }
3332 
3333     mesh->vertices[vertex].position.x = 0.0f;
3334     mesh->vertices[vertex].position.y = 0.0f;
3335     mesh->vertices[vertex].position.z = z;
3336     mesh->vertices[vertex].normal.x = 0.0f;
3337     mesh->vertices[vertex].normal.y = 0.0f;
3338     mesh->vertices[vertex].normal.z = 1.0f;
3339 
3340     mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3341     mesh->faces[face][1] = number_of_vertices - 1;
3342     mesh->faces[face][2] = vertex_index(slices, 0, stack);
3343 
3344     free_sincos_table(&theta);
3345 
3346     return TRUE;
3347 }
3348 
3349 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3350 {
3351     HRESULT hr;
3352     ID3DXMesh *cylinder;
3353     struct mesh mesh;
3354     char name[256];
3355 
3356     hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
3357     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3358     if (hr != D3D_OK)
3359     {
3360         skip("Couldn't create cylinder\n");
3361         return;
3362     }
3363 
3364     if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
3365     {
3366         skip("Couldn't create mesh\n");
3367         cylinder->lpVtbl->Release(cylinder);
3368         return;
3369     }
3370 
3371     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3372 
3373     sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
3374     compare_mesh(name, cylinder, &mesh);
3375 
3376     free_mesh(&mesh);
3377 
3378     cylinder->lpVtbl->Release(cylinder);
3379 }
3380 
3381 static void D3DXCreateCylinderTest(void)
3382 {
3383     HRESULT hr;
3384     IDirect3DDevice9* device;
3385     ID3DXMesh* cylinder = NULL;
3386     struct test_context *test_context;
3387 
3388     hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
3389     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3390 
3391     hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3392     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3393 
3394     if (!(test_context = new_test_context()))
3395     {
3396         skip("Couldn't create test context\n");
3397         return;
3398     }
3399     device = test_context->device;
3400 
3401     hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3402     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3403 
3404     hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3405     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3406 
3407     if (SUCCEEDED(hr) && cylinder)
3408     {
3409         cylinder->lpVtbl->Release(cylinder);
3410     }
3411 
3412     hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
3413     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3414 
3415     hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
3416     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3417 
3418     if (SUCCEEDED(hr) && cylinder)
3419     {
3420         cylinder->lpVtbl->Release(cylinder);
3421     }
3422 
3423     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
3424     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3425 
3426     /* Test with length == 0.0f succeeds */
3427     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
3428     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3429 
3430     if (SUCCEEDED(hr) && cylinder)
3431     {
3432         cylinder->lpVtbl->Release(cylinder);
3433     }
3434 
3435     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
3436     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3437 
3438     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
3439     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3440 
3441     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
3442     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3443 
3444     test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
3445     test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
3446     test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
3447     test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
3448     test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
3449     test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
3450 
3451     free_test_context(test_context);
3452 }
3453 
3454 static BOOL compute_torus(struct mesh *mesh, float innerradius, float outerradius, UINT sides, UINT rings)
3455 {
3456     float phi, phi_step, sin_phi, cos_phi;
3457     float theta, theta_step, sin_theta, cos_theta;
3458     unsigned int numvert, numfaces, i, j;
3459 
3460     numvert = sides * rings;
3461     numfaces = numvert * 2;
3462 
3463     if (!new_mesh(mesh, numvert, numfaces))
3464         return FALSE;
3465 
3466     phi_step = D3DX_PI / sides * 2.0f;
3467     theta_step = D3DX_PI / rings * -2.0f;
3468 
3469     theta = 0.0f;
3470 
3471     for (i = 0; i < rings; ++i)
3472     {
3473         phi = 0.0f;
3474 
3475         cos_theta = cosf(theta);
3476         sin_theta = sinf(theta);
3477 
3478         for (j = 0; j < sides; ++j)
3479         {
3480             sin_phi = sinf(phi);
3481             cos_phi = cosf(phi);
3482 
3483             mesh->vertices[i * sides + j].position.x = (innerradius * cos_phi + outerradius) * cos_theta;
3484             mesh->vertices[i * sides + j].position.y = (innerradius * cos_phi + outerradius) * sin_theta;
3485             mesh->vertices[i * sides + j].position.z = innerradius * sin_phi;
3486             mesh->vertices[i * sides + j].normal.x = cos_phi * cos_theta;
3487             mesh->vertices[i * sides + j].normal.y = cos_phi * sin_theta;
3488             mesh->vertices[i * sides + j].normal.z = sin_phi;
3489 
3490             phi += phi_step;
3491         }
3492 
3493         theta += theta_step;
3494     }
3495 
3496     for (i = 0; i < numfaces - sides * 2; ++i)
3497     {
3498         mesh->faces[i][0] = i % 2 ? i / 2 + sides : i / 2;
3499         mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3500         mesh->faces[i][2] = (i + 1) % (sides * 2) ? (i + 1) / 2 + sides : (i + 1) / 2;
3501     }
3502 
3503     for (j = 0; i < numfaces; ++i, ++j)
3504     {
3505         mesh->faces[i][0] = i % 2 ? j / 2 : i / 2;
3506         mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3507         mesh->faces[i][2] = i == numfaces - 1 ? 0 : (j + 1) / 2;
3508     }
3509 
3510     return TRUE;
3511 }
3512 
3513 static void test_torus(IDirect3DDevice9 *device, float innerradius, float outerradius, UINT sides, UINT rings)
3514 {
3515     HRESULT hr;
3516     ID3DXMesh *torus;
3517     struct mesh mesh;
3518     char name[256];
3519 
3520     hr = D3DXCreateTorus(device, innerradius, outerradius, sides, rings, &torus, NULL);
3521     ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK)\n", hr);
3522     if (hr != D3D_OK)
3523     {
3524         skip("Couldn't create torus\n");
3525         return;
3526     }
3527 
3528     if (!compute_torus(&mesh, innerradius, outerradius, sides, rings))
3529     {
3530         skip("Couldn't create mesh\n");
3531         torus->lpVtbl->Release(torus);
3532         return;
3533     }
3534 
3535     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3536 
3537     sprintf(name, "torus (%g, %g, %u, %u)", innerradius, outerradius, sides, rings);
3538     compare_mesh(name, torus, &mesh);
3539 
3540     free_mesh(&mesh);
3541 
3542     torus->lpVtbl->Release(torus);
3543 }
3544 
3545 static void D3DXCreateTorusTest(void)
3546 {
3547     HRESULT hr;
3548     IDirect3DDevice9* device;
3549     ID3DXMesh* torus = NULL;
3550     struct test_context *test_context;
3551 
3552     if (!(test_context = new_test_context()))
3553     {
3554         skip("Couldn't create test context\n");
3555         return;
3556     }
3557     device = test_context->device;
3558 
3559     hr = D3DXCreateTorus(NULL, 0.0f, 0.0f, 3, 3, &torus, NULL);
3560     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3561 
3562     hr = D3DXCreateTorus(device, -1.0f, 0.0f, 3, 3, &torus, NULL);
3563     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3564 
3565     hr = D3DXCreateTorus(device, 0.0f, -1.0f, 3, 3, &torus, NULL);
3566     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3567 
3568     hr = D3DXCreateTorus(device, 0.0f, 0.0f, 2, 3, &torus, NULL);
3569     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3570 
3571     hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 2, &torus, NULL);
3572     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3573 
3574     hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 3, NULL, NULL);
3575     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3576 
3577     test_torus(device, 0.0f, 0.0f, 3, 3);
3578     test_torus(device, 1.0f, 1.0f, 3, 3);
3579     test_torus(device, 1.0f, 1.0f, 32, 64);
3580     test_torus(device, 0.0f, 1.0f, 5, 5);
3581     test_torus(device, 1.0f, 0.0f, 5, 5);
3582     test_torus(device, 5.0f, 0.2f, 8, 8);
3583     test_torus(device, 0.2f, 1.0f, 60, 3);
3584     test_torus(device, 0.2f, 1.0f, 8, 70);
3585 
3586     free_test_context(test_context);
3587 }
3588 
3589 struct dynamic_array
3590 {
3591     int count, capacity;
3592     void *items;
3593 };
3594 
3595 enum pointtype {
3596     POINTTYPE_CURVE = 0,
3597     POINTTYPE_CORNER,
3598     POINTTYPE_CURVE_START,
3599     POINTTYPE_CURVE_END,
3600     POINTTYPE_CURVE_MIDDLE,
3601 };
3602 
3603 struct point2d
3604 {
3605     D3DXVECTOR2 pos;
3606     enum pointtype corner;
3607 };
3608 
3609 /* is a dynamic_array */
3610 struct outline
3611 {
3612     int count, capacity;
3613     struct point2d *items;
3614 };
3615 
3616 /* is a dynamic_array */
3617 struct outline_array
3618 {
3619     int count, capacity;
3620     struct outline *items;
3621 };
3622 
3623 struct glyphinfo
3624 {
3625     struct outline_array outlines;
3626     float offset_x;
3627 };
3628 
3629 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
3630 {
3631     if (count > array->capacity) {
3632         void *new_buffer;
3633         int new_capacity;
3634         if (array->items && array->capacity) {
3635             new_capacity = max(array->capacity * 2, count);
3636             new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
3637         } else {
3638             new_capacity = max(16, count);
3639             new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
3640         }
3641         if (!new_buffer)
3642             return FALSE;
3643         array->items = new_buffer;
3644         array->capacity = new_capacity;
3645     }
3646     return TRUE;
3647 }
3648 
3649 static struct point2d *add_point(struct outline *array)
3650 {
3651     struct point2d *item;
3652 
3653     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3654         return NULL;
3655 
3656     item = &array->items[array->count++];
3657     ZeroMemory(item, sizeof(*item));
3658     return item;
3659 }
3660 
3661 static struct outline *add_outline(struct outline_array *array)
3662 {
3663     struct outline *item;
3664 
3665     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3666         return NULL;
3667 
3668     item = &array->items[array->count++];
3669     ZeroMemory(item, sizeof(*item));
3670     return item;
3671 }
3672 
3673 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
3674 {
3675     D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
3676     while (count--) {
3677         D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
3678         pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
3679         pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
3680         pt++;
3681     }
3682     return ret;
3683 }
3684 
3685 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
3686                                  const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
3687                                  float max_deviation)
3688 {
3689     D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
3690     float deviation;
3691 
3692     D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
3693     D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
3694     D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
3695 
3696     deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
3697     if (deviation < max_deviation) {
3698         struct point2d *pt = add_point(outline);
3699         if (!pt) return E_OUTOFMEMORY;
3700         pt->pos = *p2;
3701         pt->corner = POINTTYPE_CURVE;
3702         /* the end point is omitted because the end line merges into the next segment of
3703          * the split bezier curve, and the end of the split bezier curve is added outside
3704          * this recursive function. */
3705     } else {
3706         HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
3707         if (hr != S_OK) return hr;
3708         hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
3709         if (hr != S_OK) return hr;
3710     }
3711 
3712     return S_OK;
3713 }
3714 
3715 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
3716 {
3717     /* dot product = cos(theta) */
3718     return D3DXVec2Dot(dir1, dir2) > cos_theta;
3719 }
3720 
3721 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
3722 {
3723     return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
3724 }
3725 
3726 static BOOL attempt_line_merge(struct outline *outline,
3727                                int pt_index,
3728                                const D3DXVECTOR2 *nextpt,
3729                                BOOL to_curve)
3730 {
3731     D3DXVECTOR2 curdir, lastdir;
3732     struct point2d *prevpt, *pt;
3733     BOOL ret = FALSE;
3734     const float cos_half = cos(D3DXToRadian(0.5f));
3735 
3736     pt = &outline->items[pt_index];
3737     pt_index = (pt_index - 1 + outline->count) % outline->count;
3738     prevpt = &outline->items[pt_index];
3739 
3740     if (to_curve)
3741         pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
3742 
3743     if (outline->count < 2)
3744         return FALSE;
3745 
3746     /* remove last point if the next line continues the last line */
3747     unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3748     unit_vec2(&curdir, &pt->pos, nextpt);
3749     if (is_direction_similar(&lastdir, &curdir, cos_half))
3750     {
3751         outline->count--;
3752         if (pt->corner == POINTTYPE_CURVE_END)
3753             prevpt->corner = pt->corner;
3754         if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
3755             prevpt->corner = POINTTYPE_CURVE_MIDDLE;
3756         pt = prevpt;
3757 
3758         ret = TRUE;
3759         if (outline->count < 2)
3760             return ret;
3761 
3762         pt_index = (pt_index - 1 + outline->count) % outline->count;
3763         prevpt = &outline->items[pt_index];
3764         unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3765         unit_vec2(&curdir, &pt->pos, nextpt);
3766     }
3767     return ret;
3768 }
3769 
3770 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
3771                               float max_deviation, float emsquare)
3772 {
3773     const float cos_45 = cos(D3DXToRadian(45.0f));
3774     const float cos_90 = cos(D3DXToRadian(90.0f));
3775     TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
3776 
3777     while ((char *)header < (char *)raw_outline + datasize)
3778     {
3779         TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
3780         struct point2d *lastpt, *pt;
3781         D3DXVECTOR2 lastdir;
3782         D3DXVECTOR2 *pt_flt;
3783         int j;
3784         struct outline *outline = add_outline(&glyph->outlines);
3785 
3786         if (!outline)
3787             return E_OUTOFMEMORY;
3788 
3789         pt = add_point(outline);
3790         if (!pt)
3791             return E_OUTOFMEMORY;
3792         pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
3793         pt->pos = *pt_flt;
3794         pt->corner = POINTTYPE_CORNER;
3795 
3796         if (header->dwType != TT_POLYGON_TYPE)
3797             trace("Unknown header type %d\n", header->dwType);
3798 
3799         while ((char *)curve < (char *)header + header->cb)
3800         {
3801             D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
3802             BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
3803 
3804             if (!curve->cpfx) {
3805                 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3806                 continue;
3807             }
3808 
3809             pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
3810 
3811             attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
3812 
3813             if (to_curve)
3814             {
3815                 HRESULT hr;
3816                 int count = curve->cpfx;
3817                 j = 0;
3818 
3819                 while (count > 2)
3820                 {
3821                     D3DXVECTOR2 bezier_end;
3822 
3823                     D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
3824                     hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
3825                     if (hr != S_OK)
3826                         return hr;
3827                     bezier_start = bezier_end;
3828                     count--;
3829                     j++;
3830                 }
3831                 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
3832                 if (hr != S_OK)
3833                     return hr;
3834 
3835                 pt = add_point(outline);
3836                 if (!pt)
3837                     return E_OUTOFMEMORY;
3838                 j++;
3839                 pt->pos = pt_flt[j];
3840                 pt->corner = POINTTYPE_CURVE_END;
3841             } else {
3842                 for (j = 0; j < curve->cpfx; j++)
3843                 {
3844                     pt = add_point(outline);
3845                     if (!pt)
3846                         return E_OUTOFMEMORY;
3847                     pt->pos = pt_flt[j];
3848                     pt->corner = POINTTYPE_CORNER;
3849                 }
3850             }
3851 
3852             curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3853         }
3854 
3855         /* remove last point if the next line continues the last line */
3856         if (outline->count >= 3) {
3857             BOOL to_curve;
3858 
3859             lastpt = &outline->items[outline->count - 1];
3860             pt = &outline->items[0];
3861             if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
3862                 if (lastpt->corner == POINTTYPE_CURVE_END)
3863                 {
3864                     if (pt->corner == POINTTYPE_CURVE_START)
3865                         pt->corner = POINTTYPE_CURVE_MIDDLE;
3866                     else
3867                         pt->corner = POINTTYPE_CURVE_END;
3868                 }
3869                 outline->count--;
3870             } else {
3871                 /* outline closed with a line from end to start point */
3872                 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
3873             }
3874             lastpt = &outline->items[0];
3875             to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
3876             if (lastpt->corner == POINTTYPE_CURVE_START)
3877                 lastpt->corner = POINTTYPE_CORNER;
3878             pt = &outline->items[1];
3879             if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
3880                 *lastpt = outline->items[outline->count];
3881         }
3882 
3883         lastpt = &outline->items[outline->count - 1];
3884         pt = &outline->items[0];
3885         unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
3886         for (j = 0; j < outline->count; j++)
3887         {
3888             D3DXVECTOR2 curdir;
3889 
3890             lastpt = pt;
3891             pt = &outline->items[(j + 1) % outline->count];
3892             unit_vec2(&curdir, &lastpt->pos, &pt->pos);
3893 
3894             switch (lastpt->corner)
3895             {
3896                 case POINTTYPE_CURVE_START:
3897                 case POINTTYPE_CURVE_END:
3898                     if (!is_direction_similar(&lastdir, &curdir, cos_45))
3899                         lastpt->corner = POINTTYPE_CORNER;
3900                     break;
3901                 case POINTTYPE_CURVE_MIDDLE:
3902                     if (!is_direction_similar(&lastdir, &curdir, cos_90))
3903                         lastpt->corner = POINTTYPE_CORNER;
3904                     else
3905                         lastpt->corner = POINTTYPE_CURVE;
3906                     break;
3907                 default:
3908                     break;
3909             }
3910             lastdir = curdir;
3911         }
3912 
3913         header = (TTPOLYGONHEADER *)((char *)header + header->cb);
3914     }
3915     return S_OK;
3916 }
3917 
3918 static void free_outline(struct outline *outline)
3919 {
3920     HeapFree(GetProcessHeap(), 0, outline->items);
3921 }
3922 
3923 static void free_glyphinfo(struct glyphinfo *glyph)
3924 {
3925     unsigned int i;
3926 
3927     for (i = 0; i < glyph->outlines.count; ++i)
3928         free_outline(&glyph->outlines.items[i]);
3929     HeapFree(GetProcessHeap(), 0, glyph->outlines.items);
3930 }
3931 
3932 static void compute_text_mesh(struct mesh *mesh, const char *text,
3933         float deviation, float extrusion, float otmEMSquare, const struct glyphinfo *glyphs)
3934 {
3935     DWORD nb_vertices, nb_faces;
3936     DWORD nb_corners, nb_outline_points;
3937     int textlen = 0;
3938     int i;
3939     struct vertex *vertex_ptr;
3940     face *face_ptr;
3941 
3942     textlen = strlen(text);
3943 
3944     /* corner points need an extra vertex for the different side faces normals */
3945     nb_corners = 0;
3946     nb_outline_points = 0;
3947     for (i = 0; i < textlen; i++)
3948     {
3949         int j;
3950         for (j = 0; j < glyphs[i].outlines.count; j++)
3951         {
3952             int k;
3953             struct outline *outline = &glyphs[i].outlines.items[j];
3954             nb_outline_points += outline->count;
3955             nb_corners++; /* first outline point always repeated as a corner */
3956             for (k = 1; k < outline->count; k++)
3957                 if (outline->items[k].corner)
3958                     nb_corners++;
3959         }
3960     }
3961 
3962     nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
3963     nb_faces = nb_outline_points * 2;
3964 
3965     ok(new_mesh(mesh, nb_vertices, nb_faces), "Failed to create reference text mesh.\n");
3966 
3967     /* convert 2D vertices and faces into 3D mesh */
3968     vertex_ptr = mesh->vertices;
3969     face_ptr = mesh->faces;
3970     for (i = 0; i < textlen; i++)
3971     {
3972         int j;
3973 
3974         /* side vertices and faces */
3975         for (j = 0; j < glyphs[i].outlines.count; j++)
3976         {
3977             struct vertex *outline_vertices = vertex_ptr;
3978             struct outline *outline = &glyphs[i].outlines.items[j];
3979             int k;
3980             struct point2d *prevpt = &outline->items[outline->count - 1];
3981             struct point2d *pt = &outline->items[0];
3982 
3983             for (k = 1; k <= outline->count; k++)
3984             {
3985                 struct vertex vtx;
3986                 struct point2d *nextpt = &outline->items[k % outline->count];
3987                 WORD vtx_idx = vertex_ptr - mesh->vertices;
3988                 D3DXVECTOR2 vec;
3989 
3990                 if (pt->corner == POINTTYPE_CURVE_START)
3991                     D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
3992                 else if (pt->corner)
3993                     D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3994                 else
3995                     D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
3996                 D3DXVec2Normalize(&vec, &vec);
3997                 vtx.normal.x = -vec.y;
3998                 vtx.normal.y = vec.x;
3999                 vtx.normal.z = 0;
4000 
4001                 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
4002                 vtx.position.y = pt->pos.y;
4003                 vtx.position.z = 0;
4004                 *vertex_ptr++ = vtx;
4005 
4006                 vtx.position.z = -extrusion;
4007                 *vertex_ptr++ = vtx;
4008 
4009                 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
4010                 vtx.position.y = nextpt->pos.y;
4011                 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
4012                     vtx.position.z = -extrusion;
4013                     *vertex_ptr++ = vtx;
4014                     vtx.position.z = 0;
4015                     *vertex_ptr++ = vtx;
4016 
4017                     (*face_ptr)[0] = vtx_idx;
4018                     (*face_ptr)[1] = vtx_idx + 2;
4019                     (*face_ptr)[2] = vtx_idx + 1;
4020                     face_ptr++;
4021 
4022                     (*face_ptr)[0] = vtx_idx;
4023                     (*face_ptr)[1] = vtx_idx + 3;
4024                     (*face_ptr)[2] = vtx_idx + 2;
4025                     face_ptr++;
4026                 } else {
4027                     if (nextpt->corner) {
4028                         if (nextpt->corner == POINTTYPE_CURVE_END) {
4029                             struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
4030                             D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
4031                         } else {
4032                             D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
4033                         }
4034                         D3DXVec2Normalize(&vec, &vec);
4035                         vtx.normal.x = -vec.y;
4036                         vtx.normal.y = vec.x;
4037 
4038                         vtx.position.z = 0;
4039                         *vertex_ptr++ = vtx;
4040                         vtx.position.z = -extrusion;
4041                         *vertex_ptr++ = vtx;
4042                     }
4043 
4044                     (*face_ptr)[0] = vtx_idx;
4045                     (*face_ptr)[1] = vtx_idx + 3;
4046                     (*face_ptr)[2] = vtx_idx + 1;
4047                     face_ptr++;
4048 
4049                     (*face_ptr)[0] = vtx_idx;
4050                     (*face_ptr)[1] = vtx_idx + 2;
4051                     (*face_ptr)[2] = vtx_idx + 3;
4052                     face_ptr++;
4053                 }
4054 
4055                 prevpt = pt;
4056                 pt = nextpt;
4057             }
4058             if (!pt->corner) {
4059                 *vertex_ptr++ = *outline_vertices++;
4060                 *vertex_ptr++ = *outline_vertices++;
4061             }
4062         }
4063 
4064         /* FIXME: compute expected faces */
4065         /* Add placeholder to separate glyph outlines */
4066         vertex_ptr->position.x = 0;
4067         vertex_ptr->position.y = 0;
4068         vertex_ptr->position.z = 0;
4069         vertex_ptr->normal.x = 0;
4070         vertex_ptr->normal.y = 0;
4071         vertex_ptr->normal.z = 1;
4072         vertex_ptr++;
4073     }
4074 }
4075 
4076 static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh,
4077         size_t textlen, float extrusion, const struct glyphinfo *glyphs)
4078 {
4079     HRESULT hr;
4080     DWORD number_of_vertices, number_of_faces;
4081     IDirect3DVertexBuffer9 *vertex_buffer = NULL;
4082     IDirect3DIndexBuffer9 *index_buffer = NULL;
4083     D3DVERTEXBUFFER_DESC vertex_buffer_description;
4084     D3DINDEXBUFFER_DESC index_buffer_description;
4085     struct vertex *vertices = NULL;
4086     face *faces = NULL;
4087     int expected, i;
4088     int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
4089 
4090     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
4091     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
4092 
4093     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
4094     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4095     hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
4096     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4097     ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, unexpected format %u.\n",
4098             name, vertex_buffer_description.Format);
4099     ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, unexpected resource type %u.\n",
4100             name, vertex_buffer_description.Type);
4101     ok(!vertex_buffer_description.Usage, "Test %s, unexpected usage %#x.\n", name, vertex_buffer_description.Usage);
4102     ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, unexpected pool %u.\n",
4103             name, vertex_buffer_description.Pool);
4104     ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, unexpected FVF %#x (expected %#x).\n",
4105             name, vertex_buffer_description.FVF, mesh->fvf);
4106     if (!mesh->fvf)
4107         expected = number_of_vertices * mesh->vertex_size;
4108     else
4109         expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
4110     ok(vertex_buffer_description.Size == expected, "Test %s, unexpected size %u (expected %u).\n",
4111             name, vertex_buffer_description.Size, expected);
4112 
4113     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
4114     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4115     hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
4116     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4117     ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, unexpected format %u.\n",
4118             name, index_buffer_description.Format);
4119     ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, unexpected resource type %u.\n",
4120             name, index_buffer_description.Type);
4121     ok(!index_buffer_description.Usage, "Test %s, unexpected usage %#x.\n",
4122             name, index_buffer_description.Usage);
4123     ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, unexpected pool %u.\n",
4124             name, index_buffer_description.Pool);
4125     expected = number_of_faces * sizeof(WORD) * 3;
4126     ok(index_buffer_description.Size == expected, "Test %s, unexpected size %u.\n",
4127             name, index_buffer_description.Size);
4128 
4129     hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
4130             (void **)&vertices, D3DLOCK_DISCARD);
4131     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4132     hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
4133             (void **)&faces, D3DLOCK_DISCARD);
4134     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4135     face_idx1 = 0;
4136     vtx_idx2 = 0;
4137     face_idx2 = 0;
4138     vtx_idx1 = 0;
4139     for (i = 0; i < textlen; i++)
4140     {
4141         int nb_outline_vertices1, nb_outline_faces1;
4142         int nb_outline_vertices2, nb_outline_faces2;
4143         int nb_back_vertices, nb_back_faces;
4144         int first_vtx1, first_vtx2;
4145         int first_face1, first_face2;
4146         int j;
4147 
4148         first_vtx1 = vtx_idx1;
4149         first_vtx2 = vtx_idx2;
4150         /* Glyphs without outlines do not generate any vertices. */
4151         if (glyphs[i].outlines.count > 0)
4152         {
4153             for (; vtx_idx1 < number_of_vertices; vtx_idx1++)
4154             {
4155                 if (vertices[vtx_idx1].normal.z != 0)
4156                     break;
4157             }
4158 
4159             for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++)
4160             {
4161                 if (mesh->vertices[vtx_idx2].normal.z != 0)
4162                     break;
4163             }
4164         }
4165         nb_outline_vertices1 = vtx_idx1 - first_vtx1;
4166         nb_outline_vertices2 = vtx_idx2 - first_vtx2;
4167         ok(nb_outline_vertices1 == nb_outline_vertices2,
4168            "Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
4169            nb_outline_vertices1, nb_outline_vertices2);
4170 
4171         for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
4172         {
4173             vtx_idx1 = first_vtx1 + j;
4174             vtx_idx2 = first_vtx2 + j;
4175             ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
4176                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4177                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
4178                mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
4179             ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
4180                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4181                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4182                mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
4183         }
4184         vtx_idx1 = first_vtx1 + nb_outline_vertices1;
4185         vtx_idx2 = first_vtx2 + nb_outline_vertices2;
4186 
4187         first_face1 = face_idx1;
4188         first_face2 = face_idx2;
4189         for (; face_idx1 < number_of_faces; face_idx1++)
4190         {
4191             if (faces[face_idx1][0] >= vtx_idx1 ||
4192                 faces[face_idx1][1] >= vtx_idx1 ||
4193                 faces[face_idx1][2] >= vtx_idx1)
4194                 break;
4195         }
4196         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
4197         {
4198             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
4199                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
4200                 mesh->faces[face_idx2][2] >= vtx_idx2)
4201                 break;
4202         }
4203         nb_outline_faces1 = face_idx1 - first_face1;
4204         nb_outline_faces2 = face_idx2 - first_face2;
4205         ok(nb_outline_faces1 == nb_outline_faces2,
4206            "Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
4207            nb_outline_faces1, nb_outline_faces2);
4208 
4209         for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
4210         {
4211             face_idx1 = first_face1 + j;
4212             face_idx2 = first_face2 + j;
4213             ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
4214                faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
4215                faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
4216                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
4217                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
4218                mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
4219                mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
4220                mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
4221         }
4222         face_idx1 = first_face1 + nb_outline_faces1;
4223         face_idx2 = first_face2 + nb_outline_faces2;
4224 
4225         /* partial test on back vertices and faces  */
4226         first_vtx1 = vtx_idx1;
4227         for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
4228             struct vertex vtx;
4229 
4230             if (vertices[vtx_idx1].normal.z != 1.0f)
4231                 break;
4232 
4233             vtx.position.z = 0.0f;
4234             vtx.normal.x = 0.0f;
4235             vtx.normal.y = 0.0f;
4236             vtx.normal.z = 1.0f;
4237             ok(compare(vertices[vtx_idx1].position.z, vtx.position.z),
4238                "Test %s, glyph %d, vertex position.z %d, result %g, expected %g\n", name, i, vtx_idx1,
4239                vertices[vtx_idx1].position.z, vtx.position.z);
4240             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
4241                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4242                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4243                vtx.normal.x, vtx.normal.y, vtx.normal.z);
4244         }
4245         nb_back_vertices = vtx_idx1 - first_vtx1;
4246         first_face1 = face_idx1;
4247         for (; face_idx1 < number_of_faces; face_idx1++)
4248         {
4249             const D3DXVECTOR3 *vtx1, *vtx2, *vtx3;
4250             D3DXVECTOR3 normal;
4251             D3DXVECTOR3 v1 = {0, 0, 0};
4252             D3DXVECTOR3 v2 = {0, 0, 0};
4253             D3DXVECTOR3 forward = {0.0f, 0.0f, 1.0f};
4254 
4255             if (faces[face_idx1][0] >= vtx_idx1 ||
4256                 faces[face_idx1][1] >= vtx_idx1 ||
4257                 faces[face_idx1][2] >= vtx_idx1)
4258                 break;
4259 
4260             vtx1 = &vertices[faces[face_idx1][0]].position;
4261             vtx2 = &vertices[faces[face_idx1][1]].position;
4262             vtx3 = &vertices[faces[face_idx1][2]].position;
4263 
4264             D3DXVec3Subtract(&v1, vtx2, vtx1);
4265             D3DXVec3Subtract(&v2, vtx3, vtx2);
4266             D3DXVec3Cross(&normal, &v1, &v2);
4267             D3DXVec3Normalize(&normal, &normal);
4268             ok(!D3DXVec3Length(&normal) || compare_vec3(normal, forward),
4269                "Test %s, glyph %d, face %d normal, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, face_idx1,
4270                normal.x, normal.y, normal.z, forward.x, forward.y, forward.z);
4271         }
4272         nb_back_faces = face_idx1 - first_face1;
4273 
4274         /* compare front and back faces & vertices */
4275         if (extrusion == 0.0f) {
4276             /* Oddly there are only back faces in this case */
4277             nb_back_vertices /= 2;
4278             nb_back_faces /= 2;
4279             face_idx1 -= nb_back_faces;
4280             vtx_idx1 -= nb_back_vertices;
4281         }
4282         for (j = 0; j < nb_back_vertices; j++)
4283         {
4284             struct vertex vtx = vertices[first_vtx1];
4285             vtx.position.z = -extrusion;
4286             vtx.normal.x = 0.0f;
4287             vtx.normal.y = 0.0f;
4288             vtx.normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
4289             ok(compare_vec3(vertices[vtx_idx1].position, vtx.position),
4290                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4291                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
4292                vtx.position.x, vtx.position.y, vtx.position.z);
4293             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
4294                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4295                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4296                vtx.normal.x, vtx.normal.y, vtx.normal.z);
4297             vtx_idx1++;
4298             first_vtx1++;
4299         }
4300         for (j = 0; j < nb_back_faces; j++)
4301         {
4302             int f1, f2;
4303             if (extrusion == 0.0f) {
4304                 f1 = 1;
4305                 f2 = 2;
4306             } else {
4307                 f1 = 2;
4308                 f2 = 1;
4309             }
4310             ok(faces[face_idx1][0] == faces[first_face1][0] + nb_back_vertices &&
4311                faces[face_idx1][1] == faces[first_face1][f1] + nb_back_vertices &&
4312                faces[face_idx1][2] == faces[first_face1][f2] + nb_back_vertices,
4313                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
4314                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
4315                faces[first_face1][0] - nb_back_faces,
4316                faces[first_face1][f1] - nb_back_faces,
4317                faces[first_face1][f2] - nb_back_faces);
4318             first_face1++;
4319             face_idx1++;
4320         }
4321 
4322         /* skip to the outline for the next glyph */
4323         for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
4324             if (mesh->vertices[vtx_idx2].normal.z == 0)
4325                 break;
4326         }
4327         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
4328         {
4329             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
4330                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
4331                 mesh->faces[face_idx2][2] >= vtx_idx2) break;
4332         }
4333     }
4334 
4335     IDirect3DIndexBuffer9_Unlock(index_buffer);
4336     IDirect3DVertexBuffer9_Unlock(vertex_buffer);
4337     IDirect3DIndexBuffer9_Release(index_buffer);
4338     IDirect3DVertexBuffer9_Release(vertex_buffer);
4339 }
4340 
4341 static void test_createtext(IDirect3DDevice9 *device, HDC hdc, const char *text, float deviation, float extrusion)
4342 {
4343     static const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
4344     HRESULT hr;
4345     ID3DXMesh *d3dxmesh = NULL;
4346     struct mesh mesh = {0};
4347     char name[256];
4348     OUTLINETEXTMETRICA otm;
4349     GLYPHMETRICS gm;
4350     struct glyphinfo *glyphs;
4351     GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
4352     int i;
4353     LOGFONTA lf;
4354     float offset_x;
4355     size_t textlen;
4356     HFONT font = NULL, oldfont = NULL;
4357     char *raw_outline;
4358 
4359     sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion);
4360 
4361     hr = D3DXCreateTextA(device, hdc, text, deviation, extrusion, &d3dxmesh, NULL, glyphmetrics_float);
4362     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
4363 
4364     /* must select a modified font having lfHeight = otm.otmEMSquare before
4365      * calling GetGlyphOutline to get the expected values */
4366     ok(GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf), "Failed to get current DC font.\n");
4367     ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "Failed to get DC font outline.\n");
4368     lf.lfHeight = otm.otmEMSquare;
4369     lf.lfWidth = 0;
4370     ok(!!(font = CreateFontIndirectA(&lf)), "Failed to create font.\n");
4371 
4372     textlen = strlen(text);
4373     glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
4374     oldfont = SelectObject(hdc, font);
4375 
4376     for (i = 0; i < textlen; i++)
4377     {
4378         GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
4379         compare_float(glyphmetrics_float[i].gmfBlackBoxX, gm.gmBlackBoxX / (float)otm.otmEMSquare);
4380         compare_float(glyphmetrics_float[i].gmfBlackBoxY, gm.gmBlackBoxY / (float)otm.otmEMSquare);
4381         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.x, gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare);
4382         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.y, gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare);
4383         compare_float(glyphmetrics_float[i].gmfCellIncX, gm.gmCellIncX / (float)otm.otmEMSquare);
4384         compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
4385     }
4386 
4387     if (deviation == 0.0f)
4388         deviation = 1.0f / otm.otmEMSquare;
4389 
4390     offset_x = 0.0f;
4391     for (i = 0; i < textlen; i++)
4392     {
4393         DWORD datasize;
4394 
4395         glyphs[i].offset_x = offset_x;
4396 
4397         datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
4398         ok(datasize != GDI_ERROR, "Failed to retrieve GDI glyph outline size.\n");
4399         raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
4400         datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
4401         ok(datasize != GDI_ERROR, "Failed to retrieve GDI glyph outline.\n");
4402         create_outline(&glyphs[i], raw_outline, datasize, deviation, otm.otmEMSquare);
4403         HeapFree(GetProcessHeap(), 0, raw_outline);
4404 
4405         offset_x += gm.gmCellIncX / (float)otm.otmEMSquare;
4406     }
4407 
4408     SelectObject(hdc, oldfont);
4409 
4410     compute_text_mesh(&mesh, text, deviation, extrusion, otm.otmEMSquare, glyphs);
4411     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
4412 
4413     compare_text_outline_mesh(name, d3dxmesh, &mesh, textlen, extrusion, glyphs);
4414 
4415     free_mesh(&mesh);
4416     d3dxmesh->lpVtbl->Release(d3dxmesh);
4417     DeleteObject(font);
4418     HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
4419 
4420     for (i = 0; i < textlen; i++)
4421         free_glyphinfo(&glyphs[i]);
4422     HeapFree(GetProcessHeap(), 0, glyphs);
4423 }
4424 
4425 static void D3DXCreateTextTest(void)
4426 {
4427     HRESULT hr;
4428     HDC hdc;
4429     IDirect3DDevice9* device;
4430     ID3DXMesh* d3dxmesh = NULL;
4431     HFONT hFont;
4432     OUTLINETEXTMETRICA otm;
4433     int number_of_vertices;
4434     int number_of_faces;
4435     struct test_context *test_context;
4436 
4437     if (!(test_context = new_test_context()))
4438     {
4439         skip("Couldn't create test context\n");
4440         return;
4441     }
4442     device = test_context->device;
4443 
4444     hdc = CreateCompatibleDC(NULL);
4445 
4446     hFont = CreateFontA(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
4447             CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
4448     SelectObject(hdc, hFont);
4449     GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
4450 
4451     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, 0.4f, NULL, NULL, NULL);
4452     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4453 
4454     /* D3DXCreateTextA page faults from passing NULL text */
4455 
4456     hr = D3DXCreateTextW(device, hdc, NULL, 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4457     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4458 
4459     hr = D3DXCreateTextA(device, hdc, "", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4460     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4461 
4462     hr = D3DXCreateTextA(device, hdc, " ", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4463     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4464 
4465     hr = D3DXCreateTextA(NULL, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4466     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4467 
4468     hr = D3DXCreateTextA(device, NULL, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4469     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4470 
4471     hr = D3DXCreateTextA(device, hdc, "wine", -FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4472     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4473 
4474     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, -FLT_MIN, &d3dxmesh, NULL, NULL);
4475     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4476 
4477     /* deviation = 0.0f treated as if deviation = 1.0f / otm.otmEMSquare */
4478     hr = D3DXCreateTextA(device, hdc, "wine", 1.0f / otm.otmEMSquare, 0.4f, &d3dxmesh, NULL, NULL);
4479     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4480     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
4481     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
4482     d3dxmesh->lpVtbl->Release(d3dxmesh);
4483 
4484     hr = D3DXCreateTextA(device, hdc, "wine", 0.0f, 0.4f, &d3dxmesh, NULL, NULL);
4485     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4486     ok(number_of_vertices == d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh),
4487        "Got %d vertices, expected %d\n",
4488        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_vertices);
4489     ok(number_of_faces == d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh),
4490        "Got %d faces, expected %d\n",
4491        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_faces);
4492     d3dxmesh->lpVtbl->Release(d3dxmesh);
4493 
4494 if (0)
4495 {
4496     /* too much detail requested, so will appear to hang */
4497     trace("Waiting for D3DXCreateText to finish with deviation = FLT_MIN ...\n");
4498     hr = D3DXCreateTextA(device, hdc, "wine", FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4499     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4500     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4501     trace("D3DXCreateText finish with deviation = FLT_MIN\n");
4502 }
4503 
4504     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4505     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4506     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4507 
4508     test_createtext(device, hdc, "wine", FLT_MAX, 0.4f);
4509     test_createtext(device, hdc, "wine", 0.001f, FLT_MIN);
4510     test_createtext(device, hdc, "wine", 0.001f, 0.0f);
4511     test_createtext(device, hdc, "wine", 0.001f, FLT_MAX);
4512     test_createtext(device, hdc, "wine", 0.0f, 1.0f);
4513     test_createtext(device, hdc, " wine", 1.0f, 0.0f);
4514     test_createtext(device, hdc, "wine ", 1.0f, 0.0f);
4515     test_createtext(device, hdc, "wi ne", 1.0f, 0.0f);
4516 
4517     DeleteDC(hdc);
4518     DeleteObject(hFont);
4519 
4520     free_test_context(test_context);
4521 }
4522 
4523 static void test_get_decl_length(void)
4524 {
4525     static const D3DVERTEXELEMENT9 declaration1[] =
4526     {
4527         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4528         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4529         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4530         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4531         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4532         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4533         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4534         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4535         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4536         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4537         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4538         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4539         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4540         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4541         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4542         D3DDECL_END(),
4543     };
4544     static const D3DVERTEXELEMENT9 declaration2[] =
4545     {
4546         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4547         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4548         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4549         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4550         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4551         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4552         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4553         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4554         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4555         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4556         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4557         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4558         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4559         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4560         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4561         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4562         D3DDECL_END(),
4563     };
4564     UINT size;
4565 
4566     size = D3DXGetDeclLength(declaration1);
4567     ok(size == 15, "Got size %u, expected 15.\n", size);
4568 
4569     size = D3DXGetDeclLength(declaration2);
4570     ok(size == 16, "Got size %u, expected 16.\n", size);
4571 }
4572 
4573 static void test_get_decl_vertex_size(void)
4574 {
4575     static const D3DVERTEXELEMENT9 declaration1[] =
4576     {
4577         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4578         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4579         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4580         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4581         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4582         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4583         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4584         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4585         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4586         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4587         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4588         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4589         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4590         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4591         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4592         D3DDECL_END(),
4593     };
4594     static const D3DVERTEXELEMENT9 declaration2[] =
4595     {
4596         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4597         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4598         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4599         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4600         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4601         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4602         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4603         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4604         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4605         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4606         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4607         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4608         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4609         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4610         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4611         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4612         D3DDECL_END(),
4613     };
4614     static const UINT sizes1[] =
4615     {
4616         4,  8,  12, 16,
4617         4,  4,  4,  8,
4618         4,  4,  8,  4,
4619         4,  4,  8,  0,
4620     };
4621     static const UINT sizes2[] =
4622     {
4623         12, 16, 20, 24,
4624         12, 12, 16, 16,
4625     };
4626     unsigned int i;
4627     UINT size;
4628 
4629     size = D3DXGetDeclVertexSize(NULL, 0);
4630     ok(size == 0, "Got size %#x, expected 0.\n", size);
4631 
4632     for (i = 0; i < 16; ++i)
4633     {
4634         size = D3DXGetDeclVertexSize(declaration1, i);
4635         ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
4636     }
4637 
4638     for (i = 0; i < 8; ++i)
4639     {
4640         size = D3DXGetDeclVertexSize(declaration2, i);
4641         ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
4642     }
4643 }
4644 
4645 static void D3DXGenerateAdjacencyTest(void)
4646 {
4647     HRESULT hr;
4648     IDirect3DDevice9 *device;
4649     ID3DXMesh *d3dxmesh = NULL;
4650     D3DXVECTOR3 *vertices = NULL;
4651     WORD *indices = NULL;
4652     int i;
4653     struct {
4654         DWORD num_vertices;
4655         D3DXVECTOR3 vertices[6];
4656         DWORD num_faces;
4657         WORD indices[3 * 3];
4658         FLOAT epsilon;
4659         DWORD adjacency[3 * 3];
4660     } test_data[] = {
4661         { /* for epsilon < 0, indices must match for faces to be adjacent */
4662             4, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
4663             2, {0, 1, 2,  0, 2, 3},
4664             -1.0,
4665             {-1, -1, 1,  0, -1, -1},
4666         },
4667         {
4668             6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
4669             2, {0, 1, 2,  3, 4, 5},
4670             -1.0,
4671             {-1, -1, -1,  -1, -1, -1},
4672         },
4673         { /* for epsilon == 0, indices or vertices must match for faces to be adjacent */
4674             6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
4675             2, {0, 1, 2,  3, 4, 5},
4676             0.0,
4677             {-1, -1, 1,  0, -1, -1},
4678         },
4679         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4680             6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.25}, {1.0, 1.0, 0.25}, {0.0, 1.0, 0.25}},
4681             2, {0, 1, 2,  3, 4, 5},
4682             0.25,
4683             {-1, -1, -1,  -1, -1, -1},
4684         },
4685         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4686             6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.25}, {1.0, 1.0, 0.25}, {0.0, 1.0, 0.25}},
4687             2, {0, 1, 2,  3, 4, 5},
4688             0.250001,
4689             {-1, -1, 1,  0, -1, -1},
4690         },
4691         { /* length between vertices are compared to epsilon, not the individual dimension deltas */
4692             6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.25, 0.25}, {1.0, 1.25, 0.25}, {0.0, 1.25, 0.25}},
4693             2, {0, 1, 2,  3, 4, 5},
4694             0.353, /* < sqrt(0.25*0.25 + 0.25*0.25) */
4695             {-1, -1, -1,  -1, -1, -1},
4696         },
4697         {
4698             6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.25, 0.25}, {1.0, 1.25, 0.25}, {0.0, 1.25, 0.25}},
4699             2, {0, 1, 2,  3, 4, 5},
4700             0.354, /* > sqrt(0.25*0.25 + 0.25*0.25) */
4701             {-1, -1, 1,  0, -1, -1},
4702         },
4703         { /* adjacent faces must have opposite winding orders at the shared edge */
4704             4, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
4705             2, {0, 1, 2,  0, 3, 2},
4706             0.0,
4707             {-1, -1, -1,  -1, -1, -1},
4708         },
4709     };
4710     struct test_context *test_context;
4711 
4712     if (!(test_context = new_test_context()))
4713     {
4714         skip("Couldn't create test context\n");
4715         return;
4716     }
4717     device = test_context->device;
4718 
4719     for (i = 0; i < ARRAY_SIZE(test_data); i++)
4720     {
4721         DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
4722         int j;
4723 
4724         if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4725         d3dxmesh = NULL;
4726 
4727         hr = D3DXCreateMeshFVF(test_data[i].num_faces, test_data[i].num_vertices, 0, D3DFVF_XYZ, device, &d3dxmesh);
4728         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4729 
4730         hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&vertices);
4731         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4732         if (FAILED(hr)) continue;
4733         CopyMemory(vertices, test_data[i].vertices, test_data[i].num_vertices * sizeof(test_data[0].vertices[0]));
4734         d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
4735 
4736         hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&indices);
4737         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4738         if (FAILED(hr)) continue;
4739         CopyMemory(indices, test_data[i].indices, test_data[i].num_faces * 3 * sizeof(test_data[0].indices[0]));
4740         d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
4741 
4742         if (i == 0) {
4743             hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, NULL);
4744             ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4745         }
4746 
4747         hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, test_data[i].epsilon, adjacency);
4748         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4749         if (FAILED(hr)) continue;
4750 
4751         for (j = 0; j < test_data[i].num_faces * 3; j++)
4752             ok(adjacency[j] == test_data[i].adjacency[j],
4753                "Test %d adjacency %d: Got result %u, expected %u\n", i, j,
4754                adjacency[j], test_data[i].adjacency[j]);
4755     }
4756     if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4757 
4758     free_test_context(test_context);
4759 }
4760 
4761 static void test_update_semantics(void)
4762 {
4763     HRESULT hr;
4764     struct test_context *test_context = NULL;
4765     ID3DXMesh *mesh = NULL;
4766     D3DVERTEXELEMENT9 declaration0[] =
4767     {
4768          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4769          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4770          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4771          D3DDECL_END()
4772     };
4773     D3DVERTEXELEMENT9 declaration_pos_type_color[] =
4774     {
4775          {0, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4776          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4777          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4778          D3DDECL_END()
4779     };
4780     D3DVERTEXELEMENT9 declaration_smaller[] =
4781     {
4782          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4783          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4784          D3DDECL_END()
4785     };
4786     D3DVERTEXELEMENT9 declaration_larger[] =
4787     {
4788          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4789          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4790          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4791          {0, 40, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4792          D3DDECL_END()
4793     };
4794     D3DVERTEXELEMENT9 declaration_multiple_streams[] =
4795     {
4796          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4797          {1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4798          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4799          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4800 
4801          D3DDECL_END()
4802     };
4803     D3DVERTEXELEMENT9 declaration_double_usage[] =
4804     {
4805          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4806          {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4807          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4808          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4809          D3DDECL_END()
4810     };
4811     D3DVERTEXELEMENT9 declaration_undefined_type[] =
4812     {
4813          {0, 0, D3DDECLTYPE_UNUSED+1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4814          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4815          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4816          D3DDECL_END()
4817     };
4818     D3DVERTEXELEMENT9 declaration_not_4_byte_aligned_offset[] =
4819     {
4820          {0, 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4821          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4822          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4823          D3DDECL_END()
4824     };
4825     static const struct
4826     {
4827         D3DXVECTOR3 position0;
4828         D3DXVECTOR3 position1;
4829         D3DXVECTOR3 normal;
4830         DWORD color;
4831     }
4832     vertices[] =
4833     {
4834         { { 0.0f,  1.0f,  0.f}, { 1.0f,  0.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xffff0000 },
4835         { { 1.0f, -1.0f,  0.f}, {-1.0f, -1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff00ff00 },
4836         { {-1.0f, -1.0f,  0.f}, {-1.0f,  1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff0000ff },
4837     };
4838     unsigned int faces[] = {0, 1, 2};
4839     unsigned int attributes[] = {0};
4840     unsigned int num_faces = ARRAY_SIZE(faces) / 3;
4841     unsigned int num_vertices = ARRAY_SIZE(vertices);
4842     int offset = sizeof(D3DXVECTOR3);
4843     DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4844     void *vertex_buffer;
4845     void *index_buffer;
4846     DWORD *attributes_buffer;
4847     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
4848     D3DVERTEXELEMENT9 *decl_ptr;
4849     DWORD exp_vertex_size = sizeof(*vertices);
4850     DWORD vertex_size = 0;
4851     int equal;
4852     int i = 0;
4853     int *decl_mem;
4854     int filler_a = 0xaaaaaaaa;
4855     int filler_b = 0xbbbbbbbb;
4856 
4857     test_context = new_test_context();
4858     if (!test_context)
4859     {
4860         skip("Couldn't create a test_context\n");
4861         goto cleanup;
4862     }
4863 
4864     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration0,
4865                         test_context->device, &mesh);
4866     if (FAILED(hr))
4867     {
4868         skip("Couldn't create test mesh %#x\n", hr);
4869         goto cleanup;
4870     }
4871 
4872     mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
4873     memcpy(vertex_buffer, vertices, sizeof(vertices));
4874     mesh->lpVtbl->UnlockVertexBuffer(mesh);
4875 
4876     mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
4877     memcpy(index_buffer, faces, sizeof(faces));
4878     mesh->lpVtbl->UnlockIndexBuffer(mesh);
4879 
4880     mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
4881     memcpy(attributes_buffer, attributes, sizeof(attributes));
4882     mesh->lpVtbl->UnlockAttributeBuffer(mesh);
4883 
4884     /* Get the declaration and try to change it */
4885     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4886     if (FAILED(hr))
4887     {
4888         skip("Couldn't get vertex declaration %#x\n", hr);
4889         goto cleanup;
4890     }
4891     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4892     ok(equal == 0, "Vertex declarations were not equal\n");
4893 
4894     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4895     {
4896         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4897         {
4898             /* Use second vertex position instead of first */
4899             decl_ptr->Offset = offset;
4900         }
4901     }
4902 
4903     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4904     ok(hr == D3D_OK, "Test UpdateSemantics, got %#x expected %#x\n", hr, D3D_OK);
4905 
4906     /* Check that declaration was written by getting it again */
4907     memset(declaration, 0, sizeof(declaration));
4908     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4909     if (FAILED(hr))
4910     {
4911         skip("Couldn't get vertex declaration %#x\n", hr);
4912         goto cleanup;
4913     }
4914 
4915     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4916     {
4917         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4918         {
4919             ok(decl_ptr->Offset == offset, "Test UpdateSemantics, got offset %d expected %d\n",
4920                decl_ptr->Offset, offset);
4921         }
4922     }
4923 
4924     /* Check that GetDeclaration only writes up to the D3DDECL_END() marker and
4925      * not the full MAX_FVF_DECL_SIZE elements.
4926      */
4927     memset(declaration, filler_a, sizeof(declaration));
4928     memcpy(declaration, declaration0, sizeof(declaration0));
4929     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4930     ok(hr == D3D_OK, "Test UpdateSemantics, "
4931        "got %#x expected D3D_OK\n", hr);
4932     memset(declaration, filler_b, sizeof(declaration));
4933     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4934     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4935     decl_mem = (int*)declaration;
4936     for (i = sizeof(declaration0)/sizeof(*decl_mem); i < sizeof(declaration)/sizeof(*decl_mem); i++)
4937     {
4938         equal = memcmp(&decl_mem[i], &filler_b, sizeof(filler_b));
4939         ok(equal == 0,
4940            "GetDeclaration wrote past the D3DDECL_END() marker. "
4941            "Got %#x, expected  %#x\n", decl_mem[i], filler_b);
4942         if (equal != 0) break;
4943     }
4944 
4945     /* UpdateSemantics does not check for overlapping fields */
4946     memset(declaration, 0, sizeof(declaration));
4947     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4948     if (FAILED(hr))
4949     {
4950         skip("Couldn't get vertex declaration %#x\n", hr);
4951         goto cleanup;
4952     }
4953 
4954     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4955     {
4956         if (decl_ptr->Type == D3DDECLTYPE_FLOAT3)
4957         {
4958             decl_ptr->Type = D3DDECLTYPE_FLOAT4;
4959         }
4960     }
4961 
4962     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4963     ok(hr == D3D_OK, "Test UpdateSemantics for overlapping fields, "
4964        "got %#x expected D3D_OK\n", hr);
4965 
4966     /* Set the position type to color instead of float3 */
4967     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_pos_type_color);
4968     ok(hr == D3D_OK, "Test UpdateSemantics position type color, "
4969        "got %#x expected D3D_OK\n", hr);
4970 
4971     /* The following test cases show that NULL, smaller or larger declarations,
4972      * and declarations with non-zero Stream values are not accepted.
4973      * UpdateSemantics returns D3DERR_INVALIDCALL and the previously set
4974      * declaration will be used by DrawSubset, GetNumBytesPerVertex, and
4975      * GetDeclaration.
4976      */
4977 
4978     /* Null declaration (invalid declaration) */
4979     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4980     hr = mesh->lpVtbl->UpdateSemantics(mesh, NULL);
4981     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics null pointer declaration, "
4982        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4983     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4984     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4985        vertex_size, exp_vertex_size);
4986     memset(declaration, 0, sizeof(declaration));
4987     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4988     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4989     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4990     ok(equal == 0, "Vertex declarations were not equal\n");
4991 
4992     /* Smaller vertex declaration (invalid declaration) */
4993     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4994     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_smaller);
4995     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics for smaller vertex declaration, "
4996        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4997     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4998     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4999        vertex_size, exp_vertex_size);
5000     memset(declaration, 0, sizeof(declaration));
5001     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
5002     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
5003     equal = memcmp(declaration, declaration0, sizeof(declaration0));
5004     ok(equal == 0, "Vertex declarations were not equal\n");
5005 
5006     /* Larger vertex declaration (invalid declaration) */
5007     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
5008     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_larger);
5009     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics for larger vertex declaration, "
5010        "got %#x expected D3DERR_INVALIDCALL\n", hr);
5011     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
5012     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
5013        vertex_size, exp_vertex_size);
5014     memset(declaration, 0, sizeof(declaration));
5015     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
5016     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
5017     equal = memcmp(declaration, declaration0, sizeof(declaration0));
5018     ok(equal == 0, "Vertex declarations were not equal\n");
5019 
5020     /* Use multiple streams and keep the same vertex size (invalid declaration) */
5021     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
5022     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_multiple_streams);
5023     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics using multiple streams, "
5024                  "got %#x expected D3DERR_INVALIDCALL\n", hr);
5025     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
5026     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
5027        vertex_size, exp_vertex_size);
5028     memset(declaration, 0, sizeof(declaration));
5029     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
5030     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
5031     equal = memcmp(declaration, declaration0, sizeof(declaration0));
5032     ok(equal == 0, "Vertex declarations were not equal\n");
5033 
5034     /* The next following test cases show that some invalid declarations are
5035      * accepted with a D3D_OK. An access violation is thrown on Windows if
5036      * DrawSubset is called. The methods GetNumBytesPerVertex and GetDeclaration
5037      * are not affected, which indicates that the declaration is cached.
5038      */
5039 
5040     /* Double usage (invalid declaration) */
5041     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
5042     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_double_usage);
5043     ok(hr == D3D_OK, "Test UpdateSemantics double usage, "
5044        "got %#x expected D3D_OK\n", hr);
5045     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
5046     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
5047        vertex_size, exp_vertex_size);
5048     memset(declaration, 0, sizeof(declaration));
5049     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
5050     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
5051     equal = memcmp(declaration, declaration_double_usage, sizeof(declaration_double_usage));
5052     ok(equal == 0, "Vertex declarations were not equal\n");
5053 
5054     /* Set the position to an undefined type (invalid declaration) */
5055     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
5056     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_undefined_type);
5057     ok(hr == D3D_OK, "Test UpdateSemantics undefined type, "
5058        "got %#x expected D3D_OK\n", hr);
5059     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
5060     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
5061        vertex_size, exp_vertex_size);
5062     memset(declaration, 0, sizeof(declaration));
5063     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
5064     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
5065     equal = memcmp(declaration, declaration_undefined_type, sizeof(declaration_undefined_type));
5066     ok(equal == 0, "Vertex declarations were not equal\n");
5067 
5068     /* Use a not 4 byte aligned offset (invalid declaration) */
5069     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
5070     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_not_4_byte_aligned_offset);
5071     ok(hr == D3D_OK, "Test UpdateSemantics not 4 byte aligned offset, "
5072        "got %#x expected D3D_OK\n", hr);
5073     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
5074     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
5075        vertex_size, exp_vertex_size);
5076     memset(declaration, 0, sizeof(declaration));
5077     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
5078     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
5079     equal = memcmp(declaration, declaration_not_4_byte_aligned_offset,
5080                    sizeof(declaration_not_4_byte_aligned_offset));
5081     ok(equal == 0, "Vertex declarations were not equal\n");
5082 
5083 cleanup:
5084     if (mesh)
5085         mesh->lpVtbl->Release(mesh);
5086 
5087     free_test_context(test_context);
5088 }
5089 
5090 static void test_create_skin_info(void)
5091 {
5092     HRESULT hr;
5093     ID3DXSkinInfo *skininfo = NULL;
5094     D3DVERTEXELEMENT9 empty_declaration[] = { D3DDECL_END() };
5095     D3DVERTEXELEMENT9 declaration_out[MAX_FVF_DECL_SIZE];
5096     const D3DVERTEXELEMENT9 declaration_with_nonzero_stream[] = {
5097         {1, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
5098         D3DDECL_END()
5099     };
5100 
5101     hr = D3DXCreateSkinInfo(0, empty_declaration, 0, &skininfo);
5102     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5103     if (skininfo) IUnknown_Release(skininfo);
5104     skininfo = NULL;
5105 
5106     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
5107     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5108 
5109     hr = D3DXCreateSkinInfo(1, declaration_with_nonzero_stream, 1, &skininfo);
5110     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5111 
5112     hr = D3DXCreateSkinInfoFVF(1, 0, 1, &skininfo);
5113     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5114     if (skininfo)
5115     {
5116         DWORD dword_result;
5117         float flt_result;
5118         const char *string_result;
5119         D3DXMATRIX *transform;
5120         D3DXMATRIX identity_matrix;
5121 
5122         /* test initial values */
5123         hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5124         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5125         if (SUCCEEDED(hr))
5126             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
5127 
5128         dword_result = skininfo->lpVtbl->GetNumBones(skininfo);
5129         ok(dword_result == 1, "Expected 1, got %u\n", dword_result);
5130 
5131         flt_result = skininfo->lpVtbl->GetMinBoneInfluence(skininfo);
5132         ok(flt_result == 0.0f, "Expected 0.0, got %g\n", flt_result);
5133 
5134         string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5135         ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
5136 
5137         dword_result = skininfo->lpVtbl->GetFVF(skininfo);
5138         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5139 
5140         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 0);
5141         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5142 
5143         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 1);
5144         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5145 
5146         transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, -1);
5147         ok(transform == NULL, "Expected NULL, got %p\n", transform);
5148 
5149         {
5150             /* test [GS]etBoneOffsetMatrix */
5151             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 1, &identity_matrix);
5152             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5153 
5154             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, NULL);
5155             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5156 
5157             D3DXMatrixIdentity(&identity_matrix);
5158             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, &identity_matrix);
5159             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5160 
5161             transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, 0);
5162             check_matrix(transform, &identity_matrix);
5163         }
5164 
5165         {
5166             /* test [GS]etBoneName */
5167             const char *name_in = "testBoneName";
5168             const char *string_result2;
5169 
5170             hr = skininfo->lpVtbl->SetBoneName(skininfo, 1, name_in);
5171             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5172 
5173             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, NULL);
5174             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5175 
5176             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, name_in);
5177             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5178 
5179             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5180             ok(string_result != NULL, "Expected non-NULL string, got %p\n", string_result);
5181             ok(!strcmp(string_result, name_in), "Expected '%s', got '%s'\n", name_in, string_result);
5182 
5183             string_result2 = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5184             ok(string_result == string_result2, "Expected %p, got %p\n", string_result, string_result2);
5185 
5186             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 1);
5187             ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
5188         }
5189 
5190         {
5191             /* test [GS]etBoneInfluence */
5192             DWORD vertices[2];
5193             FLOAT weights[2];
5194             int i;
5195             DWORD num_influences;
5196             DWORD exp_vertices[2];
5197             FLOAT exp_weights[2];
5198 
5199             /* vertex and weight arrays untouched when num_influences is 0 */
5200             vertices[0] = 0xdeadbeef;
5201             weights[0] = FLT_MAX;
5202             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5203             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5204             ok(vertices[0] == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", vertices[0]);
5205             ok(weights[0] == FLT_MAX, "expected %g, got %g\n", FLT_MAX, weights[0]);
5206 
5207             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 1, vertices, weights);
5208             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5209 
5210             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, NULL);
5211             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5212 
5213             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, NULL);
5214             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5215 
5216             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, weights);
5217             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5218 
5219 
5220             /* no vertex or weight value checking */
5221             exp_vertices[0] = 0;
5222             exp_vertices[1] = 0x87654321;
5223             exp_weights[0] = 0.5;
5224             exp_weights[1] = NAN;
5225             num_influences = 2;
5226 
5227             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 1, num_influences, vertices, weights);
5228             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5229 
5230             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, weights);
5231             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5232 
5233             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, vertices, NULL);
5234             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5235 
5236             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, NULL);
5237             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5238 
5239             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, exp_vertices, exp_weights);
5240             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5241 
5242             memset(vertices, 0, sizeof(vertices));
5243             memset(weights, 0, sizeof(weights));
5244             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5245             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5246             for (i = 0; i < num_influences; i++) {
5247                 ok(exp_vertices[i] == vertices[i],
5248                    "influence[%d]: expected vertex %u, got %u\n", i, exp_vertices[i], vertices[i]);
5249                 ok((isnan(exp_weights[i]) && isnan(weights[i])) || exp_weights[i] == weights[i],
5250                    "influence[%d]: expected weights %g, got %g\n", i, exp_weights[i], weights[i]);
5251             }
5252 
5253             /* vertices and weights aren't returned after setting num_influences to 0 */
5254             memset(vertices, 0, sizeof(vertices));
5255             memset(weights, 0, sizeof(weights));
5256             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, 0, vertices, weights);
5257             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5258 
5259             vertices[0] = 0xdeadbeef;
5260             weights[0] = FLT_MAX;
5261             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5262             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5263             ok(vertices[0] == 0xdeadbeef, "expected vertex 0xdeadbeef, got %u\n", vertices[0]);
5264             ok(weights[0] == FLT_MAX, "expected weight %g, got %g\n", FLT_MAX, weights[0]);
5265         }
5266 
5267         {
5268             /* test [GS]etFVF and [GS]etDeclaration */
5269             D3DVERTEXELEMENT9 declaration_in[MAX_FVF_DECL_SIZE];
5270             DWORD fvf = D3DFVF_XYZ;
5271             DWORD got_fvf;
5272 
5273             hr = skininfo->lpVtbl->SetDeclaration(skininfo, NULL);
5274             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5275 
5276             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_with_nonzero_stream);
5277             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5278 
5279             hr = skininfo->lpVtbl->SetFVF(skininfo, 0);
5280             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5281 
5282             hr = D3DXDeclaratorFromFVF(fvf, declaration_in);
5283             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5284             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_in);
5285             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5286             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5287             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
5288             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5289             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5290             compare_elements(declaration_out, declaration_in, __LINE__, 0);
5291 
5292             hr = skininfo->lpVtbl->SetDeclaration(skininfo, empty_declaration);
5293             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5294             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5295             ok(got_fvf == 0, "Expected 0, got %#x\n", got_fvf);
5296             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5297             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5298             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
5299 
5300             hr = skininfo->lpVtbl->SetFVF(skininfo, fvf);
5301             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5302             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5303             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
5304             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5305             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5306             compare_elements(declaration_out, declaration_in, __LINE__, 0);
5307         }
5308     }
5309     if (skininfo) IUnknown_Release(skininfo);
5310     skininfo = NULL;
5311 
5312     hr = D3DXCreateSkinInfoFVF(1, D3DFVF_XYZ, 1, NULL);
5313     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5314 
5315     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
5316     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5317 }
5318 
5319 static void test_convert_adjacency_to_point_reps(void)
5320 {
5321     HRESULT hr;
5322     struct test_context *test_context = NULL;
5323     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5324     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5325     const D3DVERTEXELEMENT9 declaration[] =
5326     {
5327         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5328         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5329         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5330         D3DDECL_END()
5331     };
5332     const unsigned int VERTS_PER_FACE = 3;
5333     void *vertex_buffer;
5334     void *index_buffer;
5335     DWORD *attributes_buffer;
5336     int i, j;
5337     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5338     struct vertex_pnc
5339     {
5340         D3DXVECTOR3 position;
5341         D3DXVECTOR3 normal;
5342         enum color color; /* In case of manual visual inspection */
5343     };
5344 #ifndef __REACTOS__
5345     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5346 #else
5347 #define up {0.0f, 0.0f, 1.0f}
5348 #endif
5349     /* mesh0 (one face)
5350      *
5351      * 0--1
5352      * | /
5353      * |/
5354      * 2
5355      */
5356     const struct vertex_pnc vertices0[] =
5357     {
5358         {{ 0.0f,  3.0f,  0.f}, up, RED},
5359         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5360         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5361     };
5362     const DWORD indices0[] = {0, 1, 2};
5363     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5364     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
5365     const DWORD adjacency0[] = {-1, -1, -1};
5366     const DWORD exp_point_rep0[] = {0, 1, 2};
5367     /* mesh1 (right)
5368      *
5369      * 0--1 3
5370      * | / /|
5371      * |/ / |
5372      * 2 5--4
5373      */
5374     const struct vertex_pnc vertices1[] =
5375     {
5376         {{ 0.0f,  3.0f,  0.f}, up, RED},
5377         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5378         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5379 
5380         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5381         {{ 3.0f,  0.0f,  0.f}, up, RED},
5382         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5383     };
5384     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5385     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5386     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
5387     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
5388     const DWORD exp_point_rep1[] = {0, 1, 2, 1, 4, 2};
5389     /* mesh2 (left)
5390      *
5391      *    3 0--1
5392      *   /| | /
5393      *  / | |/
5394      * 5--4 2
5395      */
5396     const struct vertex_pnc vertices2[] =
5397     {
5398         {{ 0.0f,  3.0f,  0.f}, up, RED},
5399         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5400         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5401 
5402         {{-1.0f,  3.0f,  0.f}, up, RED},
5403         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5404         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5405     };
5406     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5407     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5408     const unsigned int num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
5409     const DWORD adjacency2[] = {-1, -1, 1, 0, -1, -1};
5410     const DWORD exp_point_rep2[] = {0, 1, 2, 0, 2, 5};
5411     /* mesh3 (above)
5412      *
5413      *    3
5414      *   /|
5415      *  / |
5416      * 5--4
5417      * 0--1
5418      * | /
5419      * |/
5420      * 2
5421      */
5422     struct vertex_pnc vertices3[] =
5423     {
5424         {{ 0.0f,  3.0f,  0.f}, up, RED},
5425         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5426         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5427 
5428         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5429         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5430         {{ 0.0f,  4.0f,  0.f}, up, RED},
5431     };
5432     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5433     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5434     const unsigned int num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
5435     const DWORD adjacency3[] = {1, -1, -1, -1, 0, -1};
5436     const DWORD exp_point_rep3[] = {0, 1, 2, 3, 1, 0};
5437     /* mesh4 (below, tip against tip)
5438      *
5439      * 0--1
5440      * | /
5441      * |/
5442      * 2
5443      * 3
5444      * |\
5445      * | \
5446      * 5--4
5447      */
5448     struct vertex_pnc vertices4[] =
5449     {
5450         {{ 0.0f,  3.0f,  0.f}, up, RED},
5451         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5452         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5453 
5454         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5455         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5456         {{ 0.0f, -7.0f,  0.f}, up, RED},
5457     };
5458     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5459     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5460     const unsigned int num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
5461     const DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
5462     const DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
5463     /* mesh5 (gap in mesh)
5464      *
5465      *    0      3-----4  15
5466      *   / \      \   /  /  \
5467      *  /   \      \ /  /    \
5468      * 2-----1      5 17-----16
5469      * 6-----7      9 12-----13
5470      *  \   /      / \  \    /
5471      *   \ /      /   \  \  /
5472      *    8     10-----11 14
5473      *
5474      */
5475     const struct vertex_pnc vertices5[] =
5476     {
5477         {{ 0.0f,  1.0f,  0.f}, up, RED},
5478         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5479         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5480 
5481         {{ 0.1f,  1.0f,  0.f}, up, RED},
5482         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5483         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5484 
5485         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5486         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5487         {{ 0.0f, -3.1f,  0.f}, up, RED},
5488 
5489         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5490         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5491         {{ 0.1f, -3.1f,  0.f}, up, RED},
5492 
5493         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5494         {{ 3.2f, -1.1f,  0.f}, up, RED},
5495         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5496 
5497         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5498         {{ 3.2f, -1.0f,  0.f}, up, RED},
5499         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5500     };
5501     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5502     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5503     const unsigned int num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
5504     const DWORD adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5505     const DWORD exp_point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5506     const WORD indices5_16bit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5507     /* mesh6 (indices re-ordering)
5508      *
5509      * 0--1 6 3
5510      * | / /| |\
5511      * |/ / | | \
5512      * 2 8--7 5--4
5513      */
5514     const struct vertex_pnc vertices6[] =
5515     {
5516         {{ 0.0f,  3.0f,  0.f}, up, RED},
5517         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5518         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5519 
5520         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5521         {{ 3.0f,  0.0f,  0.f}, up, RED},
5522         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5523 
5524         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5525         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5526         {{ 4.0f,  0.0f,  0.f}, up, RED},
5527     };
5528     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5529     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5530     const unsigned int num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
5531     const DWORD adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5532     const DWORD exp_point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5533     /* mesh7 (expands collapsed triangle)
5534      *
5535      * 0--1 3
5536      * | / /|
5537      * |/ / |
5538      * 2 5--4
5539      */
5540     const struct vertex_pnc vertices7[] =
5541     {
5542         {{ 0.0f,  3.0f,  0.f}, up, RED},
5543         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5544         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5545 
5546         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5547         {{ 3.0f,  0.0f,  0.f}, up, RED},
5548         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5549     };
5550     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5551     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5552     const unsigned int num_faces7 = ARRAY_SIZE(indices7) / VERTS_PER_FACE;
5553     const DWORD adjacency7[] = {-1, -1, -1, -1, -1, -1};
5554     const DWORD exp_point_rep7[] = {0, 1, 2, 3, 4, 5};
5555     /* mesh8 (indices re-ordering and double replacement)
5556      *
5557      * 0--1 9  6
5558      * | / /|  |\
5559      * |/ / |  | \
5560      * 2 11-10 8--7
5561      *         3--4
5562      *         | /
5563      *         |/
5564      *         5
5565      */
5566     const struct vertex_pnc vertices8[] =
5567     {
5568         {{ 0.0f,  3.0f,  0.f}, up, RED},
5569         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5570         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5571 
5572         {{ 4.0,  -4.0,  0.f}, up, RED},
5573         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5574         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5575 
5576         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5577         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5578         {{ 4.0f,  0.0f,  0.f}, up, RED},
5579 
5580         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5581         {{ 3.0f,  0.0f,  0.f}, up, RED},
5582         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5583     };
5584     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5585     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5586     const unsigned int num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
5587     const DWORD adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5588     const DWORD exp_point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5589     /* mesh9 (right, shared vertices)
5590      *
5591      * 0--1
5592      * | /|
5593      * |/ |
5594      * 2--3
5595      */
5596     const struct vertex_pnc vertices9[] =
5597     {
5598         {{ 0.0f,  3.0f,  0.f}, up, RED},
5599         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5600         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5601 
5602         {{ 2.0f,  0.0f,  0.f}, up, RED},
5603     };
5604     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5605     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5606     const unsigned int num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
5607     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
5608     const DWORD exp_point_rep9[] = {0, 1, 2, 3};
5609     /* All mesh data */
5610     ID3DXMesh *mesh = NULL;
5611     ID3DXMesh *mesh_null_check = NULL;
5612     unsigned int attributes[] = {0};
5613     struct
5614     {
5615         const struct vertex_pnc *vertices;
5616         const DWORD *indices;
5617         const DWORD num_vertices;
5618         const DWORD num_faces;
5619         const DWORD *adjacency;
5620         const DWORD *exp_point_reps;
5621         const DWORD options;
5622     }
5623     tc[] =
5624     {
5625         {
5626             vertices0,
5627             indices0,
5628             num_vertices0,
5629             num_faces0,
5630             adjacency0,
5631             exp_point_rep0,
5632             options
5633         },
5634         {
5635             vertices1,
5636             indices1,
5637             num_vertices1,
5638             num_faces1,
5639             adjacency1,
5640             exp_point_rep1,
5641             options
5642         },
5643         {
5644             vertices2,
5645             indices2,
5646             num_vertices2,
5647             num_faces2,
5648             adjacency2,
5649             exp_point_rep2,
5650             options
5651         },
5652         {
5653             vertices3,
5654             indices3,
5655             num_vertices3,
5656             num_faces3,
5657             adjacency3,
5658             exp_point_rep3,
5659             options
5660         },
5661         {
5662             vertices4,
5663             indices4,
5664             num_vertices4,
5665             num_faces4,
5666             adjacency4,
5667             exp_point_rep4,
5668             options
5669         },
5670         {
5671             vertices5,
5672             indices5,
5673             num_vertices5,
5674             num_faces5,
5675             adjacency5,
5676             exp_point_rep5,
5677             options
5678         },
5679         {
5680             vertices6,
5681             indices6,
5682             num_vertices6,
5683             num_faces6,
5684             adjacency6,
5685             exp_point_rep6,
5686             options
5687         },
5688         {
5689             vertices7,
5690             indices7,
5691             num_vertices7,
5692             num_faces7,
5693             adjacency7,
5694             exp_point_rep7,
5695             options
5696         },
5697         {
5698             vertices8,
5699             indices8,
5700             num_vertices8,
5701             num_faces8,
5702             adjacency8,
5703             exp_point_rep8,
5704             options
5705         },
5706         {
5707             vertices9,
5708             indices9,
5709             num_vertices9,
5710             num_faces9,
5711             adjacency9,
5712             exp_point_rep9,
5713             options
5714         },
5715         {
5716             vertices5,
5717             (DWORD*)indices5_16bit,
5718             num_vertices5,
5719             num_faces5,
5720             adjacency5,
5721             exp_point_rep5,
5722             options_16bit
5723         },
5724     };
5725     DWORD *point_reps = NULL;
5726 
5727     test_context = new_test_context();
5728     if (!test_context)
5729     {
5730         skip("Couldn't create test context\n");
5731         goto cleanup;
5732     }
5733 
5734     for (i = 0; i < ARRAY_SIZE(tc); i++)
5735     {
5736         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options, declaration,
5737                             test_context->device, &mesh);
5738         if (FAILED(hr))
5739         {
5740             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5741             goto cleanup;
5742         }
5743 
5744         if (i == 0) /* Save first mesh for later NULL checks */
5745             mesh_null_check = mesh;
5746 
5747         point_reps = HeapAlloc(GetProcessHeap(), 0, tc[i].num_vertices * sizeof(*point_reps));
5748         if (!point_reps)
5749         {
5750             skip("Couldn't allocate point reps array.\n");
5751             goto cleanup;
5752         }
5753 
5754         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5755         if (FAILED(hr))
5756         {
5757             skip("Couldn't lock vertex buffer.\n");
5758             goto cleanup;
5759         }
5760         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5761         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5762         if (FAILED(hr))
5763         {
5764             skip("Couldn't unlock vertex buffer.\n");
5765             goto cleanup;
5766         }
5767 
5768         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5769         if (FAILED(hr))
5770         {
5771             skip("Couldn't lock index buffer.\n");
5772             goto cleanup;
5773         }
5774         if (tc[i].options & D3DXMESH_32BIT)
5775         {
5776             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5777         }
5778         else
5779         {
5780             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5781         }
5782         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5783         if (FAILED(hr)) {
5784             skip("Couldn't unlock index buffer.\n");
5785             goto cleanup;
5786         }
5787 
5788         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5789         if (FAILED(hr))
5790         {
5791             skip("Couldn't lock attributes buffer.\n");
5792             goto cleanup;
5793         }
5794         memcpy(attributes_buffer, attributes, sizeof(attributes));
5795         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5796         if (FAILED(hr))
5797         {
5798             skip("Couldn't unlock attributes buffer.\n");
5799             goto cleanup;
5800         }
5801 
5802         /* Convert adjacency to point representation */
5803         for (j = 0; j < tc[i].num_vertices; j++) point_reps[j] = -1;
5804         hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacency, point_reps);
5805         ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
5806            "Got %x expected D3D_OK\n", i, hr);
5807 
5808         /* Check point representation */
5809         for (j = 0; j < tc[i].num_vertices; j++)
5810         {
5811             ok(point_reps[j] == tc[i].exp_point_reps[j],
5812                "Unexpected point representation at (%d, %d)."
5813                " Got %d expected %d\n",
5814                i, j, point_reps[j], tc[i].exp_point_reps[j]);
5815         }
5816 
5817         HeapFree(GetProcessHeap(), 0, point_reps);
5818         point_reps = NULL;
5819 
5820         if (i != 0) /* First mesh will be freed during cleanup */
5821             mesh->lpVtbl->Release(mesh);
5822     }
5823 
5824     /* NULL checks */
5825     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacency, NULL);
5826     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
5827        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5828     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, NULL);
5829     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. "
5830        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5831 
5832 cleanup:
5833     if (mesh_null_check)
5834         mesh_null_check->lpVtbl->Release(mesh_null_check);
5835     HeapFree(GetProcessHeap(), 0, point_reps);
5836     free_test_context(test_context);
5837 #ifdef __REACTOS__
5838 #undef up
5839 #endif
5840 }
5841 
5842 static void test_convert_point_reps_to_adjacency(void)
5843 {
5844     HRESULT hr;
5845     struct test_context *test_context = NULL;
5846     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5847     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5848     const D3DVERTEXELEMENT9 declaration[] =
5849     {
5850         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5851         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5852         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5853         D3DDECL_END()
5854     };
5855     const unsigned int VERTS_PER_FACE = 3;
5856     void *vertex_buffer;
5857     void *index_buffer;
5858     DWORD *attributes_buffer;
5859     int i, j;
5860     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5861     struct vertex_pnc
5862     {
5863         D3DXVECTOR3 position;
5864         D3DXVECTOR3 normal;
5865         enum color color; /* In case of manual visual inspection */
5866     };
5867 #ifndef __REACTOS__
5868     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5869 #else
5870 #define up {0.0f, 0.0f, 1.0f}
5871 #endif
5872 
5873     /* mesh0 (one face)
5874      *
5875      * 0--1
5876      * | /
5877      * |/
5878      * 2
5879      */
5880     const struct vertex_pnc vertices0[] =
5881     {
5882         {{ 0.0f,  3.0f,  0.f}, up, RED},
5883         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5884         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5885     };
5886     const DWORD indices0[] = {0, 1, 2};
5887     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5888     const unsigned int num_faces0 = num_vertices0 / VERTS_PER_FACE;
5889     const DWORD exp_adjacency0[] = {-1, -1, -1};
5890     const DWORD exp_id_adjacency0[] = {-1, -1, -1};
5891     const DWORD point_rep0[] = {0, 1, 2};
5892     /* mesh1 (right)
5893      *
5894      * 0--1 3
5895      * | / /|
5896      * |/ / |
5897      * 2 5--4
5898      */
5899     const struct vertex_pnc vertices1[] =
5900     {
5901         {{ 0.0f,  3.0f,  0.f}, up, RED},
5902         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5903         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5904 
5905         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5906         {{ 3.0f,  0.0f,  0.f}, up, RED},
5907         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5908     };
5909     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5910     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5911     const unsigned int num_faces1 = num_vertices1 / VERTS_PER_FACE;
5912     const DWORD exp_adjacency1[] = {-1, 1, -1, -1, -1, 0};
5913     const DWORD exp_id_adjacency1[] = {-1, -1, -1, -1, -1, -1};
5914     const DWORD point_rep1[] = {0, 1, 2, 1, 4, 2};
5915     /* mesh2 (left)
5916      *
5917      *    3 0--1
5918      *   /| | /
5919      *  / | |/
5920      * 5--4 2
5921      */
5922     const struct vertex_pnc vertices2[] =
5923     {
5924         {{ 0.0f,  3.0f,  0.f}, up, RED},
5925         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5926         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5927 
5928         {{-1.0f,  3.0f,  0.f}, up, RED},
5929         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5930         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5931     };
5932     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5933     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5934     const unsigned int num_faces2 = num_vertices2 / VERTS_PER_FACE;
5935     const DWORD exp_adjacency2[] = {-1, -1, 1, 0, -1, -1};
5936     const DWORD exp_id_adjacency2[] = {-1, -1, -1, -1, -1, -1};
5937     const DWORD point_rep2[] = {0, 1, 2, 0, 2, 5};
5938     /* mesh3 (above)
5939      *
5940      *    3
5941      *   /|
5942      *  / |
5943      * 5--4
5944      * 0--1
5945      * | /
5946      * |/
5947      * 2
5948      */
5949     struct vertex_pnc vertices3[] =
5950     {
5951         {{ 0.0f,  3.0f,  0.f}, up, RED},
5952         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5953         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5954 
5955         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5956         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5957         {{ 0.0f,  4.0f,  0.f}, up, RED},
5958     };
5959     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5960     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5961     const unsigned int num_faces3 = num_vertices3 / VERTS_PER_FACE;
5962     const DWORD exp_adjacency3[] = {1, -1, -1, -1, 0, -1};
5963     const DWORD exp_id_adjacency3[] = {-1, -1, -1, -1, -1, -1};
5964     const DWORD point_rep3[] = {0, 1, 2, 3, 1, 0};
5965     /* mesh4 (below, tip against tip)
5966      *
5967      * 0--1
5968      * | /
5969      * |/
5970      * 2
5971      * 3
5972      * |\
5973      * | \
5974      * 5--4
5975      */
5976     struct vertex_pnc vertices4[] =
5977     {
5978         {{ 0.0f,  3.0f,  0.f}, up, RED},
5979         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5980         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5981 
5982         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5983         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5984         {{ 0.0f, -7.0f,  0.f}, up, RED},
5985     };
5986     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5987     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5988     const unsigned int num_faces4 = num_vertices4 / VERTS_PER_FACE;
5989     const DWORD exp_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5990     const DWORD exp_id_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5991     const DWORD point_rep4[] = {0, 1, 2, 3, 4, 5};
5992     /* mesh5 (gap in mesh)
5993      *
5994      *    0      3-----4  15
5995      *   / \      \   /  /  \
5996      *  /   \      \ /  /    \
5997      * 2-----1      5 17-----16
5998      * 6-----7      9 12-----13
5999      *  \   /      / \  \    /
6000      *   \ /      /   \  \  /
6001      *    8     10-----11 14
6002      *
6003      */
6004     const struct vertex_pnc vertices5[] =
6005     {
6006         {{ 0.0f,  1.0f,  0.f}, up, RED},
6007         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
6008         {{-1.0f, -1.0f,  0.f}, up, BLUE},
6009 
6010         {{ 0.1f,  1.0f,  0.f}, up, RED},
6011         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
6012         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
6013 
6014         {{-1.0f, -1.1f,  0.f}, up, BLUE},
6015         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
6016         {{ 0.0f, -3.1f,  0.f}, up, RED},
6017 
6018         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
6019         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
6020         {{ 0.1f, -3.1f,  0.f}, up, RED},
6021 
6022         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
6023         {{ 3.2f, -1.1f,  0.f}, up, RED},
6024         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
6025 
6026         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
6027         {{ 3.2f, -1.0f,  0.f}, up, RED},
6028         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
6029     };
6030     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
6031     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
6032     const unsigned int num_faces5 = num_vertices5 / VERTS_PER_FACE;
6033     const DWORD exp_adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
6034     const DWORD exp_id_adjacency5[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
6035     const DWORD point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
6036     /* mesh6 (indices re-ordering)
6037      *
6038      * 0--1 6 3
6039      * | / /| |\
6040      * |/ / | | \
6041      * 2 8--7 5--4
6042      */
6043     const struct vertex_pnc vertices6[] =
6044     {
6045         {{ 0.0f,  3.0f,  0.f}, up, RED},
6046         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6047         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6048 
6049         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
6050         {{ 3.0f,  0.0f,  0.f}, up, RED},
6051         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
6052 
6053         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
6054         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
6055         {{ 4.0f,  0.0f,  0.f}, up, RED},
6056     };
6057     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
6058     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
6059     const unsigned int num_faces6 = num_vertices6 / VERTS_PER_FACE;
6060     const DWORD exp_adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
6061     const DWORD exp_id_adjacency6[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1};
6062     const DWORD point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
6063     /* mesh7 (expands collapsed triangle)
6064      *
6065      * 0--1 3
6066      * | / /|
6067      * |/ / |
6068      * 2 5--4
6069      */
6070     const struct vertex_pnc vertices7[] =
6071     {
6072         {{ 0.0f,  3.0f,  0.f}, up, RED},
6073         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6074         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6075 
6076         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
6077         {{ 3.0f,  0.0f,  0.f}, up, RED},
6078         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
6079     };
6080     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
6081     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
6082     const unsigned int num_faces7 = num_vertices7 / VERTS_PER_FACE;
6083     const DWORD exp_adjacency7[] = {-1, -1, -1, -1, -1, -1};
6084     const DWORD exp_id_adjacency7[] = {-1, -1, -1, -1, -1, -1};
6085     const DWORD point_rep7[] = {0, 1, 2, 3, 4, 5};
6086     /* mesh8 (indices re-ordering and double replacement)
6087      *
6088      * 0--1 9  6
6089      * | / /|  |\
6090      * |/ / |  | \
6091      * 2 11-10 8--7
6092      *         3--4
6093      *         | /
6094      *         |/
6095      *         5
6096      */
6097     const struct vertex_pnc vertices8[] =
6098     {
6099         {{ 0.0f,  3.0f,  0.f}, up, RED},
6100         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6101         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6102 
6103         {{ 4.0,  -4.0,  0.f}, up, RED},
6104         {{ 6.0,  -4.0,  0.f}, up, BLUE},
6105         {{ 4.0,  -7.0,  0.f}, up, GREEN},
6106 
6107         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
6108         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
6109         {{ 4.0f,  0.0f,  0.f}, up, RED},
6110 
6111         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
6112         {{ 3.0f,  0.0f,  0.f}, up, RED},
6113         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
6114     };
6115     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
6116     const WORD indices8_16bit[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
6117     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
6118     const unsigned int num_faces8 = num_vertices8 / VERTS_PER_FACE;
6119     const DWORD exp_adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
6120     const DWORD exp_id_adjacency8[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
6121     const DWORD point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
6122      /* mesh9 (right, shared vertices)
6123      *
6124      * 0--1
6125      * | /|
6126      * |/ |
6127      * 2--3
6128      */
6129     const struct vertex_pnc vertices9[] =
6130     {
6131         {{ 0.0f,  3.0f,  0.f}, up, RED},
6132         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6133         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6134 
6135         {{ 2.0f,  0.0f,  0.f}, up, RED},
6136     };
6137     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
6138     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
6139     const unsigned int num_faces9 = 2;
6140     const DWORD exp_adjacency9[] = {-1, 1, -1, -1, -1, 0};
6141     const DWORD exp_id_adjacency9[] = {-1, 1, -1, -1, -1, 0};
6142     const DWORD point_rep9[] = {0, 1, 2, 3};
6143     /* All mesh data */
6144     ID3DXMesh *mesh = NULL;
6145     ID3DXMesh *mesh_null_check = NULL;
6146     unsigned int attributes[] = {0};
6147     struct
6148     {
6149         const struct vertex_pnc *vertices;
6150         const DWORD *indices;
6151         const DWORD num_vertices;
6152         const DWORD num_faces;
6153         const DWORD *point_reps;
6154         const DWORD *exp_adjacency;
6155         const DWORD *exp_id_adjacency;
6156         const DWORD options;
6157     }
6158     tc[] =
6159     {
6160         {
6161             vertices0,
6162             indices0,
6163             num_vertices0,
6164             num_faces0,
6165             point_rep0,
6166             exp_adjacency0,
6167             exp_id_adjacency0,
6168             options
6169         },
6170         {
6171             vertices1,
6172             indices1,
6173             num_vertices1,
6174             num_faces1,
6175             point_rep1,
6176             exp_adjacency1,
6177             exp_id_adjacency1,
6178             options
6179         },
6180         {
6181             vertices2,
6182             indices2,
6183             num_vertices2,
6184             num_faces2,
6185             point_rep2,
6186             exp_adjacency2,
6187             exp_id_adjacency2,
6188             options
6189         },
6190         {
6191             vertices3,
6192             indices3,
6193             num_vertices3,
6194             num_faces3,
6195             point_rep3,
6196             exp_adjacency3,
6197             exp_id_adjacency3,
6198             options
6199         },
6200         {
6201             vertices4,
6202             indices4,
6203             num_vertices4,
6204             num_faces4,
6205             point_rep4,
6206             exp_adjacency4,
6207             exp_id_adjacency4,
6208             options
6209         },
6210         {
6211             vertices5,
6212             indices5,
6213             num_vertices5,
6214             num_faces5,
6215             point_rep5,
6216             exp_adjacency5,
6217             exp_id_adjacency5,
6218             options
6219         },
6220         {
6221             vertices6,
6222             indices6,
6223             num_vertices6,
6224             num_faces6,
6225             point_rep6,
6226             exp_adjacency6,
6227             exp_id_adjacency6,
6228             options
6229         },
6230         {
6231             vertices7,
6232             indices7,
6233             num_vertices7,
6234             num_faces7,
6235             point_rep7,
6236             exp_adjacency7,
6237             exp_id_adjacency7,
6238             options
6239         },
6240         {
6241             vertices8,
6242             indices8,
6243             num_vertices8,
6244             num_faces8,
6245             point_rep8,
6246             exp_adjacency8,
6247             exp_id_adjacency8,
6248             options
6249         },
6250         {
6251             vertices9,
6252             indices9,
6253             num_vertices9,
6254             num_faces9,
6255             point_rep9,
6256             exp_adjacency9,
6257             exp_id_adjacency9,
6258             options
6259         },
6260         {
6261             vertices8,
6262             (DWORD*)indices8_16bit,
6263             num_vertices8,
6264             num_faces8,
6265             point_rep8,
6266             exp_adjacency8,
6267             exp_id_adjacency8,
6268             options_16bit
6269         },
6270     };
6271     DWORD *adjacency = NULL;
6272 #ifdef __REACTOS__
6273 #undef up
6274 #endif
6275 
6276     test_context = new_test_context();
6277     if (!test_context)
6278     {
6279         skip("Couldn't create test context\n");
6280         goto cleanup;
6281     }
6282 
6283     for (i = 0; i < ARRAY_SIZE(tc); i++)
6284     {
6285         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
6286                             declaration, test_context->device, &mesh);
6287         if (FAILED(hr))
6288         {
6289             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
6290             goto cleanup;
6291         }
6292 
6293         if (i == 0) /* Save first mesh for later NULL checks */
6294             mesh_null_check = mesh;
6295 
6296         adjacency = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
6297         if (!adjacency)
6298         {
6299             skip("Couldn't allocate adjacency array.\n");
6300             goto cleanup;
6301         }
6302 
6303         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
6304         if (FAILED(hr))
6305         {
6306             skip("Couldn't lock vertex buffer.\n");
6307             goto cleanup;
6308         }
6309         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
6310         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6311         if (FAILED(hr))
6312         {
6313             skip("Couldn't unlock vertex buffer.\n");
6314             goto cleanup;
6315         }
6316         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6317         if (FAILED(hr))
6318         {
6319             skip("Couldn't lock index buffer.\n");
6320             goto cleanup;
6321         }
6322         if (tc[i].options & D3DXMESH_32BIT)
6323         {
6324             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
6325         }
6326         else
6327         {
6328             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
6329         }
6330         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6331         if (FAILED(hr)) {
6332             skip("Couldn't unlock index buffer.\n");
6333             goto cleanup;
6334         }
6335 
6336         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6337         if (FAILED(hr))
6338         {
6339             skip("Couldn't lock attributes buffer.\n");
6340             goto cleanup;
6341         }
6342         memcpy(attributes_buffer, attributes, sizeof(attributes));
6343         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6344         if (FAILED(hr))
6345         {
6346             skip("Couldn't unlock attributes buffer.\n");
6347             goto cleanup;
6348         }
6349 
6350         /* Convert point representation to adjacency*/
6351         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
6352 
6353         hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
6354         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
6355            "Got %x expected D3D_OK\n", i, hr);
6356         /* Check adjacency */
6357         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
6358         {
6359             ok(adjacency[j] == tc[i].exp_adjacency[j],
6360                "Unexpected adjacency information at (%d, %d)."
6361                " Got %d expected %d\n",
6362                i, j, adjacency[j], tc[i].exp_adjacency[j]);
6363         }
6364 
6365         /* NULL point representation is considered identity. */
6366         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
6367         hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
6368         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
6369                      "Got %x expected D3D_OK\n", hr);
6370         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
6371         {
6372             ok(adjacency[j] == tc[i].exp_id_adjacency[j],
6373                "Unexpected adjacency information (id) at (%d, %d)."
6374                " Got %d expected %d\n",
6375                i, j, adjacency[j], tc[i].exp_id_adjacency[j]);
6376         }
6377 
6378         HeapFree(GetProcessHeap(), 0, adjacency);
6379         adjacency = NULL;
6380         if (i != 0) /* First mesh will be freed during cleanup */
6381             mesh->lpVtbl->Release(mesh);
6382     }
6383 
6384     /* NULL checks */
6385     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
6386     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
6387        "Got %x expected D3DERR_INVALIDCALL\n", hr);
6388     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
6389     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
6390        "Got %x expected D3DERR_INVALIDCALL\n", hr);
6391 
6392 cleanup:
6393     if (mesh_null_check)
6394         mesh_null_check->lpVtbl->Release(mesh_null_check);
6395     HeapFree(GetProcessHeap(), 0, adjacency);
6396     free_test_context(test_context);
6397 }
6398 
6399 static HRESULT init_test_mesh(const DWORD num_faces, const DWORD num_vertices,
6400                               const DWORD options,
6401                               const D3DVERTEXELEMENT9 *declaration,
6402                               IDirect3DDevice9 *device, ID3DXMesh **mesh_ptr,
6403                               const void *vertices, const DWORD vertex_size,
6404                               const DWORD *indices, const DWORD *attributes)
6405 {
6406     HRESULT hr;
6407     void *vertex_buffer;
6408     void *index_buffer;
6409     DWORD *attributes_buffer;
6410     ID3DXMesh *mesh = NULL;
6411 
6412     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration, device, mesh_ptr);
6413     if (FAILED(hr))
6414     {
6415         skip("Couldn't create mesh. Got %x expected D3D_OK\n", hr);
6416         goto cleanup;
6417     }
6418     mesh = *mesh_ptr;
6419 
6420     hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
6421     if (FAILED(hr))
6422     {
6423         skip("Couldn't lock vertex buffer.\n");
6424         goto cleanup;
6425     }
6426     memcpy(vertex_buffer, vertices, num_vertices * vertex_size);
6427     hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6428     if (FAILED(hr))
6429     {
6430         skip("Couldn't unlock vertex buffer.\n");
6431         goto cleanup;
6432     }
6433 
6434     hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6435     if (FAILED(hr))
6436     {
6437         skip("Couldn't lock index buffer.\n");
6438         goto cleanup;
6439     }
6440     if (options & D3DXMESH_32BIT)
6441     {
6442         if (indices)
6443             memcpy(index_buffer, indices, 3 * num_faces * sizeof(DWORD));
6444         else
6445         {
6446             /* Fill index buffer with 0, 1, 2, ...*/
6447             DWORD *indices_32bit = (DWORD*)index_buffer;
6448             UINT i;
6449             for (i = 0; i < 3 * num_faces; i++)
6450                 indices_32bit[i] = i;
6451         }
6452     }
6453     else
6454     {
6455         if (indices)
6456             memcpy(index_buffer, indices, 3 * num_faces * sizeof(WORD));
6457         else
6458         {
6459             /* Fill index buffer with 0, 1, 2, ...*/
6460             WORD *indices_16bit = (WORD*)index_buffer;
6461             UINT i;
6462             for (i = 0; i < 3 * num_faces; i++)
6463                 indices_16bit[i] = i;
6464         }
6465     }
6466     hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6467     if (FAILED(hr)) {
6468         skip("Couldn't unlock index buffer.\n");
6469         goto cleanup;
6470     }
6471 
6472     hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6473     if (FAILED(hr))
6474     {
6475         skip("Couldn't lock attributes buffer.\n");
6476         goto cleanup;
6477     }
6478 
6479     if (attributes)
6480         memcpy(attributes_buffer, attributes, num_faces * sizeof(*attributes));
6481     else
6482         memset(attributes_buffer, 0, num_faces * sizeof(*attributes));
6483 
6484     hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6485     if (FAILED(hr))
6486     {
6487         skip("Couldn't unlock attributes buffer.\n");
6488         goto cleanup;
6489     }
6490 
6491     hr = D3D_OK;
6492 cleanup:
6493     return hr;
6494 }
6495 
6496 /* Using structs instead of bit-fields in order to avoid compiler issues. */
6497 struct udec3
6498 {
6499     UINT x;
6500     UINT y;
6501     UINT z;
6502     UINT w;
6503 };
6504 
6505 struct dec3n
6506 {
6507     INT x;
6508     INT y;
6509     INT z;
6510     INT w;
6511 };
6512 
6513 static DWORD init_udec3_dword(UINT x, UINT y, UINT z, UINT w)
6514 {
6515     DWORD d = 0;
6516 
6517     d |= x & 0x3ff;
6518     d |= (y << 10) & 0xffc00;
6519     d |= (z << 20) & 0x3ff00000;
6520     d |= (w << 30) & 0xc0000000;
6521 
6522     return d;
6523 }
6524 
6525 static DWORD init_dec3n_dword(INT x, INT y, INT z, INT w)
6526 {
6527     DWORD d = 0;
6528 
6529     d |= x & 0x3ff;
6530     d |= (y << 10) & 0xffc00;
6531     d |= (z << 20) & 0x3ff00000;
6532     d |= (w << 30) & 0xc0000000;
6533 
6534     return d;
6535 }
6536 
6537 static struct udec3 dword_to_udec3(DWORD d)
6538 {
6539     struct udec3 v;
6540 
6541     v.x = d & 0x3ff;
6542     v.y = (d & 0xffc00) >> 10;
6543     v.z = (d & 0x3ff00000) >> 20;
6544     v.w = (d & 0xc0000000) >> 30;
6545 
6546     return v;
6547 }
6548 
6549 static struct dec3n dword_to_dec3n(DWORD d)
6550 {
6551     struct dec3n v;
6552 
6553     v.x = d & 0x3ff;
6554     v.y = (d & 0xffc00) >> 10;
6555     v.z = (d & 0x3ff00000) >> 20;
6556     v.w = (d & 0xc0000000) >> 30;
6557 
6558     return v;
6559 }
6560 
6561 static void check_vertex_components(int line, int mesh_number, int vertex_number, BYTE *got_ptr, const BYTE *exp_ptr, D3DVERTEXELEMENT9 *declaration)
6562 {
6563     const char *usage_strings[] =
6564     {
6565         "position",
6566         "blend weight",
6567         "blend indices",
6568         "normal",
6569         "point size",
6570         "texture coordinates",
6571         "tangent",
6572         "binormal",
6573         "tessellation factor",
6574         "position transformed",
6575         "color",
6576         "fog",
6577         "depth",
6578         "sample"
6579     };
6580     D3DVERTEXELEMENT9 *decl_ptr;
6581     const float PRECISION = 1e-5f;
6582 
6583     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
6584     {
6585         switch (decl_ptr->Type)
6586         {
6587             case D3DDECLTYPE_FLOAT1:
6588             {
6589                 FLOAT *got = (FLOAT*)(got_ptr + decl_ptr->Offset);
6590                 FLOAT *exp = (FLOAT*)(exp_ptr + decl_ptr->Offset);
6591                 FLOAT diff = fabsf(*got - *exp);
6592                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got %f for vertex %d %s, expected %f.\n",
6593                     mesh_number, *got, vertex_number, usage_strings[decl_ptr->Usage], *exp);
6594                 break;
6595             }
6596             case D3DDECLTYPE_FLOAT2:
6597             {
6598                 D3DXVECTOR2 *got = (D3DXVECTOR2*)(got_ptr + decl_ptr->Offset);
6599                 D3DXVECTOR2 *exp = (D3DXVECTOR2*)(exp_ptr + decl_ptr->Offset);
6600                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6601                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f) for vertex %d %s, expected (%f, %f).\n",
6602                     mesh_number, got->x, got->y, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y);
6603                 break;
6604             }
6605             case D3DDECLTYPE_FLOAT3:
6606             {
6607                 D3DXVECTOR3 *got = (D3DXVECTOR3*)(got_ptr + decl_ptr->Offset);
6608                 D3DXVECTOR3 *exp = (D3DXVECTOR3*)(exp_ptr + decl_ptr->Offset);
6609                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6610                 diff = max(diff, fabsf(got->z - exp->z));
6611                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f) for vertex %d %s, expected (%f, %f, %f).\n",
6612                     mesh_number, got->x, got->y, got->z, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y, exp->z);
6613                 break;
6614             }
6615             case D3DDECLTYPE_FLOAT4:
6616             {
6617                 D3DXVECTOR4 *got = (D3DXVECTOR4*)(got_ptr + decl_ptr->Offset);
6618                 D3DXVECTOR4 *exp = (D3DXVECTOR4*)(exp_ptr + decl_ptr->Offset);
6619                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6620                 diff = max(diff, fabsf(got->z - exp->z));
6621                 diff = max(diff, fabsf(got->w - exp->w));
6622                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f, %f) for vertex %d %s, expected (%f, %f, %f, %f).\n",
6623                     mesh_number, got->x, got->y, got->z, got->w, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y, exp->z, got->w);
6624                 break;
6625             }
6626             case D3DDECLTYPE_D3DCOLOR:
6627             {
6628                 BYTE *got = got_ptr + decl_ptr->Offset;
6629                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6630                 BOOL same_color = got[0] == exp[0] && got[1] == exp[1]
6631                                   && got[2] == exp[2] && got[3] == exp[3];
6632                 const char *color_types[] = {"diffuse", "specular", "undefined color"};
6633                 BYTE usage_index = decl_ptr->UsageIndex;
6634                 if (usage_index > 1) usage_index = 2;
6635                 ok_(__FILE__,line)(same_color, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6636                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, color_types[usage_index], exp[0], exp[1], exp[2], exp[3]);
6637                 break;
6638             }
6639             case D3DDECLTYPE_UBYTE4:
6640             case D3DDECLTYPE_UBYTE4N:
6641             {
6642                 BYTE *got = got_ptr + decl_ptr->Offset;
6643                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6644                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6645                             && got[2] == exp[2] && got[3] == exp[3];
6646                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6647                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1], exp[2], exp[3]);
6648                 break;
6649             }
6650             case D3DDECLTYPE_SHORT2:
6651             case D3DDECLTYPE_SHORT2N:
6652             {
6653                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6654                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6655                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6656                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd) for vertex %d %s, expected (%hd, %hd).\n",
6657                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6658                 break;
6659             }
6660             case D3DDECLTYPE_SHORT4:
6661             case D3DDECLTYPE_SHORT4N:
6662             {
6663                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6664                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6665                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6666                             && got[2] == exp[2] && got[3] == exp[3];
6667                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd, %hd, %hd) for vertex %d %s, expected (%hd, %hd, %hd, %hd).\n",
6668                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1], exp[2], exp[3]);
6669                 break;
6670             }
6671             case D3DDECLTYPE_USHORT2N:
6672             {
6673                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6674                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6675                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6676                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu) for vertex %d %s, expected (%hu, %hu).\n",
6677                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6678                 break;
6679             }
6680             case D3DDECLTYPE_USHORT4N:
6681             {
6682                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6683                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6684                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6685                             && got[2] == exp[2] && got[3] == exp[3];
6686                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu, %hu, %hu) for vertex %d %s, expected (%hu, %hu, %hu, %hu).\n",
6687                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1], exp[2], exp[3]);
6688                 break;
6689             }
6690             case D3DDECLTYPE_UDEC3:
6691             {
6692                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6693                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6694                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6695                 struct udec3 got_udec3 = dword_to_udec3(*got);
6696                 struct udec3 exp_udec3 = dword_to_udec3(*exp);
6697                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6698                     mesh_number, got_udec3.x, got_udec3.y, got_udec3.z, got_udec3.w, vertex_number, usage_strings[decl_ptr->Usage], exp_udec3.x, exp_udec3.y, exp_udec3.z, exp_udec3.w);
6699 
6700                 break;
6701             }
6702             case D3DDECLTYPE_DEC3N:
6703             {
6704                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6705                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6706                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6707                 struct dec3n got_dec3n = dword_to_dec3n(*got);
6708                 struct dec3n exp_dec3n = dword_to_dec3n(*exp);
6709                 ok_(__FILE__,line)(same, "Mesh %d: Got (%d, %d, %d, %d) for vertex %d %s, expected (%d, %d, %d, %d).\n",
6710                     mesh_number, got_dec3n.x, got_dec3n.y, got_dec3n.z, got_dec3n.w, vertex_number, usage_strings[decl_ptr->Usage], exp_dec3n.x, exp_dec3n.y, exp_dec3n.z, exp_dec3n.w);
6711                 break;
6712             }
6713             case D3DDECLTYPE_FLOAT16_2:
6714             {
6715                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6716                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6717                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6718                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx) for vertex %d %s, expected (%hx, %hx).\n",
6719                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6720                 break;
6721             }
6722             case D3DDECLTYPE_FLOAT16_4:
6723             {
6724                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6725                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6726                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6727                             && got[2] == exp[2] && got[3] == exp[3];
6728                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx, %hx, %hx) for vertex %d %s, expected (%hx, %hx, %hx, %hx).\n",
6729                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1], exp[3], exp[4]);
6730                 break;
6731             }
6732             default:
6733                 break;
6734         }
6735     }
6736 }
6737 
6738 static void test_weld_vertices(void)
6739 {
6740     HRESULT hr;
6741     struct test_context *test_context = NULL;
6742     DWORD i;
6743     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
6744     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
6745     BYTE *vertices = NULL;
6746     DWORD *indices = NULL;
6747     WORD *indices_16bit = NULL;
6748     const UINT VERTS_PER_FACE = 3;
6749 #ifndef __REACTOS__
6750     const D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
6751 #else
6752 #define up {0.0f, 0.0f, 1.0f}
6753 #endif
6754     struct vertex_normal
6755     {
6756         D3DXVECTOR3 position;
6757         D3DXVECTOR3 normal;
6758     };
6759     struct vertex_blendweight
6760     {
6761         D3DXVECTOR3 position;
6762         FLOAT blendweight;
6763     };
6764     struct vertex_texcoord
6765     {
6766         D3DXVECTOR3 position;
6767         D3DXVECTOR2 texcoord;
6768     };
6769     struct vertex_color
6770     {
6771         D3DXVECTOR3 position;
6772         DWORD color;
6773     };
6774     struct vertex_color_ubyte4
6775     {
6776         D3DXVECTOR3 position;
6777         BYTE color[4];
6778     };
6779     struct vertex_texcoord_short2
6780     {
6781         D3DXVECTOR3 position;
6782         SHORT texcoord[2];
6783     };
6784     struct vertex_texcoord_ushort2n
6785     {
6786         D3DXVECTOR3 position;
6787         USHORT texcoord[2];
6788     };
6789     struct vertex_normal_short4
6790     {
6791         D3DXVECTOR3 position;
6792         SHORT normal[4];
6793     };
6794     struct vertex_texcoord_float16_2
6795     {
6796         D3DXVECTOR3 position;
6797         WORD texcoord[2];
6798     };
6799     struct vertex_texcoord_float16_4
6800     {
6801         D3DXVECTOR3 position;
6802         WORD texcoord[4];
6803     };
6804     struct vertex_normal_udec3
6805     {
6806         D3DXVECTOR3 position;
6807         DWORD normal;
6808     };
6809     struct vertex_normal_dec3n
6810     {
6811         D3DXVECTOR3 position;
6812         DWORD normal;
6813     };
6814     UINT vertex_size_normal = sizeof(struct vertex_normal);
6815     UINT vertex_size_blendweight = sizeof(struct vertex_blendweight);
6816     UINT vertex_size_texcoord = sizeof(struct vertex_texcoord);
6817     UINT vertex_size_color = sizeof(struct vertex_color);
6818     UINT vertex_size_color_ubyte4 = sizeof(struct vertex_color_ubyte4);
6819     UINT vertex_size_texcoord_short2 = sizeof(struct vertex_texcoord_short2);
6820     UINT vertex_size_normal_short4 = sizeof(struct vertex_normal_short4);
6821     UINT vertex_size_texcoord_float16_2 = sizeof(struct vertex_texcoord_float16_2);
6822     UINT vertex_size_texcoord_float16_4 = sizeof(struct vertex_texcoord_float16_4);
6823     UINT vertex_size_normal_udec3 = sizeof(struct vertex_normal_udec3);
6824     UINT vertex_size_normal_dec3n = sizeof(struct vertex_normal_dec3n);
6825     D3DVERTEXELEMENT9 declaration_normal[] =
6826     {
6827         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6828         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6829         D3DDECL_END()
6830     };
6831     D3DVERTEXELEMENT9 declaration_normal3[] =
6832     {
6833         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 3},
6834         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6835         D3DDECL_END()
6836     };
6837     D3DVERTEXELEMENT9 declaration_blendweight[] =
6838     {
6839         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6840         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
6841         D3DDECL_END()
6842     };
6843     D3DVERTEXELEMENT9 declaration_texcoord[] =
6844     {
6845         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6846         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6847         D3DDECL_END()
6848     };
6849     D3DVERTEXELEMENT9 declaration_color[] =
6850     {
6851         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6852         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6853         D3DDECL_END()
6854     };
6855     D3DVERTEXELEMENT9 declaration_color_ubyte4n[] =
6856     {
6857         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6858         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6859         D3DDECL_END()
6860     };
6861     D3DVERTEXELEMENT9 declaration_color_ubyte4[] =
6862     {
6863         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6864         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6865         D3DDECL_END()
6866     };
6867     D3DVERTEXELEMENT9 declaration_texcoord_short2[] =
6868     {
6869         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6870         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6871         D3DDECL_END()
6872     };
6873     D3DVERTEXELEMENT9 declaration_texcoord_short2n[] =
6874     {
6875         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6876         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6877         D3DDECL_END()
6878     };
6879     D3DVERTEXELEMENT9 declaration_texcoord_ushort2n[] =
6880     {
6881         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6882         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6883         D3DDECL_END()
6884     };
6885     D3DVERTEXELEMENT9 declaration_normal_short4[] =
6886     {
6887         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6888         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6889         D3DDECL_END()
6890     };
6891     D3DVERTEXELEMENT9 declaration_normal_short4n[] =
6892     {
6893         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6894         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6895         D3DDECL_END()
6896     };
6897     D3DVERTEXELEMENT9 declaration_normal_ushort4n[] =
6898     {
6899         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6900         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6901         D3DDECL_END()
6902     };
6903     D3DVERTEXELEMENT9 declaration_texcoord10[] =
6904     {
6905         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6906         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 10},
6907         D3DDECL_END()
6908     };
6909     D3DVERTEXELEMENT9 declaration_color2[] =
6910     {
6911         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6912         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
6913         D3DDECL_END()
6914     };
6915     D3DVERTEXELEMENT9 declaration_color1[] =
6916     {
6917         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6918         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
6919         D3DDECL_END()
6920     };
6921     D3DVERTEXELEMENT9 declaration_texcoord_float16_2[] =
6922     {
6923         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6924         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6925         D3DDECL_END()
6926     };
6927     D3DVERTEXELEMENT9 declaration_texcoord_float16_4[] =
6928     {
6929         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6930         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6931         D3DDECL_END()
6932     };
6933     D3DVERTEXELEMENT9 declaration_normal_udec3[] =
6934    {
6935         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6936         {0, 12, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6937         D3DDECL_END()
6938     };
6939     D3DVERTEXELEMENT9 declaration_normal_dec3n[] =
6940     {
6941         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6942         {0, 12, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6943         D3DDECL_END()
6944     };
6945     /* Test 0. One face and no welding.
6946      *
6947      * 0--1
6948      * | /
6949      * |/
6950      * 2
6951      */
6952     const struct vertex vertices0[] =
6953     {
6954         {{ 0.0f,  3.0f,  0.f}, up},
6955         {{ 2.0f,  3.0f,  0.f}, up},
6956         {{ 0.0f,  0.0f,  0.f}, up},
6957     };
6958     const DWORD indices0[] = {0, 1, 2};
6959     const DWORD attributes0[] = {0};
6960     const DWORD exp_indices0[] = {0, 1, 2};
6961     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
6962     const UINT num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
6963     const DWORD flags0 = D3DXWELDEPSILONS_WELDALL;
6964     /* epsilons0 is NULL */
6965     const DWORD adjacency0[] = {-1, -1, -1};
6966     const struct vertex exp_vertices0[] =
6967     {
6968         {{ 0.0f,  3.0f,  0.f}, up},
6969         {{ 2.0f,  3.0f,  0.f}, up},
6970         {{ 0.0f,  0.0f,  0.f}, up},
6971     };
6972     const DWORD exp_face_remap0[] = {0};
6973     const DWORD exp_vertex_remap0[] = {0, 1, 2};
6974     const DWORD exp_new_num_vertices0 = ARRAY_SIZE(exp_vertices0);
6975     /* Test 1. Two vertices should be removed without regard to epsilon.
6976      *
6977      * 0--1 3
6978      * | / /|
6979      * |/ / |
6980      * 2 5--4
6981      */
6982     const struct vertex_normal vertices1[] =
6983     {
6984         {{ 0.0f,  3.0f,  0.f}, up},
6985         {{ 2.0f,  3.0f,  0.f}, up},
6986         {{ 0.0f,  0.0f,  0.f}, up},
6987 
6988         {{ 3.0f,  3.0f,  0.f}, up},
6989         {{ 3.0f,  0.0f,  0.f}, up},
6990         {{ 1.0f,  0.0f,  0.f}, up},
6991     };
6992     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
6993     const DWORD attributes1[] = {0, 0};
6994     const UINT num_vertices1 = ARRAY_SIZE(vertices1);
6995     const UINT num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
6996     const DWORD flags1 = D3DXWELDEPSILONS_WELDALL;
6997     /* epsilons1 is NULL */
6998     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
6999     const struct vertex_normal exp_vertices1[] =
7000     {
7001         {{ 0.0f,  3.0f,  0.f}, up},
7002         {{ 2.0f,  3.0f,  0.f}, up},
7003         {{ 0.0f,  0.0f,  0.f}, up},
7004 
7005         {{ 3.0f,  0.0f,  0.f}, up}
7006     };
7007     const DWORD exp_indices1[] = {0, 1, 2, 1, 3, 2};
7008     const DWORD exp_face_remap1[] = {0, 1};
7009     const DWORD exp_vertex_remap1[] = {0, 1, 2, 4, -1, -1};
7010     const DWORD exp_new_num_vertices1 = ARRAY_SIZE(exp_vertices1);
7011     /* Test 2. Two faces. No vertices should be removed because of normal
7012      * epsilon, but the positions should be replaced. */
7013     const struct vertex_normal vertices2[] =
7014     {
7015         {{ 0.0f,  3.0f,  0.f}, up},
7016         {{ 2.0f,  3.0f,  0.f}, up},
7017         {{ 0.0f,  0.0f,  0.f}, up},
7018 
7019         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7020         {{ 3.0f,  0.0f,  0.f}, up},
7021         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7022     };
7023     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
7024     const DWORD attributes2[] = {0, 0};
7025     const UINT num_vertices2 = ARRAY_SIZE(vertices2);
7026     const UINT num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
7027     DWORD flags2 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7028     const D3DXWELDEPSILONS epsilons2 = {1.0f, 0.0f, 0.499999f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7029     const DWORD adjacency2[] = {-1, 1, -1, -1, -1, 0};
7030     const struct vertex_normal exp_vertices2[] =
7031     {
7032         {{ 0.0f,  3.0f,  0.f}, up},
7033         {{ 2.0f,  3.0f,  0.f}, up},
7034         {{ 0.0f,  0.0f,  0.f}, up},
7035 
7036         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7037         {{ 3.0f,  0.0f,  0.f}, up},
7038         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7039     };
7040     const DWORD exp_indices2[] = {0, 1, 2, 3, 4, 5};
7041     const DWORD exp_face_remap2[] = {0, 1};
7042     const DWORD exp_vertex_remap2[] = {0, 1, 2, 3, 4, 5};
7043     const DWORD exp_new_num_vertices2 = ARRAY_SIZE(exp_vertices2);
7044     /* Test 3. Two faces. One vertex should be removed because of normal epsilon. */
7045     const struct vertex_normal vertices3[] =
7046     {
7047         {{ 0.0f,  3.0f,  0.f}, up},
7048         {{ 2.0f,  3.0f,  0.f}, up},
7049         {{ 0.0f,  0.0f,  0.f}, up},
7050 
7051         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7052         {{ 3.0f,  0.0f,  0.f}, up},
7053         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7054     };
7055     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
7056     const DWORD attributes3[] = {0, 0};
7057     const UINT num_vertices3 = ARRAY_SIZE(vertices3);
7058     const UINT num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
7059     DWORD flags3 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7060     const D3DXWELDEPSILONS epsilons3 = {1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7061     const DWORD adjacency3[] = {-1, 1, -1, -1, -1, 0};
7062     const struct vertex_normal exp_vertices3[] =
7063     {
7064         {{ 0.0f,  3.0f,  0.f}, up},
7065         {{ 2.0f,  3.0f,  0.f}, up},
7066         {{ 0.0f,  0.0f,  0.f}, up},
7067 
7068         {{ 3.0f,  0.0f,  0.f}, up},
7069         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7070     };
7071     const DWORD exp_indices3[] = {0, 1, 2, 1, 3, 4};
7072     const DWORD exp_face_remap3[] = {0, 1};
7073     const DWORD exp_vertex_remap3[] = {0, 1, 2, 4, 5, -1};
7074     const DWORD exp_new_num_vertices3 = ARRAY_SIZE(exp_vertices3);
7075     /* Test 4  Two faces. Two vertices should be removed. */
7076     const struct vertex_normal vertices4[] =
7077     {
7078         {{ 0.0f,  3.0f,  0.f}, up},
7079         {{ 2.0f,  3.0f,  0.f}, up},
7080         {{ 0.0f,  0.0f,  0.f}, up},
7081 
7082         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7083         {{ 3.0f,  0.0f,  0.f}, up},
7084         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7085     };
7086     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
7087     const DWORD attributes4[] = {0, 0};
7088     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
7089     const UINT num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
7090     DWORD flags4 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7091     const D3DXWELDEPSILONS epsilons4 = {1.0f, 0.0f, 0.6f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7092     const DWORD adjacency4[] = {-1, 1, -1, -1, -1, 0};
7093     const struct vertex_normal exp_vertices4[] =
7094     {
7095         {{ 0.0f,  3.0f,  0.f}, up},
7096         {{ 2.0f,  3.0f,  0.f}, up},
7097         {{ 0.0f,  0.0f,  0.f}, up},
7098 
7099         {{ 3.0f,  0.0f,  0.f}, up},
7100     };
7101     const DWORD exp_indices4[] = {0, 1, 2, 1, 3, 2};
7102     const DWORD exp_face_remap4[] = {0, 1};
7103     const DWORD exp_vertex_remap4[] = {0, 1, 2, 4, -1, -1};
7104     const DWORD exp_new_num_vertices4 = ARRAY_SIZE(exp_vertices4);
7105     /* Test 5. Odd face ordering.
7106      *
7107      * 0--1 6 3
7108      * | / /| |\
7109      * |/ / | | \
7110      * 2 8--7 5--4
7111      */
7112     const struct vertex_normal vertices5[] =
7113     {
7114         {{ 0.0f,  3.0f,  0.f}, up},
7115         {{ 2.0f,  3.0f,  0.f}, up},
7116         {{ 0.0f,  0.0f,  0.f}, up},
7117 
7118         {{ 3.0f,  3.0f,  0.f}, up},
7119         {{ 3.0f,  0.0f,  0.f}, up},
7120         {{ 1.0f,  0.0f,  0.f}, up},
7121 
7122         {{ 4.0f,  3.0f,  0.f}, up},
7123         {{ 6.0f,  0.0f,  0.f}, up},
7124         {{ 4.0f,  0.0f,  0.f}, up},
7125     };
7126     const DWORD indices5[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
7127     const DWORD exp_indices5[] = {0, 1, 2, 1, 4, 2, 1, 3, 4};
7128     const DWORD attributes5[] = {0, 0, 0};
7129     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
7130     const UINT num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
7131     DWORD flags5 = D3DXWELDEPSILONS_WELDALL;
7132     const DWORD adjacency5[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
7133     const struct vertex_normal exp_vertices5[] =
7134     {
7135         {{ 0.0f,  3.0f,  0.f}, up},
7136         {{ 2.0f,  3.0f,  0.f}, up},
7137         {{ 0.0f,  0.0f,  0.f}, up},
7138 
7139         {{ 3.0f,  0.0f,  0.f}, up},
7140         {{ 1.0f,  0.0f,  0.f}, up},
7141     };
7142     const DWORD exp_face_remap5[] = {0, 1, 2};
7143     const DWORD exp_vertex_remap5[] = {0, 1, 2, 4, 5, -1, -1, -1, -1};
7144     const DWORD exp_new_num_vertices5 = ARRAY_SIZE(exp_vertices5);
7145     /* Test 6. Two faces. Do not remove flag is used, so no vertices should be
7146      * removed. */
7147     const struct vertex_normal vertices6[] =
7148     {
7149         {{ 0.0f,  3.0f,  0.f}, up},
7150         {{ 2.0f,  3.0f,  0.f}, up},
7151         {{ 0.0f,  0.0f,  0.f}, up},
7152 
7153         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7154         {{ 3.0f,  0.0f,  0.f}, up},
7155         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7156     };
7157     const DWORD indices6[] = {0, 1, 2, 3, 4, 5};
7158     const DWORD attributes6[] = {0, 0};
7159     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
7160     const UINT num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
7161     DWORD flags6 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTREMOVEVERTICES;
7162     const D3DXWELDEPSILONS epsilons6 = {1.0f, 0.0f, 0.6f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7163     const DWORD adjacency6[] = {-1, 1, -1, -1, -1, 0};
7164     const struct vertex_normal exp_vertices6[] =
7165     {
7166         {{ 0.0f,  3.0f,  0.f}, up},
7167         {{ 2.0f,  3.0f,  0.f}, up},
7168         {{ 0.0f,  0.0f,  0.f}, up},
7169 
7170         {{ 2.0f,  3.0f,  0.f}, up},
7171         {{ 3.0f,  0.0f,  0.f}, up},
7172         {{ 0.0f,  0.0f,  0.f}, up},
7173 
7174     };
7175     const DWORD exp_indices6[] = {0, 1, 2, 3, 4, 5};
7176     const DWORD exp_face_remap6[] = {0, 1};
7177     const DWORD exp_vertex_remap6[] = {0, 1, 2, 3, 4, 5};
7178     const DWORD exp_new_num_vertices6 = ARRAY_SIZE(exp_vertices6);
7179     /* Test 7. Same as test 6 but with 16 bit indices. */
7180     const WORD indices6_16bit[] = {0, 1, 2, 3, 4, 5};
7181     /* Test 8. No flags. Same result as D3DXWELDEPSILONS_WELDPARTIALMATCHES. */
7182     const struct vertex_normal vertices8[] =
7183     {
7184         {{ 0.0f,  3.0f,  0.f}, up},
7185         {{ 2.0f,  3.0f,  0.f}, up},
7186         {{ 0.0f,  0.0f,  0.f}, up},
7187 
7188         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7189         {{ 3.0f,  0.0f,  0.f}, up},
7190         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7191     };
7192     const DWORD indices8[] = {0, 1, 2, 1, 3, 4};
7193     const DWORD attributes8[] = {0, 0};
7194     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
7195     const UINT num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
7196     DWORD flags8 = 0;
7197     const D3DXWELDEPSILONS epsilons8 = {1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7198     const DWORD adjacency8[] = {-1, 1, -1, -1, -1, 0};
7199     const struct vertex_normal exp_vertices8[] =
7200     {
7201         {{ 0.0f,  3.0f,  0.f}, up},
7202         {{ 2.0f,  3.0f,  0.f}, up},
7203         {{ 0.0f,  0.0f,  0.f}, up},
7204 
7205         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7206         {{ 3.0f,  0.0f,  0.f}, up},
7207     };
7208     const DWORD exp_indices8[] = {0, 1, 2, 1, 3, 4};
7209     const DWORD exp_face_remap8[] = {0, 1};
7210     const DWORD exp_vertex_remap8[] = {0, 1, 2, 3, 4, -1};
7211     const DWORD exp_new_num_vertices8 = ARRAY_SIZE(exp_vertices8);
7212     /* Test 9. Vertices are removed even though they belong to separate
7213      * attribute groups if D3DXWELDEPSILONS_DONOTSPLIT is set. */
7214     const struct vertex_normal vertices9[] =
7215     {
7216         {{ 0.0f,  3.0f,  0.f}, up},
7217         {{ 2.0f,  3.0f,  0.f}, up},
7218         {{ 0.0f,  0.0f,  0.f}, up},
7219 
7220         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7221         {{ 3.0f,  0.0f,  0.f}, up},
7222         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7223     };
7224     const DWORD indices9[] = {0, 1, 2, 3, 4, 5};
7225     const DWORD attributes9[] = {0, 1};
7226     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
7227     const UINT num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
7228     DWORD flags9 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTSPLIT;
7229     const D3DXWELDEPSILONS epsilons9 = {1.0f, 0.0f, 0.6f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7230     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
7231     const struct vertex_normal exp_vertices9[] =
7232     {
7233         {{ 0.0f,  3.0f,  0.f}, up},
7234         {{ 2.0f,  3.0f,  0.f}, up},
7235         {{ 0.0f,  0.0f,  0.f}, up},
7236 
7237         {{ 3.0f,  0.0f,  0.f}, up},
7238     };
7239     const DWORD exp_indices9[] = {0, 1, 2, 1, 3, 2};
7240     const DWORD exp_face_remap9[] = {0, 1};
7241     const DWORD exp_vertex_remap9[] = {0, 1, 2, 4, -1, -1};
7242     const DWORD exp_new_num_vertices9 = ARRAY_SIZE(exp_vertices9);
7243     /* Test 10. Weld blendweight (FLOAT1). */
7244     const struct vertex_blendweight vertices10[] =
7245     {
7246         {{ 0.0f,  3.0f,  0.f}, 1.0f},
7247         {{ 2.0f,  3.0f,  0.f}, 1.0f},
7248         {{ 0.0f,  0.0f,  0.f}, 1.0f},
7249 
7250         {{ 3.0f,  3.0f,  0.f}, 0.9},
7251         {{ 3.0f,  0.0f,  0.f}, 1.0},
7252         {{ 1.0f,  0.0f,  0.f}, 0.4},
7253     };
7254     const DWORD indices10[] = {0, 1, 2, 3, 4, 5};
7255     const DWORD attributes10[] = {0, 0};
7256     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
7257     const UINT num_faces10 = ARRAY_SIZE(indices10) / VERTS_PER_FACE;
7258     DWORD flags10 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7259     const D3DXWELDEPSILONS epsilons10 = {1.0f, 0.1f + FLT_EPSILON, 0.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7260     const DWORD adjacency10[] = {-1, 1, -1, -1, -1, 0};
7261     const struct vertex_blendweight exp_vertices10[] =
7262     {
7263         {{ 0.0f,  3.0f,  0.f}, 1.0f},
7264         {{ 2.0f,  3.0f,  0.f}, 1.0f},
7265         {{ 0.0f,  0.0f,  0.f}, 1.0f},
7266 
7267         {{ 3.0f,  0.0f,  0.f}, 1.0},
7268         {{ 0.0f,  0.0f,  0.f}, 0.4},
7269     };
7270     const DWORD exp_indices10[] = {0, 1, 2, 1, 3, 4};
7271     const DWORD exp_face_remap10[] = {0, 1};
7272     const DWORD exp_vertex_remap10[] = {0, 1, 2, 4, 5, -1};
7273     const DWORD exp_new_num_vertices10 = ARRAY_SIZE(exp_vertices10);
7274     /* Test 11. Weld texture coordinates. */
7275     const struct vertex_texcoord vertices11[] =
7276     {
7277         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7278         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7279         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7280 
7281         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7282         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7283         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7284     };
7285     const DWORD indices11[] = {0, 1, 2, 3, 4, 5};
7286     const DWORD attributes11[] = {0, 0};
7287     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
7288     const UINT num_faces11 = ARRAY_SIZE(indices11) / VERTS_PER_FACE;
7289     DWORD flags11 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7290     const D3DXWELDEPSILONS epsilons11 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {0.4f + FLT_EPSILON, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7291     const DWORD adjacency11[] = {-1, 1, -1, -1, -1, 0};
7292     const struct vertex_texcoord exp_vertices11[] =
7293     {
7294         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7295         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7296         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7297 
7298         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7299         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7300     };
7301     const DWORD exp_indices11[] = {0, 1, 2, 1, 3, 4};
7302     const DWORD exp_face_remap11[] = {0, 1};
7303     const DWORD exp_vertex_remap11[] = {0, 1, 2, 4, 5, -1};
7304     const DWORD exp_new_num_vertices11 = ARRAY_SIZE(exp_vertices11);
7305     /* Test 12. Weld with color. */
7306     const struct vertex_color vertices12[] =
7307     {
7308         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7309         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7310         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7311 
7312         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7313         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7314         {{ 1.0f,  0.0f,  0.f}, 0x88888888},
7315     };
7316     const DWORD indices12[] = {0, 1, 2, 3, 4, 5};
7317     const DWORD attributes12[] = {0, 0};
7318     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
7319     const UINT num_faces12 = ARRAY_SIZE(indices12) / VERTS_PER_FACE;
7320     DWORD flags12 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7321     const D3DXWELDEPSILONS epsilons12 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7322     const DWORD adjacency12[] = {-1, 1, -1, -1, -1, 0};
7323     const struct vertex_color exp_vertices12[] =
7324     {
7325         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7326         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7327         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7328 
7329         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7330         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7331     };
7332     const DWORD exp_indices12[] = {0, 1, 2, 3, 4, 2};
7333     const DWORD exp_face_remap12[] = {0, 1};
7334     const DWORD exp_vertex_remap12[] = {0, 1, 2, 3, 4, -1};
7335     const DWORD exp_new_num_vertices12 = ARRAY_SIZE(exp_vertices12);
7336     /* Test 13. Two faces. One vertex should be removed because of normal epsilon.
7337      * This is similar to test 3, but the declaration has been changed to NORMAL3.
7338      */
7339     const struct vertex_normal vertices13[] =
7340     {
7341         {{ 0.0f,  3.0f,  0.f}, up},
7342         {{ 2.0f,  3.0f,  0.f}, up},
7343         {{ 0.0f,  0.0f,  0.f}, up},
7344 
7345         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7346         {{ 3.0f,  0.0f,  0.f}, up},
7347         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7348     };
7349     const DWORD indices13[] = {0, 1, 2, 3, 4, 5};
7350     const DWORD attributes13[] = {0, 0};
7351     const UINT num_vertices13 = ARRAY_SIZE(vertices3);
7352     const UINT num_faces13 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
7353     DWORD flags13 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7354     const D3DXWELDEPSILONS epsilons13 = {1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7355     const DWORD adjacency13[] = {-1, 1, -1, -1, -1, 0};
7356     const struct vertex_normal exp_vertices13[] =
7357     {
7358         {{ 0.0f,  3.0f,  0.f}, up},
7359         {{ 2.0f,  3.0f,  0.f}, up},
7360         {{ 0.0f,  0.0f,  0.f}, up},
7361 
7362         {{ 3.0f,  0.0f,  0.f}, up},
7363         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7364     };
7365     const DWORD exp_indices13[] = {0, 1, 2, 1, 3, 4};
7366     const DWORD exp_face_remap13[] = {0, 1};
7367     const DWORD exp_vertex_remap13[] = {0, 1, 2, 4, 5, -1};
7368     const DWORD exp_new_num_vertices13 = ARRAY_SIZE(exp_vertices13);
7369     /* Test 14. Another test for welding with color. */
7370     const struct vertex_color vertices14[] =
7371     {
7372         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7373         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7374         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7375 
7376         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7377         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7378         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7379     };
7380     const DWORD indices14[] = {0, 1, 2, 3, 4, 5};
7381     const DWORD attributes14[] = {0, 0};
7382     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
7383     const UINT num_faces14 = ARRAY_SIZE(indices14) / VERTS_PER_FACE;
7384     DWORD flags14 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7385     const D3DXWELDEPSILONS epsilons14 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 254.0f/255.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7386     const DWORD adjacency14[] = {-1, 1, -1, -1, -1, 0};
7387     const struct vertex_color exp_vertices14[] =
7388     {
7389         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7390         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7391         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7392 
7393         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7394         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7395     };
7396     const DWORD exp_indices14[] = {0, 1, 2, 3, 4, 2};
7397     const DWORD exp_face_remap14[] = {0, 1};
7398     const DWORD exp_vertex_remap14[] = {0, 1, 2, 3, 4, -1};
7399     const DWORD exp_new_num_vertices14 = ARRAY_SIZE(exp_vertices14);
7400     /* Test 15. Weld with color, but as UBYTE4N instead of D3DCOLOR. It shows
7401      * that UBYTE4N and D3DCOLOR are compared the same way.
7402      */
7403     const struct vertex_color_ubyte4 vertices15[] =
7404     {
7405         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7406         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7407         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7408 
7409         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7410         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7411         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7412     };
7413     const DWORD indices15[] = {0, 1, 2, 3, 4, 5};
7414     const DWORD attributes15[] = {0, 0};
7415     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
7416     const UINT num_faces15 = ARRAY_SIZE(indices15) / VERTS_PER_FACE;
7417     DWORD flags15 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7418     const D3DXWELDEPSILONS epsilons15 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 254.0f/255.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7419     const DWORD adjacency15[] = {-1, 1, -1, -1, -1, 0};
7420     const struct vertex_color_ubyte4 exp_vertices15[] =
7421     {
7422         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7423         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7424         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7425 
7426         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7427         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7428     };
7429     const DWORD exp_indices15[] = {0, 1, 2, 3, 4, 2};
7430     const DWORD exp_face_remap15[] = {0, 1};
7431     const DWORD exp_vertex_remap15[] = {0, 1, 2, 3, 4, -1};
7432     const DWORD exp_new_num_vertices15 = ARRAY_SIZE(exp_vertices15);
7433     /* Test 16. Weld with color, but as UBYTE4 instead of D3DCOLOR. It shows
7434      * that UBYTE4 is not normalized and that epsilon is truncated and compared
7435      * directly to each of the four bytes.
7436      */
7437     const struct vertex_color_ubyte4 vertices16[] =
7438     {
7439         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7440         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7441         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7442 
7443         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7444         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7445         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7446     };
7447     const DWORD indices16[] = {0, 1, 2, 3, 4, 5};
7448     const DWORD attributes16[] = {0, 0};
7449     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
7450     const UINT num_faces16 = ARRAY_SIZE(indices16) / VERTS_PER_FACE;
7451     DWORD flags16 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7452     const D3DXWELDEPSILONS epsilons16 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 254.9f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7453     const DWORD adjacency16[] = {-1, 1, -1, -1, -1, 0};
7454     const struct vertex_color_ubyte4 exp_vertices16[] =
7455     {
7456         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7457         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7458         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7459 
7460         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7461         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7462     };
7463     const DWORD exp_indices16[] = {0, 1, 2, 3, 4, 2};
7464     const DWORD exp_face_remap16[] = {0, 1};
7465     const DWORD exp_vertex_remap16[] = {0, 1, 2, 3, 4, -1};
7466     const DWORD exp_new_num_vertices16 = ARRAY_SIZE(exp_vertices16);
7467     /* Test 17. Weld texture coordinates but as SHORT2 instead of D3DXVECTOR2.*/
7468     const struct vertex_texcoord_short2 vertices17[] =
7469     {
7470         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7471         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7472         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7473 
7474         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7475         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7476         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7477     };
7478     const DWORD indices17[] = {0, 1, 2, 3, 4, 5};
7479     const DWORD attributes17[] = {0, 0};
7480     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
7481     const UINT num_faces17 = ARRAY_SIZE(indices17) / VERTS_PER_FACE;
7482     DWORD flags17 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7483     const D3DXWELDEPSILONS epsilons17 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {32766.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7484     const DWORD adjacency17[] = {-1, 1, -1, -1, -1, 0};
7485     const struct vertex_texcoord_short2 exp_vertices17[] =
7486     {
7487         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7488         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7489         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7490 
7491         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7492         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7493     };
7494     const DWORD exp_indices17[] = {0, 1, 2, 3, 4, 2};
7495     const DWORD exp_face_remap17[] = {0, 1};
7496     const DWORD exp_vertex_remap17[] = {0, 1, 2, 3, 4, -1};
7497     const DWORD exp_new_num_vertices17 = ARRAY_SIZE(exp_vertices17);
7498     /* Test 18. Weld texture coordinates but as SHORT2N instead of D3DXVECTOR2. */
7499     const struct vertex_texcoord_short2 vertices18[] =
7500     {
7501         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7502         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7503         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7504 
7505         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7506         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7507         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7508     };
7509     const DWORD indices18[] = {0, 1, 2, 3, 4, 5};
7510     const DWORD attributes18[] = {0, 0};
7511     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
7512     const UINT num_faces18 = ARRAY_SIZE(indices18) / VERTS_PER_FACE;
7513     DWORD flags18 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7514     const D3DXWELDEPSILONS epsilons18 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {32766.0f/32767.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7515     const DWORD adjacency18[] = {-1, 1, -1, -1, -1, 0};
7516     const struct vertex_texcoord_short2 exp_vertices18[] =
7517     {
7518         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7519         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7520         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7521 
7522         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7523         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7524     };
7525     const DWORD exp_indices18[] = {0, 1, 2, 3, 4, 2};
7526     const DWORD exp_face_remap18[] = {0, 1};
7527     const DWORD exp_vertex_remap18[] = {0, 1, 2, 3, 4, -1};
7528     const DWORD exp_new_num_vertices18 = ARRAY_SIZE(exp_vertices18);
7529     /* Test 19.  Weld texture coordinates but as USHORT2N instead of D3DXVECTOR2. */
7530     const struct vertex_texcoord_ushort2n vertices19[] =
7531     {
7532         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7533         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7534         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7535 
7536         {{ 3.0f,  3.0f,  0.f}, {65535, 65535}},
7537         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7538         {{ 1.0f,  0.0f,  0.f}, {65534, 65534}},
7539     };
7540     const DWORD indices19[] = {0, 1, 2, 3, 4, 5};
7541     const DWORD attributes19[] = {0, 0};
7542     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
7543     const UINT num_faces19 = ARRAY_SIZE(indices19) / VERTS_PER_FACE;
7544     DWORD flags19 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7545     const D3DXWELDEPSILONS epsilons19 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {65534.0f/65535.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7546     const DWORD adjacency19[] = {-1, 1, -1, -1, -1, 0};
7547     const struct vertex_texcoord_ushort2n exp_vertices19[] =
7548     {
7549         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7550         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7551         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7552 
7553         {{ 2.0f,  3.0f,  0.f}, {65535, 65535}},
7554         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7555     };
7556     const DWORD exp_indices19[] = {0, 1, 2, 3, 4, 2};
7557     const DWORD exp_face_remap19[] = {0, 1};
7558     const DWORD exp_vertex_remap19[] = {0, 1, 2, 3, 4, -1};
7559     const DWORD exp_new_num_vertices19 = ARRAY_SIZE(exp_vertices19);
7560     /* Test 20.  Weld normal as SHORT4 instead of D3DXVECTOR3. */
7561     const struct vertex_normal_short4 vertices20[] =
7562     {
7563         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7564         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7565         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7566 
7567         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7568         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7569         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7570     };
7571     const DWORD indices20[] = {0, 1, 2, 3, 4, 5};
7572     const DWORD attributes20[] = {0, 0};
7573     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
7574     const UINT num_faces20 = ARRAY_SIZE(indices20) / VERTS_PER_FACE;
7575     DWORD flags20 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7576     const D3DXWELDEPSILONS epsilons20 = {1.0f, 0.0f, 32766.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7577     const DWORD adjacency20[] = {-1, 1, -1, -1, -1, 0};
7578     const struct vertex_normal_short4 exp_vertices20[] =
7579     {
7580         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7581         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7582         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7583 
7584         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7585         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7586     };
7587     const DWORD exp_indices20[] = {0, 1, 2, 3, 4, 2};
7588     const DWORD exp_face_remap20[] = {0, 1};
7589     const DWORD exp_vertex_remap20[] = {0, 1, 2, 3, 4, -1};
7590     const DWORD exp_new_num_vertices20 = ARRAY_SIZE(exp_vertices20);
7591     /* Test 21.  Weld normal as SHORT4N instead of D3DXVECTOR3. */
7592     const struct vertex_normal_short4 vertices21[] =
7593     {
7594         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7595         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7596         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7597 
7598         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7599         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7600         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7601     };
7602     const DWORD indices21[] = {0, 1, 2, 3, 4, 5};
7603     const DWORD attributes21[] = {0, 0};
7604     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
7605     const UINT num_faces21 = ARRAY_SIZE(indices21) / VERTS_PER_FACE;
7606     DWORD flags21 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7607     const D3DXWELDEPSILONS epsilons21 = {1.0f, 0.0f, 32766.0f/32767.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7608     const DWORD adjacency21[] = {-1, 1, -1, -1, -1, 0};
7609     const struct vertex_normal_short4 exp_vertices21[] =
7610     {
7611         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7612         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7613         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7614 
7615         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7616         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7617     };
7618     const DWORD exp_indices21[] = {0, 1, 2, 3, 4, 2};
7619     const DWORD exp_face_remap21[] = {0, 1};
7620     const DWORD exp_vertex_remap21[] = {0, 1, 2, 3, 4, -1};
7621     const DWORD exp_new_num_vertices21 = ARRAY_SIZE(exp_vertices21);
7622     /* Test 22.  Weld normal as USHORT4N instead of D3DXVECTOR3. */
7623     const struct vertex_normal_short4 vertices22[] =
7624     {
7625         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7626         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7627         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7628 
7629         {{ 3.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7630         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7631         {{ 1.0f,  0.0f,  0.f}, {65534, 65534, 65534, 65534}},
7632     };
7633     const DWORD indices22[] = {0, 1, 2, 3, 4, 5};
7634     const DWORD attributes22[] = {0, 0};
7635     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
7636     const UINT num_faces22 = ARRAY_SIZE(indices22) / VERTS_PER_FACE;
7637     DWORD flags22 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7638     const D3DXWELDEPSILONS epsilons22 = {1.0f, 0.0f, 65534.0f/65535.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7639     const DWORD adjacency22[] = {-1, 1, -1, -1, -1, 0};
7640     const struct vertex_normal_short4 exp_vertices22[] =
7641     {
7642         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7643         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7644         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7645 
7646         {{ 2.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7647         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7648     };
7649     const DWORD exp_indices22[] = {0, 1, 2, 3, 4, 2};
7650     const DWORD exp_face_remap22[] = {0, 1};
7651     const DWORD exp_vertex_remap22[] = {0, 1, 2, 3, 4, -1};
7652     const DWORD exp_new_num_vertices22 = ARRAY_SIZE(exp_vertices22);
7653     /* Test 23. Weld texture coordinates as FLOAT16_2. Similar to test 11, but
7654      * with texture coordinates converted to float16 in hex. */
7655     const struct vertex_texcoord_float16_2 vertices23[] =
7656     {
7657         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7658         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7659         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7660 
7661         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
7662         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7663         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7664     };
7665     const DWORD indices23[] = {0, 1, 2, 3, 4, 5};
7666     const DWORD attributes23[] = {0, 0};
7667     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
7668     const UINT num_faces23 = ARRAY_SIZE(indices23) / VERTS_PER_FACE;
7669     DWORD flags23 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7670     const D3DXWELDEPSILONS epsilons23 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {0.41f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7671     const DWORD adjacency23[] = {-1, 1, -1, -1, -1, 0};
7672     const struct vertex_texcoord_float16_2 exp_vertices23[] =
7673     {
7674         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7675         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7676         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7677 
7678         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7679         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7680     };
7681     const DWORD exp_indices23[] = {0, 1, 2, 1, 3, 4};
7682     const DWORD exp_face_remap23[] = {0, 1};
7683     const DWORD exp_vertex_remap23[] = {0, 1, 2, 4, 5, -1};
7684     const DWORD exp_new_num_vertices23 = ARRAY_SIZE(exp_vertices23);
7685     /* Test 24. Weld texture coordinates as FLOAT16_4. Similar to test 24. */
7686     const struct vertex_texcoord_float16_4 vertices24[] =
7687     {
7688         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7689         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7690         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7691 
7692         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0x3266, 0x34cd}},
7693         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7694         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7695     };
7696     const DWORD indices24[] = {0, 1, 2, 3, 4, 5};
7697     const DWORD attributes24[] = {0, 0};
7698     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
7699     const UINT num_faces24 = ARRAY_SIZE(indices24) / VERTS_PER_FACE;
7700     DWORD flags24 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7701     const D3DXWELDEPSILONS epsilons24 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {0.41f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7702     const DWORD adjacency24[] = {-1, 1, -1, -1, -1, 0};
7703     const struct vertex_texcoord_float16_4 exp_vertices24[] =
7704     {
7705         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7706         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7707         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7708 
7709         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7710         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7711     };
7712     const DWORD exp_indices24[] = {0, 1, 2, 1, 3, 4};
7713     const DWORD exp_face_remap24[] = {0, 1};
7714     const DWORD exp_vertex_remap24[] = {0, 1, 2, 4, 5, -1};
7715     const DWORD exp_new_num_vertices24 = ARRAY_SIZE(exp_vertices24);
7716     /* Test 25. Weld texture coordinates with usage index 10 (TEXCOORD10). The
7717      * usage index is capped at 7, so the epsilon for TEXCOORD7 is used instead.
7718      */
7719     const struct vertex_texcoord vertices25[] =
7720     {
7721         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7722         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7723         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7724 
7725         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7726         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7727         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7728     };
7729     const DWORD indices25[] = {0, 1, 2, 3, 4, 5};
7730     const DWORD attributes25[] = {0, 0};
7731     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
7732     const UINT num_faces25 = ARRAY_SIZE(indices25) / VERTS_PER_FACE;
7733     DWORD flags25 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7734     const D3DXWELDEPSILONS epsilons25 = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f + FLT_EPSILON}, 0.0f, 0.0f, 0.0f};
7735     const DWORD adjacency25[] = {-1, 1, -1, -1, -1, 0};
7736     const struct vertex_texcoord exp_vertices25[] =
7737     {
7738         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7739         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7740         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7741 
7742         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7743         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7744     };
7745     const DWORD exp_indices25[] = {0, 1, 2, 1, 3, 4};
7746     const DWORD exp_face_remap25[] = {0, 1};
7747     const DWORD exp_vertex_remap25[] = {0, 1, 2, 4, 5, -1};
7748     const DWORD exp_new_num_vertices25 = ARRAY_SIZE(exp_vertices25);
7749     /* Test 26. Weld color with usage index larger than 1. Shows that none of
7750      * the epsilon values are used. */
7751     const struct vertex_color vertices26[] =
7752     {
7753         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7754         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7755         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7756 
7757         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7758         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7759         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7760     };
7761     const DWORD indices26[] = {0, 1, 2, 3, 4, 5};
7762     const DWORD attributes26[] = {0, 0};
7763     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
7764     const UINT num_faces26 = ARRAY_SIZE(indices26) / VERTS_PER_FACE;
7765     DWORD flags26 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7766     const D3DXWELDEPSILONS epsilons26 = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, 1.0f, 1.0f, 1.0f};
7767     const DWORD adjacency26[] = {-1, 1, -1, -1, -1, 0};
7768     const struct vertex_color exp_vertices26[] =
7769     {
7770         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7771         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7772         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7773 
7774         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7775         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7776         {{ 0.0f,  0.0f,  0.f}, 0x01010101},
7777     };
7778     const DWORD exp_indices26[] = {0, 1, 2, 3, 4, 5};
7779     const DWORD exp_face_remap26[] = {0, 1};
7780     const DWORD exp_vertex_remap26[] = {0, 1, 2, 3, 4, 5};
7781     const DWORD exp_new_num_vertices26 = ARRAY_SIZE(exp_vertices26);
7782     /* Test 27. Weld color with usage index 1 (specular). */
7783     /* Previously this test used float color values and index > 1 but that case
7784      * appears to be effectively unhandled in native so the test gave
7785      * inconsistent results. */
7786     const struct vertex_color vertices27[] =
7787     {
7788         {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
7789         {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
7790         {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
7791 
7792         {{ 3.0f,  3.0f,  0.0f}, 0x11213141},
7793         {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
7794         {{ 1.0f,  0.0f,  0.0f}, 0x51617181},
7795     };
7796     const DWORD indices27[] = {0, 1, 2, 3, 4, 5};
7797     const DWORD attributes27[] = {0, 0};
7798     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
7799     const UINT num_faces27 = ARRAY_SIZE(indices27) / VERTS_PER_FACE;
7800     DWORD flags27 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7801     const D3DXWELDEPSILONS epsilons27 =
7802     {
7803         1.1f, 0.0f, 0.0f, 0.0f, 2.0f / 255.0f, 0.0f,
7804         {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f
7805     };
7806     const DWORD adjacency27[] = {-1, 1, -1, -1, -1, 0};
7807     const struct vertex_color exp_vertices27[] =
7808     {
7809         {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
7810         {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
7811         {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
7812 
7813         {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
7814     };
7815     const DWORD exp_indices27[] = {0, 1, 2, 1, 3, 2};
7816     const DWORD exp_face_remap27[] = {0, 1};
7817     const DWORD exp_vertex_remap27[] = {0, 1, 2, 4, -1, -1};
7818     const DWORD exp_new_num_vertices27 = ARRAY_SIZE(exp_vertices27);
7819     /* Test 28. Weld one normal with UDEC3. */
7820     const DWORD dword_udec3_zero = init_udec3_dword(0, 0, 0, 1);
7821     const DWORD dword_udec3_1023 = init_udec3_dword(1023, 1023, 1023, 1);
7822     const DWORD dword_udec3_1022 = init_udec3_dword(1022, 1022, 1022, 1);
7823     const struct vertex_normal_udec3 vertices28[] =
7824     {
7825         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7826         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7827         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7828 
7829         {{ 3.0f,  3.0f,  0.f}, dword_udec3_1023},
7830         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7831         {{ 1.0f,  0.0f,  0.f}, dword_udec3_1022},
7832     };
7833     const DWORD indices28[] = {0, 1, 2, 3, 4, 5};
7834     const DWORD attributes28[] = {0, 0};
7835     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
7836     const UINT num_faces28 = ARRAY_SIZE(indices28) / VERTS_PER_FACE;
7837     DWORD flags28 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7838     const D3DXWELDEPSILONS epsilons28 = {1.0f, 0.0f, 1022.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f};
7839     const DWORD adjacency28[] = {-1, 1, -1, -1, -1, 0};
7840     const struct vertex_normal_udec3 exp_vertices28[] =
7841     {
7842         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7843         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7844         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7845 
7846         {{ 2.0f,  3.0f,  0.f}, dword_udec3_1023},
7847         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7848     };
7849     const DWORD exp_indices28[] = {0, 1, 2, 3, 4, 2};
7850     const DWORD exp_face_remap28[] = {0, 1};
7851     const DWORD exp_vertex_remap28[] = {0, 1, 2, 3, 4, -1};
7852     const DWORD exp_new_num_vertices28 = ARRAY_SIZE(exp_vertices28);
7853     /* Test 29. Weld one normal with DEC3N. */
7854     const DWORD dword_dec3n_zero = init_dec3n_dword(0, 0, 0, 1);
7855     const DWORD dword_dec3n_511 = init_dec3n_dword(511, 511, 511, 1);
7856     const DWORD dword_dec3n_510 = init_dec3n_dword(510, 510, 510, 1);
7857     const struct vertex_normal_dec3n vertices29[] =
7858     {
7859         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7860         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7861         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7862 
7863         {{ 3.0f,  3.0f,  0.f}, dword_dec3n_511},
7864         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7865         {{ 1.0f,  0.0f,  0.f}, dword_dec3n_510},
7866     };
7867     const DWORD indices29[] = {0, 1, 2, 3, 4, 5};
7868     const DWORD attributes29[] = {0, 0};
7869     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
7870     const UINT num_faces29 = ARRAY_SIZE(indices29) / VERTS_PER_FACE;
7871     DWORD flags29 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7872     const D3DXWELDEPSILONS epsilons29 = {1.0f, 0.0f, 510.0f/511.0f, 0.0f, 0.0f, 0.0f, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, .0f}, 0.0f, 0.0f, 0.0f};
7873     const DWORD adjacency29[] = {-1, 1, -1, -1, -1, 0};
7874     const struct vertex_normal_dec3n exp_vertices29[] =
7875     {
7876         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7877         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7878         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7879 
7880         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_511},
7881         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7882     };
7883     const DWORD exp_indices29[] = {0, 1, 2, 3, 4, 2};
7884     const DWORD exp_face_remap29[] = {0, 1};
7885     const DWORD exp_vertex_remap29[] = {0, 1, 2, 3, 4, -1};
7886     const DWORD exp_new_num_vertices29 = ARRAY_SIZE(exp_vertices29);
7887     /* All mesh data */
7888     DWORD *adjacency_out = NULL;
7889     DWORD *face_remap = NULL;
7890     ID3DXMesh *mesh = NULL;
7891     ID3DXBuffer *vertex_remap = NULL;
7892     struct
7893     {
7894         const BYTE *vertices;
7895         const DWORD *indices;
7896         const DWORD *attributes;
7897         const DWORD num_vertices;
7898         const DWORD num_faces;
7899         const DWORD options;
7900         D3DVERTEXELEMENT9 *declaration;
7901         const UINT vertex_size;
7902         const DWORD flags;
7903         const D3DXWELDEPSILONS *epsilons;
7904         const DWORD *adjacency;
7905         const BYTE *exp_vertices;
7906         const DWORD *exp_indices;
7907         const DWORD *exp_face_remap;
7908         const DWORD *exp_vertex_remap;
7909         const DWORD exp_new_num_vertices;
7910     }
7911     tc[] =
7912     {
7913         {
7914             (BYTE*)vertices0,
7915             indices0,
7916             attributes0,
7917             num_vertices0,
7918             num_faces0,
7919             options,
7920             declaration_normal,
7921             vertex_size_normal,
7922             flags0,
7923             NULL,
7924             adjacency0,
7925             (BYTE*)exp_vertices0,
7926             exp_indices0,
7927             exp_face_remap0,
7928             exp_vertex_remap0,
7929             exp_new_num_vertices0
7930         },
7931         {
7932             (BYTE*)vertices1,
7933             indices1,
7934             attributes1,
7935             num_vertices1,
7936             num_faces1,
7937             options,
7938             declaration_normal,
7939             vertex_size_normal,
7940             flags1,
7941             NULL,
7942             adjacency1,
7943             (BYTE*)exp_vertices1,
7944             exp_indices1,
7945             exp_face_remap1,
7946             exp_vertex_remap1,
7947             exp_new_num_vertices1
7948         },
7949         {
7950             (BYTE*)vertices2,
7951             indices2,
7952             attributes2,
7953             num_vertices2,
7954             num_faces2,
7955             options,
7956             declaration_normal,
7957             vertex_size_normal,
7958             flags2,
7959             &epsilons2,
7960             adjacency2,
7961             (BYTE*)exp_vertices2,
7962             exp_indices2,
7963             exp_face_remap2,
7964             exp_vertex_remap2,
7965             exp_new_num_vertices2
7966         },
7967         {
7968             (BYTE*)vertices3,
7969             indices3,
7970             attributes3,
7971             num_vertices3,
7972             num_faces3,
7973             options,
7974             declaration_normal,
7975             vertex_size_normal,
7976             flags3,
7977             &epsilons3,
7978             adjacency3,
7979             (BYTE*)exp_vertices3,
7980             exp_indices3,
7981             exp_face_remap3,
7982             exp_vertex_remap3,
7983             exp_new_num_vertices3
7984         },
7985         {
7986             (BYTE*)vertices4,
7987             indices4,
7988             attributes4,
7989             num_vertices4,
7990             num_faces4,
7991             options,
7992             declaration_normal,
7993             vertex_size_normal,
7994             flags4,
7995             &epsilons4,
7996             adjacency4,
7997             (BYTE*)exp_vertices4,
7998             exp_indices4,
7999             exp_face_remap4,
8000             exp_vertex_remap4,
8001             exp_new_num_vertices4
8002         },
8003         /* Unusual ordering. */
8004         {
8005             (BYTE*)vertices5,
8006             indices5,
8007             attributes5,
8008             num_vertices5,
8009             num_faces5,
8010             options,
8011             declaration_normal,
8012             vertex_size_normal,
8013             flags5,
8014             NULL,
8015             adjacency5,
8016             (BYTE*)exp_vertices5,
8017             exp_indices5,
8018             exp_face_remap5,
8019             exp_vertex_remap5,
8020             exp_new_num_vertices5
8021         },
8022         {
8023             (BYTE*)vertices6,
8024             indices6,
8025             attributes6,
8026             num_vertices6,
8027             num_faces6,
8028             options,
8029             declaration_normal,
8030             vertex_size_normal,
8031             flags6,
8032             &epsilons6,
8033             adjacency6,
8034             (BYTE*)exp_vertices6,
8035             exp_indices6,
8036             exp_face_remap6,
8037             exp_vertex_remap6,
8038             exp_new_num_vertices6
8039         },
8040         {
8041             (BYTE*)vertices6,
8042             (DWORD*)indices6_16bit,
8043             attributes6,
8044             num_vertices6,
8045             num_faces6,
8046             options_16bit,
8047             declaration_normal,
8048             vertex_size_normal,
8049             flags6,
8050             &epsilons6,
8051             adjacency6,
8052             (BYTE*)exp_vertices6,
8053             exp_indices6,
8054             exp_face_remap6,
8055             exp_vertex_remap6,
8056             exp_new_num_vertices6
8057         },
8058         {
8059             (BYTE*)vertices8,
8060             indices8,
8061             attributes8,
8062             num_vertices8,
8063             num_faces8,
8064             options,
8065             declaration_normal,
8066             vertex_size_normal,
8067             flags8,
8068             &epsilons8,
8069             adjacency8,
8070             (BYTE*)exp_vertices8,
8071             exp_indices8,
8072             exp_face_remap8,
8073             exp_vertex_remap8,
8074             exp_new_num_vertices8
8075         },
8076         {
8077             (BYTE*)vertices9,
8078             indices9,
8079             attributes9,
8080             num_vertices9,
8081             num_faces9,
8082             options,
8083             declaration_normal,
8084             vertex_size_normal,
8085             flags9,
8086             &epsilons9,
8087             adjacency9,
8088             (BYTE*)exp_vertices9,
8089             exp_indices9,
8090             exp_face_remap9,
8091             exp_vertex_remap9,
8092             exp_new_num_vertices9
8093         },
8094         {
8095             (BYTE*)vertices10,
8096             indices10,
8097             attributes10,
8098             num_vertices10,
8099             num_faces10,
8100             options,
8101             declaration_blendweight,
8102             vertex_size_blendweight,
8103             flags10,
8104             &epsilons10,
8105             adjacency10,
8106             (BYTE*)exp_vertices10,
8107             exp_indices10,
8108             exp_face_remap10,
8109             exp_vertex_remap10,
8110             exp_new_num_vertices10
8111         },
8112         {
8113             (BYTE*)vertices11,
8114             indices11,
8115             attributes11,
8116             num_vertices11,
8117             num_faces11,
8118             options,
8119             declaration_texcoord,
8120             vertex_size_texcoord,
8121             flags11,
8122             &epsilons11,
8123             adjacency11,
8124             (BYTE*)exp_vertices11,
8125             exp_indices11,
8126             exp_face_remap11,
8127             exp_vertex_remap11,
8128             exp_new_num_vertices11
8129         },
8130         {
8131             (BYTE*)vertices12,
8132             indices12,
8133             attributes12,
8134             num_vertices12,
8135             num_faces12,
8136             options,
8137             declaration_color,
8138             vertex_size_color,
8139             flags12,
8140             &epsilons12,
8141             adjacency12,
8142             (BYTE*)exp_vertices12,
8143             exp_indices12,
8144             exp_face_remap12,
8145             exp_vertex_remap12,
8146             exp_new_num_vertices12
8147         },
8148         {
8149             (BYTE*)vertices13,
8150             indices13,
8151             attributes13,
8152             num_vertices13,
8153             num_faces13,
8154             options,
8155             declaration_normal3,
8156             vertex_size_normal,
8157             flags13,
8158             &epsilons13,
8159             adjacency13,
8160             (BYTE*)exp_vertices13,
8161             exp_indices13,
8162             exp_face_remap13,
8163             exp_vertex_remap13,
8164             exp_new_num_vertices13
8165         },
8166         {
8167             (BYTE*)vertices14,
8168             indices14,
8169             attributes14,
8170             num_vertices14,
8171             num_faces14,
8172             options,
8173             declaration_color,
8174             vertex_size_color,
8175             flags14,
8176             &epsilons14,
8177             adjacency14,
8178             (BYTE*)exp_vertices14,
8179             exp_indices14,
8180             exp_face_remap14,
8181             exp_vertex_remap14,
8182             exp_new_num_vertices14
8183         },
8184         {
8185             (BYTE*)vertices15,
8186             indices15,
8187             attributes15,
8188             num_vertices15,
8189             num_faces15,
8190             options,
8191             declaration_color_ubyte4n,
8192             vertex_size_color_ubyte4, /* UBYTE4 same size as UBYTE4N */
8193             flags15,
8194             &epsilons15,
8195             adjacency15,
8196             (BYTE*)exp_vertices15,
8197             exp_indices15,
8198             exp_face_remap15,
8199             exp_vertex_remap15,
8200             exp_new_num_vertices15
8201         },
8202         {
8203             (BYTE*)vertices16,
8204             indices16,
8205             attributes16,
8206             num_vertices16,
8207             num_faces16,
8208             options,
8209             declaration_color_ubyte4,
8210             vertex_size_color_ubyte4,
8211             flags16,
8212             &epsilons16,
8213             adjacency16,
8214             (BYTE*)exp_vertices16,
8215             exp_indices16,
8216             exp_face_remap16,
8217             exp_vertex_remap16,
8218             exp_new_num_vertices16
8219         },
8220         {
8221             (BYTE*)vertices17,
8222             indices17,
8223             attributes17,
8224             num_vertices17,
8225             num_faces17,
8226             options,
8227             declaration_texcoord_short2,
8228             vertex_size_texcoord_short2,
8229             flags17,
8230             &epsilons17,
8231             adjacency17,
8232             (BYTE*)exp_vertices17,
8233             exp_indices17,
8234             exp_face_remap17,
8235             exp_vertex_remap17,
8236             exp_new_num_vertices17
8237         },
8238         {
8239             (BYTE*)vertices18,
8240             indices18,
8241             attributes18,
8242             num_vertices18,
8243             num_faces18,
8244             options,
8245             declaration_texcoord_short2n,
8246             vertex_size_texcoord_short2, /* SHORT2 same size as SHORT2N */
8247             flags18,
8248             &epsilons18,
8249             adjacency18,
8250             (BYTE*)exp_vertices18,
8251             exp_indices18,
8252             exp_face_remap18,
8253             exp_vertex_remap18,
8254             exp_new_num_vertices18
8255         },
8256         {
8257             (BYTE*)vertices19,
8258             indices19,
8259             attributes19,
8260             num_vertices19,
8261             num_faces19,
8262             options,
8263             declaration_texcoord_ushort2n,
8264             vertex_size_texcoord_short2, /* SHORT2 same size as USHORT2N */
8265             flags19,
8266             &epsilons19,
8267             adjacency19,
8268             (BYTE*)exp_vertices19,
8269             exp_indices19,
8270             exp_face_remap19,
8271             exp_vertex_remap19,
8272             exp_new_num_vertices19
8273         },
8274         {
8275             (BYTE*)vertices20,
8276             indices20,
8277             attributes20,
8278             num_vertices20,
8279             num_faces20,
8280             options,
8281             declaration_normal_short4,
8282             vertex_size_normal_short4,
8283             flags20,
8284             &epsilons20,
8285             adjacency20,
8286             (BYTE*)exp_vertices20,
8287             exp_indices20,
8288             exp_face_remap20,
8289             exp_vertex_remap20,
8290             exp_new_num_vertices20
8291         },
8292         {
8293             (BYTE*)vertices21,
8294             indices21,
8295             attributes21,
8296             num_vertices21,
8297             num_faces21,
8298             options,
8299             declaration_normal_short4n,
8300             vertex_size_normal_short4, /* SHORT4 same size as SHORT4N */
8301             flags21,
8302             &epsilons21,
8303             adjacency21,
8304             (BYTE*)exp_vertices21,
8305             exp_indices21,
8306             exp_face_remap21,
8307             exp_vertex_remap21,
8308             exp_new_num_vertices21
8309         },
8310         {
8311             (BYTE*)vertices22,
8312             indices22,
8313             attributes22,
8314             num_vertices22,
8315             num_faces22,
8316             options,
8317             declaration_normal_ushort4n,
8318             vertex_size_normal_short4, /* SHORT4 same size as USHORT4N */
8319             flags22,
8320             &epsilons22,
8321             adjacency22,
8322             (BYTE*)exp_vertices22,
8323             exp_indices22,
8324             exp_face_remap22,
8325             exp_vertex_remap22,
8326             exp_new_num_vertices22
8327         },
8328         {
8329             (BYTE*)vertices23,
8330             indices23,
8331             attributes23,
8332             num_vertices23,
8333             num_faces23,
8334             options,
8335             declaration_texcoord_float16_2,
8336             vertex_size_texcoord_float16_2,
8337             flags23,
8338             &epsilons23,
8339             adjacency23,
8340             (BYTE*)exp_vertices23,
8341             exp_indices23,
8342             exp_face_remap23,
8343             exp_vertex_remap23,
8344             exp_new_num_vertices23
8345         },
8346         {
8347             (BYTE*)vertices24,
8348             indices24,
8349             attributes24,
8350             num_vertices24,
8351             num_faces24,
8352             options,
8353             declaration_texcoord_float16_4,
8354             vertex_size_texcoord_float16_4,
8355             flags24,
8356             &epsilons24,
8357             adjacency24,
8358             (BYTE*)exp_vertices24,
8359             exp_indices24,
8360             exp_face_remap24,
8361             exp_vertex_remap24,
8362             exp_new_num_vertices24
8363         },
8364         {
8365             (BYTE*)vertices25,
8366             indices25,
8367             attributes25,
8368             num_vertices25,
8369             num_faces25,
8370             options,
8371             declaration_texcoord10,
8372             vertex_size_texcoord,
8373             flags25,
8374             &epsilons25,
8375             adjacency25,
8376             (BYTE*)exp_vertices25,
8377             exp_indices25,
8378             exp_face_remap25,
8379             exp_vertex_remap25,
8380             exp_new_num_vertices25
8381         },
8382         {
8383             (BYTE*)vertices26,
8384             indices26,
8385             attributes26,
8386             num_vertices26,
8387             num_faces26,
8388             options,
8389             declaration_color2,
8390             vertex_size_color,
8391             flags26,
8392             &epsilons26,
8393             adjacency26,
8394             (BYTE*)exp_vertices26,
8395             exp_indices26,
8396             exp_face_remap26,
8397             exp_vertex_remap26,
8398             exp_new_num_vertices26
8399         },
8400         {
8401             (BYTE*)vertices27,
8402             indices27,
8403             attributes27,
8404             num_vertices27,
8405             num_faces27,
8406             options,
8407             declaration_color1,
8408             vertex_size_color,
8409             flags27,
8410             &epsilons27,
8411             adjacency27,
8412             (BYTE*)exp_vertices27,
8413             exp_indices27,
8414             exp_face_remap27,
8415             exp_vertex_remap27,
8416             exp_new_num_vertices27
8417         },
8418         {
8419             (BYTE*)vertices28,
8420             indices28,
8421             attributes28,
8422             num_vertices28,
8423             num_faces28,
8424             options,
8425             declaration_normal_udec3,
8426             vertex_size_normal_udec3,
8427             flags28,
8428             &epsilons28,
8429             adjacency28,
8430             (BYTE*)exp_vertices28,
8431             exp_indices28,
8432             exp_face_remap28,
8433             exp_vertex_remap28,
8434             exp_new_num_vertices28
8435         },
8436         {
8437             (BYTE*)vertices29,
8438             indices29,
8439             attributes29,
8440             num_vertices29,
8441             num_faces29,
8442             options,
8443             declaration_normal_dec3n,
8444             vertex_size_normal_dec3n,
8445             flags29,
8446             &epsilons29,
8447             adjacency29,
8448             (BYTE*)exp_vertices29,
8449             exp_indices29,
8450             exp_face_remap29,
8451             exp_vertex_remap29,
8452             exp_new_num_vertices29
8453         }
8454     };
8455 #ifdef __REACTOS__
8456 #undef up
8457 #endif
8458 
8459     test_context = new_test_context();
8460     if (!test_context)
8461     {
8462         skip("Couldn't create test context\n");
8463         goto cleanup;
8464     }
8465 
8466     for (i = 0; i < ARRAY_SIZE(tc); i++)
8467     {
8468         DWORD j;
8469         DWORD *vertex_remap_ptr;
8470         DWORD new_num_vertices;
8471 
8472         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
8473                             tc[i].declaration, test_context->device, &mesh,
8474                             tc[i].vertices, tc[i].vertex_size,
8475                             tc[i].indices, tc[i].attributes);
8476         if (FAILED(hr))
8477         {
8478             skip("Couldn't initialize test mesh %d.\n", i);
8479             goto cleanup;
8480         }
8481 
8482         /* Allocate out parameters */
8483         adjacency_out = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency_out));
8484         if (!adjacency_out)
8485         {
8486             skip("Couldn't allocate adjacency_out array.\n");
8487             goto cleanup;
8488         }
8489         face_remap = HeapAlloc(GetProcessHeap(), 0, tc[i].num_faces * sizeof(*face_remap));
8490         if (!face_remap)
8491         {
8492             skip("Couldn't allocate face_remap array.\n");
8493             goto cleanup;
8494         }
8495 
8496         hr = D3DXWeldVertices(mesh, tc[i].flags, tc[i].epsilons, tc[i].adjacency,
8497                               adjacency_out, face_remap, &vertex_remap);
8498         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
8499         /* Check number of vertices*/
8500         new_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
8501         ok(new_num_vertices == tc[i].exp_new_num_vertices,
8502            "Mesh %d: new_num_vertices == %d, expected %d.\n",
8503            i, new_num_vertices, tc[i].exp_new_num_vertices);
8504         /* Check index buffer */
8505         if (tc[i].options & D3DXMESH_32BIT)
8506         {
8507             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices);
8508             if (FAILED(hr))
8509             {
8510                 skip("Couldn't lock index buffer.\n");
8511                 goto cleanup;
8512             }
8513             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8514             {
8515                 ok(indices[j] == tc[i].exp_indices[j],
8516                    "Mesh %d: indices[%d] == %d, expected %d\n",
8517                    i, j, indices[j], tc[i].exp_indices[j]);
8518             }
8519         }
8520         else
8521         {
8522             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices_16bit);
8523             if (FAILED(hr))
8524             {
8525                 skip("Couldn't lock index buffer.\n");
8526                 goto cleanup;
8527             }
8528             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8529             {
8530                 ok(indices_16bit[j] == tc[i].exp_indices[j],
8531                    "Mesh %d: indices_16bit[%d] == %d, expected %d\n",
8532                    i, j, indices_16bit[j], tc[i].exp_indices[j]);
8533             }
8534         }
8535         mesh->lpVtbl->UnlockIndexBuffer(mesh);
8536         indices = NULL;
8537         indices_16bit = NULL;
8538         /* Check adjacency_out */
8539         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8540         {
8541             ok(adjacency_out[j] == tc[i].adjacency[j],
8542                "Mesh %d: adjacency_out[%d] == %d, expected %d\n",
8543                i, j, adjacency_out[j], tc[i].adjacency[j]);
8544         }
8545         /* Check face_remap */
8546         for (j = 0; j < tc[i].num_faces; j++)
8547         {
8548             ok(face_remap[j] == tc[i].exp_face_remap[j],
8549                "Mesh %d: face_remap[%d] == %d, expected %d\n",
8550                i, j, face_remap[j], tc[i].exp_face_remap[j]);
8551         }
8552         /* Check vertex_remap */
8553         vertex_remap_ptr = vertex_remap->lpVtbl->GetBufferPointer(vertex_remap);
8554         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8555         {
8556             ok(vertex_remap_ptr[j] == tc[i].exp_vertex_remap[j],
8557                "Mesh %d: vertex_remap_ptr[%d] == %d, expected %d\n",
8558                i, j, vertex_remap_ptr[j], tc[i].exp_vertex_remap[j]);
8559         }
8560         /* Check vertex buffer */
8561         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void*)&vertices);
8562         if (FAILED(hr))
8563         {
8564             skip("Couldn't lock vertex buffer.\n");
8565             goto cleanup;
8566         }
8567         /* Check contents of re-ordered vertex buffer */
8568         for (j = 0; j < tc[i].exp_new_num_vertices; j++)
8569         {
8570             int index = tc[i].vertex_size*j;
8571             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].declaration);
8572         }
8573         mesh->lpVtbl->UnlockVertexBuffer(mesh);
8574         vertices = NULL;
8575 
8576         /* Free mesh and output data */
8577         HeapFree(GetProcessHeap(), 0, adjacency_out);
8578         adjacency_out = NULL;
8579         HeapFree(GetProcessHeap(), 0, face_remap);
8580         face_remap = NULL;
8581         vertex_remap->lpVtbl->Release(vertex_remap);
8582         vertex_remap = NULL;
8583         mesh->lpVtbl->Release(mesh);
8584         mesh = NULL;
8585     }
8586 
8587 cleanup:
8588     HeapFree(GetProcessHeap(), 0, adjacency_out);
8589     HeapFree(GetProcessHeap(), 0, face_remap);
8590     if (indices) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8591     if (indices_16bit) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8592     if (mesh) mesh->lpVtbl->Release(mesh);
8593     if (vertex_remap) vertex_remap->lpVtbl->Release(vertex_remap);
8594     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
8595     free_test_context(test_context);
8596 }
8597 
8598 static void test_clone_mesh(void)
8599 {
8600     HRESULT hr;
8601     struct test_context *test_context = NULL;
8602     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
8603     D3DVERTEXELEMENT9 declaration_pn[] =
8604     {
8605         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8606         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8607         D3DDECL_END()
8608     };
8609     D3DVERTEXELEMENT9 declaration_pntc[] =
8610     {
8611         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8612         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8613         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8614         D3DDECL_END()
8615     };
8616     D3DVERTEXELEMENT9 declaration_ptcn[] =
8617     {
8618         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8619         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8620         {0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8621         D3DDECL_END()
8622     };
8623     D3DVERTEXELEMENT9 declaration_ptc[] =
8624     {
8625         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8626         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8627         D3DDECL_END()
8628     };
8629     D3DVERTEXELEMENT9 declaration_ptc_float16_2[] =
8630     {
8631         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8632         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8633         D3DDECL_END()
8634     };
8635     D3DVERTEXELEMENT9 declaration_ptc_float16_4[] =
8636     {
8637         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8638         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8639         D3DDECL_END()
8640     };
8641     D3DVERTEXELEMENT9 declaration_ptc_float1[] =
8642     {
8643         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8644         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8645         D3DDECL_END()
8646     };
8647     D3DVERTEXELEMENT9 declaration_ptc_float3[] =
8648     {
8649         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8650         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8651         D3DDECL_END()
8652     };
8653     D3DVERTEXELEMENT9 declaration_ptc_float4[] =
8654     {
8655         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8656         {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8657         D3DDECL_END()
8658     };
8659     D3DVERTEXELEMENT9 declaration_ptc_d3dcolor[] =
8660     {
8661         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8662         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8663         D3DDECL_END()
8664     };
8665     D3DVERTEXELEMENT9 declaration_ptc_ubyte4[] =
8666     {
8667         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8668         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8669         D3DDECL_END()
8670     };
8671     D3DVERTEXELEMENT9 declaration_ptc_ubyte4n[] =
8672     {
8673         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8674         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8675         D3DDECL_END()
8676     };
8677     D3DVERTEXELEMENT9 declaration_ptc_short2[] =
8678     {
8679         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8680         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8681         D3DDECL_END()
8682     };
8683     D3DVERTEXELEMENT9 declaration_ptc_short4[] =
8684     {
8685         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8686         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8687         D3DDECL_END()
8688     };
8689     D3DVERTEXELEMENT9 declaration_ptc_short2n[] =
8690     {
8691         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8692         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8693         D3DDECL_END()
8694     };
8695     D3DVERTEXELEMENT9 declaration_ptc_short4n[] =
8696     {
8697         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8698         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8699         D3DDECL_END()
8700     };
8701     D3DVERTEXELEMENT9 declaration_ptc_ushort2n[] =
8702     {
8703         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8704         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8705         D3DDECL_END()
8706     };
8707     D3DVERTEXELEMENT9 declaration_ptc_ushort4n[] =
8708     {
8709         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8710         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8711         D3DDECL_END()
8712     };
8713     D3DVERTEXELEMENT9 declaration_ptc_float16_2_partialu[] =
8714     {
8715         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8716         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_PARTIALU, D3DDECLUSAGE_TEXCOORD, 0},
8717         D3DDECL_END()
8718     };
8719     D3DVERTEXELEMENT9 declaration_pntc1[] =
8720     {
8721         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8722         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8723         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
8724         D3DDECL_END()
8725     };
8726     const unsigned int VERTS_PER_FACE = 3;
8727     BYTE *vertices = NULL;
8728     INT i;
8729     struct vertex_pn
8730     {
8731         D3DXVECTOR3 position;
8732         D3DXVECTOR3 normal;
8733     };
8734     struct vertex_pntc
8735     {
8736         D3DXVECTOR3 position;
8737         D3DXVECTOR3 normal;
8738         D3DXVECTOR2 texcoords;
8739     };
8740     struct vertex_ptcn
8741     {
8742         D3DXVECTOR3 position;
8743         D3DXVECTOR2 texcoords;
8744         D3DXVECTOR3 normal;
8745     };
8746     struct vertex_ptc
8747     {
8748         D3DXVECTOR3 position;
8749         D3DXVECTOR2 texcoords;
8750     };
8751     struct vertex_ptc_float16_2
8752     {
8753         D3DXVECTOR3 position;
8754         WORD texcoords[2]; /* float16_2 */
8755     };
8756     struct vertex_ptc_float16_4
8757     {
8758         D3DXVECTOR3 position;
8759         WORD texcoords[4]; /* float16_4 */
8760     };
8761     struct vertex_ptc_float1
8762     {
8763         D3DXVECTOR3 position;
8764         FLOAT texcoords;
8765     };
8766     struct vertex_ptc_float3
8767     {
8768         D3DXVECTOR3 position;
8769         FLOAT texcoords[3];
8770     };
8771     struct vertex_ptc_float4
8772     {
8773         D3DXVECTOR3 position;
8774         FLOAT texcoords[4];
8775     };
8776     struct vertex_ptc_d3dcolor
8777     {
8778         D3DXVECTOR3 position;
8779         BYTE texcoords[4];
8780     };
8781     struct vertex_ptc_ubyte4
8782     {
8783         D3DXVECTOR3 position;
8784         BYTE texcoords[4];
8785     };
8786     struct vertex_ptc_ubyte4n
8787     {
8788         D3DXVECTOR3 position;
8789         BYTE texcoords[4];
8790     };
8791     struct vertex_ptc_short2
8792     {
8793         D3DXVECTOR3 position;
8794         SHORT texcoords[2];
8795     };
8796     struct vertex_ptc_short4
8797     {
8798         D3DXVECTOR3 position;
8799         SHORT texcoords[4];
8800     };
8801     struct vertex_ptc_ushort2n
8802     {
8803         D3DXVECTOR3 position;
8804         USHORT texcoords[2];
8805     };
8806     struct vertex_ptc_ushort4n
8807     {
8808         D3DXVECTOR3 position;
8809         USHORT texcoords[4];
8810     };
8811     struct vertex_ptc_udec3
8812     {
8813         D3DXVECTOR3 position;
8814         DWORD texcoords;
8815     };
8816     struct vertex_ptc_dec3n
8817     {
8818         D3DXVECTOR3 position;
8819         DWORD texcoords;
8820     };
8821 #ifndef __REACTOS__
8822     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
8823     D3DXVECTOR2 zero_vec2 = {0.0f, 0.0f};
8824 #else
8825 #define up {0.0f, 0.0f, 1.0f}
8826 #define zero_vec2 {0.0f, 0.0f}
8827 #endif
8828     /* Test 0. Check that a mesh can be cloned if the new declaration is the
8829      * same as the one used to create the mesh.
8830      *
8831      * 0--1 3
8832      * | / /|
8833      * |/ / |
8834      * 2 5--4
8835      */
8836     const struct vertex_pn vertices0[] =
8837     {
8838         {{ 0.0f,  3.0f,  0.f}, up},
8839         {{ 2.0f,  3.0f,  0.f}, up},
8840         {{ 0.0f,  0.0f,  0.f}, up},
8841 
8842         {{ 3.0f,  3.0f,  0.f}, up},
8843         {{ 3.0f,  0.0f,  0.f}, up},
8844         {{ 1.0f,  0.0f,  0.f}, up},
8845     };
8846     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
8847     const UINT num_faces0 = ARRAY_SIZE(vertices0) / VERTS_PER_FACE;
8848     const UINT vertex_size0 = sizeof(*vertices0);
8849     /* Test 1. Check that 16-bit indices are handled. */
8850     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
8851     /* Test 2. Check that the size of each vertex is increased and the data
8852      * moved if the new declaration adds an element after the original elements.
8853      */
8854     const struct vertex_pntc exp_vertices2[] =
8855     {
8856         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8857         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8858         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8859 
8860         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8861         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8862         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8863     };
8864     const UINT exp_vertex_size2 = sizeof(*exp_vertices2);
8865     /* Test 3. Check that the size of each vertex is increased and the data
8866      * moved if the new declaration adds an element between the original
8867      * elements.
8868      */
8869     const struct vertex_ptcn exp_vertices3[] =
8870     {
8871         {{ 0.0f,  3.0f,  0.f}, zero_vec2, up},
8872         {{ 2.0f,  3.0f,  0.f}, zero_vec2, up},
8873         {{ 0.0f,  0.0f,  0.f}, zero_vec2, up},
8874 
8875         {{ 3.0f,  3.0f,  0.f}, zero_vec2, up},
8876         {{ 3.0f,  0.0f,  0.f}, zero_vec2, up},
8877         {{ 1.0f,  0.0f,  0.f}, zero_vec2, up},
8878     };
8879     const UINT exp_vertex_size3 = sizeof(*exp_vertices3);
8880     /* Test 4. Test that data types can be converted, e.g. FLOAT2 to FLOAT16_2. */
8881     const struct vertex_ptc vertices4[] =
8882     {
8883         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8884         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8885         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8886 
8887         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8888         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8889         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8890     };
8891     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
8892     const UINT num_faces4 = ARRAY_SIZE(vertices4) / VERTS_PER_FACE;
8893     const UINT vertex_size4 = sizeof(*vertices4);
8894     const struct vertex_ptc_float16_2 exp_vertices4[] =
8895     {
8896         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8897         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
8898         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
8899 
8900         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
8901         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8902         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
8903     };
8904     const UINT exp_vertex_size4 = sizeof(*exp_vertices4);
8905     /* Test 5. Convert FLOAT2 to FLOAT16_4. */
8906     const struct vertex_ptc vertices5[] =
8907     {
8908         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8909         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8910         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8911 
8912         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8913         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8914         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8915     };
8916     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
8917     const UINT num_faces5 = ARRAY_SIZE(vertices5) / VERTS_PER_FACE;
8918     const UINT vertex_size5 = sizeof(*vertices5);
8919     const struct vertex_ptc_float16_4 exp_vertices5[] =
8920     {
8921         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8922         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0, 0x3c00}}, /* {0.5f, 0.7f, 0.0f, 1.0f} */
8923         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0, 0x3c00}}, /* {-0.2f, -0.3f, 0.0f, 1.0f} */
8924 
8925         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0, 0x3c00}}, /* {0.2f, 0.3f, 0.0f, 1.0f} */
8926         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8927         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0, 0x3c00}}, /* {0.1f, 0.2f, 0.0f, 1.0f} */
8928     };
8929     const UINT exp_vertex_size5 = sizeof(*exp_vertices5);
8930     /* Test 6. Convert FLOAT2 to FLOAT1. */
8931     const struct vertex_ptc vertices6[] =
8932     {
8933         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8934         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8935         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8936 
8937         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8938         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8939         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8940     };
8941     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
8942     const UINT num_faces6 = ARRAY_SIZE(vertices6) / VERTS_PER_FACE;
8943     const UINT vertex_size6 = sizeof(*vertices6);
8944     const struct vertex_ptc_float1 exp_vertices6[] =
8945     {
8946         {{ 0.0f,  3.0f,  0.f},  1.0f},
8947         {{ 2.0f,  3.0f,  0.f},  0.5f},
8948         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8949 
8950         {{ 3.0f,  3.0f,  0.f},  0.2f},
8951         {{ 3.0f,  0.0f,  0.f},  1.0f},
8952         {{ 1.0f,  0.0f,  0.f},  0.1f},
8953     };
8954     const UINT exp_vertex_size6 = sizeof(*exp_vertices6);
8955     /* Test 7. Convert FLOAT2 to FLOAT3. */
8956     const struct vertex_ptc vertices7[] =
8957     {
8958         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8959         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8960         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8961 
8962         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8963         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8964         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8965     };
8966     const UINT num_vertices7 = ARRAY_SIZE(vertices7);
8967     const UINT num_faces7 = ARRAY_SIZE(vertices7) / VERTS_PER_FACE;
8968     const UINT vertex_size7 = sizeof(*vertices7);
8969     const struct vertex_ptc_float3 exp_vertices7[] =
8970     {
8971         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8972         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f}},
8973         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f}},
8974 
8975         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f}},
8976         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8977         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f}},
8978     };
8979     const UINT exp_vertex_size7 = sizeof(*exp_vertices7);
8980     /* Test 8. Convert FLOAT2 to FLOAT4. */
8981     const struct vertex_ptc vertices8[] =
8982     {
8983         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8984         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8985         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8986 
8987         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8988         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8989         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8990     };
8991     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
8992     const UINT num_faces8 = ARRAY_SIZE(vertices8) / VERTS_PER_FACE;
8993     const UINT vertex_size8 = sizeof(*vertices8);
8994     const struct vertex_ptc_float4 exp_vertices8[] =
8995     {
8996         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
8997         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f, 1.0f}},
8998         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f, 1.0f}},
8999 
9000         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f, 1.0f}},
9001         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
9002         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f, 1.0f}},
9003     };
9004     const UINT exp_vertex_size8 = sizeof(*exp_vertices8);
9005     /* Test 9. Convert FLOAT2 to D3DCOLOR. */
9006     const struct vertex_ptc vertices9[] =
9007     {
9008         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9009         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9010         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.6f}},
9011 
9012         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9013         {{ 3.0f,  0.0f,  0.f}, { 2.0f, 256.0f}},
9014         {{ 1.0f,  0.0f,  0.f}, { 0.11f,  0.2f}},
9015     };
9016     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
9017     const UINT num_faces9 = ARRAY_SIZE(vertices9) / VERTS_PER_FACE;
9018     const UINT vertex_size9 = sizeof(*vertices9);
9019     const struct vertex_ptc_d3dcolor exp_vertices9[] =
9020     {
9021         {{ 0.0f,  3.0f,  0.f}, {0, 255, 255, 255}},
9022         {{ 2.0f,  3.0f,  0.f}, {0, 179, 128, 255}},
9023         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9024 
9025         {{ 3.0f,  3.0f,  0.f}, {0, 77, 51, 255}},
9026         {{ 3.0f,  0.0f,  0.f}, {0, 255, 255, 255}},
9027         {{ 1.0f,  0.0f,  0.f}, {0, 51, 28, 255}},
9028     };
9029     const UINT exp_vertex_size9 = sizeof(*exp_vertices9);
9030     /* Test 10. Convert FLOAT2 to UBYTE4. */
9031     const struct vertex_ptc vertices10[] =
9032     {
9033         {{ 0.0f,  3.0f,  0.f}, { 0.0f,  1.0f}},
9034         {{ 2.0f,  3.0f,  0.f}, { 2.0f,  3.0f}},
9035         {{ 0.0f,  0.0f,  0.f}, { 254.0f,  255.0f}},
9036 
9037         {{ 3.0f,  3.0f,  0.f}, { 256.0f, 257.0f}},
9038         {{ 3.0f,  0.0f,  0.f}, { 1.4f, 1.5f}},
9039         {{ 1.0f,  0.0f,  0.f}, {-4.0f, -5.0f}},
9040     };
9041     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
9042     const UINT num_faces10 = ARRAY_SIZE(vertices10) / VERTS_PER_FACE;
9043     const UINT vertex_size10 = sizeof(*vertices10);
9044     const struct vertex_ptc_ubyte4 exp_vertices10[] =
9045     {
9046         {{ 0.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9047         {{ 2.0f,  3.0f,  0.f}, {2, 3, 0, 1}},
9048         {{ 0.0f,  0.0f,  0.f}, {254, 255, 0, 1}},
9049 
9050         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9051         {{ 3.0f,  0.0f,  0.f}, {1, 2, 0, 1}},
9052         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9053     };
9054     const UINT exp_vertex_size10 = sizeof(*exp_vertices10);
9055     /* Test 11. Convert FLOAT2 to SHORT2. */
9056     const struct vertex_ptc vertices11[] =
9057     {
9058         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
9059         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
9060         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
9061 
9062         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9063         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
9064         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
9065 
9066         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
9067         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
9068         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
9069     };
9070     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
9071     const UINT num_faces11 = ARRAY_SIZE(vertices11) / VERTS_PER_FACE;
9072     const UINT vertex_size11 = sizeof(*vertices11);
9073     const struct vertex_ptc_short2 exp_vertices11[] =
9074     {
9075         {{ 0.0f,  3.0f,  0.f}, {1, 0}},
9076         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9077         {{ 0.0f,  0.0f,  0.f}, {0, -4}},
9078 
9079         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1}},
9080         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN}},
9081         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
9082 
9083         {{ 4.0f,  3.0f,  0.f}, {-2, 1}},
9084         {{ 6.0f,  0.0f,  0.f}, {32765, -32767}},
9085         {{ 4.0f,  0.0f,  0.f}, {-4, 1}},
9086     };
9087     const UINT exp_vertex_size11 = sizeof(*exp_vertices11);
9088     /* Test 12. Convert FLOAT2 to SHORT4. */
9089     const struct vertex_ptc vertices12[] =
9090     {
9091         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
9092         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
9093         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
9094 
9095         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9096         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
9097         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
9098 
9099         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
9100         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
9101         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
9102     };
9103     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
9104     const UINT num_faces12 = ARRAY_SIZE(vertices12) / VERTS_PER_FACE;
9105     const UINT vertex_size12 = sizeof(*vertices12);
9106     const struct vertex_ptc_short4 exp_vertices12[] =
9107     {
9108         {{ 0.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
9109         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9110         {{ 0.0f,  0.0f,  0.f}, {0, -4, 0, 1}},
9111 
9112         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1, 0, 1}},
9113         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN, 0, 1}},
9114         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, 0, 1}},
9115 
9116         {{ 4.0f,  3.0f,  0.f}, {-2, 1, 0, 1}},
9117         {{ 6.0f,  0.0f,  0.f}, {32765, -32767, 0, 1}},
9118         {{ 4.0f,  0.0f,  0.f}, {-4, 1, 0, 1}},
9119     };
9120     const UINT exp_vertex_size12 = sizeof(*exp_vertices12);
9121     /* Test 13. Convert FLOAT2 to UBYTE4N. */
9122     const struct vertex_ptc vertices13[] =
9123     {
9124         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  2.0f}},
9125         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9126         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.5f}},
9127 
9128         {{ 3.0f,  3.0f,  0.f}, {-0.6f,  -1.0f}},
9129         {{ 3.0f,  0.0f,  0.f}, {UCHAR_MAX,  UCHAR_MAX + 1}},
9130         {{ 1.0f,  0.0f,  0.f}, {2 * UCHAR_MAX, -UCHAR_MAX}},
9131     };
9132     const UINT num_vertices13 = ARRAY_SIZE(vertices13);
9133     const UINT num_faces13 = ARRAY_SIZE(vertices13) / VERTS_PER_FACE;
9134     const UINT vertex_size13 = sizeof(*vertices13);
9135     const struct vertex_ptc_ubyte4n exp_vertices13[] =
9136     {
9137         {{ 0.0f,  3.0f,  0.f}, {255, 255, 0, 255}},
9138         {{ 2.0f,  3.0f,  0.f}, {128, 179, 0, 255}},
9139         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9140 
9141         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, 255}},
9142         {{ 3.0f,  0.0f,  0.f}, {255, 255, 0, 255}},
9143         {{ 1.0f,  0.0f,  0.f}, {255, 0, 0, 255}},
9144     };
9145     const UINT exp_vertex_size13 = sizeof(*exp_vertices13);
9146     /* Test 14. Convert FLOAT2 to SHORT2N. */
9147     const struct vertex_ptc vertices14[] =
9148     {
9149         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9150         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9151         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9152 
9153         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9154         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
9155         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9156     };
9157     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
9158     const UINT num_faces14 = ARRAY_SIZE(vertices14) / VERTS_PER_FACE;
9159     const UINT vertex_size14 = sizeof(*vertices14);
9160     const struct vertex_ptc_short2 exp_vertices14[] =
9161     {
9162         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX}},
9163         {{ 2.0f,  3.0f,  0.f}, {13107, 16384}},
9164         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2}},
9165 
9166         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383}},
9167         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3}},
9168         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2}},
9169     };
9170     const UINT exp_vertex_size14 = sizeof(*exp_vertices14);
9171     /* Test 15. Convert FLOAT2 to SHORT4N. */
9172     const struct vertex_ptc vertices15[] =
9173     {
9174         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9175         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9176         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9177 
9178         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9179         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
9180         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9181     };
9182     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
9183     const UINT num_faces15 = ARRAY_SIZE(vertices15) / VERTS_PER_FACE;
9184     const UINT vertex_size15 = sizeof(*vertices15);
9185     const struct vertex_ptc_short4 exp_vertices15[] =
9186     {
9187         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX, 0, SHRT_MAX}},
9188         {{ 2.0f,  3.0f,  0.f}, {13107, 16384, 0, SHRT_MAX}},
9189         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2, 0, SHRT_MAX}},
9190 
9191         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383, 0, SHRT_MAX}},
9192         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3, 0, SHRT_MAX}},
9193         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2, 0, SHRT_MAX}},
9194     };
9195     const UINT exp_vertex_size15 = sizeof(*exp_vertices15);
9196     /* Test 16. Convert FLOAT2 to USHORT2N. */
9197     const struct vertex_ptc vertices16[] =
9198     {
9199         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9200         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9201         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9202 
9203         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9204         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
9205         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
9206     };
9207     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
9208     const UINT num_faces16 = ARRAY_SIZE(vertices16) / VERTS_PER_FACE;
9209     const UINT vertex_size16 = sizeof(*vertices16);
9210     const struct vertex_ptc_ushort2n exp_vertices16[] =
9211     {
9212         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX}},
9213         {{ 2.0f,  3.0f,  0.f}, {26214, 32768}},
9214         {{ 0.0f,  0.0f,  0.f}, {39321, 0}},
9215 
9216         {{ 3.0f,  3.0f,  0.f}, {0, 0}},
9217         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1}},
9218         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0}},
9219     };
9220     const UINT exp_vertex_size16 = sizeof(*exp_vertices16);
9221     /* Test 17. Convert FLOAT2 to USHORT4N. */
9222     const struct vertex_ptc vertices17[] =
9223     {
9224         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9225         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9226         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9227 
9228         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9229         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
9230         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
9231     };
9232     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
9233     const UINT num_faces17 = ARRAY_SIZE(vertices17) / VERTS_PER_FACE;
9234     const UINT vertex_size17 = sizeof(*vertices17);
9235     const struct vertex_ptc_ushort4n exp_vertices17[] =
9236     {
9237         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX, 0, USHRT_MAX}},
9238         {{ 2.0f,  3.0f,  0.f}, {26214, 32768, 0, USHRT_MAX}},
9239         {{ 0.0f,  0.0f,  0.f}, {39321, 0, 0, USHRT_MAX}},
9240 
9241         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, USHRT_MAX}},
9242         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1, 0, USHRT_MAX}},
9243         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0, 0, USHRT_MAX}},
9244     };
9245     const UINT exp_vertex_size17 = sizeof(*exp_vertices17);
9246     /* Test 18. Test that the method field is compared by converting a FLOAT2 to
9247      * FLOAT16_2. where the method field has been change from
9248      * D3DDECLMETHOD_DEFAULT to D3DDECLMETHOD_PARTIALU. */
9249     const struct vertex_ptc vertices18[] =
9250     {
9251         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9252         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9253         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
9254 
9255         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9256         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
9257         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
9258     };
9259     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
9260     const UINT num_faces18 = ARRAY_SIZE(vertices18) / VERTS_PER_FACE;
9261     const UINT vertex_size18 = sizeof(*vertices18);
9262     const struct vertex_ptc_float16_2 exp_vertices18[] =
9263     {
9264         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9265         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9266         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9267 
9268         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9269         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9270         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9271     };
9272     const UINT exp_vertex_size18 = sizeof(*exp_vertices18);
9273     /* Test 19. Test that data is lost if usage index changes, e.g. TEXCOORD0
9274      * TEXCOORD1. */
9275     const struct vertex_pntc vertices19[] =
9276     {
9277         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
9278         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
9279         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
9280 
9281         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
9282         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
9283         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
9284     };
9285     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
9286     const UINT num_faces19 = ARRAY_SIZE(vertices19) / VERTS_PER_FACE;
9287     const UINT vertex_size19 = sizeof(*vertices19);
9288     const struct vertex_pntc exp_vertices19[] =
9289     {
9290         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
9291         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
9292         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
9293 
9294         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
9295         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
9296         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
9297     };
9298     const UINT exp_vertex_size19 = sizeof(*exp_vertices19);
9299     /* Test 20. Another test that data is lost if usage index changes, e.g.
9300      * TEXCOORD1 to TEXCOORD0. */
9301     const struct vertex_pntc vertices20[] =
9302     {
9303         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
9304         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
9305         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
9306 
9307         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
9308         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
9309         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
9310     };
9311     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
9312     const UINT num_faces20 = ARRAY_SIZE(vertices20) / VERTS_PER_FACE;
9313     const UINT vertex_size20 = sizeof(*vertices20);
9314     const struct vertex_pntc exp_vertices20[] =
9315     {
9316         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
9317         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
9318         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
9319 
9320         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
9321         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
9322         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
9323     };
9324     const UINT exp_vertex_size20 = sizeof(*exp_vertices20);
9325     /* Test 21. Convert FLOAT1 to FLOAT2. */
9326     const struct vertex_ptc_float1 vertices21[] =
9327     {
9328         {{ 0.0f,  3.0f,  0.f},  1.0f},
9329         {{ 2.0f,  3.0f,  0.f},  0.5f},
9330         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9331 
9332         {{ 3.0f,  3.0f,  0.f},  0.2f},
9333         {{ 3.0f,  0.0f,  0.f},  1.0f},
9334         {{ 1.0f,  0.0f,  0.f},  0.1f},
9335     };
9336     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
9337     const UINT num_faces21 = ARRAY_SIZE(vertices21) / VERTS_PER_FACE;
9338     const UINT vertex_size21 = sizeof(*vertices21);
9339     const struct vertex_ptc exp_vertices21[] =
9340     {
9341         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f}},
9342         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f}},
9343         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f}},
9344 
9345         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f}},
9346         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f}},
9347         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f}},
9348     };
9349     const UINT exp_vertex_size21 = sizeof(*exp_vertices21);
9350     /* Test 22. Convert FLOAT1 to FLOAT3. */
9351     const struct vertex_ptc_float1 vertices22[] =
9352     {
9353         {{ 0.0f,  3.0f,  0.f},  1.0f},
9354         {{ 2.0f,  3.0f,  0.f},  0.5f},
9355         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9356 
9357         {{ 3.0f,  3.0f,  0.f},  0.2f},
9358         {{ 3.0f,  0.0f,  0.f},  1.0f},
9359         {{ 1.0f,  0.0f,  0.f},  0.1f},
9360     };
9361     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
9362     const UINT num_faces22 = ARRAY_SIZE(vertices22) / VERTS_PER_FACE;
9363     const UINT vertex_size22 = sizeof(*vertices22);
9364     const struct vertex_ptc_float3 exp_vertices22[] =
9365     {
9366         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
9367         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f}},
9368         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f}},
9369 
9370         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f}},
9371         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
9372         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f}},
9373     };
9374     const UINT exp_vertex_size22 = sizeof(*exp_vertices22);
9375     /* Test 23. Convert FLOAT1 to FLOAT4. */
9376     const struct vertex_ptc_float1 vertices23[] =
9377     {
9378         {{ 0.0f,  3.0f,  0.f},  1.0f},
9379         {{ 2.0f,  3.0f,  0.f},  0.5f},
9380         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9381 
9382         {{ 3.0f,  3.0f,  0.f},  0.2f},
9383         {{ 3.0f,  0.0f,  0.f},  1.0f},
9384         {{ 1.0f,  0.0f,  0.f},  0.1f},
9385     };
9386     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
9387     const UINT num_faces23 = ARRAY_SIZE(vertices23) / VERTS_PER_FACE;
9388     const UINT vertex_size23 = sizeof(*vertices23);
9389     const struct vertex_ptc_float4 exp_vertices23[] =
9390     {
9391         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
9392         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f, 1.0f}},
9393         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f, 1.0f}},
9394 
9395         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f, 1.0f}},
9396         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
9397         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f, 1.0f}},
9398     };
9399     const UINT exp_vertex_size23 = sizeof(*exp_vertices23);
9400     /* Test 24. Convert FLOAT1 to D3DCOLOR. */
9401     const struct vertex_ptc_float1 vertices24[] =
9402     {
9403         {{ 0.0f,  3.0f,  0.f},  1.0f},
9404         {{ 2.0f,  3.0f,  0.f},  0.5f},
9405         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9406 
9407         {{ 3.0f,  3.0f,  0.f},  0.2f},
9408         {{ 3.0f,  0.0f,  0.f},  1.0f},
9409         {{ 1.0f,  0.0f,  0.f},  0.11f},
9410     };
9411     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
9412     const UINT num_faces24 = ARRAY_SIZE(vertices24) / VERTS_PER_FACE;
9413     const UINT vertex_size24 = sizeof(*vertices24);
9414     const struct vertex_ptc_d3dcolor exp_vertices24[] =
9415     {
9416         {{ 0.0f,  3.0f,  0.f}, {0, 0, 255, 255}},
9417         {{ 2.0f,  3.0f,  0.f}, {0, 0, 128, 255}},
9418         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9419 
9420         {{ 3.0f,  3.0f,  0.f}, {0, 0, 51, 255}},
9421         {{ 3.0f,  0.0f,  0.f}, {0, 0, 255, 255}},
9422         {{ 1.0f,  0.0f,  0.f}, {0, 0, 28, 255}},
9423     };
9424     const UINT exp_vertex_size24 = sizeof(*exp_vertices24);
9425     /* Test 25. Convert FLOAT1 to ubyte4. */
9426     const struct vertex_ptc_float1 vertices25[] =
9427     {
9428         {{ 0.0f,  3.0f,  0.f}, 0.0f},
9429         {{ 2.0f,  3.0f,  0.f}, 1.4f},
9430         {{ 0.0f,  0.0f,  0.f}, 1.5f},
9431 
9432         {{ 3.0f,  3.0f,  0.f}, 255.0f},
9433         {{ 3.0f,  0.0f,  0.f}, 256.0f},
9434         {{ 1.0f,  0.0f,  0.f}, -1.0f},
9435     };
9436     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
9437     const UINT num_faces25 = ARRAY_SIZE(vertices25) / VERTS_PER_FACE;
9438     const UINT vertex_size25 = sizeof(*vertices25);
9439     const struct vertex_ptc_ubyte4 exp_vertices25[] =
9440     {
9441         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 1}},
9442         {{ 2.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
9443         {{ 0.0f,  0.0f,  0.f}, {2, 0, 0, 1}},
9444 
9445         {{ 3.0f,  3.0f,  0.f}, {255, 0, 0, 1}},
9446         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9447         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9448     };
9449     const UINT exp_vertex_size25 = sizeof(*exp_vertices25);
9450     /* Test 26. Convert FLOAT4 to D3DCOLOR. */
9451     const struct vertex_ptc_float4 vertices26[] =
9452     {
9453         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.5f}},
9454         {{ 2.0f,  3.0f,  0.f}, {-0.4f, -0.5f, -1.0f, -2.0f}},
9455         {{ 0.0f,  0.0f,  0.f}, {254.0f, 255.0f, 256.0f, 257.0f}},
9456 
9457         {{ 3.0f,  3.0f,  0.f}, {0.1f, 0.2f, 0.3f, 0.4f}},
9458         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.6f, 0.7f, 0.8f}},
9459         {{ 1.0f,  0.0f,  0.f}, {0.9f, 0.99f, 0.995f, 0.999f}},
9460     };
9461     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
9462     const UINT num_faces26 = ARRAY_SIZE(vertices26) / VERTS_PER_FACE;
9463     const UINT vertex_size26 = sizeof(*vertices26);
9464     const struct vertex_ptc_d3dcolor exp_vertices26[] =
9465     {
9466         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9467         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9468         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9469 
9470         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9471         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9472         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9473     };
9474     const UINT exp_vertex_size26 = sizeof(*exp_vertices26);
9475     /* Test 27. Convert D3DCOLOR to FLOAT4. */
9476     const struct vertex_ptc_d3dcolor vertices27[] =
9477     {
9478         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9479         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9480         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9481 
9482         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9483         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9484         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9485     };
9486     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
9487     const UINT num_faces27 = ARRAY_SIZE(vertices27) / VERTS_PER_FACE;
9488     const UINT vertex_size27 = sizeof(*vertices27);
9489     const struct vertex_ptc_float4 exp_vertices27[] =
9490     {
9491         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.501961f}},
9492         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9493         {{ 0.0f,  0.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9494 
9495         {{ 3.0f,  3.0f,  0.f}, {0.101961f, 0.2f, 0.301961f, 0.4f}},
9496         {{ 3.0f,  0.0f,  0.f}, {0.501961f, 0.6f, 0.701961f, 0.8f}},
9497         {{ 1.0f,  0.0f,  0.f}, {0.901961f, 0.988235f, 0.996078f, 1.0f}},
9498     };
9499     const UINT exp_vertex_size27 = sizeof(*exp_vertices27);
9500     /* Test 28. Convert UBYTE4 to FLOAT4. */
9501     const struct vertex_ptc_ubyte4 vertices28[] =
9502     {
9503         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9504         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9505         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9506 
9507         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9508         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9509         {{ 1.0f,  0.0f,  0.f}, {50, 60, 127, 255}},
9510     };
9511     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
9512     const UINT num_faces28 = ARRAY_SIZE(vertices28) / VERTS_PER_FACE;
9513     const UINT vertex_size28 = sizeof(*vertices28);
9514     const struct vertex_ptc_float4 exp_vertices28[] =
9515     {
9516         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9517         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9518         {{ 0.0f,  0.0f,  0.f}, {1.0f,  0.0f, 1.0f, 0.0f}},
9519 
9520         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9521         {{ 3.0f,  0.0f,  0.f}, {10.0f, 20.0f, 30.0f, 40.0f}},
9522         {{ 1.0f,  0.0f,  0.f}, {50.0f, 60.0f, 127.0f, 255.0f}},
9523     };
9524     const UINT exp_vertex_size28 = sizeof(*exp_vertices28);
9525     /* Test 29. Convert SHORT2 to FLOAT4. */
9526     const struct vertex_ptc_short2 vertices29[] =
9527     {
9528         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9529         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9530         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9531 
9532         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9533         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX}},
9534         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9535     };
9536     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
9537     const UINT num_faces29 = ARRAY_SIZE(vertices29) / VERTS_PER_FACE;
9538     const UINT vertex_size29 = sizeof(*vertices29);
9539     const struct vertex_ptc_float4 exp_vertices29[] =
9540     {
9541         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9542         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9543         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 0.0f, 1.0f}},
9544 
9545         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9546         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 0.0f, 1.0f}},
9547         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, 0.0f, 1.0f}},
9548     };
9549     const UINT exp_vertex_size29 = sizeof(*exp_vertices29);
9550     /* Test 29. Convert SHORT4 to FLOAT4. */
9551     const struct vertex_ptc_short4 vertices30[] =
9552     {
9553         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9554         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9555         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9556 
9557         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9558         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1, 0}},
9559         {{ 1.0f,  0.0f,  0.f}, {-42, 42, SHRT_MAX, SHRT_MIN}},
9560     };
9561     const UINT num_vertices30 = ARRAY_SIZE(vertices30);
9562     const UINT num_faces30 = ARRAY_SIZE(vertices30) / VERTS_PER_FACE;
9563     const UINT vertex_size30 = sizeof(*vertices30);
9564     const struct vertex_ptc_float4 exp_vertices30[] =
9565     {
9566         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9567         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9568         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9569 
9570         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9571         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1.0f, 0.0f}},
9572         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, SHRT_MAX, SHRT_MIN}},
9573     };
9574     const UINT exp_vertex_size30 = sizeof(*exp_vertices30);
9575     /* Test 31. Convert UBYTE4N to FLOAT4. */
9576     const struct vertex_ptc_ubyte4n vertices31[] =
9577     {
9578         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9579         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9580         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9581 
9582         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9583         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9584         {{ 1.0f,  0.0f,  0.f}, {50, 60, 70, UCHAR_MAX}},
9585     };
9586     const UINT num_vertices31 = ARRAY_SIZE(vertices31);
9587     const UINT num_faces31 = ARRAY_SIZE(vertices31) / VERTS_PER_FACE;
9588     const UINT vertex_size31 = sizeof(*vertices31);
9589     const struct vertex_ptc_float4 exp_vertices31[] =
9590     {
9591         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9592         {{ 2.0f,  3.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX}},
9593         {{ 0.0f,  0.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX, 0.0f}},
9594 
9595         {{ 3.0f,  3.0f,  0.f}, {0.0f, (FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX}},
9596         {{ 3.0f,  0.0f,  0.f}, {(FLOAT)10/UCHAR_MAX, (FLOAT)20/UCHAR_MAX, (FLOAT)30/UCHAR_MAX, (FLOAT)40/UCHAR_MAX}},
9597         {{ 1.0f,  0.0f,  0.f}, {(FLOAT)50/UCHAR_MAX, (FLOAT)60/UCHAR_MAX, (FLOAT)70/UCHAR_MAX, 1.0f}},
9598     };
9599     const UINT exp_vertex_size31 = sizeof(*exp_vertices31);
9600     /* Test 32. Convert SHORT2N to FLOAT4. */
9601     const struct vertex_ptc_short2 vertices32[] =
9602     {
9603         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9604         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9605         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9606 
9607         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9608         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
9609         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9610     };
9611     const UINT num_vertices32 = ARRAY_SIZE(vertices32);
9612     const UINT num_faces32 = ARRAY_SIZE(vertices32) / VERTS_PER_FACE;
9613     const UINT vertex_size32 = sizeof(*vertices32);
9614     const struct vertex_ptc_float4 exp_vertices32[] =
9615     {
9616         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9617         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9618         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 0.0f, 1.0f}},
9619 
9620         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9621         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, 0.0f, 1.0f}},
9622         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 0.0f, 1.0f}},
9623     };
9624     const UINT exp_vertex_size32 = sizeof(*exp_vertices32);
9625     /* Test 33. Convert SHORT4N to FLOAT4. */
9626     const struct vertex_ptc_short4 vertices33[] =
9627     {
9628         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9629         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9630         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9631 
9632         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9633         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, SHRT_MIN + 1, SHRT_MAX}},
9634         {{ 1.0f,  0.0f,  0.f}, {-42, 42, 1, 1}},
9635     };
9636     const UINT num_vertices33 = ARRAY_SIZE(vertices33);
9637     const UINT num_faces33 = ARRAY_SIZE(vertices33) / VERTS_PER_FACE;
9638     const UINT vertex_size33 = sizeof(*vertices33);
9639     const struct vertex_ptc_float4 exp_vertices33[] =
9640     {
9641         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9642         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX}},
9643         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX, 0.0f}},
9644 
9645         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9646         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, -1.0f, 1.0f}},
9647         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9648     };
9649     const UINT exp_vertex_size33 = sizeof(*exp_vertices33);
9650     /* Test 34. Convert FLOAT16_2 to FLOAT4. */
9651     const struct vertex_ptc_float16_2 vertices34[] =
9652     {
9653         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9654         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9655         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9656 
9657         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9658         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9659         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9660     };
9661     const UINT num_vertices34 = ARRAY_SIZE(vertices34);
9662     const UINT num_faces34 = ARRAY_SIZE(vertices34) / VERTS_PER_FACE;
9663     const UINT vertex_size34 = sizeof(*vertices34);
9664     const struct vertex_ptc_float4 exp_vertices34[] =
9665     {
9666         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9667         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.700195f, 0.0f, 1.0f}},
9668         {{ 0.0f,  0.0f,  0.f}, {-0.199951f, -0.300049f, 0.0f, 1.0f}},
9669 
9670         {{ 3.0f,  3.0f,  0.f}, {0.199951f, 0.300049f, 0.0f, 1.0f}},
9671         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9672         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.0f, 1.0f}},
9673     };
9674     const UINT exp_vertex_size34 = sizeof(*exp_vertices34);
9675     /* Test 35. Convert FLOAT16_4 to FLOAT4. */
9676     const struct vertex_ptc_float16_4 vertices35[] =
9677     {
9678         {{ 0.0f,  3.0f,  0.f}, {0x0000, 0x0000, 0x0000, 0x0000}},
9679         {{ 2.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
9680         {{ 0.0f,  0.0f,  0.f}, {0x3c00, 0x0000, 0x3c00, 0x0000}},
9681 
9682         {{ 3.0f,  3.0f,  0.f}, {0x0000, 0x3c00, 0x0000, 0x3c00}},
9683         {{ 3.0f,  0.0f,  0.f}, {0x3800, 0x399a, 0xb266, 0xb4cd}},
9684         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
9685     };
9686     const UINT num_vertices35 = ARRAY_SIZE(vertices35);
9687     const UINT num_faces35 = ARRAY_SIZE(vertices35) / VERTS_PER_FACE;
9688     const UINT vertex_size35 = sizeof(*vertices35);
9689     const struct vertex_ptc_float4 exp_vertices35[] =
9690     {
9691         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9692         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9693         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9694 
9695         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9696         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.700195f, -0.199951f, -0.300049f}},
9697         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.099976f, 0.199951f}},
9698     };
9699     const UINT exp_vertex_size35 = sizeof(*exp_vertices35);
9700     /* Test 36. Check that vertex buffer sharing is ok. */
9701     const struct vertex_pn vertices36[] =
9702     {
9703         {{ 0.0f,  3.0f,  0.f}, up},
9704         {{ 2.0f,  3.0f,  0.f}, up},
9705         {{ 0.0f,  0.0f,  0.f}, up},
9706     };
9707     const UINT num_vertices36 = ARRAY_SIZE(vertices36);
9708     const UINT num_faces36 = ARRAY_SIZE(vertices36) / VERTS_PER_FACE;
9709     const UINT vertex_size36 = sizeof(*vertices36);
9710     const DWORD clone_options36 = options | D3DXMESH_VB_SHARE;
9711     /* Common mesh data */
9712     ID3DXMesh *mesh = NULL;
9713     ID3DXMesh *mesh_clone = NULL;
9714     struct
9715     {
9716         const BYTE *vertices;
9717         const DWORD *indices;
9718         const DWORD *attributes;
9719         const UINT num_vertices;
9720         const UINT num_faces;
9721         const UINT vertex_size;
9722         const DWORD create_options;
9723         const DWORD clone_options;
9724         D3DVERTEXELEMENT9 *declaration;
9725         D3DVERTEXELEMENT9 *new_declaration;
9726         const BYTE *exp_vertices;
9727         const UINT exp_vertex_size;
9728     }
9729     tc[] =
9730     {
9731         {
9732             (BYTE*)vertices0,
9733             NULL,
9734             NULL,
9735             num_vertices0,
9736             num_faces0,
9737             vertex_size0,
9738             options,
9739             options,
9740             declaration_pn,
9741             declaration_pn,
9742             (BYTE*)vertices0,
9743             vertex_size0
9744         },
9745         {
9746             (BYTE*)vertices0,
9747             NULL,
9748             NULL,
9749             num_vertices0,
9750             num_faces0,
9751             vertex_size0,
9752             options_16bit,
9753             options_16bit,
9754             declaration_pn,
9755             declaration_pn,
9756             (BYTE*)vertices0,
9757             vertex_size0
9758         },
9759         {
9760             (BYTE*)vertices0,
9761             NULL,
9762             NULL,
9763             num_vertices0,
9764             num_faces0,
9765             vertex_size0,
9766             options,
9767             options,
9768             declaration_pn,
9769             declaration_pntc,
9770             (BYTE*)exp_vertices2,
9771             exp_vertex_size2
9772         },
9773         {
9774             (BYTE*)vertices0,
9775             NULL,
9776             NULL,
9777             num_vertices0,
9778             num_faces0,
9779             vertex_size0,
9780             options,
9781             options,
9782             declaration_pn,
9783             declaration_ptcn,
9784             (BYTE*)exp_vertices3,
9785             exp_vertex_size3
9786         },
9787         {
9788             (BYTE*)vertices4,
9789             NULL,
9790             NULL,
9791             num_vertices4,
9792             num_faces4,
9793             vertex_size4,
9794             options,
9795             options,
9796             declaration_ptc,
9797             declaration_ptc_float16_2,
9798             (BYTE*)exp_vertices4,
9799             exp_vertex_size4
9800         },
9801         {
9802             (BYTE*)vertices5,
9803             NULL,
9804             NULL,
9805             num_vertices5,
9806             num_faces5,
9807             vertex_size5,
9808             options,
9809             options,
9810             declaration_ptc,
9811             declaration_ptc_float16_4,
9812             (BYTE*)exp_vertices5,
9813             exp_vertex_size5
9814         },
9815         {
9816             (BYTE*)vertices6,
9817             NULL,
9818             NULL,
9819             num_vertices6,
9820             num_faces6,
9821             vertex_size6,
9822             options,
9823             options,
9824             declaration_ptc,
9825             declaration_ptc_float1,
9826             (BYTE*)exp_vertices6,
9827             exp_vertex_size6
9828         },
9829         {
9830             (BYTE*)vertices7,
9831             NULL,
9832             NULL,
9833             num_vertices7,
9834             num_faces7,
9835             vertex_size7,
9836             options,
9837             options,
9838             declaration_ptc,
9839             declaration_ptc_float3,
9840             (BYTE*)exp_vertices7,
9841             exp_vertex_size7
9842         },
9843         {
9844             (BYTE*)vertices8,
9845             NULL,
9846             NULL,
9847             num_vertices8,
9848             num_faces8,
9849             vertex_size8,
9850             options,
9851             options,
9852             declaration_ptc,
9853             declaration_ptc_float4,
9854             (BYTE*)exp_vertices8,
9855             exp_vertex_size8
9856         },
9857         {
9858             (BYTE*)vertices9,
9859             NULL,
9860             NULL,
9861             num_vertices9,
9862             num_faces9,
9863             vertex_size9,
9864             options,
9865             options,
9866             declaration_ptc,
9867             declaration_ptc_d3dcolor,
9868             (BYTE*)exp_vertices9,
9869             exp_vertex_size9
9870         },
9871         {
9872             (BYTE*)vertices10,
9873             NULL,
9874             NULL,
9875             num_vertices10,
9876             num_faces10,
9877             vertex_size10,
9878             options,
9879             options,
9880             declaration_ptc,
9881             declaration_ptc_ubyte4,
9882             (BYTE*)exp_vertices10,
9883             exp_vertex_size10
9884         },
9885         {
9886             (BYTE*)vertices11,
9887             NULL,
9888             NULL,
9889             num_vertices11,
9890             num_faces11,
9891             vertex_size11,
9892             options,
9893             options,
9894             declaration_ptc,
9895             declaration_ptc_short2,
9896             (BYTE*)exp_vertices11,
9897             exp_vertex_size11
9898         },
9899         {
9900             (BYTE*)vertices12,
9901             NULL,
9902             NULL,
9903             num_vertices12,
9904             num_faces12,
9905             vertex_size12,
9906             options,
9907             options,
9908             declaration_ptc,
9909             declaration_ptc_short4,
9910             (BYTE*)exp_vertices12,
9911             exp_vertex_size12
9912         },
9913         {
9914             (BYTE*)vertices13,
9915             NULL,
9916             NULL,
9917             num_vertices13,
9918             num_faces13,
9919             vertex_size13,
9920             options,
9921             options,
9922             declaration_ptc,
9923             declaration_ptc_ubyte4n,
9924             (BYTE*)exp_vertices13,
9925             exp_vertex_size13
9926         },
9927         {
9928             (BYTE*)vertices14,
9929             NULL,
9930             NULL,
9931             num_vertices14,
9932             num_faces14,
9933             vertex_size14,
9934             options,
9935             options,
9936             declaration_ptc,
9937             declaration_ptc_short2n,
9938             (BYTE*)exp_vertices14,
9939             exp_vertex_size14
9940         },
9941         {
9942             (BYTE*)vertices15,
9943             NULL,
9944             NULL,
9945             num_vertices15,
9946             num_faces15,
9947             vertex_size15,
9948             options,
9949             options,
9950             declaration_ptc,
9951             declaration_ptc_short4n,
9952             (BYTE*)exp_vertices15,
9953             exp_vertex_size15
9954         },
9955         {
9956             (BYTE*)vertices16,
9957             NULL,
9958             NULL,
9959             num_vertices16,
9960             num_faces16,
9961             vertex_size16,
9962             options,
9963             options,
9964             declaration_ptc,
9965             declaration_ptc_ushort2n,
9966             (BYTE*)exp_vertices16,
9967             exp_vertex_size16
9968         },
9969         {
9970             (BYTE*)vertices17,
9971             NULL,
9972             NULL,
9973             num_vertices17,
9974             num_faces17,
9975             vertex_size17,
9976             options,
9977             options,
9978             declaration_ptc,
9979             declaration_ptc_ushort4n,
9980             (BYTE*)exp_vertices17,
9981             exp_vertex_size17
9982         },
9983         {
9984             (BYTE*)vertices18,
9985             NULL,
9986             NULL,
9987             num_vertices18,
9988             num_faces18,
9989             vertex_size18,
9990             options,
9991             options,
9992             declaration_ptc,
9993             declaration_ptc_float16_2_partialu,
9994             (BYTE*)exp_vertices18,
9995             exp_vertex_size18
9996         },
9997         {
9998             (BYTE*)vertices19,
9999             NULL,
10000             NULL,
10001             num_vertices19,
10002             num_faces19,
10003             vertex_size19,
10004             options,
10005             options,
10006             declaration_pntc,
10007             declaration_pntc1,
10008             (BYTE*)exp_vertices19,
10009             exp_vertex_size19
10010         },
10011         {
10012             (BYTE*)vertices20,
10013             NULL,
10014             NULL,
10015             num_vertices20,
10016             num_faces20,
10017             vertex_size20,
10018             options,
10019             options,
10020             declaration_pntc1,
10021             declaration_pntc,
10022             (BYTE*)exp_vertices20,
10023             exp_vertex_size20
10024         },
10025         {
10026             (BYTE*)vertices21,
10027             NULL,
10028             NULL,
10029             num_vertices21,
10030             num_faces21,
10031             vertex_size21,
10032             options,
10033             options,
10034             declaration_ptc_float1,
10035             declaration_ptc,
10036             (BYTE*)exp_vertices21,
10037             exp_vertex_size21
10038         },
10039         {
10040             (BYTE*)vertices22,
10041             NULL,
10042             NULL,
10043             num_vertices22,
10044             num_faces22,
10045             vertex_size22,
10046             options,
10047             options,
10048             declaration_ptc_float1,
10049             declaration_ptc_float3,
10050             (BYTE*)exp_vertices22,
10051             exp_vertex_size22
10052         },
10053         {
10054             (BYTE*)vertices23,
10055             NULL,
10056             NULL,
10057             num_vertices23,
10058             num_faces23,
10059             vertex_size23,
10060             options,
10061             options,
10062             declaration_ptc_float1,
10063             declaration_ptc_float4,
10064             (BYTE*)exp_vertices23,
10065             exp_vertex_size23
10066         },
10067         {
10068             (BYTE*)vertices24,
10069             NULL,
10070             NULL,
10071             num_vertices24,
10072             num_faces24,
10073             vertex_size24,
10074             options,
10075             options,
10076             declaration_ptc_float1,
10077             declaration_ptc_d3dcolor,
10078             (BYTE*)exp_vertices24,
10079             exp_vertex_size24
10080         },
10081         {
10082             (BYTE*)vertices25,
10083             NULL,
10084             NULL,
10085             num_vertices25,
10086             num_faces25,
10087             vertex_size25,
10088             options,
10089             options,
10090             declaration_ptc_float1,
10091             declaration_ptc_ubyte4,
10092             (BYTE*)exp_vertices25,
10093             exp_vertex_size25
10094         },
10095         {
10096             (BYTE*)vertices26,
10097             NULL,
10098             NULL,
10099             num_vertices26,
10100             num_faces26,
10101             vertex_size26,
10102             options,
10103             options,
10104             declaration_ptc_float4,
10105             declaration_ptc_d3dcolor,
10106             (BYTE*)exp_vertices26,
10107             exp_vertex_size26
10108         },
10109         {
10110             (BYTE*)vertices27,
10111             NULL,
10112             NULL,
10113             num_vertices27,
10114             num_faces27,
10115             vertex_size27,
10116             options,
10117             options,
10118             declaration_ptc_d3dcolor,
10119             declaration_ptc_float4,
10120             (BYTE*)exp_vertices27,
10121             exp_vertex_size27
10122         },
10123         {
10124             (BYTE*)vertices28,
10125             NULL,
10126             NULL,
10127             num_vertices28,
10128             num_faces28,
10129             vertex_size28,
10130             options,
10131             options,
10132             declaration_ptc_ubyte4,
10133             declaration_ptc_float4,
10134             (BYTE*)exp_vertices28,
10135             exp_vertex_size28
10136         },
10137         {
10138             (BYTE*)vertices29,
10139             NULL,
10140             NULL,
10141             num_vertices29,
10142             num_faces29,
10143             vertex_size29,
10144             options,
10145             options,
10146             declaration_ptc_short2,
10147             declaration_ptc_float4,
10148             (BYTE*)exp_vertices29,
10149             exp_vertex_size29
10150         },
10151         {
10152             (BYTE*)vertices30,
10153             NULL,
10154             NULL,
10155             num_vertices30,
10156             num_faces30,
10157             vertex_size30,
10158             options,
10159             options,
10160             declaration_ptc_short4,
10161             declaration_ptc_float4,
10162             (BYTE*)exp_vertices30,
10163             exp_vertex_size30
10164         },
10165         {
10166             (BYTE*)vertices31,
10167             NULL,
10168             NULL,
10169             num_vertices31,
10170             num_faces31,
10171             vertex_size31,
10172             options,
10173             options,
10174             declaration_ptc_ubyte4n,
10175             declaration_ptc_float4,
10176             (BYTE*)exp_vertices31,
10177             exp_vertex_size31
10178         },
10179         {
10180             (BYTE*)vertices32,
10181             NULL,
10182             NULL,
10183             num_vertices32,
10184             num_faces32,
10185             vertex_size32,
10186             options,
10187             options,
10188             declaration_ptc_short2n,
10189             declaration_ptc_float4,
10190             (BYTE*)exp_vertices32,
10191             exp_vertex_size32
10192         },
10193         {
10194             (BYTE*)vertices33,
10195             NULL,
10196             NULL,
10197             num_vertices33,
10198             num_faces33,
10199             vertex_size33,
10200             options,
10201             options,
10202             declaration_ptc_short4n,
10203             declaration_ptc_float4,
10204             (BYTE*)exp_vertices33,
10205             exp_vertex_size33
10206         },
10207         {
10208             (BYTE*)vertices34,
10209             NULL,
10210             NULL,
10211             num_vertices34,
10212             num_faces34,
10213             vertex_size34,
10214             options,
10215             options,
10216             declaration_ptc_float16_2,
10217             declaration_ptc_float4,
10218             (BYTE*)exp_vertices34,
10219             exp_vertex_size34
10220         },
10221         {
10222             (BYTE*)vertices35,
10223             NULL,
10224             NULL,
10225             num_vertices35,
10226             num_faces35,
10227             vertex_size35,
10228             options,
10229             options,
10230             declaration_ptc_float16_4,
10231             declaration_ptc_float4,
10232             (BYTE*)exp_vertices35,
10233             exp_vertex_size35
10234         },
10235         {
10236             (BYTE*)vertices36,
10237             NULL,
10238             NULL,
10239             num_vertices36,
10240             num_faces36,
10241             vertex_size36,
10242             options,
10243             clone_options36,
10244             declaration_pn,
10245             declaration_pn,
10246             (BYTE*)vertices36,
10247             vertex_size36
10248         },
10249     };
10250 #ifdef __REACTOS__
10251 #undef up
10252 #undef zero_vec2
10253 #endif
10254 
10255     test_context = new_test_context();
10256     if (!test_context)
10257     {
10258         skip("Couldn't create test context\n");
10259         goto cleanup;
10260     }
10261 
10262     for (i = 0; i < ARRAY_SIZE(tc); i++)
10263     {
10264         UINT j;
10265         D3DVERTEXELEMENT9 new_declaration[MAX_FVF_DECL_SIZE];
10266         UINT exp_new_decl_length, new_decl_length;
10267         UINT exp_new_decl_size, new_decl_size;
10268 
10269         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10270                               tc[i].create_options,
10271                               tc[i].declaration,
10272                               test_context->device, &mesh,
10273                               tc[i].vertices, tc[i].vertex_size,
10274                               tc[i].indices, tc[i].attributes);
10275         if (FAILED(hr))
10276         {
10277             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10278             goto cleanup;
10279         }
10280 
10281         hr = mesh->lpVtbl->CloneMesh(mesh, tc[i].clone_options, tc[i].new_declaration,
10282                                      test_context->device, &mesh_clone);
10283         ok(hr == D3D_OK, "CloneMesh test case %d failed. Got %x, expected D3D_OK.\n", i, hr);
10284 
10285         hr = mesh_clone->lpVtbl->GetDeclaration(mesh_clone, new_declaration);
10286         ok(hr == D3D_OK, "GetDeclaration test case %d failed. Got %x, expected D3D_OK.\n", i, hr);
10287         /* Check declaration elements */
10288         for (j = 0; tc[i].new_declaration[j].Stream != 0xFF; j++)
10289         {
10290             ok(memcmp(&tc[i].new_declaration[j], &new_declaration[j], sizeof(*new_declaration)) == 0,
10291                "Test case %d failed. Declaration element %d did not match.\n", i, j);
10292         }
10293 
10294         /* Check declaration length */
10295         exp_new_decl_length = D3DXGetDeclLength(tc[i].new_declaration);
10296         new_decl_length = D3DXGetDeclLength(new_declaration);
10297         ok(new_decl_length == exp_new_decl_length,
10298            "Test case %d failed. Got new declaration length %d, expected %d\n",
10299            i, new_decl_length, exp_new_decl_length);
10300 
10301         /* Check declaration size */
10302         exp_new_decl_size = D3DXGetDeclVertexSize(tc[i].new_declaration, 0);
10303         new_decl_size = D3DXGetDeclVertexSize(new_declaration, 0);
10304         ok(new_decl_size == exp_new_decl_size,
10305            "Test case %d failed. Got new declaration size %d, expected %d\n",
10306            i, new_decl_size, exp_new_decl_size);
10307 
10308         /* Check vertex data in cloned mesh */
10309         hr = mesh_clone->lpVtbl->LockVertexBuffer(mesh_clone, 0, (void**)&vertices);
10310         if (FAILED(hr))
10311         {
10312             skip("Couldn't lock cloned vertex buffer.\n");
10313             goto cleanup;
10314         }
10315         for (j = 0; j < tc[i].num_vertices; j++)
10316         {
10317             UINT index = tc[i].exp_vertex_size * j;
10318             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].new_declaration);
10319         }
10320         hr = mesh_clone->lpVtbl->UnlockVertexBuffer(mesh_clone);
10321         if (FAILED(hr))
10322         {
10323             skip("Couldn't unlock vertex buffer.\n");
10324             goto cleanup;
10325         }
10326         vertices = NULL;
10327         mesh->lpVtbl->Release(mesh);
10328         mesh = NULL;
10329         mesh_clone->lpVtbl->Release(mesh_clone);
10330         mesh_clone = NULL;
10331     }
10332 
10333     /* The following test shows that it is not possible to share a vertex buffer
10334      * with D3DXMESH_VB_SHARE and change the vertex declaration at the same
10335      * time. It reuses the test data from test 2.
10336      */
10337     hr = init_test_mesh(tc[2].num_faces, tc[2].num_vertices,
10338                         tc[2].create_options,
10339                         tc[2].declaration,
10340                         test_context->device, &mesh,
10341                         tc[2].vertices, tc[2].vertex_size,
10342                         tc[2].indices, tc[2].attributes);
10343     if (FAILED(hr))
10344     {
10345         skip("Couldn't initialize test mesh for D3DXMESH_VB_SHARE case."
10346              " Got %x expected D3D_OK\n", hr);
10347         goto cleanup;
10348     }
10349 
10350     hr = mesh->lpVtbl->CloneMesh(mesh, tc[2].create_options | D3DXMESH_VB_SHARE,
10351                                  tc[2].new_declaration, test_context->device,
10352                                  &mesh_clone);
10353     ok(hr == D3DERR_INVALIDCALL, "CloneMesh D3DXMESH_VB_SHARE with new"
10354        " declaration. Got %x, expected D3DERR_INVALIDCALL\n",
10355        hr);
10356     mesh->lpVtbl->Release(mesh);
10357     mesh = NULL;
10358     mesh_clone = NULL;
10359 
10360 cleanup:
10361     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
10362     if (mesh) mesh->lpVtbl->Release(mesh);
10363     if (mesh_clone) mesh_clone->lpVtbl->Release(mesh_clone);
10364     free_test_context(test_context);
10365 }
10366 
10367 static void test_valid_mesh(void)
10368 {
10369     HRESULT hr;
10370     struct test_context *test_context = NULL;
10371     UINT i;
10372     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
10373     const D3DVERTEXELEMENT9 declaration[] =
10374     {
10375         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10376         D3DDECL_END()
10377     };
10378     const unsigned int VERTS_PER_FACE = 3;
10379     /* mesh0 (one face)
10380      *
10381      * 0--1
10382      * | /
10383      * |/
10384      * 2
10385      */
10386     const D3DXVECTOR3 vertices0[] =
10387     {
10388         { 0.0f,  3.0f,  0.f},
10389         { 2.0f,  3.0f,  0.f},
10390         { 0.0f,  0.0f,  0.f},
10391     };
10392     const DWORD indices0[] = {0, 1, 2};
10393     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
10394     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
10395     const DWORD adjacency0[] = {-1, -1, -1};
10396     const HRESULT exp_hr0 = D3D_OK;
10397     /* mesh1 (Simple bow-tie)
10398      *
10399      * 0--1 1--3
10400      * | /   \ |
10401      * |/     \|
10402      * 2       4
10403      */
10404     const D3DXVECTOR3 vertices1[] =
10405     {
10406         { 0.0f,  3.0f,  0.f},
10407         { 2.0f,  3.0f,  0.f},
10408         { 0.0f,  0.0f,  0.f},
10409 
10410         { 4.0f,  3.0f,  0.f},
10411         { 4.0f,  0.0f,  0.f},
10412     };
10413     const DWORD indices1[] = {0, 1, 2, 1, 3, 4};
10414     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
10415     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
10416     const DWORD adjacency1[] = {-1, -1, -1, -1, -1, -1};
10417     const HRESULT exp_hr1 = D3DXERR_INVALIDMESH;
10418     /* Common mesh data */
10419     ID3DXMesh *mesh = NULL;
10420     UINT vertex_size = sizeof(D3DXVECTOR3);
10421     ID3DXBuffer *errors_and_warnings = NULL;
10422     struct
10423     {
10424         const D3DXVECTOR3 *vertices;
10425         const DWORD *indices;
10426         const UINT num_vertices;
10427         const UINT num_faces;
10428         const DWORD *adjacency;
10429         const HRESULT exp_hr;
10430     }
10431     tc[] =
10432     {
10433         {
10434             vertices0,
10435             indices0,
10436             num_vertices0,
10437             num_faces0,
10438             adjacency0,
10439             exp_hr0,
10440         },
10441         {
10442             vertices1,
10443             indices1,
10444             num_vertices1,
10445             num_faces1,
10446             adjacency1,
10447             exp_hr1,
10448         },
10449     };
10450 
10451     test_context = new_test_context();
10452     if (!test_context)
10453     {
10454         skip("Couldn't create test context\n");
10455         goto cleanup;
10456     }
10457 
10458     for (i = 0; i < ARRAY_SIZE(tc); i++)
10459     {
10460         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10461                             options, declaration,
10462                             test_context->device, &mesh,
10463                             tc[i].vertices, vertex_size,
10464                             tc[i].indices, NULL);
10465         if (FAILED(hr))
10466         {
10467             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10468             goto cleanup;
10469         }
10470 
10471         hr = D3DXValidMesh(mesh, tc[i].adjacency, &errors_and_warnings);
10472         todo_wine ok(hr == tc[i].exp_hr, "D3DXValidMesh test case %d failed. "
10473                 "Got %x, expected %x.\n", i, hr, tc[i].exp_hr);
10474 
10475         /* Note errors_and_warnings is deliberately not checked because that
10476          * would require copying wast amounts of the text output. */
10477         if (errors_and_warnings)
10478         {
10479             ID3DXBuffer_Release(errors_and_warnings);
10480             errors_and_warnings = NULL;
10481         }
10482         mesh->lpVtbl->Release(mesh);
10483         mesh = NULL;
10484     }
10485 
10486 cleanup:
10487     if (mesh) mesh->lpVtbl->Release(mesh);
10488     free_test_context(test_context);
10489 }
10490 
10491 static void test_optimize_vertices(void)
10492 {
10493     HRESULT hr;
10494     DWORD vertex_remap[3];
10495     const DWORD indices[] = {0, 1, 2};
10496     const UINT num_faces = 1;
10497     const UINT num_vertices = 3;
10498 
10499     hr = D3DXOptimizeVertices(indices, num_faces,
10500                               num_vertices, FALSE,
10501                               vertex_remap);
10502     ok(hr == D3D_OK, "D3DXOptimizeVertices failed. Got %x, expected D3D_OK.\n", hr);
10503 
10504     /* vertex_remap must not be NULL */
10505     hr = D3DXOptimizeVertices(indices, num_faces,
10506                               num_vertices, FALSE,
10507                               NULL);
10508     ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeVertices passed NULL vertex_remap "
10509             "pointer. Got %x, expected D3DERR_INVALIDCALL.\n", hr);
10510 }
10511 
10512 static void test_optimize_faces(void)
10513 {
10514     HRESULT hr;
10515     UINT i;
10516     DWORD smallest_face_remap;
10517     /* mesh0
10518      *
10519      * 0--1
10520      * | /
10521      * |/
10522      * 2
10523      */
10524     const DWORD indices0[] = {0, 1, 2};
10525     const UINT num_faces0 = 1;
10526     const UINT num_vertices0 = 3;
10527     const DWORD exp_face_remap0[] = {0};
10528     /* mesh1
10529      *
10530      * 0--1 3
10531      * | / /|
10532      * |/ / |
10533      * 2 5--4
10534      */
10535     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
10536     const UINT num_faces1 = 2;
10537     const UINT num_vertices1 = 6;
10538     const DWORD exp_face_remap1[] = {1, 0};
10539     /* mesh2
10540      *
10541      * 0--1
10542      * | /|
10543      * |/ |
10544      * 2--3
10545      */
10546     const DWORD indices2[] = {0, 1, 2, 1, 3, 2};
10547     const UINT num_faces2 = 2;
10548     const UINT num_vertices2 = 4;
10549     const DWORD exp_face_remap2[] = {1, 0};
10550     /* mesh3
10551      *
10552      * 0--1
10553      * | /|
10554      * |/ |
10555      * 2--3
10556      * | /|
10557      * |/ |
10558      * 4--5
10559      */
10560     const DWORD indices3[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
10561     const UINT num_faces3 = 4;
10562     const UINT num_vertices3 = 6;
10563     const DWORD exp_face_remap3[] = {3, 2, 1, 0};
10564     /* mesh4
10565      *
10566      * 0--1
10567      * | /|
10568      * |/ |
10569      * 2--3
10570      * | /|
10571      * |/ |
10572      * 4--5
10573      */
10574     const WORD indices4[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
10575     const UINT num_faces4 = 4;
10576     const UINT num_vertices4 = 6;
10577     const DWORD exp_face_remap4[] = {3, 2, 1, 0};
10578     /* Test cases are stored in the tc array */
10579     struct
10580     {
10581         const VOID *indices;
10582         const UINT num_faces;
10583         const UINT num_vertices;
10584         const BOOL indices_are_32bit;
10585         const DWORD *exp_face_remap;
10586     }
10587     tc[] =
10588     {
10589         {
10590             indices0,
10591             num_faces0,
10592             num_vertices0,
10593             TRUE,
10594             exp_face_remap0
10595         },
10596         {
10597             indices1,
10598             num_faces1,
10599             num_vertices1,
10600             TRUE,
10601             exp_face_remap1
10602         },
10603         {
10604             indices2,
10605             num_faces2,
10606             num_vertices2,
10607             TRUE,
10608             exp_face_remap2
10609         },
10610         {
10611             indices3,
10612             num_faces3,
10613             num_vertices3,
10614             TRUE,
10615             exp_face_remap3
10616         },
10617         {
10618             indices4,
10619             num_faces4,
10620             num_vertices4,
10621             FALSE,
10622             exp_face_remap4
10623         },
10624     };
10625 
10626     /* Go through all test cases */
10627     for (i = 0; i < ARRAY_SIZE(tc); i++)
10628     {
10629         DWORD j;
10630         DWORD *face_remap;
10631         face_remap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
10632                                tc[i].num_faces*sizeof(*face_remap));
10633 
10634         hr = D3DXOptimizeFaces(tc[i].indices, tc[i].num_faces,
10635                                tc[i].num_vertices, tc[i].indices_are_32bit,
10636                                face_remap);
10637         ok(hr == D3D_OK, "D3DXOptimizeFaces test case %d failed. "
10638                 "Got %x, expected D3D_OK.\n", i, hr);
10639 
10640         /* Compare face remap with expected face remap */
10641         for (j = 0; j < tc[i].num_faces; j++)
10642         {
10643             ok(tc[i].exp_face_remap[j] == face_remap[j],
10644                "Test case %d: Got face %d at %d, expected %d\n", i,
10645                face_remap[j], j, tc[i].exp_face_remap[j]);
10646         }
10647 
10648         HeapFree(GetProcessHeap(), 0, face_remap);
10649     }
10650 
10651     /* face_remap must not be NULL */
10652     hr = D3DXOptimizeFaces(tc[0].indices, tc[0].num_faces,
10653                            tc[0].num_vertices, tc[0].indices_are_32bit,
10654                            NULL);
10655     ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeFaces passed NULL face_remap "
10656             "pointer. Got %x, expected D3DERR_INVALIDCALL.\n", hr);
10657 
10658     /* Number of faces must be smaller than 2^15 */
10659     hr = D3DXOptimizeFaces(tc[0].indices, 2 << 15,
10660                            tc[0].num_vertices, FALSE,
10661                            &smallest_face_remap);
10662     ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeFaces should not accept 2^15 "
10663             "faces when using 16-bit indices. Got %x, expected D3DERR_INVALIDCALL.\n", hr);
10664 }
10665 
10666 static HRESULT clear_normals(ID3DXMesh *mesh)
10667 {
10668     HRESULT hr;
10669     BYTE *vertices;
10670     size_t normal_size;
10671     DWORD i, num_vertices, vertex_stride;
10672     const D3DXVECTOR4 normal = {NAN, NAN, NAN, NAN};
10673     D3DVERTEXELEMENT9 *normal_declaration = NULL;
10674     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
10675 
10676     if (FAILED(hr = mesh->lpVtbl->GetDeclaration(mesh, declaration)))
10677         return hr;
10678 
10679     for (i = 0; declaration[i].Stream != 0xff; i++)
10680     {
10681         if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
10682         {
10683             normal_declaration = &declaration[i];
10684             break;
10685         }
10686     }
10687 
10688     if (!normal_declaration)
10689         return D3DERR_INVALIDCALL;
10690 
10691     if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
10692     {
10693         normal_size = sizeof(D3DXVECTOR3);
10694     }
10695     else if (normal_declaration->Type == D3DDECLTYPE_FLOAT4)
10696     {
10697         normal_size = sizeof(D3DXVECTOR4);
10698     }
10699     else
10700     {
10701         trace("Cannot clear normals\n");
10702         return E_NOTIMPL;
10703     }
10704 
10705     num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
10706     vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
10707 
10708     if (FAILED(hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
10709         return hr;
10710 
10711     vertices += normal_declaration->Offset;
10712 
10713     for (i = 0; i < num_vertices; i++, vertices += vertex_stride)
10714         memcpy(vertices, &normal, normal_size);
10715 
10716     return mesh->lpVtbl->UnlockVertexBuffer(mesh);
10717 }
10718 
10719 static void compare_normals(unsigned int line, const char *test_name,
10720         ID3DXMesh *mesh, const D3DXVECTOR3 *normals, unsigned int num_normals)
10721 {
10722     unsigned int i;
10723     BYTE *vertices;
10724     DWORD num_vertices, vertex_stride;
10725     D3DVERTEXELEMENT9 *normal_declaration = NULL;
10726     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
10727 
10728     if (FAILED(mesh->lpVtbl->GetDeclaration(mesh, declaration)))
10729     {
10730         ok_(__FILE__, line)(0, "%s: Failed to get declaration\n", test_name);
10731         return;
10732     }
10733 
10734     for (i = 0; declaration[i].Stream != 0xff; i++)
10735     {
10736         if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
10737         {
10738             normal_declaration = &declaration[i];
10739             break;
10740         }
10741     }
10742 
10743     if (!normal_declaration)
10744     {
10745         ok_(__FILE__, line)(0, "%s: Mesh has no normals\n", test_name);
10746         return;
10747     }
10748 
10749     if (normal_declaration->Type != D3DDECLTYPE_FLOAT3 && normal_declaration->Type != D3DDECLTYPE_FLOAT4)
10750     {
10751         ok_(__FILE__, line)(0, "%s: Mesh has invalid normals type\n", test_name);
10752         return;
10753     }
10754 
10755     num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
10756     vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
10757 
10758     ok_(__FILE__, line)(num_vertices == num_normals, "%s: Expected %u vertices, got %u\n", test_name,
10759             num_normals, num_vertices);
10760 
10761     if (FAILED(mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
10762     {
10763         ok_(__FILE__, line)(0, "%s: Failed to compare normals\n", test_name);
10764         return;
10765     }
10766 
10767     vertices += normal_declaration->Offset;
10768 
10769     for (i = 0; i < min(num_vertices, num_normals); i++, vertices += vertex_stride)
10770     {
10771         if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
10772         {
10773             const D3DXVECTOR3 *n = (D3DXVECTOR3 *)vertices;
10774             ok_(__FILE__, line)(compare_vec3(*n, normals[i]),
10775                     "%s: normal %2u, expected (%f, %f, %f), got (%f, %f, %f)\n",
10776                     test_name, i, normals[i].x, normals[i].y, normals[i].z, n->x, n->y, n->z);
10777         }
10778         else
10779         {
10780             const D3DXVECTOR4 *n = (D3DXVECTOR4 *)vertices;
10781             const D3DXVECTOR4 normal = {normals[i].x, normals[i].y, normals[i].z, 1.0f};
10782             ok_(__FILE__, line)(compare_vec4(*n, normal),
10783                     "%s: normal %2u, expected (%f, %f, %f, %f), got (%f, %f, %f, %f)\n",
10784                     test_name, i, normals[i].x, normals[i].y, normals[i].z, 1.0f,
10785                     n->x, n->y, n->z, n->w);
10786         }
10787     }
10788 
10789     mesh->lpVtbl->UnlockVertexBuffer(mesh);
10790 }
10791 
10792 static HRESULT compute_normals_D3DXComputeNormals(ID3DXMesh *mesh, const DWORD *adjacency)
10793 {
10794     return D3DXComputeNormals((ID3DXBaseMesh *)mesh, adjacency);
10795 }
10796 
10797 static HRESULT compute_normals_D3DXComputeTangentFrameEx(ID3DXMesh *mesh, const DWORD *adjacency)
10798 {
10799     return D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10800             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
10801             adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL);
10802 }
10803 
10804 static void test_compute_normals(void)
10805 {
10806     HRESULT hr;
10807     ULONG refcount;
10808     ID3DXMesh *mesh, *cloned_mesh;
10809     ID3DXBuffer *adjacency;
10810     IDirect3DDevice9 *device;
10811     struct test_context *test_context;
10812     unsigned int i;
10813 
10814     static const struct compute_normals_func
10815     {
10816         const char *name;
10817         HRESULT (*apply)(ID3DXMesh *mesh, const DWORD *adjacency);
10818     }
10819     compute_normals_funcs[] =
10820     {
10821         {"D3DXComputeNormals",        compute_normals_D3DXComputeNormals       },
10822         {"D3DXComputeTangentFrameEx", compute_normals_D3DXComputeTangentFrameEx}
10823     };
10824 
10825     static const D3DXVECTOR3 box_normals[24] =
10826     {
10827         {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f},
10828         { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f},
10829         { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f},
10830         { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f},
10831         { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f},
10832         { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}
10833     };
10834     const float box_normal_component = 1.0f / sqrtf(3.0f);
10835     const D3DXVECTOR3 box_normals_adjacency[24] =
10836     {
10837         {-box_normal_component, -box_normal_component, -box_normal_component},
10838         {-box_normal_component, -box_normal_component,  box_normal_component},
10839         {-box_normal_component,  box_normal_component,  box_normal_component},
10840         {-box_normal_component,  box_normal_component, -box_normal_component},
10841         {-box_normal_component,  box_normal_component, -box_normal_component},
10842         {-box_normal_component,  box_normal_component,  box_normal_component},
10843         { box_normal_component,  box_normal_component,  box_normal_component},
10844         { box_normal_component,  box_normal_component, -box_normal_component},
10845         { box_normal_component,  box_normal_component, -box_normal_component},
10846         { box_normal_component,  box_normal_component,  box_normal_component},
10847         { box_normal_component, -box_normal_component,  box_normal_component},
10848         { box_normal_component, -box_normal_component, -box_normal_component},
10849         {-box_normal_component, -box_normal_component,  box_normal_component},
10850         {-box_normal_component, -box_normal_component, -box_normal_component},
10851         { box_normal_component, -box_normal_component, -box_normal_component},
10852         { box_normal_component, -box_normal_component,  box_normal_component},
10853         {-box_normal_component, -box_normal_component,  box_normal_component},
10854         { box_normal_component, -box_normal_component,  box_normal_component},
10855         { box_normal_component,  box_normal_component,  box_normal_component},
10856         {-box_normal_component,  box_normal_component,  box_normal_component},
10857         {-box_normal_component, -box_normal_component, -box_normal_component},
10858         {-box_normal_component,  box_normal_component, -box_normal_component},
10859         { box_normal_component,  box_normal_component, -box_normal_component},
10860         { box_normal_component, -box_normal_component, -box_normal_component}
10861     };
10862     static const D3DXVECTOR3 box_normals_adjacency_area[24] =
10863     {
10864         {-0.666667f, -0.333333f, -0.666667f}, {-0.333333f, -0.666667f,  0.666667f},
10865         {-0.816496f,  0.408248f,  0.408248f}, {-0.408248f,  0.816496f, -0.408248f},
10866         {-0.408248f,  0.816496f, -0.408248f}, {-0.816496f,  0.408248f,  0.408248f},
10867         { 0.333333f,  0.666667f,  0.666667f}, { 0.666667f,  0.333333f, -0.666667f},
10868         { 0.666667f,  0.333333f, -0.666667f}, { 0.333333f,  0.666667f,  0.666667f},
10869         { 0.816496f, -0.408248f,  0.408248f}, { 0.408248f, -0.816496f, -0.408248f},
10870         {-0.333333f, -0.666667f,  0.666667f}, {-0.666667f, -0.333333f, -0.666667f},
10871         { 0.408248f, -0.816496f, -0.408248f}, { 0.816496f, -0.408248f,  0.408248f},
10872         {-0.333333f, -0.666667f,  0.666667f}, { 0.816497f, -0.408248f,  0.408248f},
10873         { 0.333333f,  0.666667f,  0.666667f}, {-0.816497f,  0.408248f,  0.408248f},
10874         {-0.666667f, -0.333333f, -0.666667f}, {-0.408248f,  0.816497f, -0.408248f},
10875         { 0.666667f,  0.333333f, -0.666667f}, { 0.408248f, -0.816496f, -0.408248f}
10876     };
10877     static const D3DXVECTOR3 box_normals_position1f[24] = {{0}};
10878     static const D3DXVECTOR3 box_normals_position2f[24] =
10879     {
10880         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
10881         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f},
10882         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
10883         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
10884         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
10885         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
10886         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
10887         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}
10888     };
10889 
10890     static const D3DXVECTOR3 sphere_normals[22] =
10891     {
10892         { 0.000000f, -0.000000f,  1.000000f}, { 0.000000f,  0.582244f,  0.813014f},
10893         { 0.582244f, -0.000000f,  0.813014f}, {-0.000000f, -0.582244f,  0.813014f},
10894         {-0.582244f,  0.000000f,  0.813014f}, {-0.000000f,  0.890608f,  0.454772f},
10895         { 0.890608f,  0.000000f,  0.454772f}, { 0.000000f, -0.890608f,  0.454772f},
10896         {-0.890608f, -0.000000f,  0.454772f}, { 0.000000f,  1.000000f, -0.000000f},
10897         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10898         {-1.000000f,  0.000000f, -0.000000f}, { 0.000000f,  0.890608f, -0.454773f},
10899         { 0.890608f, -0.000000f, -0.454772f}, {-0.000000f, -0.890608f, -0.454773f},
10900         {-0.890608f,  0.000000f, -0.454773f}, { 0.000000f,  0.582244f, -0.813015f},
10901         { 0.582244f, -0.000000f, -0.813015f}, { 0.000000f, -0.582244f, -0.813015f},
10902         {-0.582243f,  0.000000f, -0.813015f}, { 0.000000f,  0.000000f, -1.000000f}
10903     };
10904     static const D3DXVECTOR3 sphere_normals_area[22] =
10905     {
10906         { 0.000000f, -0.000000f,  1.000000f}, {-0.215311f,  0.554931f,  0.803550f},
10907         { 0.554931f,  0.215311f,  0.803550f}, { 0.215311f, -0.554931f,  0.803550f},
10908         {-0.554931f, -0.215311f,  0.803550f}, {-0.126638f,  0.872121f,  0.472618f},
10909         { 0.872121f,  0.126638f,  0.472618f}, { 0.126638f, -0.872121f,  0.472618f},
10910         {-0.872121f, -0.126637f,  0.472618f}, { 0.000000f,  1.000000f, -0.000000f},
10911         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10912         {-1.000000f,  0.000000f, -0.000000f}, { 0.126638f,  0.872121f, -0.472618f},
10913         { 0.872121f, -0.126638f, -0.472618f}, {-0.126638f, -0.872121f, -0.472618f},
10914         {-0.872121f,  0.126638f, -0.472618f}, { 0.215311f,  0.554931f, -0.803550f},
10915         { 0.554931f, -0.215311f, -0.803550f}, {-0.215311f, -0.554931f, -0.803550f},
10916         {-0.554931f,  0.215311f, -0.803550f}, { 0.000000f,  0.000000f, -1.000000f}
10917     };
10918     static const D3DXVECTOR3 sphere_normals_equal[22] =
10919     {
10920         { 0.000000f, -0.000000f,  1.000000f}, {-0.134974f,  0.522078f,  0.842150f},
10921         { 0.522078f,  0.134974f,  0.842150f}, { 0.134974f, -0.522078f,  0.842150f},
10922         {-0.522078f, -0.134974f,  0.842150f}, {-0.026367f,  0.857121f,  0.514440f},
10923         { 0.857121f,  0.026367f,  0.514440f}, { 0.026367f, -0.857121f,  0.514440f},
10924         {-0.857121f, -0.026367f,  0.514440f}, { 0.000000f,  1.000000f, -0.000000f},
10925         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10926         {-1.000000f,  0.000000f, -0.000000f}, { 0.026367f,  0.857121f, -0.514440f},
10927         { 0.857121f, -0.026367f, -0.514440f}, {-0.026367f, -0.857121f, -0.514440f},
10928         {-0.857121f,  0.026367f, -0.514440f}, { 0.134975f,  0.522078f, -0.842150f},
10929         { 0.522078f, -0.134975f, -0.842150f}, {-0.134974f, -0.522078f, -0.842150f},
10930         {-0.522078f,  0.134974f, -0.842150f}, { 0.000000f,  0.000000f, -1.000000f}
10931     };
10932 
10933     static const D3DVERTEXELEMENT9 position3f_normal1f_declaration[] =
10934     {
10935         {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10936         {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10937         D3DDECL_END()
10938     };
10939     static const D3DVERTEXELEMENT9 position3f_normal2f_declaration[] =
10940     {
10941         {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10942         {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10943         D3DDECL_END()
10944     };
10945     static const D3DVERTEXELEMENT9 normal4f_position3f_declaration[] =
10946     {
10947         {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10948         {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10949         D3DDECL_END()
10950     };
10951     static const D3DVERTEXELEMENT9 position1f_normal3f_declaration[] =
10952     {
10953         {0, 0,                   D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10954         {0, sizeof(float),       D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10955         D3DDECL_END()
10956     };
10957     static const D3DVERTEXELEMENT9 position2f_normal3f_declaration[] =
10958     {
10959         {0, 0,                   D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10960         {0, sizeof(D3DXVECTOR2), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10961         D3DDECL_END()
10962     };
10963     static const D3DVERTEXELEMENT9 position4f_normal3f_declaration[] =
10964     {
10965         {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10966         {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10967         D3DDECL_END()
10968     };
10969 
10970     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
10971     {
10972         hr = compute_normals_funcs[i].apply(NULL, NULL);
10973         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", compute_normals_funcs[i].name, hr);
10974     }
10975 
10976     if (!(test_context = new_test_context()))
10977     {
10978         skip("Couldn't create test context\n");
10979         return;
10980     }
10981     device = test_context->device;
10982 
10983     hr = D3DXCreateBox(device, 1.0f, 1.0f, 1.0f, &mesh, &adjacency);
10984     ok(SUCCEEDED(hr), "D3DXCreateBox failed %#x\n", hr);
10985 
10986     /* Check wrong input */
10987     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10988             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10989     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10990 
10991     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DDECLUSAGE_NORMAL, 0,
10992             D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA | D3DXTANGENT_WEIGHT_EQUAL,
10993             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10994     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10995 
10996     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10997             D3DDECLUSAGE_NORMAL, 0, 0, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10998     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10999 
11000     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11001             D3DDECLUSAGE_NORMAL, 1, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
11002             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11003     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11004 
11005     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11006             D3DX_DEFAULT, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
11007             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11008     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11009 
11010     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11011             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_CALCULATE_NORMALS,
11012             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11013     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11014 
11015     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
11016     {
11017         const struct compute_normals_func *func = &compute_normals_funcs[i];
11018 
11019         /* Mesh without normals */
11020         hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_XYZ, device, &cloned_mesh);
11021         ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
11022 
11023         hr = func->apply(cloned_mesh, NULL);
11024         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11025 
11026         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11027         ok(!refcount, "Mesh has %u references left\n", refcount);
11028 
11029         /* Mesh without positions */
11030         hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_NORMAL, device, &cloned_mesh);
11031         ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
11032 
11033         hr = func->apply(cloned_mesh, NULL);
11034         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11035 
11036         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11037         ok(!refcount, "Mesh has %u references left\n", refcount);
11038 
11039         /* Mesh with D3DDECLTYPE_FLOAT1 normals */
11040         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal1f_declaration, device, &cloned_mesh);
11041         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11042 
11043         hr = func->apply(cloned_mesh, NULL);
11044         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11045 
11046         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11047         ok(!refcount, "Mesh has %u references left\n", refcount);
11048 
11049         /* Mesh with D3DDECLTYPE_FLOAT2 normals */
11050         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal2f_declaration, device, &cloned_mesh);
11051         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11052 
11053         hr = func->apply(cloned_mesh, NULL);
11054         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11055 
11056         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11057         ok(!refcount, "Mesh has %u references left\n", refcount);
11058 
11059         /* Mesh without adjacency data */
11060         hr = clear_normals(mesh);
11061         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11062 
11063         hr = func->apply(mesh, NULL);
11064         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11065 
11066         compare_normals(__LINE__, func->name, mesh, box_normals, ARRAY_SIZE(box_normals));
11067 
11068         /* Mesh with adjacency data */
11069         hr = clear_normals(mesh);
11070         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11071 
11072         hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11073         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11074 
11075         compare_normals(__LINE__, func->name, mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
11076 
11077         /* Mesh with custom vertex format, D3DDECLTYPE_FLOAT4 normals and adjacency */
11078         hr = mesh->lpVtbl->CloneMesh(mesh, 0, normal4f_position3f_declaration, device, &cloned_mesh);
11079         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11080 
11081         hr = clear_normals(cloned_mesh);
11082         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11083 
11084         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11085         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11086 
11087         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
11088 
11089         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11090         ok(!refcount, "Mesh has %u references left\n", refcount);
11091 
11092         /* Mesh with D3DDECLTYPE_FLOAT1 positions and D3DDECLTYPE_FLOAT3 normals */
11093         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position1f_normal3f_declaration, device, &cloned_mesh);
11094         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11095 
11096         hr = clear_normals(cloned_mesh);
11097         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11098 
11099         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11100         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11101 
11102         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position1f, ARRAY_SIZE(box_normals_position1f));
11103 
11104         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11105         ok(!refcount, "Mesh has %u references left\n", refcount);
11106 
11107         /* Mesh with D3DDECLTYPE_FLOAT2 positions and D3DDECLTYPE_FLOAT3 normals */
11108         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position2f_normal3f_declaration, device, &cloned_mesh);
11109         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11110 
11111         hr = clear_normals(cloned_mesh);
11112         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11113 
11114         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11115         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11116 
11117         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position2f, ARRAY_SIZE(box_normals_position2f));
11118 
11119         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11120         ok(!refcount, "Mesh has %u references left\n", refcount);
11121 
11122         /* Mesh with D3DDECLTYPE_FLOAT4 positions and D3DDECLTYPE_FLOAT3 normals */
11123         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position4f_normal3f_declaration, device, &cloned_mesh);
11124         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11125 
11126         hr = clear_normals(cloned_mesh);
11127         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11128 
11129         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11130         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11131 
11132         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
11133 
11134         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11135         ok(!refcount, "Mesh has %u references left\n", refcount);
11136     }
11137 
11138     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11139             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11140             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11141     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11142 
11143     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
11144 
11145     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11146             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11147             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11148     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11149 
11150     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
11151 
11152     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11153             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11154             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11155     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11156 
11157     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
11158 
11159     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11160             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11161             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11162     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11163 
11164     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
11165 
11166     refcount = mesh->lpVtbl->Release(mesh);
11167     ok(!refcount, "Mesh has %u references left\n", refcount);
11168     refcount = ID3DXBuffer_Release(adjacency);
11169     ok(!refcount, "Buffer has %u references left\n", refcount);
11170 
11171     hr = D3DXCreateSphere(device, 1.0f, 4, 6, &mesh, &adjacency);
11172     ok(SUCCEEDED(hr), "D3DXCreateSphere failed %#x\n", hr);
11173 
11174     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
11175     {
11176         const struct compute_normals_func *func = &compute_normals_funcs[i];
11177 
11178         /* Sphere without adjacency data */
11179         hr = clear_normals(mesh);
11180         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11181 
11182         hr = func->apply(mesh, NULL);
11183         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11184 
11185         compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
11186 
11187         /* Sphere with adjacency data */
11188         hr = clear_normals(mesh);
11189         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11190 
11191         hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11192         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11193 
11194         compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
11195     }
11196 
11197     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11198             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11199             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11200     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11201 
11202     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
11203 
11204     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11205             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11206             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11207     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11208 
11209     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
11210 
11211     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11212             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11213             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11214     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11215 
11216     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
11217 
11218     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11219             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11220             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11221     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11222 
11223     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
11224 
11225     refcount = mesh->lpVtbl->Release(mesh);
11226     ok(!refcount, "Mesh has %u references left\n", refcount);
11227     refcount = ID3DXBuffer_Release(adjacency);
11228     ok(!refcount, "Buffer has %u references left\n", refcount);
11229 
11230     free_test_context(test_context);
11231 }
11232 
11233 static void D3DXCreateAnimationControllerTest(void)
11234 {
11235     HRESULT hr;
11236     ID3DXAnimationController *animation;
11237     UINT value;
11238 
11239     hr = D3DXCreateAnimationController(0, 0, 0, 0, NULL);
11240     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11241 
11242     animation = (void*)0xdeadbeef;
11243     hr = D3DXCreateAnimationController(0, 1, 1, 1, &animation);
11244     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11245     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11246 
11247     animation = (void*)0xdeadbeef;
11248     hr = D3DXCreateAnimationController(1, 0, 1, 1, &animation);
11249     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11250     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11251 
11252     animation = (void*)0xdeadbeef;
11253     hr = D3DXCreateAnimationController(1, 1, 0, 1, &animation);
11254     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11255     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11256 
11257     animation = (void*)0xdeadbeef;
11258     hr = D3DXCreateAnimationController(1, 1, 1, 0, &animation);
11259     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11260     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11261 
11262     hr = D3DXCreateAnimationController(1, 1, 1, 1, &animation);
11263     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11264 
11265     value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
11266     ok(value == 1, "Got unexpected value %u.\n", value);
11267 
11268     value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
11269     ok(value == 1, "Got unexpected value %u.\n", value);
11270 
11271     value = animation->lpVtbl->GetMaxNumTracks(animation);
11272     ok(value == 1, "Got unexpected value %u.\n", value);
11273 
11274     value = animation->lpVtbl->GetMaxNumEvents(animation);
11275     ok(value == 1, "Got unexpected value %u.\n", value);
11276 
11277     animation->lpVtbl->Release(animation);
11278 
11279     hr = D3DXCreateAnimationController(100, 101, 102, 103, &animation);
11280     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11281 
11282     value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
11283     ok(value == 100, "Got unexpected value %u.\n", value);
11284 
11285     value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
11286     ok(value == 101, "Got unexpected value %u.\n", value);
11287 
11288     value = animation->lpVtbl->GetMaxNumTracks(animation);
11289     ok(value == 102, "Got unexpected value %u.\n", value);
11290 
11291     value = animation->lpVtbl->GetMaxNumEvents(animation);
11292     ok(value == 103, "Got unexpected value %u.\n", value);
11293 
11294     animation->lpVtbl->Release(animation);
11295 }
11296 
11297 static void test_D3DXFrameFind(void)
11298 {
11299     static char n1[] = "name1";
11300     static char n2[] = "name2";
11301     static char n3[] = "name3";
11302     static char n4[] = "name4";
11303     static char n5[] = "name5";
11304     static char n6[] = "name6";
11305     static char N1[] = "Name1";
11306     D3DXFRAME root, sibling, sibling2, child, *ret;
11307     D3DXFRAME child2, child3;
11308 
11309     ret = D3DXFrameFind(NULL, NULL);
11310     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11311 
11312     ret = D3DXFrameFind(NULL, "test");
11313     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11314 
11315     memset(&root, 0, sizeof(root));
11316 
11317     ret = D3DXFrameFind(&root, NULL);
11318     ok(ret == &root, "Unexpected frame, %p.\n", ret);
11319 
11320     root.Name = n1;
11321     ret = D3DXFrameFind(&root, NULL);
11322     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11323 
11324     ret = D3DXFrameFind(&root, n1);
11325     ok(ret == &root, "Unexpected frame, %p.\n", ret);
11326 
11327     ret = D3DXFrameFind(&root, N1);
11328     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11329 
11330     /* Test siblings order traversal. */
11331     memset(&sibling, 0, sizeof(sibling));
11332     sibling.Name = n2;
11333     root.pFrameSibling = &sibling;
11334     ret = D3DXFrameFind(&root, n2);
11335     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11336 
11337     memset(&sibling2, 0, sizeof(sibling2));
11338     sibling2.Name = n2;
11339     sibling.pFrameSibling = &sibling2;
11340     ret = D3DXFrameFind(&root, n2);
11341     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11342 
11343     sibling2.Name = n3;
11344     ret = D3DXFrameFind(&root, n3);
11345     ok(ret == &sibling2, "Unexpected frame, %p.\n", ret);
11346 
11347     /* Siblings first. */
11348     memset(&child, 0, sizeof(child));
11349     child.Name = n2;
11350     root.pFrameFirstChild = &child;
11351     ret = D3DXFrameFind(&root, n2);
11352     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11353 
11354     child.Name = n4;
11355     ret = D3DXFrameFind(&root, n4);
11356     ok(ret == &child, "Unexpected frame, %p.\n", ret);
11357 
11358     /* Link a grandchild and another one for sibling. */
11359     memset(&child2, 0, sizeof(child2));
11360     memset(&child3, 0, sizeof(child3));
11361     child2.Name = child3.Name = n5;
11362     sibling.pFrameFirstChild = &child2;
11363     child.pFrameFirstChild = &child3;
11364     ret = D3DXFrameFind(&root, n5);
11365     ok(ret == &child2, "Unexpected frame, %p.\n", ret);
11366 
11367     child3.Name = n6;
11368     ret = D3DXFrameFind(&root, n6);
11369     ok(ret == &child3, "Unexpected frame, %p.\n", ret);
11370 }
11371 
11372 START_TEST(mesh)
11373 {
11374     D3DXBoundProbeTest();
11375     D3DXComputeBoundingBoxTest();
11376     D3DXComputeBoundingSphereTest();
11377     D3DXGetFVFVertexSizeTest();
11378     D3DXIntersectTriTest();
11379     D3DXCreateMeshTest();
11380     D3DXCreateMeshFVFTest();
11381     D3DXLoadMeshTest();
11382     D3DXLoadSkinMeshFromXofTest();
11383     D3DXCreateBoxTest();
11384     D3DXCreatePolygonTest();
11385     D3DXCreateSphereTest();
11386     D3DXCreateCylinderTest();
11387     D3DXCreateTextTest();
11388     D3DXCreateTorusTest();
11389     D3DXCreateAnimationControllerTest();
11390     test_get_decl_length();
11391     test_get_decl_vertex_size();
11392     test_fvf_decl_conversion();
11393     D3DXGenerateAdjacencyTest();
11394     test_update_semantics();
11395     test_create_skin_info();
11396     test_convert_adjacency_to_point_reps();
11397     test_convert_point_reps_to_adjacency();
11398     test_weld_vertices();
11399     test_clone_mesh();
11400     test_valid_mesh();
11401     test_optimize_vertices();
11402     test_optimize_faces();
11403     test_compute_normals();
11404     test_D3DXFrameFind();
11405 }
11406