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_update_skinned_mesh(void)
5320 {
5321     static DWORD bone0_vertices[2] = { 1, 3 };
5322     static FLOAT bone0_weights[2] = { 1.0f, 0.5f };
5323     static DWORD bone1_vertices[2] = { 2, 3 };
5324     static FLOAT bone1_weights[2] = { 1.0f, 0.5f };
5325     static D3DMATRIX bones_matrix[2] =
5326     { { { {
5327                1.0f,  0.0f,  0.0f,  0.0f,
5328                0.0f,  1.0f,  0.0f,  0.0f,
5329                0.0f,  0.0f,  1.0f,  0.0f,
5330                2.0f,  2.0f,  4.0f,  1.0f
5331       } } },
5332       { { {
5333                1.0f,  0.0f,  0.0f,  0.0f,
5334                0.0f,  1.0f,  0.0f,  0.0f,
5335                0.0f,  0.0f,  1.0f,  0.0f,
5336               -4.0f, -4.0f,  4.0f,  1.0f
5337       } } } };
5338     static D3DVECTOR vertices_src[] = {{  1.0f,  1.0f,  1.0f },
5339                                        {  1.0f,  0.0f,  0.0f },
5340                                        {  1.0f,  1.0f, -1.0f },
5341                                        {  0.0f,  1.0f,  0.0f },
5342                                        { -1.0f, -1.0f,  1.0f },
5343                                        {  0.0f,  0.0f,  1.0f },
5344                                        { -1.0f, -1.0f, -1.0f },
5345                                        { -1.0f,  0.0f,  0.0f },
5346                                       };
5347     static D3DVECTOR vertices_ref[] = {{  0.0f,  0.0f,  0.0f },
5348                                        {  0.0f,  0.0f,  0.0f },
5349                                        {  3.0f,  3.0f,  3.0f },
5350                                        {  0.0f,  1.0f,  0.0f },
5351                                        { -5.0f, -5.0f,  5.0f },
5352                                        {  0.0f,  0.0f,  1.0f },
5353                                        { -2.0f, -2.0f,  3.0f },
5354                                        { -1.0f,  0.0f,  0.0f },
5355                                       };
5356     D3DVECTOR vertices_dest[8];
5357     HRESULT hr;
5358     ID3DXSkinInfo *skin_info;
5359     D3DXMATRIX matrix;
5360     int i;
5361 
5362     D3DXMatrixIdentity(&matrix);
5363     for (i = 0; i < 8; i++)
5364     {
5365         vertices_dest[i].x = 10000.0f;
5366         vertices_dest[i].y = 10000.0f;
5367         vertices_dest[i].z = 10000.0f;
5368     }
5369 
5370     hr = D3DXCreateSkinInfoFVF(4, D3DFVF_XYZ | D3DFVF_NORMAL, 2, &skin_info);
5371     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5372 
5373     skin_info->lpVtbl->SetBoneInfluence(skin_info, 0, 2, bone0_vertices, bone0_weights);
5374     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5375     skin_info->lpVtbl->SetBoneOffsetMatrix(skin_info, 0, &matrix);
5376     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5377     skin_info->lpVtbl->SetBoneInfluence(skin_info, 1, 2, bone1_vertices, bone1_weights);
5378     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5379     skin_info->lpVtbl->SetBoneOffsetMatrix(skin_info, 1, &matrix);
5380     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5381     skin_info->lpVtbl->UpdateSkinnedMesh(skin_info, bones_matrix, NULL, vertices_src, vertices_dest);
5382     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5383     for (i = 0; i < 4; i++)
5384     {
5385         ok(compare(vertices_dest[i*2].x, vertices_ref[i*2].x), "Vertex[%d].position.x: got %g, expected %g\n",
5386            i, vertices_dest[i*2].x, vertices_ref[i*2].x);
5387         ok(compare(vertices_dest[i*2].y, vertices_ref[i*2].y), "Vertex[%d].position.y: got %g, expected %g\n",
5388            i, vertices_dest[i*2].y, vertices_ref[i*2].y);
5389         ok(compare(vertices_dest[i*2].z, vertices_ref[i*2].z), "Vertex[%d].position.z: got %g, expected %g\n",
5390            i, vertices_dest[i*2].z, vertices_ref[i*2].z);
5391         ok(compare(vertices_dest[i*2+1].x, vertices_ref[i*2+1].x), "Vertex[%d].normal.x: got %g, expected %g\n",
5392            i, vertices_dest[i*2+1].x, vertices_ref[i*2+1].x);
5393         ok(compare(vertices_dest[i*2+1].y, vertices_ref[i*2+1].y), "Vertex[%d].normal.y: got %g, expected %g\n",
5394            i, vertices_dest[i*2+1].y, vertices_ref[i*2+1].y);
5395         ok(compare(vertices_dest[i*2+1].z, vertices_ref[i*2+1].z), "Vertex[%d].normal.z: got %g, expected %g\n",
5396            i, vertices_dest[i*2+1].z, vertices_ref[i*2+1].z);
5397     }
5398     skin_info->lpVtbl->Release(skin_info);
5399 }
5400 
5401 static void test_convert_adjacency_to_point_reps(void)
5402 {
5403     HRESULT hr;
5404     struct test_context *test_context = NULL;
5405     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5406     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5407     const D3DVERTEXELEMENT9 declaration[] =
5408     {
5409         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5410         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5411         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5412         D3DDECL_END()
5413     };
5414     const unsigned int VERTS_PER_FACE = 3;
5415     void *vertex_buffer;
5416     void *index_buffer;
5417     DWORD *attributes_buffer;
5418     int i, j;
5419     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5420     struct vertex_pnc
5421     {
5422         D3DXVECTOR3 position;
5423         D3DXVECTOR3 normal;
5424         enum color color; /* In case of manual visual inspection */
5425     };
5426 #ifndef __REACTOS__
5427     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5428 #else
5429 #define up {0.0f, 0.0f, 1.0f}
5430 #endif
5431     /* mesh0 (one face)
5432      *
5433      * 0--1
5434      * | /
5435      * |/
5436      * 2
5437      */
5438     const struct vertex_pnc vertices0[] =
5439     {
5440         {{ 0.0f,  3.0f,  0.f}, up, RED},
5441         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5442         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5443     };
5444     const DWORD indices0[] = {0, 1, 2};
5445     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5446     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
5447     const DWORD adjacency0[] = {-1, -1, -1};
5448     const DWORD exp_point_rep0[] = {0, 1, 2};
5449     /* mesh1 (right)
5450      *
5451      * 0--1 3
5452      * | / /|
5453      * |/ / |
5454      * 2 5--4
5455      */
5456     const struct vertex_pnc vertices1[] =
5457     {
5458         {{ 0.0f,  3.0f,  0.f}, up, RED},
5459         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5460         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5461 
5462         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5463         {{ 3.0f,  0.0f,  0.f}, up, RED},
5464         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5465     };
5466     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5467     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5468     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
5469     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
5470     const DWORD exp_point_rep1[] = {0, 1, 2, 1, 4, 2};
5471     /* mesh2 (left)
5472      *
5473      *    3 0--1
5474      *   /| | /
5475      *  / | |/
5476      * 5--4 2
5477      */
5478     const struct vertex_pnc vertices2[] =
5479     {
5480         {{ 0.0f,  3.0f,  0.f}, up, RED},
5481         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5482         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5483 
5484         {{-1.0f,  3.0f,  0.f}, up, RED},
5485         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5486         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5487     };
5488     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5489     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5490     const unsigned int num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
5491     const DWORD adjacency2[] = {-1, -1, 1, 0, -1, -1};
5492     const DWORD exp_point_rep2[] = {0, 1, 2, 0, 2, 5};
5493     /* mesh3 (above)
5494      *
5495      *    3
5496      *   /|
5497      *  / |
5498      * 5--4
5499      * 0--1
5500      * | /
5501      * |/
5502      * 2
5503      */
5504     struct vertex_pnc vertices3[] =
5505     {
5506         {{ 0.0f,  3.0f,  0.f}, up, RED},
5507         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5508         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5509 
5510         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5511         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5512         {{ 0.0f,  4.0f,  0.f}, up, RED},
5513     };
5514     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5515     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5516     const unsigned int num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
5517     const DWORD adjacency3[] = {1, -1, -1, -1, 0, -1};
5518     const DWORD exp_point_rep3[] = {0, 1, 2, 3, 1, 0};
5519     /* mesh4 (below, tip against tip)
5520      *
5521      * 0--1
5522      * | /
5523      * |/
5524      * 2
5525      * 3
5526      * |\
5527      * | \
5528      * 5--4
5529      */
5530     struct vertex_pnc vertices4[] =
5531     {
5532         {{ 0.0f,  3.0f,  0.f}, up, RED},
5533         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5534         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5535 
5536         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5537         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5538         {{ 0.0f, -7.0f,  0.f}, up, RED},
5539     };
5540     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5541     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5542     const unsigned int num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
5543     const DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
5544     const DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
5545     /* mesh5 (gap in mesh)
5546      *
5547      *    0      3-----4  15
5548      *   / \      \   /  /  \
5549      *  /   \      \ /  /    \
5550      * 2-----1      5 17-----16
5551      * 6-----7      9 12-----13
5552      *  \   /      / \  \    /
5553      *   \ /      /   \  \  /
5554      *    8     10-----11 14
5555      *
5556      */
5557     const struct vertex_pnc vertices5[] =
5558     {
5559         {{ 0.0f,  1.0f,  0.f}, up, RED},
5560         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5561         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5562 
5563         {{ 0.1f,  1.0f,  0.f}, up, RED},
5564         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5565         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5566 
5567         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5568         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5569         {{ 0.0f, -3.1f,  0.f}, up, RED},
5570 
5571         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5572         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5573         {{ 0.1f, -3.1f,  0.f}, up, RED},
5574 
5575         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5576         {{ 3.2f, -1.1f,  0.f}, up, RED},
5577         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5578 
5579         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5580         {{ 3.2f, -1.0f,  0.f}, up, RED},
5581         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5582     };
5583     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5584     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5585     const unsigned int num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
5586     const DWORD adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5587     const DWORD exp_point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5588     const WORD indices5_16bit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5589     /* mesh6 (indices re-ordering)
5590      *
5591      * 0--1 6 3
5592      * | / /| |\
5593      * |/ / | | \
5594      * 2 8--7 5--4
5595      */
5596     const struct vertex_pnc vertices6[] =
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         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5603         {{ 3.0f,  0.0f,  0.f}, up, RED},
5604         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5605 
5606         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5607         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5608         {{ 4.0f,  0.0f,  0.f}, up, RED},
5609     };
5610     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5611     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5612     const unsigned int num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
5613     const DWORD adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5614     const DWORD exp_point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5615     /* mesh7 (expands collapsed triangle)
5616      *
5617      * 0--1 3
5618      * | / /|
5619      * |/ / |
5620      * 2 5--4
5621      */
5622     const struct vertex_pnc vertices7[] =
5623     {
5624         {{ 0.0f,  3.0f,  0.f}, up, RED},
5625         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5626         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5627 
5628         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5629         {{ 3.0f,  0.0f,  0.f}, up, RED},
5630         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5631     };
5632     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5633     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5634     const unsigned int num_faces7 = ARRAY_SIZE(indices7) / VERTS_PER_FACE;
5635     const DWORD adjacency7[] = {-1, -1, -1, -1, -1, -1};
5636     const DWORD exp_point_rep7[] = {0, 1, 2, 3, 4, 5};
5637     /* mesh8 (indices re-ordering and double replacement)
5638      *
5639      * 0--1 9  6
5640      * | / /|  |\
5641      * |/ / |  | \
5642      * 2 11-10 8--7
5643      *         3--4
5644      *         | /
5645      *         |/
5646      *         5
5647      */
5648     const struct vertex_pnc vertices8[] =
5649     {
5650         {{ 0.0f,  3.0f,  0.f}, up, RED},
5651         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5652         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5653 
5654         {{ 4.0,  -4.0,  0.f}, up, RED},
5655         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5656         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5657 
5658         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5659         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5660         {{ 4.0f,  0.0f,  0.f}, up, RED},
5661 
5662         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5663         {{ 3.0f,  0.0f,  0.f}, up, RED},
5664         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5665     };
5666     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5667     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5668     const unsigned int num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
5669     const DWORD adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5670     const DWORD exp_point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5671     /* mesh9 (right, shared vertices)
5672      *
5673      * 0--1
5674      * | /|
5675      * |/ |
5676      * 2--3
5677      */
5678     const struct vertex_pnc vertices9[] =
5679     {
5680         {{ 0.0f,  3.0f,  0.f}, up, RED},
5681         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5682         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5683 
5684         {{ 2.0f,  0.0f,  0.f}, up, RED},
5685     };
5686     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5687     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5688     const unsigned int num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
5689     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
5690     const DWORD exp_point_rep9[] = {0, 1, 2, 3};
5691     /* All mesh data */
5692     ID3DXMesh *mesh = NULL;
5693     ID3DXMesh *mesh_null_check = NULL;
5694     unsigned int attributes[] = {0};
5695     struct
5696     {
5697         const struct vertex_pnc *vertices;
5698         const DWORD *indices;
5699         const DWORD num_vertices;
5700         const DWORD num_faces;
5701         const DWORD *adjacency;
5702         const DWORD *exp_point_reps;
5703         const DWORD options;
5704     }
5705     tc[] =
5706     {
5707         {
5708             vertices0,
5709             indices0,
5710             num_vertices0,
5711             num_faces0,
5712             adjacency0,
5713             exp_point_rep0,
5714             options
5715         },
5716         {
5717             vertices1,
5718             indices1,
5719             num_vertices1,
5720             num_faces1,
5721             adjacency1,
5722             exp_point_rep1,
5723             options
5724         },
5725         {
5726             vertices2,
5727             indices2,
5728             num_vertices2,
5729             num_faces2,
5730             adjacency2,
5731             exp_point_rep2,
5732             options
5733         },
5734         {
5735             vertices3,
5736             indices3,
5737             num_vertices3,
5738             num_faces3,
5739             adjacency3,
5740             exp_point_rep3,
5741             options
5742         },
5743         {
5744             vertices4,
5745             indices4,
5746             num_vertices4,
5747             num_faces4,
5748             adjacency4,
5749             exp_point_rep4,
5750             options
5751         },
5752         {
5753             vertices5,
5754             indices5,
5755             num_vertices5,
5756             num_faces5,
5757             adjacency5,
5758             exp_point_rep5,
5759             options
5760         },
5761         {
5762             vertices6,
5763             indices6,
5764             num_vertices6,
5765             num_faces6,
5766             adjacency6,
5767             exp_point_rep6,
5768             options
5769         },
5770         {
5771             vertices7,
5772             indices7,
5773             num_vertices7,
5774             num_faces7,
5775             adjacency7,
5776             exp_point_rep7,
5777             options
5778         },
5779         {
5780             vertices8,
5781             indices8,
5782             num_vertices8,
5783             num_faces8,
5784             adjacency8,
5785             exp_point_rep8,
5786             options
5787         },
5788         {
5789             vertices9,
5790             indices9,
5791             num_vertices9,
5792             num_faces9,
5793             adjacency9,
5794             exp_point_rep9,
5795             options
5796         },
5797         {
5798             vertices5,
5799             (DWORD*)indices5_16bit,
5800             num_vertices5,
5801             num_faces5,
5802             adjacency5,
5803             exp_point_rep5,
5804             options_16bit
5805         },
5806     };
5807     DWORD *point_reps = NULL;
5808 
5809     test_context = new_test_context();
5810     if (!test_context)
5811     {
5812         skip("Couldn't create test context\n");
5813         goto cleanup;
5814     }
5815 
5816     for (i = 0; i < ARRAY_SIZE(tc); i++)
5817     {
5818         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options, declaration,
5819                             test_context->device, &mesh);
5820         if (FAILED(hr))
5821         {
5822             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5823             goto cleanup;
5824         }
5825 
5826         if (i == 0) /* Save first mesh for later NULL checks */
5827             mesh_null_check = mesh;
5828 
5829         point_reps = HeapAlloc(GetProcessHeap(), 0, tc[i].num_vertices * sizeof(*point_reps));
5830         if (!point_reps)
5831         {
5832             skip("Couldn't allocate point reps array.\n");
5833             goto cleanup;
5834         }
5835 
5836         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5837         if (FAILED(hr))
5838         {
5839             skip("Couldn't lock vertex buffer.\n");
5840             goto cleanup;
5841         }
5842         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5843         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5844         if (FAILED(hr))
5845         {
5846             skip("Couldn't unlock vertex buffer.\n");
5847             goto cleanup;
5848         }
5849 
5850         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5851         if (FAILED(hr))
5852         {
5853             skip("Couldn't lock index buffer.\n");
5854             goto cleanup;
5855         }
5856         if (tc[i].options & D3DXMESH_32BIT)
5857         {
5858             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5859         }
5860         else
5861         {
5862             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5863         }
5864         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5865         if (FAILED(hr)) {
5866             skip("Couldn't unlock index buffer.\n");
5867             goto cleanup;
5868         }
5869 
5870         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5871         if (FAILED(hr))
5872         {
5873             skip("Couldn't lock attributes buffer.\n");
5874             goto cleanup;
5875         }
5876         memcpy(attributes_buffer, attributes, sizeof(attributes));
5877         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5878         if (FAILED(hr))
5879         {
5880             skip("Couldn't unlock attributes buffer.\n");
5881             goto cleanup;
5882         }
5883 
5884         /* Convert adjacency to point representation */
5885         for (j = 0; j < tc[i].num_vertices; j++) point_reps[j] = -1;
5886         hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacency, point_reps);
5887         ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
5888            "Got %x expected D3D_OK\n", i, hr);
5889 
5890         /* Check point representation */
5891         for (j = 0; j < tc[i].num_vertices; j++)
5892         {
5893             ok(point_reps[j] == tc[i].exp_point_reps[j],
5894                "Unexpected point representation at (%d, %d)."
5895                " Got %d expected %d\n",
5896                i, j, point_reps[j], tc[i].exp_point_reps[j]);
5897         }
5898 
5899         HeapFree(GetProcessHeap(), 0, point_reps);
5900         point_reps = NULL;
5901 
5902         if (i != 0) /* First mesh will be freed during cleanup */
5903             mesh->lpVtbl->Release(mesh);
5904     }
5905 
5906     /* NULL checks */
5907     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacency, NULL);
5908     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
5909        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5910     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, NULL);
5911     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. "
5912        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5913 
5914 cleanup:
5915     if (mesh_null_check)
5916         mesh_null_check->lpVtbl->Release(mesh_null_check);
5917     HeapFree(GetProcessHeap(), 0, point_reps);
5918     free_test_context(test_context);
5919 #ifdef __REACTOS__
5920 #undef up
5921 #endif
5922 }
5923 
5924 static void test_convert_point_reps_to_adjacency(void)
5925 {
5926     HRESULT hr;
5927     struct test_context *test_context = NULL;
5928     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5929     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5930     const D3DVERTEXELEMENT9 declaration[] =
5931     {
5932         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5933         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5934         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5935         D3DDECL_END()
5936     };
5937     const unsigned int VERTS_PER_FACE = 3;
5938     void *vertex_buffer;
5939     void *index_buffer;
5940     DWORD *attributes_buffer;
5941     int i, j;
5942     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5943     struct vertex_pnc
5944     {
5945         D3DXVECTOR3 position;
5946         D3DXVECTOR3 normal;
5947         enum color color; /* In case of manual visual inspection */
5948     };
5949 #ifndef __REACTOS__
5950     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5951 #else
5952 #define up {0.0f, 0.0f, 1.0f}
5953 #endif
5954 
5955     /* mesh0 (one face)
5956      *
5957      * 0--1
5958      * | /
5959      * |/
5960      * 2
5961      */
5962     const struct vertex_pnc vertices0[] =
5963     {
5964         {{ 0.0f,  3.0f,  0.f}, up, RED},
5965         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5966         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5967     };
5968     const DWORD indices0[] = {0, 1, 2};
5969     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5970     const unsigned int num_faces0 = num_vertices0 / VERTS_PER_FACE;
5971     const DWORD exp_adjacency0[] = {-1, -1, -1};
5972     const DWORD exp_id_adjacency0[] = {-1, -1, -1};
5973     const DWORD point_rep0[] = {0, 1, 2};
5974     /* mesh1 (right)
5975      *
5976      * 0--1 3
5977      * | / /|
5978      * |/ / |
5979      * 2 5--4
5980      */
5981     const struct vertex_pnc vertices1[] =
5982     {
5983         {{ 0.0f,  3.0f,  0.f}, up, RED},
5984         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5985         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5986 
5987         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5988         {{ 3.0f,  0.0f,  0.f}, up, RED},
5989         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5990     };
5991     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5992     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5993     const unsigned int num_faces1 = num_vertices1 / VERTS_PER_FACE;
5994     const DWORD exp_adjacency1[] = {-1, 1, -1, -1, -1, 0};
5995     const DWORD exp_id_adjacency1[] = {-1, -1, -1, -1, -1, -1};
5996     const DWORD point_rep1[] = {0, 1, 2, 1, 4, 2};
5997     /* mesh2 (left)
5998      *
5999      *    3 0--1
6000      *   /| | /
6001      *  / | |/
6002      * 5--4 2
6003      */
6004     const struct vertex_pnc vertices2[] =
6005     {
6006         {{ 0.0f,  3.0f,  0.f}, up, RED},
6007         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6008         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6009 
6010         {{-1.0f,  3.0f,  0.f}, up, RED},
6011         {{-1.0f,  0.0f,  0.f}, up, GREEN},
6012         {{-3.0f,  0.0f,  0.f}, up, BLUE},
6013     };
6014     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
6015     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
6016     const unsigned int num_faces2 = num_vertices2 / VERTS_PER_FACE;
6017     const DWORD exp_adjacency2[] = {-1, -1, 1, 0, -1, -1};
6018     const DWORD exp_id_adjacency2[] = {-1, -1, -1, -1, -1, -1};
6019     const DWORD point_rep2[] = {0, 1, 2, 0, 2, 5};
6020     /* mesh3 (above)
6021      *
6022      *    3
6023      *   /|
6024      *  / |
6025      * 5--4
6026      * 0--1
6027      * | /
6028      * |/
6029      * 2
6030      */
6031     struct vertex_pnc vertices3[] =
6032     {
6033         {{ 0.0f,  3.0f,  0.f}, up, RED},
6034         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6035         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6036 
6037         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
6038         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
6039         {{ 0.0f,  4.0f,  0.f}, up, RED},
6040     };
6041     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
6042     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
6043     const unsigned int num_faces3 = num_vertices3 / VERTS_PER_FACE;
6044     const DWORD exp_adjacency3[] = {1, -1, -1, -1, 0, -1};
6045     const DWORD exp_id_adjacency3[] = {-1, -1, -1, -1, -1, -1};
6046     const DWORD point_rep3[] = {0, 1, 2, 3, 1, 0};
6047     /* mesh4 (below, tip against tip)
6048      *
6049      * 0--1
6050      * | /
6051      * |/
6052      * 2
6053      * 3
6054      * |\
6055      * | \
6056      * 5--4
6057      */
6058     struct vertex_pnc vertices4[] =
6059     {
6060         {{ 0.0f,  3.0f,  0.f}, up, RED},
6061         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6062         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6063 
6064         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
6065         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
6066         {{ 0.0f, -7.0f,  0.f}, up, RED},
6067     };
6068     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
6069     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
6070     const unsigned int num_faces4 = num_vertices4 / VERTS_PER_FACE;
6071     const DWORD exp_adjacency4[] = {-1, -1, -1, -1, -1, -1};
6072     const DWORD exp_id_adjacency4[] = {-1, -1, -1, -1, -1, -1};
6073     const DWORD point_rep4[] = {0, 1, 2, 3, 4, 5};
6074     /* mesh5 (gap in mesh)
6075      *
6076      *    0      3-----4  15
6077      *   / \      \   /  /  \
6078      *  /   \      \ /  /    \
6079      * 2-----1      5 17-----16
6080      * 6-----7      9 12-----13
6081      *  \   /      / \  \    /
6082      *   \ /      /   \  \  /
6083      *    8     10-----11 14
6084      *
6085      */
6086     const struct vertex_pnc vertices5[] =
6087     {
6088         {{ 0.0f,  1.0f,  0.f}, up, RED},
6089         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
6090         {{-1.0f, -1.0f,  0.f}, up, BLUE},
6091 
6092         {{ 0.1f,  1.0f,  0.f}, up, RED},
6093         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
6094         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
6095 
6096         {{-1.0f, -1.1f,  0.f}, up, BLUE},
6097         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
6098         {{ 0.0f, -3.1f,  0.f}, up, RED},
6099 
6100         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
6101         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
6102         {{ 0.1f, -3.1f,  0.f}, up, RED},
6103 
6104         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
6105         {{ 3.2f, -1.1f,  0.f}, up, RED},
6106         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
6107 
6108         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
6109         {{ 3.2f, -1.0f,  0.f}, up, RED},
6110         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
6111     };
6112     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
6113     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
6114     const unsigned int num_faces5 = num_vertices5 / VERTS_PER_FACE;
6115     const DWORD exp_adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
6116     const DWORD exp_id_adjacency5[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
6117     const DWORD point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
6118     /* mesh6 (indices re-ordering)
6119      *
6120      * 0--1 6 3
6121      * | / /| |\
6122      * |/ / | | \
6123      * 2 8--7 5--4
6124      */
6125     const struct vertex_pnc vertices6[] =
6126     {
6127         {{ 0.0f,  3.0f,  0.f}, up, RED},
6128         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6129         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6130 
6131         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
6132         {{ 3.0f,  0.0f,  0.f}, up, RED},
6133         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
6134 
6135         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
6136         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
6137         {{ 4.0f,  0.0f,  0.f}, up, RED},
6138     };
6139     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
6140     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
6141     const unsigned int num_faces6 = num_vertices6 / VERTS_PER_FACE;
6142     const DWORD exp_adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
6143     const DWORD exp_id_adjacency6[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1};
6144     const DWORD point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
6145     /* mesh7 (expands collapsed triangle)
6146      *
6147      * 0--1 3
6148      * | / /|
6149      * |/ / |
6150      * 2 5--4
6151      */
6152     const struct vertex_pnc vertices7[] =
6153     {
6154         {{ 0.0f,  3.0f,  0.f}, up, RED},
6155         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6156         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6157 
6158         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
6159         {{ 3.0f,  0.0f,  0.f}, up, RED},
6160         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
6161     };
6162     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
6163     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
6164     const unsigned int num_faces7 = num_vertices7 / VERTS_PER_FACE;
6165     const DWORD exp_adjacency7[] = {-1, -1, -1, -1, -1, -1};
6166     const DWORD exp_id_adjacency7[] = {-1, -1, -1, -1, -1, -1};
6167     const DWORD point_rep7[] = {0, 1, 2, 3, 4, 5};
6168     /* mesh8 (indices re-ordering and double replacement)
6169      *
6170      * 0--1 9  6
6171      * | / /|  |\
6172      * |/ / |  | \
6173      * 2 11-10 8--7
6174      *         3--4
6175      *         | /
6176      *         |/
6177      *         5
6178      */
6179     const struct vertex_pnc vertices8[] =
6180     {
6181         {{ 0.0f,  3.0f,  0.f}, up, RED},
6182         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6183         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6184 
6185         {{ 4.0,  -4.0,  0.f}, up, RED},
6186         {{ 6.0,  -4.0,  0.f}, up, BLUE},
6187         {{ 4.0,  -7.0,  0.f}, up, GREEN},
6188 
6189         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
6190         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
6191         {{ 4.0f,  0.0f,  0.f}, up, RED},
6192 
6193         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
6194         {{ 3.0f,  0.0f,  0.f}, up, RED},
6195         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
6196     };
6197     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
6198     const WORD indices8_16bit[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
6199     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
6200     const unsigned int num_faces8 = num_vertices8 / VERTS_PER_FACE;
6201     const DWORD exp_adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
6202     const DWORD exp_id_adjacency8[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
6203     const DWORD point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
6204      /* mesh9 (right, shared vertices)
6205      *
6206      * 0--1
6207      * | /|
6208      * |/ |
6209      * 2--3
6210      */
6211     const struct vertex_pnc vertices9[] =
6212     {
6213         {{ 0.0f,  3.0f,  0.f}, up, RED},
6214         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6215         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6216 
6217         {{ 2.0f,  0.0f,  0.f}, up, RED},
6218     };
6219     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
6220     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
6221     const unsigned int num_faces9 = 2;
6222     const DWORD exp_adjacency9[] = {-1, 1, -1, -1, -1, 0};
6223     const DWORD exp_id_adjacency9[] = {-1, 1, -1, -1, -1, 0};
6224     const DWORD point_rep9[] = {0, 1, 2, 3};
6225     /* All mesh data */
6226     ID3DXMesh *mesh = NULL;
6227     ID3DXMesh *mesh_null_check = NULL;
6228     unsigned int attributes[] = {0};
6229     struct
6230     {
6231         const struct vertex_pnc *vertices;
6232         const DWORD *indices;
6233         const DWORD num_vertices;
6234         const DWORD num_faces;
6235         const DWORD *point_reps;
6236         const DWORD *exp_adjacency;
6237         const DWORD *exp_id_adjacency;
6238         const DWORD options;
6239     }
6240     tc[] =
6241     {
6242         {
6243             vertices0,
6244             indices0,
6245             num_vertices0,
6246             num_faces0,
6247             point_rep0,
6248             exp_adjacency0,
6249             exp_id_adjacency0,
6250             options
6251         },
6252         {
6253             vertices1,
6254             indices1,
6255             num_vertices1,
6256             num_faces1,
6257             point_rep1,
6258             exp_adjacency1,
6259             exp_id_adjacency1,
6260             options
6261         },
6262         {
6263             vertices2,
6264             indices2,
6265             num_vertices2,
6266             num_faces2,
6267             point_rep2,
6268             exp_adjacency2,
6269             exp_id_adjacency2,
6270             options
6271         },
6272         {
6273             vertices3,
6274             indices3,
6275             num_vertices3,
6276             num_faces3,
6277             point_rep3,
6278             exp_adjacency3,
6279             exp_id_adjacency3,
6280             options
6281         },
6282         {
6283             vertices4,
6284             indices4,
6285             num_vertices4,
6286             num_faces4,
6287             point_rep4,
6288             exp_adjacency4,
6289             exp_id_adjacency4,
6290             options
6291         },
6292         {
6293             vertices5,
6294             indices5,
6295             num_vertices5,
6296             num_faces5,
6297             point_rep5,
6298             exp_adjacency5,
6299             exp_id_adjacency5,
6300             options
6301         },
6302         {
6303             vertices6,
6304             indices6,
6305             num_vertices6,
6306             num_faces6,
6307             point_rep6,
6308             exp_adjacency6,
6309             exp_id_adjacency6,
6310             options
6311         },
6312         {
6313             vertices7,
6314             indices7,
6315             num_vertices7,
6316             num_faces7,
6317             point_rep7,
6318             exp_adjacency7,
6319             exp_id_adjacency7,
6320             options
6321         },
6322         {
6323             vertices8,
6324             indices8,
6325             num_vertices8,
6326             num_faces8,
6327             point_rep8,
6328             exp_adjacency8,
6329             exp_id_adjacency8,
6330             options
6331         },
6332         {
6333             vertices9,
6334             indices9,
6335             num_vertices9,
6336             num_faces9,
6337             point_rep9,
6338             exp_adjacency9,
6339             exp_id_adjacency9,
6340             options
6341         },
6342         {
6343             vertices8,
6344             (DWORD*)indices8_16bit,
6345             num_vertices8,
6346             num_faces8,
6347             point_rep8,
6348             exp_adjacency8,
6349             exp_id_adjacency8,
6350             options_16bit
6351         },
6352     };
6353     DWORD *adjacency = NULL;
6354 #ifdef __REACTOS__
6355 #undef up
6356 #endif
6357 
6358     test_context = new_test_context();
6359     if (!test_context)
6360     {
6361         skip("Couldn't create test context\n");
6362         goto cleanup;
6363     }
6364 
6365     for (i = 0; i < ARRAY_SIZE(tc); i++)
6366     {
6367         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
6368                             declaration, test_context->device, &mesh);
6369         if (FAILED(hr))
6370         {
6371             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
6372             goto cleanup;
6373         }
6374 
6375         if (i == 0) /* Save first mesh for later NULL checks */
6376             mesh_null_check = mesh;
6377 
6378         adjacency = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
6379         if (!adjacency)
6380         {
6381             skip("Couldn't allocate adjacency array.\n");
6382             goto cleanup;
6383         }
6384 
6385         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
6386         if (FAILED(hr))
6387         {
6388             skip("Couldn't lock vertex buffer.\n");
6389             goto cleanup;
6390         }
6391         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
6392         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6393         if (FAILED(hr))
6394         {
6395             skip("Couldn't unlock vertex buffer.\n");
6396             goto cleanup;
6397         }
6398         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6399         if (FAILED(hr))
6400         {
6401             skip("Couldn't lock index buffer.\n");
6402             goto cleanup;
6403         }
6404         if (tc[i].options & D3DXMESH_32BIT)
6405         {
6406             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
6407         }
6408         else
6409         {
6410             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
6411         }
6412         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6413         if (FAILED(hr)) {
6414             skip("Couldn't unlock index buffer.\n");
6415             goto cleanup;
6416         }
6417 
6418         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6419         if (FAILED(hr))
6420         {
6421             skip("Couldn't lock attributes buffer.\n");
6422             goto cleanup;
6423         }
6424         memcpy(attributes_buffer, attributes, sizeof(attributes));
6425         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6426         if (FAILED(hr))
6427         {
6428             skip("Couldn't unlock attributes buffer.\n");
6429             goto cleanup;
6430         }
6431 
6432         /* Convert point representation to adjacency*/
6433         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
6434 
6435         hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
6436         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
6437            "Got %x expected D3D_OK\n", i, hr);
6438         /* Check adjacency */
6439         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
6440         {
6441             ok(adjacency[j] == tc[i].exp_adjacency[j],
6442                "Unexpected adjacency information at (%d, %d)."
6443                " Got %d expected %d\n",
6444                i, j, adjacency[j], tc[i].exp_adjacency[j]);
6445         }
6446 
6447         /* NULL point representation is considered identity. */
6448         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
6449         hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
6450         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
6451                      "Got %x expected D3D_OK\n", hr);
6452         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
6453         {
6454             ok(adjacency[j] == tc[i].exp_id_adjacency[j],
6455                "Unexpected adjacency information (id) at (%d, %d)."
6456                " Got %d expected %d\n",
6457                i, j, adjacency[j], tc[i].exp_id_adjacency[j]);
6458         }
6459 
6460         HeapFree(GetProcessHeap(), 0, adjacency);
6461         adjacency = NULL;
6462         if (i != 0) /* First mesh will be freed during cleanup */
6463             mesh->lpVtbl->Release(mesh);
6464     }
6465 
6466     /* NULL checks */
6467     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
6468     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
6469        "Got %x expected D3DERR_INVALIDCALL\n", hr);
6470     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
6471     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
6472        "Got %x expected D3DERR_INVALIDCALL\n", hr);
6473 
6474 cleanup:
6475     if (mesh_null_check)
6476         mesh_null_check->lpVtbl->Release(mesh_null_check);
6477     HeapFree(GetProcessHeap(), 0, adjacency);
6478     free_test_context(test_context);
6479 }
6480 
6481 static HRESULT init_test_mesh(const DWORD num_faces, const DWORD num_vertices,
6482                               const DWORD options,
6483                               const D3DVERTEXELEMENT9 *declaration,
6484                               IDirect3DDevice9 *device, ID3DXMesh **mesh_ptr,
6485                               const void *vertices, const DWORD vertex_size,
6486                               const DWORD *indices, const DWORD *attributes)
6487 {
6488     HRESULT hr;
6489     void *vertex_buffer;
6490     void *index_buffer;
6491     DWORD *attributes_buffer;
6492     ID3DXMesh *mesh = NULL;
6493 
6494     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration, device, mesh_ptr);
6495     if (FAILED(hr))
6496     {
6497         skip("Couldn't create mesh. Got %x expected D3D_OK\n", hr);
6498         goto cleanup;
6499     }
6500     mesh = *mesh_ptr;
6501 
6502     hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
6503     if (FAILED(hr))
6504     {
6505         skip("Couldn't lock vertex buffer.\n");
6506         goto cleanup;
6507     }
6508     memcpy(vertex_buffer, vertices, num_vertices * vertex_size);
6509     hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6510     if (FAILED(hr))
6511     {
6512         skip("Couldn't unlock vertex buffer.\n");
6513         goto cleanup;
6514     }
6515 
6516     hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6517     if (FAILED(hr))
6518     {
6519         skip("Couldn't lock index buffer.\n");
6520         goto cleanup;
6521     }
6522     if (options & D3DXMESH_32BIT)
6523     {
6524         if (indices)
6525             memcpy(index_buffer, indices, 3 * num_faces * sizeof(DWORD));
6526         else
6527         {
6528             /* Fill index buffer with 0, 1, 2, ...*/
6529             DWORD *indices_32bit = (DWORD*)index_buffer;
6530             UINT i;
6531             for (i = 0; i < 3 * num_faces; i++)
6532                 indices_32bit[i] = i;
6533         }
6534     }
6535     else
6536     {
6537         if (indices)
6538             memcpy(index_buffer, indices, 3 * num_faces * sizeof(WORD));
6539         else
6540         {
6541             /* Fill index buffer with 0, 1, 2, ...*/
6542             WORD *indices_16bit = (WORD*)index_buffer;
6543             UINT i;
6544             for (i = 0; i < 3 * num_faces; i++)
6545                 indices_16bit[i] = i;
6546         }
6547     }
6548     hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6549     if (FAILED(hr)) {
6550         skip("Couldn't unlock index buffer.\n");
6551         goto cleanup;
6552     }
6553 
6554     hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6555     if (FAILED(hr))
6556     {
6557         skip("Couldn't lock attributes buffer.\n");
6558         goto cleanup;
6559     }
6560 
6561     if (attributes)
6562         memcpy(attributes_buffer, attributes, num_faces * sizeof(*attributes));
6563     else
6564         memset(attributes_buffer, 0, num_faces * sizeof(*attributes));
6565 
6566     hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6567     if (FAILED(hr))
6568     {
6569         skip("Couldn't unlock attributes buffer.\n");
6570         goto cleanup;
6571     }
6572 
6573     hr = D3D_OK;
6574 cleanup:
6575     return hr;
6576 }
6577 
6578 /* Using structs instead of bit-fields in order to avoid compiler issues. */
6579 struct udec3
6580 {
6581     UINT x;
6582     UINT y;
6583     UINT z;
6584     UINT w;
6585 };
6586 
6587 struct dec3n
6588 {
6589     INT x;
6590     INT y;
6591     INT z;
6592     INT w;
6593 };
6594 
6595 static DWORD init_udec3_dword(UINT x, UINT y, UINT z, UINT w)
6596 {
6597     DWORD d = 0;
6598 
6599     d |= x & 0x3ff;
6600     d |= (y << 10) & 0xffc00;
6601     d |= (z << 20) & 0x3ff00000;
6602     d |= (w << 30) & 0xc0000000;
6603 
6604     return d;
6605 }
6606 
6607 static DWORD init_dec3n_dword(INT x, INT y, INT z, INT w)
6608 {
6609     DWORD d = 0;
6610 
6611     d |= x & 0x3ff;
6612     d |= (y << 10) & 0xffc00;
6613     d |= (z << 20) & 0x3ff00000;
6614     d |= (w << 30) & 0xc0000000;
6615 
6616     return d;
6617 }
6618 
6619 static struct udec3 dword_to_udec3(DWORD d)
6620 {
6621     struct udec3 v;
6622 
6623     v.x = d & 0x3ff;
6624     v.y = (d & 0xffc00) >> 10;
6625     v.z = (d & 0x3ff00000) >> 20;
6626     v.w = (d & 0xc0000000) >> 30;
6627 
6628     return v;
6629 }
6630 
6631 static struct dec3n dword_to_dec3n(DWORD d)
6632 {
6633     struct dec3n v;
6634 
6635     v.x = d & 0x3ff;
6636     v.y = (d & 0xffc00) >> 10;
6637     v.z = (d & 0x3ff00000) >> 20;
6638     v.w = (d & 0xc0000000) >> 30;
6639 
6640     return v;
6641 }
6642 
6643 static void check_vertex_components(int line, int mesh_number, int vertex_number, BYTE *got_ptr, const BYTE *exp_ptr, D3DVERTEXELEMENT9 *declaration)
6644 {
6645     const char *usage_strings[] =
6646     {
6647         "position",
6648         "blend weight",
6649         "blend indices",
6650         "normal",
6651         "point size",
6652         "texture coordinates",
6653         "tangent",
6654         "binormal",
6655         "tessellation factor",
6656         "position transformed",
6657         "color",
6658         "fog",
6659         "depth",
6660         "sample"
6661     };
6662     D3DVERTEXELEMENT9 *decl_ptr;
6663     const float PRECISION = 1e-5f;
6664 
6665     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
6666     {
6667         switch (decl_ptr->Type)
6668         {
6669             case D3DDECLTYPE_FLOAT1:
6670             {
6671                 FLOAT *got = (FLOAT*)(got_ptr + decl_ptr->Offset);
6672                 FLOAT *exp = (FLOAT*)(exp_ptr + decl_ptr->Offset);
6673                 FLOAT diff = fabsf(*got - *exp);
6674                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got %f for vertex %d %s, expected %f.\n",
6675                     mesh_number, *got, vertex_number, usage_strings[decl_ptr->Usage], *exp);
6676                 break;
6677             }
6678             case D3DDECLTYPE_FLOAT2:
6679             {
6680                 D3DXVECTOR2 *got = (D3DXVECTOR2*)(got_ptr + decl_ptr->Offset);
6681                 D3DXVECTOR2 *exp = (D3DXVECTOR2*)(exp_ptr + decl_ptr->Offset);
6682                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6683                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f) for vertex %d %s, expected (%f, %f).\n",
6684                     mesh_number, got->x, got->y, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y);
6685                 break;
6686             }
6687             case D3DDECLTYPE_FLOAT3:
6688             {
6689                 D3DXVECTOR3 *got = (D3DXVECTOR3*)(got_ptr + decl_ptr->Offset);
6690                 D3DXVECTOR3 *exp = (D3DXVECTOR3*)(exp_ptr + decl_ptr->Offset);
6691                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6692                 diff = max(diff, fabsf(got->z - exp->z));
6693                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f) for vertex %d %s, expected (%f, %f, %f).\n",
6694                     mesh_number, got->x, got->y, got->z, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y, exp->z);
6695                 break;
6696             }
6697             case D3DDECLTYPE_FLOAT4:
6698             {
6699                 D3DXVECTOR4 *got = (D3DXVECTOR4*)(got_ptr + decl_ptr->Offset);
6700                 D3DXVECTOR4 *exp = (D3DXVECTOR4*)(exp_ptr + decl_ptr->Offset);
6701                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6702                 diff = max(diff, fabsf(got->z - exp->z));
6703                 diff = max(diff, fabsf(got->w - exp->w));
6704                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f, %f) for vertex %d %s, expected (%f, %f, %f, %f).\n",
6705                     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);
6706                 break;
6707             }
6708             case D3DDECLTYPE_D3DCOLOR:
6709             {
6710                 BYTE *got = got_ptr + decl_ptr->Offset;
6711                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6712                 BOOL same_color = got[0] == exp[0] && got[1] == exp[1]
6713                                   && got[2] == exp[2] && got[3] == exp[3];
6714                 const char *color_types[] = {"diffuse", "specular", "undefined color"};
6715                 BYTE usage_index = decl_ptr->UsageIndex;
6716                 if (usage_index > 1) usage_index = 2;
6717                 ok_(__FILE__,line)(same_color, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6718                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, color_types[usage_index], exp[0], exp[1], exp[2], exp[3]);
6719                 break;
6720             }
6721             case D3DDECLTYPE_UBYTE4:
6722             case D3DDECLTYPE_UBYTE4N:
6723             {
6724                 BYTE *got = got_ptr + decl_ptr->Offset;
6725                 const BYTE *exp = 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 (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6729                     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]);
6730                 break;
6731             }
6732             case D3DDECLTYPE_SHORT2:
6733             case D3DDECLTYPE_SHORT2N:
6734             {
6735                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6736                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6737                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6738                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd) for vertex %d %s, expected (%hd, %hd).\n",
6739                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6740                 break;
6741             }
6742             case D3DDECLTYPE_SHORT4:
6743             case D3DDECLTYPE_SHORT4N:
6744             {
6745                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6746                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6747                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6748                             && got[2] == exp[2] && got[3] == exp[3];
6749                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd, %hd, %hd) for vertex %d %s, expected (%hd, %hd, %hd, %hd).\n",
6750                     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]);
6751                 break;
6752             }
6753             case D3DDECLTYPE_USHORT2N:
6754             {
6755                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6756                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6757                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6758                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu) for vertex %d %s, expected (%hu, %hu).\n",
6759                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6760                 break;
6761             }
6762             case D3DDECLTYPE_USHORT4N:
6763             {
6764                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6765                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6766                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6767                             && got[2] == exp[2] && got[3] == exp[3];
6768                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu, %hu, %hu) for vertex %d %s, expected (%hu, %hu, %hu, %hu).\n",
6769                     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]);
6770                 break;
6771             }
6772             case D3DDECLTYPE_UDEC3:
6773             {
6774                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6775                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6776                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6777                 struct udec3 got_udec3 = dword_to_udec3(*got);
6778                 struct udec3 exp_udec3 = dword_to_udec3(*exp);
6779                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6780                     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);
6781 
6782                 break;
6783             }
6784             case D3DDECLTYPE_DEC3N:
6785             {
6786                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6787                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6788                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6789                 struct dec3n got_dec3n = dword_to_dec3n(*got);
6790                 struct dec3n exp_dec3n = dword_to_dec3n(*exp);
6791                 ok_(__FILE__,line)(same, "Mesh %d: Got (%d, %d, %d, %d) for vertex %d %s, expected (%d, %d, %d, %d).\n",
6792                     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);
6793                 break;
6794             }
6795             case D3DDECLTYPE_FLOAT16_2:
6796             {
6797                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6798                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6799                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6800                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx) for vertex %d %s, expected (%hx, %hx).\n",
6801                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6802                 break;
6803             }
6804             case D3DDECLTYPE_FLOAT16_4:
6805             {
6806                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6807                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6808                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6809                             && got[2] == exp[2] && got[3] == exp[3];
6810                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx, %hx, %hx) for vertex %d %s, expected (%hx, %hx, %hx, %hx).\n",
6811                     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]);
6812                 break;
6813             }
6814             default:
6815                 break;
6816         }
6817     }
6818 }
6819 
6820 static void test_weld_vertices(void)
6821 {
6822     HRESULT hr;
6823     struct test_context *test_context = NULL;
6824     DWORD i;
6825     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
6826     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
6827     BYTE *vertices = NULL;
6828     DWORD *indices = NULL;
6829     WORD *indices_16bit = NULL;
6830     const UINT VERTS_PER_FACE = 3;
6831 #ifndef __REACTOS__
6832     const D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
6833 #else
6834 #define up {0.0f, 0.0f, 1.0f}
6835 #endif
6836     struct vertex_normal
6837     {
6838         D3DXVECTOR3 position;
6839         D3DXVECTOR3 normal;
6840     };
6841     struct vertex_blendweight
6842     {
6843         D3DXVECTOR3 position;
6844         FLOAT blendweight;
6845     };
6846     struct vertex_texcoord
6847     {
6848         D3DXVECTOR3 position;
6849         D3DXVECTOR2 texcoord;
6850     };
6851     struct vertex_color
6852     {
6853         D3DXVECTOR3 position;
6854         DWORD color;
6855     };
6856     struct vertex_color_ubyte4
6857     {
6858         D3DXVECTOR3 position;
6859         BYTE color[4];
6860     };
6861     struct vertex_texcoord_short2
6862     {
6863         D3DXVECTOR3 position;
6864         SHORT texcoord[2];
6865     };
6866     struct vertex_texcoord_ushort2n
6867     {
6868         D3DXVECTOR3 position;
6869         USHORT texcoord[2];
6870     };
6871     struct vertex_normal_short4
6872     {
6873         D3DXVECTOR3 position;
6874         SHORT normal[4];
6875     };
6876     struct vertex_texcoord_float16_2
6877     {
6878         D3DXVECTOR3 position;
6879         WORD texcoord[2];
6880     };
6881     struct vertex_texcoord_float16_4
6882     {
6883         D3DXVECTOR3 position;
6884         WORD texcoord[4];
6885     };
6886     struct vertex_normal_udec3
6887     {
6888         D3DXVECTOR3 position;
6889         DWORD normal;
6890     };
6891     struct vertex_normal_dec3n
6892     {
6893         D3DXVECTOR3 position;
6894         DWORD normal;
6895     };
6896     UINT vertex_size_normal = sizeof(struct vertex_normal);
6897     UINT vertex_size_blendweight = sizeof(struct vertex_blendweight);
6898     UINT vertex_size_texcoord = sizeof(struct vertex_texcoord);
6899     UINT vertex_size_color = sizeof(struct vertex_color);
6900     UINT vertex_size_color_ubyte4 = sizeof(struct vertex_color_ubyte4);
6901     UINT vertex_size_texcoord_short2 = sizeof(struct vertex_texcoord_short2);
6902     UINT vertex_size_normal_short4 = sizeof(struct vertex_normal_short4);
6903     UINT vertex_size_texcoord_float16_2 = sizeof(struct vertex_texcoord_float16_2);
6904     UINT vertex_size_texcoord_float16_4 = sizeof(struct vertex_texcoord_float16_4);
6905     UINT vertex_size_normal_udec3 = sizeof(struct vertex_normal_udec3);
6906     UINT vertex_size_normal_dec3n = sizeof(struct vertex_normal_dec3n);
6907     D3DVERTEXELEMENT9 declaration_normal[] =
6908     {
6909         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6910         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6911         D3DDECL_END()
6912     };
6913     D3DVERTEXELEMENT9 declaration_normal3[] =
6914     {
6915         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 3},
6916         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6917         D3DDECL_END()
6918     };
6919     D3DVERTEXELEMENT9 declaration_blendweight[] =
6920     {
6921         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6922         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
6923         D3DDECL_END()
6924     };
6925     D3DVERTEXELEMENT9 declaration_texcoord[] =
6926     {
6927         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6928         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6929         D3DDECL_END()
6930     };
6931     D3DVERTEXELEMENT9 declaration_color[] =
6932     {
6933         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6934         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6935         D3DDECL_END()
6936     };
6937     D3DVERTEXELEMENT9 declaration_color_ubyte4n[] =
6938     {
6939         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6940         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6941         D3DDECL_END()
6942     };
6943     D3DVERTEXELEMENT9 declaration_color_ubyte4[] =
6944     {
6945         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6946         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6947         D3DDECL_END()
6948     };
6949     D3DVERTEXELEMENT9 declaration_texcoord_short2[] =
6950     {
6951         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6952         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6953         D3DDECL_END()
6954     };
6955     D3DVERTEXELEMENT9 declaration_texcoord_short2n[] =
6956     {
6957         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6958         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6959         D3DDECL_END()
6960     };
6961     D3DVERTEXELEMENT9 declaration_texcoord_ushort2n[] =
6962     {
6963         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6964         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6965         D3DDECL_END()
6966     };
6967     D3DVERTEXELEMENT9 declaration_normal_short4[] =
6968     {
6969         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6970         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6971         D3DDECL_END()
6972     };
6973     D3DVERTEXELEMENT9 declaration_normal_short4n[] =
6974     {
6975         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6976         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6977         D3DDECL_END()
6978     };
6979     D3DVERTEXELEMENT9 declaration_normal_ushort4n[] =
6980     {
6981         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6982         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6983         D3DDECL_END()
6984     };
6985     D3DVERTEXELEMENT9 declaration_texcoord10[] =
6986     {
6987         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6988         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 10},
6989         D3DDECL_END()
6990     };
6991     D3DVERTEXELEMENT9 declaration_color2[] =
6992     {
6993         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6994         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
6995         D3DDECL_END()
6996     };
6997     D3DVERTEXELEMENT9 declaration_color1[] =
6998     {
6999         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
7000         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
7001         D3DDECL_END()
7002     };
7003     D3DVERTEXELEMENT9 declaration_texcoord_float16_2[] =
7004     {
7005         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
7006         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
7007         D3DDECL_END()
7008     };
7009     D3DVERTEXELEMENT9 declaration_texcoord_float16_4[] =
7010     {
7011         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
7012         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
7013         D3DDECL_END()
7014     };
7015     D3DVERTEXELEMENT9 declaration_normal_udec3[] =
7016    {
7017         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
7018         {0, 12, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
7019         D3DDECL_END()
7020     };
7021     D3DVERTEXELEMENT9 declaration_normal_dec3n[] =
7022     {
7023         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
7024         {0, 12, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
7025         D3DDECL_END()
7026     };
7027     /* Test 0. One face and no welding.
7028      *
7029      * 0--1
7030      * | /
7031      * |/
7032      * 2
7033      */
7034     const struct vertex vertices0[] =
7035     {
7036         {{ 0.0f,  3.0f,  0.f}, up},
7037         {{ 2.0f,  3.0f,  0.f}, up},
7038         {{ 0.0f,  0.0f,  0.f}, up},
7039     };
7040     const DWORD indices0[] = {0, 1, 2};
7041     const DWORD attributes0[] = {0};
7042     const DWORD exp_indices0[] = {0, 1, 2};
7043     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
7044     const UINT num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
7045     const DWORD flags0 = D3DXWELDEPSILONS_WELDALL;
7046     /* epsilons0 is NULL */
7047     const DWORD adjacency0[] = {-1, -1, -1};
7048     const struct vertex exp_vertices0[] =
7049     {
7050         {{ 0.0f,  3.0f,  0.f}, up},
7051         {{ 2.0f,  3.0f,  0.f}, up},
7052         {{ 0.0f,  0.0f,  0.f}, up},
7053     };
7054     const DWORD exp_face_remap0[] = {0};
7055     const DWORD exp_vertex_remap0[] = {0, 1, 2};
7056     const DWORD exp_new_num_vertices0 = ARRAY_SIZE(exp_vertices0);
7057     /* Test 1. Two vertices should be removed without regard to epsilon.
7058      *
7059      * 0--1 3
7060      * | / /|
7061      * |/ / |
7062      * 2 5--4
7063      */
7064     const struct vertex_normal vertices1[] =
7065     {
7066         {{ 0.0f,  3.0f,  0.f}, up},
7067         {{ 2.0f,  3.0f,  0.f}, up},
7068         {{ 0.0f,  0.0f,  0.f}, up},
7069 
7070         {{ 3.0f,  3.0f,  0.f}, up},
7071         {{ 3.0f,  0.0f,  0.f}, up},
7072         {{ 1.0f,  0.0f,  0.f}, up},
7073     };
7074     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
7075     const DWORD attributes1[] = {0, 0};
7076     const UINT num_vertices1 = ARRAY_SIZE(vertices1);
7077     const UINT num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
7078     const DWORD flags1 = D3DXWELDEPSILONS_WELDALL;
7079     /* epsilons1 is NULL */
7080     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
7081     const struct vertex_normal exp_vertices1[] =
7082     {
7083         {{ 0.0f,  3.0f,  0.f}, up},
7084         {{ 2.0f,  3.0f,  0.f}, up},
7085         {{ 0.0f,  0.0f,  0.f}, up},
7086 
7087         {{ 3.0f,  0.0f,  0.f}, up}
7088     };
7089     const DWORD exp_indices1[] = {0, 1, 2, 1, 3, 2};
7090     const DWORD exp_face_remap1[] = {0, 1};
7091     const DWORD exp_vertex_remap1[] = {0, 1, 2, 4, -1, -1};
7092     const DWORD exp_new_num_vertices1 = ARRAY_SIZE(exp_vertices1);
7093     /* Test 2. Two faces. No vertices should be removed because of normal
7094      * epsilon, but the positions should be replaced. */
7095     const struct vertex_normal vertices2[] =
7096     {
7097         {{ 0.0f,  3.0f,  0.f}, up},
7098         {{ 2.0f,  3.0f,  0.f}, up},
7099         {{ 0.0f,  0.0f,  0.f}, up},
7100 
7101         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7102         {{ 3.0f,  0.0f,  0.f}, up},
7103         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7104     };
7105     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
7106     const DWORD attributes2[] = {0, 0};
7107     const UINT num_vertices2 = ARRAY_SIZE(vertices2);
7108     const UINT num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
7109     DWORD flags2 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7110     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};
7111     const DWORD adjacency2[] = {-1, 1, -1, -1, -1, 0};
7112     const struct vertex_normal exp_vertices2[] =
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         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7119         {{ 3.0f,  0.0f,  0.f}, up},
7120         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7121     };
7122     const DWORD exp_indices2[] = {0, 1, 2, 3, 4, 5};
7123     const DWORD exp_face_remap2[] = {0, 1};
7124     const DWORD exp_vertex_remap2[] = {0, 1, 2, 3, 4, 5};
7125     const DWORD exp_new_num_vertices2 = ARRAY_SIZE(exp_vertices2);
7126     /* Test 3. Two faces. One vertex should be removed because of normal epsilon. */
7127     const struct vertex_normal vertices3[] =
7128     {
7129         {{ 0.0f,  3.0f,  0.f}, up},
7130         {{ 2.0f,  3.0f,  0.f}, up},
7131         {{ 0.0f,  0.0f,  0.f}, up},
7132 
7133         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7134         {{ 3.0f,  0.0f,  0.f}, up},
7135         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7136     };
7137     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
7138     const DWORD attributes3[] = {0, 0};
7139     const UINT num_vertices3 = ARRAY_SIZE(vertices3);
7140     const UINT num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
7141     DWORD flags3 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7142     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};
7143     const DWORD adjacency3[] = {-1, 1, -1, -1, -1, 0};
7144     const struct vertex_normal exp_vertices3[] =
7145     {
7146         {{ 0.0f,  3.0f,  0.f}, up},
7147         {{ 2.0f,  3.0f,  0.f}, up},
7148         {{ 0.0f,  0.0f,  0.f}, up},
7149 
7150         {{ 3.0f,  0.0f,  0.f}, up},
7151         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7152     };
7153     const DWORD exp_indices3[] = {0, 1, 2, 1, 3, 4};
7154     const DWORD exp_face_remap3[] = {0, 1};
7155     const DWORD exp_vertex_remap3[] = {0, 1, 2, 4, 5, -1};
7156     const DWORD exp_new_num_vertices3 = ARRAY_SIZE(exp_vertices3);
7157     /* Test 4  Two faces. Two vertices should be removed. */
7158     const struct vertex_normal vertices4[] =
7159     {
7160         {{ 0.0f,  3.0f,  0.f}, up},
7161         {{ 2.0f,  3.0f,  0.f}, up},
7162         {{ 0.0f,  0.0f,  0.f}, up},
7163 
7164         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7165         {{ 3.0f,  0.0f,  0.f}, up},
7166         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7167     };
7168     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
7169     const DWORD attributes4[] = {0, 0};
7170     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
7171     const UINT num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
7172     DWORD flags4 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7173     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};
7174     const DWORD adjacency4[] = {-1, 1, -1, -1, -1, 0};
7175     const struct vertex_normal exp_vertices4[] =
7176     {
7177         {{ 0.0f,  3.0f,  0.f}, up},
7178         {{ 2.0f,  3.0f,  0.f}, up},
7179         {{ 0.0f,  0.0f,  0.f}, up},
7180 
7181         {{ 3.0f,  0.0f,  0.f}, up},
7182     };
7183     const DWORD exp_indices4[] = {0, 1, 2, 1, 3, 2};
7184     const DWORD exp_face_remap4[] = {0, 1};
7185     const DWORD exp_vertex_remap4[] = {0, 1, 2, 4, -1, -1};
7186     const DWORD exp_new_num_vertices4 = ARRAY_SIZE(exp_vertices4);
7187     /* Test 5. Odd face ordering.
7188      *
7189      * 0--1 6 3
7190      * | / /| |\
7191      * |/ / | | \
7192      * 2 8--7 5--4
7193      */
7194     const struct vertex_normal vertices5[] =
7195     {
7196         {{ 0.0f,  3.0f,  0.f}, up},
7197         {{ 2.0f,  3.0f,  0.f}, up},
7198         {{ 0.0f,  0.0f,  0.f}, up},
7199 
7200         {{ 3.0f,  3.0f,  0.f}, up},
7201         {{ 3.0f,  0.0f,  0.f}, up},
7202         {{ 1.0f,  0.0f,  0.f}, up},
7203 
7204         {{ 4.0f,  3.0f,  0.f}, up},
7205         {{ 6.0f,  0.0f,  0.f}, up},
7206         {{ 4.0f,  0.0f,  0.f}, up},
7207     };
7208     const DWORD indices5[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
7209     const DWORD exp_indices5[] = {0, 1, 2, 1, 4, 2, 1, 3, 4};
7210     const DWORD attributes5[] = {0, 0, 0};
7211     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
7212     const UINT num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
7213     DWORD flags5 = D3DXWELDEPSILONS_WELDALL;
7214     const DWORD adjacency5[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
7215     const struct vertex_normal exp_vertices5[] =
7216     {
7217         {{ 0.0f,  3.0f,  0.f}, up},
7218         {{ 2.0f,  3.0f,  0.f}, up},
7219         {{ 0.0f,  0.0f,  0.f}, up},
7220 
7221         {{ 3.0f,  0.0f,  0.f}, up},
7222         {{ 1.0f,  0.0f,  0.f}, up},
7223     };
7224     const DWORD exp_face_remap5[] = {0, 1, 2};
7225     const DWORD exp_vertex_remap5[] = {0, 1, 2, 4, 5, -1, -1, -1, -1};
7226     const DWORD exp_new_num_vertices5 = ARRAY_SIZE(exp_vertices5);
7227     /* Test 6. Two faces. Do not remove flag is used, so no vertices should be
7228      * removed. */
7229     const struct vertex_normal vertices6[] =
7230     {
7231         {{ 0.0f,  3.0f,  0.f}, up},
7232         {{ 2.0f,  3.0f,  0.f}, up},
7233         {{ 0.0f,  0.0f,  0.f}, up},
7234 
7235         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7236         {{ 3.0f,  0.0f,  0.f}, up},
7237         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7238     };
7239     const DWORD indices6[] = {0, 1, 2, 3, 4, 5};
7240     const DWORD attributes6[] = {0, 0};
7241     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
7242     const UINT num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
7243     DWORD flags6 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTREMOVEVERTICES;
7244     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};
7245     const DWORD adjacency6[] = {-1, 1, -1, -1, -1, 0};
7246     const struct vertex_normal exp_vertices6[] =
7247     {
7248         {{ 0.0f,  3.0f,  0.f}, up},
7249         {{ 2.0f,  3.0f,  0.f}, up},
7250         {{ 0.0f,  0.0f,  0.f}, up},
7251 
7252         {{ 2.0f,  3.0f,  0.f}, up},
7253         {{ 3.0f,  0.0f,  0.f}, up},
7254         {{ 0.0f,  0.0f,  0.f}, up},
7255 
7256     };
7257     const DWORD exp_indices6[] = {0, 1, 2, 3, 4, 5};
7258     const DWORD exp_face_remap6[] = {0, 1};
7259     const DWORD exp_vertex_remap6[] = {0, 1, 2, 3, 4, 5};
7260     const DWORD exp_new_num_vertices6 = ARRAY_SIZE(exp_vertices6);
7261     /* Test 7. Same as test 6 but with 16 bit indices. */
7262     const WORD indices6_16bit[] = {0, 1, 2, 3, 4, 5};
7263     /* Test 8. No flags. Same result as D3DXWELDEPSILONS_WELDPARTIALMATCHES. */
7264     const struct vertex_normal vertices8[] =
7265     {
7266         {{ 0.0f,  3.0f,  0.f}, up},
7267         {{ 2.0f,  3.0f,  0.f}, up},
7268         {{ 0.0f,  0.0f,  0.f}, up},
7269 
7270         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7271         {{ 3.0f,  0.0f,  0.f}, up},
7272         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7273     };
7274     const DWORD indices8[] = {0, 1, 2, 1, 3, 4};
7275     const DWORD attributes8[] = {0, 0};
7276     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
7277     const UINT num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
7278     DWORD flags8 = 0;
7279     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};
7280     const DWORD adjacency8[] = {-1, 1, -1, -1, -1, 0};
7281     const struct vertex_normal exp_vertices8[] =
7282     {
7283         {{ 0.0f,  3.0f,  0.f}, up},
7284         {{ 2.0f,  3.0f,  0.f}, up},
7285         {{ 0.0f,  0.0f,  0.f}, up},
7286 
7287         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7288         {{ 3.0f,  0.0f,  0.f}, up},
7289     };
7290     const DWORD exp_indices8[] = {0, 1, 2, 1, 3, 4};
7291     const DWORD exp_face_remap8[] = {0, 1};
7292     const DWORD exp_vertex_remap8[] = {0, 1, 2, 3, 4, -1};
7293     const DWORD exp_new_num_vertices8 = ARRAY_SIZE(exp_vertices8);
7294     /* Test 9. Vertices are removed even though they belong to separate
7295      * attribute groups if D3DXWELDEPSILONS_DONOTSPLIT is set. */
7296     const struct vertex_normal vertices9[] =
7297     {
7298         {{ 0.0f,  3.0f,  0.f}, up},
7299         {{ 2.0f,  3.0f,  0.f}, up},
7300         {{ 0.0f,  0.0f,  0.f}, up},
7301 
7302         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7303         {{ 3.0f,  0.0f,  0.f}, up},
7304         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7305     };
7306     const DWORD indices9[] = {0, 1, 2, 3, 4, 5};
7307     const DWORD attributes9[] = {0, 1};
7308     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
7309     const UINT num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
7310     DWORD flags9 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTSPLIT;
7311     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};
7312     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
7313     const struct vertex_normal exp_vertices9[] =
7314     {
7315         {{ 0.0f,  3.0f,  0.f}, up},
7316         {{ 2.0f,  3.0f,  0.f}, up},
7317         {{ 0.0f,  0.0f,  0.f}, up},
7318 
7319         {{ 3.0f,  0.0f,  0.f}, up},
7320     };
7321     const DWORD exp_indices9[] = {0, 1, 2, 1, 3, 2};
7322     const DWORD exp_face_remap9[] = {0, 1};
7323     const DWORD exp_vertex_remap9[] = {0, 1, 2, 4, -1, -1};
7324     const DWORD exp_new_num_vertices9 = ARRAY_SIZE(exp_vertices9);
7325     /* Test 10. Weld blendweight (FLOAT1). */
7326     const struct vertex_blendweight vertices10[] =
7327     {
7328         {{ 0.0f,  3.0f,  0.f}, 1.0f},
7329         {{ 2.0f,  3.0f,  0.f}, 1.0f},
7330         {{ 0.0f,  0.0f,  0.f}, 1.0f},
7331 
7332         {{ 3.0f,  3.0f,  0.f}, 0.9},
7333         {{ 3.0f,  0.0f,  0.f}, 1.0},
7334         {{ 1.0f,  0.0f,  0.f}, 0.4},
7335     };
7336     const DWORD indices10[] = {0, 1, 2, 3, 4, 5};
7337     const DWORD attributes10[] = {0, 0};
7338     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
7339     const UINT num_faces10 = ARRAY_SIZE(indices10) / VERTS_PER_FACE;
7340     DWORD flags10 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7341     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};
7342     const DWORD adjacency10[] = {-1, 1, -1, -1, -1, 0};
7343     const struct vertex_blendweight exp_vertices10[] =
7344     {
7345         {{ 0.0f,  3.0f,  0.f}, 1.0f},
7346         {{ 2.0f,  3.0f,  0.f}, 1.0f},
7347         {{ 0.0f,  0.0f,  0.f}, 1.0f},
7348 
7349         {{ 3.0f,  0.0f,  0.f}, 1.0},
7350         {{ 0.0f,  0.0f,  0.f}, 0.4},
7351     };
7352     const DWORD exp_indices10[] = {0, 1, 2, 1, 3, 4};
7353     const DWORD exp_face_remap10[] = {0, 1};
7354     const DWORD exp_vertex_remap10[] = {0, 1, 2, 4, 5, -1};
7355     const DWORD exp_new_num_vertices10 = ARRAY_SIZE(exp_vertices10);
7356     /* Test 11. Weld texture coordinates. */
7357     const struct vertex_texcoord vertices11[] =
7358     {
7359         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7360         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7361         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7362 
7363         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7364         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7365         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7366     };
7367     const DWORD indices11[] = {0, 1, 2, 3, 4, 5};
7368     const DWORD attributes11[] = {0, 0};
7369     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
7370     const UINT num_faces11 = ARRAY_SIZE(indices11) / VERTS_PER_FACE;
7371     DWORD flags11 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7372     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};
7373     const DWORD adjacency11[] = {-1, 1, -1, -1, -1, 0};
7374     const struct vertex_texcoord exp_vertices11[] =
7375     {
7376         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7377         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7378         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7379 
7380         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7381         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7382     };
7383     const DWORD exp_indices11[] = {0, 1, 2, 1, 3, 4};
7384     const DWORD exp_face_remap11[] = {0, 1};
7385     const DWORD exp_vertex_remap11[] = {0, 1, 2, 4, 5, -1};
7386     const DWORD exp_new_num_vertices11 = ARRAY_SIZE(exp_vertices11);
7387     /* Test 12. Weld with color. */
7388     const struct vertex_color vertices12[] =
7389     {
7390         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7391         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7392         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7393 
7394         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7395         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7396         {{ 1.0f,  0.0f,  0.f}, 0x88888888},
7397     };
7398     const DWORD indices12[] = {0, 1, 2, 3, 4, 5};
7399     const DWORD attributes12[] = {0, 0};
7400     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
7401     const UINT num_faces12 = ARRAY_SIZE(indices12) / VERTS_PER_FACE;
7402     DWORD flags12 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7403     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};
7404     const DWORD adjacency12[] = {-1, 1, -1, -1, -1, 0};
7405     const struct vertex_color exp_vertices12[] =
7406     {
7407         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7408         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7409         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7410 
7411         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7412         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7413     };
7414     const DWORD exp_indices12[] = {0, 1, 2, 3, 4, 2};
7415     const DWORD exp_face_remap12[] = {0, 1};
7416     const DWORD exp_vertex_remap12[] = {0, 1, 2, 3, 4, -1};
7417     const DWORD exp_new_num_vertices12 = ARRAY_SIZE(exp_vertices12);
7418     /* Test 13. Two faces. One vertex should be removed because of normal epsilon.
7419      * This is similar to test 3, but the declaration has been changed to NORMAL3.
7420      */
7421     const struct vertex_normal vertices13[] =
7422     {
7423         {{ 0.0f,  3.0f,  0.f}, up},
7424         {{ 2.0f,  3.0f,  0.f}, up},
7425         {{ 0.0f,  0.0f,  0.f}, up},
7426 
7427         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7428         {{ 3.0f,  0.0f,  0.f}, up},
7429         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7430     };
7431     const DWORD indices13[] = {0, 1, 2, 3, 4, 5};
7432     const DWORD attributes13[] = {0, 0};
7433     const UINT num_vertices13 = ARRAY_SIZE(vertices3);
7434     const UINT num_faces13 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
7435     DWORD flags13 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7436     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};
7437     const DWORD adjacency13[] = {-1, 1, -1, -1, -1, 0};
7438     const struct vertex_normal exp_vertices13[] =
7439     {
7440         {{ 0.0f,  3.0f,  0.f}, up},
7441         {{ 2.0f,  3.0f,  0.f}, up},
7442         {{ 0.0f,  0.0f,  0.f}, up},
7443 
7444         {{ 3.0f,  0.0f,  0.f}, up},
7445         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7446     };
7447     const DWORD exp_indices13[] = {0, 1, 2, 1, 3, 4};
7448     const DWORD exp_face_remap13[] = {0, 1};
7449     const DWORD exp_vertex_remap13[] = {0, 1, 2, 4, 5, -1};
7450     const DWORD exp_new_num_vertices13 = ARRAY_SIZE(exp_vertices13);
7451     /* Test 14. Another test for welding with color. */
7452     const struct vertex_color vertices14[] =
7453     {
7454         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7455         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7456         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7457 
7458         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7459         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7460         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7461     };
7462     const DWORD indices14[] = {0, 1, 2, 3, 4, 5};
7463     const DWORD attributes14[] = {0, 0};
7464     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
7465     const UINT num_faces14 = ARRAY_SIZE(indices14) / VERTS_PER_FACE;
7466     DWORD flags14 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7467     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};
7468     const DWORD adjacency14[] = {-1, 1, -1, -1, -1, 0};
7469     const struct vertex_color exp_vertices14[] =
7470     {
7471         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7472         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7473         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7474 
7475         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7476         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7477     };
7478     const DWORD exp_indices14[] = {0, 1, 2, 3, 4, 2};
7479     const DWORD exp_face_remap14[] = {0, 1};
7480     const DWORD exp_vertex_remap14[] = {0, 1, 2, 3, 4, -1};
7481     const DWORD exp_new_num_vertices14 = ARRAY_SIZE(exp_vertices14);
7482     /* Test 15. Weld with color, but as UBYTE4N instead of D3DCOLOR. It shows
7483      * that UBYTE4N and D3DCOLOR are compared the same way.
7484      */
7485     const struct vertex_color_ubyte4 vertices15[] =
7486     {
7487         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7488         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7489         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7490 
7491         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7492         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7493         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7494     };
7495     const DWORD indices15[] = {0, 1, 2, 3, 4, 5};
7496     const DWORD attributes15[] = {0, 0};
7497     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
7498     const UINT num_faces15 = ARRAY_SIZE(indices15) / VERTS_PER_FACE;
7499     DWORD flags15 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7500     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};
7501     const DWORD adjacency15[] = {-1, 1, -1, -1, -1, 0};
7502     const struct vertex_color_ubyte4 exp_vertices15[] =
7503     {
7504         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7505         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7506         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7507 
7508         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7509         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7510     };
7511     const DWORD exp_indices15[] = {0, 1, 2, 3, 4, 2};
7512     const DWORD exp_face_remap15[] = {0, 1};
7513     const DWORD exp_vertex_remap15[] = {0, 1, 2, 3, 4, -1};
7514     const DWORD exp_new_num_vertices15 = ARRAY_SIZE(exp_vertices15);
7515     /* Test 16. Weld with color, but as UBYTE4 instead of D3DCOLOR. It shows
7516      * that UBYTE4 is not normalized and that epsilon is truncated and compared
7517      * directly to each of the four bytes.
7518      */
7519     const struct vertex_color_ubyte4 vertices16[] =
7520     {
7521         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7522         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7523         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7524 
7525         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7526         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7527         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7528     };
7529     const DWORD indices16[] = {0, 1, 2, 3, 4, 5};
7530     const DWORD attributes16[] = {0, 0};
7531     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
7532     const UINT num_faces16 = ARRAY_SIZE(indices16) / VERTS_PER_FACE;
7533     DWORD flags16 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7534     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};
7535     const DWORD adjacency16[] = {-1, 1, -1, -1, -1, 0};
7536     const struct vertex_color_ubyte4 exp_vertices16[] =
7537     {
7538         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7539         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7540         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7541 
7542         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7543         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7544     };
7545     const DWORD exp_indices16[] = {0, 1, 2, 3, 4, 2};
7546     const DWORD exp_face_remap16[] = {0, 1};
7547     const DWORD exp_vertex_remap16[] = {0, 1, 2, 3, 4, -1};
7548     const DWORD exp_new_num_vertices16 = ARRAY_SIZE(exp_vertices16);
7549     /* Test 17. Weld texture coordinates but as SHORT2 instead of D3DXVECTOR2.*/
7550     const struct vertex_texcoord_short2 vertices17[] =
7551     {
7552         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7553         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7554         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7555 
7556         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7557         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7558         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7559     };
7560     const DWORD indices17[] = {0, 1, 2, 3, 4, 5};
7561     const DWORD attributes17[] = {0, 0};
7562     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
7563     const UINT num_faces17 = ARRAY_SIZE(indices17) / VERTS_PER_FACE;
7564     DWORD flags17 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7565     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};
7566     const DWORD adjacency17[] = {-1, 1, -1, -1, -1, 0};
7567     const struct vertex_texcoord_short2 exp_vertices17[] =
7568     {
7569         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7570         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7571         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7572 
7573         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7574         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7575     };
7576     const DWORD exp_indices17[] = {0, 1, 2, 3, 4, 2};
7577     const DWORD exp_face_remap17[] = {0, 1};
7578     const DWORD exp_vertex_remap17[] = {0, 1, 2, 3, 4, -1};
7579     const DWORD exp_new_num_vertices17 = ARRAY_SIZE(exp_vertices17);
7580     /* Test 18. Weld texture coordinates but as SHORT2N instead of D3DXVECTOR2. */
7581     const struct vertex_texcoord_short2 vertices18[] =
7582     {
7583         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7584         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7585         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7586 
7587         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7588         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7589         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7590     };
7591     const DWORD indices18[] = {0, 1, 2, 3, 4, 5};
7592     const DWORD attributes18[] = {0, 0};
7593     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
7594     const UINT num_faces18 = ARRAY_SIZE(indices18) / VERTS_PER_FACE;
7595     DWORD flags18 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7596     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};
7597     const DWORD adjacency18[] = {-1, 1, -1, -1, -1, 0};
7598     const struct vertex_texcoord_short2 exp_vertices18[] =
7599     {
7600         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7601         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7602         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7603 
7604         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7605         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7606     };
7607     const DWORD exp_indices18[] = {0, 1, 2, 3, 4, 2};
7608     const DWORD exp_face_remap18[] = {0, 1};
7609     const DWORD exp_vertex_remap18[] = {0, 1, 2, 3, 4, -1};
7610     const DWORD exp_new_num_vertices18 = ARRAY_SIZE(exp_vertices18);
7611     /* Test 19.  Weld texture coordinates but as USHORT2N instead of D3DXVECTOR2. */
7612     const struct vertex_texcoord_ushort2n vertices19[] =
7613     {
7614         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7615         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7616         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7617 
7618         {{ 3.0f,  3.0f,  0.f}, {65535, 65535}},
7619         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7620         {{ 1.0f,  0.0f,  0.f}, {65534, 65534}},
7621     };
7622     const DWORD indices19[] = {0, 1, 2, 3, 4, 5};
7623     const DWORD attributes19[] = {0, 0};
7624     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
7625     const UINT num_faces19 = ARRAY_SIZE(indices19) / VERTS_PER_FACE;
7626     DWORD flags19 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7627     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};
7628     const DWORD adjacency19[] = {-1, 1, -1, -1, -1, 0};
7629     const struct vertex_texcoord_ushort2n exp_vertices19[] =
7630     {
7631         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7632         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7633         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7634 
7635         {{ 2.0f,  3.0f,  0.f}, {65535, 65535}},
7636         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7637     };
7638     const DWORD exp_indices19[] = {0, 1, 2, 3, 4, 2};
7639     const DWORD exp_face_remap19[] = {0, 1};
7640     const DWORD exp_vertex_remap19[] = {0, 1, 2, 3, 4, -1};
7641     const DWORD exp_new_num_vertices19 = ARRAY_SIZE(exp_vertices19);
7642     /* Test 20.  Weld normal as SHORT4 instead of D3DXVECTOR3. */
7643     const struct vertex_normal_short4 vertices20[] =
7644     {
7645         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7646         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7647         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7648 
7649         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7650         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7651         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7652     };
7653     const DWORD indices20[] = {0, 1, 2, 3, 4, 5};
7654     const DWORD attributes20[] = {0, 0};
7655     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
7656     const UINT num_faces20 = ARRAY_SIZE(indices20) / VERTS_PER_FACE;
7657     DWORD flags20 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7658     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};
7659     const DWORD adjacency20[] = {-1, 1, -1, -1, -1, 0};
7660     const struct vertex_normal_short4 exp_vertices20[] =
7661     {
7662         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7663         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7664         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7665 
7666         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7667         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7668     };
7669     const DWORD exp_indices20[] = {0, 1, 2, 3, 4, 2};
7670     const DWORD exp_face_remap20[] = {0, 1};
7671     const DWORD exp_vertex_remap20[] = {0, 1, 2, 3, 4, -1};
7672     const DWORD exp_new_num_vertices20 = ARRAY_SIZE(exp_vertices20);
7673     /* Test 21.  Weld normal as SHORT4N instead of D3DXVECTOR3. */
7674     const struct vertex_normal_short4 vertices21[] =
7675     {
7676         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7677         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7678         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7679 
7680         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7681         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7682         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7683     };
7684     const DWORD indices21[] = {0, 1, 2, 3, 4, 5};
7685     const DWORD attributes21[] = {0, 0};
7686     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
7687     const UINT num_faces21 = ARRAY_SIZE(indices21) / VERTS_PER_FACE;
7688     DWORD flags21 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7689     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};
7690     const DWORD adjacency21[] = {-1, 1, -1, -1, -1, 0};
7691     const struct vertex_normal_short4 exp_vertices21[] =
7692     {
7693         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7694         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7695         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7696 
7697         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7698         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7699     };
7700     const DWORD exp_indices21[] = {0, 1, 2, 3, 4, 2};
7701     const DWORD exp_face_remap21[] = {0, 1};
7702     const DWORD exp_vertex_remap21[] = {0, 1, 2, 3, 4, -1};
7703     const DWORD exp_new_num_vertices21 = ARRAY_SIZE(exp_vertices21);
7704     /* Test 22.  Weld normal as USHORT4N instead of D3DXVECTOR3. */
7705     const struct vertex_normal_short4 vertices22[] =
7706     {
7707         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7708         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7709         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7710 
7711         {{ 3.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7712         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7713         {{ 1.0f,  0.0f,  0.f}, {65534, 65534, 65534, 65534}},
7714     };
7715     const DWORD indices22[] = {0, 1, 2, 3, 4, 5};
7716     const DWORD attributes22[] = {0, 0};
7717     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
7718     const UINT num_faces22 = ARRAY_SIZE(indices22) / VERTS_PER_FACE;
7719     DWORD flags22 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7720     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};
7721     const DWORD adjacency22[] = {-1, 1, -1, -1, -1, 0};
7722     const struct vertex_normal_short4 exp_vertices22[] =
7723     {
7724         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7725         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7726         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7727 
7728         {{ 2.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7729         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7730     };
7731     const DWORD exp_indices22[] = {0, 1, 2, 3, 4, 2};
7732     const DWORD exp_face_remap22[] = {0, 1};
7733     const DWORD exp_vertex_remap22[] = {0, 1, 2, 3, 4, -1};
7734     const DWORD exp_new_num_vertices22 = ARRAY_SIZE(exp_vertices22);
7735     /* Test 23. Weld texture coordinates as FLOAT16_2. Similar to test 11, but
7736      * with texture coordinates converted to float16 in hex. */
7737     const struct vertex_texcoord_float16_2 vertices23[] =
7738     {
7739         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7740         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7741         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7742 
7743         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
7744         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7745         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7746     };
7747     const DWORD indices23[] = {0, 1, 2, 3, 4, 5};
7748     const DWORD attributes23[] = {0, 0};
7749     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
7750     const UINT num_faces23 = ARRAY_SIZE(indices23) / VERTS_PER_FACE;
7751     DWORD flags23 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7752     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};
7753     const DWORD adjacency23[] = {-1, 1, -1, -1, -1, 0};
7754     const struct vertex_texcoord_float16_2 exp_vertices23[] =
7755     {
7756         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7757         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7758         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7759 
7760         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7761         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7762     };
7763     const DWORD exp_indices23[] = {0, 1, 2, 1, 3, 4};
7764     const DWORD exp_face_remap23[] = {0, 1};
7765     const DWORD exp_vertex_remap23[] = {0, 1, 2, 4, 5, -1};
7766     const DWORD exp_new_num_vertices23 = ARRAY_SIZE(exp_vertices23);
7767     /* Test 24. Weld texture coordinates as FLOAT16_4. Similar to test 24. */
7768     const struct vertex_texcoord_float16_4 vertices24[] =
7769     {
7770         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7771         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7772         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7773 
7774         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0x3266, 0x34cd}},
7775         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7776         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7777     };
7778     const DWORD indices24[] = {0, 1, 2, 3, 4, 5};
7779     const DWORD attributes24[] = {0, 0};
7780     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
7781     const UINT num_faces24 = ARRAY_SIZE(indices24) / VERTS_PER_FACE;
7782     DWORD flags24 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7783     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};
7784     const DWORD adjacency24[] = {-1, 1, -1, -1, -1, 0};
7785     const struct vertex_texcoord_float16_4 exp_vertices24[] =
7786     {
7787         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7788         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7789         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7790 
7791         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7792         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7793     };
7794     const DWORD exp_indices24[] = {0, 1, 2, 1, 3, 4};
7795     const DWORD exp_face_remap24[] = {0, 1};
7796     const DWORD exp_vertex_remap24[] = {0, 1, 2, 4, 5, -1};
7797     const DWORD exp_new_num_vertices24 = ARRAY_SIZE(exp_vertices24);
7798     /* Test 25. Weld texture coordinates with usage index 10 (TEXCOORD10). The
7799      * usage index is capped at 7, so the epsilon for TEXCOORD7 is used instead.
7800      */
7801     const struct vertex_texcoord vertices25[] =
7802     {
7803         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7804         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7805         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7806 
7807         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7808         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7809         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7810     };
7811     const DWORD indices25[] = {0, 1, 2, 3, 4, 5};
7812     const DWORD attributes25[] = {0, 0};
7813     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
7814     const UINT num_faces25 = ARRAY_SIZE(indices25) / VERTS_PER_FACE;
7815     DWORD flags25 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7816     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};
7817     const DWORD adjacency25[] = {-1, 1, -1, -1, -1, 0};
7818     const struct vertex_texcoord exp_vertices25[] =
7819     {
7820         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7821         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7822         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7823 
7824         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7825         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7826     };
7827     const DWORD exp_indices25[] = {0, 1, 2, 1, 3, 4};
7828     const DWORD exp_face_remap25[] = {0, 1};
7829     const DWORD exp_vertex_remap25[] = {0, 1, 2, 4, 5, -1};
7830     const DWORD exp_new_num_vertices25 = ARRAY_SIZE(exp_vertices25);
7831     /* Test 26. Weld color with usage index larger than 1. Shows that none of
7832      * the epsilon values are used. */
7833     const struct vertex_color vertices26[] =
7834     {
7835         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7836         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7837         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7838 
7839         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7840         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7841         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7842     };
7843     const DWORD indices26[] = {0, 1, 2, 3, 4, 5};
7844     const DWORD attributes26[] = {0, 0};
7845     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
7846     const UINT num_faces26 = ARRAY_SIZE(indices26) / VERTS_PER_FACE;
7847     DWORD flags26 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7848     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};
7849     const DWORD adjacency26[] = {-1, 1, -1, -1, -1, 0};
7850     const struct vertex_color exp_vertices26[] =
7851     {
7852         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7853         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7854         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7855 
7856         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7857         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7858         {{ 0.0f,  0.0f,  0.f}, 0x01010101},
7859     };
7860     const DWORD exp_indices26[] = {0, 1, 2, 3, 4, 5};
7861     const DWORD exp_face_remap26[] = {0, 1};
7862     const DWORD exp_vertex_remap26[] = {0, 1, 2, 3, 4, 5};
7863     const DWORD exp_new_num_vertices26 = ARRAY_SIZE(exp_vertices26);
7864     /* Test 27. Weld color with usage index 1 (specular). */
7865     /* Previously this test used float color values and index > 1 but that case
7866      * appears to be effectively unhandled in native so the test gave
7867      * inconsistent results. */
7868     const struct vertex_color vertices27[] =
7869     {
7870         {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
7871         {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
7872         {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
7873 
7874         {{ 3.0f,  3.0f,  0.0f}, 0x11213141},
7875         {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
7876         {{ 1.0f,  0.0f,  0.0f}, 0x51617181},
7877     };
7878     const DWORD indices27[] = {0, 1, 2, 3, 4, 5};
7879     const DWORD attributes27[] = {0, 0};
7880     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
7881     const UINT num_faces27 = ARRAY_SIZE(indices27) / VERTS_PER_FACE;
7882     DWORD flags27 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7883     const D3DXWELDEPSILONS epsilons27 =
7884     {
7885         1.1f, 0.0f, 0.0f, 0.0f, 2.0f / 255.0f, 0.0f,
7886         {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f
7887     };
7888     const DWORD adjacency27[] = {-1, 1, -1, -1, -1, 0};
7889     const struct vertex_color exp_vertices27[] =
7890     {
7891         {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
7892         {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
7893         {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
7894 
7895         {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
7896     };
7897     const DWORD exp_indices27[] = {0, 1, 2, 1, 3, 2};
7898     const DWORD exp_face_remap27[] = {0, 1};
7899     const DWORD exp_vertex_remap27[] = {0, 1, 2, 4, -1, -1};
7900     const DWORD exp_new_num_vertices27 = ARRAY_SIZE(exp_vertices27);
7901     /* Test 28. Weld one normal with UDEC3. */
7902     const DWORD dword_udec3_zero = init_udec3_dword(0, 0, 0, 1);
7903     const DWORD dword_udec3_1023 = init_udec3_dword(1023, 1023, 1023, 1);
7904     const DWORD dword_udec3_1022 = init_udec3_dword(1022, 1022, 1022, 1);
7905     const struct vertex_normal_udec3 vertices28[] =
7906     {
7907         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7908         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7909         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7910 
7911         {{ 3.0f,  3.0f,  0.f}, dword_udec3_1023},
7912         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7913         {{ 1.0f,  0.0f,  0.f}, dword_udec3_1022},
7914     };
7915     const DWORD indices28[] = {0, 1, 2, 3, 4, 5};
7916     const DWORD attributes28[] = {0, 0};
7917     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
7918     const UINT num_faces28 = ARRAY_SIZE(indices28) / VERTS_PER_FACE;
7919     DWORD flags28 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7920     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};
7921     const DWORD adjacency28[] = {-1, 1, -1, -1, -1, 0};
7922     const struct vertex_normal_udec3 exp_vertices28[] =
7923     {
7924         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7925         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7926         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7927 
7928         {{ 2.0f,  3.0f,  0.f}, dword_udec3_1023},
7929         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7930     };
7931     const DWORD exp_indices28[] = {0, 1, 2, 3, 4, 2};
7932     const DWORD exp_face_remap28[] = {0, 1};
7933     const DWORD exp_vertex_remap28[] = {0, 1, 2, 3, 4, -1};
7934     const DWORD exp_new_num_vertices28 = ARRAY_SIZE(exp_vertices28);
7935     /* Test 29. Weld one normal with DEC3N. */
7936     const DWORD dword_dec3n_zero = init_dec3n_dword(0, 0, 0, 1);
7937     const DWORD dword_dec3n_511 = init_dec3n_dword(511, 511, 511, 1);
7938     const DWORD dword_dec3n_510 = init_dec3n_dword(510, 510, 510, 1);
7939     const struct vertex_normal_dec3n vertices29[] =
7940     {
7941         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7942         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7943         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7944 
7945         {{ 3.0f,  3.0f,  0.f}, dword_dec3n_511},
7946         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7947         {{ 1.0f,  0.0f,  0.f}, dword_dec3n_510},
7948     };
7949     const DWORD indices29[] = {0, 1, 2, 3, 4, 5};
7950     const DWORD attributes29[] = {0, 0};
7951     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
7952     const UINT num_faces29 = ARRAY_SIZE(indices29) / VERTS_PER_FACE;
7953     DWORD flags29 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7954     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};
7955     const DWORD adjacency29[] = {-1, 1, -1, -1, -1, 0};
7956     const struct vertex_normal_dec3n exp_vertices29[] =
7957     {
7958         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7959         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7960         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7961 
7962         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_511},
7963         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7964     };
7965     const DWORD exp_indices29[] = {0, 1, 2, 3, 4, 2};
7966     const DWORD exp_face_remap29[] = {0, 1};
7967     const DWORD exp_vertex_remap29[] = {0, 1, 2, 3, 4, -1};
7968     const DWORD exp_new_num_vertices29 = ARRAY_SIZE(exp_vertices29);
7969     /* All mesh data */
7970     DWORD *adjacency_out = NULL;
7971     DWORD *face_remap = NULL;
7972     ID3DXMesh *mesh = NULL;
7973     ID3DXBuffer *vertex_remap = NULL;
7974     struct
7975     {
7976         const BYTE *vertices;
7977         const DWORD *indices;
7978         const DWORD *attributes;
7979         const DWORD num_vertices;
7980         const DWORD num_faces;
7981         const DWORD options;
7982         D3DVERTEXELEMENT9 *declaration;
7983         const UINT vertex_size;
7984         const DWORD flags;
7985         const D3DXWELDEPSILONS *epsilons;
7986         const DWORD *adjacency;
7987         const BYTE *exp_vertices;
7988         const DWORD *exp_indices;
7989         const DWORD *exp_face_remap;
7990         const DWORD *exp_vertex_remap;
7991         const DWORD exp_new_num_vertices;
7992     }
7993     tc[] =
7994     {
7995         {
7996             (BYTE*)vertices0,
7997             indices0,
7998             attributes0,
7999             num_vertices0,
8000             num_faces0,
8001             options,
8002             declaration_normal,
8003             vertex_size_normal,
8004             flags0,
8005             NULL,
8006             adjacency0,
8007             (BYTE*)exp_vertices0,
8008             exp_indices0,
8009             exp_face_remap0,
8010             exp_vertex_remap0,
8011             exp_new_num_vertices0
8012         },
8013         {
8014             (BYTE*)vertices1,
8015             indices1,
8016             attributes1,
8017             num_vertices1,
8018             num_faces1,
8019             options,
8020             declaration_normal,
8021             vertex_size_normal,
8022             flags1,
8023             NULL,
8024             adjacency1,
8025             (BYTE*)exp_vertices1,
8026             exp_indices1,
8027             exp_face_remap1,
8028             exp_vertex_remap1,
8029             exp_new_num_vertices1
8030         },
8031         {
8032             (BYTE*)vertices2,
8033             indices2,
8034             attributes2,
8035             num_vertices2,
8036             num_faces2,
8037             options,
8038             declaration_normal,
8039             vertex_size_normal,
8040             flags2,
8041             &epsilons2,
8042             adjacency2,
8043             (BYTE*)exp_vertices2,
8044             exp_indices2,
8045             exp_face_remap2,
8046             exp_vertex_remap2,
8047             exp_new_num_vertices2
8048         },
8049         {
8050             (BYTE*)vertices3,
8051             indices3,
8052             attributes3,
8053             num_vertices3,
8054             num_faces3,
8055             options,
8056             declaration_normal,
8057             vertex_size_normal,
8058             flags3,
8059             &epsilons3,
8060             adjacency3,
8061             (BYTE*)exp_vertices3,
8062             exp_indices3,
8063             exp_face_remap3,
8064             exp_vertex_remap3,
8065             exp_new_num_vertices3
8066         },
8067         {
8068             (BYTE*)vertices4,
8069             indices4,
8070             attributes4,
8071             num_vertices4,
8072             num_faces4,
8073             options,
8074             declaration_normal,
8075             vertex_size_normal,
8076             flags4,
8077             &epsilons4,
8078             adjacency4,
8079             (BYTE*)exp_vertices4,
8080             exp_indices4,
8081             exp_face_remap4,
8082             exp_vertex_remap4,
8083             exp_new_num_vertices4
8084         },
8085         /* Unusual ordering. */
8086         {
8087             (BYTE*)vertices5,
8088             indices5,
8089             attributes5,
8090             num_vertices5,
8091             num_faces5,
8092             options,
8093             declaration_normal,
8094             vertex_size_normal,
8095             flags5,
8096             NULL,
8097             adjacency5,
8098             (BYTE*)exp_vertices5,
8099             exp_indices5,
8100             exp_face_remap5,
8101             exp_vertex_remap5,
8102             exp_new_num_vertices5
8103         },
8104         {
8105             (BYTE*)vertices6,
8106             indices6,
8107             attributes6,
8108             num_vertices6,
8109             num_faces6,
8110             options,
8111             declaration_normal,
8112             vertex_size_normal,
8113             flags6,
8114             &epsilons6,
8115             adjacency6,
8116             (BYTE*)exp_vertices6,
8117             exp_indices6,
8118             exp_face_remap6,
8119             exp_vertex_remap6,
8120             exp_new_num_vertices6
8121         },
8122         {
8123             (BYTE*)vertices6,
8124             (DWORD*)indices6_16bit,
8125             attributes6,
8126             num_vertices6,
8127             num_faces6,
8128             options_16bit,
8129             declaration_normal,
8130             vertex_size_normal,
8131             flags6,
8132             &epsilons6,
8133             adjacency6,
8134             (BYTE*)exp_vertices6,
8135             exp_indices6,
8136             exp_face_remap6,
8137             exp_vertex_remap6,
8138             exp_new_num_vertices6
8139         },
8140         {
8141             (BYTE*)vertices8,
8142             indices8,
8143             attributes8,
8144             num_vertices8,
8145             num_faces8,
8146             options,
8147             declaration_normal,
8148             vertex_size_normal,
8149             flags8,
8150             &epsilons8,
8151             adjacency8,
8152             (BYTE*)exp_vertices8,
8153             exp_indices8,
8154             exp_face_remap8,
8155             exp_vertex_remap8,
8156             exp_new_num_vertices8
8157         },
8158         {
8159             (BYTE*)vertices9,
8160             indices9,
8161             attributes9,
8162             num_vertices9,
8163             num_faces9,
8164             options,
8165             declaration_normal,
8166             vertex_size_normal,
8167             flags9,
8168             &epsilons9,
8169             adjacency9,
8170             (BYTE*)exp_vertices9,
8171             exp_indices9,
8172             exp_face_remap9,
8173             exp_vertex_remap9,
8174             exp_new_num_vertices9
8175         },
8176         {
8177             (BYTE*)vertices10,
8178             indices10,
8179             attributes10,
8180             num_vertices10,
8181             num_faces10,
8182             options,
8183             declaration_blendweight,
8184             vertex_size_blendweight,
8185             flags10,
8186             &epsilons10,
8187             adjacency10,
8188             (BYTE*)exp_vertices10,
8189             exp_indices10,
8190             exp_face_remap10,
8191             exp_vertex_remap10,
8192             exp_new_num_vertices10
8193         },
8194         {
8195             (BYTE*)vertices11,
8196             indices11,
8197             attributes11,
8198             num_vertices11,
8199             num_faces11,
8200             options,
8201             declaration_texcoord,
8202             vertex_size_texcoord,
8203             flags11,
8204             &epsilons11,
8205             adjacency11,
8206             (BYTE*)exp_vertices11,
8207             exp_indices11,
8208             exp_face_remap11,
8209             exp_vertex_remap11,
8210             exp_new_num_vertices11
8211         },
8212         {
8213             (BYTE*)vertices12,
8214             indices12,
8215             attributes12,
8216             num_vertices12,
8217             num_faces12,
8218             options,
8219             declaration_color,
8220             vertex_size_color,
8221             flags12,
8222             &epsilons12,
8223             adjacency12,
8224             (BYTE*)exp_vertices12,
8225             exp_indices12,
8226             exp_face_remap12,
8227             exp_vertex_remap12,
8228             exp_new_num_vertices12
8229         },
8230         {
8231             (BYTE*)vertices13,
8232             indices13,
8233             attributes13,
8234             num_vertices13,
8235             num_faces13,
8236             options,
8237             declaration_normal3,
8238             vertex_size_normal,
8239             flags13,
8240             &epsilons13,
8241             adjacency13,
8242             (BYTE*)exp_vertices13,
8243             exp_indices13,
8244             exp_face_remap13,
8245             exp_vertex_remap13,
8246             exp_new_num_vertices13
8247         },
8248         {
8249             (BYTE*)vertices14,
8250             indices14,
8251             attributes14,
8252             num_vertices14,
8253             num_faces14,
8254             options,
8255             declaration_color,
8256             vertex_size_color,
8257             flags14,
8258             &epsilons14,
8259             adjacency14,
8260             (BYTE*)exp_vertices14,
8261             exp_indices14,
8262             exp_face_remap14,
8263             exp_vertex_remap14,
8264             exp_new_num_vertices14
8265         },
8266         {
8267             (BYTE*)vertices15,
8268             indices15,
8269             attributes15,
8270             num_vertices15,
8271             num_faces15,
8272             options,
8273             declaration_color_ubyte4n,
8274             vertex_size_color_ubyte4, /* UBYTE4 same size as UBYTE4N */
8275             flags15,
8276             &epsilons15,
8277             adjacency15,
8278             (BYTE*)exp_vertices15,
8279             exp_indices15,
8280             exp_face_remap15,
8281             exp_vertex_remap15,
8282             exp_new_num_vertices15
8283         },
8284         {
8285             (BYTE*)vertices16,
8286             indices16,
8287             attributes16,
8288             num_vertices16,
8289             num_faces16,
8290             options,
8291             declaration_color_ubyte4,
8292             vertex_size_color_ubyte4,
8293             flags16,
8294             &epsilons16,
8295             adjacency16,
8296             (BYTE*)exp_vertices16,
8297             exp_indices16,
8298             exp_face_remap16,
8299             exp_vertex_remap16,
8300             exp_new_num_vertices16
8301         },
8302         {
8303             (BYTE*)vertices17,
8304             indices17,
8305             attributes17,
8306             num_vertices17,
8307             num_faces17,
8308             options,
8309             declaration_texcoord_short2,
8310             vertex_size_texcoord_short2,
8311             flags17,
8312             &epsilons17,
8313             adjacency17,
8314             (BYTE*)exp_vertices17,
8315             exp_indices17,
8316             exp_face_remap17,
8317             exp_vertex_remap17,
8318             exp_new_num_vertices17
8319         },
8320         {
8321             (BYTE*)vertices18,
8322             indices18,
8323             attributes18,
8324             num_vertices18,
8325             num_faces18,
8326             options,
8327             declaration_texcoord_short2n,
8328             vertex_size_texcoord_short2, /* SHORT2 same size as SHORT2N */
8329             flags18,
8330             &epsilons18,
8331             adjacency18,
8332             (BYTE*)exp_vertices18,
8333             exp_indices18,
8334             exp_face_remap18,
8335             exp_vertex_remap18,
8336             exp_new_num_vertices18
8337         },
8338         {
8339             (BYTE*)vertices19,
8340             indices19,
8341             attributes19,
8342             num_vertices19,
8343             num_faces19,
8344             options,
8345             declaration_texcoord_ushort2n,
8346             vertex_size_texcoord_short2, /* SHORT2 same size as USHORT2N */
8347             flags19,
8348             &epsilons19,
8349             adjacency19,
8350             (BYTE*)exp_vertices19,
8351             exp_indices19,
8352             exp_face_remap19,
8353             exp_vertex_remap19,
8354             exp_new_num_vertices19
8355         },
8356         {
8357             (BYTE*)vertices20,
8358             indices20,
8359             attributes20,
8360             num_vertices20,
8361             num_faces20,
8362             options,
8363             declaration_normal_short4,
8364             vertex_size_normal_short4,
8365             flags20,
8366             &epsilons20,
8367             adjacency20,
8368             (BYTE*)exp_vertices20,
8369             exp_indices20,
8370             exp_face_remap20,
8371             exp_vertex_remap20,
8372             exp_new_num_vertices20
8373         },
8374         {
8375             (BYTE*)vertices21,
8376             indices21,
8377             attributes21,
8378             num_vertices21,
8379             num_faces21,
8380             options,
8381             declaration_normal_short4n,
8382             vertex_size_normal_short4, /* SHORT4 same size as SHORT4N */
8383             flags21,
8384             &epsilons21,
8385             adjacency21,
8386             (BYTE*)exp_vertices21,
8387             exp_indices21,
8388             exp_face_remap21,
8389             exp_vertex_remap21,
8390             exp_new_num_vertices21
8391         },
8392         {
8393             (BYTE*)vertices22,
8394             indices22,
8395             attributes22,
8396             num_vertices22,
8397             num_faces22,
8398             options,
8399             declaration_normal_ushort4n,
8400             vertex_size_normal_short4, /* SHORT4 same size as USHORT4N */
8401             flags22,
8402             &epsilons22,
8403             adjacency22,
8404             (BYTE*)exp_vertices22,
8405             exp_indices22,
8406             exp_face_remap22,
8407             exp_vertex_remap22,
8408             exp_new_num_vertices22
8409         },
8410         {
8411             (BYTE*)vertices23,
8412             indices23,
8413             attributes23,
8414             num_vertices23,
8415             num_faces23,
8416             options,
8417             declaration_texcoord_float16_2,
8418             vertex_size_texcoord_float16_2,
8419             flags23,
8420             &epsilons23,
8421             adjacency23,
8422             (BYTE*)exp_vertices23,
8423             exp_indices23,
8424             exp_face_remap23,
8425             exp_vertex_remap23,
8426             exp_new_num_vertices23
8427         },
8428         {
8429             (BYTE*)vertices24,
8430             indices24,
8431             attributes24,
8432             num_vertices24,
8433             num_faces24,
8434             options,
8435             declaration_texcoord_float16_4,
8436             vertex_size_texcoord_float16_4,
8437             flags24,
8438             &epsilons24,
8439             adjacency24,
8440             (BYTE*)exp_vertices24,
8441             exp_indices24,
8442             exp_face_remap24,
8443             exp_vertex_remap24,
8444             exp_new_num_vertices24
8445         },
8446         {
8447             (BYTE*)vertices25,
8448             indices25,
8449             attributes25,
8450             num_vertices25,
8451             num_faces25,
8452             options,
8453             declaration_texcoord10,
8454             vertex_size_texcoord,
8455             flags25,
8456             &epsilons25,
8457             adjacency25,
8458             (BYTE*)exp_vertices25,
8459             exp_indices25,
8460             exp_face_remap25,
8461             exp_vertex_remap25,
8462             exp_new_num_vertices25
8463         },
8464         {
8465             (BYTE*)vertices26,
8466             indices26,
8467             attributes26,
8468             num_vertices26,
8469             num_faces26,
8470             options,
8471             declaration_color2,
8472             vertex_size_color,
8473             flags26,
8474             &epsilons26,
8475             adjacency26,
8476             (BYTE*)exp_vertices26,
8477             exp_indices26,
8478             exp_face_remap26,
8479             exp_vertex_remap26,
8480             exp_new_num_vertices26
8481         },
8482         {
8483             (BYTE*)vertices27,
8484             indices27,
8485             attributes27,
8486             num_vertices27,
8487             num_faces27,
8488             options,
8489             declaration_color1,
8490             vertex_size_color,
8491             flags27,
8492             &epsilons27,
8493             adjacency27,
8494             (BYTE*)exp_vertices27,
8495             exp_indices27,
8496             exp_face_remap27,
8497             exp_vertex_remap27,
8498             exp_new_num_vertices27
8499         },
8500         {
8501             (BYTE*)vertices28,
8502             indices28,
8503             attributes28,
8504             num_vertices28,
8505             num_faces28,
8506             options,
8507             declaration_normal_udec3,
8508             vertex_size_normal_udec3,
8509             flags28,
8510             &epsilons28,
8511             adjacency28,
8512             (BYTE*)exp_vertices28,
8513             exp_indices28,
8514             exp_face_remap28,
8515             exp_vertex_remap28,
8516             exp_new_num_vertices28
8517         },
8518         {
8519             (BYTE*)vertices29,
8520             indices29,
8521             attributes29,
8522             num_vertices29,
8523             num_faces29,
8524             options,
8525             declaration_normal_dec3n,
8526             vertex_size_normal_dec3n,
8527             flags29,
8528             &epsilons29,
8529             adjacency29,
8530             (BYTE*)exp_vertices29,
8531             exp_indices29,
8532             exp_face_remap29,
8533             exp_vertex_remap29,
8534             exp_new_num_vertices29
8535         }
8536     };
8537 #ifdef __REACTOS__
8538 #undef up
8539 #endif
8540 
8541     test_context = new_test_context();
8542     if (!test_context)
8543     {
8544         skip("Couldn't create test context\n");
8545         goto cleanup;
8546     }
8547 
8548     for (i = 0; i < ARRAY_SIZE(tc); i++)
8549     {
8550         DWORD j;
8551         DWORD *vertex_remap_ptr;
8552         DWORD new_num_vertices;
8553 
8554         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
8555                             tc[i].declaration, test_context->device, &mesh,
8556                             tc[i].vertices, tc[i].vertex_size,
8557                             tc[i].indices, tc[i].attributes);
8558         if (FAILED(hr))
8559         {
8560             skip("Couldn't initialize test mesh %d.\n", i);
8561             goto cleanup;
8562         }
8563 
8564         /* Allocate out parameters */
8565         adjacency_out = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency_out));
8566         if (!adjacency_out)
8567         {
8568             skip("Couldn't allocate adjacency_out array.\n");
8569             goto cleanup;
8570         }
8571         face_remap = HeapAlloc(GetProcessHeap(), 0, tc[i].num_faces * sizeof(*face_remap));
8572         if (!face_remap)
8573         {
8574             skip("Couldn't allocate face_remap array.\n");
8575             goto cleanup;
8576         }
8577 
8578         hr = D3DXWeldVertices(mesh, tc[i].flags, tc[i].epsilons, tc[i].adjacency,
8579                               adjacency_out, face_remap, &vertex_remap);
8580         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
8581         /* Check number of vertices*/
8582         new_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
8583         ok(new_num_vertices == tc[i].exp_new_num_vertices,
8584            "Mesh %d: new_num_vertices == %d, expected %d.\n",
8585            i, new_num_vertices, tc[i].exp_new_num_vertices);
8586         /* Check index buffer */
8587         if (tc[i].options & D3DXMESH_32BIT)
8588         {
8589             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices);
8590             if (FAILED(hr))
8591             {
8592                 skip("Couldn't lock index buffer.\n");
8593                 goto cleanup;
8594             }
8595             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8596             {
8597                 ok(indices[j] == tc[i].exp_indices[j],
8598                    "Mesh %d: indices[%d] == %d, expected %d\n",
8599                    i, j, indices[j], tc[i].exp_indices[j]);
8600             }
8601         }
8602         else
8603         {
8604             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices_16bit);
8605             if (FAILED(hr))
8606             {
8607                 skip("Couldn't lock index buffer.\n");
8608                 goto cleanup;
8609             }
8610             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8611             {
8612                 ok(indices_16bit[j] == tc[i].exp_indices[j],
8613                    "Mesh %d: indices_16bit[%d] == %d, expected %d\n",
8614                    i, j, indices_16bit[j], tc[i].exp_indices[j]);
8615             }
8616         }
8617         mesh->lpVtbl->UnlockIndexBuffer(mesh);
8618         indices = NULL;
8619         indices_16bit = NULL;
8620         /* Check adjacency_out */
8621         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8622         {
8623             ok(adjacency_out[j] == tc[i].adjacency[j],
8624                "Mesh %d: adjacency_out[%d] == %d, expected %d\n",
8625                i, j, adjacency_out[j], tc[i].adjacency[j]);
8626         }
8627         /* Check face_remap */
8628         for (j = 0; j < tc[i].num_faces; j++)
8629         {
8630             ok(face_remap[j] == tc[i].exp_face_remap[j],
8631                "Mesh %d: face_remap[%d] == %d, expected %d\n",
8632                i, j, face_remap[j], tc[i].exp_face_remap[j]);
8633         }
8634         /* Check vertex_remap */
8635         vertex_remap_ptr = vertex_remap->lpVtbl->GetBufferPointer(vertex_remap);
8636         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8637         {
8638             ok(vertex_remap_ptr[j] == tc[i].exp_vertex_remap[j],
8639                "Mesh %d: vertex_remap_ptr[%d] == %d, expected %d\n",
8640                i, j, vertex_remap_ptr[j], tc[i].exp_vertex_remap[j]);
8641         }
8642         /* Check vertex buffer */
8643         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void*)&vertices);
8644         if (FAILED(hr))
8645         {
8646             skip("Couldn't lock vertex buffer.\n");
8647             goto cleanup;
8648         }
8649         /* Check contents of re-ordered vertex buffer */
8650         for (j = 0; j < tc[i].exp_new_num_vertices; j++)
8651         {
8652             int index = tc[i].vertex_size*j;
8653             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].declaration);
8654         }
8655         mesh->lpVtbl->UnlockVertexBuffer(mesh);
8656         vertices = NULL;
8657 
8658         /* Free mesh and output data */
8659         HeapFree(GetProcessHeap(), 0, adjacency_out);
8660         adjacency_out = NULL;
8661         HeapFree(GetProcessHeap(), 0, face_remap);
8662         face_remap = NULL;
8663         vertex_remap->lpVtbl->Release(vertex_remap);
8664         vertex_remap = NULL;
8665         mesh->lpVtbl->Release(mesh);
8666         mesh = NULL;
8667     }
8668 
8669 cleanup:
8670     HeapFree(GetProcessHeap(), 0, adjacency_out);
8671     HeapFree(GetProcessHeap(), 0, face_remap);
8672     if (indices) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8673     if (indices_16bit) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8674     if (mesh) mesh->lpVtbl->Release(mesh);
8675     if (vertex_remap) vertex_remap->lpVtbl->Release(vertex_remap);
8676     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
8677     free_test_context(test_context);
8678 }
8679 
8680 static void test_clone_mesh(void)
8681 {
8682     HRESULT hr;
8683     struct test_context *test_context = NULL;
8684     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
8685     D3DVERTEXELEMENT9 declaration_pn[] =
8686     {
8687         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8688         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8689         D3DDECL_END()
8690     };
8691     D3DVERTEXELEMENT9 declaration_pntc[] =
8692     {
8693         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8694         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8695         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8696         D3DDECL_END()
8697     };
8698     D3DVERTEXELEMENT9 declaration_ptcn[] =
8699     {
8700         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8701         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8702         {0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8703         D3DDECL_END()
8704     };
8705     D3DVERTEXELEMENT9 declaration_ptc[] =
8706     {
8707         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8708         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8709         D3DDECL_END()
8710     };
8711     D3DVERTEXELEMENT9 declaration_ptc_float16_2[] =
8712     {
8713         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8714         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8715         D3DDECL_END()
8716     };
8717     D3DVERTEXELEMENT9 declaration_ptc_float16_4[] =
8718     {
8719         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8720         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8721         D3DDECL_END()
8722     };
8723     D3DVERTEXELEMENT9 declaration_ptc_float1[] =
8724     {
8725         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8726         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8727         D3DDECL_END()
8728     };
8729     D3DVERTEXELEMENT9 declaration_ptc_float3[] =
8730     {
8731         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8732         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8733         D3DDECL_END()
8734     };
8735     D3DVERTEXELEMENT9 declaration_ptc_float4[] =
8736     {
8737         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8738         {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8739         D3DDECL_END()
8740     };
8741     D3DVERTEXELEMENT9 declaration_ptc_d3dcolor[] =
8742     {
8743         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8744         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8745         D3DDECL_END()
8746     };
8747     D3DVERTEXELEMENT9 declaration_ptc_ubyte4[] =
8748     {
8749         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8750         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8751         D3DDECL_END()
8752     };
8753     D3DVERTEXELEMENT9 declaration_ptc_ubyte4n[] =
8754     {
8755         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8756         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8757         D3DDECL_END()
8758     };
8759     D3DVERTEXELEMENT9 declaration_ptc_short2[] =
8760     {
8761         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8762         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8763         D3DDECL_END()
8764     };
8765     D3DVERTEXELEMENT9 declaration_ptc_short4[] =
8766     {
8767         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8768         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8769         D3DDECL_END()
8770     };
8771     D3DVERTEXELEMENT9 declaration_ptc_short2n[] =
8772     {
8773         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8774         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8775         D3DDECL_END()
8776     };
8777     D3DVERTEXELEMENT9 declaration_ptc_short4n[] =
8778     {
8779         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8780         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8781         D3DDECL_END()
8782     };
8783     D3DVERTEXELEMENT9 declaration_ptc_ushort2n[] =
8784     {
8785         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8786         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8787         D3DDECL_END()
8788     };
8789     D3DVERTEXELEMENT9 declaration_ptc_ushort4n[] =
8790     {
8791         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8792         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8793         D3DDECL_END()
8794     };
8795     D3DVERTEXELEMENT9 declaration_ptc_float16_2_partialu[] =
8796     {
8797         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8798         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_PARTIALU, D3DDECLUSAGE_TEXCOORD, 0},
8799         D3DDECL_END()
8800     };
8801     D3DVERTEXELEMENT9 declaration_pntc1[] =
8802     {
8803         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8804         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8805         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
8806         D3DDECL_END()
8807     };
8808     const unsigned int VERTS_PER_FACE = 3;
8809     BYTE *vertices = NULL;
8810     INT i;
8811     struct vertex_pn
8812     {
8813         D3DXVECTOR3 position;
8814         D3DXVECTOR3 normal;
8815     };
8816     struct vertex_pntc
8817     {
8818         D3DXVECTOR3 position;
8819         D3DXVECTOR3 normal;
8820         D3DXVECTOR2 texcoords;
8821     };
8822     struct vertex_ptcn
8823     {
8824         D3DXVECTOR3 position;
8825         D3DXVECTOR2 texcoords;
8826         D3DXVECTOR3 normal;
8827     };
8828     struct vertex_ptc
8829     {
8830         D3DXVECTOR3 position;
8831         D3DXVECTOR2 texcoords;
8832     };
8833     struct vertex_ptc_float16_2
8834     {
8835         D3DXVECTOR3 position;
8836         WORD texcoords[2]; /* float16_2 */
8837     };
8838     struct vertex_ptc_float16_4
8839     {
8840         D3DXVECTOR3 position;
8841         WORD texcoords[4]; /* float16_4 */
8842     };
8843     struct vertex_ptc_float1
8844     {
8845         D3DXVECTOR3 position;
8846         FLOAT texcoords;
8847     };
8848     struct vertex_ptc_float3
8849     {
8850         D3DXVECTOR3 position;
8851         FLOAT texcoords[3];
8852     };
8853     struct vertex_ptc_float4
8854     {
8855         D3DXVECTOR3 position;
8856         FLOAT texcoords[4];
8857     };
8858     struct vertex_ptc_d3dcolor
8859     {
8860         D3DXVECTOR3 position;
8861         BYTE texcoords[4];
8862     };
8863     struct vertex_ptc_ubyte4
8864     {
8865         D3DXVECTOR3 position;
8866         BYTE texcoords[4];
8867     };
8868     struct vertex_ptc_ubyte4n
8869     {
8870         D3DXVECTOR3 position;
8871         BYTE texcoords[4];
8872     };
8873     struct vertex_ptc_short2
8874     {
8875         D3DXVECTOR3 position;
8876         SHORT texcoords[2];
8877     };
8878     struct vertex_ptc_short4
8879     {
8880         D3DXVECTOR3 position;
8881         SHORT texcoords[4];
8882     };
8883     struct vertex_ptc_ushort2n
8884     {
8885         D3DXVECTOR3 position;
8886         USHORT texcoords[2];
8887     };
8888     struct vertex_ptc_ushort4n
8889     {
8890         D3DXVECTOR3 position;
8891         USHORT texcoords[4];
8892     };
8893     struct vertex_ptc_udec3
8894     {
8895         D3DXVECTOR3 position;
8896         DWORD texcoords;
8897     };
8898     struct vertex_ptc_dec3n
8899     {
8900         D3DXVECTOR3 position;
8901         DWORD texcoords;
8902     };
8903 #ifndef __REACTOS__
8904     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
8905     D3DXVECTOR2 zero_vec2 = {0.0f, 0.0f};
8906 #else
8907 #define up {0.0f, 0.0f, 1.0f}
8908 #define zero_vec2 {0.0f, 0.0f}
8909 #endif
8910     /* Test 0. Check that a mesh can be cloned if the new declaration is the
8911      * same as the one used to create the mesh.
8912      *
8913      * 0--1 3
8914      * | / /|
8915      * |/ / |
8916      * 2 5--4
8917      */
8918     const struct vertex_pn vertices0[] =
8919     {
8920         {{ 0.0f,  3.0f,  0.f}, up},
8921         {{ 2.0f,  3.0f,  0.f}, up},
8922         {{ 0.0f,  0.0f,  0.f}, up},
8923 
8924         {{ 3.0f,  3.0f,  0.f}, up},
8925         {{ 3.0f,  0.0f,  0.f}, up},
8926         {{ 1.0f,  0.0f,  0.f}, up},
8927     };
8928     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
8929     const UINT num_faces0 = ARRAY_SIZE(vertices0) / VERTS_PER_FACE;
8930     const UINT vertex_size0 = sizeof(*vertices0);
8931     /* Test 1. Check that 16-bit indices are handled. */
8932     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
8933     /* Test 2. Check that the size of each vertex is increased and the data
8934      * moved if the new declaration adds an element after the original elements.
8935      */
8936     const struct vertex_pntc exp_vertices2[] =
8937     {
8938         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8939         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8940         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8941 
8942         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8943         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8944         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8945     };
8946     const UINT exp_vertex_size2 = sizeof(*exp_vertices2);
8947     /* Test 3. Check that the size of each vertex is increased and the data
8948      * moved if the new declaration adds an element between the original
8949      * elements.
8950      */
8951     const struct vertex_ptcn exp_vertices3[] =
8952     {
8953         {{ 0.0f,  3.0f,  0.f}, zero_vec2, up},
8954         {{ 2.0f,  3.0f,  0.f}, zero_vec2, up},
8955         {{ 0.0f,  0.0f,  0.f}, zero_vec2, up},
8956 
8957         {{ 3.0f,  3.0f,  0.f}, zero_vec2, up},
8958         {{ 3.0f,  0.0f,  0.f}, zero_vec2, up},
8959         {{ 1.0f,  0.0f,  0.f}, zero_vec2, up},
8960     };
8961     const UINT exp_vertex_size3 = sizeof(*exp_vertices3);
8962     /* Test 4. Test that data types can be converted, e.g. FLOAT2 to FLOAT16_2. */
8963     const struct vertex_ptc vertices4[] =
8964     {
8965         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8966         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8967         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8968 
8969         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8970         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8971         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8972     };
8973     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
8974     const UINT num_faces4 = ARRAY_SIZE(vertices4) / VERTS_PER_FACE;
8975     const UINT vertex_size4 = sizeof(*vertices4);
8976     const struct vertex_ptc_float16_2 exp_vertices4[] =
8977     {
8978         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8979         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
8980         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
8981 
8982         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
8983         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8984         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
8985     };
8986     const UINT exp_vertex_size4 = sizeof(*exp_vertices4);
8987     /* Test 5. Convert FLOAT2 to FLOAT16_4. */
8988     const struct vertex_ptc vertices5[] =
8989     {
8990         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8991         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8992         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8993 
8994         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8995         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8996         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8997     };
8998     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
8999     const UINT num_faces5 = ARRAY_SIZE(vertices5) / VERTS_PER_FACE;
9000     const UINT vertex_size5 = sizeof(*vertices5);
9001     const struct vertex_ptc_float16_4 exp_vertices5[] =
9002     {
9003         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
9004         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0, 0x3c00}}, /* {0.5f, 0.7f, 0.0f, 1.0f} */
9005         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0, 0x3c00}}, /* {-0.2f, -0.3f, 0.0f, 1.0f} */
9006 
9007         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0, 0x3c00}}, /* {0.2f, 0.3f, 0.0f, 1.0f} */
9008         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
9009         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0, 0x3c00}}, /* {0.1f, 0.2f, 0.0f, 1.0f} */
9010     };
9011     const UINT exp_vertex_size5 = sizeof(*exp_vertices5);
9012     /* Test 6. Convert FLOAT2 to FLOAT1. */
9013     const struct vertex_ptc vertices6[] =
9014     {
9015         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9016         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9017         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
9018 
9019         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9020         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
9021         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
9022     };
9023     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
9024     const UINT num_faces6 = ARRAY_SIZE(vertices6) / VERTS_PER_FACE;
9025     const UINT vertex_size6 = sizeof(*vertices6);
9026     const struct vertex_ptc_float1 exp_vertices6[] =
9027     {
9028         {{ 0.0f,  3.0f,  0.f},  1.0f},
9029         {{ 2.0f,  3.0f,  0.f},  0.5f},
9030         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9031 
9032         {{ 3.0f,  3.0f,  0.f},  0.2f},
9033         {{ 3.0f,  0.0f,  0.f},  1.0f},
9034         {{ 1.0f,  0.0f,  0.f},  0.1f},
9035     };
9036     const UINT exp_vertex_size6 = sizeof(*exp_vertices6);
9037     /* Test 7. Convert FLOAT2 to FLOAT3. */
9038     const struct vertex_ptc vertices7[] =
9039     {
9040         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9041         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9042         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
9043 
9044         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9045         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
9046         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
9047     };
9048     const UINT num_vertices7 = ARRAY_SIZE(vertices7);
9049     const UINT num_faces7 = ARRAY_SIZE(vertices7) / VERTS_PER_FACE;
9050     const UINT vertex_size7 = sizeof(*vertices7);
9051     const struct vertex_ptc_float3 exp_vertices7[] =
9052     {
9053         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
9054         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f}},
9055         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f}},
9056 
9057         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f}},
9058         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
9059         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f}},
9060     };
9061     const UINT exp_vertex_size7 = sizeof(*exp_vertices7);
9062     /* Test 8. Convert FLOAT2 to FLOAT4. */
9063     const struct vertex_ptc vertices8[] =
9064     {
9065         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9066         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9067         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
9068 
9069         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9070         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
9071         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
9072     };
9073     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
9074     const UINT num_faces8 = ARRAY_SIZE(vertices8) / VERTS_PER_FACE;
9075     const UINT vertex_size8 = sizeof(*vertices8);
9076     const struct vertex_ptc_float4 exp_vertices8[] =
9077     {
9078         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
9079         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f, 1.0f}},
9080         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f, 1.0f}},
9081 
9082         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f, 1.0f}},
9083         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
9084         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f, 1.0f}},
9085     };
9086     const UINT exp_vertex_size8 = sizeof(*exp_vertices8);
9087     /* Test 9. Convert FLOAT2 to D3DCOLOR. */
9088     const struct vertex_ptc vertices9[] =
9089     {
9090         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9091         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9092         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.6f}},
9093 
9094         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9095         {{ 3.0f,  0.0f,  0.f}, { 2.0f, 256.0f}},
9096         {{ 1.0f,  0.0f,  0.f}, { 0.11f,  0.2f}},
9097     };
9098     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
9099     const UINT num_faces9 = ARRAY_SIZE(vertices9) / VERTS_PER_FACE;
9100     const UINT vertex_size9 = sizeof(*vertices9);
9101     const struct vertex_ptc_d3dcolor exp_vertices9[] =
9102     {
9103         {{ 0.0f,  3.0f,  0.f}, {0, 255, 255, 255}},
9104         {{ 2.0f,  3.0f,  0.f}, {0, 179, 128, 255}},
9105         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9106 
9107         {{ 3.0f,  3.0f,  0.f}, {0, 77, 51, 255}},
9108         {{ 3.0f,  0.0f,  0.f}, {0, 255, 255, 255}},
9109         {{ 1.0f,  0.0f,  0.f}, {0, 51, 28, 255}},
9110     };
9111     const UINT exp_vertex_size9 = sizeof(*exp_vertices9);
9112     /* Test 10. Convert FLOAT2 to UBYTE4. */
9113     const struct vertex_ptc vertices10[] =
9114     {
9115         {{ 0.0f,  3.0f,  0.f}, { 0.0f,  1.0f}},
9116         {{ 2.0f,  3.0f,  0.f}, { 2.0f,  3.0f}},
9117         {{ 0.0f,  0.0f,  0.f}, { 254.0f,  255.0f}},
9118 
9119         {{ 3.0f,  3.0f,  0.f}, { 256.0f, 257.0f}},
9120         {{ 3.0f,  0.0f,  0.f}, { 1.4f, 1.5f}},
9121         {{ 1.0f,  0.0f,  0.f}, {-4.0f, -5.0f}},
9122     };
9123     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
9124     const UINT num_faces10 = ARRAY_SIZE(vertices10) / VERTS_PER_FACE;
9125     const UINT vertex_size10 = sizeof(*vertices10);
9126     const struct vertex_ptc_ubyte4 exp_vertices10[] =
9127     {
9128         {{ 0.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9129         {{ 2.0f,  3.0f,  0.f}, {2, 3, 0, 1}},
9130         {{ 0.0f,  0.0f,  0.f}, {254, 255, 0, 1}},
9131 
9132         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9133         {{ 3.0f,  0.0f,  0.f}, {1, 2, 0, 1}},
9134         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9135     };
9136     const UINT exp_vertex_size10 = sizeof(*exp_vertices10);
9137     /* Test 11. Convert FLOAT2 to SHORT2. */
9138     const struct vertex_ptc vertices11[] =
9139     {
9140         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
9141         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
9142         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
9143 
9144         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9145         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
9146         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
9147 
9148         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
9149         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
9150         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
9151     };
9152     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
9153     const UINT num_faces11 = ARRAY_SIZE(vertices11) / VERTS_PER_FACE;
9154     const UINT vertex_size11 = sizeof(*vertices11);
9155     const struct vertex_ptc_short2 exp_vertices11[] =
9156     {
9157         {{ 0.0f,  3.0f,  0.f}, {1, 0}},
9158         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9159         {{ 0.0f,  0.0f,  0.f}, {0, -4}},
9160 
9161         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1}},
9162         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN}},
9163         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
9164 
9165         {{ 4.0f,  3.0f,  0.f}, {-2, 1}},
9166         {{ 6.0f,  0.0f,  0.f}, {32765, -32767}},
9167         {{ 4.0f,  0.0f,  0.f}, {-4, 1}},
9168     };
9169     const UINT exp_vertex_size11 = sizeof(*exp_vertices11);
9170     /* Test 12. Convert FLOAT2 to SHORT4. */
9171     const struct vertex_ptc vertices12[] =
9172     {
9173         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
9174         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
9175         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
9176 
9177         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9178         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
9179         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
9180 
9181         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
9182         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
9183         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
9184     };
9185     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
9186     const UINT num_faces12 = ARRAY_SIZE(vertices12) / VERTS_PER_FACE;
9187     const UINT vertex_size12 = sizeof(*vertices12);
9188     const struct vertex_ptc_short4 exp_vertices12[] =
9189     {
9190         {{ 0.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
9191         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9192         {{ 0.0f,  0.0f,  0.f}, {0, -4, 0, 1}},
9193 
9194         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1, 0, 1}},
9195         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN, 0, 1}},
9196         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, 0, 1}},
9197 
9198         {{ 4.0f,  3.0f,  0.f}, {-2, 1, 0, 1}},
9199         {{ 6.0f,  0.0f,  0.f}, {32765, -32767, 0, 1}},
9200         {{ 4.0f,  0.0f,  0.f}, {-4, 1, 0, 1}},
9201     };
9202     const UINT exp_vertex_size12 = sizeof(*exp_vertices12);
9203     /* Test 13. Convert FLOAT2 to UBYTE4N. */
9204     const struct vertex_ptc vertices13[] =
9205     {
9206         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  2.0f}},
9207         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9208         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.5f}},
9209 
9210         {{ 3.0f,  3.0f,  0.f}, {-0.6f,  -1.0f}},
9211         {{ 3.0f,  0.0f,  0.f}, {UCHAR_MAX,  UCHAR_MAX + 1}},
9212         {{ 1.0f,  0.0f,  0.f}, {2 * UCHAR_MAX, -UCHAR_MAX}},
9213     };
9214     const UINT num_vertices13 = ARRAY_SIZE(vertices13);
9215     const UINT num_faces13 = ARRAY_SIZE(vertices13) / VERTS_PER_FACE;
9216     const UINT vertex_size13 = sizeof(*vertices13);
9217     const struct vertex_ptc_ubyte4n exp_vertices13[] =
9218     {
9219         {{ 0.0f,  3.0f,  0.f}, {255, 255, 0, 255}},
9220         {{ 2.0f,  3.0f,  0.f}, {128, 179, 0, 255}},
9221         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9222 
9223         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, 255}},
9224         {{ 3.0f,  0.0f,  0.f}, {255, 255, 0, 255}},
9225         {{ 1.0f,  0.0f,  0.f}, {255, 0, 0, 255}},
9226     };
9227     const UINT exp_vertex_size13 = sizeof(*exp_vertices13);
9228     /* Test 14. Convert FLOAT2 to SHORT2N. */
9229     const struct vertex_ptc vertices14[] =
9230     {
9231         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9232         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9233         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9234 
9235         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9236         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
9237         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9238     };
9239     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
9240     const UINT num_faces14 = ARRAY_SIZE(vertices14) / VERTS_PER_FACE;
9241     const UINT vertex_size14 = sizeof(*vertices14);
9242     const struct vertex_ptc_short2 exp_vertices14[] =
9243     {
9244         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX}},
9245         {{ 2.0f,  3.0f,  0.f}, {13107, 16384}},
9246         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2}},
9247 
9248         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383}},
9249         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3}},
9250         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2}},
9251     };
9252     const UINT exp_vertex_size14 = sizeof(*exp_vertices14);
9253     /* Test 15. Convert FLOAT2 to SHORT4N. */
9254     const struct vertex_ptc vertices15[] =
9255     {
9256         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9257         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9258         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9259 
9260         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9261         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
9262         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9263     };
9264     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
9265     const UINT num_faces15 = ARRAY_SIZE(vertices15) / VERTS_PER_FACE;
9266     const UINT vertex_size15 = sizeof(*vertices15);
9267     const struct vertex_ptc_short4 exp_vertices15[] =
9268     {
9269         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX, 0, SHRT_MAX}},
9270         {{ 2.0f,  3.0f,  0.f}, {13107, 16384, 0, SHRT_MAX}},
9271         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2, 0, SHRT_MAX}},
9272 
9273         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383, 0, SHRT_MAX}},
9274         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3, 0, SHRT_MAX}},
9275         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2, 0, SHRT_MAX}},
9276     };
9277     const UINT exp_vertex_size15 = sizeof(*exp_vertices15);
9278     /* Test 16. Convert FLOAT2 to USHORT2N. */
9279     const struct vertex_ptc vertices16[] =
9280     {
9281         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9282         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9283         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9284 
9285         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9286         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
9287         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
9288     };
9289     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
9290     const UINT num_faces16 = ARRAY_SIZE(vertices16) / VERTS_PER_FACE;
9291     const UINT vertex_size16 = sizeof(*vertices16);
9292     const struct vertex_ptc_ushort2n exp_vertices16[] =
9293     {
9294         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX}},
9295         {{ 2.0f,  3.0f,  0.f}, {26214, 32768}},
9296         {{ 0.0f,  0.0f,  0.f}, {39321, 0}},
9297 
9298         {{ 3.0f,  3.0f,  0.f}, {0, 0}},
9299         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1}},
9300         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0}},
9301     };
9302     const UINT exp_vertex_size16 = sizeof(*exp_vertices16);
9303     /* Test 17. Convert FLOAT2 to USHORT4N. */
9304     const struct vertex_ptc vertices17[] =
9305     {
9306         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9307         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9308         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9309 
9310         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9311         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
9312         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
9313     };
9314     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
9315     const UINT num_faces17 = ARRAY_SIZE(vertices17) / VERTS_PER_FACE;
9316     const UINT vertex_size17 = sizeof(*vertices17);
9317     const struct vertex_ptc_ushort4n exp_vertices17[] =
9318     {
9319         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX, 0, USHRT_MAX}},
9320         {{ 2.0f,  3.0f,  0.f}, {26214, 32768, 0, USHRT_MAX}},
9321         {{ 0.0f,  0.0f,  0.f}, {39321, 0, 0, USHRT_MAX}},
9322 
9323         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, USHRT_MAX}},
9324         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1, 0, USHRT_MAX}},
9325         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0, 0, USHRT_MAX}},
9326     };
9327     const UINT exp_vertex_size17 = sizeof(*exp_vertices17);
9328     /* Test 18. Test that the method field is compared by converting a FLOAT2 to
9329      * FLOAT16_2. where the method field has been change from
9330      * D3DDECLMETHOD_DEFAULT to D3DDECLMETHOD_PARTIALU. */
9331     const struct vertex_ptc vertices18[] =
9332     {
9333         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9334         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9335         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
9336 
9337         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9338         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
9339         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
9340     };
9341     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
9342     const UINT num_faces18 = ARRAY_SIZE(vertices18) / VERTS_PER_FACE;
9343     const UINT vertex_size18 = sizeof(*vertices18);
9344     const struct vertex_ptc_float16_2 exp_vertices18[] =
9345     {
9346         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9347         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9348         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9349 
9350         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9351         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9352         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9353     };
9354     const UINT exp_vertex_size18 = sizeof(*exp_vertices18);
9355     /* Test 19. Test that data is lost if usage index changes, e.g. TEXCOORD0
9356      * TEXCOORD1. */
9357     const struct vertex_pntc vertices19[] =
9358     {
9359         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
9360         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
9361         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
9362 
9363         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
9364         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
9365         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
9366     };
9367     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
9368     const UINT num_faces19 = ARRAY_SIZE(vertices19) / VERTS_PER_FACE;
9369     const UINT vertex_size19 = sizeof(*vertices19);
9370     const struct vertex_pntc exp_vertices19[] =
9371     {
9372         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
9373         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
9374         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
9375 
9376         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
9377         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
9378         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
9379     };
9380     const UINT exp_vertex_size19 = sizeof(*exp_vertices19);
9381     /* Test 20. Another test that data is lost if usage index changes, e.g.
9382      * TEXCOORD1 to TEXCOORD0. */
9383     const struct vertex_pntc vertices20[] =
9384     {
9385         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
9386         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
9387         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
9388 
9389         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
9390         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
9391         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
9392     };
9393     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
9394     const UINT num_faces20 = ARRAY_SIZE(vertices20) / VERTS_PER_FACE;
9395     const UINT vertex_size20 = sizeof(*vertices20);
9396     const struct vertex_pntc exp_vertices20[] =
9397     {
9398         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
9399         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
9400         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
9401 
9402         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
9403         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
9404         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
9405     };
9406     const UINT exp_vertex_size20 = sizeof(*exp_vertices20);
9407     /* Test 21. Convert FLOAT1 to FLOAT2. */
9408     const struct vertex_ptc_float1 vertices21[] =
9409     {
9410         {{ 0.0f,  3.0f,  0.f},  1.0f},
9411         {{ 2.0f,  3.0f,  0.f},  0.5f},
9412         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9413 
9414         {{ 3.0f,  3.0f,  0.f},  0.2f},
9415         {{ 3.0f,  0.0f,  0.f},  1.0f},
9416         {{ 1.0f,  0.0f,  0.f},  0.1f},
9417     };
9418     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
9419     const UINT num_faces21 = ARRAY_SIZE(vertices21) / VERTS_PER_FACE;
9420     const UINT vertex_size21 = sizeof(*vertices21);
9421     const struct vertex_ptc exp_vertices21[] =
9422     {
9423         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f}},
9424         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f}},
9425         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f}},
9426 
9427         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f}},
9428         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f}},
9429         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f}},
9430     };
9431     const UINT exp_vertex_size21 = sizeof(*exp_vertices21);
9432     /* Test 22. Convert FLOAT1 to FLOAT3. */
9433     const struct vertex_ptc_float1 vertices22[] =
9434     {
9435         {{ 0.0f,  3.0f,  0.f},  1.0f},
9436         {{ 2.0f,  3.0f,  0.f},  0.5f},
9437         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9438 
9439         {{ 3.0f,  3.0f,  0.f},  0.2f},
9440         {{ 3.0f,  0.0f,  0.f},  1.0f},
9441         {{ 1.0f,  0.0f,  0.f},  0.1f},
9442     };
9443     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
9444     const UINT num_faces22 = ARRAY_SIZE(vertices22) / VERTS_PER_FACE;
9445     const UINT vertex_size22 = sizeof(*vertices22);
9446     const struct vertex_ptc_float3 exp_vertices22[] =
9447     {
9448         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
9449         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f}},
9450         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f}},
9451 
9452         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f}},
9453         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
9454         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f}},
9455     };
9456     const UINT exp_vertex_size22 = sizeof(*exp_vertices22);
9457     /* Test 23. Convert FLOAT1 to FLOAT4. */
9458     const struct vertex_ptc_float1 vertices23[] =
9459     {
9460         {{ 0.0f,  3.0f,  0.f},  1.0f},
9461         {{ 2.0f,  3.0f,  0.f},  0.5f},
9462         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9463 
9464         {{ 3.0f,  3.0f,  0.f},  0.2f},
9465         {{ 3.0f,  0.0f,  0.f},  1.0f},
9466         {{ 1.0f,  0.0f,  0.f},  0.1f},
9467     };
9468     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
9469     const UINT num_faces23 = ARRAY_SIZE(vertices23) / VERTS_PER_FACE;
9470     const UINT vertex_size23 = sizeof(*vertices23);
9471     const struct vertex_ptc_float4 exp_vertices23[] =
9472     {
9473         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
9474         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f, 1.0f}},
9475         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f, 1.0f}},
9476 
9477         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f, 1.0f}},
9478         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
9479         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f, 1.0f}},
9480     };
9481     const UINT exp_vertex_size23 = sizeof(*exp_vertices23);
9482     /* Test 24. Convert FLOAT1 to D3DCOLOR. */
9483     const struct vertex_ptc_float1 vertices24[] =
9484     {
9485         {{ 0.0f,  3.0f,  0.f},  1.0f},
9486         {{ 2.0f,  3.0f,  0.f},  0.5f},
9487         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9488 
9489         {{ 3.0f,  3.0f,  0.f},  0.2f},
9490         {{ 3.0f,  0.0f,  0.f},  1.0f},
9491         {{ 1.0f,  0.0f,  0.f},  0.11f},
9492     };
9493     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
9494     const UINT num_faces24 = ARRAY_SIZE(vertices24) / VERTS_PER_FACE;
9495     const UINT vertex_size24 = sizeof(*vertices24);
9496     const struct vertex_ptc_d3dcolor exp_vertices24[] =
9497     {
9498         {{ 0.0f,  3.0f,  0.f}, {0, 0, 255, 255}},
9499         {{ 2.0f,  3.0f,  0.f}, {0, 0, 128, 255}},
9500         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9501 
9502         {{ 3.0f,  3.0f,  0.f}, {0, 0, 51, 255}},
9503         {{ 3.0f,  0.0f,  0.f}, {0, 0, 255, 255}},
9504         {{ 1.0f,  0.0f,  0.f}, {0, 0, 28, 255}},
9505     };
9506     const UINT exp_vertex_size24 = sizeof(*exp_vertices24);
9507     /* Test 25. Convert FLOAT1 to ubyte4. */
9508     const struct vertex_ptc_float1 vertices25[] =
9509     {
9510         {{ 0.0f,  3.0f,  0.f}, 0.0f},
9511         {{ 2.0f,  3.0f,  0.f}, 1.4f},
9512         {{ 0.0f,  0.0f,  0.f}, 1.5f},
9513 
9514         {{ 3.0f,  3.0f,  0.f}, 255.0f},
9515         {{ 3.0f,  0.0f,  0.f}, 256.0f},
9516         {{ 1.0f,  0.0f,  0.f}, -1.0f},
9517     };
9518     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
9519     const UINT num_faces25 = ARRAY_SIZE(vertices25) / VERTS_PER_FACE;
9520     const UINT vertex_size25 = sizeof(*vertices25);
9521     const struct vertex_ptc_ubyte4 exp_vertices25[] =
9522     {
9523         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 1}},
9524         {{ 2.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
9525         {{ 0.0f,  0.0f,  0.f}, {2, 0, 0, 1}},
9526 
9527         {{ 3.0f,  3.0f,  0.f}, {255, 0, 0, 1}},
9528         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9529         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9530     };
9531     const UINT exp_vertex_size25 = sizeof(*exp_vertices25);
9532     /* Test 26. Convert FLOAT4 to D3DCOLOR. */
9533     const struct vertex_ptc_float4 vertices26[] =
9534     {
9535         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.5f}},
9536         {{ 2.0f,  3.0f,  0.f}, {-0.4f, -0.5f, -1.0f, -2.0f}},
9537         {{ 0.0f,  0.0f,  0.f}, {254.0f, 255.0f, 256.0f, 257.0f}},
9538 
9539         {{ 3.0f,  3.0f,  0.f}, {0.1f, 0.2f, 0.3f, 0.4f}},
9540         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.6f, 0.7f, 0.8f}},
9541         {{ 1.0f,  0.0f,  0.f}, {0.9f, 0.99f, 0.995f, 0.999f}},
9542     };
9543     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
9544     const UINT num_faces26 = ARRAY_SIZE(vertices26) / VERTS_PER_FACE;
9545     const UINT vertex_size26 = sizeof(*vertices26);
9546     const struct vertex_ptc_d3dcolor exp_vertices26[] =
9547     {
9548         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9549         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9550         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9551 
9552         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9553         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9554         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9555     };
9556     const UINT exp_vertex_size26 = sizeof(*exp_vertices26);
9557     /* Test 27. Convert D3DCOLOR to FLOAT4. */
9558     const struct vertex_ptc_d3dcolor vertices27[] =
9559     {
9560         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9561         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9562         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9563 
9564         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9565         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9566         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9567     };
9568     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
9569     const UINT num_faces27 = ARRAY_SIZE(vertices27) / VERTS_PER_FACE;
9570     const UINT vertex_size27 = sizeof(*vertices27);
9571     const struct vertex_ptc_float4 exp_vertices27[] =
9572     {
9573         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.501961f}},
9574         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9575         {{ 0.0f,  0.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9576 
9577         {{ 3.0f,  3.0f,  0.f}, {0.101961f, 0.2f, 0.301961f, 0.4f}},
9578         {{ 3.0f,  0.0f,  0.f}, {0.501961f, 0.6f, 0.701961f, 0.8f}},
9579         {{ 1.0f,  0.0f,  0.f}, {0.901961f, 0.988235f, 0.996078f, 1.0f}},
9580     };
9581     const UINT exp_vertex_size27 = sizeof(*exp_vertices27);
9582     /* Test 28. Convert UBYTE4 to FLOAT4. */
9583     const struct vertex_ptc_ubyte4 vertices28[] =
9584     {
9585         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9586         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9587         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9588 
9589         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9590         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9591         {{ 1.0f,  0.0f,  0.f}, {50, 60, 127, 255}},
9592     };
9593     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
9594     const UINT num_faces28 = ARRAY_SIZE(vertices28) / VERTS_PER_FACE;
9595     const UINT vertex_size28 = sizeof(*vertices28);
9596     const struct vertex_ptc_float4 exp_vertices28[] =
9597     {
9598         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9599         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9600         {{ 0.0f,  0.0f,  0.f}, {1.0f,  0.0f, 1.0f, 0.0f}},
9601 
9602         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9603         {{ 3.0f,  0.0f,  0.f}, {10.0f, 20.0f, 30.0f, 40.0f}},
9604         {{ 1.0f,  0.0f,  0.f}, {50.0f, 60.0f, 127.0f, 255.0f}},
9605     };
9606     const UINT exp_vertex_size28 = sizeof(*exp_vertices28);
9607     /* Test 29. Convert SHORT2 to FLOAT4. */
9608     const struct vertex_ptc_short2 vertices29[] =
9609     {
9610         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9611         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9612         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9613 
9614         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9615         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX}},
9616         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9617     };
9618     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
9619     const UINT num_faces29 = ARRAY_SIZE(vertices29) / VERTS_PER_FACE;
9620     const UINT vertex_size29 = sizeof(*vertices29);
9621     const struct vertex_ptc_float4 exp_vertices29[] =
9622     {
9623         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9624         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9625         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 0.0f, 1.0f}},
9626 
9627         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9628         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 0.0f, 1.0f}},
9629         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, 0.0f, 1.0f}},
9630     };
9631     const UINT exp_vertex_size29 = sizeof(*exp_vertices29);
9632     /* Test 29. Convert SHORT4 to FLOAT4. */
9633     const struct vertex_ptc_short4 vertices30[] =
9634     {
9635         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9636         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9637         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9638 
9639         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9640         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1, 0}},
9641         {{ 1.0f,  0.0f,  0.f}, {-42, 42, SHRT_MAX, SHRT_MIN}},
9642     };
9643     const UINT num_vertices30 = ARRAY_SIZE(vertices30);
9644     const UINT num_faces30 = ARRAY_SIZE(vertices30) / VERTS_PER_FACE;
9645     const UINT vertex_size30 = sizeof(*vertices30);
9646     const struct vertex_ptc_float4 exp_vertices30[] =
9647     {
9648         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9649         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9650         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9651 
9652         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9653         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1.0f, 0.0f}},
9654         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, SHRT_MAX, SHRT_MIN}},
9655     };
9656     const UINT exp_vertex_size30 = sizeof(*exp_vertices30);
9657     /* Test 31. Convert UBYTE4N to FLOAT4. */
9658     const struct vertex_ptc_ubyte4n vertices31[] =
9659     {
9660         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9661         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9662         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9663 
9664         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9665         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9666         {{ 1.0f,  0.0f,  0.f}, {50, 60, 70, UCHAR_MAX}},
9667     };
9668     const UINT num_vertices31 = ARRAY_SIZE(vertices31);
9669     const UINT num_faces31 = ARRAY_SIZE(vertices31) / VERTS_PER_FACE;
9670     const UINT vertex_size31 = sizeof(*vertices31);
9671     const struct vertex_ptc_float4 exp_vertices31[] =
9672     {
9673         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9674         {{ 2.0f,  3.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX}},
9675         {{ 0.0f,  0.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX, 0.0f}},
9676 
9677         {{ 3.0f,  3.0f,  0.f}, {0.0f, (FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX}},
9678         {{ 3.0f,  0.0f,  0.f}, {(FLOAT)10/UCHAR_MAX, (FLOAT)20/UCHAR_MAX, (FLOAT)30/UCHAR_MAX, (FLOAT)40/UCHAR_MAX}},
9679         {{ 1.0f,  0.0f,  0.f}, {(FLOAT)50/UCHAR_MAX, (FLOAT)60/UCHAR_MAX, (FLOAT)70/UCHAR_MAX, 1.0f}},
9680     };
9681     const UINT exp_vertex_size31 = sizeof(*exp_vertices31);
9682     /* Test 32. Convert SHORT2N to FLOAT4. */
9683     const struct vertex_ptc_short2 vertices32[] =
9684     {
9685         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9686         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9687         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9688 
9689         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9690         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
9691         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9692     };
9693     const UINT num_vertices32 = ARRAY_SIZE(vertices32);
9694     const UINT num_faces32 = ARRAY_SIZE(vertices32) / VERTS_PER_FACE;
9695     const UINT vertex_size32 = sizeof(*vertices32);
9696     const struct vertex_ptc_float4 exp_vertices32[] =
9697     {
9698         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9699         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9700         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 0.0f, 1.0f}},
9701 
9702         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9703         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, 0.0f, 1.0f}},
9704         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 0.0f, 1.0f}},
9705     };
9706     const UINT exp_vertex_size32 = sizeof(*exp_vertices32);
9707     /* Test 33. Convert SHORT4N to FLOAT4. */
9708     const struct vertex_ptc_short4 vertices33[] =
9709     {
9710         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9711         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9712         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9713 
9714         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9715         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, SHRT_MIN + 1, SHRT_MAX}},
9716         {{ 1.0f,  0.0f,  0.f}, {-42, 42, 1, 1}},
9717     };
9718     const UINT num_vertices33 = ARRAY_SIZE(vertices33);
9719     const UINT num_faces33 = ARRAY_SIZE(vertices33) / VERTS_PER_FACE;
9720     const UINT vertex_size33 = sizeof(*vertices33);
9721     const struct vertex_ptc_float4 exp_vertices33[] =
9722     {
9723         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9724         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX}},
9725         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX, 0.0f}},
9726 
9727         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9728         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, -1.0f, 1.0f}},
9729         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9730     };
9731     const UINT exp_vertex_size33 = sizeof(*exp_vertices33);
9732     /* Test 34. Convert FLOAT16_2 to FLOAT4. */
9733     const struct vertex_ptc_float16_2 vertices34[] =
9734     {
9735         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9736         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9737         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9738 
9739         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9740         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9741         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9742     };
9743     const UINT num_vertices34 = ARRAY_SIZE(vertices34);
9744     const UINT num_faces34 = ARRAY_SIZE(vertices34) / VERTS_PER_FACE;
9745     const UINT vertex_size34 = sizeof(*vertices34);
9746     const struct vertex_ptc_float4 exp_vertices34[] =
9747     {
9748         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9749         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.700195f, 0.0f, 1.0f}},
9750         {{ 0.0f,  0.0f,  0.f}, {-0.199951f, -0.300049f, 0.0f, 1.0f}},
9751 
9752         {{ 3.0f,  3.0f,  0.f}, {0.199951f, 0.300049f, 0.0f, 1.0f}},
9753         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9754         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.0f, 1.0f}},
9755     };
9756     const UINT exp_vertex_size34 = sizeof(*exp_vertices34);
9757     /* Test 35. Convert FLOAT16_4 to FLOAT4. */
9758     const struct vertex_ptc_float16_4 vertices35[] =
9759     {
9760         {{ 0.0f,  3.0f,  0.f}, {0x0000, 0x0000, 0x0000, 0x0000}},
9761         {{ 2.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
9762         {{ 0.0f,  0.0f,  0.f}, {0x3c00, 0x0000, 0x3c00, 0x0000}},
9763 
9764         {{ 3.0f,  3.0f,  0.f}, {0x0000, 0x3c00, 0x0000, 0x3c00}},
9765         {{ 3.0f,  0.0f,  0.f}, {0x3800, 0x399a, 0xb266, 0xb4cd}},
9766         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
9767     };
9768     const UINT num_vertices35 = ARRAY_SIZE(vertices35);
9769     const UINT num_faces35 = ARRAY_SIZE(vertices35) / VERTS_PER_FACE;
9770     const UINT vertex_size35 = sizeof(*vertices35);
9771     const struct vertex_ptc_float4 exp_vertices35[] =
9772     {
9773         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9774         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9775         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9776 
9777         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9778         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.700195f, -0.199951f, -0.300049f}},
9779         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.099976f, 0.199951f}},
9780     };
9781     const UINT exp_vertex_size35 = sizeof(*exp_vertices35);
9782     /* Test 36. Check that vertex buffer sharing is ok. */
9783     const struct vertex_pn vertices36[] =
9784     {
9785         {{ 0.0f,  3.0f,  0.f}, up},
9786         {{ 2.0f,  3.0f,  0.f}, up},
9787         {{ 0.0f,  0.0f,  0.f}, up},
9788     };
9789     const UINT num_vertices36 = ARRAY_SIZE(vertices36);
9790     const UINT num_faces36 = ARRAY_SIZE(vertices36) / VERTS_PER_FACE;
9791     const UINT vertex_size36 = sizeof(*vertices36);
9792     const DWORD clone_options36 = options | D3DXMESH_VB_SHARE;
9793     /* Common mesh data */
9794     ID3DXMesh *mesh = NULL;
9795     ID3DXMesh *mesh_clone = NULL;
9796     struct
9797     {
9798         const BYTE *vertices;
9799         const DWORD *indices;
9800         const DWORD *attributes;
9801         const UINT num_vertices;
9802         const UINT num_faces;
9803         const UINT vertex_size;
9804         const DWORD create_options;
9805         const DWORD clone_options;
9806         D3DVERTEXELEMENT9 *declaration;
9807         D3DVERTEXELEMENT9 *new_declaration;
9808         const BYTE *exp_vertices;
9809         const UINT exp_vertex_size;
9810     }
9811     tc[] =
9812     {
9813         {
9814             (BYTE*)vertices0,
9815             NULL,
9816             NULL,
9817             num_vertices0,
9818             num_faces0,
9819             vertex_size0,
9820             options,
9821             options,
9822             declaration_pn,
9823             declaration_pn,
9824             (BYTE*)vertices0,
9825             vertex_size0
9826         },
9827         {
9828             (BYTE*)vertices0,
9829             NULL,
9830             NULL,
9831             num_vertices0,
9832             num_faces0,
9833             vertex_size0,
9834             options_16bit,
9835             options_16bit,
9836             declaration_pn,
9837             declaration_pn,
9838             (BYTE*)vertices0,
9839             vertex_size0
9840         },
9841         {
9842             (BYTE*)vertices0,
9843             NULL,
9844             NULL,
9845             num_vertices0,
9846             num_faces0,
9847             vertex_size0,
9848             options,
9849             options,
9850             declaration_pn,
9851             declaration_pntc,
9852             (BYTE*)exp_vertices2,
9853             exp_vertex_size2
9854         },
9855         {
9856             (BYTE*)vertices0,
9857             NULL,
9858             NULL,
9859             num_vertices0,
9860             num_faces0,
9861             vertex_size0,
9862             options,
9863             options,
9864             declaration_pn,
9865             declaration_ptcn,
9866             (BYTE*)exp_vertices3,
9867             exp_vertex_size3
9868         },
9869         {
9870             (BYTE*)vertices4,
9871             NULL,
9872             NULL,
9873             num_vertices4,
9874             num_faces4,
9875             vertex_size4,
9876             options,
9877             options,
9878             declaration_ptc,
9879             declaration_ptc_float16_2,
9880             (BYTE*)exp_vertices4,
9881             exp_vertex_size4
9882         },
9883         {
9884             (BYTE*)vertices5,
9885             NULL,
9886             NULL,
9887             num_vertices5,
9888             num_faces5,
9889             vertex_size5,
9890             options,
9891             options,
9892             declaration_ptc,
9893             declaration_ptc_float16_4,
9894             (BYTE*)exp_vertices5,
9895             exp_vertex_size5
9896         },
9897         {
9898             (BYTE*)vertices6,
9899             NULL,
9900             NULL,
9901             num_vertices6,
9902             num_faces6,
9903             vertex_size6,
9904             options,
9905             options,
9906             declaration_ptc,
9907             declaration_ptc_float1,
9908             (BYTE*)exp_vertices6,
9909             exp_vertex_size6
9910         },
9911         {
9912             (BYTE*)vertices7,
9913             NULL,
9914             NULL,
9915             num_vertices7,
9916             num_faces7,
9917             vertex_size7,
9918             options,
9919             options,
9920             declaration_ptc,
9921             declaration_ptc_float3,
9922             (BYTE*)exp_vertices7,
9923             exp_vertex_size7
9924         },
9925         {
9926             (BYTE*)vertices8,
9927             NULL,
9928             NULL,
9929             num_vertices8,
9930             num_faces8,
9931             vertex_size8,
9932             options,
9933             options,
9934             declaration_ptc,
9935             declaration_ptc_float4,
9936             (BYTE*)exp_vertices8,
9937             exp_vertex_size8
9938         },
9939         {
9940             (BYTE*)vertices9,
9941             NULL,
9942             NULL,
9943             num_vertices9,
9944             num_faces9,
9945             vertex_size9,
9946             options,
9947             options,
9948             declaration_ptc,
9949             declaration_ptc_d3dcolor,
9950             (BYTE*)exp_vertices9,
9951             exp_vertex_size9
9952         },
9953         {
9954             (BYTE*)vertices10,
9955             NULL,
9956             NULL,
9957             num_vertices10,
9958             num_faces10,
9959             vertex_size10,
9960             options,
9961             options,
9962             declaration_ptc,
9963             declaration_ptc_ubyte4,
9964             (BYTE*)exp_vertices10,
9965             exp_vertex_size10
9966         },
9967         {
9968             (BYTE*)vertices11,
9969             NULL,
9970             NULL,
9971             num_vertices11,
9972             num_faces11,
9973             vertex_size11,
9974             options,
9975             options,
9976             declaration_ptc,
9977             declaration_ptc_short2,
9978             (BYTE*)exp_vertices11,
9979             exp_vertex_size11
9980         },
9981         {
9982             (BYTE*)vertices12,
9983             NULL,
9984             NULL,
9985             num_vertices12,
9986             num_faces12,
9987             vertex_size12,
9988             options,
9989             options,
9990             declaration_ptc,
9991             declaration_ptc_short4,
9992             (BYTE*)exp_vertices12,
9993             exp_vertex_size12
9994         },
9995         {
9996             (BYTE*)vertices13,
9997             NULL,
9998             NULL,
9999             num_vertices13,
10000             num_faces13,
10001             vertex_size13,
10002             options,
10003             options,
10004             declaration_ptc,
10005             declaration_ptc_ubyte4n,
10006             (BYTE*)exp_vertices13,
10007             exp_vertex_size13
10008         },
10009         {
10010             (BYTE*)vertices14,
10011             NULL,
10012             NULL,
10013             num_vertices14,
10014             num_faces14,
10015             vertex_size14,
10016             options,
10017             options,
10018             declaration_ptc,
10019             declaration_ptc_short2n,
10020             (BYTE*)exp_vertices14,
10021             exp_vertex_size14
10022         },
10023         {
10024             (BYTE*)vertices15,
10025             NULL,
10026             NULL,
10027             num_vertices15,
10028             num_faces15,
10029             vertex_size15,
10030             options,
10031             options,
10032             declaration_ptc,
10033             declaration_ptc_short4n,
10034             (BYTE*)exp_vertices15,
10035             exp_vertex_size15
10036         },
10037         {
10038             (BYTE*)vertices16,
10039             NULL,
10040             NULL,
10041             num_vertices16,
10042             num_faces16,
10043             vertex_size16,
10044             options,
10045             options,
10046             declaration_ptc,
10047             declaration_ptc_ushort2n,
10048             (BYTE*)exp_vertices16,
10049             exp_vertex_size16
10050         },
10051         {
10052             (BYTE*)vertices17,
10053             NULL,
10054             NULL,
10055             num_vertices17,
10056             num_faces17,
10057             vertex_size17,
10058             options,
10059             options,
10060             declaration_ptc,
10061             declaration_ptc_ushort4n,
10062             (BYTE*)exp_vertices17,
10063             exp_vertex_size17
10064         },
10065         {
10066             (BYTE*)vertices18,
10067             NULL,
10068             NULL,
10069             num_vertices18,
10070             num_faces18,
10071             vertex_size18,
10072             options,
10073             options,
10074             declaration_ptc,
10075             declaration_ptc_float16_2_partialu,
10076             (BYTE*)exp_vertices18,
10077             exp_vertex_size18
10078         },
10079         {
10080             (BYTE*)vertices19,
10081             NULL,
10082             NULL,
10083             num_vertices19,
10084             num_faces19,
10085             vertex_size19,
10086             options,
10087             options,
10088             declaration_pntc,
10089             declaration_pntc1,
10090             (BYTE*)exp_vertices19,
10091             exp_vertex_size19
10092         },
10093         {
10094             (BYTE*)vertices20,
10095             NULL,
10096             NULL,
10097             num_vertices20,
10098             num_faces20,
10099             vertex_size20,
10100             options,
10101             options,
10102             declaration_pntc1,
10103             declaration_pntc,
10104             (BYTE*)exp_vertices20,
10105             exp_vertex_size20
10106         },
10107         {
10108             (BYTE*)vertices21,
10109             NULL,
10110             NULL,
10111             num_vertices21,
10112             num_faces21,
10113             vertex_size21,
10114             options,
10115             options,
10116             declaration_ptc_float1,
10117             declaration_ptc,
10118             (BYTE*)exp_vertices21,
10119             exp_vertex_size21
10120         },
10121         {
10122             (BYTE*)vertices22,
10123             NULL,
10124             NULL,
10125             num_vertices22,
10126             num_faces22,
10127             vertex_size22,
10128             options,
10129             options,
10130             declaration_ptc_float1,
10131             declaration_ptc_float3,
10132             (BYTE*)exp_vertices22,
10133             exp_vertex_size22
10134         },
10135         {
10136             (BYTE*)vertices23,
10137             NULL,
10138             NULL,
10139             num_vertices23,
10140             num_faces23,
10141             vertex_size23,
10142             options,
10143             options,
10144             declaration_ptc_float1,
10145             declaration_ptc_float4,
10146             (BYTE*)exp_vertices23,
10147             exp_vertex_size23
10148         },
10149         {
10150             (BYTE*)vertices24,
10151             NULL,
10152             NULL,
10153             num_vertices24,
10154             num_faces24,
10155             vertex_size24,
10156             options,
10157             options,
10158             declaration_ptc_float1,
10159             declaration_ptc_d3dcolor,
10160             (BYTE*)exp_vertices24,
10161             exp_vertex_size24
10162         },
10163         {
10164             (BYTE*)vertices25,
10165             NULL,
10166             NULL,
10167             num_vertices25,
10168             num_faces25,
10169             vertex_size25,
10170             options,
10171             options,
10172             declaration_ptc_float1,
10173             declaration_ptc_ubyte4,
10174             (BYTE*)exp_vertices25,
10175             exp_vertex_size25
10176         },
10177         {
10178             (BYTE*)vertices26,
10179             NULL,
10180             NULL,
10181             num_vertices26,
10182             num_faces26,
10183             vertex_size26,
10184             options,
10185             options,
10186             declaration_ptc_float4,
10187             declaration_ptc_d3dcolor,
10188             (BYTE*)exp_vertices26,
10189             exp_vertex_size26
10190         },
10191         {
10192             (BYTE*)vertices27,
10193             NULL,
10194             NULL,
10195             num_vertices27,
10196             num_faces27,
10197             vertex_size27,
10198             options,
10199             options,
10200             declaration_ptc_d3dcolor,
10201             declaration_ptc_float4,
10202             (BYTE*)exp_vertices27,
10203             exp_vertex_size27
10204         },
10205         {
10206             (BYTE*)vertices28,
10207             NULL,
10208             NULL,
10209             num_vertices28,
10210             num_faces28,
10211             vertex_size28,
10212             options,
10213             options,
10214             declaration_ptc_ubyte4,
10215             declaration_ptc_float4,
10216             (BYTE*)exp_vertices28,
10217             exp_vertex_size28
10218         },
10219         {
10220             (BYTE*)vertices29,
10221             NULL,
10222             NULL,
10223             num_vertices29,
10224             num_faces29,
10225             vertex_size29,
10226             options,
10227             options,
10228             declaration_ptc_short2,
10229             declaration_ptc_float4,
10230             (BYTE*)exp_vertices29,
10231             exp_vertex_size29
10232         },
10233         {
10234             (BYTE*)vertices30,
10235             NULL,
10236             NULL,
10237             num_vertices30,
10238             num_faces30,
10239             vertex_size30,
10240             options,
10241             options,
10242             declaration_ptc_short4,
10243             declaration_ptc_float4,
10244             (BYTE*)exp_vertices30,
10245             exp_vertex_size30
10246         },
10247         {
10248             (BYTE*)vertices31,
10249             NULL,
10250             NULL,
10251             num_vertices31,
10252             num_faces31,
10253             vertex_size31,
10254             options,
10255             options,
10256             declaration_ptc_ubyte4n,
10257             declaration_ptc_float4,
10258             (BYTE*)exp_vertices31,
10259             exp_vertex_size31
10260         },
10261         {
10262             (BYTE*)vertices32,
10263             NULL,
10264             NULL,
10265             num_vertices32,
10266             num_faces32,
10267             vertex_size32,
10268             options,
10269             options,
10270             declaration_ptc_short2n,
10271             declaration_ptc_float4,
10272             (BYTE*)exp_vertices32,
10273             exp_vertex_size32
10274         },
10275         {
10276             (BYTE*)vertices33,
10277             NULL,
10278             NULL,
10279             num_vertices33,
10280             num_faces33,
10281             vertex_size33,
10282             options,
10283             options,
10284             declaration_ptc_short4n,
10285             declaration_ptc_float4,
10286             (BYTE*)exp_vertices33,
10287             exp_vertex_size33
10288         },
10289         {
10290             (BYTE*)vertices34,
10291             NULL,
10292             NULL,
10293             num_vertices34,
10294             num_faces34,
10295             vertex_size34,
10296             options,
10297             options,
10298             declaration_ptc_float16_2,
10299             declaration_ptc_float4,
10300             (BYTE*)exp_vertices34,
10301             exp_vertex_size34
10302         },
10303         {
10304             (BYTE*)vertices35,
10305             NULL,
10306             NULL,
10307             num_vertices35,
10308             num_faces35,
10309             vertex_size35,
10310             options,
10311             options,
10312             declaration_ptc_float16_4,
10313             declaration_ptc_float4,
10314             (BYTE*)exp_vertices35,
10315             exp_vertex_size35
10316         },
10317         {
10318             (BYTE*)vertices36,
10319             NULL,
10320             NULL,
10321             num_vertices36,
10322             num_faces36,
10323             vertex_size36,
10324             options,
10325             clone_options36,
10326             declaration_pn,
10327             declaration_pn,
10328             (BYTE*)vertices36,
10329             vertex_size36
10330         },
10331     };
10332 #ifdef __REACTOS__
10333 #undef up
10334 #undef zero_vec2
10335 #endif
10336 
10337     test_context = new_test_context();
10338     if (!test_context)
10339     {
10340         skip("Couldn't create test context\n");
10341         goto cleanup;
10342     }
10343 
10344     for (i = 0; i < ARRAY_SIZE(tc); i++)
10345     {
10346         UINT j;
10347         D3DVERTEXELEMENT9 new_declaration[MAX_FVF_DECL_SIZE];
10348         UINT exp_new_decl_length, new_decl_length;
10349         UINT exp_new_decl_size, new_decl_size;
10350 
10351         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10352                               tc[i].create_options,
10353                               tc[i].declaration,
10354                               test_context->device, &mesh,
10355                               tc[i].vertices, tc[i].vertex_size,
10356                               tc[i].indices, tc[i].attributes);
10357         if (FAILED(hr))
10358         {
10359             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10360             goto cleanup;
10361         }
10362 
10363         hr = mesh->lpVtbl->CloneMesh(mesh, tc[i].clone_options, tc[i].new_declaration,
10364                                      test_context->device, &mesh_clone);
10365         ok(hr == D3D_OK, "CloneMesh test case %d failed. Got %x, expected D3D_OK.\n", i, hr);
10366 
10367         hr = mesh_clone->lpVtbl->GetDeclaration(mesh_clone, new_declaration);
10368         ok(hr == D3D_OK, "GetDeclaration test case %d failed. Got %x, expected D3D_OK.\n", i, hr);
10369         /* Check declaration elements */
10370         for (j = 0; tc[i].new_declaration[j].Stream != 0xFF; j++)
10371         {
10372             ok(memcmp(&tc[i].new_declaration[j], &new_declaration[j], sizeof(*new_declaration)) == 0,
10373                "Test case %d failed. Declaration element %d did not match.\n", i, j);
10374         }
10375 
10376         /* Check declaration length */
10377         exp_new_decl_length = D3DXGetDeclLength(tc[i].new_declaration);
10378         new_decl_length = D3DXGetDeclLength(new_declaration);
10379         ok(new_decl_length == exp_new_decl_length,
10380            "Test case %d failed. Got new declaration length %d, expected %d\n",
10381            i, new_decl_length, exp_new_decl_length);
10382 
10383         /* Check declaration size */
10384         exp_new_decl_size = D3DXGetDeclVertexSize(tc[i].new_declaration, 0);
10385         new_decl_size = D3DXGetDeclVertexSize(new_declaration, 0);
10386         ok(new_decl_size == exp_new_decl_size,
10387            "Test case %d failed. Got new declaration size %d, expected %d\n",
10388            i, new_decl_size, exp_new_decl_size);
10389 
10390         /* Check vertex data in cloned mesh */
10391         hr = mesh_clone->lpVtbl->LockVertexBuffer(mesh_clone, 0, (void**)&vertices);
10392         if (FAILED(hr))
10393         {
10394             skip("Couldn't lock cloned vertex buffer.\n");
10395             goto cleanup;
10396         }
10397         for (j = 0; j < tc[i].num_vertices; j++)
10398         {
10399             UINT index = tc[i].exp_vertex_size * j;
10400             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].new_declaration);
10401         }
10402         hr = mesh_clone->lpVtbl->UnlockVertexBuffer(mesh_clone);
10403         if (FAILED(hr))
10404         {
10405             skip("Couldn't unlock vertex buffer.\n");
10406             goto cleanup;
10407         }
10408         vertices = NULL;
10409         mesh->lpVtbl->Release(mesh);
10410         mesh = NULL;
10411         mesh_clone->lpVtbl->Release(mesh_clone);
10412         mesh_clone = NULL;
10413     }
10414 
10415     /* The following test shows that it is not possible to share a vertex buffer
10416      * with D3DXMESH_VB_SHARE and change the vertex declaration at the same
10417      * time. It reuses the test data from test 2.
10418      */
10419     hr = init_test_mesh(tc[2].num_faces, tc[2].num_vertices,
10420                         tc[2].create_options,
10421                         tc[2].declaration,
10422                         test_context->device, &mesh,
10423                         tc[2].vertices, tc[2].vertex_size,
10424                         tc[2].indices, tc[2].attributes);
10425     if (FAILED(hr))
10426     {
10427         skip("Couldn't initialize test mesh for D3DXMESH_VB_SHARE case."
10428              " Got %x expected D3D_OK\n", hr);
10429         goto cleanup;
10430     }
10431 
10432     hr = mesh->lpVtbl->CloneMesh(mesh, tc[2].create_options | D3DXMESH_VB_SHARE,
10433                                  tc[2].new_declaration, test_context->device,
10434                                  &mesh_clone);
10435     ok(hr == D3DERR_INVALIDCALL, "CloneMesh D3DXMESH_VB_SHARE with new"
10436        " declaration. Got %x, expected D3DERR_INVALIDCALL\n",
10437        hr);
10438     mesh->lpVtbl->Release(mesh);
10439     mesh = NULL;
10440     mesh_clone = NULL;
10441 
10442 cleanup:
10443     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
10444     if (mesh) mesh->lpVtbl->Release(mesh);
10445     if (mesh_clone) mesh_clone->lpVtbl->Release(mesh_clone);
10446     free_test_context(test_context);
10447 }
10448 
10449 static void test_valid_mesh(void)
10450 {
10451     HRESULT hr;
10452     struct test_context *test_context = NULL;
10453     UINT i;
10454     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
10455     const D3DVERTEXELEMENT9 declaration[] =
10456     {
10457         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10458         D3DDECL_END()
10459     };
10460     const unsigned int VERTS_PER_FACE = 3;
10461     /* mesh0 (one face)
10462      *
10463      * 0--1
10464      * | /
10465      * |/
10466      * 2
10467      */
10468     const D3DXVECTOR3 vertices0[] =
10469     {
10470         { 0.0f,  3.0f,  0.f},
10471         { 2.0f,  3.0f,  0.f},
10472         { 0.0f,  0.0f,  0.f},
10473     };
10474     const DWORD indices0[] = {0, 1, 2};
10475     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
10476     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
10477     const DWORD adjacency0[] = {-1, -1, -1};
10478     const HRESULT exp_hr0 = D3D_OK;
10479     /* mesh1 (Simple bow-tie)
10480      *
10481      * 0--1 1--3
10482      * | /   \ |
10483      * |/     \|
10484      * 2       4
10485      */
10486     const D3DXVECTOR3 vertices1[] =
10487     {
10488         { 0.0f,  3.0f,  0.f},
10489         { 2.0f,  3.0f,  0.f},
10490         { 0.0f,  0.0f,  0.f},
10491 
10492         { 4.0f,  3.0f,  0.f},
10493         { 4.0f,  0.0f,  0.f},
10494     };
10495     const DWORD indices1[] = {0, 1, 2, 1, 3, 4};
10496     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
10497     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
10498     const DWORD adjacency1[] = {-1, -1, -1, -1, -1, -1};
10499     const HRESULT exp_hr1 = D3DXERR_INVALIDMESH;
10500     /* Common mesh data */
10501     ID3DXMesh *mesh = NULL;
10502     UINT vertex_size = sizeof(D3DXVECTOR3);
10503     ID3DXBuffer *errors_and_warnings = NULL;
10504     struct
10505     {
10506         const D3DXVECTOR3 *vertices;
10507         const DWORD *indices;
10508         const UINT num_vertices;
10509         const UINT num_faces;
10510         const DWORD *adjacency;
10511         const HRESULT exp_hr;
10512     }
10513     tc[] =
10514     {
10515         {
10516             vertices0,
10517             indices0,
10518             num_vertices0,
10519             num_faces0,
10520             adjacency0,
10521             exp_hr0,
10522         },
10523         {
10524             vertices1,
10525             indices1,
10526             num_vertices1,
10527             num_faces1,
10528             adjacency1,
10529             exp_hr1,
10530         },
10531     };
10532 
10533     test_context = new_test_context();
10534     if (!test_context)
10535     {
10536         skip("Couldn't create test context\n");
10537         goto cleanup;
10538     }
10539 
10540     for (i = 0; i < ARRAY_SIZE(tc); i++)
10541     {
10542         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10543                             options, declaration,
10544                             test_context->device, &mesh,
10545                             tc[i].vertices, vertex_size,
10546                             tc[i].indices, NULL);
10547         if (FAILED(hr))
10548         {
10549             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10550             goto cleanup;
10551         }
10552 
10553         hr = D3DXValidMesh(mesh, tc[i].adjacency, &errors_and_warnings);
10554         todo_wine ok(hr == tc[i].exp_hr, "D3DXValidMesh test case %d failed. "
10555                 "Got %x, expected %x.\n", i, hr, tc[i].exp_hr);
10556 
10557         /* Note errors_and_warnings is deliberately not checked because that
10558          * would require copying wast amounts of the text output. */
10559         if (errors_and_warnings)
10560         {
10561             ID3DXBuffer_Release(errors_and_warnings);
10562             errors_and_warnings = NULL;
10563         }
10564         mesh->lpVtbl->Release(mesh);
10565         mesh = NULL;
10566     }
10567 
10568 cleanup:
10569     if (mesh) mesh->lpVtbl->Release(mesh);
10570     free_test_context(test_context);
10571 }
10572 
10573 static void test_optimize_vertices(void)
10574 {
10575     HRESULT hr;
10576     DWORD vertex_remap[3];
10577     const DWORD indices[] = {0, 1, 2};
10578     const UINT num_faces = 1;
10579     const UINT num_vertices = 3;
10580 
10581     hr = D3DXOptimizeVertices(indices, num_faces,
10582                               num_vertices, FALSE,
10583                               vertex_remap);
10584     ok(hr == D3D_OK, "D3DXOptimizeVertices failed. Got %x, expected D3D_OK.\n", hr);
10585 
10586     /* vertex_remap must not be NULL */
10587     hr = D3DXOptimizeVertices(indices, num_faces,
10588                               num_vertices, FALSE,
10589                               NULL);
10590     ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeVertices passed NULL vertex_remap "
10591             "pointer. Got %x, expected D3DERR_INVALIDCALL.\n", hr);
10592 }
10593 
10594 static void test_optimize_faces(void)
10595 {
10596     HRESULT hr;
10597     UINT i;
10598     DWORD smallest_face_remap;
10599     /* mesh0
10600      *
10601      * 0--1
10602      * | /
10603      * |/
10604      * 2
10605      */
10606     const DWORD indices0[] = {0, 1, 2};
10607     const UINT num_faces0 = 1;
10608     const UINT num_vertices0 = 3;
10609     const DWORD exp_face_remap0[] = {0};
10610     /* mesh1
10611      *
10612      * 0--1 3
10613      * | / /|
10614      * |/ / |
10615      * 2 5--4
10616      */
10617     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
10618     const UINT num_faces1 = 2;
10619     const UINT num_vertices1 = 6;
10620     const DWORD exp_face_remap1[] = {1, 0};
10621     /* mesh2
10622      *
10623      * 0--1
10624      * | /|
10625      * |/ |
10626      * 2--3
10627      */
10628     const DWORD indices2[] = {0, 1, 2, 1, 3, 2};
10629     const UINT num_faces2 = 2;
10630     const UINT num_vertices2 = 4;
10631     const DWORD exp_face_remap2[] = {1, 0};
10632     /* mesh3
10633      *
10634      * 0--1
10635      * | /|
10636      * |/ |
10637      * 2--3
10638      * | /|
10639      * |/ |
10640      * 4--5
10641      */
10642     const DWORD indices3[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
10643     const UINT num_faces3 = 4;
10644     const UINT num_vertices3 = 6;
10645     const DWORD exp_face_remap3[] = {3, 2, 1, 0};
10646     /* mesh4
10647      *
10648      * 0--1
10649      * | /|
10650      * |/ |
10651      * 2--3
10652      * | /|
10653      * |/ |
10654      * 4--5
10655      */
10656     const WORD indices4[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
10657     const UINT num_faces4 = 4;
10658     const UINT num_vertices4 = 6;
10659     const DWORD exp_face_remap4[] = {3, 2, 1, 0};
10660     /* Test cases are stored in the tc array */
10661     struct
10662     {
10663         const VOID *indices;
10664         const UINT num_faces;
10665         const UINT num_vertices;
10666         const BOOL indices_are_32bit;
10667         const DWORD *exp_face_remap;
10668     }
10669     tc[] =
10670     {
10671         {
10672             indices0,
10673             num_faces0,
10674             num_vertices0,
10675             TRUE,
10676             exp_face_remap0
10677         },
10678         {
10679             indices1,
10680             num_faces1,
10681             num_vertices1,
10682             TRUE,
10683             exp_face_remap1
10684         },
10685         {
10686             indices2,
10687             num_faces2,
10688             num_vertices2,
10689             TRUE,
10690             exp_face_remap2
10691         },
10692         {
10693             indices3,
10694             num_faces3,
10695             num_vertices3,
10696             TRUE,
10697             exp_face_remap3
10698         },
10699         {
10700             indices4,
10701             num_faces4,
10702             num_vertices4,
10703             FALSE,
10704             exp_face_remap4
10705         },
10706     };
10707 
10708     /* Go through all test cases */
10709     for (i = 0; i < ARRAY_SIZE(tc); i++)
10710     {
10711         DWORD j;
10712         DWORD *face_remap;
10713         face_remap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
10714                                tc[i].num_faces*sizeof(*face_remap));
10715 
10716         hr = D3DXOptimizeFaces(tc[i].indices, tc[i].num_faces,
10717                                tc[i].num_vertices, tc[i].indices_are_32bit,
10718                                face_remap);
10719         ok(hr == D3D_OK, "D3DXOptimizeFaces test case %d failed. "
10720                 "Got %x, expected D3D_OK.\n", i, hr);
10721 
10722         /* Compare face remap with expected face remap */
10723         for (j = 0; j < tc[i].num_faces; j++)
10724         {
10725             ok(tc[i].exp_face_remap[j] == face_remap[j],
10726                "Test case %d: Got face %d at %d, expected %d\n", i,
10727                face_remap[j], j, tc[i].exp_face_remap[j]);
10728         }
10729 
10730         HeapFree(GetProcessHeap(), 0, face_remap);
10731     }
10732 
10733     /* face_remap must not be NULL */
10734     hr = D3DXOptimizeFaces(tc[0].indices, tc[0].num_faces,
10735                            tc[0].num_vertices, tc[0].indices_are_32bit,
10736                            NULL);
10737     ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeFaces passed NULL face_remap "
10738             "pointer. Got %x, expected D3DERR_INVALIDCALL.\n", hr);
10739 
10740     /* Number of faces must be smaller than 2^15 */
10741     hr = D3DXOptimizeFaces(tc[0].indices, 2 << 15,
10742                            tc[0].num_vertices, FALSE,
10743                            &smallest_face_remap);
10744     ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeFaces should not accept 2^15 "
10745             "faces when using 16-bit indices. Got %x, expected D3DERR_INVALIDCALL.\n", hr);
10746 }
10747 
10748 static HRESULT clear_normals(ID3DXMesh *mesh)
10749 {
10750     HRESULT hr;
10751     BYTE *vertices;
10752     size_t normal_size;
10753     DWORD i, num_vertices, vertex_stride;
10754     const D3DXVECTOR4 normal = {NAN, NAN, NAN, NAN};
10755     D3DVERTEXELEMENT9 *normal_declaration = NULL;
10756     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
10757 
10758     if (FAILED(hr = mesh->lpVtbl->GetDeclaration(mesh, declaration)))
10759         return hr;
10760 
10761     for (i = 0; declaration[i].Stream != 0xff; i++)
10762     {
10763         if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
10764         {
10765             normal_declaration = &declaration[i];
10766             break;
10767         }
10768     }
10769 
10770     if (!normal_declaration)
10771         return D3DERR_INVALIDCALL;
10772 
10773     if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
10774     {
10775         normal_size = sizeof(D3DXVECTOR3);
10776     }
10777     else if (normal_declaration->Type == D3DDECLTYPE_FLOAT4)
10778     {
10779         normal_size = sizeof(D3DXVECTOR4);
10780     }
10781     else
10782     {
10783         trace("Cannot clear normals\n");
10784         return E_NOTIMPL;
10785     }
10786 
10787     num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
10788     vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
10789 
10790     if (FAILED(hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
10791         return hr;
10792 
10793     vertices += normal_declaration->Offset;
10794 
10795     for (i = 0; i < num_vertices; i++, vertices += vertex_stride)
10796         memcpy(vertices, &normal, normal_size);
10797 
10798     return mesh->lpVtbl->UnlockVertexBuffer(mesh);
10799 }
10800 
10801 static void compare_normals(unsigned int line, const char *test_name,
10802         ID3DXMesh *mesh, const D3DXVECTOR3 *normals, unsigned int num_normals)
10803 {
10804     unsigned int i;
10805     BYTE *vertices;
10806     DWORD num_vertices, vertex_stride;
10807     D3DVERTEXELEMENT9 *normal_declaration = NULL;
10808     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
10809 
10810     if (FAILED(mesh->lpVtbl->GetDeclaration(mesh, declaration)))
10811     {
10812         ok_(__FILE__, line)(0, "%s: Failed to get declaration\n", test_name);
10813         return;
10814     }
10815 
10816     for (i = 0; declaration[i].Stream != 0xff; i++)
10817     {
10818         if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
10819         {
10820             normal_declaration = &declaration[i];
10821             break;
10822         }
10823     }
10824 
10825     if (!normal_declaration)
10826     {
10827         ok_(__FILE__, line)(0, "%s: Mesh has no normals\n", test_name);
10828         return;
10829     }
10830 
10831     if (normal_declaration->Type != D3DDECLTYPE_FLOAT3 && normal_declaration->Type != D3DDECLTYPE_FLOAT4)
10832     {
10833         ok_(__FILE__, line)(0, "%s: Mesh has invalid normals type\n", test_name);
10834         return;
10835     }
10836 
10837     num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
10838     vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
10839 
10840     ok_(__FILE__, line)(num_vertices == num_normals, "%s: Expected %u vertices, got %u\n", test_name,
10841             num_normals, num_vertices);
10842 
10843     if (FAILED(mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
10844     {
10845         ok_(__FILE__, line)(0, "%s: Failed to compare normals\n", test_name);
10846         return;
10847     }
10848 
10849     vertices += normal_declaration->Offset;
10850 
10851     for (i = 0; i < min(num_vertices, num_normals); i++, vertices += vertex_stride)
10852     {
10853         if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
10854         {
10855             const D3DXVECTOR3 *n = (D3DXVECTOR3 *)vertices;
10856             ok_(__FILE__, line)(compare_vec3(*n, normals[i]),
10857                     "%s: normal %2u, expected (%f, %f, %f), got (%f, %f, %f)\n",
10858                     test_name, i, normals[i].x, normals[i].y, normals[i].z, n->x, n->y, n->z);
10859         }
10860         else
10861         {
10862             const D3DXVECTOR4 *n = (D3DXVECTOR4 *)vertices;
10863             const D3DXVECTOR4 normal = {normals[i].x, normals[i].y, normals[i].z, 1.0f};
10864             ok_(__FILE__, line)(compare_vec4(*n, normal),
10865                     "%s: normal %2u, expected (%f, %f, %f, %f), got (%f, %f, %f, %f)\n",
10866                     test_name, i, normals[i].x, normals[i].y, normals[i].z, 1.0f,
10867                     n->x, n->y, n->z, n->w);
10868         }
10869     }
10870 
10871     mesh->lpVtbl->UnlockVertexBuffer(mesh);
10872 }
10873 
10874 static HRESULT compute_normals_D3DXComputeNormals(ID3DXMesh *mesh, const DWORD *adjacency)
10875 {
10876     return D3DXComputeNormals((ID3DXBaseMesh *)mesh, adjacency);
10877 }
10878 
10879 static HRESULT compute_normals_D3DXComputeTangentFrameEx(ID3DXMesh *mesh, const DWORD *adjacency)
10880 {
10881     return D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10882             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
10883             adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL);
10884 }
10885 
10886 static void test_compute_normals(void)
10887 {
10888     HRESULT hr;
10889     ULONG refcount;
10890     ID3DXMesh *mesh, *cloned_mesh;
10891     ID3DXBuffer *adjacency;
10892     IDirect3DDevice9 *device;
10893     struct test_context *test_context;
10894     unsigned int i;
10895 
10896     static const struct compute_normals_func
10897     {
10898         const char *name;
10899         HRESULT (*apply)(ID3DXMesh *mesh, const DWORD *adjacency);
10900     }
10901     compute_normals_funcs[] =
10902     {
10903         {"D3DXComputeNormals",        compute_normals_D3DXComputeNormals       },
10904         {"D3DXComputeTangentFrameEx", compute_normals_D3DXComputeTangentFrameEx}
10905     };
10906 
10907     static const D3DXVECTOR3 box_normals[24] =
10908     {
10909         {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f},
10910         { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f},
10911         { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f},
10912         { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f},
10913         { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f},
10914         { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}
10915     };
10916     const float box_normal_component = 1.0f / sqrtf(3.0f);
10917     const D3DXVECTOR3 box_normals_adjacency[24] =
10918     {
10919         {-box_normal_component, -box_normal_component, -box_normal_component},
10920         {-box_normal_component, -box_normal_component,  box_normal_component},
10921         {-box_normal_component,  box_normal_component,  box_normal_component},
10922         {-box_normal_component,  box_normal_component, -box_normal_component},
10923         {-box_normal_component,  box_normal_component, -box_normal_component},
10924         {-box_normal_component,  box_normal_component,  box_normal_component},
10925         { box_normal_component,  box_normal_component,  box_normal_component},
10926         { box_normal_component,  box_normal_component, -box_normal_component},
10927         { box_normal_component,  box_normal_component, -box_normal_component},
10928         { box_normal_component,  box_normal_component,  box_normal_component},
10929         { box_normal_component, -box_normal_component,  box_normal_component},
10930         { box_normal_component, -box_normal_component, -box_normal_component},
10931         {-box_normal_component, -box_normal_component,  box_normal_component},
10932         {-box_normal_component, -box_normal_component, -box_normal_component},
10933         { box_normal_component, -box_normal_component, -box_normal_component},
10934         { box_normal_component, -box_normal_component,  box_normal_component},
10935         {-box_normal_component, -box_normal_component,  box_normal_component},
10936         { box_normal_component, -box_normal_component,  box_normal_component},
10937         { box_normal_component,  box_normal_component,  box_normal_component},
10938         {-box_normal_component,  box_normal_component,  box_normal_component},
10939         {-box_normal_component, -box_normal_component, -box_normal_component},
10940         {-box_normal_component,  box_normal_component, -box_normal_component},
10941         { box_normal_component,  box_normal_component, -box_normal_component},
10942         { box_normal_component, -box_normal_component, -box_normal_component}
10943     };
10944     static const D3DXVECTOR3 box_normals_adjacency_area[24] =
10945     {
10946         {-0.666667f, -0.333333f, -0.666667f}, {-0.333333f, -0.666667f,  0.666667f},
10947         {-0.816496f,  0.408248f,  0.408248f}, {-0.408248f,  0.816496f, -0.408248f},
10948         {-0.408248f,  0.816496f, -0.408248f}, {-0.816496f,  0.408248f,  0.408248f},
10949         { 0.333333f,  0.666667f,  0.666667f}, { 0.666667f,  0.333333f, -0.666667f},
10950         { 0.666667f,  0.333333f, -0.666667f}, { 0.333333f,  0.666667f,  0.666667f},
10951         { 0.816496f, -0.408248f,  0.408248f}, { 0.408248f, -0.816496f, -0.408248f},
10952         {-0.333333f, -0.666667f,  0.666667f}, {-0.666667f, -0.333333f, -0.666667f},
10953         { 0.408248f, -0.816496f, -0.408248f}, { 0.816496f, -0.408248f,  0.408248f},
10954         {-0.333333f, -0.666667f,  0.666667f}, { 0.816497f, -0.408248f,  0.408248f},
10955         { 0.333333f,  0.666667f,  0.666667f}, {-0.816497f,  0.408248f,  0.408248f},
10956         {-0.666667f, -0.333333f, -0.666667f}, {-0.408248f,  0.816497f, -0.408248f},
10957         { 0.666667f,  0.333333f, -0.666667f}, { 0.408248f, -0.816496f, -0.408248f}
10958     };
10959     static const D3DXVECTOR3 box_normals_position1f[24] = {{0}};
10960     static const D3DXVECTOR3 box_normals_position2f[24] =
10961     {
10962         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
10963         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f},
10964         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
10965         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
10966         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
10967         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
10968         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
10969         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}
10970     };
10971 
10972     static const D3DXVECTOR3 sphere_normals[22] =
10973     {
10974         { 0.000000f, -0.000000f,  1.000000f}, { 0.000000f,  0.582244f,  0.813014f},
10975         { 0.582244f, -0.000000f,  0.813014f}, {-0.000000f, -0.582244f,  0.813014f},
10976         {-0.582244f,  0.000000f,  0.813014f}, {-0.000000f,  0.890608f,  0.454772f},
10977         { 0.890608f,  0.000000f,  0.454772f}, { 0.000000f, -0.890608f,  0.454772f},
10978         {-0.890608f, -0.000000f,  0.454772f}, { 0.000000f,  1.000000f, -0.000000f},
10979         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10980         {-1.000000f,  0.000000f, -0.000000f}, { 0.000000f,  0.890608f, -0.454773f},
10981         { 0.890608f, -0.000000f, -0.454772f}, {-0.000000f, -0.890608f, -0.454773f},
10982         {-0.890608f,  0.000000f, -0.454773f}, { 0.000000f,  0.582244f, -0.813015f},
10983         { 0.582244f, -0.000000f, -0.813015f}, { 0.000000f, -0.582244f, -0.813015f},
10984         {-0.582243f,  0.000000f, -0.813015f}, { 0.000000f,  0.000000f, -1.000000f}
10985     };
10986     static const D3DXVECTOR3 sphere_normals_area[22] =
10987     {
10988         { 0.000000f, -0.000000f,  1.000000f}, {-0.215311f,  0.554931f,  0.803550f},
10989         { 0.554931f,  0.215311f,  0.803550f}, { 0.215311f, -0.554931f,  0.803550f},
10990         {-0.554931f, -0.215311f,  0.803550f}, {-0.126638f,  0.872121f,  0.472618f},
10991         { 0.872121f,  0.126638f,  0.472618f}, { 0.126638f, -0.872121f,  0.472618f},
10992         {-0.872121f, -0.126637f,  0.472618f}, { 0.000000f,  1.000000f, -0.000000f},
10993         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10994         {-1.000000f,  0.000000f, -0.000000f}, { 0.126638f,  0.872121f, -0.472618f},
10995         { 0.872121f, -0.126638f, -0.472618f}, {-0.126638f, -0.872121f, -0.472618f},
10996         {-0.872121f,  0.126638f, -0.472618f}, { 0.215311f,  0.554931f, -0.803550f},
10997         { 0.554931f, -0.215311f, -0.803550f}, {-0.215311f, -0.554931f, -0.803550f},
10998         {-0.554931f,  0.215311f, -0.803550f}, { 0.000000f,  0.000000f, -1.000000f}
10999     };
11000     static const D3DXVECTOR3 sphere_normals_equal[22] =
11001     {
11002         { 0.000000f, -0.000000f,  1.000000f}, {-0.134974f,  0.522078f,  0.842150f},
11003         { 0.522078f,  0.134974f,  0.842150f}, { 0.134974f, -0.522078f,  0.842150f},
11004         {-0.522078f, -0.134974f,  0.842150f}, {-0.026367f,  0.857121f,  0.514440f},
11005         { 0.857121f,  0.026367f,  0.514440f}, { 0.026367f, -0.857121f,  0.514440f},
11006         {-0.857121f, -0.026367f,  0.514440f}, { 0.000000f,  1.000000f, -0.000000f},
11007         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
11008         {-1.000000f,  0.000000f, -0.000000f}, { 0.026367f,  0.857121f, -0.514440f},
11009         { 0.857121f, -0.026367f, -0.514440f}, {-0.026367f, -0.857121f, -0.514440f},
11010         {-0.857121f,  0.026367f, -0.514440f}, { 0.134975f,  0.522078f, -0.842150f},
11011         { 0.522078f, -0.134975f, -0.842150f}, {-0.134974f, -0.522078f, -0.842150f},
11012         {-0.522078f,  0.134974f, -0.842150f}, { 0.000000f,  0.000000f, -1.000000f}
11013     };
11014 
11015     static const D3DVERTEXELEMENT9 position3f_normal1f_declaration[] =
11016     {
11017         {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
11018         {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
11019         D3DDECL_END()
11020     };
11021     static const D3DVERTEXELEMENT9 position3f_normal2f_declaration[] =
11022     {
11023         {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
11024         {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
11025         D3DDECL_END()
11026     };
11027     static const D3DVERTEXELEMENT9 normal4f_position3f_declaration[] =
11028     {
11029         {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
11030         {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
11031         D3DDECL_END()
11032     };
11033     static const D3DVERTEXELEMENT9 position1f_normal3f_declaration[] =
11034     {
11035         {0, 0,                   D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
11036         {0, sizeof(float),       D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
11037         D3DDECL_END()
11038     };
11039     static const D3DVERTEXELEMENT9 position2f_normal3f_declaration[] =
11040     {
11041         {0, 0,                   D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
11042         {0, sizeof(D3DXVECTOR2), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
11043         D3DDECL_END()
11044     };
11045     static const D3DVERTEXELEMENT9 position4f_normal3f_declaration[] =
11046     {
11047         {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
11048         {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
11049         D3DDECL_END()
11050     };
11051 
11052     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
11053     {
11054         hr = compute_normals_funcs[i].apply(NULL, NULL);
11055         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", compute_normals_funcs[i].name, hr);
11056     }
11057 
11058     if (!(test_context = new_test_context()))
11059     {
11060         skip("Couldn't create test context\n");
11061         return;
11062     }
11063     device = test_context->device;
11064 
11065     hr = D3DXCreateBox(device, 1.0f, 1.0f, 1.0f, &mesh, &adjacency);
11066     ok(SUCCEEDED(hr), "D3DXCreateBox failed %#x\n", hr);
11067 
11068     /* Check wrong input */
11069     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11070             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11071     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11072 
11073     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DDECLUSAGE_NORMAL, 0,
11074             D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA | D3DXTANGENT_WEIGHT_EQUAL,
11075             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11076     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11077 
11078     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11079             D3DDECLUSAGE_NORMAL, 0, 0, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11080     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11081 
11082     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11083             D3DDECLUSAGE_NORMAL, 1, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
11084             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11085     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11086 
11087     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11088             D3DX_DEFAULT, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
11089             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11090     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11091 
11092     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11093             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_CALCULATE_NORMALS,
11094             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11095     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11096 
11097     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
11098     {
11099         const struct compute_normals_func *func = &compute_normals_funcs[i];
11100 
11101         /* Mesh without normals */
11102         hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_XYZ, device, &cloned_mesh);
11103         ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
11104 
11105         hr = func->apply(cloned_mesh, NULL);
11106         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11107 
11108         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11109         ok(!refcount, "Mesh has %u references left\n", refcount);
11110 
11111         /* Mesh without positions */
11112         hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_NORMAL, device, &cloned_mesh);
11113         ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
11114 
11115         hr = func->apply(cloned_mesh, NULL);
11116         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11117 
11118         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11119         ok(!refcount, "Mesh has %u references left\n", refcount);
11120 
11121         /* Mesh with D3DDECLTYPE_FLOAT1 normals */
11122         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal1f_declaration, device, &cloned_mesh);
11123         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11124 
11125         hr = func->apply(cloned_mesh, NULL);
11126         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11127 
11128         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11129         ok(!refcount, "Mesh has %u references left\n", refcount);
11130 
11131         /* Mesh with D3DDECLTYPE_FLOAT2 normals */
11132         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal2f_declaration, device, &cloned_mesh);
11133         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11134 
11135         hr = func->apply(cloned_mesh, NULL);
11136         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11137 
11138         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11139         ok(!refcount, "Mesh has %u references left\n", refcount);
11140 
11141         /* Mesh without adjacency data */
11142         hr = clear_normals(mesh);
11143         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11144 
11145         hr = func->apply(mesh, NULL);
11146         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11147 
11148         compare_normals(__LINE__, func->name, mesh, box_normals, ARRAY_SIZE(box_normals));
11149 
11150         /* Mesh with adjacency data */
11151         hr = clear_normals(mesh);
11152         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11153 
11154         hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11155         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11156 
11157         compare_normals(__LINE__, func->name, mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
11158 
11159         /* Mesh with custom vertex format, D3DDECLTYPE_FLOAT4 normals and adjacency */
11160         hr = mesh->lpVtbl->CloneMesh(mesh, 0, normal4f_position3f_declaration, device, &cloned_mesh);
11161         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11162 
11163         hr = clear_normals(cloned_mesh);
11164         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11165 
11166         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11167         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11168 
11169         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
11170 
11171         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11172         ok(!refcount, "Mesh has %u references left\n", refcount);
11173 
11174         /* Mesh with D3DDECLTYPE_FLOAT1 positions and D3DDECLTYPE_FLOAT3 normals */
11175         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position1f_normal3f_declaration, device, &cloned_mesh);
11176         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11177 
11178         hr = clear_normals(cloned_mesh);
11179         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11180 
11181         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11182         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11183 
11184         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position1f, ARRAY_SIZE(box_normals_position1f));
11185 
11186         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11187         ok(!refcount, "Mesh has %u references left\n", refcount);
11188 
11189         /* Mesh with D3DDECLTYPE_FLOAT2 positions and D3DDECLTYPE_FLOAT3 normals */
11190         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position2f_normal3f_declaration, device, &cloned_mesh);
11191         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11192 
11193         hr = clear_normals(cloned_mesh);
11194         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11195 
11196         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11197         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11198 
11199         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position2f, ARRAY_SIZE(box_normals_position2f));
11200 
11201         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11202         ok(!refcount, "Mesh has %u references left\n", refcount);
11203 
11204         /* Mesh with D3DDECLTYPE_FLOAT4 positions and D3DDECLTYPE_FLOAT3 normals */
11205         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position4f_normal3f_declaration, device, &cloned_mesh);
11206         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11207 
11208         hr = clear_normals(cloned_mesh);
11209         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11210 
11211         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11212         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11213 
11214         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
11215 
11216         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11217         ok(!refcount, "Mesh has %u references left\n", refcount);
11218     }
11219 
11220     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11221             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11222             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11223     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11224 
11225     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
11226 
11227     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11228             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11229             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11230     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11231 
11232     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
11233 
11234     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11235             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11236             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11237     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11238 
11239     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
11240 
11241     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11242             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11243             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11244     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11245 
11246     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
11247 
11248     refcount = mesh->lpVtbl->Release(mesh);
11249     ok(!refcount, "Mesh has %u references left\n", refcount);
11250     refcount = ID3DXBuffer_Release(adjacency);
11251     ok(!refcount, "Buffer has %u references left\n", refcount);
11252 
11253     hr = D3DXCreateSphere(device, 1.0f, 4, 6, &mesh, &adjacency);
11254     ok(SUCCEEDED(hr), "D3DXCreateSphere failed %#x\n", hr);
11255 
11256     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
11257     {
11258         const struct compute_normals_func *func = &compute_normals_funcs[i];
11259 
11260         /* Sphere without adjacency data */
11261         hr = clear_normals(mesh);
11262         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11263 
11264         hr = func->apply(mesh, NULL);
11265         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11266 
11267         compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
11268 
11269         /* Sphere with adjacency data */
11270         hr = clear_normals(mesh);
11271         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11272 
11273         hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11274         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11275 
11276         compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
11277     }
11278 
11279     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11280             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11281             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11282     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11283 
11284     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
11285 
11286     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11287             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11288             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11289     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11290 
11291     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
11292 
11293     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11294             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11295             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11296     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11297 
11298     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
11299 
11300     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11301             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11302             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11303     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11304 
11305     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
11306 
11307     refcount = mesh->lpVtbl->Release(mesh);
11308     ok(!refcount, "Mesh has %u references left\n", refcount);
11309     refcount = ID3DXBuffer_Release(adjacency);
11310     ok(!refcount, "Buffer has %u references left\n", refcount);
11311 
11312     free_test_context(test_context);
11313 }
11314 
11315 static void D3DXCreateAnimationControllerTest(void)
11316 {
11317     HRESULT hr;
11318     ID3DXAnimationController *animation;
11319     UINT value;
11320 
11321     hr = D3DXCreateAnimationController(0, 0, 0, 0, NULL);
11322     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11323 
11324     animation = (void*)0xdeadbeef;
11325     hr = D3DXCreateAnimationController(0, 1, 1, 1, &animation);
11326     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11327     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11328 
11329     animation = (void*)0xdeadbeef;
11330     hr = D3DXCreateAnimationController(1, 0, 1, 1, &animation);
11331     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11332     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11333 
11334     animation = (void*)0xdeadbeef;
11335     hr = D3DXCreateAnimationController(1, 1, 0, 1, &animation);
11336     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11337     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11338 
11339     animation = (void*)0xdeadbeef;
11340     hr = D3DXCreateAnimationController(1, 1, 1, 0, &animation);
11341     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11342     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11343 
11344     hr = D3DXCreateAnimationController(1, 1, 1, 1, &animation);
11345     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11346 
11347     value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
11348     ok(value == 1, "Got unexpected value %u.\n", value);
11349 
11350     value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
11351     ok(value == 1, "Got unexpected value %u.\n", value);
11352 
11353     value = animation->lpVtbl->GetMaxNumTracks(animation);
11354     ok(value == 1, "Got unexpected value %u.\n", value);
11355 
11356     value = animation->lpVtbl->GetMaxNumEvents(animation);
11357     ok(value == 1, "Got unexpected value %u.\n", value);
11358 
11359     animation->lpVtbl->Release(animation);
11360 
11361     hr = D3DXCreateAnimationController(100, 101, 102, 103, &animation);
11362     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11363 
11364     value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
11365     ok(value == 100, "Got unexpected value %u.\n", value);
11366 
11367     value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
11368     ok(value == 101, "Got unexpected value %u.\n", value);
11369 
11370     value = animation->lpVtbl->GetMaxNumTracks(animation);
11371     ok(value == 102, "Got unexpected value %u.\n", value);
11372 
11373     value = animation->lpVtbl->GetMaxNumEvents(animation);
11374     ok(value == 103, "Got unexpected value %u.\n", value);
11375 
11376     animation->lpVtbl->Release(animation);
11377 }
11378 
11379 static void test_D3DXFrameFind(void)
11380 {
11381     static char n1[] = "name1";
11382     static char n2[] = "name2";
11383     static char n3[] = "name3";
11384     static char n4[] = "name4";
11385     static char n5[] = "name5";
11386     static char n6[] = "name6";
11387     static char N1[] = "Name1";
11388     D3DXFRAME root, sibling, sibling2, child, *ret;
11389     D3DXFRAME child2, child3;
11390 
11391     ret = D3DXFrameFind(NULL, NULL);
11392     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11393 
11394     ret = D3DXFrameFind(NULL, "test");
11395     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11396 
11397     memset(&root, 0, sizeof(root));
11398 
11399     ret = D3DXFrameFind(&root, NULL);
11400     ok(ret == &root, "Unexpected frame, %p.\n", ret);
11401 
11402     root.Name = n1;
11403     ret = D3DXFrameFind(&root, NULL);
11404     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11405 
11406     ret = D3DXFrameFind(&root, n1);
11407     ok(ret == &root, "Unexpected frame, %p.\n", ret);
11408 
11409     ret = D3DXFrameFind(&root, N1);
11410     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11411 
11412     /* Test siblings order traversal. */
11413     memset(&sibling, 0, sizeof(sibling));
11414     sibling.Name = n2;
11415     root.pFrameSibling = &sibling;
11416     ret = D3DXFrameFind(&root, n2);
11417     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11418 
11419     memset(&sibling2, 0, sizeof(sibling2));
11420     sibling2.Name = n2;
11421     sibling.pFrameSibling = &sibling2;
11422     ret = D3DXFrameFind(&root, n2);
11423     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11424 
11425     sibling2.Name = n3;
11426     ret = D3DXFrameFind(&root, n3);
11427     ok(ret == &sibling2, "Unexpected frame, %p.\n", ret);
11428 
11429     /* Siblings first. */
11430     memset(&child, 0, sizeof(child));
11431     child.Name = n2;
11432     root.pFrameFirstChild = &child;
11433     ret = D3DXFrameFind(&root, n2);
11434     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11435 
11436     child.Name = n4;
11437     ret = D3DXFrameFind(&root, n4);
11438     ok(ret == &child, "Unexpected frame, %p.\n", ret);
11439 
11440     /* Link a grandchild and another one for sibling. */
11441     memset(&child2, 0, sizeof(child2));
11442     memset(&child3, 0, sizeof(child3));
11443     child2.Name = child3.Name = n5;
11444     sibling.pFrameFirstChild = &child2;
11445     child.pFrameFirstChild = &child3;
11446     ret = D3DXFrameFind(&root, n5);
11447     ok(ret == &child2, "Unexpected frame, %p.\n", ret);
11448 
11449     child3.Name = n6;
11450     ret = D3DXFrameFind(&root, n6);
11451     ok(ret == &child3, "Unexpected frame, %p.\n", ret);
11452 }
11453 
11454 START_TEST(mesh)
11455 {
11456     D3DXBoundProbeTest();
11457     D3DXComputeBoundingBoxTest();
11458     D3DXComputeBoundingSphereTest();
11459     D3DXGetFVFVertexSizeTest();
11460     D3DXIntersectTriTest();
11461     D3DXCreateMeshTest();
11462     D3DXCreateMeshFVFTest();
11463     D3DXLoadMeshTest();
11464     D3DXLoadSkinMeshFromXofTest();
11465     D3DXCreateBoxTest();
11466     D3DXCreatePolygonTest();
11467     D3DXCreateSphereTest();
11468     D3DXCreateCylinderTest();
11469     D3DXCreateTextTest();
11470     D3DXCreateTorusTest();
11471     D3DXCreateAnimationControllerTest();
11472     test_get_decl_length();
11473     test_get_decl_vertex_size();
11474     test_fvf_decl_conversion();
11475     D3DXGenerateAdjacencyTest();
11476     test_update_semantics();
11477     test_create_skin_info();
11478     test_update_skinned_mesh();
11479     test_convert_adjacency_to_point_reps();
11480     test_convert_point_reps_to_adjacency();
11481     test_weld_vertices();
11482     test_clone_mesh();
11483     test_valid_mesh();
11484     test_optimize_vertices();
11485     test_optimize_faces();
11486     test_compute_normals();
11487     test_D3DXFrameFind();
11488 }
11489