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 
29 #ifndef NAN
30 /* From wine/port.h */
31 static inline float __port_nan(void)
32 {
33     static const unsigned __nan_bytes = 0x7fc00000;
34     return *(const float *)&__nan_bytes;
35 }
36 #define NAN __port_nan()
37 #endif
38 
39 /* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose
40  * function call traces of ID3DXAllocateHierarchy callbacks. */
41 #define TRACECALLBACK if(winetest_debug > 1) trace
42 
43 #define admitted_error 0.0001f
44 
45 #define compare_vertex_sizes(type, exp) \
46     got=D3DXGetFVFVertexSize(type); \
47     ok(got==exp, "Expected: %d, Got: %d\n", exp, got);
48 
49 #define compare_float(got, exp) \
50     do { \
51         float _got = (got); \
52         float _exp = (exp); \
53         ok(_got == _exp, "Expected: %g, Got: %g\n", _exp, _got); \
54     } while (0)
55 
56 static BOOL compare(FLOAT u, FLOAT v)
57 {
58     return (fabs(u-v) < admitted_error);
59 }
60 
61 static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v)
62 {
63     return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
64 }
65 
66 static BOOL compare_vec4(D3DXVECTOR4 u, D3DXVECTOR4 v)
67 {
68     return compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) && compare(u.w, v.w);
69 }
70 
71 #define check_floats(got, exp, dim) check_floats_(__LINE__, "", got, exp, dim)
72 static void check_floats_(int line, const char *prefix, const float *got, const float *exp, int dim)
73 {
74     int i;
75     char exp_buffer[256] = "";
76     char got_buffer[256] = "";
77     char *exp_buffer_ptr = exp_buffer;
78     char *got_buffer_ptr = got_buffer;
79     BOOL equal = TRUE;
80 
81     for (i = 0; i < dim; i++) {
82         if (i) {
83             exp_buffer_ptr += sprintf(exp_buffer_ptr, ", ");
84             got_buffer_ptr += sprintf(got_buffer_ptr, ", ");
85         }
86         equal = equal && compare(*exp, *got);
87         exp_buffer_ptr += sprintf(exp_buffer_ptr, "%g", *exp);
88         got_buffer_ptr += sprintf(got_buffer_ptr, "%g", *got);
89         exp++, got++;
90     }
91     ok_(__FILE__,line)(equal, "%sExpected (%s), got (%s)", prefix, exp_buffer, got_buffer);
92 }
93 
94 struct vertex
95 {
96     D3DXVECTOR3 position;
97     D3DXVECTOR3 normal;
98 };
99 
100 typedef WORD face[3];
101 
102 static BOOL compare_face(face a, face b)
103 {
104     return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
105 }
106 
107 struct test_context
108 {
109     HWND hwnd;
110     IDirect3D9 *d3d;
111     IDirect3DDevice9 *device;
112 };
113 
114 /* Initializes a test context struct. Use it to initialize DirectX.
115  *
116  * Returns NULL if an error occurred.
117  */
118 static struct test_context *new_test_context(void)
119 {
120     HRESULT hr;
121     HWND hwnd = NULL;
122     IDirect3D9 *d3d = NULL;
123     IDirect3DDevice9 *device = NULL;
124     D3DPRESENT_PARAMETERS d3dpp = {0};
125     struct test_context *test_context;
126 
127     if (!(hwnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
128             640, 480, NULL, NULL, NULL, NULL)))
129     {
130         skip("Couldn't create application window\n");
131         goto error;
132     }
133 
134     d3d = Direct3DCreate9(D3D_SDK_VERSION);
135     if (!d3d)
136     {
137         skip("Couldn't create IDirect3D9 object\n");
138         goto error;
139     }
140 
141     memset(&d3dpp, 0, sizeof(d3dpp));
142     d3dpp.Windowed = TRUE;
143     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
144     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
145                                  D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
146     if (FAILED(hr))
147     {
148         skip("Couldn't create IDirect3DDevice9 object %#x\n", hr);
149         goto error;
150     }
151 
152     test_context = HeapAlloc(GetProcessHeap(), 0, sizeof(*test_context));
153     if (!test_context)
154     {
155         skip("Couldn't allocate memory for test_context\n");
156         goto error;
157     }
158     test_context->hwnd = hwnd;
159     test_context->d3d = d3d;
160     test_context->device = device;
161 
162     return test_context;
163 
164 error:
165     if (device)
166         IDirect3DDevice9_Release(device);
167 
168     if (d3d)
169         IDirect3D9_Release(d3d);
170 
171     if (hwnd)
172         DestroyWindow(hwnd);
173 
174     return NULL;
175 }
176 
177 static void free_test_context(struct test_context *test_context)
178 {
179     if (!test_context)
180         return;
181 
182     if (test_context->device)
183         IDirect3DDevice9_Release(test_context->device);
184 
185     if (test_context->d3d)
186         IDirect3D9_Release(test_context->d3d);
187 
188     if (test_context->hwnd)
189         DestroyWindow(test_context->hwnd);
190 
191     HeapFree(GetProcessHeap(), 0, test_context);
192 }
193 
194 struct mesh
195 {
196     DWORD number_of_vertices;
197     struct vertex *vertices;
198 
199     DWORD number_of_faces;
200     face *faces;
201 
202     DWORD fvf;
203     UINT vertex_size;
204 };
205 
206 static void free_mesh(struct mesh *mesh)
207 {
208     HeapFree(GetProcessHeap(), 0, mesh->faces);
209     HeapFree(GetProcessHeap(), 0, mesh->vertices);
210 }
211 
212 static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
213 {
214     mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
215     if (!mesh->vertices)
216     {
217         return FALSE;
218     }
219     mesh->number_of_vertices = number_of_vertices;
220 
221     mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
222     if (!mesh->faces)
223     {
224         HeapFree(GetProcessHeap(), 0, mesh->vertices);
225         return FALSE;
226     }
227     mesh->number_of_faces = number_of_faces;
228 
229     return TRUE;
230 }
231 
232 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
233 {
234     HRESULT hr;
235     DWORD number_of_vertices, number_of_faces;
236     IDirect3DVertexBuffer9 *vertex_buffer;
237     IDirect3DIndexBuffer9 *index_buffer;
238     D3DVERTEXBUFFER_DESC vertex_buffer_description;
239     D3DINDEXBUFFER_DESC index_buffer_description;
240     struct vertex *vertices;
241     face *faces;
242     int expected, i;
243 
244     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
245     ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
246        name, number_of_vertices, mesh->number_of_vertices);
247 
248     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
249     ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
250        name, number_of_faces, mesh->number_of_faces);
251 
252     /* vertex buffer */
253     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
254     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
255 
256     if (hr != D3D_OK)
257     {
258         skip("Couldn't get vertex buffer\n");
259     }
260     else
261     {
262         hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
263         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
264 
265         if (hr != D3D_OK)
266         {
267             skip("Couldn't get vertex buffer description\n");
268         }
269         else
270         {
271             ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
272                name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
273             ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
274                name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
275             ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
276             ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
277                name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
278             ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
279                name, vertex_buffer_description.FVF, mesh->fvf);
280             if (mesh->fvf == 0)
281             {
282                 expected = number_of_vertices * mesh->vertex_size;
283             }
284             else
285             {
286                 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
287             }
288             ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
289                name, vertex_buffer_description.Size, expected);
290         }
291 
292         /* specify offset and size to avoid potential overruns */
293         hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
294                 (void **)&vertices, D3DLOCK_DISCARD);
295         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
296 
297         if (hr != D3D_OK)
298         {
299             skip("Couldn't lock vertex buffer\n");
300         }
301         else
302         {
303             for (i = 0; i < number_of_vertices; i++)
304             {
305                 ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
306                    "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
307                    vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
308                    mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
309                 ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
310                    "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
311                    vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
312                    mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
313             }
314 
315             IDirect3DVertexBuffer9_Unlock(vertex_buffer);
316         }
317 
318         IDirect3DVertexBuffer9_Release(vertex_buffer);
319     }
320 
321     /* index buffer */
322     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
323     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
324 
325     if (!index_buffer)
326     {
327         skip("Couldn't get index buffer\n");
328     }
329     else
330     {
331         hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
332         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
333 
334         if (hr != D3D_OK)
335         {
336             skip("Couldn't get index buffer description\n");
337         }
338         else
339         {
340             ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
341                name, index_buffer_description.Format, D3DFMT_INDEX16);
342             ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
343                name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
344             ok(index_buffer_description.Usage == 0, "Test %s, result %#x, expected %#x.\n",
345                     name, index_buffer_description.Usage, 0);
346             ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
347                name, index_buffer_description.Pool, D3DPOOL_MANAGED);
348             expected = number_of_faces * sizeof(WORD) * 3;
349             ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
350                name, index_buffer_description.Size, expected);
351         }
352 
353         /* specify offset and size to avoid potential overruns */
354         hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
355                 (void **)&faces, D3DLOCK_DISCARD);
356         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
357 
358         if (hr != D3D_OK)
359         {
360             skip("Couldn't lock index buffer\n");
361         }
362         else
363         {
364             for (i = 0; i < number_of_faces; i++)
365             {
366                 ok(compare_face(faces[i], mesh->faces[i]),
367                    "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
368                    faces[i][0], faces[i][1], faces[i][2],
369                    mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
370             }
371 
372             IDirect3DIndexBuffer9_Unlock(index_buffer);
373         }
374 
375         IDirect3DIndexBuffer9_Release(index_buffer);
376     }
377 }
378 
379 static void D3DXBoundProbeTest(void)
380 {
381     BOOL result;
382     D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
383     FLOAT radius;
384 
385 /*____________Test the Box case___________________________*/
386     bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
387     top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
388 
389     raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
390     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
391     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
392     ok(result == TRUE, "expected TRUE, received FALSE\n");
393 
394     raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
395     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
396     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
397     ok(result == FALSE, "expected FALSE, received TRUE\n");
398 
399     rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
400     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
401     ok(result == TRUE, "expected TRUE, received FALSE\n");
402 
403     bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
404     top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
405     rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
406     raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
407     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
408     ok(result == FALSE, "expected FALSE, received TRUE\n");
409 
410     bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
411     top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
412 
413     raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
414     rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
415     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
416     ok(result == TRUE, "expected TRUE, received FALSE\n");
417 
418     bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
419     top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
420 
421     raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
422     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
423     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
424     ok(result == FALSE, "expected FALSE, received TRUE\n");
425 
426     raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
427     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
428     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
429     ok(result == TRUE, "expected TRUE, received FALSE\n");
430 
431 /*____________Test the Sphere case________________________*/
432     radius = sqrt(77.0f);
433     center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
434     raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
435 
436     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
437     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
438     ok(result == TRUE, "expected TRUE, received FALSE\n");
439 
440     rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
441     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
442     ok(result == FALSE, "expected FALSE, received TRUE\n");
443 
444     rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
445     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
446     ok(result == FALSE, "expected FALSE, received TRUE\n");
447 }
448 
449 static void D3DXComputeBoundingBoxTest(void)
450 {
451     D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
452     HRESULT hr;
453 
454     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
455     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
456     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
457     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
458     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
459 
460     exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
461     exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
462 
463     hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
464 
465     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
466     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);
467     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);
468 
469 /*________________________*/
470 
471     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
472     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
473     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
474     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
475     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
476 
477     exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
478     exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
479 
480     hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
481 
482     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
483     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);
484     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);
485 
486 /*________________________*/
487 
488     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
489     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
490     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
491     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
492     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
493 
494     exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
495     exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
496 
497     hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
498 
499     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
500     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);
501     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);
502 
503 /*________________________*/
504     hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
505     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
506 
507 /*________________________*/
508     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
509     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
510 
511 /*________________________*/
512     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
513     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
514 }
515 
516 static void D3DXComputeBoundingSphereTest(void)
517 {
518     D3DXVECTOR3 exp_cen, got_cen, vertex[5];
519     FLOAT exp_rad, got_rad;
520     HRESULT hr;
521 
522     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
523     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
524     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
525     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
526     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
527 
528     exp_rad = 6.928203f;
529     exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
530 
531     hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
532 
533     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
534     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
535     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);
536 
537 /*________________________*/
538 
539     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
540     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
541     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
542     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
543     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
544 
545     exp_rad = 13.707883f;
546     exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
547 
548     hr = D3DXComputeBoundingSphere(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
549 
550     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
551     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
552     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);
553 
554 /*________________________*/
555     hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
556     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
557 
558 /*________________________*/
559     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
560     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
561 
562 /*________________________*/
563     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
564     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
565 }
566 
567 static void print_elements(const D3DVERTEXELEMENT9 *elements)
568 {
569     D3DVERTEXELEMENT9 last = D3DDECL_END();
570     const D3DVERTEXELEMENT9 *ptr = elements;
571     int count = 0;
572 
573     while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
574     {
575         trace(
576             "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
577              count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
578         ptr++;
579         count++;
580     }
581 }
582 
583 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
584         unsigned int line, unsigned int test_id)
585 {
586     D3DVERTEXELEMENT9 last = D3DDECL_END();
587     unsigned int i;
588 
589     for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
590     {
591         int end1 = memcmp(&elements[i], &last, sizeof(last));
592         int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
593         int status;
594 
595         if (!end1 && !end2) break;
596 
597         status = !end1 ^ !end2;
598         ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
599                 line, test_id, end1 ? "shorter" : "longer");
600         if (status)
601         {
602             print_elements(elements);
603             break;
604         }
605 
606         status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
607         ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
608         if (status)
609         {
610             print_elements(elements);
611             break;
612         }
613     }
614 }
615 
616 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
617         HRESULT expected_hr, unsigned int line, unsigned int test_id)
618 {
619     HRESULT hr;
620     D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
621 
622     hr = D3DXDeclaratorFromFVF(test_fvf, decl);
623     ok(hr == expected_hr,
624             "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
625             line, test_id, hr, expected_hr);
626     if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
627 }
628 
629 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
630         HRESULT expected_hr, unsigned int line, unsigned int test_id)
631 {
632     HRESULT hr;
633     DWORD result_fvf = 0xdeadbeef;
634 
635     hr = D3DXFVFFromDeclarator(decl, &result_fvf);
636     ok(hr == expected_hr,
637        "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
638        line, test_id, hr, expected_hr);
639     if (SUCCEEDED(hr))
640     {
641         ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
642                 line, test_id, result_fvf, expected_fvf);
643     }
644 }
645 
646 static void test_fvf_decl_conversion(void)
647 {
648     static const struct
649     {
650         D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
651         DWORD fvf;
652     }
653     test_data[] =
654     {
655         {{
656             D3DDECL_END(),
657         }, 0},
658         {{
659             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
660             D3DDECL_END(),
661         }, D3DFVF_XYZ},
662         {{
663             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
664             D3DDECL_END(),
665         }, D3DFVF_XYZRHW},
666         {{
667             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
668             D3DDECL_END(),
669         }, D3DFVF_XYZRHW},
670         {{
671             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
672             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
673             D3DDECL_END(),
674         }, D3DFVF_XYZB1},
675         {{
676             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
677             {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
678             D3DDECL_END(),
679         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
680         {{
681             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
682             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
683             D3DDECL_END(),
684         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
685         {{
686             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
687             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
688             D3DDECL_END(),
689         }, D3DFVF_XYZB2},
690         {{
691             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
692             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
693             {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
694             D3DDECL_END(),
695         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
696         {{
697             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
698             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
699             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
700             D3DDECL_END(),
701         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
702         {{
703             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
704             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
705             D3DDECL_END(),
706         }, D3DFVF_XYZB3},
707         {{
708             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
709             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
710             {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
711             D3DDECL_END(),
712         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
713         {{
714             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
715             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
716             {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
717             D3DDECL_END(),
718         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
719         {{
720             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
721             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
722             D3DDECL_END(),
723         }, D3DFVF_XYZB4},
724         {{
725             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
726             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
727             {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
728             D3DDECL_END(),
729         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
730         {{
731             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
732             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
733             {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
734             D3DDECL_END(),
735         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
736         {{
737             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
738             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
739             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
740             D3DDECL_END(),
741         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
742         {{
743             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
744             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
745             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
746             D3DDECL_END(),
747         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
748         {{
749             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
750             D3DDECL_END(),
751         }, D3DFVF_NORMAL},
752         {{
753             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
754             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
755             D3DDECL_END(),
756         }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
757         {{
758             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
759             D3DDECL_END(),
760         }, D3DFVF_PSIZE},
761         {{
762             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
763             D3DDECL_END(),
764         }, D3DFVF_DIFFUSE},
765         {{
766             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
767             D3DDECL_END(),
768         }, D3DFVF_SPECULAR},
769         /* Make sure textures of different sizes work. */
770         {{
771             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
772             D3DDECL_END(),
773         }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
774         {{
775             {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
776             D3DDECL_END(),
777         }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
778         {{
779             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
780             D3DDECL_END(),
781         }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
782         {{
783             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
784             D3DDECL_END(),
785         }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
786         /* Make sure the TEXCOORD index works correctly - try several textures. */
787         {{
788             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
789             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
790             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
791             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
792             D3DDECL_END(),
793         }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
794                 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
795         /* Now try some combination tests. */
796         {{
797             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
798             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
799             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
800             {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
801             {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
802             {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
803             D3DDECL_END(),
804         }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
805                 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
806         {{
807             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
808             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
809             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
810             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
811             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
812             {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
813             D3DDECL_END(),
814         }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
815                 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
816     };
817     unsigned int i;
818 
819     for (i = 0; i < ARRAY_SIZE(test_data); ++i)
820     {
821         test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
822         test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
823     }
824 
825     /* Usage indices for position and normal are apparently ignored. */
826     {
827         const D3DVERTEXELEMENT9 decl[] =
828         {
829             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
830             D3DDECL_END(),
831         };
832         test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
833     }
834     {
835         const D3DVERTEXELEMENT9 decl[] =
836         {
837             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
838             D3DDECL_END(),
839         };
840         test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
841     }
842     /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
843      * there are no blend matrices. */
844     {
845         const D3DVERTEXELEMENT9 decl[] =
846         {
847             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
848             D3DDECL_END(),
849         };
850         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
851     }
852     {
853         const D3DVERTEXELEMENT9 decl[] =
854         {
855             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
856             D3DDECL_END(),
857         };
858         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
859     }
860     /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
861     {
862         const D3DVERTEXELEMENT9 decl[] =
863         {
864             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
865             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
866             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
867             D3DDECL_END(),
868         };
869         test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
870                 decl, D3D_OK, __LINE__, 0);
871     }
872     /* These are supposed to fail, both ways. */
873     {
874         const D3DVERTEXELEMENT9 decl[] =
875         {
876             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
877             D3DDECL_END(),
878         };
879         test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
880         test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
881     }
882     {
883         const D3DVERTEXELEMENT9 decl[] =
884         {
885             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
886             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
887             D3DDECL_END(),
888         };
889         test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
890         test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
891     }
892     {
893         const D3DVERTEXELEMENT9 decl[] =
894         {
895             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
896             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
897             {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
898             D3DDECL_END(),
899         };
900         test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
901         test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
902     }
903     /* Test a declaration that can't be converted to an FVF. */
904     {
905         const D3DVERTEXELEMENT9 decl[] =
906         {
907             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
908             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
909             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
910             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
911             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
912             /* 8 bytes padding */
913             {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
914             D3DDECL_END(),
915         };
916         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
917     }
918     /* Elements must be ordered by offset. */
919     {
920         const D3DVERTEXELEMENT9 decl[] =
921         {
922             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
923             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
924             D3DDECL_END(),
925         };
926         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
927     }
928     /* Basic tests for element order. */
929     {
930         const D3DVERTEXELEMENT9 decl[] =
931         {
932             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
933             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
934             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
935             D3DDECL_END(),
936         };
937         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
938     }
939     {
940         const D3DVERTEXELEMENT9 decl[] =
941         {
942             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
943             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
944             D3DDECL_END(),
945         };
946         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
947     }
948     {
949         const D3DVERTEXELEMENT9 decl[] =
950         {
951             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
952             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
953             D3DDECL_END(),
954         };
955         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
956     }
957     /* Textures must be ordered by texcoords. */
958     {
959         const D3DVERTEXELEMENT9 decl[] =
960         {
961             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
962             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
963             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
964             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
965             D3DDECL_END(),
966         };
967         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
968     }
969     /* Duplicate elements are not allowed. */
970     {
971         const D3DVERTEXELEMENT9 decl[] =
972         {
973             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
974             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
975             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
976             D3DDECL_END(),
977         };
978         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
979     }
980     /* Invalid FVFs cannot be converted to a declarator. */
981     test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
982 }
983 
984 static void D3DXGetFVFVertexSizeTest(void)
985 {
986     UINT got;
987 
988     compare_vertex_sizes (D3DFVF_XYZ, 12);
989 
990     compare_vertex_sizes (D3DFVF_XYZB3, 24);
991 
992     compare_vertex_sizes (D3DFVF_XYZB5, 32);
993 
994     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
995 
996     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
997 
998     compare_vertex_sizes (
999         D3DFVF_XYZ |
1000         D3DFVF_TEX1 |
1001         D3DFVF_TEXCOORDSIZE1(0), 16);
1002     compare_vertex_sizes (
1003         D3DFVF_XYZ |
1004         D3DFVF_TEX2 |
1005         D3DFVF_TEXCOORDSIZE1(0) |
1006         D3DFVF_TEXCOORDSIZE1(1), 20);
1007 
1008     compare_vertex_sizes (
1009         D3DFVF_XYZ |
1010         D3DFVF_TEX1 |
1011         D3DFVF_TEXCOORDSIZE2(0), 20);
1012 
1013     compare_vertex_sizes (
1014         D3DFVF_XYZ |
1015         D3DFVF_TEX2 |
1016         D3DFVF_TEXCOORDSIZE2(0) |
1017         D3DFVF_TEXCOORDSIZE2(1), 28);
1018 
1019     compare_vertex_sizes (
1020         D3DFVF_XYZ |
1021         D3DFVF_TEX6 |
1022         D3DFVF_TEXCOORDSIZE2(0) |
1023         D3DFVF_TEXCOORDSIZE2(1) |
1024         D3DFVF_TEXCOORDSIZE2(2) |
1025         D3DFVF_TEXCOORDSIZE2(3) |
1026         D3DFVF_TEXCOORDSIZE2(4) |
1027         D3DFVF_TEXCOORDSIZE2(5), 60);
1028 
1029     compare_vertex_sizes (
1030         D3DFVF_XYZ |
1031         D3DFVF_TEX8 |
1032         D3DFVF_TEXCOORDSIZE2(0) |
1033         D3DFVF_TEXCOORDSIZE2(1) |
1034         D3DFVF_TEXCOORDSIZE2(2) |
1035         D3DFVF_TEXCOORDSIZE2(3) |
1036         D3DFVF_TEXCOORDSIZE2(4) |
1037         D3DFVF_TEXCOORDSIZE2(5) |
1038         D3DFVF_TEXCOORDSIZE2(6) |
1039         D3DFVF_TEXCOORDSIZE2(7), 76);
1040 
1041     compare_vertex_sizes (
1042         D3DFVF_XYZ |
1043         D3DFVF_TEX1 |
1044         D3DFVF_TEXCOORDSIZE3(0), 24);
1045 
1046     compare_vertex_sizes (
1047         D3DFVF_XYZ |
1048         D3DFVF_TEX4 |
1049         D3DFVF_TEXCOORDSIZE3(0) |
1050         D3DFVF_TEXCOORDSIZE3(1) |
1051         D3DFVF_TEXCOORDSIZE3(2) |
1052         D3DFVF_TEXCOORDSIZE3(3), 60);
1053 
1054     compare_vertex_sizes (
1055         D3DFVF_XYZ |
1056         D3DFVF_TEX1 |
1057         D3DFVF_TEXCOORDSIZE4(0), 28);
1058 
1059     compare_vertex_sizes (
1060         D3DFVF_XYZ |
1061         D3DFVF_TEX2 |
1062         D3DFVF_TEXCOORDSIZE4(0) |
1063         D3DFVF_TEXCOORDSIZE4(1), 44);
1064 
1065     compare_vertex_sizes (
1066         D3DFVF_XYZ |
1067         D3DFVF_TEX3 |
1068         D3DFVF_TEXCOORDSIZE4(0) |
1069         D3DFVF_TEXCOORDSIZE4(1) |
1070         D3DFVF_TEXCOORDSIZE4(2), 60);
1071 
1072     compare_vertex_sizes (
1073         D3DFVF_XYZB5 |
1074         D3DFVF_NORMAL |
1075         D3DFVF_DIFFUSE |
1076         D3DFVF_SPECULAR |
1077         D3DFVF_TEX8 |
1078         D3DFVF_TEXCOORDSIZE4(0) |
1079         D3DFVF_TEXCOORDSIZE4(1) |
1080         D3DFVF_TEXCOORDSIZE4(2) |
1081         D3DFVF_TEXCOORDSIZE4(3) |
1082         D3DFVF_TEXCOORDSIZE4(4) |
1083         D3DFVF_TEXCOORDSIZE4(5) |
1084         D3DFVF_TEXCOORDSIZE4(6) |
1085         D3DFVF_TEXCOORDSIZE4(7), 180);
1086 }
1087 
1088 static void D3DXIntersectTriTest(void)
1089 {
1090     BOOL exp_res, got_res;
1091     D3DXVECTOR3 position, ray, vertex[3];
1092     FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
1093 
1094     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1095     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1096     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1097 
1098     position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
1099 
1100     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1101 
1102     exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
1103 
1104     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1105     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1106     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1107     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1108     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1109 
1110     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1111     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1112 
1113     vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1114     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1115     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 0.0f;
1116 
1117     got_u = got_v = got_dist = 0.0f;
1118     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1119     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1120     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1121     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1122     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1123 
1124     vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1125     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = -0.5f;
1126     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = -1.0f;
1127     exp_u = 0.375f;
1128     exp_v = 0.5625f;
1129     exp_dist = 7.9375f;
1130     got_u = got_v = got_dist = 0.0f;
1131     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1132     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1133     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1134     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1135     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1136 
1137 
1138 /*Only positive ray is taken in account*/
1139 
1140     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1141     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1142     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1143 
1144     position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
1145 
1146     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1147 
1148     exp_res = FALSE;
1149 
1150     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1151     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1152 
1153     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1154     ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1155 
1156 /*Intersection between ray and triangle in a same plane is considered as empty*/
1157 
1158     vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1159     vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1160     vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
1161 
1162     position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
1163 
1164     ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
1165 
1166     exp_res = FALSE;
1167 
1168     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1169     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1170 
1171     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1172     ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1173 }
1174 
1175 static void D3DXCreateMeshTest(void)
1176 {
1177     HRESULT hr;
1178     IDirect3DDevice9 *device, *test_device;
1179     ID3DXMesh *d3dxmesh;
1180     int i, size;
1181     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1182     DWORD options;
1183     struct mesh mesh;
1184     struct test_context *test_context;
1185 
1186     static const D3DVERTEXELEMENT9 decl1[] =
1187     {
1188         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1189         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1190         D3DDECL_END(),
1191     };
1192 
1193     static const D3DVERTEXELEMENT9 decl2[] =
1194     {
1195         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1196         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1197         {0, 24, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
1198         {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
1199         {0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
1200         /* 8 bytes padding */
1201         {0, 44, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
1202         D3DDECL_END(),
1203     };
1204 
1205     static const D3DVERTEXELEMENT9 decl3[] =
1206     {
1207         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1208         {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1209         D3DDECL_END(),
1210     };
1211 
1212     hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1213     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1214 
1215     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1216     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1217 
1218     test_context = new_test_context();
1219     if (!test_context)
1220     {
1221         skip("Couldn't create test context\n");
1222         return;
1223     }
1224     device = test_context->device;
1225 
1226     hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1227     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1228 
1229     hr = D3DXCreateMesh(1, 0, 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, 3, 0, decl1, device, &d3dxmesh);
1233     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1234 
1235     if (hr == D3D_OK)
1236     {
1237         d3dxmesh->lpVtbl->Release(d3dxmesh);
1238     }
1239 
1240     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1241     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1242 
1243     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
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, &d3dxmesh);
1247     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1248 
1249     if (hr == D3D_OK)
1250     {
1251         /* device */
1252         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1253         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1254 
1255         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1256         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1257         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1258 
1259         if (hr == D3D_OK)
1260         {
1261             IDirect3DDevice9_Release(device);
1262         }
1263 
1264         /* declaration */
1265         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1266         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1267 
1268         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1269         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1270 
1271         if (hr == D3D_OK)
1272         {
1273             size = ARRAY_SIZE(decl1);
1274             for (i = 0; i < size - 1; i++)
1275             {
1276                 ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1277                 ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1278                 ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1279                 ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1280                 ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1281                 ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1282             }
1283             ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1284         }
1285 
1286         /* options */
1287         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1288         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1289 
1290         /* rest */
1291         if (!new_mesh(&mesh, 3, 1))
1292         {
1293             skip("Couldn't create mesh\n");
1294         }
1295         else
1296         {
1297             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1298             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1299             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1300 
1301             compare_mesh("createmesh1", d3dxmesh, &mesh);
1302 
1303             free_mesh(&mesh);
1304         }
1305 
1306         d3dxmesh->lpVtbl->Release(d3dxmesh);
1307     }
1308 
1309     /* Test a declaration that can't be converted to an FVF. */
1310     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1311     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1312 
1313     if (hr == D3D_OK)
1314     {
1315         /* device */
1316         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1317         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1318 
1319         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1320         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1321         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1322 
1323         if (hr == D3D_OK)
1324         {
1325             IDirect3DDevice9_Release(device);
1326         }
1327 
1328         /* declaration */
1329         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1330         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1331 
1332         if (hr == D3D_OK)
1333         {
1334             size = ARRAY_SIZE(decl2);
1335             for (i = 0; i < size - 1; i++)
1336             {
1337                 ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1338                 ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1339                 ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1340                 ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1341                 ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1342                 ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1343             }
1344             ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1345         }
1346 
1347         /* options */
1348         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1349         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1350 
1351         /* rest */
1352         if (!new_mesh(&mesh, 3, 1))
1353         {
1354             skip("Couldn't create mesh\n");
1355         }
1356         else
1357         {
1358             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1359             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1360             mesh.fvf = 0;
1361             mesh.vertex_size = 60;
1362 
1363             compare_mesh("createmesh2", d3dxmesh, &mesh);
1364 
1365             free_mesh(&mesh);
1366         }
1367 
1368         mesh.vertex_size = d3dxmesh->lpVtbl->GetNumBytesPerVertex(d3dxmesh);
1369         ok(mesh.vertex_size == 60, "Got vertex size %u, expected %u\n", mesh.vertex_size, 60);
1370 
1371         d3dxmesh->lpVtbl->Release(d3dxmesh);
1372     }
1373 
1374     /* Test a declaration with multiple streams. */
1375     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
1376     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1377 
1378     free_test_context(test_context);
1379 }
1380 
1381 static void D3DXCreateMeshFVFTest(void)
1382 {
1383     HRESULT hr;
1384     IDirect3DDevice9 *device, *test_device;
1385     ID3DXMesh *d3dxmesh;
1386     int i, size;
1387     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1388     DWORD options;
1389     struct mesh mesh;
1390     struct test_context *test_context;
1391 
1392     static const D3DVERTEXELEMENT9 decl[] =
1393     {
1394         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1395         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1396         D3DDECL_END(),
1397     };
1398 
1399     hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1400     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1401 
1402     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, NULL, &d3dxmesh);
1403     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1404 
1405     test_context = new_test_context();
1406     if (!test_context)
1407     {
1408         skip("Couldn't create test context\n");
1409         return;
1410     }
1411     device = test_context->device;
1412 
1413     hr = D3DXCreateMeshFVF(0, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1414     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1415 
1416     hr = D3DXCreateMeshFVF(1, 0, 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, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1420     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1421 
1422     if (hr == D3D_OK)
1423     {
1424         d3dxmesh->lpVtbl->Release(d3dxmesh);
1425     }
1426 
1427     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1428     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1429 
1430     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, NULL);
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, &d3dxmesh);
1434     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1435 
1436     if (hr == D3D_OK)
1437     {
1438         /* device */
1439         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1440         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1441 
1442         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1443         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1444         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1445 
1446         if (hr == D3D_OK)
1447         {
1448             IDirect3DDevice9_Release(device);
1449         }
1450 
1451         /* declaration */
1452         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1453         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1454 
1455         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1456         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1457 
1458         if (hr == D3D_OK)
1459         {
1460             size = ARRAY_SIZE(decl);
1461             for (i = 0; i < size - 1; i++)
1462             {
1463                 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1464                 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1465                 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1466                 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1467                 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1468                    test_decl[i].UsageIndex, decl[i].UsageIndex);
1469                 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1470             }
1471             ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1472         }
1473 
1474         /* options */
1475         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1476         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1477 
1478         /* rest */
1479         if (!new_mesh(&mesh, 3, 1))
1480         {
1481             skip("Couldn't create mesh\n");
1482         }
1483         else
1484         {
1485             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1486             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1487             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1488 
1489             compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1490 
1491             free_mesh(&mesh);
1492         }
1493 
1494         d3dxmesh->lpVtbl->Release(d3dxmesh);
1495     }
1496 
1497     free_test_context(test_context);
1498 }
1499 
1500 #define check_vertex_buffer(mesh, vertices, num_vertices, fvf) \
1501     check_vertex_buffer_(__LINE__, mesh, vertices, num_vertices, fvf)
1502 static void check_vertex_buffer_(int line, ID3DXMesh *mesh, const void *vertices, DWORD num_vertices, DWORD fvf)
1503 {
1504     DWORD mesh_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
1505     DWORD mesh_fvf = mesh->lpVtbl->GetFVF(mesh);
1506     const void *mesh_vertices;
1507     HRESULT hr;
1508 
1509     ok_(__FILE__,line)(fvf == mesh_fvf, "expected FVF %x, got %x\n", fvf, mesh_fvf);
1510     ok_(__FILE__,line)(num_vertices == mesh_num_vertices,
1511        "Expected %u vertices, got %u\n", num_vertices, mesh_num_vertices);
1512 
1513     hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
1514     ok_(__FILE__,line)(hr == D3D_OK, "LockVertexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1515     if (FAILED(hr))
1516         return;
1517 
1518     if (mesh_fvf == fvf) {
1519         DWORD vertex_size = D3DXGetFVFVertexSize(fvf), i;
1520 
1521         for (i = 0; i < min(num_vertices, mesh_num_vertices); i++)
1522         {
1523             const FLOAT *exp_float = vertices;
1524             const FLOAT *got_float = mesh_vertices;
1525             DWORD texcount;
1526             DWORD pos_dim = 0;
1527             int j;
1528             BOOL last_beta_dword = FALSE;
1529             char prefix[128];
1530 
1531             switch (fvf & D3DFVF_POSITION_MASK) {
1532                 case D3DFVF_XYZ: pos_dim = 3; break;
1533                 case D3DFVF_XYZRHW: pos_dim = 4; break;
1534                 case D3DFVF_XYZB1:
1535                 case D3DFVF_XYZB2:
1536                 case D3DFVF_XYZB3:
1537                 case D3DFVF_XYZB4:
1538                 case D3DFVF_XYZB5:
1539                     pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
1540                     if (fvf & (D3DFVF_LASTBETA_UBYTE4 | D3DFVF_LASTBETA_D3DCOLOR))
1541                     {
1542                         pos_dim--;
1543                         last_beta_dword = TRUE;
1544                     }
1545                     break;
1546                 case D3DFVF_XYZW: pos_dim = 4; break;
1547             }
1548             sprintf(prefix, "vertex[%u] position, ", i);
1549             check_floats_(line, prefix, got_float, exp_float, pos_dim);
1550             exp_float += pos_dim;
1551             got_float += pos_dim;
1552 
1553             if (last_beta_dword) {
1554                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1555                     "Vertex[%u]: Expected last beta %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1556                 exp_float++;
1557                 got_float++;
1558             }
1559 
1560             if (fvf & D3DFVF_NORMAL) {
1561                 sprintf(prefix, "vertex[%u] normal, ", i);
1562                 check_floats_(line, prefix, got_float, exp_float, 3);
1563                 exp_float += 3;
1564                 got_float += 3;
1565             }
1566             if (fvf & D3DFVF_PSIZE) {
1567                 ok_(__FILE__,line)(compare(*exp_float, *got_float),
1568                         "Vertex[%u]: Expected psize %g, got %g\n", i, *exp_float, *got_float);
1569                 exp_float++;
1570                 got_float++;
1571             }
1572             if (fvf & D3DFVF_DIFFUSE) {
1573                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1574                     "Vertex[%u]: Expected diffuse %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1575                 exp_float++;
1576                 got_float++;
1577             }
1578             if (fvf & D3DFVF_SPECULAR) {
1579                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1580                     "Vertex[%u]: Expected specular %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1581                 exp_float++;
1582                 got_float++;
1583             }
1584 
1585             texcount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
1586             for (j = 0; j < texcount; j++) {
1587                 DWORD dim = (((fvf >> (16 + 2 * j)) + 1) & 0x03) + 1;
1588                 sprintf(prefix, "vertex[%u] texture, ", i);
1589                 check_floats_(line, prefix, got_float, exp_float, dim);
1590                 exp_float += dim;
1591                 got_float += dim;
1592             }
1593 
1594             vertices = (BYTE*)vertices + vertex_size;
1595             mesh_vertices = (BYTE*)mesh_vertices + vertex_size;
1596         }
1597     }
1598 
1599     mesh->lpVtbl->UnlockVertexBuffer(mesh);
1600 }
1601 
1602 #define check_index_buffer(mesh, indices, num_indices, index_size) \
1603     check_index_buffer_(__LINE__, mesh, indices, num_indices, index_size)
1604 static void check_index_buffer_(int line, ID3DXMesh *mesh, const void *indices, DWORD num_indices, DWORD index_size)
1605 {
1606     DWORD mesh_index_size = (mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT) ? 4 : 2;
1607     DWORD mesh_num_indices = mesh->lpVtbl->GetNumFaces(mesh) * 3;
1608     const void *mesh_indices;
1609     HRESULT hr;
1610     DWORD i;
1611 
1612     ok_(__FILE__,line)(index_size == mesh_index_size,
1613         "Expected index size %u, got %u\n", index_size, mesh_index_size);
1614     ok_(__FILE__,line)(num_indices == mesh_num_indices,
1615         "Expected %u indices, got %u\n", num_indices, mesh_num_indices);
1616 
1617     hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
1618     ok_(__FILE__,line)(hr == D3D_OK, "LockIndexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1619     if (FAILED(hr))
1620         return;
1621 
1622     if (mesh_index_size == index_size) {
1623         for (i = 0; i < min(num_indices, mesh_num_indices); i++)
1624         {
1625             if (index_size == 4)
1626                 ok_(__FILE__,line)(*(DWORD*)indices == *(DWORD*)mesh_indices,
1627                     "Index[%u]: expected %u, got %u\n", i, *(DWORD*)indices, *(DWORD*)mesh_indices);
1628             else
1629                 ok_(__FILE__,line)(*(WORD*)indices == *(WORD*)mesh_indices,
1630                     "Index[%u]: expected %u, got %u\n", i, *(WORD*)indices, *(WORD*)mesh_indices);
1631             indices = (BYTE*)indices + index_size;
1632             mesh_indices = (BYTE*)mesh_indices + index_size;
1633         }
1634     }
1635     mesh->lpVtbl->UnlockIndexBuffer(mesh);
1636 }
1637 
1638 #define check_matrix(got, expected) check_matrix_(__LINE__, got, expected)
1639 static void check_matrix_(int line, const D3DXMATRIX *got, const D3DXMATRIX *expected)
1640 {
1641     int i, j;
1642     for (i = 0; i < 4; i++) {
1643         for (j = 0; j < 4; j++) {
1644             ok_(__FILE__,line)(compare(U(*expected).m[i][j], U(*got).m[i][j]),
1645                     "matrix[%u][%u]: expected %g, got %g\n",
1646                     i, j, U(*expected).m[i][j], U(*got).m[i][j]);
1647         }
1648     }
1649 }
1650 
1651 static void check_colorvalue_(int line, const char *prefix, const D3DCOLORVALUE got, const D3DCOLORVALUE expected)
1652 {
1653     ok_(__FILE__,line)(expected.r == got.r && expected.g == got.g && expected.b == got.b && expected.a == got.a,
1654             "%sExpected (%g, %g, %g, %g), got (%g, %g, %g, %g)\n", prefix,
1655             expected.r, expected.g, expected.b, expected.a, got.r, got.g, got.b, got.a);
1656 }
1657 
1658 #define check_materials(got, got_count, expected, expected_count) \
1659     check_materials_(__LINE__, got, got_count, expected, expected_count)
1660 static void check_materials_(int line, const D3DXMATERIAL *got, DWORD got_count, const D3DXMATERIAL *expected, DWORD expected_count)
1661 {
1662     int i;
1663     ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
1664     if (!expected) {
1665         ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
1666         return;
1667     }
1668     for (i = 0; i < min(expected_count, got_count); i++)
1669     {
1670         if (!expected[i].pTextureFilename)
1671             ok_(__FILE__,line)(got[i].pTextureFilename == NULL,
1672                     "Expected NULL pTextureFilename, got %p\n", got[i].pTextureFilename);
1673         else
1674             ok_(__FILE__,line)(!strcmp(expected[i].pTextureFilename, got[i].pTextureFilename),
1675                     "Expected '%s' for pTextureFilename, got '%s'\n", expected[i].pTextureFilename, got[i].pTextureFilename);
1676         check_colorvalue_(line, "Diffuse: ", got[i].MatD3D.Diffuse, expected[i].MatD3D.Diffuse);
1677         check_colorvalue_(line, "Ambient: ", got[i].MatD3D.Ambient, expected[i].MatD3D.Ambient);
1678         check_colorvalue_(line, "Specular: ", got[i].MatD3D.Specular, expected[i].MatD3D.Specular);
1679         check_colorvalue_(line, "Emissive: ", got[i].MatD3D.Emissive, expected[i].MatD3D.Emissive);
1680         ok_(__FILE__,line)(expected[i].MatD3D.Power == got[i].MatD3D.Power,
1681                 "Power: Expected %g, got %g\n", expected[i].MatD3D.Power, got[i].MatD3D.Power);
1682     }
1683 }
1684 
1685 #define check_generated_adjacency(mesh, got, epsilon) check_generated_adjacency_(__LINE__, mesh, got, epsilon)
1686 static void check_generated_adjacency_(int line, ID3DXMesh *mesh, const DWORD *got, FLOAT epsilon)
1687 {
1688     DWORD *expected;
1689     DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
1690     HRESULT hr;
1691 
1692     expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
1693     if (!expected) {
1694         skip_(__FILE__, line)("Out of memory\n");
1695         return;
1696     }
1697     hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
1698     ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1699     if (SUCCEEDED(hr))
1700     {
1701         int i;
1702         for (i = 0; i < num_faces; i++)
1703         {
1704             ok_(__FILE__, line)(expected[i * 3] == got[i * 3] &&
1705                     expected[i * 3 + 1] == got[i * 3 + 1] &&
1706                     expected[i * 3 + 2] == got[i * 3 + 2],
1707                     "Face %u adjacencies: Expected (%u, %u, %u), got (%u, %u, %u)\n", i,
1708                     expected[i * 3], expected[i * 3 + 1], expected[i * 3 + 2],
1709                     got[i * 3], got[i * 3 + 1], got[i * 3 + 2]);
1710         }
1711     }
1712     HeapFree(GetProcessHeap(), 0, expected);
1713 }
1714 
1715 #define check_generated_effects(materials, num_materials, effects) \
1716     check_generated_effects_(__LINE__, materials, num_materials, effects)
1717 static void check_generated_effects_(int line, const D3DXMATERIAL *materials, DWORD num_materials, const D3DXEFFECTINSTANCE *effects)
1718 {
1719     int i;
1720     static const struct {
1721         const char *name;
1722         DWORD name_size;
1723         DWORD num_bytes;
1724         DWORD value_offset;
1725     } params[] = {
1726 #define EFFECT_TABLE_ENTRY(str, field) \
1727     {str, sizeof(str), sizeof(materials->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
1728         EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
1729         EFFECT_TABLE_ENTRY("Power", Power),
1730         EFFECT_TABLE_ENTRY("Specular", Specular),
1731         EFFECT_TABLE_ENTRY("Emissive", Emissive),
1732         EFFECT_TABLE_ENTRY("Ambient", Ambient),
1733 #undef EFFECT_TABLE_ENTRY
1734     };
1735 
1736     if (!num_materials) {
1737         ok_(__FILE__, line)(effects == NULL, "Expected NULL effects, got %p\n", effects);
1738         return;
1739     }
1740     for (i = 0; i < num_materials; i++)
1741     {
1742         int j;
1743         DWORD expected_num_defaults = ARRAY_SIZE(params) + (materials[i].pTextureFilename ? 1 : 0);
1744 
1745         ok_(__FILE__,line)(expected_num_defaults == effects[i].NumDefaults,
1746                 "effect[%u] NumDefaults: Expected %u, got %u\n", i,
1747                 expected_num_defaults, effects[i].NumDefaults);
1748         for (j = 0; j < min(ARRAY_SIZE(params), effects[i].NumDefaults); j++)
1749         {
1750             int k;
1751             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1752             ok_(__FILE__,line)(!strcmp(params[j].name, got_param->pParamName),
1753                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1754                params[j].name, got_param->pParamName);
1755             ok_(__FILE__,line)(D3DXEDT_FLOATS == got_param->Type,
1756                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1757                D3DXEDT_FLOATS, got_param->Type);
1758             ok_(__FILE__,line)(params[j].num_bytes == got_param->NumBytes,
1759                "effect[%u].pDefaults[%u].NumBytes: Expected %u, got %u\n", i, j,
1760                params[j].num_bytes, got_param->NumBytes);
1761             for (k = 0; k < min(params[j].num_bytes, got_param->NumBytes) / 4; k++)
1762             {
1763                 FLOAT expected = ((FLOAT*)((BYTE*)&materials[i] + params[j].value_offset))[k];
1764                 FLOAT got = ((FLOAT*)got_param->pValue)[k];
1765                 ok_(__FILE__,line)(compare(expected, got),
1766                    "effect[%u].pDefaults[%u] float value %u: Expected %g, got %g\n", i, j, k, expected, got);
1767             }
1768         }
1769         if (effects[i].NumDefaults > ARRAY_SIZE(params)) {
1770             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1771             static const char *expected_name = "Texture0@Name";
1772 
1773             ok_(__FILE__,line)(!strcmp(expected_name, got_param->pParamName),
1774                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1775                expected_name, got_param->pParamName);
1776             ok_(__FILE__,line)(D3DXEDT_STRING == got_param->Type,
1777                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1778                D3DXEDT_STRING, got_param->Type);
1779             if (materials[i].pTextureFilename) {
1780                 ok_(__FILE__,line)(strlen(materials[i].pTextureFilename) + 1 == got_param->NumBytes,
1781                    "effect[%u] texture filename length: Expected %u, got %u\n", i,
1782                    (DWORD)strlen(materials[i].pTextureFilename) + 1, got_param->NumBytes);
1783                 ok_(__FILE__,line)(!strcmp(materials[i].pTextureFilename, got_param->pValue),
1784                    "effect[%u] texture filename: Expected '%s', got '%s'\n", i,
1785                    materials[i].pTextureFilename, (char*)got_param->pValue);
1786             }
1787         }
1788     }
1789 }
1790 
1791 static char *strdupA(const char *p)
1792 {
1793     char *ret;
1794     if (!p) return NULL;
1795     ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
1796     if (ret) strcpy(ret, p);
1797     return ret;
1798 }
1799 
1800 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
1801 {
1802     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
1803     if (frame) {
1804         HeapFree(GetProcessHeap(), 0, frame->Name);
1805         HeapFree(GetProcessHeap(), 0, frame);
1806     }
1807     return D3D_OK;
1808 }
1809 
1810 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface,
1811         const char *name, D3DXFRAME **new_frame)
1812 {
1813     D3DXFRAME *frame;
1814 
1815     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
1816     frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
1817     if (!frame)
1818         return E_OUTOFMEMORY;
1819     if (name) {
1820         frame->Name = strdupA(name);
1821         if (!frame->Name) {
1822             HeapFree(GetProcessHeap(), 0, frame);
1823             return E_OUTOFMEMORY;
1824         }
1825     }
1826     *new_frame = frame;
1827     return D3D_OK;
1828 }
1829 
1830 static HRESULT destroy_mesh_container(LPD3DXMESHCONTAINER mesh_container)
1831 {
1832     int i;
1833 
1834     if (!mesh_container)
1835         return D3D_OK;
1836     HeapFree(GetProcessHeap(), 0, mesh_container->Name);
1837     if (U(mesh_container->MeshData).pMesh)
1838         IUnknown_Release(U(mesh_container->MeshData).pMesh);
1839     if (mesh_container->pMaterials) {
1840         for (i = 0; i < mesh_container->NumMaterials; i++)
1841             HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials[i].pTextureFilename);
1842         HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials);
1843     }
1844     if (mesh_container->pEffects) {
1845         for (i = 0; i < mesh_container->NumMaterials; i++) {
1846             HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pEffectFilename);
1847             if (mesh_container->pEffects[i].pDefaults) {
1848                 int j;
1849                 for (j = 0; j < mesh_container->pEffects[i].NumDefaults; j++) {
1850                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pParamName);
1851                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pValue);
1852                 }
1853                 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults);
1854             }
1855         }
1856         HeapFree(GetProcessHeap(), 0, mesh_container->pEffects);
1857     }
1858     HeapFree(GetProcessHeap(), 0, mesh_container->pAdjacency);
1859     if (mesh_container->pSkinInfo)
1860         IUnknown_Release(mesh_container->pSkinInfo);
1861     HeapFree(GetProcessHeap(), 0, mesh_container);
1862     return D3D_OK;
1863 }
1864 
1865 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyMeshContainer(ID3DXAllocateHierarchy *iface, LPD3DXMESHCONTAINER mesh_container)
1866 {
1867     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyMeshContainer(%p, %p)\n", iface, mesh_container);
1868     return destroy_mesh_container(mesh_container);
1869 }
1870 
1871 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateMeshContainer(ID3DXAllocateHierarchy *iface,
1872         const char *name, const D3DXMESHDATA *mesh_data, const D3DXMATERIAL *materials,
1873         const D3DXEFFECTINSTANCE *effects, DWORD num_materials, const DWORD *adjacency,
1874         ID3DXSkinInfo *skin_info, D3DXMESHCONTAINER **new_mesh_container)
1875 {
1876     LPD3DXMESHCONTAINER mesh_container = NULL;
1877     int i;
1878 
1879     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateMeshContainer(%p, '%s', %u, %p, %p, %p, %d, %p, %p, %p)\n",
1880             iface, name, mesh_data->Type, U(*mesh_data).pMesh, materials, effects,
1881             num_materials, adjacency, skin_info, *new_mesh_container);
1882 
1883     mesh_container = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mesh_container));
1884     if (!mesh_container)
1885         return E_OUTOFMEMORY;
1886 
1887     if (name) {
1888         mesh_container->Name = strdupA(name);
1889         if (!mesh_container->Name)
1890             goto error;
1891     }
1892 
1893     mesh_container->NumMaterials = num_materials;
1894     if (num_materials) {
1895         mesh_container->pMaterials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*materials));
1896         if (!mesh_container->pMaterials)
1897             goto error;
1898 
1899         memcpy(mesh_container->pMaterials, materials, num_materials * sizeof(*materials));
1900         for (i = 0; i < num_materials; i++)
1901             mesh_container->pMaterials[i].pTextureFilename = NULL;
1902         for (i = 0; i < num_materials; i++) {
1903             if (materials[i].pTextureFilename) {
1904                 mesh_container->pMaterials[i].pTextureFilename = strdupA(materials[i].pTextureFilename);
1905                 if (!mesh_container->pMaterials[i].pTextureFilename)
1906                     goto error;
1907             }
1908         }
1909 
1910         mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
1911         if (!mesh_container->pEffects)
1912             goto error;
1913         for (i = 0; i < num_materials; i++) {
1914             int j;
1915             const D3DXEFFECTINSTANCE *effect_src = &effects[i];
1916             D3DXEFFECTINSTANCE *effect_dest = &mesh_container->pEffects[i];
1917 
1918             if (effect_src->pEffectFilename) {
1919                 effect_dest->pEffectFilename = strdupA(effect_src->pEffectFilename);
1920                 if (!effect_dest->pEffectFilename)
1921                     goto error;
1922             }
1923             effect_dest->pDefaults = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1924                     effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
1925             if (!effect_dest->pDefaults)
1926                 goto error;
1927             effect_dest->NumDefaults = effect_src->NumDefaults;
1928             for (j = 0; j < effect_src->NumDefaults; j++) {
1929                 const D3DXEFFECTDEFAULT *default_src = &effect_src->pDefaults[j];
1930                 D3DXEFFECTDEFAULT *default_dest = &effect_dest->pDefaults[j];
1931 
1932                 if (default_src->pParamName) {
1933                     default_dest->pParamName = strdupA(default_src->pParamName);
1934                     if (!default_dest->pParamName)
1935                         goto error;
1936                 }
1937                 default_dest->NumBytes = default_src->NumBytes;
1938                 default_dest->Type = default_src->Type;
1939                 default_dest->pValue = HeapAlloc(GetProcessHeap(), 0, default_src->NumBytes);
1940                 memcpy(default_dest->pValue, default_src->pValue, default_src->NumBytes);
1941             }
1942         }
1943     }
1944 
1945     ok(adjacency != NULL, "Expected non-NULL adjacency, got NULL\n");
1946     if (adjacency) {
1947         if (mesh_data->Type == D3DXMESHTYPE_MESH || mesh_data->Type == D3DXMESHTYPE_PMESH) {
1948             ID3DXBaseMesh *basemesh = (ID3DXBaseMesh*)U(*mesh_data).pMesh;
1949             DWORD num_faces = basemesh->lpVtbl->GetNumFaces(basemesh);
1950             size_t size = num_faces * sizeof(DWORD) * 3;
1951             mesh_container->pAdjacency = HeapAlloc(GetProcessHeap(), 0, size);
1952             if (!mesh_container->pAdjacency)
1953                 goto error;
1954             memcpy(mesh_container->pAdjacency, adjacency, size);
1955         } else {
1956             ok(mesh_data->Type == D3DXMESHTYPE_PATCHMESH, "Unknown mesh type %u\n", mesh_data->Type);
1957             if (mesh_data->Type == D3DXMESHTYPE_PATCHMESH)
1958                 trace("FIXME: copying adjacency data for patch mesh not implemented\n");
1959         }
1960     }
1961 
1962     memcpy(&mesh_container->MeshData, mesh_data, sizeof(*mesh_data));
1963     if (U(*mesh_data).pMesh)
1964         IUnknown_AddRef(U(*mesh_data).pMesh);
1965     if (skin_info) {
1966         mesh_container->pSkinInfo = skin_info;
1967         skin_info->lpVtbl->AddRef(skin_info);
1968     }
1969     *new_mesh_container = mesh_container;
1970 
1971     return S_OK;
1972 error:
1973     destroy_mesh_container(mesh_container);
1974     return E_OUTOFMEMORY;
1975 }
1976 
1977 static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
1978     ID3DXAllocateHierarchyImpl_CreateFrame,
1979     ID3DXAllocateHierarchyImpl_CreateMeshContainer,
1980     ID3DXAllocateHierarchyImpl_DestroyFrame,
1981     ID3DXAllocateHierarchyImpl_DestroyMeshContainer,
1982 };
1983 static ID3DXAllocateHierarchy alloc_hier = { &ID3DXAllocateHierarchyImpl_Vtbl };
1984 
1985 #define test_LoadMeshFromX(device, xfile_str, vertex_array, fvf, index_array, materials_array, check_adjacency) \
1986     test_LoadMeshFromX_(__LINE__, device, xfile_str, sizeof(xfile_str) - 1, vertex_array, ARRAY_SIZE(vertex_array), fvf, \
1987             index_array, ARRAY_SIZE(index_array), sizeof(*index_array), materials_array, ARRAY_SIZE(materials_array), \
1988             check_adjacency);
1989 static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char *xfile_str, size_t xfile_strlen,
1990         const void *vertices, DWORD num_vertices, DWORD fvf, const void *indices, DWORD num_indices, size_t index_size,
1991         const D3DXMATERIAL *expected_materials, DWORD expected_num_materials, BOOL check_adjacency)
1992 {
1993     HRESULT hr;
1994     ID3DXBuffer *materials = NULL;
1995     ID3DXBuffer *effects = NULL;
1996     ID3DXBuffer *adjacency = NULL;
1997     ID3DXMesh *mesh = NULL;
1998     DWORD num_materials = 0;
1999 
2000     /* Adjacency is not checked when the X file contains multiple meshes,
2001      * since calling GenerateAdjacency on the merged mesh is not equivalent
2002      * to calling GenerateAdjacency on the individual meshes and then merging
2003      * the adjacency data. */
2004     hr = D3DXLoadMeshFromXInMemory(xfile_str, xfile_strlen, D3DXMESH_MANAGED, device,
2005             check_adjacency ? &adjacency : NULL, &materials, &effects, &num_materials, &mesh);
2006     ok_(__FILE__,line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2007     if (SUCCEEDED(hr)) {
2008         D3DXMATERIAL *materials_ptr = materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL;
2009         D3DXEFFECTINSTANCE *effects_ptr = effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL;
2010         DWORD *adjacency_ptr = check_adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL;
2011 
2012         check_vertex_buffer_(line, mesh, vertices, num_vertices, fvf);
2013         check_index_buffer_(line, mesh, indices, num_indices, index_size);
2014         check_materials_(line, materials_ptr, num_materials, expected_materials, expected_num_materials);
2015         check_generated_effects_(line, materials_ptr, num_materials, effects_ptr);
2016         if (check_adjacency)
2017             check_generated_adjacency_(line, mesh, adjacency_ptr, 0.0f);
2018 
2019         if (materials) ID3DXBuffer_Release(materials);
2020         if (effects) ID3DXBuffer_Release(effects);
2021         if (adjacency) ID3DXBuffer_Release(adjacency);
2022         IUnknown_Release(mesh);
2023     }
2024 }
2025 
2026 static void D3DXLoadMeshTest(void)
2027 {
2028     static const char empty_xfile[] = "xof 0303txt 0032";
2029     /*________________________*/
2030     static const char simple_xfile[] =
2031         "xof 0303txt 0032"
2032         "Mesh {"
2033             "3;"
2034             "0.0; 0.0; 0.0;,"
2035             "0.0; 1.0; 0.0;,"
2036             "1.0; 1.0; 0.0;;"
2037             "1;"
2038             "3; 0, 1, 2;;"
2039         "}";
2040     static const WORD simple_index_buffer[] = {0, 1, 2};
2041     static const D3DXVECTOR3 simple_vertex_buffer[] = {
2042         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}
2043     };
2044     const DWORD simple_fvf = D3DFVF_XYZ;
2045     static const char framed_xfile[] =
2046         "xof 0303txt 0032"
2047         "Frame {"
2048             "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;; }"
2049             "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */
2050               "1.0, 0.0, 0.0, 0.0,"
2051               "0.0, 1.0, 0.0, 0.0,"
2052               "0.0, 0.0, 1.0, 0.0,"
2053               "0.0, 0.0, 2.0, 1.0;;"
2054             "}"
2055             "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;; }"
2056             "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */
2057               "1.0, 0.0, 0.0, 0.0,"
2058               "0.0, 1.0, 0.0, 0.0,"
2059               "0.0, 0.0, 1.0, 0.0,"
2060               "0.0, 0.0, 3.0, 1.0;;"
2061             "}"
2062             "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;; }"
2063         "}";
2064     static const WORD framed_index_buffer[] = { 0, 1, 2 };
2065     static const D3DXVECTOR3 framed_vertex_buffers[3][3] = {
2066         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}},
2067         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}},
2068         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {3.0, 1.0, 0.0}},
2069     };
2070     static const WORD merged_index_buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
2071     /* frame transforms accumulates for D3DXLoadMeshFromX */
2072     static const D3DXVECTOR3 merged_vertex_buffer[] = {
2073         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0},
2074         {0.0, 0.0, 2.0}, {0.0, 1.0, 2.0}, {2.0, 1.0, 2.0},
2075         {0.0, 0.0, 5.0}, {0.0, 1.0, 5.0}, {3.0, 1.0, 5.0},
2076     };
2077     const DWORD framed_fvf = D3DFVF_XYZ;
2078     /*________________________*/
2079     static const char box_xfile[] =
2080         "xof 0303txt 0032"
2081         "Mesh {"
2082             "8;" /* DWORD nVertices; */
2083             /* array Vector vertices[nVertices]; */
2084             "0.0; 0.0; 0.0;,"
2085             "0.0; 0.0; 1.0;,"
2086             "0.0; 1.0; 0.0;,"
2087             "0.0; 1.0; 1.0;,"
2088             "1.0; 0.0; 0.0;,"
2089             "1.0; 0.0; 1.0;,"
2090             "1.0; 1.0; 0.0;,"
2091             "1.0; 1.0; 1.0;;"
2092             "6;" /* DWORD nFaces; */
2093             /* array MeshFace faces[nFaces]; */
2094             "4; 0, 1, 3, 2;," /* (left side) */
2095             "4; 2, 3, 7, 6;," /* (top side) */
2096             "4; 6, 7, 5, 4;," /* (right side) */
2097             "4; 1, 0, 4, 5;," /* (bottom side) */
2098             "4; 1, 5, 7, 3;," /* (back side) */
2099             "4; 0, 2, 6, 4;;" /* (front side) */
2100             "MeshNormals {"
2101               "6;" /* DWORD nNormals; */
2102               /* array Vector normals[nNormals]; */
2103               "-1.0; 0.0; 0.0;,"
2104               "0.0; 1.0; 0.0;,"
2105               "1.0; 0.0; 0.0;,"
2106               "0.0; -1.0; 0.0;,"
2107               "0.0; 0.0; 1.0;,"
2108               "0.0; 0.0; -1.0;;"
2109               "6;" /* DWORD nFaceNormals; */
2110               /* array MeshFace faceNormals[nFaceNormals]; */
2111               "4; 0, 0, 0, 0;,"
2112               "4; 1, 1, 1, 1;,"
2113               "4; 2, 2, 2, 2;,"
2114               "4; 3, 3, 3, 3;,"
2115               "4; 4, 4, 4, 4;,"
2116               "4; 5, 5, 5, 5;;"
2117             "}"
2118             "MeshMaterialList materials {"
2119               "2;" /* DWORD nMaterials; */
2120               "6;" /* DWORD nFaceIndexes; */
2121               /* array DWORD faceIndexes[nFaceIndexes]; */
2122               "0, 0, 0, 1, 1, 1;;"
2123               "Material {"
2124                 /* ColorRGBA faceColor; */
2125                 "0.0; 0.0; 1.0; 1.0;;"
2126                 /* FLOAT power; */
2127                 "0.5;"
2128                 /* ColorRGB specularColor; */
2129                 "1.0; 1.0; 1.0;;"
2130                 /* ColorRGB emissiveColor; */
2131                 "0.0; 0.0; 0.0;;"
2132               "}"
2133               "Material {"
2134                 /* ColorRGBA faceColor; */
2135                 "1.0; 1.0; 1.0; 1.0;;"
2136                 /* FLOAT power; */
2137                 "1.0;"
2138                 /* ColorRGB specularColor; */
2139                 "1.0; 1.0; 1.0;;"
2140                 /* ColorRGB emissiveColor; */
2141                 "0.0; 0.0; 0.0;;"
2142                 "TextureFilename { \"texture.jpg\"; }"
2143               "}"
2144             "}"
2145             "MeshVertexColors {"
2146               "8;" /* DWORD nVertexColors; */
2147               /* array IndexedColor vertexColors[nVertexColors]; */
2148               "0; 0.0; 0.0; 0.0; 0.0;;"
2149               "1; 0.0; 0.0; 1.0; 0.1;;"
2150               "2; 0.0; 1.0; 0.0; 0.2;;"
2151               "3; 0.0; 1.0; 1.0; 0.3;;"
2152               "4; 1.0; 0.0; 0.0; 0.4;;"
2153               "5; 1.0; 0.0; 1.0; 0.5;;"
2154               "6; 1.0; 1.0; 0.0; 0.6;;"
2155               "7; 1.0; 1.0; 1.0; 0.7;;"
2156             "}"
2157             "MeshTextureCoords {"
2158               "8;" /* DWORD nTextureCoords; */
2159               /* array Coords2d textureCoords[nTextureCoords]; */
2160               "0.0; 1.0;,"
2161               "1.0; 1.0;,"
2162               "0.0; 0.0;,"
2163               "1.0; 0.0;,"
2164               "1.0; 1.0;,"
2165               "0.0; 1.0;,"
2166               "1.0; 0.0;,"
2167               "0.0; 0.0;;"
2168             "}"
2169           "}";
2170     static const WORD box_index_buffer[] = {
2171         0, 1, 3,
2172         0, 3, 2,
2173         8, 9, 7,
2174         8, 7, 6,
2175         10, 11, 5,
2176         10, 5, 4,
2177         12, 13, 14,
2178         12, 14, 15,
2179         16, 17, 18,
2180         16, 18, 19,
2181         20, 21, 22,
2182         20, 22, 23,
2183     };
2184     static const struct {
2185         D3DXVECTOR3 position;
2186         D3DXVECTOR3 normal;
2187         D3DCOLOR diffuse;
2188         D3DXVECTOR2 tex_coords;
2189     } box_vertex_buffer[] = {
2190         {{0.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, 0x00000000, {0.0, 1.0}},
2191         {{0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2192         {{0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2193         {{0.0, 1.0, 1.0}, {-1.0, 0.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2194         {{1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2195         {{1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2196         {{1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2197         {{1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2198         {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2199         {{0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2200         {{1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2201         {{1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2202         {{0.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2203         {{0.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x00000000, {0.0, 1.0}},
2204         {{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2205         {{1.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2206         {{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x1a0000ff, {1.0, 1.0}},
2207         {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x80ff00ff, {0.0, 1.0}},
2208         {{1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0xb3ffffff, {0.0, 0.0}},
2209         {{0.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0x4d00ffff, {1.0, 0.0}},
2210         {{0.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x00000000, {0.0, 1.0}},
2211         {{0.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x3300ff00, {0.0, 0.0}},
2212         {{1.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x99ffff00, {1.0, 0.0}},
2213         {{1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x66ff0000, {1.0, 1.0}},
2214     };
2215     static const D3DXMATERIAL box_materials[] = {
2216         {
2217             {
2218                 {0.0, 0.0, 1.0, 1.0}, /* Diffuse */
2219                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2220                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2221                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2222                 0.5, /* Power */
2223             },
2224             NULL, /* pTextureFilename */
2225         },
2226         {
2227             {
2228                 {1.0, 1.0, 1.0, 1.0}, /* Diffuse */
2229                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2230                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2231                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2232                 1.0, /* Power */
2233             },
2234             (char *)"texture.jpg", /* pTextureFilename */
2235         },
2236     };
2237     static const char box_anim_xfile[] =
2238         "xof 0303txt 0032"
2239         "Mesh CubeMesh {"
2240         "8;" /* DWORD nVertices; */
2241         /* array Vector vertices[nVertices]; */
2242         "0.0; 0.0; 0.0;,"
2243         "0.0; 0.0; 1.0;,"
2244         "0.0; 1.0; 0.0;,"
2245         "0.0; 1.0; 1.0;,"
2246         "1.0; 0.0; 0.0;,"
2247         "1.0; 0.0; 1.0;,"
2248         "1.0; 1.0; 0.0;,"
2249         "1.0; 1.0; 1.0;;"
2250         "6;" /* DWORD nFaces; */
2251         /* array MeshFace faces[nFaces]; */
2252         "4; 0, 1, 3, 2;," /* left side */
2253         "4; 2, 3, 7, 6;," /* top side */
2254         "4; 6, 7, 5, 4;," /* right side */
2255         "4; 1, 0, 4, 5;," /* bottom side */
2256         "4; 1, 5, 7, 3;," /* back side */
2257         "4; 0, 2, 6, 4;;" /* front side */
2258         "MeshNormals {"
2259         "6;" /* DWORD nNormals; */
2260         /* array Vector normals[nNormals]; */
2261         "-1.0; 0.0; 0.0;,"
2262         "0.0; 1.0; 0.0;,"
2263         "1.0; 0.0; 0.0;,"
2264         "0.0; -1.0; 0.0;,"
2265         "0.0; 0.0; 1.0;,"
2266         "0.0; 0.0; -1.0;;"
2267         "6;" /* DWORD nFaceNormals; */
2268         /* array MeshFace faceNormals[nFaceNormals]; */
2269         "4; 0, 0, 0, 0;,"
2270         "4; 1, 1, 1, 1;,"
2271         "4; 2, 2, 2, 2;,"
2272         "4; 3, 3, 3, 3;,"
2273         "4; 4, 4, 4, 4;,"
2274         "4; 5, 5, 5, 5;;"
2275         "}"
2276         "MeshMaterialList materials {"
2277         "2;" /* DWORD nMaterials; */
2278         "6;" /* DWORD nFaceIndexes; */
2279         /* array DWORD faceIndexes[nFaceIndexes]; */
2280         "0, 0, 0, 1, 1, 1;;"
2281         "Material {"
2282         /* ColorRGBA faceColor; */
2283         "0.0; 0.0; 1.0; 1.0;;"
2284         /* FLOAT power; */
2285         "0.5;"
2286         /* ColorRGB specularColor; */
2287         "1.0; 1.0; 1.0;;"
2288         /* ColorRGB emissiveColor; */
2289         "0.0; 0.0; 0.0;;"
2290         "}"
2291         "Material {"
2292         /* ColorRGBA faceColor; */
2293         "1.0; 1.0; 1.0; 1.0;;"
2294         /* FLOAT power; */
2295         "1.0;"
2296         /* ColorRGB specularColor; */
2297         "1.0; 1.0; 1.0;;"
2298         /* ColorRGB emissiveColor; */
2299         "0.0; 0.0; 0.0;;"
2300         "TextureFilename { \"texture.jpg\"; }"
2301         "}"
2302         "}"
2303         "MeshVertexColors {"
2304         "8;" /* DWORD nVertexColors; */
2305         /* array IndexedColor vertexColors[nVertexColors]; */
2306         "0; 0.0; 0.0; 0.0; 0.0;;"
2307         "1; 0.0; 0.0; 1.0; 0.1;;"
2308         "2; 0.0; 1.0; 0.0; 0.2;;"
2309         "3; 0.0; 1.0; 1.0; 0.3;;"
2310         "4; 1.0; 0.0; 0.0; 0.4;;"
2311         "5; 1.0; 0.0; 1.0; 0.5;;"
2312         "6; 1.0; 1.0; 0.0; 0.6;;"
2313         "7; 1.0; 1.0; 1.0; 0.7;;"
2314         "}"
2315         "MeshTextureCoords {"
2316         "8;" /* DWORD nTextureCoords; */
2317         /* array Coords2d textureCoords[nTextureCoords]; */
2318         "0.0; 1.0;,"
2319         "1.0; 1.0;,"
2320         "0.0; 0.0;,"
2321         "1.0; 0.0;,"
2322         "1.0; 1.0;,"
2323         "0.0; 1.0;,"
2324         "1.0; 0.0;,"
2325         "0.0; 0.0;;"
2326         "}"
2327         "}"
2328         "Frame CubeFrame {"
2329         "FrameTransformMatrix {"
2330         /* Matrix4x4 frameMatrix; */
2331         "1.0, 0.0, 0.0, 0.0,"
2332         "0.0, 1.0, 0.0, 0.0,"
2333         "0.0, 0.0, 1.0, 0.0,"
2334         "0.0, 0.0, 0.0, 1.0;;"
2335         "}"
2336         "{CubeMesh}"
2337         "}"
2338         "AnimationSet AnimationSet0 {"
2339         "Animation Animation0 {"
2340         "{CubeFrame}"
2341         "AnimationKey {"
2342         "2;" /* DWORD keyType; */
2343         "9;" /* DWORD nKeys; */
2344         /* array TimedFloatKeys keys[nKeys]; */
2345         "10; 3; -100.0, 0.0, 0.0;;,"
2346         "20; 3; -75.0,  0.0, 0.0;;,"
2347         "30; 3; -50.0,  0.0, 0.0;;,"
2348         "40; 3; -25.5,  0.0, 0.0;;,"
2349         "50; 3; 0.0,    0.0, 0.0;;,"
2350         "60; 3; 25.5,   0.0, 0.0;;,"
2351         "70; 3; 50.0,   0.0, 0.0;;,"
2352         "80; 3; 75.5,   0.0, 0.0;;,"
2353         "90; 3; 100.0,  0.0, 0.0;;;"
2354         "}"
2355         "}"
2356         "}";
2357 
2358     const DWORD box_fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
2359     /*________________________*/
2360     static const D3DXMATERIAL default_materials[] = {
2361         {
2362             {
2363                 {0.5, 0.5, 0.5, 0.0}, /* Diffuse */
2364                 {0.0, 0.0, 0.0, 0.0}, /* Ambient */
2365                 {0.5, 0.5, 0.5, 0.0}, /* Specular */
2366                 {0.0, 0.0, 0.0, 0.0}, /* Emissive */
2367                 0.0, /* Power */
2368             },
2369             NULL, /* pTextureFilename */
2370         }
2371     };
2372     HRESULT hr;
2373     IDirect3DDevice9 *device = NULL;
2374     ID3DXMesh *mesh = NULL;
2375     D3DXFRAME *frame_hier = NULL;
2376     D3DXMATRIX transform;
2377     struct test_context *test_context;
2378     ID3DXAnimationController *controller;
2379 
2380     if (!(test_context = new_test_context()))
2381     {
2382         skip("Couldn't create test context\n");
2383         return;
2384     }
2385     device = test_context->device;
2386 
2387     hr = D3DXLoadMeshHierarchyFromXInMemory(NULL, sizeof(simple_xfile) - 1,
2388             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2389     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2390 
2391     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, 0,
2392             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2393     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2394 
2395     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2396             D3DXMESH_MANAGED, NULL, &alloc_hier, NULL, &frame_hier, NULL);
2397     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2398 
2399     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2400             D3DXMESH_MANAGED, device, NULL, NULL, &frame_hier, NULL);
2401     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2402 
2403     hr = D3DXLoadMeshHierarchyFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1,
2404             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2405     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2406 
2407     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2408             D3DXMESH_MANAGED, device, &alloc_hier, NULL, NULL, NULL);
2409     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2410 
2411     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2412             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2413     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2414     if (SUCCEEDED(hr)) {
2415         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2416 
2417         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2418         D3DXMatrixIdentity(&transform);
2419         check_matrix(&frame_hier->TransformationMatrix, &transform);
2420 
2421         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2422         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2423            D3DXMESHTYPE_MESH, container->MeshData.Type);
2424         mesh = U(container->MeshData).pMesh;
2425         check_vertex_buffer(mesh, simple_vertex_buffer, ARRAY_SIZE(simple_vertex_buffer), simple_fvf);
2426         check_index_buffer(mesh, simple_index_buffer, ARRAY_SIZE(simple_index_buffer), sizeof(*simple_index_buffer));
2427         check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2428         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2429         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2430         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2431         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2432         frame_hier = NULL;
2433     }
2434 
2435     controller = (ID3DXAnimationController *)0xdeadbeef;
2436     hr = D3DXLoadMeshHierarchyFromXInMemory(box_anim_xfile, sizeof(box_anim_xfile) - 1,
2437             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2438     todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2439     if (SUCCEEDED(hr))
2440     {
2441         ok(controller != NULL, "Animation Controller NULL.\n");
2442 
2443         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2444         ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2445         if (controller)
2446             controller->lpVtbl->Release(controller);
2447 
2448         frame_hier = NULL;
2449     }
2450 
2451     controller = (ID3DXAnimationController *)0xdeadbeef;
2452     hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1,
2453             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2454     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2455     if (SUCCEEDED(hr))
2456     {
2457         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2458 
2459         ok(!controller, "Animation Controller returned.\n");
2460         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2461         D3DXMatrixIdentity(&transform);
2462         check_matrix(&frame_hier->TransformationMatrix, &transform);
2463 
2464         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2465         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2466            D3DXMESHTYPE_MESH, container->MeshData.Type);
2467         mesh = U(container->MeshData).pMesh;
2468         check_vertex_buffer(mesh, box_vertex_buffer, ARRAY_SIZE(box_vertex_buffer), box_fvf);
2469         check_index_buffer(mesh, box_index_buffer, ARRAY_SIZE(box_index_buffer), sizeof(*box_index_buffer));
2470         check_materials(container->pMaterials, container->NumMaterials, box_materials, ARRAY_SIZE(box_materials));
2471         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2472         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2473         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2474         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2475         frame_hier = NULL;
2476     }
2477 
2478     hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1,
2479             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2480     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2481     if (SUCCEEDED(hr)) {
2482         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2483         int i;
2484 
2485         ok(!strcmp(frame_hier->Name, ""), "Expected '', got '%s'\n", frame_hier->Name);
2486         /* last frame transform replaces the first */
2487         D3DXMatrixIdentity(&transform);
2488         U(transform).m[3][2] = 3.0;
2489         check_matrix(&frame_hier->TransformationMatrix, &transform);
2490 
2491         for (i = 0; i < 3; i++) {
2492             ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2493             ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2494                D3DXMESHTYPE_MESH, container->MeshData.Type);
2495             mesh = U(container->MeshData).pMesh;
2496             check_vertex_buffer(mesh, framed_vertex_buffers[i], ARRAY_SIZE(framed_vertex_buffers[0]), framed_fvf);
2497             check_index_buffer(mesh, framed_index_buffer, ARRAY_SIZE(framed_index_buffer), sizeof(*framed_index_buffer));
2498             check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2499             check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2500             check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2501             container = container->pNextMeshContainer;
2502         }
2503         ok(container == NULL, "Expected NULL, got %p\n", container);
2504         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2505         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2506         frame_hier = NULL;
2507     }
2508 
2509 
2510     hr = D3DXLoadMeshFromXInMemory(NULL, 0, D3DXMESH_MANAGED,
2511                                    device, NULL, NULL, NULL, NULL, &mesh);
2512     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2513 
2514     hr = D3DXLoadMeshFromXInMemory(NULL, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2515                                    device, NULL, NULL, NULL, NULL, &mesh);
2516     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2517 
2518     hr = D3DXLoadMeshFromXInMemory(simple_xfile, 0, D3DXMESH_MANAGED,
2519                                    device, NULL, NULL, NULL, NULL, &mesh);
2520     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2521 
2522     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2523                                    device, NULL, NULL, NULL, NULL, NULL);
2524     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2525 
2526     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2527                                    NULL, NULL, NULL, NULL, NULL, &mesh);
2528     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2529 
2530     hr = D3DXLoadMeshFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1, D3DXMESH_MANAGED,
2531                                    device, NULL, NULL, NULL, NULL, &mesh);
2532     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2533 
2534     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2535                                    device, NULL, NULL, NULL, NULL, &mesh);
2536     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2537     if (SUCCEEDED(hr))
2538         IUnknown_Release(mesh);
2539 
2540     test_LoadMeshFromX(device, simple_xfile, simple_vertex_buffer, simple_fvf, simple_index_buffer, default_materials, TRUE);
2541     test_LoadMeshFromX(device, box_xfile, box_vertex_buffer, box_fvf, box_index_buffer, box_materials, TRUE);
2542     test_LoadMeshFromX(device, framed_xfile, merged_vertex_buffer, framed_fvf, merged_index_buffer, default_materials, FALSE);
2543 
2544     free_test_context(test_context);
2545 }
2546 
2547 static BOOL compute_box(struct mesh *mesh, float width, float height, float depth)
2548 {
2549     unsigned int i, face;
2550     static const D3DXVECTOR3 unit_box[] =
2551     {
2552         {-1.0f, -1.0f, -1.0f}, {-1.0f, -1.0f,  1.0f}, {-1.0f,  1.0f,  1.0f}, {-1.0f,  1.0f, -1.0f},
2553         {-1.0f,  1.0f, -1.0f}, {-1.0f,  1.0f,  1.0f}, { 1.0f,  1.0f,  1.0f}, { 1.0f,  1.0f, -1.0f},
2554         { 1.0f,  1.0f, -1.0f}, { 1.0f,  1.0f,  1.0f}, { 1.0f, -1.0f,  1.0f}, { 1.0f, -1.0f, -1.0f},
2555         {-1.0f, -1.0f,  1.0f}, {-1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f,  1.0f},
2556         {-1.0f, -1.0f,  1.0f}, { 1.0f, -1.0f,  1.0f}, { 1.0f,  1.0f,  1.0f}, {-1.0f,  1.0f,  1.0f},
2557         {-1.0f, -1.0f, -1.0f}, {-1.0f,  1.0f, -1.0f}, { 1.0f,  1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}
2558     };
2559     static const D3DXVECTOR3 normals[] =
2560     {
2561         {-1.0f,  0.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f,  0.0f},
2562         { 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, -1.0f}
2563     };
2564 
2565     if (!new_mesh(mesh, 24, 12))
2566     {
2567         return FALSE;
2568     }
2569 
2570     width /= 2.0f;
2571     height /= 2.0f;
2572     depth /= 2.0f;
2573 
2574     for (i = 0; i < 24; i++)
2575     {
2576         mesh->vertices[i].position.x = width * unit_box[i].x;
2577         mesh->vertices[i].position.y = height * unit_box[i].y;
2578         mesh->vertices[i].position.z = depth * unit_box[i].z;
2579         mesh->vertices[i].normal.x = normals[i / 4].x;
2580         mesh->vertices[i].normal.y = normals[i / 4].y;
2581         mesh->vertices[i].normal.z = normals[i / 4].z;
2582     }
2583 
2584     face = 0;
2585     for (i = 0; i < 12; i++)
2586     {
2587         mesh->faces[i][0] = face++;
2588         mesh->faces[i][1] = face++;
2589         mesh->faces[i][2] = (i % 2) ? face - 4 : face;
2590     }
2591 
2592     return TRUE;
2593 }
2594 
2595 static void test_box(IDirect3DDevice9 *device, float width, float height, float depth)
2596 {
2597     HRESULT hr;
2598     ID3DXMesh *box;
2599     struct mesh mesh;
2600     char name[256];
2601 
2602     hr = D3DXCreateBox(device, width, height, depth, &box, NULL);
2603     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2604     if (hr != D3D_OK)
2605     {
2606         skip("Couldn't create box\n");
2607         return;
2608     }
2609 
2610     if (!compute_box(&mesh, width, height, depth))
2611     {
2612         skip("Couldn't create mesh\n");
2613         box->lpVtbl->Release(box);
2614         return;
2615     }
2616 
2617     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2618 
2619     sprintf(name, "box (%g, %g, %g)", width, height, depth);
2620     compare_mesh(name, box, &mesh);
2621 
2622     free_mesh(&mesh);
2623 
2624     box->lpVtbl->Release(box);
2625 }
2626 static void D3DXCreateBoxTest(void)
2627 {
2628     HRESULT hr;
2629     IDirect3DDevice9* device;
2630     ID3DXMesh* box;
2631     ID3DXBuffer* ppBuffer;
2632     DWORD *buffer;
2633     static const DWORD adjacency[36]=
2634         {6, 9, 1, 2, 10, 0,
2635          1, 9, 3, 4, 10, 2,
2636          3, 8, 5, 7, 11, 4,
2637          0, 11, 7, 5, 8, 6,
2638          7, 4, 9, 2, 0, 8,
2639          1, 3, 11, 5, 6, 10};
2640     unsigned int i;
2641     struct test_context *test_context;
2642 
2643     if (!(test_context = new_test_context()))
2644     {
2645         skip("Couldn't create test context\n");
2646         return;
2647     }
2648     device = test_context->device;
2649 
2650     hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
2651     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2652 
2653     hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
2654     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2655 
2656     hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
2657     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2658 
2659     hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
2660     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2661 
2662     hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
2663     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2664 
2665     ppBuffer = NULL;
2666     hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
2667     ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2668 
2669     buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
2670     for(i=0; i<36; i++)
2671         ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
2672 
2673     box->lpVtbl->Release(box);
2674     ID3DXBuffer_Release(ppBuffer);
2675 
2676     test_box(device, 10.9f, 20.0f, 4.9f);
2677 
2678     free_test_context(test_context);
2679 }
2680 
2681 static BOOL compute_polygon(struct mesh *mesh, float length, unsigned int sides)
2682 {
2683     unsigned int i;
2684     float angle, scale;
2685 
2686     if (!new_mesh(mesh, sides + 1, sides))
2687         return FALSE;
2688 
2689     angle = D3DX_PI / sides;
2690     scale = 0.5f * length / sinf(angle);
2691     angle *= 2.0f;
2692 
2693     mesh->vertices[0].position.x = 0.0f;
2694     mesh->vertices[0].position.y = 0.0f;
2695     mesh->vertices[0].position.z = 0.0f;
2696     mesh->vertices[0].normal.x = 0.0f;
2697     mesh->vertices[0].normal.y = 0.0f;
2698     mesh->vertices[0].normal.z = 1.0f;
2699 
2700     for (i = 0; i < sides; ++i)
2701     {
2702         mesh->vertices[i + 1].position.x = cosf(angle * i) * scale;
2703         mesh->vertices[i + 1].position.y = sinf(angle * i) * scale;
2704         mesh->vertices[i + 1].position.z = 0.0f;
2705         mesh->vertices[i + 1].normal.x = 0.0f;
2706         mesh->vertices[i + 1].normal.y = 0.0f;
2707         mesh->vertices[i + 1].normal.z = 1.0f;
2708 
2709         mesh->faces[i][0] = 0;
2710         mesh->faces[i][1] = i + 1;
2711         mesh->faces[i][2] = i + 2;
2712     }
2713 
2714     mesh->faces[sides - 1][2] = 1;
2715 
2716     return TRUE;
2717 }
2718 
2719 static void test_polygon(IDirect3DDevice9 *device, float length, unsigned int sides)
2720 {
2721     HRESULT hr;
2722     ID3DXMesh *polygon;
2723     struct mesh mesh;
2724     char name[64];
2725 
2726     hr = D3DXCreatePolygon(device, length, sides, &polygon, NULL);
2727     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2728     if (hr != D3D_OK)
2729     {
2730         skip("Couldn't create polygon\n");
2731         return;
2732     }
2733 
2734     if (!compute_polygon(&mesh, length, sides))
2735     {
2736         skip("Couldn't create mesh\n");
2737         polygon->lpVtbl->Release(polygon);
2738         return;
2739     }
2740 
2741     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2742 
2743     sprintf(name, "polygon (%g, %u)", length, sides);
2744     compare_mesh(name, polygon, &mesh);
2745 
2746     free_mesh(&mesh);
2747 
2748     polygon->lpVtbl->Release(polygon);
2749 }
2750 
2751 static void D3DXCreatePolygonTest(void)
2752 {
2753     HRESULT hr;
2754     IDirect3DDevice9 *device;
2755     ID3DXMesh *polygon;
2756     ID3DXBuffer *adjacency;
2757     DWORD (*buffer)[3], buffer_size;
2758     unsigned int i;
2759     struct test_context *test_context;
2760 
2761     if (!(test_context = new_test_context()))
2762     {
2763         skip("Couldn't create test context\n");
2764         return;
2765     }
2766     device = test_context->device;
2767 
2768     hr = D3DXCreatePolygon(device, 2.0f, 11, NULL, &adjacency);
2769     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2770 
2771     hr = D3DXCreatePolygon(NULL, 2.0f, 11, &polygon, &adjacency);
2772     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2773 
2774     hr = D3DXCreatePolygon(device, -2.0f, 11, &polygon, &adjacency);
2775     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2776 
2777     polygon = (void *)0xdeadbeef;
2778     adjacency = (void *)0xdeadbeef;
2779     hr = D3DXCreatePolygon(device, 2.0f, 0, &polygon, &adjacency);
2780     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2781     ok(polygon == (void *)0xdeadbeef, "Polygon was changed to %p\n", polygon);
2782     ok(adjacency == (void *)0xdeadbeef, "Adjacency was changed to %p\n", adjacency);
2783 
2784     hr = D3DXCreatePolygon(device, 2.0f, 2, &polygon, &adjacency);
2785     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2786 
2787     adjacency = NULL;
2788     hr = D3DXCreatePolygon(device, 3.0f, 11, &polygon, &adjacency);
2789     ok(hr == D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2790 
2791     buffer_size = ID3DXBuffer_GetBufferSize(adjacency);
2792     ok(buffer_size == 33 * sizeof(DWORD), "Wrong adjacency buffer size %u\n", buffer_size);
2793 
2794     buffer = ID3DXBuffer_GetBufferPointer(adjacency);
2795     for (i = 0; i < 11; ++i)
2796     {
2797         ok(buffer[i][0] == (i + 10) % 11, "Wrong adjacency[%d][0] = %u\n", i, buffer[i][0]);
2798         ok(buffer[i][1] == ~0U, "Wrong adjacency[%d][1] = %u\n", i, buffer[i][1]);
2799         ok(buffer[i][2] == (i + 1) % 11, "Wrong adjacency[%d][2] = %u\n", i, buffer[i][2]);
2800     }
2801 
2802     polygon->lpVtbl->Release(polygon);
2803     ID3DXBuffer_Release(adjacency);
2804 
2805     test_polygon(device, 2.0f, 3);
2806     test_polygon(device, 10.0f, 3);
2807     test_polygon(device, 10.0f, 5);
2808     test_polygon(device, 10.0f, 10);
2809     test_polygon(device, 20.0f, 10);
2810     test_polygon(device, 20.0f, 32000);
2811 
2812     free_test_context(test_context);
2813 }
2814 
2815 struct sincos_table
2816 {
2817     float *sin;
2818     float *cos;
2819 };
2820 
2821 static void free_sincos_table(struct sincos_table *sincos_table)
2822 {
2823     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
2824     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2825 }
2826 
2827 /* pre compute sine and cosine tables; caller must free */
2828 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
2829 {
2830     float angle;
2831     int i;
2832 
2833     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2834     if (!sincos_table->sin)
2835     {
2836         return FALSE;
2837     }
2838     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2839     if (!sincos_table->cos)
2840     {
2841         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2842         return FALSE;
2843     }
2844 
2845     angle = angle_start;
2846     for (i = 0; i < n; i++)
2847     {
2848         sincos_table->sin[i] = sin(angle);
2849         sincos_table->cos[i] = cos(angle);
2850         angle += angle_step;
2851     }
2852 
2853     return TRUE;
2854 }
2855 
2856 static WORD vertex_index(UINT slices, int slice, int stack)
2857 {
2858     return stack*slices+slice+1;
2859 }
2860 
2861 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
2862 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
2863 {
2864     float theta_step, theta_start;
2865     struct sincos_table theta;
2866     float phi_step, phi_start;
2867     struct sincos_table phi;
2868     DWORD number_of_vertices, number_of_faces;
2869     DWORD vertex, face;
2870     int slice, stack;
2871 
2872     /* theta = angle on xy plane wrt x axis */
2873     theta_step = D3DX_PI / stacks;
2874     theta_start = theta_step;
2875 
2876     /* phi = angle on xz plane wrt z axis */
2877     phi_step = -2 * D3DX_PI / slices;
2878     phi_start = D3DX_PI / 2;
2879 
2880     if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
2881     {
2882         return FALSE;
2883     }
2884     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
2885     {
2886         free_sincos_table(&theta);
2887         return FALSE;
2888     }
2889 
2890     number_of_vertices = 2 + slices * (stacks-1);
2891     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
2892 
2893     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2894     {
2895         free_sincos_table(&phi);
2896         free_sincos_table(&theta);
2897         return FALSE;
2898     }
2899 
2900     vertex = 0;
2901     face = 0;
2902 
2903     mesh->vertices[vertex].normal.x = 0.0f;
2904     mesh->vertices[vertex].normal.y = 0.0f;
2905     mesh->vertices[vertex].normal.z = 1.0f;
2906     mesh->vertices[vertex].position.x = 0.0f;
2907     mesh->vertices[vertex].position.y = 0.0f;
2908     mesh->vertices[vertex].position.z = radius;
2909     vertex++;
2910 
2911     for (stack = 0; stack < stacks - 1; stack++)
2912     {
2913         for (slice = 0; slice < slices; slice++)
2914         {
2915             mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
2916             mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
2917             mesh->vertices[vertex].normal.z = theta.cos[stack];
2918             mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
2919             mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
2920             mesh->vertices[vertex].position.z = radius * theta.cos[stack];
2921             vertex++;
2922 
2923             if (slice > 0)
2924             {
2925                 if (stack == 0)
2926                 {
2927                     /* top stack is triangle fan */
2928                     mesh->faces[face][0] = 0;
2929                     mesh->faces[face][1] = slice + 1;
2930                     mesh->faces[face][2] = slice;
2931                     face++;
2932                 }
2933                 else
2934                 {
2935                     /* stacks in between top and bottom are quad strips */
2936                     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2937                     mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2938                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2939                     face++;
2940 
2941                     mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2942                     mesh->faces[face][1] = vertex_index(slices, slice, stack);
2943                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2944                     face++;
2945                 }
2946             }
2947         }
2948 
2949         if (stack == 0)
2950         {
2951             mesh->faces[face][0] = 0;
2952             mesh->faces[face][1] = 1;
2953             mesh->faces[face][2] = slice;
2954             face++;
2955         }
2956         else
2957         {
2958             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2959             mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2960             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2961             face++;
2962 
2963             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2964             mesh->faces[face][1] = vertex_index(slices, 0, stack);
2965             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2966             face++;
2967         }
2968     }
2969 
2970     mesh->vertices[vertex].position.x = 0.0f;
2971     mesh->vertices[vertex].position.y = 0.0f;
2972     mesh->vertices[vertex].position.z = -radius;
2973     mesh->vertices[vertex].normal.x = 0.0f;
2974     mesh->vertices[vertex].normal.y = 0.0f;
2975     mesh->vertices[vertex].normal.z = -1.0f;
2976 
2977     /* bottom stack is triangle fan */
2978     for (slice = 1; slice < slices; slice++)
2979     {
2980         mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2981         mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2982         mesh->faces[face][2] = vertex;
2983         face++;
2984     }
2985 
2986     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2987     mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2988     mesh->faces[face][2] = vertex;
2989 
2990     free_sincos_table(&phi);
2991     free_sincos_table(&theta);
2992 
2993     return TRUE;
2994 }
2995 
2996 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
2997 {
2998     HRESULT hr;
2999     ID3DXMesh *sphere;
3000     struct mesh mesh;
3001     char name[256];
3002 
3003     hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
3004     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3005     if (hr != D3D_OK)
3006     {
3007         skip("Couldn't create sphere\n");
3008         return;
3009     }
3010 
3011     if (!compute_sphere(&mesh, radius, slices, stacks))
3012     {
3013         skip("Couldn't create mesh\n");
3014         sphere->lpVtbl->Release(sphere);
3015         return;
3016     }
3017 
3018     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3019 
3020     sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
3021     compare_mesh(name, sphere, &mesh);
3022 
3023     free_mesh(&mesh);
3024 
3025     sphere->lpVtbl->Release(sphere);
3026 }
3027 
3028 static void D3DXCreateSphereTest(void)
3029 {
3030     HRESULT hr;
3031     IDirect3DDevice9* device;
3032     ID3DXMesh* sphere = NULL;
3033     struct test_context *test_context;
3034 
3035     hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
3036     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3037 
3038     hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
3039     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3040 
3041     hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
3042     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3043 
3044     hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
3045     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3046 
3047     if (!(test_context = new_test_context()))
3048     {
3049         skip("Couldn't create test context\n");
3050         return;
3051     }
3052     device = test_context->device;
3053 
3054     hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
3055     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3056 
3057     hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
3058     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3059 
3060     hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
3061     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3062 
3063     hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
3064     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3065 
3066     test_sphere(device, 0.0f, 2, 2);
3067     test_sphere(device, 1.0f, 2, 2);
3068     test_sphere(device, 1.0f, 3, 2);
3069     test_sphere(device, 1.0f, 4, 4);
3070     test_sphere(device, 1.0f, 3, 4);
3071     test_sphere(device, 5.0f, 6, 7);
3072     test_sphere(device, 10.0f, 11, 12);
3073 
3074     free_test_context(test_context);
3075 }
3076 
3077 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3078 {
3079     float theta_step, theta_start;
3080     struct sincos_table theta;
3081     FLOAT delta_radius, radius, radius_step;
3082     FLOAT z, z_step, z_normal;
3083     DWORD number_of_vertices, number_of_faces;
3084     DWORD vertex, face;
3085     int slice, stack;
3086 
3087     /* theta = angle on xy plane wrt x axis */
3088     theta_step = -2 * D3DX_PI / slices;
3089     theta_start = D3DX_PI / 2;
3090 
3091     if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
3092     {
3093         return FALSE;
3094     }
3095 
3096     number_of_vertices = 2 + (slices * (3 + stacks));
3097     number_of_faces = 2 * slices + stacks * (2 * slices);
3098 
3099     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
3100     {
3101         free_sincos_table(&theta);
3102         return FALSE;
3103     }
3104 
3105     vertex = 0;
3106     face = 0;
3107 
3108     delta_radius = radius1 - radius2;
3109     radius = radius1;
3110     radius_step = delta_radius / stacks;
3111 
3112     z = -length / 2;
3113     z_step = length / stacks;
3114     z_normal = delta_radius / length;
3115     if (isnan(z_normal))
3116     {
3117         z_normal = 0.0f;
3118     }
3119 
3120     mesh->vertices[vertex].normal.x = 0.0f;
3121     mesh->vertices[vertex].normal.y = 0.0f;
3122     mesh->vertices[vertex].normal.z = -1.0f;
3123     mesh->vertices[vertex].position.x = 0.0f;
3124     mesh->vertices[vertex].position.y = 0.0f;
3125     mesh->vertices[vertex++].position.z = z;
3126 
3127     for (slice = 0; slice < slices; slice++, vertex++)
3128     {
3129         mesh->vertices[vertex].normal.x = 0.0f;
3130         mesh->vertices[vertex].normal.y = 0.0f;
3131         mesh->vertices[vertex].normal.z = -1.0f;
3132         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3133         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3134         mesh->vertices[vertex].position.z = z;
3135 
3136         if (slice > 0)
3137         {
3138             mesh->faces[face][0] = 0;
3139             mesh->faces[face][1] = slice;
3140             mesh->faces[face++][2] = slice + 1;
3141         }
3142     }
3143 
3144     mesh->faces[face][0] = 0;
3145     mesh->faces[face][1] = slice;
3146     mesh->faces[face++][2] = 1;
3147 
3148     for (stack = 1; stack <= stacks+1; stack++)
3149     {
3150         for (slice = 0; slice < slices; slice++, vertex++)
3151         {
3152             mesh->vertices[vertex].normal.x = theta.cos[slice];
3153             mesh->vertices[vertex].normal.y = theta.sin[slice];
3154             mesh->vertices[vertex].normal.z = z_normal;
3155             D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
3156             mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3157             mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3158             mesh->vertices[vertex].position.z = z;
3159 
3160             if (stack > 1 && slice > 0)
3161             {
3162                 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3163                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3164                 mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
3165 
3166                 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
3167                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3168                 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3169             }
3170         }
3171 
3172         if (stack > 1)
3173         {
3174             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3175             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3176             mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
3177 
3178             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
3179             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3180             mesh->faces[face++][2] = vertex_index(slices, 0, stack);
3181         }
3182 
3183         if (stack < stacks + 1)
3184         {
3185             z += z_step;
3186             radius -= radius_step;
3187         }
3188     }
3189 
3190     for (slice = 0; slice < slices; slice++, vertex++)
3191     {
3192         mesh->vertices[vertex].normal.x = 0.0f;
3193         mesh->vertices[vertex].normal.y = 0.0f;
3194         mesh->vertices[vertex].normal.z = 1.0f;
3195         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3196         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3197         mesh->vertices[vertex].position.z = z;
3198 
3199         if (slice > 0)
3200         {
3201             mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3202             mesh->faces[face][1] = number_of_vertices - 1;
3203             mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3204         }
3205     }
3206 
3207     mesh->vertices[vertex].position.x = 0.0f;
3208     mesh->vertices[vertex].position.y = 0.0f;
3209     mesh->vertices[vertex].position.z = z;
3210     mesh->vertices[vertex].normal.x = 0.0f;
3211     mesh->vertices[vertex].normal.y = 0.0f;
3212     mesh->vertices[vertex].normal.z = 1.0f;
3213 
3214     mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3215     mesh->faces[face][1] = number_of_vertices - 1;
3216     mesh->faces[face][2] = vertex_index(slices, 0, stack);
3217 
3218     free_sincos_table(&theta);
3219 
3220     return TRUE;
3221 }
3222 
3223 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3224 {
3225     HRESULT hr;
3226     ID3DXMesh *cylinder;
3227     struct mesh mesh;
3228     char name[256];
3229 
3230     hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
3231     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3232     if (hr != D3D_OK)
3233     {
3234         skip("Couldn't create cylinder\n");
3235         return;
3236     }
3237 
3238     if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
3239     {
3240         skip("Couldn't create mesh\n");
3241         cylinder->lpVtbl->Release(cylinder);
3242         return;
3243     }
3244 
3245     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3246 
3247     sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
3248     compare_mesh(name, cylinder, &mesh);
3249 
3250     free_mesh(&mesh);
3251 
3252     cylinder->lpVtbl->Release(cylinder);
3253 }
3254 
3255 static void D3DXCreateCylinderTest(void)
3256 {
3257     HRESULT hr;
3258     IDirect3DDevice9* device;
3259     ID3DXMesh* cylinder = NULL;
3260     struct test_context *test_context;
3261 
3262     hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
3263     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3264 
3265     hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3266     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3267 
3268     if (!(test_context = new_test_context()))
3269     {
3270         skip("Couldn't create test context\n");
3271         return;
3272     }
3273     device = test_context->device;
3274 
3275     hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3276     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3277 
3278     hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3279     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3280 
3281     if (SUCCEEDED(hr) && cylinder)
3282     {
3283         cylinder->lpVtbl->Release(cylinder);
3284     }
3285 
3286     hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
3287     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3288 
3289     hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
3290     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3291 
3292     if (SUCCEEDED(hr) && cylinder)
3293     {
3294         cylinder->lpVtbl->Release(cylinder);
3295     }
3296 
3297     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
3298     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3299 
3300     /* Test with length == 0.0f succeeds */
3301     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
3302     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3303 
3304     if (SUCCEEDED(hr) && cylinder)
3305     {
3306         cylinder->lpVtbl->Release(cylinder);
3307     }
3308 
3309     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
3310     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3311 
3312     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
3313     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3314 
3315     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
3316     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3317 
3318     test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
3319     test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
3320     test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
3321     test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
3322     test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
3323     test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
3324 
3325     free_test_context(test_context);
3326 }
3327 
3328 static BOOL compute_torus(struct mesh *mesh, float innerradius, float outerradius, UINT sides, UINT rings)
3329 {
3330     float phi, phi_step, sin_phi, cos_phi;
3331     float theta, theta_step, sin_theta, cos_theta;
3332     unsigned int numvert, numfaces, i, j;
3333 
3334     numvert = sides * rings;
3335     numfaces = numvert * 2;
3336 
3337     if (!new_mesh(mesh, numvert, numfaces))
3338         return FALSE;
3339 
3340     phi_step = D3DX_PI / sides * 2.0f;
3341     theta_step = D3DX_PI / rings * -2.0f;
3342 
3343     theta = 0.0f;
3344 
3345     for (i = 0; i < rings; ++i)
3346     {
3347         phi = 0.0f;
3348 
3349         cos_theta = cosf(theta);
3350         sin_theta = sinf(theta);
3351 
3352         for (j = 0; j < sides; ++j)
3353         {
3354             sin_phi = sinf(phi);
3355             cos_phi = cosf(phi);
3356 
3357             mesh->vertices[i * sides + j].position.x = (innerradius * cos_phi + outerradius) * cos_theta;
3358             mesh->vertices[i * sides + j].position.y = (innerradius * cos_phi + outerradius) * sin_theta;
3359             mesh->vertices[i * sides + j].position.z = innerradius * sin_phi;
3360             mesh->vertices[i * sides + j].normal.x = cos_phi * cos_theta;
3361             mesh->vertices[i * sides + j].normal.y = cos_phi * sin_theta;
3362             mesh->vertices[i * sides + j].normal.z = sin_phi;
3363 
3364             phi += phi_step;
3365         }
3366 
3367         theta += theta_step;
3368     }
3369 
3370     for (i = 0; i < numfaces - sides * 2; ++i)
3371     {
3372         mesh->faces[i][0] = i % 2 ? i / 2 + sides : i / 2;
3373         mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3374         mesh->faces[i][2] = (i + 1) % (sides * 2) ? (i + 1) / 2 + sides : (i + 1) / 2;
3375     }
3376 
3377     for (j = 0; i < numfaces; ++i, ++j)
3378     {
3379         mesh->faces[i][0] = i % 2 ? j / 2 : i / 2;
3380         mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3381         mesh->faces[i][2] = i == numfaces - 1 ? 0 : (j + 1) / 2;
3382     }
3383 
3384     return TRUE;
3385 }
3386 
3387 static void test_torus(IDirect3DDevice9 *device, float innerradius, float outerradius, UINT sides, UINT rings)
3388 {
3389     HRESULT hr;
3390     ID3DXMesh *torus;
3391     struct mesh mesh;
3392     char name[256];
3393 
3394     hr = D3DXCreateTorus(device, innerradius, outerradius, sides, rings, &torus, NULL);
3395     ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK)\n", hr);
3396     if (hr != D3D_OK)
3397     {
3398         skip("Couldn't create torus\n");
3399         return;
3400     }
3401 
3402     if (!compute_torus(&mesh, innerradius, outerradius, sides, rings))
3403     {
3404         skip("Couldn't create mesh\n");
3405         torus->lpVtbl->Release(torus);
3406         return;
3407     }
3408 
3409     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3410 
3411     sprintf(name, "torus (%g, %g, %u, %u)", innerradius, outerradius, sides, rings);
3412     compare_mesh(name, torus, &mesh);
3413 
3414     free_mesh(&mesh);
3415 
3416     torus->lpVtbl->Release(torus);
3417 }
3418 
3419 static void D3DXCreateTorusTest(void)
3420 {
3421     HRESULT hr;
3422     IDirect3DDevice9* device;
3423     ID3DXMesh* torus = NULL;
3424     struct test_context *test_context;
3425 
3426     if (!(test_context = new_test_context()))
3427     {
3428         skip("Couldn't create test context\n");
3429         return;
3430     }
3431     device = test_context->device;
3432 
3433     hr = D3DXCreateTorus(NULL, 0.0f, 0.0f, 3, 3, &torus, NULL);
3434     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3435 
3436     hr = D3DXCreateTorus(device, -1.0f, 0.0f, 3, 3, &torus, NULL);
3437     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3438 
3439     hr = D3DXCreateTorus(device, 0.0f, -1.0f, 3, 3, &torus, NULL);
3440     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3441 
3442     hr = D3DXCreateTorus(device, 0.0f, 0.0f, 2, 3, &torus, NULL);
3443     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3444 
3445     hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 2, &torus, NULL);
3446     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3447 
3448     hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 3, NULL, NULL);
3449     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3450 
3451     test_torus(device, 0.0f, 0.0f, 3, 3);
3452     test_torus(device, 1.0f, 1.0f, 3, 3);
3453     test_torus(device, 1.0f, 1.0f, 32, 64);
3454     test_torus(device, 0.0f, 1.0f, 5, 5);
3455     test_torus(device, 1.0f, 0.0f, 5, 5);
3456     test_torus(device, 5.0f, 0.2f, 8, 8);
3457     test_torus(device, 0.2f, 1.0f, 60, 3);
3458     test_torus(device, 0.2f, 1.0f, 8, 70);
3459 
3460     free_test_context(test_context);
3461 }
3462 
3463 struct dynamic_array
3464 {
3465     int count, capacity;
3466     void *items;
3467 };
3468 
3469 enum pointtype {
3470     POINTTYPE_CURVE = 0,
3471     POINTTYPE_CORNER,
3472     POINTTYPE_CURVE_START,
3473     POINTTYPE_CURVE_END,
3474     POINTTYPE_CURVE_MIDDLE,
3475 };
3476 
3477 struct point2d
3478 {
3479     D3DXVECTOR2 pos;
3480     enum pointtype corner;
3481 };
3482 
3483 /* is a dynamic_array */
3484 struct outline
3485 {
3486     int count, capacity;
3487     struct point2d *items;
3488 };
3489 
3490 /* is a dynamic_array */
3491 struct outline_array
3492 {
3493     int count, capacity;
3494     struct outline *items;
3495 };
3496 
3497 struct glyphinfo
3498 {
3499     struct outline_array outlines;
3500     float offset_x;
3501 };
3502 
3503 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
3504 {
3505     if (count > array->capacity) {
3506         void *new_buffer;
3507         int new_capacity;
3508         if (array->items && array->capacity) {
3509             new_capacity = max(array->capacity * 2, count);
3510             new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
3511         } else {
3512             new_capacity = max(16, count);
3513             new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
3514         }
3515         if (!new_buffer)
3516             return FALSE;
3517         array->items = new_buffer;
3518         array->capacity = new_capacity;
3519     }
3520     return TRUE;
3521 }
3522 
3523 static struct point2d *add_point(struct outline *array)
3524 {
3525     struct point2d *item;
3526 
3527     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3528         return NULL;
3529 
3530     item = &array->items[array->count++];
3531     ZeroMemory(item, sizeof(*item));
3532     return item;
3533 }
3534 
3535 static struct outline *add_outline(struct outline_array *array)
3536 {
3537     struct outline *item;
3538 
3539     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3540         return NULL;
3541 
3542     item = &array->items[array->count++];
3543     ZeroMemory(item, sizeof(*item));
3544     return item;
3545 }
3546 
3547 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
3548 {
3549     D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
3550     while (count--) {
3551         D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
3552         pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
3553         pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
3554         pt++;
3555     }
3556     return ret;
3557 }
3558 
3559 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
3560                                  const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
3561                                  float max_deviation)
3562 {
3563     D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
3564     float deviation;
3565 
3566     D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
3567     D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
3568     D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
3569 
3570     deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
3571     if (deviation < max_deviation) {
3572         struct point2d *pt = add_point(outline);
3573         if (!pt) return E_OUTOFMEMORY;
3574         pt->pos = *p2;
3575         pt->corner = POINTTYPE_CURVE;
3576         /* the end point is omitted because the end line merges into the next segment of
3577          * the split bezier curve, and the end of the split bezier curve is added outside
3578          * this recursive function. */
3579     } else {
3580         HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
3581         if (hr != S_OK) return hr;
3582         hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
3583         if (hr != S_OK) return hr;
3584     }
3585 
3586     return S_OK;
3587 }
3588 
3589 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
3590 {
3591     /* dot product = cos(theta) */
3592     return D3DXVec2Dot(dir1, dir2) > cos_theta;
3593 }
3594 
3595 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
3596 {
3597     return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
3598 }
3599 
3600 static BOOL attempt_line_merge(struct outline *outline,
3601                                int pt_index,
3602                                const D3DXVECTOR2 *nextpt,
3603                                BOOL to_curve)
3604 {
3605     D3DXVECTOR2 curdir, lastdir;
3606     struct point2d *prevpt, *pt;
3607     BOOL ret = FALSE;
3608     const float cos_half = cos(D3DXToRadian(0.5f));
3609 
3610     pt = &outline->items[pt_index];
3611     pt_index = (pt_index - 1 + outline->count) % outline->count;
3612     prevpt = &outline->items[pt_index];
3613 
3614     if (to_curve)
3615         pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
3616 
3617     if (outline->count < 2)
3618         return FALSE;
3619 
3620     /* remove last point if the next line continues the last line */
3621     unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3622     unit_vec2(&curdir, &pt->pos, nextpt);
3623     if (is_direction_similar(&lastdir, &curdir, cos_half))
3624     {
3625         outline->count--;
3626         if (pt->corner == POINTTYPE_CURVE_END)
3627             prevpt->corner = pt->corner;
3628         if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
3629             prevpt->corner = POINTTYPE_CURVE_MIDDLE;
3630         pt = prevpt;
3631 
3632         ret = TRUE;
3633         if (outline->count < 2)
3634             return ret;
3635 
3636         pt_index = (pt_index - 1 + outline->count) % outline->count;
3637         prevpt = &outline->items[pt_index];
3638         unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3639         unit_vec2(&curdir, &pt->pos, nextpt);
3640     }
3641     return ret;
3642 }
3643 
3644 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
3645                               float max_deviation, float emsquare)
3646 {
3647     const float cos_45 = cos(D3DXToRadian(45.0f));
3648     const float cos_90 = cos(D3DXToRadian(90.0f));
3649     TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
3650 
3651     while ((char *)header < (char *)raw_outline + datasize)
3652     {
3653         TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
3654         struct point2d *lastpt, *pt;
3655         D3DXVECTOR2 lastdir;
3656         D3DXVECTOR2 *pt_flt;
3657         int j;
3658         struct outline *outline = add_outline(&glyph->outlines);
3659 
3660         if (!outline)
3661             return E_OUTOFMEMORY;
3662 
3663         pt = add_point(outline);
3664         if (!pt)
3665             return E_OUTOFMEMORY;
3666         pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
3667         pt->pos = *pt_flt;
3668         pt->corner = POINTTYPE_CORNER;
3669 
3670         if (header->dwType != TT_POLYGON_TYPE)
3671             trace("Unknown header type %d\n", header->dwType);
3672 
3673         while ((char *)curve < (char *)header + header->cb)
3674         {
3675             D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
3676             BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
3677 
3678             if (!curve->cpfx) {
3679                 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3680                 continue;
3681             }
3682 
3683             pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
3684 
3685             attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
3686 
3687             if (to_curve)
3688             {
3689                 HRESULT hr;
3690                 int count = curve->cpfx;
3691                 j = 0;
3692 
3693                 while (count > 2)
3694                 {
3695                     D3DXVECTOR2 bezier_end;
3696 
3697                     D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
3698                     hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
3699                     if (hr != S_OK)
3700                         return hr;
3701                     bezier_start = bezier_end;
3702                     count--;
3703                     j++;
3704                 }
3705                 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
3706                 if (hr != S_OK)
3707                     return hr;
3708 
3709                 pt = add_point(outline);
3710                 if (!pt)
3711                     return E_OUTOFMEMORY;
3712                 j++;
3713                 pt->pos = pt_flt[j];
3714                 pt->corner = POINTTYPE_CURVE_END;
3715             } else {
3716                 for (j = 0; j < curve->cpfx; j++)
3717                 {
3718                     pt = add_point(outline);
3719                     if (!pt)
3720                         return E_OUTOFMEMORY;
3721                     pt->pos = pt_flt[j];
3722                     pt->corner = POINTTYPE_CORNER;
3723                 }
3724             }
3725 
3726             curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3727         }
3728 
3729         /* remove last point if the next line continues the last line */
3730         if (outline->count >= 3) {
3731             BOOL to_curve;
3732 
3733             lastpt = &outline->items[outline->count - 1];
3734             pt = &outline->items[0];
3735             if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
3736                 if (lastpt->corner == POINTTYPE_CURVE_END)
3737                 {
3738                     if (pt->corner == POINTTYPE_CURVE_START)
3739                         pt->corner = POINTTYPE_CURVE_MIDDLE;
3740                     else
3741                         pt->corner = POINTTYPE_CURVE_END;
3742                 }
3743                 outline->count--;
3744             } else {
3745                 /* outline closed with a line from end to start point */
3746                 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
3747             }
3748             lastpt = &outline->items[0];
3749             to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
3750             if (lastpt->corner == POINTTYPE_CURVE_START)
3751                 lastpt->corner = POINTTYPE_CORNER;
3752             pt = &outline->items[1];
3753             if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
3754                 *lastpt = outline->items[outline->count];
3755         }
3756 
3757         lastpt = &outline->items[outline->count - 1];
3758         pt = &outline->items[0];
3759         unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
3760         for (j = 0; j < outline->count; j++)
3761         {
3762             D3DXVECTOR2 curdir;
3763 
3764             lastpt = pt;
3765             pt = &outline->items[(j + 1) % outline->count];
3766             unit_vec2(&curdir, &lastpt->pos, &pt->pos);
3767 
3768             switch (lastpt->corner)
3769             {
3770                 case POINTTYPE_CURVE_START:
3771                 case POINTTYPE_CURVE_END:
3772                     if (!is_direction_similar(&lastdir, &curdir, cos_45))
3773                         lastpt->corner = POINTTYPE_CORNER;
3774                     break;
3775                 case POINTTYPE_CURVE_MIDDLE:
3776                     if (!is_direction_similar(&lastdir, &curdir, cos_90))
3777                         lastpt->corner = POINTTYPE_CORNER;
3778                     else
3779                         lastpt->corner = POINTTYPE_CURVE;
3780                     break;
3781                 default:
3782                     break;
3783             }
3784             lastdir = curdir;
3785         }
3786 
3787         header = (TTPOLYGONHEADER *)((char *)header + header->cb);
3788     }
3789     return S_OK;
3790 }
3791 
3792 static void free_outline(struct outline *outline)
3793 {
3794     HeapFree(GetProcessHeap(), 0, outline->items);
3795 }
3796 
3797 static void free_glyphinfo(struct glyphinfo *glyph)
3798 {
3799     unsigned int i;
3800 
3801     for (i = 0; i < glyph->outlines.count; ++i)
3802         free_outline(&glyph->outlines.items[i]);
3803     HeapFree(GetProcessHeap(), 0, glyph->outlines.items);
3804 }
3805 
3806 static void compute_text_mesh(struct mesh *mesh, const char *text,
3807         float deviation, float extrusion, float otmEMSquare, const struct glyphinfo *glyphs)
3808 {
3809     DWORD nb_vertices, nb_faces;
3810     DWORD nb_corners, nb_outline_points;
3811     int textlen = 0;
3812     int i;
3813     struct vertex *vertex_ptr;
3814     face *face_ptr;
3815 
3816     textlen = strlen(text);
3817 
3818     /* corner points need an extra vertex for the different side faces normals */
3819     nb_corners = 0;
3820     nb_outline_points = 0;
3821     for (i = 0; i < textlen; i++)
3822     {
3823         int j;
3824         for (j = 0; j < glyphs[i].outlines.count; j++)
3825         {
3826             int k;
3827             struct outline *outline = &glyphs[i].outlines.items[j];
3828             nb_outline_points += outline->count;
3829             nb_corners++; /* first outline point always repeated as a corner */
3830             for (k = 1; k < outline->count; k++)
3831                 if (outline->items[k].corner)
3832                     nb_corners++;
3833         }
3834     }
3835 
3836     nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
3837     nb_faces = nb_outline_points * 2;
3838 
3839     ok(new_mesh(mesh, nb_vertices, nb_faces), "Failed to create reference text mesh.\n");
3840 
3841     /* convert 2D vertices and faces into 3D mesh */
3842     vertex_ptr = mesh->vertices;
3843     face_ptr = mesh->faces;
3844     for (i = 0; i < textlen; i++)
3845     {
3846         int j;
3847 
3848         /* side vertices and faces */
3849         for (j = 0; j < glyphs[i].outlines.count; j++)
3850         {
3851             struct vertex *outline_vertices = vertex_ptr;
3852             struct outline *outline = &glyphs[i].outlines.items[j];
3853             int k;
3854             struct point2d *prevpt = &outline->items[outline->count - 1];
3855             struct point2d *pt = &outline->items[0];
3856 
3857             for (k = 1; k <= outline->count; k++)
3858             {
3859                 struct vertex vtx;
3860                 struct point2d *nextpt = &outline->items[k % outline->count];
3861                 WORD vtx_idx = vertex_ptr - mesh->vertices;
3862                 D3DXVECTOR2 vec;
3863 
3864                 if (pt->corner == POINTTYPE_CURVE_START)
3865                     D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
3866                 else if (pt->corner)
3867                     D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3868                 else
3869                     D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
3870                 D3DXVec2Normalize(&vec, &vec);
3871                 vtx.normal.x = -vec.y;
3872                 vtx.normal.y = vec.x;
3873                 vtx.normal.z = 0;
3874 
3875                 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
3876                 vtx.position.y = pt->pos.y;
3877                 vtx.position.z = 0;
3878                 *vertex_ptr++ = vtx;
3879 
3880                 vtx.position.z = -extrusion;
3881                 *vertex_ptr++ = vtx;
3882 
3883                 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
3884                 vtx.position.y = nextpt->pos.y;
3885                 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
3886                     vtx.position.z = -extrusion;
3887                     *vertex_ptr++ = vtx;
3888                     vtx.position.z = 0;
3889                     *vertex_ptr++ = vtx;
3890 
3891                     (*face_ptr)[0] = vtx_idx;
3892                     (*face_ptr)[1] = vtx_idx + 2;
3893                     (*face_ptr)[2] = vtx_idx + 1;
3894                     face_ptr++;
3895 
3896                     (*face_ptr)[0] = vtx_idx;
3897                     (*face_ptr)[1] = vtx_idx + 3;
3898                     (*face_ptr)[2] = vtx_idx + 2;
3899                     face_ptr++;
3900                 } else {
3901                     if (nextpt->corner) {
3902                         if (nextpt->corner == POINTTYPE_CURVE_END) {
3903                             struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
3904                             D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
3905                         } else {
3906                             D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3907                         }
3908                         D3DXVec2Normalize(&vec, &vec);
3909                         vtx.normal.x = -vec.y;
3910                         vtx.normal.y = vec.x;
3911 
3912                         vtx.position.z = 0;
3913                         *vertex_ptr++ = vtx;
3914                         vtx.position.z = -extrusion;
3915                         *vertex_ptr++ = vtx;
3916                     }
3917 
3918                     (*face_ptr)[0] = vtx_idx;
3919                     (*face_ptr)[1] = vtx_idx + 3;
3920                     (*face_ptr)[2] = vtx_idx + 1;
3921                     face_ptr++;
3922 
3923                     (*face_ptr)[0] = vtx_idx;
3924                     (*face_ptr)[1] = vtx_idx + 2;
3925                     (*face_ptr)[2] = vtx_idx + 3;
3926                     face_ptr++;
3927                 }
3928 
3929                 prevpt = pt;
3930                 pt = nextpt;
3931             }
3932             if (!pt->corner) {
3933                 *vertex_ptr++ = *outline_vertices++;
3934                 *vertex_ptr++ = *outline_vertices++;
3935             }
3936         }
3937 
3938         /* FIXME: compute expected faces */
3939         /* Add placeholder to separate glyph outlines */
3940         vertex_ptr->position.x = 0;
3941         vertex_ptr->position.y = 0;
3942         vertex_ptr->position.z = 0;
3943         vertex_ptr->normal.x = 0;
3944         vertex_ptr->normal.y = 0;
3945         vertex_ptr->normal.z = 1;
3946         vertex_ptr++;
3947     }
3948 }
3949 
3950 static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh,
3951         size_t textlen, float extrusion, const struct glyphinfo *glyphs)
3952 {
3953     HRESULT hr;
3954     DWORD number_of_vertices, number_of_faces;
3955     IDirect3DVertexBuffer9 *vertex_buffer = NULL;
3956     IDirect3DIndexBuffer9 *index_buffer = NULL;
3957     D3DVERTEXBUFFER_DESC vertex_buffer_description;
3958     D3DINDEXBUFFER_DESC index_buffer_description;
3959     struct vertex *vertices = NULL;
3960     face *faces = NULL;
3961     int expected, i;
3962     int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
3963 
3964     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
3965     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
3966 
3967     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
3968     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
3969     hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
3970     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
3971     ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, unexpected format %u.\n",
3972             name, vertex_buffer_description.Format);
3973     ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, unexpected resource type %u.\n",
3974             name, vertex_buffer_description.Type);
3975     ok(!vertex_buffer_description.Usage, "Test %s, unexpected usage %#x.\n", name, vertex_buffer_description.Usage);
3976     ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, unexpected pool %u.\n",
3977             name, vertex_buffer_description.Pool);
3978     ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, unexpected FVF %#x (expected %#x).\n",
3979             name, vertex_buffer_description.FVF, mesh->fvf);
3980     if (!mesh->fvf)
3981         expected = number_of_vertices * mesh->vertex_size;
3982     else
3983         expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
3984     ok(vertex_buffer_description.Size == expected, "Test %s, unexpected size %u (expected %u).\n",
3985             name, vertex_buffer_description.Size, expected);
3986 
3987     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
3988     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
3989     hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
3990     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
3991     ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, unexpected format %u.\n",
3992             name, index_buffer_description.Format);
3993     ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, unexpected resource type %u.\n",
3994             name, index_buffer_description.Type);
3995     ok(!index_buffer_description.Usage, "Test %s, unexpected usage %#x.\n",
3996             name, index_buffer_description.Usage);
3997     ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, unexpected pool %u.\n",
3998             name, index_buffer_description.Pool);
3999     expected = number_of_faces * sizeof(WORD) * 3;
4000     ok(index_buffer_description.Size == expected, "Test %s, unexpected size %u.\n",
4001             name, index_buffer_description.Size);
4002 
4003     hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
4004             (void **)&vertices, D3DLOCK_DISCARD);
4005     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4006     hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
4007             (void **)&faces, D3DLOCK_DISCARD);
4008     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4009     face_idx1 = 0;
4010     vtx_idx2 = 0;
4011     face_idx2 = 0;
4012     vtx_idx1 = 0;
4013     for (i = 0; i < textlen; i++)
4014     {
4015         int nb_outline_vertices1, nb_outline_faces1;
4016         int nb_outline_vertices2, nb_outline_faces2;
4017         int nb_back_vertices, nb_back_faces;
4018         int first_vtx1, first_vtx2;
4019         int first_face1, first_face2;
4020         int j;
4021 
4022         first_vtx1 = vtx_idx1;
4023         first_vtx2 = vtx_idx2;
4024         /* Glyphs without outlines do not generate any vertices. */
4025         if (glyphs[i].outlines.count > 0)
4026         {
4027             for (; vtx_idx1 < number_of_vertices; vtx_idx1++)
4028             {
4029                 if (vertices[vtx_idx1].normal.z != 0)
4030                     break;
4031             }
4032 
4033             for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++)
4034             {
4035                 if (mesh->vertices[vtx_idx2].normal.z != 0)
4036                     break;
4037             }
4038         }
4039         nb_outline_vertices1 = vtx_idx1 - first_vtx1;
4040         nb_outline_vertices2 = vtx_idx2 - first_vtx2;
4041         ok(nb_outline_vertices1 == nb_outline_vertices2,
4042            "Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
4043            nb_outline_vertices1, nb_outline_vertices2);
4044 
4045         for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
4046         {
4047             vtx_idx1 = first_vtx1 + j;
4048             vtx_idx2 = first_vtx2 + j;
4049             ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
4050                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4051                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
4052                mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
4053             ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
4054                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4055                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4056                mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
4057         }
4058         vtx_idx1 = first_vtx1 + nb_outline_vertices1;
4059         vtx_idx2 = first_vtx2 + nb_outline_vertices2;
4060 
4061         first_face1 = face_idx1;
4062         first_face2 = face_idx2;
4063         for (; face_idx1 < number_of_faces; face_idx1++)
4064         {
4065             if (faces[face_idx1][0] >= vtx_idx1 ||
4066                 faces[face_idx1][1] >= vtx_idx1 ||
4067                 faces[face_idx1][2] >= vtx_idx1)
4068                 break;
4069         }
4070         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
4071         {
4072             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
4073                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
4074                 mesh->faces[face_idx2][2] >= vtx_idx2)
4075                 break;
4076         }
4077         nb_outline_faces1 = face_idx1 - first_face1;
4078         nb_outline_faces2 = face_idx2 - first_face2;
4079         ok(nb_outline_faces1 == nb_outline_faces2,
4080            "Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
4081            nb_outline_faces1, nb_outline_faces2);
4082 
4083         for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
4084         {
4085             face_idx1 = first_face1 + j;
4086             face_idx2 = first_face2 + j;
4087             ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
4088                faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
4089                faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
4090                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
4091                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
4092                mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
4093                mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
4094                mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
4095         }
4096         face_idx1 = first_face1 + nb_outline_faces1;
4097         face_idx2 = first_face2 + nb_outline_faces2;
4098 
4099         /* partial test on back vertices and faces  */
4100         first_vtx1 = vtx_idx1;
4101         for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
4102             struct vertex vtx;
4103 
4104             if (vertices[vtx_idx1].normal.z != 1.0f)
4105                 break;
4106 
4107             vtx.position.z = 0.0f;
4108             vtx.normal.x = 0.0f;
4109             vtx.normal.y = 0.0f;
4110             vtx.normal.z = 1.0f;
4111             ok(compare(vertices[vtx_idx1].position.z, vtx.position.z),
4112                "Test %s, glyph %d, vertex position.z %d, result %g, expected %g\n", name, i, vtx_idx1,
4113                vertices[vtx_idx1].position.z, vtx.position.z);
4114             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
4115                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4116                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4117                vtx.normal.x, vtx.normal.y, vtx.normal.z);
4118         }
4119         nb_back_vertices = vtx_idx1 - first_vtx1;
4120         first_face1 = face_idx1;
4121         for (; face_idx1 < number_of_faces; face_idx1++)
4122         {
4123             const D3DXVECTOR3 *vtx1, *vtx2, *vtx3;
4124             D3DXVECTOR3 normal;
4125             D3DXVECTOR3 v1 = {0, 0, 0};
4126             D3DXVECTOR3 v2 = {0, 0, 0};
4127             D3DXVECTOR3 forward = {0.0f, 0.0f, 1.0f};
4128 
4129             if (faces[face_idx1][0] >= vtx_idx1 ||
4130                 faces[face_idx1][1] >= vtx_idx1 ||
4131                 faces[face_idx1][2] >= vtx_idx1)
4132                 break;
4133 
4134             vtx1 = &vertices[faces[face_idx1][0]].position;
4135             vtx2 = &vertices[faces[face_idx1][1]].position;
4136             vtx3 = &vertices[faces[face_idx1][2]].position;
4137 
4138             D3DXVec3Subtract(&v1, vtx2, vtx1);
4139             D3DXVec3Subtract(&v2, vtx3, vtx2);
4140             D3DXVec3Cross(&normal, &v1, &v2);
4141             D3DXVec3Normalize(&normal, &normal);
4142             ok(!D3DXVec3Length(&normal) || compare_vec3(normal, forward),
4143                "Test %s, glyph %d, face %d normal, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, face_idx1,
4144                normal.x, normal.y, normal.z, forward.x, forward.y, forward.z);
4145         }
4146         nb_back_faces = face_idx1 - first_face1;
4147 
4148         /* compare front and back faces & vertices */
4149         if (extrusion == 0.0f) {
4150             /* Oddly there are only back faces in this case */
4151             nb_back_vertices /= 2;
4152             nb_back_faces /= 2;
4153             face_idx1 -= nb_back_faces;
4154             vtx_idx1 -= nb_back_vertices;
4155         }
4156         for (j = 0; j < nb_back_vertices; j++)
4157         {
4158             struct vertex vtx = vertices[first_vtx1];
4159             vtx.position.z = -extrusion;
4160             vtx.normal.x = 0.0f;
4161             vtx.normal.y = 0.0f;
4162             vtx.normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
4163             ok(compare_vec3(vertices[vtx_idx1].position, vtx.position),
4164                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4165                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
4166                vtx.position.x, vtx.position.y, vtx.position.z);
4167             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
4168                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4169                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4170                vtx.normal.x, vtx.normal.y, vtx.normal.z);
4171             vtx_idx1++;
4172             first_vtx1++;
4173         }
4174         for (j = 0; j < nb_back_faces; j++)
4175         {
4176             int f1, f2;
4177             if (extrusion == 0.0f) {
4178                 f1 = 1;
4179                 f2 = 2;
4180             } else {
4181                 f1 = 2;
4182                 f2 = 1;
4183             }
4184             ok(faces[face_idx1][0] == faces[first_face1][0] + nb_back_vertices &&
4185                faces[face_idx1][1] == faces[first_face1][f1] + nb_back_vertices &&
4186                faces[face_idx1][2] == faces[first_face1][f2] + nb_back_vertices,
4187                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
4188                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
4189                faces[first_face1][0] - nb_back_faces,
4190                faces[first_face1][f1] - nb_back_faces,
4191                faces[first_face1][f2] - nb_back_faces);
4192             first_face1++;
4193             face_idx1++;
4194         }
4195 
4196         /* skip to the outline for the next glyph */
4197         for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
4198             if (mesh->vertices[vtx_idx2].normal.z == 0)
4199                 break;
4200         }
4201         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
4202         {
4203             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
4204                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
4205                 mesh->faces[face_idx2][2] >= vtx_idx2) break;
4206         }
4207     }
4208 
4209     IDirect3DIndexBuffer9_Unlock(index_buffer);
4210     IDirect3DVertexBuffer9_Unlock(vertex_buffer);
4211     IDirect3DIndexBuffer9_Release(index_buffer);
4212     IDirect3DVertexBuffer9_Release(vertex_buffer);
4213 }
4214 
4215 static void test_createtext(IDirect3DDevice9 *device, HDC hdc, const char *text, float deviation, float extrusion)
4216 {
4217     static const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
4218     HRESULT hr;
4219     ID3DXMesh *d3dxmesh = NULL;
4220     struct mesh mesh = {0};
4221     char name[256];
4222     OUTLINETEXTMETRICA otm;
4223     GLYPHMETRICS gm;
4224     struct glyphinfo *glyphs;
4225     GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
4226     int i;
4227     LOGFONTA lf;
4228     float offset_x;
4229     size_t textlen;
4230     HFONT font = NULL, oldfont = NULL;
4231     char *raw_outline;
4232 
4233     sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion);
4234 
4235     hr = D3DXCreateTextA(device, hdc, text, deviation, extrusion, &d3dxmesh, NULL, glyphmetrics_float);
4236     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
4237 
4238     /* must select a modified font having lfHeight = otm.otmEMSquare before
4239      * calling GetGlyphOutline to get the expected values */
4240     ok(GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf), "Failed to get current DC font.\n");
4241     ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "Failed to get DC font outline.\n");
4242     lf.lfHeight = otm.otmEMSquare;
4243     lf.lfWidth = 0;
4244     ok(!!(font = CreateFontIndirectA(&lf)), "Failed to create font.\n");
4245 
4246     textlen = strlen(text);
4247     glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
4248     oldfont = SelectObject(hdc, font);
4249 
4250     for (i = 0; i < textlen; i++)
4251     {
4252         GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
4253         compare_float(glyphmetrics_float[i].gmfBlackBoxX, gm.gmBlackBoxX / (float)otm.otmEMSquare);
4254         compare_float(glyphmetrics_float[i].gmfBlackBoxY, gm.gmBlackBoxY / (float)otm.otmEMSquare);
4255         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.x, gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare);
4256         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.y, gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare);
4257         compare_float(glyphmetrics_float[i].gmfCellIncX, gm.gmCellIncX / (float)otm.otmEMSquare);
4258         compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
4259     }
4260 
4261     if (deviation == 0.0f)
4262         deviation = 1.0f / otm.otmEMSquare;
4263 
4264     offset_x = 0.0f;
4265     for (i = 0; i < textlen; i++)
4266     {
4267         DWORD datasize;
4268 
4269         glyphs[i].offset_x = offset_x;
4270 
4271         datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
4272         ok(datasize != GDI_ERROR, "Failed to retrieve GDI glyph outline size.\n");
4273         raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
4274         datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
4275         ok(datasize != GDI_ERROR, "Failed to retrieve GDI glyph outline.\n");
4276         create_outline(&glyphs[i], raw_outline, datasize, deviation, otm.otmEMSquare);
4277         HeapFree(GetProcessHeap(), 0, raw_outline);
4278 
4279         offset_x += gm.gmCellIncX / (float)otm.otmEMSquare;
4280     }
4281 
4282     SelectObject(hdc, oldfont);
4283 
4284     compute_text_mesh(&mesh, text, deviation, extrusion, otm.otmEMSquare, glyphs);
4285     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
4286 
4287     compare_text_outline_mesh(name, d3dxmesh, &mesh, textlen, extrusion, glyphs);
4288 
4289     free_mesh(&mesh);
4290     d3dxmesh->lpVtbl->Release(d3dxmesh);
4291     DeleteObject(font);
4292     HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
4293 
4294     for (i = 0; i < textlen; i++)
4295         free_glyphinfo(&glyphs[i]);
4296     HeapFree(GetProcessHeap(), 0, glyphs);
4297 }
4298 
4299 static void D3DXCreateTextTest(void)
4300 {
4301     HRESULT hr;
4302     HDC hdc;
4303     IDirect3DDevice9* device;
4304     ID3DXMesh* d3dxmesh = NULL;
4305     HFONT hFont;
4306     OUTLINETEXTMETRICA otm;
4307     int number_of_vertices;
4308     int number_of_faces;
4309     struct test_context *test_context;
4310 
4311     if (!(test_context = new_test_context()))
4312     {
4313         skip("Couldn't create test context\n");
4314         return;
4315     }
4316     device = test_context->device;
4317 
4318     hdc = CreateCompatibleDC(NULL);
4319 
4320     hFont = CreateFontA(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
4321             CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
4322     SelectObject(hdc, hFont);
4323     GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
4324 
4325     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, 0.4f, NULL, NULL, NULL);
4326     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4327 
4328     /* D3DXCreateTextA page faults from passing NULL text */
4329 
4330     hr = D3DXCreateTextW(device, hdc, NULL, 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4331     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4332 
4333     hr = D3DXCreateTextA(device, hdc, "", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4334     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4335 
4336     hr = D3DXCreateTextA(device, hdc, " ", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4337     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4338 
4339     hr = D3DXCreateTextA(NULL, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4340     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4341 
4342     hr = D3DXCreateTextA(device, NULL, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4343     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4344 
4345     hr = D3DXCreateTextA(device, hdc, "wine", -FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4346     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4347 
4348     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, -FLT_MIN, &d3dxmesh, NULL, NULL);
4349     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4350 
4351     /* deviation = 0.0f treated as if deviation = 1.0f / otm.otmEMSquare */
4352     hr = D3DXCreateTextA(device, hdc, "wine", 1.0f / otm.otmEMSquare, 0.4f, &d3dxmesh, NULL, NULL);
4353     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4354     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
4355     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
4356     d3dxmesh->lpVtbl->Release(d3dxmesh);
4357 
4358     hr = D3DXCreateTextA(device, hdc, "wine", 0.0f, 0.4f, &d3dxmesh, NULL, NULL);
4359     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4360     ok(number_of_vertices == d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh),
4361        "Got %d vertices, expected %d\n",
4362        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_vertices);
4363     ok(number_of_faces == d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh),
4364        "Got %d faces, expected %d\n",
4365        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_faces);
4366     d3dxmesh->lpVtbl->Release(d3dxmesh);
4367 
4368 if (0)
4369 {
4370     /* too much detail requested, so will appear to hang */
4371     trace("Waiting for D3DXCreateText to finish with deviation = FLT_MIN ...\n");
4372     hr = D3DXCreateTextA(device, hdc, "wine", FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4373     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4374     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4375     trace("D3DXCreateText finish with deviation = FLT_MIN\n");
4376 }
4377 
4378     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4379     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4380     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4381 
4382     test_createtext(device, hdc, "wine", FLT_MAX, 0.4f);
4383     test_createtext(device, hdc, "wine", 0.001f, FLT_MIN);
4384     test_createtext(device, hdc, "wine", 0.001f, 0.0f);
4385     test_createtext(device, hdc, "wine", 0.001f, FLT_MAX);
4386     test_createtext(device, hdc, "wine", 0.0f, 1.0f);
4387     test_createtext(device, hdc, " wine", 1.0f, 0.0f);
4388     test_createtext(device, hdc, "wine ", 1.0f, 0.0f);
4389     test_createtext(device, hdc, "wi ne", 1.0f, 0.0f);
4390 
4391     DeleteDC(hdc);
4392     DeleteObject(hFont);
4393 
4394     free_test_context(test_context);
4395 }
4396 
4397 static void test_get_decl_length(void)
4398 {
4399     static const D3DVERTEXELEMENT9 declaration1[] =
4400     {
4401         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4402         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4403         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4404         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4405         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4406         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4407         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4408         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4409         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4410         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4411         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4412         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4413         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4414         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4415         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4416         D3DDECL_END(),
4417     };
4418     static const D3DVERTEXELEMENT9 declaration2[] =
4419     {
4420         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4421         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4422         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4423         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4424         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4425         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4426         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4427         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4428         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4429         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4430         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4431         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4432         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4433         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4434         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4435         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4436         D3DDECL_END(),
4437     };
4438     UINT size;
4439 
4440     size = D3DXGetDeclLength(declaration1);
4441     ok(size == 15, "Got size %u, expected 15.\n", size);
4442 
4443     size = D3DXGetDeclLength(declaration2);
4444     ok(size == 16, "Got size %u, expected 16.\n", size);
4445 }
4446 
4447 static void test_get_decl_vertex_size(void)
4448 {
4449     static const D3DVERTEXELEMENT9 declaration1[] =
4450     {
4451         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4452         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4453         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4454         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4455         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4456         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4457         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4458         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4459         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4460         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4461         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4462         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4463         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4464         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4465         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4466         D3DDECL_END(),
4467     };
4468     static const D3DVERTEXELEMENT9 declaration2[] =
4469     {
4470         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4471         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4472         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4473         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4474         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4475         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4476         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4477         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4478         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4479         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4480         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4481         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4482         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4483         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4484         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4485         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4486         D3DDECL_END(),
4487     };
4488     static const UINT sizes1[] =
4489     {
4490         4,  8,  12, 16,
4491         4,  4,  4,  8,
4492         4,  4,  8,  4,
4493         4,  4,  8,  0,
4494     };
4495     static const UINT sizes2[] =
4496     {
4497         12, 16, 20, 24,
4498         12, 12, 16, 16,
4499     };
4500     unsigned int i;
4501     UINT size;
4502 
4503     size = D3DXGetDeclVertexSize(NULL, 0);
4504     ok(size == 0, "Got size %#x, expected 0.\n", size);
4505 
4506     for (i = 0; i < 16; ++i)
4507     {
4508         size = D3DXGetDeclVertexSize(declaration1, i);
4509         ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
4510     }
4511 
4512     for (i = 0; i < 8; ++i)
4513     {
4514         size = D3DXGetDeclVertexSize(declaration2, i);
4515         ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
4516     }
4517 }
4518 
4519 static void D3DXGenerateAdjacencyTest(void)
4520 {
4521     HRESULT hr;
4522     IDirect3DDevice9 *device;
4523     ID3DXMesh *d3dxmesh = NULL;
4524     D3DXVECTOR3 *vertices = NULL;
4525     WORD *indices = NULL;
4526     int i;
4527     struct {
4528         DWORD num_vertices;
4529         D3DXVECTOR3 vertices[6];
4530         DWORD num_faces;
4531         WORD indices[3 * 3];
4532         FLOAT epsilon;
4533         DWORD adjacency[3 * 3];
4534     } test_data[] = {
4535         { /* for epsilon < 0, indices must match for faces to be adjacent */
4536             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}},
4537             2, {0, 1, 2,  0, 2, 3},
4538             -1.0,
4539             {-1, -1, 1,  0, -1, -1},
4540         },
4541         {
4542             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}},
4543             2, {0, 1, 2,  3, 4, 5},
4544             -1.0,
4545             {-1, -1, -1,  -1, -1, -1},
4546         },
4547         { /* for epsilon == 0, indices or vertices must match for faces to be adjacent */
4548             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}},
4549             2, {0, 1, 2,  3, 4, 5},
4550             0.0,
4551             {-1, -1, 1,  0, -1, -1},
4552         },
4553         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4554             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}},
4555             2, {0, 1, 2,  3, 4, 5},
4556             0.25,
4557             {-1, -1, -1,  -1, -1, -1},
4558         },
4559         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4560             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}},
4561             2, {0, 1, 2,  3, 4, 5},
4562             0.250001,
4563             {-1, -1, 1,  0, -1, -1},
4564         },
4565         { /* length between vertices are compared to epsilon, not the individual dimension deltas */
4566             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}},
4567             2, {0, 1, 2,  3, 4, 5},
4568             0.353, /* < sqrt(0.25*0.25 + 0.25*0.25) */
4569             {-1, -1, -1,  -1, -1, -1},
4570         },
4571         {
4572             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}},
4573             2, {0, 1, 2,  3, 4, 5},
4574             0.354, /* > sqrt(0.25*0.25 + 0.25*0.25) */
4575             {-1, -1, 1,  0, -1, -1},
4576         },
4577         { /* adjacent faces must have opposite winding orders at the shared edge */
4578             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}},
4579             2, {0, 1, 2,  0, 3, 2},
4580             0.0,
4581             {-1, -1, -1,  -1, -1, -1},
4582         },
4583     };
4584     struct test_context *test_context;
4585 
4586     if (!(test_context = new_test_context()))
4587     {
4588         skip("Couldn't create test context\n");
4589         return;
4590     }
4591     device = test_context->device;
4592 
4593     for (i = 0; i < ARRAY_SIZE(test_data); i++)
4594     {
4595         DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
4596         int j;
4597 
4598         if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4599         d3dxmesh = NULL;
4600 
4601         hr = D3DXCreateMeshFVF(test_data[i].num_faces, test_data[i].num_vertices, 0, D3DFVF_XYZ, device, &d3dxmesh);
4602         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4603 
4604         hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&vertices);
4605         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4606         if (FAILED(hr)) continue;
4607         CopyMemory(vertices, test_data[i].vertices, test_data[i].num_vertices * sizeof(test_data[0].vertices[0]));
4608         d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
4609 
4610         hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&indices);
4611         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4612         if (FAILED(hr)) continue;
4613         CopyMemory(indices, test_data[i].indices, test_data[i].num_faces * 3 * sizeof(test_data[0].indices[0]));
4614         d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
4615 
4616         if (i == 0) {
4617             hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, NULL);
4618             ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4619         }
4620 
4621         hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, test_data[i].epsilon, adjacency);
4622         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4623         if (FAILED(hr)) continue;
4624 
4625         for (j = 0; j < test_data[i].num_faces * 3; j++)
4626             ok(adjacency[j] == test_data[i].adjacency[j],
4627                "Test %d adjacency %d: Got result %u, expected %u\n", i, j,
4628                adjacency[j], test_data[i].adjacency[j]);
4629     }
4630     if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4631 
4632     free_test_context(test_context);
4633 }
4634 
4635 static void test_update_semantics(void)
4636 {
4637     HRESULT hr;
4638     struct test_context *test_context = NULL;
4639     ID3DXMesh *mesh = NULL;
4640     D3DVERTEXELEMENT9 declaration0[] =
4641     {
4642          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4643          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4644          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4645          D3DDECL_END()
4646     };
4647     D3DVERTEXELEMENT9 declaration_pos_type_color[] =
4648     {
4649          {0, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4650          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4651          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4652          D3DDECL_END()
4653     };
4654     D3DVERTEXELEMENT9 declaration_smaller[] =
4655     {
4656          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4657          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4658          D3DDECL_END()
4659     };
4660     D3DVERTEXELEMENT9 declaration_larger[] =
4661     {
4662          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4663          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4664          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4665          {0, 40, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4666          D3DDECL_END()
4667     };
4668     D3DVERTEXELEMENT9 declaration_multiple_streams[] =
4669     {
4670          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4671          {1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4672          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4673          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4674 
4675          D3DDECL_END()
4676     };
4677     D3DVERTEXELEMENT9 declaration_double_usage[] =
4678     {
4679          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4680          {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4681          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4682          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4683          D3DDECL_END()
4684     };
4685     D3DVERTEXELEMENT9 declaration_undefined_type[] =
4686     {
4687          {0, 0, D3DDECLTYPE_UNUSED+1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4688          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4689          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4690          D3DDECL_END()
4691     };
4692     D3DVERTEXELEMENT9 declaration_not_4_byte_aligned_offset[] =
4693     {
4694          {0, 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4695          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4696          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4697          D3DDECL_END()
4698     };
4699     static const struct
4700     {
4701         D3DXVECTOR3 position0;
4702         D3DXVECTOR3 position1;
4703         D3DXVECTOR3 normal;
4704         DWORD color;
4705     }
4706     vertices[] =
4707     {
4708         { { 0.0f,  1.0f,  0.f}, { 1.0f,  0.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xffff0000 },
4709         { { 1.0f, -1.0f,  0.f}, {-1.0f, -1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff00ff00 },
4710         { {-1.0f, -1.0f,  0.f}, {-1.0f,  1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff0000ff },
4711     };
4712     unsigned int faces[] = {0, 1, 2};
4713     unsigned int attributes[] = {0};
4714     unsigned int num_faces = ARRAY_SIZE(faces) / 3;
4715     unsigned int num_vertices = ARRAY_SIZE(vertices);
4716     int offset = sizeof(D3DXVECTOR3);
4717     DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4718     void *vertex_buffer;
4719     void *index_buffer;
4720     DWORD *attributes_buffer;
4721     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
4722     D3DVERTEXELEMENT9 *decl_ptr;
4723     DWORD exp_vertex_size = sizeof(*vertices);
4724     DWORD vertex_size = 0;
4725     int equal;
4726     int i = 0;
4727     int *decl_mem;
4728     int filler_a = 0xaaaaaaaa;
4729     int filler_b = 0xbbbbbbbb;
4730 
4731     test_context = new_test_context();
4732     if (!test_context)
4733     {
4734         skip("Couldn't create a test_context\n");
4735         goto cleanup;
4736     }
4737 
4738     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration0,
4739                         test_context->device, &mesh);
4740     if (FAILED(hr))
4741     {
4742         skip("Couldn't create test mesh %#x\n", hr);
4743         goto cleanup;
4744     }
4745 
4746     mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
4747     memcpy(vertex_buffer, vertices, sizeof(vertices));
4748     mesh->lpVtbl->UnlockVertexBuffer(mesh);
4749 
4750     mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
4751     memcpy(index_buffer, faces, sizeof(faces));
4752     mesh->lpVtbl->UnlockIndexBuffer(mesh);
4753 
4754     mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
4755     memcpy(attributes_buffer, attributes, sizeof(attributes));
4756     mesh->lpVtbl->UnlockAttributeBuffer(mesh);
4757 
4758     /* Get the declaration and try to change it */
4759     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4760     if (FAILED(hr))
4761     {
4762         skip("Couldn't get vertex declaration %#x\n", hr);
4763         goto cleanup;
4764     }
4765     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4766     ok(equal == 0, "Vertex declarations were not equal\n");
4767 
4768     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4769     {
4770         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4771         {
4772             /* Use second vertex position instead of first */
4773             decl_ptr->Offset = offset;
4774         }
4775     }
4776 
4777     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4778     ok(hr == D3D_OK, "Test UpdateSemantics, got %#x expected %#x\n", hr, D3D_OK);
4779 
4780     /* Check that declaration was written by getting it again */
4781     memset(declaration, 0, sizeof(declaration));
4782     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4783     if (FAILED(hr))
4784     {
4785         skip("Couldn't get vertex declaration %#x\n", hr);
4786         goto cleanup;
4787     }
4788 
4789     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4790     {
4791         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4792         {
4793             ok(decl_ptr->Offset == offset, "Test UpdateSemantics, got offset %d expected %d\n",
4794                decl_ptr->Offset, offset);
4795         }
4796     }
4797 
4798     /* Check that GetDeclaration only writes up to the D3DDECL_END() marker and
4799      * not the full MAX_FVF_DECL_SIZE elements.
4800      */
4801     memset(declaration, filler_a, sizeof(declaration));
4802     memcpy(declaration, declaration0, sizeof(declaration0));
4803     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4804     ok(hr == D3D_OK, "Test UpdateSemantics, "
4805        "got %#x expected D3D_OK\n", hr);
4806     memset(declaration, filler_b, sizeof(declaration));
4807     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4808     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4809     decl_mem = (int*)declaration;
4810     for (i = sizeof(declaration0)/sizeof(*decl_mem); i < sizeof(declaration)/sizeof(*decl_mem); i++)
4811     {
4812         equal = memcmp(&decl_mem[i], &filler_b, sizeof(filler_b));
4813         ok(equal == 0,
4814            "GetDeclaration wrote past the D3DDECL_END() marker. "
4815            "Got %#x, expected  %#x\n", decl_mem[i], filler_b);
4816         if (equal != 0) break;
4817     }
4818 
4819     /* UpdateSemantics does not check for overlapping fields */
4820     memset(declaration, 0, sizeof(declaration));
4821     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4822     if (FAILED(hr))
4823     {
4824         skip("Couldn't get vertex declaration %#x\n", hr);
4825         goto cleanup;
4826     }
4827 
4828     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4829     {
4830         if (decl_ptr->Type == D3DDECLTYPE_FLOAT3)
4831         {
4832             decl_ptr->Type = D3DDECLTYPE_FLOAT4;
4833         }
4834     }
4835 
4836     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4837     ok(hr == D3D_OK, "Test UpdateSemantics for overlapping fields, "
4838        "got %#x expected D3D_OK\n", hr);
4839 
4840     /* Set the position type to color instead of float3 */
4841     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_pos_type_color);
4842     ok(hr == D3D_OK, "Test UpdateSemantics position type color, "
4843        "got %#x expected D3D_OK\n", hr);
4844 
4845     /* The following test cases show that NULL, smaller or larger declarations,
4846      * and declarations with non-zero Stream values are not accepted.
4847      * UpdateSemantics returns D3DERR_INVALIDCALL and the previously set
4848      * declaration will be used by DrawSubset, GetNumBytesPerVertex, and
4849      * GetDeclaration.
4850      */
4851 
4852     /* Null declaration (invalid declaration) */
4853     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4854     hr = mesh->lpVtbl->UpdateSemantics(mesh, NULL);
4855     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics null pointer declaration, "
4856        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4857     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4858     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4859        vertex_size, exp_vertex_size);
4860     memset(declaration, 0, sizeof(declaration));
4861     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4862     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4863     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4864     ok(equal == 0, "Vertex declarations were not equal\n");
4865 
4866     /* Smaller vertex declaration (invalid declaration) */
4867     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4868     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_smaller);
4869     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics for smaller vertex declaration, "
4870        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4871     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4872     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4873        vertex_size, exp_vertex_size);
4874     memset(declaration, 0, sizeof(declaration));
4875     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4876     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4877     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4878     ok(equal == 0, "Vertex declarations were not equal\n");
4879 
4880     /* Larger vertex declaration (invalid declaration) */
4881     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4882     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_larger);
4883     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics for larger vertex declaration, "
4884        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4885     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4886     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4887        vertex_size, exp_vertex_size);
4888     memset(declaration, 0, sizeof(declaration));
4889     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4890     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4891     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4892     ok(equal == 0, "Vertex declarations were not equal\n");
4893 
4894     /* Use multiple streams and keep the same vertex size (invalid declaration) */
4895     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4896     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_multiple_streams);
4897     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics using multiple streams, "
4898                  "got %#x expected D3DERR_INVALIDCALL\n", hr);
4899     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4900     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4901        vertex_size, exp_vertex_size);
4902     memset(declaration, 0, sizeof(declaration));
4903     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4904     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4905     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4906     ok(equal == 0, "Vertex declarations were not equal\n");
4907 
4908     /* The next following test cases show that some invalid declarations are
4909      * accepted with a D3D_OK. An access violation is thrown on Windows if
4910      * DrawSubset is called. The methods GetNumBytesPerVertex and GetDeclaration
4911      * are not affected, which indicates that the declaration is cached.
4912      */
4913 
4914     /* Double usage (invalid declaration) */
4915     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4916     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_double_usage);
4917     ok(hr == D3D_OK, "Test UpdateSemantics double usage, "
4918        "got %#x expected D3D_OK\n", hr);
4919     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4920     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4921        vertex_size, exp_vertex_size);
4922     memset(declaration, 0, sizeof(declaration));
4923     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4924     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4925     equal = memcmp(declaration, declaration_double_usage, sizeof(declaration_double_usage));
4926     ok(equal == 0, "Vertex declarations were not equal\n");
4927 
4928     /* Set the position to an undefined type (invalid declaration) */
4929     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4930     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_undefined_type);
4931     ok(hr == D3D_OK, "Test UpdateSemantics undefined type, "
4932        "got %#x expected D3D_OK\n", hr);
4933     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4934     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4935        vertex_size, exp_vertex_size);
4936     memset(declaration, 0, sizeof(declaration));
4937     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4938     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4939     equal = memcmp(declaration, declaration_undefined_type, sizeof(declaration_undefined_type));
4940     ok(equal == 0, "Vertex declarations were not equal\n");
4941 
4942     /* Use a not 4 byte aligned offset (invalid declaration) */
4943     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4944     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_not_4_byte_aligned_offset);
4945     ok(hr == D3D_OK, "Test UpdateSemantics not 4 byte aligned offset, "
4946        "got %#x expected D3D_OK\n", hr);
4947     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4948     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4949        vertex_size, exp_vertex_size);
4950     memset(declaration, 0, sizeof(declaration));
4951     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4952     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4953     equal = memcmp(declaration, declaration_not_4_byte_aligned_offset,
4954                    sizeof(declaration_not_4_byte_aligned_offset));
4955     ok(equal == 0, "Vertex declarations were not equal\n");
4956 
4957 cleanup:
4958     if (mesh)
4959         mesh->lpVtbl->Release(mesh);
4960 
4961     free_test_context(test_context);
4962 }
4963 
4964 static void test_create_skin_info(void)
4965 {
4966     HRESULT hr;
4967     ID3DXSkinInfo *skininfo = NULL;
4968     D3DVERTEXELEMENT9 empty_declaration[] = { D3DDECL_END() };
4969     D3DVERTEXELEMENT9 declaration_out[MAX_FVF_DECL_SIZE];
4970     const D3DVERTEXELEMENT9 declaration_with_nonzero_stream[] = {
4971         {1, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
4972         D3DDECL_END()
4973     };
4974 
4975     hr = D3DXCreateSkinInfo(0, empty_declaration, 0, &skininfo);
4976     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4977     if (skininfo) IUnknown_Release(skininfo);
4978     skininfo = NULL;
4979 
4980     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
4981     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4982 
4983     hr = D3DXCreateSkinInfo(1, declaration_with_nonzero_stream, 1, &skininfo);
4984     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4985 
4986     hr = D3DXCreateSkinInfoFVF(1, 0, 1, &skininfo);
4987     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4988     if (skininfo)
4989     {
4990         DWORD dword_result;
4991         float flt_result;
4992         const char *string_result;
4993         D3DXMATRIX *transform;
4994         D3DXMATRIX identity_matrix;
4995 
4996         /* test initial values */
4997         hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4998         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4999         if (SUCCEEDED(hr))
5000             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
5001 
5002         dword_result = skininfo->lpVtbl->GetNumBones(skininfo);
5003         ok(dword_result == 1, "Expected 1, got %u\n", dword_result);
5004 
5005         flt_result = skininfo->lpVtbl->GetMinBoneInfluence(skininfo);
5006         ok(flt_result == 0.0f, "Expected 0.0, got %g\n", flt_result);
5007 
5008         string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5009         ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
5010 
5011         dword_result = skininfo->lpVtbl->GetFVF(skininfo);
5012         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5013 
5014         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 0);
5015         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5016 
5017         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 1);
5018         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5019 
5020         transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, -1);
5021         ok(transform == NULL, "Expected NULL, got %p\n", transform);
5022 
5023         {
5024             /* test [GS]etBoneOffsetMatrix */
5025             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 1, &identity_matrix);
5026             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5027 
5028             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, NULL);
5029             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5030 
5031             D3DXMatrixIdentity(&identity_matrix);
5032             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, &identity_matrix);
5033             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5034 
5035             transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, 0);
5036             check_matrix(transform, &identity_matrix);
5037         }
5038 
5039         {
5040             /* test [GS]etBoneName */
5041             const char *name_in = "testBoneName";
5042             const char *string_result2;
5043 
5044             hr = skininfo->lpVtbl->SetBoneName(skininfo, 1, name_in);
5045             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5046 
5047             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, NULL);
5048             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5049 
5050             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, name_in);
5051             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5052 
5053             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5054             ok(string_result != NULL, "Expected non-NULL string, got %p\n", string_result);
5055             ok(!strcmp(string_result, name_in), "Expected '%s', got '%s'\n", name_in, string_result);
5056 
5057             string_result2 = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5058             ok(string_result == string_result2, "Expected %p, got %p\n", string_result, string_result2);
5059 
5060             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 1);
5061             ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
5062         }
5063 
5064         {
5065             /* test [GS]etBoneInfluence */
5066             DWORD vertices[2];
5067             FLOAT weights[2];
5068             int i;
5069             DWORD num_influences;
5070             DWORD exp_vertices[2];
5071             FLOAT exp_weights[2];
5072 
5073             /* vertex and weight arrays untouched when num_influences is 0 */
5074             vertices[0] = 0xdeadbeef;
5075             weights[0] = FLT_MAX;
5076             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5077             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5078             ok(vertices[0] == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", vertices[0]);
5079             ok(weights[0] == FLT_MAX, "expected %g, got %g\n", FLT_MAX, weights[0]);
5080 
5081             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 1, vertices, weights);
5082             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5083 
5084             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, NULL);
5085             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5086 
5087             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, NULL);
5088             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5089 
5090             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, weights);
5091             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5092 
5093 
5094             /* no vertex or weight value checking */
5095             exp_vertices[0] = 0;
5096             exp_vertices[1] = 0x87654321;
5097             exp_weights[0] = 0.5;
5098             exp_weights[1] = NAN;
5099             num_influences = 2;
5100 
5101             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 1, num_influences, vertices, weights);
5102             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5103 
5104             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, weights);
5105             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5106 
5107             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, vertices, NULL);
5108             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5109 
5110             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, NULL);
5111             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5112 
5113             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, exp_vertices, exp_weights);
5114             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5115 
5116             memset(vertices, 0, sizeof(vertices));
5117             memset(weights, 0, sizeof(weights));
5118             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5119             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5120             for (i = 0; i < num_influences; i++) {
5121                 ok(exp_vertices[i] == vertices[i],
5122                    "influence[%d]: expected vertex %u, got %u\n", i, exp_vertices[i], vertices[i]);
5123                 ok((isnan(exp_weights[i]) && isnan(weights[i])) || exp_weights[i] == weights[i],
5124                    "influence[%d]: expected weights %g, got %g\n", i, exp_weights[i], weights[i]);
5125             }
5126 
5127             /* vertices and weights aren't returned after setting num_influences to 0 */
5128             memset(vertices, 0, sizeof(vertices));
5129             memset(weights, 0, sizeof(weights));
5130             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, 0, vertices, weights);
5131             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5132 
5133             vertices[0] = 0xdeadbeef;
5134             weights[0] = FLT_MAX;
5135             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5136             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5137             ok(vertices[0] == 0xdeadbeef, "expected vertex 0xdeadbeef, got %u\n", vertices[0]);
5138             ok(weights[0] == FLT_MAX, "expected weight %g, got %g\n", FLT_MAX, weights[0]);
5139         }
5140 
5141         {
5142             /* test [GS]etFVF and [GS]etDeclaration */
5143             D3DVERTEXELEMENT9 declaration_in[MAX_FVF_DECL_SIZE];
5144             DWORD fvf = D3DFVF_XYZ;
5145             DWORD got_fvf;
5146 
5147             hr = skininfo->lpVtbl->SetDeclaration(skininfo, NULL);
5148             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5149 
5150             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_with_nonzero_stream);
5151             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5152 
5153             hr = skininfo->lpVtbl->SetFVF(skininfo, 0);
5154             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5155 
5156             hr = D3DXDeclaratorFromFVF(fvf, declaration_in);
5157             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5158             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_in);
5159             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5160             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5161             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
5162             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5163             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5164             compare_elements(declaration_out, declaration_in, __LINE__, 0);
5165 
5166             hr = skininfo->lpVtbl->SetDeclaration(skininfo, empty_declaration);
5167             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5168             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5169             ok(got_fvf == 0, "Expected 0, got %#x\n", got_fvf);
5170             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5171             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5172             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
5173 
5174             hr = skininfo->lpVtbl->SetFVF(skininfo, fvf);
5175             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5176             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5177             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
5178             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5179             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5180             compare_elements(declaration_out, declaration_in, __LINE__, 0);
5181         }
5182     }
5183     if (skininfo) IUnknown_Release(skininfo);
5184     skininfo = NULL;
5185 
5186     hr = D3DXCreateSkinInfoFVF(1, D3DFVF_XYZ, 1, NULL);
5187     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5188 
5189     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
5190     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5191 }
5192 
5193 static void test_convert_adjacency_to_point_reps(void)
5194 {
5195     HRESULT hr;
5196     struct test_context *test_context = NULL;
5197     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5198     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5199     const D3DVERTEXELEMENT9 declaration[] =
5200     {
5201         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5202         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5203         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5204         D3DDECL_END()
5205     };
5206     const unsigned int VERTS_PER_FACE = 3;
5207     void *vertex_buffer;
5208     void *index_buffer;
5209     DWORD *attributes_buffer;
5210     int i, j;
5211     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5212     struct vertex_pnc
5213     {
5214         D3DXVECTOR3 position;
5215         D3DXVECTOR3 normal;
5216         enum color color; /* In case of manual visual inspection */
5217     };
5218 #ifndef __REACTOS__
5219     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5220 #else
5221 #define up {0.0f, 0.0f, 1.0f}
5222 #endif
5223     /* mesh0 (one face)
5224      *
5225      * 0--1
5226      * | /
5227      * |/
5228      * 2
5229      */
5230     const struct vertex_pnc vertices0[] =
5231     {
5232         {{ 0.0f,  3.0f,  0.f}, up, RED},
5233         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5234         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5235     };
5236     const DWORD indices0[] = {0, 1, 2};
5237     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5238     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
5239     const DWORD adjacency0[] = {-1, -1, -1};
5240     const DWORD exp_point_rep0[] = {0, 1, 2};
5241     /* mesh1 (right)
5242      *
5243      * 0--1 3
5244      * | / /|
5245      * |/ / |
5246      * 2 5--4
5247      */
5248     const struct vertex_pnc vertices1[] =
5249     {
5250         {{ 0.0f,  3.0f,  0.f}, up, RED},
5251         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5252         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5253 
5254         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5255         {{ 3.0f,  0.0f,  0.f}, up, RED},
5256         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5257     };
5258     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5259     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5260     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
5261     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
5262     const DWORD exp_point_rep1[] = {0, 1, 2, 1, 4, 2};
5263     /* mesh2 (left)
5264      *
5265      *    3 0--1
5266      *   /| | /
5267      *  / | |/
5268      * 5--4 2
5269      */
5270     const struct vertex_pnc vertices2[] =
5271     {
5272         {{ 0.0f,  3.0f,  0.f}, up, RED},
5273         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5274         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5275 
5276         {{-1.0f,  3.0f,  0.f}, up, RED},
5277         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5278         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5279     };
5280     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5281     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5282     const unsigned int num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
5283     const DWORD adjacency2[] = {-1, -1, 1, 0, -1, -1};
5284     const DWORD exp_point_rep2[] = {0, 1, 2, 0, 2, 5};
5285     /* mesh3 (above)
5286      *
5287      *    3
5288      *   /|
5289      *  / |
5290      * 5--4
5291      * 0--1
5292      * | /
5293      * |/
5294      * 2
5295      */
5296     struct vertex_pnc vertices3[] =
5297     {
5298         {{ 0.0f,  3.0f,  0.f}, up, RED},
5299         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5300         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5301 
5302         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5303         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5304         {{ 0.0f,  4.0f,  0.f}, up, RED},
5305     };
5306     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5307     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5308     const unsigned int num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
5309     const DWORD adjacency3[] = {1, -1, -1, -1, 0, -1};
5310     const DWORD exp_point_rep3[] = {0, 1, 2, 3, 1, 0};
5311     /* mesh4 (below, tip against tip)
5312      *
5313      * 0--1
5314      * | /
5315      * |/
5316      * 2
5317      * 3
5318      * |\
5319      * | \
5320      * 5--4
5321      */
5322     struct vertex_pnc vertices4[] =
5323     {
5324         {{ 0.0f,  3.0f,  0.f}, up, RED},
5325         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5326         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5327 
5328         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5329         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5330         {{ 0.0f, -7.0f,  0.f}, up, RED},
5331     };
5332     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5333     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5334     const unsigned int num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
5335     const DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
5336     const DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
5337     /* mesh5 (gap in mesh)
5338      *
5339      *    0      3-----4  15
5340      *   / \      \   /  /  \
5341      *  /   \      \ /  /    \
5342      * 2-----1      5 17-----16
5343      * 6-----7      9 12-----13
5344      *  \   /      / \  \    /
5345      *   \ /      /   \  \  /
5346      *    8     10-----11 14
5347      *
5348      */
5349     const struct vertex_pnc vertices5[] =
5350     {
5351         {{ 0.0f,  1.0f,  0.f}, up, RED},
5352         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5353         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5354 
5355         {{ 0.1f,  1.0f,  0.f}, up, RED},
5356         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5357         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5358 
5359         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5360         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5361         {{ 0.0f, -3.1f,  0.f}, up, RED},
5362 
5363         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5364         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5365         {{ 0.1f, -3.1f,  0.f}, up, RED},
5366 
5367         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5368         {{ 3.2f, -1.1f,  0.f}, up, RED},
5369         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5370 
5371         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5372         {{ 3.2f, -1.0f,  0.f}, up, RED},
5373         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5374     };
5375     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5376     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5377     const unsigned int num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
5378     const DWORD adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5379     const DWORD exp_point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5380     const WORD indices5_16bit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5381     /* mesh6 (indices re-ordering)
5382      *
5383      * 0--1 6 3
5384      * | / /| |\
5385      * |/ / | | \
5386      * 2 8--7 5--4
5387      */
5388     const struct vertex_pnc vertices6[] =
5389     {
5390         {{ 0.0f,  3.0f,  0.f}, up, RED},
5391         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5392         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5393 
5394         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5395         {{ 3.0f,  0.0f,  0.f}, up, RED},
5396         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5397 
5398         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5399         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5400         {{ 4.0f,  0.0f,  0.f}, up, RED},
5401     };
5402     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5403     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5404     const unsigned int num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
5405     const DWORD adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5406     const DWORD exp_point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5407     /* mesh7 (expands collapsed triangle)
5408      *
5409      * 0--1 3
5410      * | / /|
5411      * |/ / |
5412      * 2 5--4
5413      */
5414     const struct vertex_pnc vertices7[] =
5415     {
5416         {{ 0.0f,  3.0f,  0.f}, up, RED},
5417         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5418         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5419 
5420         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5421         {{ 3.0f,  0.0f,  0.f}, up, RED},
5422         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5423     };
5424     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5425     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5426     const unsigned int num_faces7 = ARRAY_SIZE(indices7) / VERTS_PER_FACE;
5427     const DWORD adjacency7[] = {-1, -1, -1, -1, -1, -1};
5428     const DWORD exp_point_rep7[] = {0, 1, 2, 3, 4, 5};
5429     /* mesh8 (indices re-ordering and double replacement)
5430      *
5431      * 0--1 9  6
5432      * | / /|  |\
5433      * |/ / |  | \
5434      * 2 11-10 8--7
5435      *         3--4
5436      *         | /
5437      *         |/
5438      *         5
5439      */
5440     const struct vertex_pnc vertices8[] =
5441     {
5442         {{ 0.0f,  3.0f,  0.f}, up, RED},
5443         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5444         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5445 
5446         {{ 4.0,  -4.0,  0.f}, up, RED},
5447         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5448         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5449 
5450         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5451         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5452         {{ 4.0f,  0.0f,  0.f}, up, RED},
5453 
5454         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5455         {{ 3.0f,  0.0f,  0.f}, up, RED},
5456         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5457     };
5458     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5459     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5460     const unsigned int num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
5461     const DWORD adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5462     const DWORD exp_point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5463     /* mesh9 (right, shared vertices)
5464      *
5465      * 0--1
5466      * | /|
5467      * |/ |
5468      * 2--3
5469      */
5470     const struct vertex_pnc vertices9[] =
5471     {
5472         {{ 0.0f,  3.0f,  0.f}, up, RED},
5473         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5474         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5475 
5476         {{ 2.0f,  0.0f,  0.f}, up, RED},
5477     };
5478     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5479     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5480     const unsigned int num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
5481     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
5482     const DWORD exp_point_rep9[] = {0, 1, 2, 3};
5483     /* All mesh data */
5484     ID3DXMesh *mesh = NULL;
5485     ID3DXMesh *mesh_null_check = NULL;
5486     unsigned int attributes[] = {0};
5487     struct
5488     {
5489         const struct vertex_pnc *vertices;
5490         const DWORD *indices;
5491         const DWORD num_vertices;
5492         const DWORD num_faces;
5493         const DWORD *adjacency;
5494         const DWORD *exp_point_reps;
5495         const DWORD options;
5496     }
5497     tc[] =
5498     {
5499         {
5500             vertices0,
5501             indices0,
5502             num_vertices0,
5503             num_faces0,
5504             adjacency0,
5505             exp_point_rep0,
5506             options
5507         },
5508         {
5509             vertices1,
5510             indices1,
5511             num_vertices1,
5512             num_faces1,
5513             adjacency1,
5514             exp_point_rep1,
5515             options
5516         },
5517         {
5518             vertices2,
5519             indices2,
5520             num_vertices2,
5521             num_faces2,
5522             adjacency2,
5523             exp_point_rep2,
5524             options
5525         },
5526         {
5527             vertices3,
5528             indices3,
5529             num_vertices3,
5530             num_faces3,
5531             adjacency3,
5532             exp_point_rep3,
5533             options
5534         },
5535         {
5536             vertices4,
5537             indices4,
5538             num_vertices4,
5539             num_faces4,
5540             adjacency4,
5541             exp_point_rep4,
5542             options
5543         },
5544         {
5545             vertices5,
5546             indices5,
5547             num_vertices5,
5548             num_faces5,
5549             adjacency5,
5550             exp_point_rep5,
5551             options
5552         },
5553         {
5554             vertices6,
5555             indices6,
5556             num_vertices6,
5557             num_faces6,
5558             adjacency6,
5559             exp_point_rep6,
5560             options
5561         },
5562         {
5563             vertices7,
5564             indices7,
5565             num_vertices7,
5566             num_faces7,
5567             adjacency7,
5568             exp_point_rep7,
5569             options
5570         },
5571         {
5572             vertices8,
5573             indices8,
5574             num_vertices8,
5575             num_faces8,
5576             adjacency8,
5577             exp_point_rep8,
5578             options
5579         },
5580         {
5581             vertices9,
5582             indices9,
5583             num_vertices9,
5584             num_faces9,
5585             adjacency9,
5586             exp_point_rep9,
5587             options
5588         },
5589         {
5590             vertices5,
5591             (DWORD*)indices5_16bit,
5592             num_vertices5,
5593             num_faces5,
5594             adjacency5,
5595             exp_point_rep5,
5596             options_16bit
5597         },
5598     };
5599     DWORD *point_reps = NULL;
5600 
5601     test_context = new_test_context();
5602     if (!test_context)
5603     {
5604         skip("Couldn't create test context\n");
5605         goto cleanup;
5606     }
5607 
5608     for (i = 0; i < ARRAY_SIZE(tc); i++)
5609     {
5610         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options, declaration,
5611                             test_context->device, &mesh);
5612         if (FAILED(hr))
5613         {
5614             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5615             goto cleanup;
5616         }
5617 
5618         if (i == 0) /* Save first mesh for later NULL checks */
5619             mesh_null_check = mesh;
5620 
5621         point_reps = HeapAlloc(GetProcessHeap(), 0, tc[i].num_vertices * sizeof(*point_reps));
5622         if (!point_reps)
5623         {
5624             skip("Couldn't allocate point reps array.\n");
5625             goto cleanup;
5626         }
5627 
5628         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5629         if (FAILED(hr))
5630         {
5631             skip("Couldn't lock vertex buffer.\n");
5632             goto cleanup;
5633         }
5634         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5635         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5636         if (FAILED(hr))
5637         {
5638             skip("Couldn't unlock vertex buffer.\n");
5639             goto cleanup;
5640         }
5641 
5642         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5643         if (FAILED(hr))
5644         {
5645             skip("Couldn't lock index buffer.\n");
5646             goto cleanup;
5647         }
5648         if (tc[i].options & D3DXMESH_32BIT)
5649         {
5650             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5651         }
5652         else
5653         {
5654             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5655         }
5656         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5657         if (FAILED(hr)) {
5658             skip("Couldn't unlock index buffer.\n");
5659             goto cleanup;
5660         }
5661 
5662         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5663         if (FAILED(hr))
5664         {
5665             skip("Couldn't lock attributes buffer.\n");
5666             goto cleanup;
5667         }
5668         memcpy(attributes_buffer, attributes, sizeof(attributes));
5669         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5670         if (FAILED(hr))
5671         {
5672             skip("Couldn't unlock attributes buffer.\n");
5673             goto cleanup;
5674         }
5675 
5676         /* Convert adjacency to point representation */
5677         for (j = 0; j < tc[i].num_vertices; j++) point_reps[j] = -1;
5678         hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacency, point_reps);
5679         ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
5680            "Got %x expected D3D_OK\n", i, hr);
5681 
5682         /* Check point representation */
5683         for (j = 0; j < tc[i].num_vertices; j++)
5684         {
5685             ok(point_reps[j] == tc[i].exp_point_reps[j],
5686                "Unexpected point representation at (%d, %d)."
5687                " Got %d expected %d\n",
5688                i, j, point_reps[j], tc[i].exp_point_reps[j]);
5689         }
5690 
5691         HeapFree(GetProcessHeap(), 0, point_reps);
5692         point_reps = NULL;
5693 
5694         if (i != 0) /* First mesh will be freed during cleanup */
5695             mesh->lpVtbl->Release(mesh);
5696     }
5697 
5698     /* NULL checks */
5699     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacency, NULL);
5700     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
5701        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5702     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, NULL);
5703     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. "
5704        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5705 
5706 cleanup:
5707     if (mesh_null_check)
5708         mesh_null_check->lpVtbl->Release(mesh_null_check);
5709     HeapFree(GetProcessHeap(), 0, point_reps);
5710     free_test_context(test_context);
5711 #ifdef __REACTOS__
5712 #undef up
5713 #endif
5714 }
5715 
5716 static void test_convert_point_reps_to_adjacency(void)
5717 {
5718     HRESULT hr;
5719     struct test_context *test_context = NULL;
5720     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5721     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5722     const D3DVERTEXELEMENT9 declaration[] =
5723     {
5724         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5725         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5726         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5727         D3DDECL_END()
5728     };
5729     const unsigned int VERTS_PER_FACE = 3;
5730     void *vertex_buffer;
5731     void *index_buffer;
5732     DWORD *attributes_buffer;
5733     int i, j;
5734     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5735     struct vertex_pnc
5736     {
5737         D3DXVECTOR3 position;
5738         D3DXVECTOR3 normal;
5739         enum color color; /* In case of manual visual inspection */
5740     };
5741 #ifndef __REACTOS__
5742     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5743 #else
5744 #define up {0.0f, 0.0f, 1.0f}
5745 #endif
5746 
5747     /* mesh0 (one face)
5748      *
5749      * 0--1
5750      * | /
5751      * |/
5752      * 2
5753      */
5754     const struct vertex_pnc vertices0[] =
5755     {
5756         {{ 0.0f,  3.0f,  0.f}, up, RED},
5757         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5758         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5759     };
5760     const DWORD indices0[] = {0, 1, 2};
5761     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5762     const unsigned int num_faces0 = num_vertices0 / VERTS_PER_FACE;
5763     const DWORD exp_adjacency0[] = {-1, -1, -1};
5764     const DWORD exp_id_adjacency0[] = {-1, -1, -1};
5765     const DWORD point_rep0[] = {0, 1, 2};
5766     /* mesh1 (right)
5767      *
5768      * 0--1 3
5769      * | / /|
5770      * |/ / |
5771      * 2 5--4
5772      */
5773     const struct vertex_pnc vertices1[] =
5774     {
5775         {{ 0.0f,  3.0f,  0.f}, up, RED},
5776         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5777         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5778 
5779         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5780         {{ 3.0f,  0.0f,  0.f}, up, RED},
5781         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5782     };
5783     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5784     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5785     const unsigned int num_faces1 = num_vertices1 / VERTS_PER_FACE;
5786     const DWORD exp_adjacency1[] = {-1, 1, -1, -1, -1, 0};
5787     const DWORD exp_id_adjacency1[] = {-1, -1, -1, -1, -1, -1};
5788     const DWORD point_rep1[] = {0, 1, 2, 1, 4, 2};
5789     /* mesh2 (left)
5790      *
5791      *    3 0--1
5792      *   /| | /
5793      *  / | |/
5794      * 5--4 2
5795      */
5796     const struct vertex_pnc vertices2[] =
5797     {
5798         {{ 0.0f,  3.0f,  0.f}, up, RED},
5799         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5800         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5801 
5802         {{-1.0f,  3.0f,  0.f}, up, RED},
5803         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5804         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5805     };
5806     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5807     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5808     const unsigned int num_faces2 = num_vertices2 / VERTS_PER_FACE;
5809     const DWORD exp_adjacency2[] = {-1, -1, 1, 0, -1, -1};
5810     const DWORD exp_id_adjacency2[] = {-1, -1, -1, -1, -1, -1};
5811     const DWORD point_rep2[] = {0, 1, 2, 0, 2, 5};
5812     /* mesh3 (above)
5813      *
5814      *    3
5815      *   /|
5816      *  / |
5817      * 5--4
5818      * 0--1
5819      * | /
5820      * |/
5821      * 2
5822      */
5823     struct vertex_pnc vertices3[] =
5824     {
5825         {{ 0.0f,  3.0f,  0.f}, up, RED},
5826         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5827         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5828 
5829         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5830         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5831         {{ 0.0f,  4.0f,  0.f}, up, RED},
5832     };
5833     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5834     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5835     const unsigned int num_faces3 = num_vertices3 / VERTS_PER_FACE;
5836     const DWORD exp_adjacency3[] = {1, -1, -1, -1, 0, -1};
5837     const DWORD exp_id_adjacency3[] = {-1, -1, -1, -1, -1, -1};
5838     const DWORD point_rep3[] = {0, 1, 2, 3, 1, 0};
5839     /* mesh4 (below, tip against tip)
5840      *
5841      * 0--1
5842      * | /
5843      * |/
5844      * 2
5845      * 3
5846      * |\
5847      * | \
5848      * 5--4
5849      */
5850     struct vertex_pnc vertices4[] =
5851     {
5852         {{ 0.0f,  3.0f,  0.f}, up, RED},
5853         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5854         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5855 
5856         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5857         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5858         {{ 0.0f, -7.0f,  0.f}, up, RED},
5859     };
5860     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5861     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5862     const unsigned int num_faces4 = num_vertices4 / VERTS_PER_FACE;
5863     const DWORD exp_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5864     const DWORD exp_id_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5865     const DWORD point_rep4[] = {0, 1, 2, 3, 4, 5};
5866     /* mesh5 (gap in mesh)
5867      *
5868      *    0      3-----4  15
5869      *   / \      \   /  /  \
5870      *  /   \      \ /  /    \
5871      * 2-----1      5 17-----16
5872      * 6-----7      9 12-----13
5873      *  \   /      / \  \    /
5874      *   \ /      /   \  \  /
5875      *    8     10-----11 14
5876      *
5877      */
5878     const struct vertex_pnc vertices5[] =
5879     {
5880         {{ 0.0f,  1.0f,  0.f}, up, RED},
5881         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5882         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5883 
5884         {{ 0.1f,  1.0f,  0.f}, up, RED},
5885         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5886         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5887 
5888         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5889         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5890         {{ 0.0f, -3.1f,  0.f}, up, RED},
5891 
5892         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5893         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5894         {{ 0.1f, -3.1f,  0.f}, up, RED},
5895 
5896         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5897         {{ 3.2f, -1.1f,  0.f}, up, RED},
5898         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5899 
5900         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5901         {{ 3.2f, -1.0f,  0.f}, up, RED},
5902         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5903     };
5904     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5905     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5906     const unsigned int num_faces5 = num_vertices5 / VERTS_PER_FACE;
5907     const DWORD exp_adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5908     const DWORD exp_id_adjacency5[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5909     const DWORD point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5910     /* mesh6 (indices re-ordering)
5911      *
5912      * 0--1 6 3
5913      * | / /| |\
5914      * |/ / | | \
5915      * 2 8--7 5--4
5916      */
5917     const struct vertex_pnc vertices6[] =
5918     {
5919         {{ 0.0f,  3.0f,  0.f}, up, RED},
5920         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5921         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5922 
5923         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5924         {{ 3.0f,  0.0f,  0.f}, up, RED},
5925         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5926 
5927         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5928         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5929         {{ 4.0f,  0.0f,  0.f}, up, RED},
5930     };
5931     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5932     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5933     const unsigned int num_faces6 = num_vertices6 / VERTS_PER_FACE;
5934     const DWORD exp_adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5935     const DWORD exp_id_adjacency6[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1};
5936     const DWORD point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5937     /* mesh7 (expands collapsed triangle)
5938      *
5939      * 0--1 3
5940      * | / /|
5941      * |/ / |
5942      * 2 5--4
5943      */
5944     const struct vertex_pnc vertices7[] =
5945     {
5946         {{ 0.0f,  3.0f,  0.f}, up, RED},
5947         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5948         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5949 
5950         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5951         {{ 3.0f,  0.0f,  0.f}, up, RED},
5952         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5953     };
5954     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5955     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5956     const unsigned int num_faces7 = num_vertices7 / VERTS_PER_FACE;
5957     const DWORD exp_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5958     const DWORD exp_id_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5959     const DWORD point_rep7[] = {0, 1, 2, 3, 4, 5};
5960     /* mesh8 (indices re-ordering and double replacement)
5961      *
5962      * 0--1 9  6
5963      * | / /|  |\
5964      * |/ / |  | \
5965      * 2 11-10 8--7
5966      *         3--4
5967      *         | /
5968      *         |/
5969      *         5
5970      */
5971     const struct vertex_pnc vertices8[] =
5972     {
5973         {{ 0.0f,  3.0f,  0.f}, up, RED},
5974         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5975         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5976 
5977         {{ 4.0,  -4.0,  0.f}, up, RED},
5978         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5979         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5980 
5981         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5982         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5983         {{ 4.0f,  0.0f,  0.f}, up, RED},
5984 
5985         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5986         {{ 3.0f,  0.0f,  0.f}, up, RED},
5987         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5988     };
5989     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5990     const WORD indices8_16bit[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5991     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5992     const unsigned int num_faces8 = num_vertices8 / VERTS_PER_FACE;
5993     const DWORD exp_adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5994     const DWORD exp_id_adjacency8[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5995     const DWORD point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5996      /* mesh9 (right, shared vertices)
5997      *
5998      * 0--1
5999      * | /|
6000      * |/ |
6001      * 2--3
6002      */
6003     const struct vertex_pnc vertices9[] =
6004     {
6005         {{ 0.0f,  3.0f,  0.f}, up, RED},
6006         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6007         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6008 
6009         {{ 2.0f,  0.0f,  0.f}, up, RED},
6010     };
6011     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
6012     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
6013     const unsigned int num_faces9 = 2;
6014     const DWORD exp_adjacency9[] = {-1, 1, -1, -1, -1, 0};
6015     const DWORD exp_id_adjacency9[] = {-1, 1, -1, -1, -1, 0};
6016     const DWORD point_rep9[] = {0, 1, 2, 3};
6017     /* All mesh data */
6018     ID3DXMesh *mesh = NULL;
6019     ID3DXMesh *mesh_null_check = NULL;
6020     unsigned int attributes[] = {0};
6021     struct
6022     {
6023         const struct vertex_pnc *vertices;
6024         const DWORD *indices;
6025         const DWORD num_vertices;
6026         const DWORD num_faces;
6027         const DWORD *point_reps;
6028         const DWORD *exp_adjacency;
6029         const DWORD *exp_id_adjacency;
6030         const DWORD options;
6031     }
6032     tc[] =
6033     {
6034         {
6035             vertices0,
6036             indices0,
6037             num_vertices0,
6038             num_faces0,
6039             point_rep0,
6040             exp_adjacency0,
6041             exp_id_adjacency0,
6042             options
6043         },
6044         {
6045             vertices1,
6046             indices1,
6047             num_vertices1,
6048             num_faces1,
6049             point_rep1,
6050             exp_adjacency1,
6051             exp_id_adjacency1,
6052             options
6053         },
6054         {
6055             vertices2,
6056             indices2,
6057             num_vertices2,
6058             num_faces2,
6059             point_rep2,
6060             exp_adjacency2,
6061             exp_id_adjacency2,
6062             options
6063         },
6064         {
6065             vertices3,
6066             indices3,
6067             num_vertices3,
6068             num_faces3,
6069             point_rep3,
6070             exp_adjacency3,
6071             exp_id_adjacency3,
6072             options
6073         },
6074         {
6075             vertices4,
6076             indices4,
6077             num_vertices4,
6078             num_faces4,
6079             point_rep4,
6080             exp_adjacency4,
6081             exp_id_adjacency4,
6082             options
6083         },
6084         {
6085             vertices5,
6086             indices5,
6087             num_vertices5,
6088             num_faces5,
6089             point_rep5,
6090             exp_adjacency5,
6091             exp_id_adjacency5,
6092             options
6093         },
6094         {
6095             vertices6,
6096             indices6,
6097             num_vertices6,
6098             num_faces6,
6099             point_rep6,
6100             exp_adjacency6,
6101             exp_id_adjacency6,
6102             options
6103         },
6104         {
6105             vertices7,
6106             indices7,
6107             num_vertices7,
6108             num_faces7,
6109             point_rep7,
6110             exp_adjacency7,
6111             exp_id_adjacency7,
6112             options
6113         },
6114         {
6115             vertices8,
6116             indices8,
6117             num_vertices8,
6118             num_faces8,
6119             point_rep8,
6120             exp_adjacency8,
6121             exp_id_adjacency8,
6122             options
6123         },
6124         {
6125             vertices9,
6126             indices9,
6127             num_vertices9,
6128             num_faces9,
6129             point_rep9,
6130             exp_adjacency9,
6131             exp_id_adjacency9,
6132             options
6133         },
6134         {
6135             vertices8,
6136             (DWORD*)indices8_16bit,
6137             num_vertices8,
6138             num_faces8,
6139             point_rep8,
6140             exp_adjacency8,
6141             exp_id_adjacency8,
6142             options_16bit
6143         },
6144     };
6145     DWORD *adjacency = NULL;
6146 #ifdef __REACTOS__
6147 #undef up
6148 #endif
6149 
6150     test_context = new_test_context();
6151     if (!test_context)
6152     {
6153         skip("Couldn't create test context\n");
6154         goto cleanup;
6155     }
6156 
6157     for (i = 0; i < ARRAY_SIZE(tc); i++)
6158     {
6159         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
6160                             declaration, test_context->device, &mesh);
6161         if (FAILED(hr))
6162         {
6163             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
6164             goto cleanup;
6165         }
6166 
6167         if (i == 0) /* Save first mesh for later NULL checks */
6168             mesh_null_check = mesh;
6169 
6170         adjacency = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
6171         if (!adjacency)
6172         {
6173             skip("Couldn't allocate adjacency array.\n");
6174             goto cleanup;
6175         }
6176 
6177         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
6178         if (FAILED(hr))
6179         {
6180             skip("Couldn't lock vertex buffer.\n");
6181             goto cleanup;
6182         }
6183         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
6184         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6185         if (FAILED(hr))
6186         {
6187             skip("Couldn't unlock vertex buffer.\n");
6188             goto cleanup;
6189         }
6190         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6191         if (FAILED(hr))
6192         {
6193             skip("Couldn't lock index buffer.\n");
6194             goto cleanup;
6195         }
6196         if (tc[i].options & D3DXMESH_32BIT)
6197         {
6198             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
6199         }
6200         else
6201         {
6202             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
6203         }
6204         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6205         if (FAILED(hr)) {
6206             skip("Couldn't unlock index buffer.\n");
6207             goto cleanup;
6208         }
6209 
6210         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6211         if (FAILED(hr))
6212         {
6213             skip("Couldn't lock attributes buffer.\n");
6214             goto cleanup;
6215         }
6216         memcpy(attributes_buffer, attributes, sizeof(attributes));
6217         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6218         if (FAILED(hr))
6219         {
6220             skip("Couldn't unlock attributes buffer.\n");
6221             goto cleanup;
6222         }
6223 
6224         /* Convert point representation to adjacency*/
6225         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
6226 
6227         hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
6228         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
6229            "Got %x expected D3D_OK\n", i, hr);
6230         /* Check adjacency */
6231         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
6232         {
6233             ok(adjacency[j] == tc[i].exp_adjacency[j],
6234                "Unexpected adjacency information at (%d, %d)."
6235                " Got %d expected %d\n",
6236                i, j, adjacency[j], tc[i].exp_adjacency[j]);
6237         }
6238 
6239         /* NULL point representation is considered identity. */
6240         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
6241         hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
6242         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
6243                      "Got %x expected D3D_OK\n", hr);
6244         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
6245         {
6246             ok(adjacency[j] == tc[i].exp_id_adjacency[j],
6247                "Unexpected adjacency information (id) at (%d, %d)."
6248                " Got %d expected %d\n",
6249                i, j, adjacency[j], tc[i].exp_id_adjacency[j]);
6250         }
6251 
6252         HeapFree(GetProcessHeap(), 0, adjacency);
6253         adjacency = NULL;
6254         if (i != 0) /* First mesh will be freed during cleanup */
6255             mesh->lpVtbl->Release(mesh);
6256     }
6257 
6258     /* NULL checks */
6259     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
6260     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
6261        "Got %x expected D3DERR_INVALIDCALL\n", hr);
6262     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
6263     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
6264        "Got %x expected D3DERR_INVALIDCALL\n", hr);
6265 
6266 cleanup:
6267     if (mesh_null_check)
6268         mesh_null_check->lpVtbl->Release(mesh_null_check);
6269     HeapFree(GetProcessHeap(), 0, adjacency);
6270     free_test_context(test_context);
6271 }
6272 
6273 static HRESULT init_test_mesh(const DWORD num_faces, const DWORD num_vertices,
6274                               const DWORD options,
6275                               const D3DVERTEXELEMENT9 *declaration,
6276                               IDirect3DDevice9 *device, ID3DXMesh **mesh_ptr,
6277                               const void *vertices, const DWORD vertex_size,
6278                               const DWORD *indices, const DWORD *attributes)
6279 {
6280     HRESULT hr;
6281     void *vertex_buffer;
6282     void *index_buffer;
6283     DWORD *attributes_buffer;
6284     ID3DXMesh *mesh = NULL;
6285 
6286     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration, device, mesh_ptr);
6287     if (FAILED(hr))
6288     {
6289         skip("Couldn't create mesh. Got %x expected D3D_OK\n", hr);
6290         goto cleanup;
6291     }
6292     mesh = *mesh_ptr;
6293 
6294     hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
6295     if (FAILED(hr))
6296     {
6297         skip("Couldn't lock vertex buffer.\n");
6298         goto cleanup;
6299     }
6300     memcpy(vertex_buffer, vertices, num_vertices * vertex_size);
6301     hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6302     if (FAILED(hr))
6303     {
6304         skip("Couldn't unlock vertex buffer.\n");
6305         goto cleanup;
6306     }
6307 
6308     hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6309     if (FAILED(hr))
6310     {
6311         skip("Couldn't lock index buffer.\n");
6312         goto cleanup;
6313     }
6314     if (options & D3DXMESH_32BIT)
6315     {
6316         if (indices)
6317             memcpy(index_buffer, indices, 3 * num_faces * sizeof(DWORD));
6318         else
6319         {
6320             /* Fill index buffer with 0, 1, 2, ...*/
6321             DWORD *indices_32bit = (DWORD*)index_buffer;
6322             UINT i;
6323             for (i = 0; i < 3 * num_faces; i++)
6324                 indices_32bit[i] = i;
6325         }
6326     }
6327     else
6328     {
6329         if (indices)
6330             memcpy(index_buffer, indices, 3 * num_faces * sizeof(WORD));
6331         else
6332         {
6333             /* Fill index buffer with 0, 1, 2, ...*/
6334             WORD *indices_16bit = (WORD*)index_buffer;
6335             UINT i;
6336             for (i = 0; i < 3 * num_faces; i++)
6337                 indices_16bit[i] = i;
6338         }
6339     }
6340     hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6341     if (FAILED(hr)) {
6342         skip("Couldn't unlock index buffer.\n");
6343         goto cleanup;
6344     }
6345 
6346     hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6347     if (FAILED(hr))
6348     {
6349         skip("Couldn't lock attributes buffer.\n");
6350         goto cleanup;
6351     }
6352 
6353     if (attributes)
6354         memcpy(attributes_buffer, attributes, num_faces * sizeof(*attributes));
6355     else
6356         memset(attributes_buffer, 0, num_faces * sizeof(*attributes));
6357 
6358     hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6359     if (FAILED(hr))
6360     {
6361         skip("Couldn't unlock attributes buffer.\n");
6362         goto cleanup;
6363     }
6364 
6365     hr = D3D_OK;
6366 cleanup:
6367     return hr;
6368 }
6369 
6370 /* Using structs instead of bit-fields in order to avoid compiler issues. */
6371 struct udec3
6372 {
6373     UINT x;
6374     UINT y;
6375     UINT z;
6376     UINT w;
6377 };
6378 
6379 struct dec3n
6380 {
6381     INT x;
6382     INT y;
6383     INT z;
6384     INT w;
6385 };
6386 
6387 static DWORD init_udec3_dword(UINT x, UINT y, UINT z, UINT w)
6388 {
6389     DWORD d = 0;
6390 
6391     d |= x & 0x3ff;
6392     d |= (y << 10) & 0xffc00;
6393     d |= (z << 20) & 0x3ff00000;
6394     d |= (w << 30) & 0xc0000000;
6395 
6396     return d;
6397 }
6398 
6399 static DWORD init_dec3n_dword(INT x, INT y, INT z, INT w)
6400 {
6401     DWORD d = 0;
6402 
6403     d |= x & 0x3ff;
6404     d |= (y << 10) & 0xffc00;
6405     d |= (z << 20) & 0x3ff00000;
6406     d |= (w << 30) & 0xc0000000;
6407 
6408     return d;
6409 }
6410 
6411 static struct udec3 dword_to_udec3(DWORD d)
6412 {
6413     struct udec3 v;
6414 
6415     v.x = d & 0x3ff;
6416     v.y = (d & 0xffc00) >> 10;
6417     v.z = (d & 0x3ff00000) >> 20;
6418     v.w = (d & 0xc0000000) >> 30;
6419 
6420     return v;
6421 }
6422 
6423 static struct dec3n dword_to_dec3n(DWORD d)
6424 {
6425     struct dec3n v;
6426 
6427     v.x = d & 0x3ff;
6428     v.y = (d & 0xffc00) >> 10;
6429     v.z = (d & 0x3ff00000) >> 20;
6430     v.w = (d & 0xc0000000) >> 30;
6431 
6432     return v;
6433 }
6434 
6435 static void check_vertex_components(int line, int mesh_number, int vertex_number, BYTE *got_ptr, const BYTE *exp_ptr, D3DVERTEXELEMENT9 *declaration)
6436 {
6437     const char *usage_strings[] =
6438     {
6439         "position",
6440         "blend weight",
6441         "blend indices",
6442         "normal",
6443         "point size",
6444         "texture coordinates",
6445         "tangent",
6446         "binormal",
6447         "tessellation factor",
6448         "position transformed",
6449         "color",
6450         "fog",
6451         "depth",
6452         "sample"
6453     };
6454     D3DVERTEXELEMENT9 *decl_ptr;
6455     const float PRECISION = 1e-5f;
6456 
6457     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
6458     {
6459         switch (decl_ptr->Type)
6460         {
6461             case D3DDECLTYPE_FLOAT1:
6462             {
6463                 FLOAT *got = (FLOAT*)(got_ptr + decl_ptr->Offset);
6464                 FLOAT *exp = (FLOAT*)(exp_ptr + decl_ptr->Offset);
6465                 FLOAT diff = fabsf(*got - *exp);
6466                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got %f for vertex %d %s, expected %f.\n",
6467                     mesh_number, *got, vertex_number, usage_strings[decl_ptr->Usage], *exp);
6468                 break;
6469             }
6470             case D3DDECLTYPE_FLOAT2:
6471             {
6472                 D3DXVECTOR2 *got = (D3DXVECTOR2*)(got_ptr + decl_ptr->Offset);
6473                 D3DXVECTOR2 *exp = (D3DXVECTOR2*)(exp_ptr + decl_ptr->Offset);
6474                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6475                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f) for vertex %d %s, expected (%f, %f).\n",
6476                     mesh_number, got->x, got->y, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y);
6477                 break;
6478             }
6479             case D3DDECLTYPE_FLOAT3:
6480             {
6481                 D3DXVECTOR3 *got = (D3DXVECTOR3*)(got_ptr + decl_ptr->Offset);
6482                 D3DXVECTOR3 *exp = (D3DXVECTOR3*)(exp_ptr + decl_ptr->Offset);
6483                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6484                 diff = max(diff, fabsf(got->z - exp->z));
6485                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f) for vertex %d %s, expected (%f, %f, %f).\n",
6486                     mesh_number, got->x, got->y, got->z, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y, exp->z);
6487                 break;
6488             }
6489             case D3DDECLTYPE_FLOAT4:
6490             {
6491                 D3DXVECTOR4 *got = (D3DXVECTOR4*)(got_ptr + decl_ptr->Offset);
6492                 D3DXVECTOR4 *exp = (D3DXVECTOR4*)(exp_ptr + decl_ptr->Offset);
6493                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6494                 diff = max(diff, fabsf(got->z - exp->z));
6495                 diff = max(diff, fabsf(got->w - exp->w));
6496                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f, %f) for vertex %d %s, expected (%f, %f, %f, %f).\n",
6497                     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);
6498                 break;
6499             }
6500             case D3DDECLTYPE_D3DCOLOR:
6501             {
6502                 BYTE *got = got_ptr + decl_ptr->Offset;
6503                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6504                 BOOL same_color = got[0] == exp[0] && got[1] == exp[1]
6505                                   && got[2] == exp[2] && got[3] == exp[3];
6506                 const char *color_types[] = {"diffuse", "specular", "undefined color"};
6507                 BYTE usage_index = decl_ptr->UsageIndex;
6508                 if (usage_index > 1) usage_index = 2;
6509                 ok_(__FILE__,line)(same_color, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6510                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, color_types[usage_index], exp[0], exp[1], exp[2], exp[3]);
6511                 break;
6512             }
6513             case D3DDECLTYPE_UBYTE4:
6514             case D3DDECLTYPE_UBYTE4N:
6515             {
6516                 BYTE *got = got_ptr + decl_ptr->Offset;
6517                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6518                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6519                             && got[2] == exp[2] && got[3] == exp[3];
6520                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6521                     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]);
6522                 break;
6523             }
6524             case D3DDECLTYPE_SHORT2:
6525             case D3DDECLTYPE_SHORT2N:
6526             {
6527                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6528                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6529                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6530                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd) for vertex %d %s, expected (%hd, %hd).\n",
6531                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6532                 break;
6533             }
6534             case D3DDECLTYPE_SHORT4:
6535             case D3DDECLTYPE_SHORT4N:
6536             {
6537                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6538                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6539                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6540                             && got[2] == exp[2] && got[3] == exp[3];
6541                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd, %hd, %hd) for vertex %d %s, expected (%hd, %hd, %hd, %hd).\n",
6542                     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]);
6543                 break;
6544             }
6545             case D3DDECLTYPE_USHORT2N:
6546             {
6547                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6548                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6549                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6550                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu) for vertex %d %s, expected (%hu, %hu).\n",
6551                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6552                 break;
6553             }
6554             case D3DDECLTYPE_USHORT4N:
6555             {
6556                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6557                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6558                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6559                             && got[2] == exp[2] && got[3] == exp[3];
6560                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu, %hu, %hu) for vertex %d %s, expected (%hu, %hu, %hu, %hu).\n",
6561                     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]);
6562                 break;
6563             }
6564             case D3DDECLTYPE_UDEC3:
6565             {
6566                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6567                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6568                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6569                 struct udec3 got_udec3 = dword_to_udec3(*got);
6570                 struct udec3 exp_udec3 = dword_to_udec3(*exp);
6571                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6572                     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);
6573 
6574                 break;
6575             }
6576             case D3DDECLTYPE_DEC3N:
6577             {
6578                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6579                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6580                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6581                 struct dec3n got_dec3n = dword_to_dec3n(*got);
6582                 struct dec3n exp_dec3n = dword_to_dec3n(*exp);
6583                 ok_(__FILE__,line)(same, "Mesh %d: Got (%d, %d, %d, %d) for vertex %d %s, expected (%d, %d, %d, %d).\n",
6584                     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);
6585                 break;
6586             }
6587             case D3DDECLTYPE_FLOAT16_2:
6588             {
6589                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6590                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6591                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6592                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx) for vertex %d %s, expected (%hx, %hx).\n",
6593                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6594                 break;
6595             }
6596             case D3DDECLTYPE_FLOAT16_4:
6597             {
6598                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6599                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6600                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6601                             && got[2] == exp[2] && got[3] == exp[3];
6602                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx, %hx, %hx) for vertex %d %s, expected (%hx, %hx, %hx, %hx).\n",
6603                     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]);
6604                 break;
6605             }
6606             default:
6607                 break;
6608         }
6609     }
6610 }
6611 
6612 static void test_weld_vertices(void)
6613 {
6614     HRESULT hr;
6615     struct test_context *test_context = NULL;
6616     DWORD i;
6617     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
6618     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
6619     BYTE *vertices = NULL;
6620     DWORD *indices = NULL;
6621     WORD *indices_16bit = NULL;
6622     const UINT VERTS_PER_FACE = 3;
6623 #ifndef __REACTOS__
6624     const D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
6625 #else
6626 #define up {0.0f, 0.0f, 1.0f}
6627 #endif
6628     struct vertex_normal
6629     {
6630         D3DXVECTOR3 position;
6631         D3DXVECTOR3 normal;
6632     };
6633     struct vertex_blendweight
6634     {
6635         D3DXVECTOR3 position;
6636         FLOAT blendweight;
6637     };
6638     struct vertex_texcoord
6639     {
6640         D3DXVECTOR3 position;
6641         D3DXVECTOR2 texcoord;
6642     };
6643     struct vertex_color
6644     {
6645         D3DXVECTOR3 position;
6646         DWORD color;
6647     };
6648     struct vertex_color_ubyte4
6649     {
6650         D3DXVECTOR3 position;
6651         BYTE color[4];
6652     };
6653     struct vertex_texcoord_short2
6654     {
6655         D3DXVECTOR3 position;
6656         SHORT texcoord[2];
6657     };
6658     struct vertex_texcoord_ushort2n
6659     {
6660         D3DXVECTOR3 position;
6661         USHORT texcoord[2];
6662     };
6663     struct vertex_normal_short4
6664     {
6665         D3DXVECTOR3 position;
6666         SHORT normal[4];
6667     };
6668     struct vertex_texcoord_float16_2
6669     {
6670         D3DXVECTOR3 position;
6671         WORD texcoord[2];
6672     };
6673     struct vertex_texcoord_float16_4
6674     {
6675         D3DXVECTOR3 position;
6676         WORD texcoord[4];
6677     };
6678     struct vertex_normal_udec3
6679     {
6680         D3DXVECTOR3 position;
6681         DWORD normal;
6682     };
6683     struct vertex_normal_dec3n
6684     {
6685         D3DXVECTOR3 position;
6686         DWORD normal;
6687     };
6688     UINT vertex_size_normal = sizeof(struct vertex_normal);
6689     UINT vertex_size_blendweight = sizeof(struct vertex_blendweight);
6690     UINT vertex_size_texcoord = sizeof(struct vertex_texcoord);
6691     UINT vertex_size_color = sizeof(struct vertex_color);
6692     UINT vertex_size_color_ubyte4 = sizeof(struct vertex_color_ubyte4);
6693     UINT vertex_size_texcoord_short2 = sizeof(struct vertex_texcoord_short2);
6694     UINT vertex_size_normal_short4 = sizeof(struct vertex_normal_short4);
6695     UINT vertex_size_texcoord_float16_2 = sizeof(struct vertex_texcoord_float16_2);
6696     UINT vertex_size_texcoord_float16_4 = sizeof(struct vertex_texcoord_float16_4);
6697     UINT vertex_size_normal_udec3 = sizeof(struct vertex_normal_udec3);
6698     UINT vertex_size_normal_dec3n = sizeof(struct vertex_normal_dec3n);
6699     D3DVERTEXELEMENT9 declaration_normal[] =
6700     {
6701         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6702         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6703         D3DDECL_END()
6704     };
6705     D3DVERTEXELEMENT9 declaration_normal3[] =
6706     {
6707         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 3},
6708         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6709         D3DDECL_END()
6710     };
6711     D3DVERTEXELEMENT9 declaration_blendweight[] =
6712     {
6713         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6714         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
6715         D3DDECL_END()
6716     };
6717     D3DVERTEXELEMENT9 declaration_texcoord[] =
6718     {
6719         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6720         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6721         D3DDECL_END()
6722     };
6723     D3DVERTEXELEMENT9 declaration_color[] =
6724     {
6725         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6726         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6727         D3DDECL_END()
6728     };
6729     D3DVERTEXELEMENT9 declaration_color_ubyte4n[] =
6730     {
6731         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6732         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6733         D3DDECL_END()
6734     };
6735     D3DVERTEXELEMENT9 declaration_color_ubyte4[] =
6736     {
6737         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6738         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6739         D3DDECL_END()
6740     };
6741     D3DVERTEXELEMENT9 declaration_texcoord_short2[] =
6742     {
6743         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6744         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6745         D3DDECL_END()
6746     };
6747     D3DVERTEXELEMENT9 declaration_texcoord_short2n[] =
6748     {
6749         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6750         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6751         D3DDECL_END()
6752     };
6753     D3DVERTEXELEMENT9 declaration_texcoord_ushort2n[] =
6754     {
6755         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6756         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6757         D3DDECL_END()
6758     };
6759     D3DVERTEXELEMENT9 declaration_normal_short4[] =
6760     {
6761         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6762         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6763         D3DDECL_END()
6764     };
6765     D3DVERTEXELEMENT9 declaration_normal_short4n[] =
6766     {
6767         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6768         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6769         D3DDECL_END()
6770     };
6771     D3DVERTEXELEMENT9 declaration_normal_ushort4n[] =
6772     {
6773         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6774         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6775         D3DDECL_END()
6776     };
6777     D3DVERTEXELEMENT9 declaration_texcoord10[] =
6778     {
6779         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6780         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 10},
6781         D3DDECL_END()
6782     };
6783     D3DVERTEXELEMENT9 declaration_color2[] =
6784     {
6785         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6786         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
6787         D3DDECL_END()
6788     };
6789     D3DVERTEXELEMENT9 declaration_color1[] =
6790     {
6791         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6792         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
6793         D3DDECL_END()
6794     };
6795     D3DVERTEXELEMENT9 declaration_texcoord_float16_2[] =
6796     {
6797         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6798         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6799         D3DDECL_END()
6800     };
6801     D3DVERTEXELEMENT9 declaration_texcoord_float16_4[] =
6802     {
6803         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6804         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6805         D3DDECL_END()
6806     };
6807     D3DVERTEXELEMENT9 declaration_normal_udec3[] =
6808    {
6809         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6810         {0, 12, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6811         D3DDECL_END()
6812     };
6813     D3DVERTEXELEMENT9 declaration_normal_dec3n[] =
6814     {
6815         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6816         {0, 12, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6817         D3DDECL_END()
6818     };
6819     /* Test 0. One face and no welding.
6820      *
6821      * 0--1
6822      * | /
6823      * |/
6824      * 2
6825      */
6826     const struct vertex vertices0[] =
6827     {
6828         {{ 0.0f,  3.0f,  0.f}, up},
6829         {{ 2.0f,  3.0f,  0.f}, up},
6830         {{ 0.0f,  0.0f,  0.f}, up},
6831     };
6832     const DWORD indices0[] = {0, 1, 2};
6833     const DWORD attributes0[] = {0};
6834     const DWORD exp_indices0[] = {0, 1, 2};
6835     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
6836     const UINT num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
6837     const DWORD flags0 = D3DXWELDEPSILONS_WELDALL;
6838     /* epsilons0 is NULL */
6839     const DWORD adjacency0[] = {-1, -1, -1};
6840     const struct vertex exp_vertices0[] =
6841     {
6842         {{ 0.0f,  3.0f,  0.f}, up},
6843         {{ 2.0f,  3.0f,  0.f}, up},
6844         {{ 0.0f,  0.0f,  0.f}, up},
6845     };
6846     const DWORD exp_face_remap0[] = {0};
6847     const DWORD exp_vertex_remap0[] = {0, 1, 2};
6848     const DWORD exp_new_num_vertices0 = ARRAY_SIZE(exp_vertices0);
6849     /* Test 1. Two vertices should be removed without regard to epsilon.
6850      *
6851      * 0--1 3
6852      * | / /|
6853      * |/ / |
6854      * 2 5--4
6855      */
6856     const struct vertex_normal vertices1[] =
6857     {
6858         {{ 0.0f,  3.0f,  0.f}, up},
6859         {{ 2.0f,  3.0f,  0.f}, up},
6860         {{ 0.0f,  0.0f,  0.f}, up},
6861 
6862         {{ 3.0f,  3.0f,  0.f}, up},
6863         {{ 3.0f,  0.0f,  0.f}, up},
6864         {{ 1.0f,  0.0f,  0.f}, up},
6865     };
6866     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
6867     const DWORD attributes1[] = {0, 0};
6868     const UINT num_vertices1 = ARRAY_SIZE(vertices1);
6869     const UINT num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
6870     const DWORD flags1 = D3DXWELDEPSILONS_WELDALL;
6871     /* epsilons1 is NULL */
6872     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
6873     const struct vertex_normal exp_vertices1[] =
6874     {
6875         {{ 0.0f,  3.0f,  0.f}, up},
6876         {{ 2.0f,  3.0f,  0.f}, up},
6877         {{ 0.0f,  0.0f,  0.f}, up},
6878 
6879         {{ 3.0f,  0.0f,  0.f}, up}
6880     };
6881     const DWORD exp_indices1[] = {0, 1, 2, 1, 3, 2};
6882     const DWORD exp_face_remap1[] = {0, 1};
6883     const DWORD exp_vertex_remap1[] = {0, 1, 2, 4, -1, -1};
6884     const DWORD exp_new_num_vertices1 = ARRAY_SIZE(exp_vertices1);
6885     /* Test 2. Two faces. No vertices should be removed because of normal
6886      * epsilon, but the positions should be replaced. */
6887     const struct vertex_normal vertices2[] =
6888     {
6889         {{ 0.0f,  3.0f,  0.f}, up},
6890         {{ 2.0f,  3.0f,  0.f}, up},
6891         {{ 0.0f,  0.0f,  0.f}, up},
6892 
6893         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6894         {{ 3.0f,  0.0f,  0.f}, up},
6895         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6896     };
6897     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
6898     const DWORD attributes2[] = {0, 0};
6899     const UINT num_vertices2 = ARRAY_SIZE(vertices2);
6900     const UINT num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
6901     DWORD flags2 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6902     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};
6903     const DWORD adjacency2[] = {-1, 1, -1, -1, -1, 0};
6904     const struct vertex_normal exp_vertices2[] =
6905     {
6906         {{ 0.0f,  3.0f,  0.f}, up},
6907         {{ 2.0f,  3.0f,  0.f}, up},
6908         {{ 0.0f,  0.0f,  0.f}, up},
6909 
6910         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6911         {{ 3.0f,  0.0f,  0.f}, up},
6912         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6913     };
6914     const DWORD exp_indices2[] = {0, 1, 2, 3, 4, 5};
6915     const DWORD exp_face_remap2[] = {0, 1};
6916     const DWORD exp_vertex_remap2[] = {0, 1, 2, 3, 4, 5};
6917     const DWORD exp_new_num_vertices2 = ARRAY_SIZE(exp_vertices2);
6918     /* Test 3. Two faces. One vertex should be removed because of normal epsilon. */
6919     const struct vertex_normal vertices3[] =
6920     {
6921         {{ 0.0f,  3.0f,  0.f}, up},
6922         {{ 2.0f,  3.0f,  0.f}, up},
6923         {{ 0.0f,  0.0f,  0.f}, up},
6924 
6925         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6926         {{ 3.0f,  0.0f,  0.f}, up},
6927         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6928     };
6929     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
6930     const DWORD attributes3[] = {0, 0};
6931     const UINT num_vertices3 = ARRAY_SIZE(vertices3);
6932     const UINT num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
6933     DWORD flags3 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6934     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};
6935     const DWORD adjacency3[] = {-1, 1, -1, -1, -1, 0};
6936     const struct vertex_normal exp_vertices3[] =
6937     {
6938         {{ 0.0f,  3.0f,  0.f}, up},
6939         {{ 2.0f,  3.0f,  0.f}, up},
6940         {{ 0.0f,  0.0f,  0.f}, up},
6941 
6942         {{ 3.0f,  0.0f,  0.f}, up},
6943         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6944     };
6945     const DWORD exp_indices3[] = {0, 1, 2, 1, 3, 4};
6946     const DWORD exp_face_remap3[] = {0, 1};
6947     const DWORD exp_vertex_remap3[] = {0, 1, 2, 4, 5, -1};
6948     const DWORD exp_new_num_vertices3 = ARRAY_SIZE(exp_vertices3);
6949     /* Test 4  Two faces. Two vertices should be removed. */
6950     const struct vertex_normal vertices4[] =
6951     {
6952         {{ 0.0f,  3.0f,  0.f}, up},
6953         {{ 2.0f,  3.0f,  0.f}, up},
6954         {{ 0.0f,  0.0f,  0.f}, up},
6955 
6956         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6957         {{ 3.0f,  0.0f,  0.f}, up},
6958         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6959     };
6960     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
6961     const DWORD attributes4[] = {0, 0};
6962     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
6963     const UINT num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
6964     DWORD flags4 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6965     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};
6966     const DWORD adjacency4[] = {-1, 1, -1, -1, -1, 0};
6967     const struct vertex_normal exp_vertices4[] =
6968     {
6969         {{ 0.0f,  3.0f,  0.f}, up},
6970         {{ 2.0f,  3.0f,  0.f}, up},
6971         {{ 0.0f,  0.0f,  0.f}, up},
6972 
6973         {{ 3.0f,  0.0f,  0.f}, up},
6974     };
6975     const DWORD exp_indices4[] = {0, 1, 2, 1, 3, 2};
6976     const DWORD exp_face_remap4[] = {0, 1};
6977     const DWORD exp_vertex_remap4[] = {0, 1, 2, 4, -1, -1};
6978     const DWORD exp_new_num_vertices4 = ARRAY_SIZE(exp_vertices4);
6979     /* Test 5. Odd face ordering.
6980      *
6981      * 0--1 6 3
6982      * | / /| |\
6983      * |/ / | | \
6984      * 2 8--7 5--4
6985      */
6986     const struct vertex_normal vertices5[] =
6987     {
6988         {{ 0.0f,  3.0f,  0.f}, up},
6989         {{ 2.0f,  3.0f,  0.f}, up},
6990         {{ 0.0f,  0.0f,  0.f}, up},
6991 
6992         {{ 3.0f,  3.0f,  0.f}, up},
6993         {{ 3.0f,  0.0f,  0.f}, up},
6994         {{ 1.0f,  0.0f,  0.f}, up},
6995 
6996         {{ 4.0f,  3.0f,  0.f}, up},
6997         {{ 6.0f,  0.0f,  0.f}, up},
6998         {{ 4.0f,  0.0f,  0.f}, up},
6999     };
7000     const DWORD indices5[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
7001     const DWORD exp_indices5[] = {0, 1, 2, 1, 4, 2, 1, 3, 4};
7002     const DWORD attributes5[] = {0, 0, 0};
7003     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
7004     const UINT num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
7005     DWORD flags5 = D3DXWELDEPSILONS_WELDALL;
7006     const DWORD adjacency5[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
7007     const struct vertex_normal exp_vertices5[] =
7008     {
7009         {{ 0.0f,  3.0f,  0.f}, up},
7010         {{ 2.0f,  3.0f,  0.f}, up},
7011         {{ 0.0f,  0.0f,  0.f}, up},
7012 
7013         {{ 3.0f,  0.0f,  0.f}, up},
7014         {{ 1.0f,  0.0f,  0.f}, up},
7015     };
7016     const DWORD exp_face_remap5[] = {0, 1, 2};
7017     const DWORD exp_vertex_remap5[] = {0, 1, 2, 4, 5, -1, -1, -1, -1};
7018     const DWORD exp_new_num_vertices5 = ARRAY_SIZE(exp_vertices5);
7019     /* Test 6. Two faces. Do not remove flag is used, so no vertices should be
7020      * removed. */
7021     const struct vertex_normal vertices6[] =
7022     {
7023         {{ 0.0f,  3.0f,  0.f}, up},
7024         {{ 2.0f,  3.0f,  0.f}, up},
7025         {{ 0.0f,  0.0f,  0.f}, up},
7026 
7027         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7028         {{ 3.0f,  0.0f,  0.f}, up},
7029         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7030     };
7031     const DWORD indices6[] = {0, 1, 2, 3, 4, 5};
7032     const DWORD attributes6[] = {0, 0};
7033     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
7034     const UINT num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
7035     DWORD flags6 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTREMOVEVERTICES;
7036     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};
7037     const DWORD adjacency6[] = {-1, 1, -1, -1, -1, 0};
7038     const struct vertex_normal exp_vertices6[] =
7039     {
7040         {{ 0.0f,  3.0f,  0.f}, up},
7041         {{ 2.0f,  3.0f,  0.f}, up},
7042         {{ 0.0f,  0.0f,  0.f}, up},
7043 
7044         {{ 2.0f,  3.0f,  0.f}, up},
7045         {{ 3.0f,  0.0f,  0.f}, up},
7046         {{ 0.0f,  0.0f,  0.f}, up},
7047 
7048     };
7049     const DWORD exp_indices6[] = {0, 1, 2, 3, 4, 5};
7050     const DWORD exp_face_remap6[] = {0, 1};
7051     const DWORD exp_vertex_remap6[] = {0, 1, 2, 3, 4, 5};
7052     const DWORD exp_new_num_vertices6 = ARRAY_SIZE(exp_vertices6);
7053     /* Test 7. Same as test 6 but with 16 bit indices. */
7054     const WORD indices6_16bit[] = {0, 1, 2, 3, 4, 5};
7055     /* Test 8. No flags. Same result as D3DXWELDEPSILONS_WELDPARTIALMATCHES. */
7056     const struct vertex_normal vertices8[] =
7057     {
7058         {{ 0.0f,  3.0f,  0.f}, up},
7059         {{ 2.0f,  3.0f,  0.f}, up},
7060         {{ 0.0f,  0.0f,  0.f}, up},
7061 
7062         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7063         {{ 3.0f,  0.0f,  0.f}, up},
7064         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7065     };
7066     const DWORD indices8[] = {0, 1, 2, 1, 3, 4};
7067     const DWORD attributes8[] = {0, 0};
7068     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
7069     const UINT num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
7070     DWORD flags8 = 0;
7071     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};
7072     const DWORD adjacency8[] = {-1, 1, -1, -1, -1, 0};
7073     const struct vertex_normal exp_vertices8[] =
7074     {
7075         {{ 0.0f,  3.0f,  0.f}, up},
7076         {{ 2.0f,  3.0f,  0.f}, up},
7077         {{ 0.0f,  0.0f,  0.f}, up},
7078 
7079         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7080         {{ 3.0f,  0.0f,  0.f}, up},
7081     };
7082     const DWORD exp_indices8[] = {0, 1, 2, 1, 3, 4};
7083     const DWORD exp_face_remap8[] = {0, 1};
7084     const DWORD exp_vertex_remap8[] = {0, 1, 2, 3, 4, -1};
7085     const DWORD exp_new_num_vertices8 = ARRAY_SIZE(exp_vertices8);
7086     /* Test 9. Vertices are removed even though they belong to separate
7087      * attribute groups if D3DXWELDEPSILONS_DONOTSPLIT is set. */
7088     const struct vertex_normal vertices9[] =
7089     {
7090         {{ 0.0f,  3.0f,  0.f}, up},
7091         {{ 2.0f,  3.0f,  0.f}, up},
7092         {{ 0.0f,  0.0f,  0.f}, up},
7093 
7094         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7095         {{ 3.0f,  0.0f,  0.f}, up},
7096         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7097     };
7098     const DWORD indices9[] = {0, 1, 2, 3, 4, 5};
7099     const DWORD attributes9[] = {0, 1};
7100     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
7101     const UINT num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
7102     DWORD flags9 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTSPLIT;
7103     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};
7104     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
7105     const struct vertex_normal exp_vertices9[] =
7106     {
7107         {{ 0.0f,  3.0f,  0.f}, up},
7108         {{ 2.0f,  3.0f,  0.f}, up},
7109         {{ 0.0f,  0.0f,  0.f}, up},
7110 
7111         {{ 3.0f,  0.0f,  0.f}, up},
7112     };
7113     const DWORD exp_indices9[] = {0, 1, 2, 1, 3, 2};
7114     const DWORD exp_face_remap9[] = {0, 1};
7115     const DWORD exp_vertex_remap9[] = {0, 1, 2, 4, -1, -1};
7116     const DWORD exp_new_num_vertices9 = ARRAY_SIZE(exp_vertices9);
7117     /* Test 10. Weld blendweight (FLOAT1). */
7118     const struct vertex_blendweight vertices10[] =
7119     {
7120         {{ 0.0f,  3.0f,  0.f}, 1.0f},
7121         {{ 2.0f,  3.0f,  0.f}, 1.0f},
7122         {{ 0.0f,  0.0f,  0.f}, 1.0f},
7123 
7124         {{ 3.0f,  3.0f,  0.f}, 0.9},
7125         {{ 3.0f,  0.0f,  0.f}, 1.0},
7126         {{ 1.0f,  0.0f,  0.f}, 0.4},
7127     };
7128     const DWORD indices10[] = {0, 1, 2, 3, 4, 5};
7129     const DWORD attributes10[] = {0, 0};
7130     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
7131     const UINT num_faces10 = ARRAY_SIZE(indices10) / VERTS_PER_FACE;
7132     DWORD flags10 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7133     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};
7134     const DWORD adjacency10[] = {-1, 1, -1, -1, -1, 0};
7135     const struct vertex_blendweight exp_vertices10[] =
7136     {
7137         {{ 0.0f,  3.0f,  0.f}, 1.0f},
7138         {{ 2.0f,  3.0f,  0.f}, 1.0f},
7139         {{ 0.0f,  0.0f,  0.f}, 1.0f},
7140 
7141         {{ 3.0f,  0.0f,  0.f}, 1.0},
7142         {{ 0.0f,  0.0f,  0.f}, 0.4},
7143     };
7144     const DWORD exp_indices10[] = {0, 1, 2, 1, 3, 4};
7145     const DWORD exp_face_remap10[] = {0, 1};
7146     const DWORD exp_vertex_remap10[] = {0, 1, 2, 4, 5, -1};
7147     const DWORD exp_new_num_vertices10 = ARRAY_SIZE(exp_vertices10);
7148     /* Test 11. Weld texture coordinates. */
7149     const struct vertex_texcoord vertices11[] =
7150     {
7151         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7152         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7153         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7154 
7155         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7156         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7157         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7158     };
7159     const DWORD indices11[] = {0, 1, 2, 3, 4, 5};
7160     const DWORD attributes11[] = {0, 0};
7161     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
7162     const UINT num_faces11 = ARRAY_SIZE(indices11) / VERTS_PER_FACE;
7163     DWORD flags11 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7164     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};
7165     const DWORD adjacency11[] = {-1, 1, -1, -1, -1, 0};
7166     const struct vertex_texcoord exp_vertices11[] =
7167     {
7168         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7169         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7170         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7171 
7172         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7173         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7174     };
7175     const DWORD exp_indices11[] = {0, 1, 2, 1, 3, 4};
7176     const DWORD exp_face_remap11[] = {0, 1};
7177     const DWORD exp_vertex_remap11[] = {0, 1, 2, 4, 5, -1};
7178     const DWORD exp_new_num_vertices11 = ARRAY_SIZE(exp_vertices11);
7179     /* Test 12. Weld with color. */
7180     const struct vertex_color vertices12[] =
7181     {
7182         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7183         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7184         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7185 
7186         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7187         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7188         {{ 1.0f,  0.0f,  0.f}, 0x88888888},
7189     };
7190     const DWORD indices12[] = {0, 1, 2, 3, 4, 5};
7191     const DWORD attributes12[] = {0, 0};
7192     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
7193     const UINT num_faces12 = ARRAY_SIZE(indices12) / VERTS_PER_FACE;
7194     DWORD flags12 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7195     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};
7196     const DWORD adjacency12[] = {-1, 1, -1, -1, -1, 0};
7197     const struct vertex_color exp_vertices12[] =
7198     {
7199         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7200         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7201         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7202 
7203         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7204         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7205     };
7206     const DWORD exp_indices12[] = {0, 1, 2, 3, 4, 2};
7207     const DWORD exp_face_remap12[] = {0, 1};
7208     const DWORD exp_vertex_remap12[] = {0, 1, 2, 3, 4, -1};
7209     const DWORD exp_new_num_vertices12 = ARRAY_SIZE(exp_vertices12);
7210     /* Test 13. Two faces. One vertex should be removed because of normal epsilon.
7211      * This is similar to test 3, but the declaration has been changed to NORMAL3.
7212      */
7213     const struct vertex_normal vertices13[] =
7214     {
7215         {{ 0.0f,  3.0f,  0.f}, up},
7216         {{ 2.0f,  3.0f,  0.f}, up},
7217         {{ 0.0f,  0.0f,  0.f}, up},
7218 
7219         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7220         {{ 3.0f,  0.0f,  0.f}, up},
7221         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7222     };
7223     const DWORD indices13[] = {0, 1, 2, 3, 4, 5};
7224     const DWORD attributes13[] = {0, 0};
7225     const UINT num_vertices13 = ARRAY_SIZE(vertices3);
7226     const UINT num_faces13 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
7227     DWORD flags13 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7228     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};
7229     const DWORD adjacency13[] = {-1, 1, -1, -1, -1, 0};
7230     const struct vertex_normal exp_vertices13[] =
7231     {
7232         {{ 0.0f,  3.0f,  0.f}, up},
7233         {{ 2.0f,  3.0f,  0.f}, up},
7234         {{ 0.0f,  0.0f,  0.f}, up},
7235 
7236         {{ 3.0f,  0.0f,  0.f}, up},
7237         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7238     };
7239     const DWORD exp_indices13[] = {0, 1, 2, 1, 3, 4};
7240     const DWORD exp_face_remap13[] = {0, 1};
7241     const DWORD exp_vertex_remap13[] = {0, 1, 2, 4, 5, -1};
7242     const DWORD exp_new_num_vertices13 = ARRAY_SIZE(exp_vertices13);
7243     /* Test 14. Another test for welding with color. */
7244     const struct vertex_color vertices14[] =
7245     {
7246         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7247         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7248         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7249 
7250         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7251         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7252         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7253     };
7254     const DWORD indices14[] = {0, 1, 2, 3, 4, 5};
7255     const DWORD attributes14[] = {0, 0};
7256     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
7257     const UINT num_faces14 = ARRAY_SIZE(indices14) / VERTS_PER_FACE;
7258     DWORD flags14 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7259     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};
7260     const DWORD adjacency14[] = {-1, 1, -1, -1, -1, 0};
7261     const struct vertex_color exp_vertices14[] =
7262     {
7263         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7264         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7265         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7266 
7267         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7268         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7269     };
7270     const DWORD exp_indices14[] = {0, 1, 2, 3, 4, 2};
7271     const DWORD exp_face_remap14[] = {0, 1};
7272     const DWORD exp_vertex_remap14[] = {0, 1, 2, 3, 4, -1};
7273     const DWORD exp_new_num_vertices14 = ARRAY_SIZE(exp_vertices14);
7274     /* Test 15. Weld with color, but as UBYTE4N instead of D3DCOLOR. It shows
7275      * that UBYTE4N and D3DCOLOR are compared the same way.
7276      */
7277     const struct vertex_color_ubyte4 vertices15[] =
7278     {
7279         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7280         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7281         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7282 
7283         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7284         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7285         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7286     };
7287     const DWORD indices15[] = {0, 1, 2, 3, 4, 5};
7288     const DWORD attributes15[] = {0, 0};
7289     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
7290     const UINT num_faces15 = ARRAY_SIZE(indices15) / VERTS_PER_FACE;
7291     DWORD flags15 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7292     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};
7293     const DWORD adjacency15[] = {-1, 1, -1, -1, -1, 0};
7294     const struct vertex_color_ubyte4 exp_vertices15[] =
7295     {
7296         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7297         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7298         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7299 
7300         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7301         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7302     };
7303     const DWORD exp_indices15[] = {0, 1, 2, 3, 4, 2};
7304     const DWORD exp_face_remap15[] = {0, 1};
7305     const DWORD exp_vertex_remap15[] = {0, 1, 2, 3, 4, -1};
7306     const DWORD exp_new_num_vertices15 = ARRAY_SIZE(exp_vertices15);
7307     /* Test 16. Weld with color, but as UBYTE4 instead of D3DCOLOR. It shows
7308      * that UBYTE4 is not normalized and that epsilon is truncated and compared
7309      * directly to each of the four bytes.
7310      */
7311     const struct vertex_color_ubyte4 vertices16[] =
7312     {
7313         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7314         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7315         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7316 
7317         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7318         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7319         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7320     };
7321     const DWORD indices16[] = {0, 1, 2, 3, 4, 5};
7322     const DWORD attributes16[] = {0, 0};
7323     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
7324     const UINT num_faces16 = ARRAY_SIZE(indices16) / VERTS_PER_FACE;
7325     DWORD flags16 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7326     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};
7327     const DWORD adjacency16[] = {-1, 1, -1, -1, -1, 0};
7328     const struct vertex_color_ubyte4 exp_vertices16[] =
7329     {
7330         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7331         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7332         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7333 
7334         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7335         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7336     };
7337     const DWORD exp_indices16[] = {0, 1, 2, 3, 4, 2};
7338     const DWORD exp_face_remap16[] = {0, 1};
7339     const DWORD exp_vertex_remap16[] = {0, 1, 2, 3, 4, -1};
7340     const DWORD exp_new_num_vertices16 = ARRAY_SIZE(exp_vertices16);
7341     /* Test 17. Weld texture coordinates but as SHORT2 instead of D3DXVECTOR2.*/
7342     const struct vertex_texcoord_short2 vertices17[] =
7343     {
7344         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7345         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7346         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7347 
7348         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7349         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7350         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7351     };
7352     const DWORD indices17[] = {0, 1, 2, 3, 4, 5};
7353     const DWORD attributes17[] = {0, 0};
7354     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
7355     const UINT num_faces17 = ARRAY_SIZE(indices17) / VERTS_PER_FACE;
7356     DWORD flags17 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7357     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};
7358     const DWORD adjacency17[] = {-1, 1, -1, -1, -1, 0};
7359     const struct vertex_texcoord_short2 exp_vertices17[] =
7360     {
7361         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7362         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7363         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7364 
7365         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7366         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7367     };
7368     const DWORD exp_indices17[] = {0, 1, 2, 3, 4, 2};
7369     const DWORD exp_face_remap17[] = {0, 1};
7370     const DWORD exp_vertex_remap17[] = {0, 1, 2, 3, 4, -1};
7371     const DWORD exp_new_num_vertices17 = ARRAY_SIZE(exp_vertices17);
7372     /* Test 18. Weld texture coordinates but as SHORT2N instead of D3DXVECTOR2. */
7373     const struct vertex_texcoord_short2 vertices18[] =
7374     {
7375         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7376         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7377         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7378 
7379         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7380         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7381         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7382     };
7383     const DWORD indices18[] = {0, 1, 2, 3, 4, 5};
7384     const DWORD attributes18[] = {0, 0};
7385     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
7386     const UINT num_faces18 = ARRAY_SIZE(indices18) / VERTS_PER_FACE;
7387     DWORD flags18 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7388     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};
7389     const DWORD adjacency18[] = {-1, 1, -1, -1, -1, 0};
7390     const struct vertex_texcoord_short2 exp_vertices18[] =
7391     {
7392         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7393         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7394         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7395 
7396         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7397         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7398     };
7399     const DWORD exp_indices18[] = {0, 1, 2, 3, 4, 2};
7400     const DWORD exp_face_remap18[] = {0, 1};
7401     const DWORD exp_vertex_remap18[] = {0, 1, 2, 3, 4, -1};
7402     const DWORD exp_new_num_vertices18 = ARRAY_SIZE(exp_vertices18);
7403     /* Test 19.  Weld texture coordinates but as USHORT2N instead of D3DXVECTOR2. */
7404     const struct vertex_texcoord_ushort2n vertices19[] =
7405     {
7406         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7407         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7408         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7409 
7410         {{ 3.0f,  3.0f,  0.f}, {65535, 65535}},
7411         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7412         {{ 1.0f,  0.0f,  0.f}, {65534, 65534}},
7413     };
7414     const DWORD indices19[] = {0, 1, 2, 3, 4, 5};
7415     const DWORD attributes19[] = {0, 0};
7416     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
7417     const UINT num_faces19 = ARRAY_SIZE(indices19) / VERTS_PER_FACE;
7418     DWORD flags19 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7419     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};
7420     const DWORD adjacency19[] = {-1, 1, -1, -1, -1, 0};
7421     const struct vertex_texcoord_ushort2n exp_vertices19[] =
7422     {
7423         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7424         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7425         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7426 
7427         {{ 2.0f,  3.0f,  0.f}, {65535, 65535}},
7428         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7429     };
7430     const DWORD exp_indices19[] = {0, 1, 2, 3, 4, 2};
7431     const DWORD exp_face_remap19[] = {0, 1};
7432     const DWORD exp_vertex_remap19[] = {0, 1, 2, 3, 4, -1};
7433     const DWORD exp_new_num_vertices19 = ARRAY_SIZE(exp_vertices19);
7434     /* Test 20.  Weld normal as SHORT4 instead of D3DXVECTOR3. */
7435     const struct vertex_normal_short4 vertices20[] =
7436     {
7437         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7438         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7439         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7440 
7441         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7442         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7443         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7444     };
7445     const DWORD indices20[] = {0, 1, 2, 3, 4, 5};
7446     const DWORD attributes20[] = {0, 0};
7447     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
7448     const UINT num_faces20 = ARRAY_SIZE(indices20) / VERTS_PER_FACE;
7449     DWORD flags20 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7450     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};
7451     const DWORD adjacency20[] = {-1, 1, -1, -1, -1, 0};
7452     const struct vertex_normal_short4 exp_vertices20[] =
7453     {
7454         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7455         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7456         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7457 
7458         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7459         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7460     };
7461     const DWORD exp_indices20[] = {0, 1, 2, 3, 4, 2};
7462     const DWORD exp_face_remap20[] = {0, 1};
7463     const DWORD exp_vertex_remap20[] = {0, 1, 2, 3, 4, -1};
7464     const DWORD exp_new_num_vertices20 = ARRAY_SIZE(exp_vertices20);
7465     /* Test 21.  Weld normal as SHORT4N instead of D3DXVECTOR3. */
7466     const struct vertex_normal_short4 vertices21[] =
7467     {
7468         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7469         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7470         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7471 
7472         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7473         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7474         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7475     };
7476     const DWORD indices21[] = {0, 1, 2, 3, 4, 5};
7477     const DWORD attributes21[] = {0, 0};
7478     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
7479     const UINT num_faces21 = ARRAY_SIZE(indices21) / VERTS_PER_FACE;
7480     DWORD flags21 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7481     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};
7482     const DWORD adjacency21[] = {-1, 1, -1, -1, -1, 0};
7483     const struct vertex_normal_short4 exp_vertices21[] =
7484     {
7485         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7486         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7487         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7488 
7489         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7490         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7491     };
7492     const DWORD exp_indices21[] = {0, 1, 2, 3, 4, 2};
7493     const DWORD exp_face_remap21[] = {0, 1};
7494     const DWORD exp_vertex_remap21[] = {0, 1, 2, 3, 4, -1};
7495     const DWORD exp_new_num_vertices21 = ARRAY_SIZE(exp_vertices21);
7496     /* Test 22.  Weld normal as USHORT4N instead of D3DXVECTOR3. */
7497     const struct vertex_normal_short4 vertices22[] =
7498     {
7499         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7500         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7501         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7502 
7503         {{ 3.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7504         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7505         {{ 1.0f,  0.0f,  0.f}, {65534, 65534, 65534, 65534}},
7506     };
7507     const DWORD indices22[] = {0, 1, 2, 3, 4, 5};
7508     const DWORD attributes22[] = {0, 0};
7509     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
7510     const UINT num_faces22 = ARRAY_SIZE(indices22) / VERTS_PER_FACE;
7511     DWORD flags22 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7512     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};
7513     const DWORD adjacency22[] = {-1, 1, -1, -1, -1, 0};
7514     const struct vertex_normal_short4 exp_vertices22[] =
7515     {
7516         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7517         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7518         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7519 
7520         {{ 2.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7521         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7522     };
7523     const DWORD exp_indices22[] = {0, 1, 2, 3, 4, 2};
7524     const DWORD exp_face_remap22[] = {0, 1};
7525     const DWORD exp_vertex_remap22[] = {0, 1, 2, 3, 4, -1};
7526     const DWORD exp_new_num_vertices22 = ARRAY_SIZE(exp_vertices22);
7527     /* Test 23. Weld texture coordinates as FLOAT16_2. Similar to test 11, but
7528      * with texture coordinates converted to float16 in hex. */
7529     const struct vertex_texcoord_float16_2 vertices23[] =
7530     {
7531         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7532         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7533         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7534 
7535         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
7536         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7537         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7538     };
7539     const DWORD indices23[] = {0, 1, 2, 3, 4, 5};
7540     const DWORD attributes23[] = {0, 0};
7541     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
7542     const UINT num_faces23 = ARRAY_SIZE(indices23) / VERTS_PER_FACE;
7543     DWORD flags23 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7544     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};
7545     const DWORD adjacency23[] = {-1, 1, -1, -1, -1, 0};
7546     const struct vertex_texcoord_float16_2 exp_vertices23[] =
7547     {
7548         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7549         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7550         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7551 
7552         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7553         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7554     };
7555     const DWORD exp_indices23[] = {0, 1, 2, 1, 3, 4};
7556     const DWORD exp_face_remap23[] = {0, 1};
7557     const DWORD exp_vertex_remap23[] = {0, 1, 2, 4, 5, -1};
7558     const DWORD exp_new_num_vertices23 = ARRAY_SIZE(exp_vertices23);
7559     /* Test 24. Weld texture coordinates as FLOAT16_4. Similar to test 24. */
7560     const struct vertex_texcoord_float16_4 vertices24[] =
7561     {
7562         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7563         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7564         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7565 
7566         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0x3266, 0x34cd}},
7567         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7568         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7569     };
7570     const DWORD indices24[] = {0, 1, 2, 3, 4, 5};
7571     const DWORD attributes24[] = {0, 0};
7572     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
7573     const UINT num_faces24 = ARRAY_SIZE(indices24) / VERTS_PER_FACE;
7574     DWORD flags24 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7575     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};
7576     const DWORD adjacency24[] = {-1, 1, -1, -1, -1, 0};
7577     const struct vertex_texcoord_float16_4 exp_vertices24[] =
7578     {
7579         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7580         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7581         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7582 
7583         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7584         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7585     };
7586     const DWORD exp_indices24[] = {0, 1, 2, 1, 3, 4};
7587     const DWORD exp_face_remap24[] = {0, 1};
7588     const DWORD exp_vertex_remap24[] = {0, 1, 2, 4, 5, -1};
7589     const DWORD exp_new_num_vertices24 = ARRAY_SIZE(exp_vertices24);
7590     /* Test 25. Weld texture coordinates with usage index 10 (TEXCOORD10). The
7591      * usage index is capped at 7, so the epsilon for TEXCOORD7 is used instead.
7592      */
7593     const struct vertex_texcoord vertices25[] =
7594     {
7595         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7596         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7597         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7598 
7599         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7600         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7601         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7602     };
7603     const DWORD indices25[] = {0, 1, 2, 3, 4, 5};
7604     const DWORD attributes25[] = {0, 0};
7605     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
7606     const UINT num_faces25 = ARRAY_SIZE(indices25) / VERTS_PER_FACE;
7607     DWORD flags25 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7608     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};
7609     const DWORD adjacency25[] = {-1, 1, -1, -1, -1, 0};
7610     const struct vertex_texcoord exp_vertices25[] =
7611     {
7612         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7613         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7614         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7615 
7616         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7617         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7618     };
7619     const DWORD exp_indices25[] = {0, 1, 2, 1, 3, 4};
7620     const DWORD exp_face_remap25[] = {0, 1};
7621     const DWORD exp_vertex_remap25[] = {0, 1, 2, 4, 5, -1};
7622     const DWORD exp_new_num_vertices25 = ARRAY_SIZE(exp_vertices25);
7623     /* Test 26. Weld color with usage index larger than 1. Shows that none of
7624      * the epsilon values are used. */
7625     const struct vertex_color vertices26[] =
7626     {
7627         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7628         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7629         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7630 
7631         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7632         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7633         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7634     };
7635     const DWORD indices26[] = {0, 1, 2, 3, 4, 5};
7636     const DWORD attributes26[] = {0, 0};
7637     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
7638     const UINT num_faces26 = ARRAY_SIZE(indices26) / VERTS_PER_FACE;
7639     DWORD flags26 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7640     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};
7641     const DWORD adjacency26[] = {-1, 1, -1, -1, -1, 0};
7642     const struct vertex_color exp_vertices26[] =
7643     {
7644         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7645         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7646         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7647 
7648         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7649         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7650         {{ 0.0f,  0.0f,  0.f}, 0x01010101},
7651     };
7652     const DWORD exp_indices26[] = {0, 1, 2, 3, 4, 5};
7653     const DWORD exp_face_remap26[] = {0, 1};
7654     const DWORD exp_vertex_remap26[] = {0, 1, 2, 3, 4, 5};
7655     const DWORD exp_new_num_vertices26 = ARRAY_SIZE(exp_vertices26);
7656     /* Test 27. Weld color with usage index 1 (specular). */
7657     /* Previously this test used float color values and index > 1 but that case
7658      * appears to be effectively unhandled in native so the test gave
7659      * inconsistent results. */
7660     const struct vertex_color vertices27[] =
7661     {
7662         {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
7663         {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
7664         {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
7665 
7666         {{ 3.0f,  3.0f,  0.0f}, 0x11213141},
7667         {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
7668         {{ 1.0f,  0.0f,  0.0f}, 0x51617181},
7669     };
7670     const DWORD indices27[] = {0, 1, 2, 3, 4, 5};
7671     const DWORD attributes27[] = {0, 0};
7672     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
7673     const UINT num_faces27 = ARRAY_SIZE(indices27) / VERTS_PER_FACE;
7674     DWORD flags27 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7675     const D3DXWELDEPSILONS epsilons27 =
7676     {
7677         1.1f, 0.0f, 0.0f, 0.0f, 2.0f / 255.0f, 0.0f,
7678         {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f
7679     };
7680     const DWORD adjacency27[] = {-1, 1, -1, -1, -1, 0};
7681     const struct vertex_color exp_vertices27[] =
7682     {
7683         {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
7684         {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
7685         {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
7686 
7687         {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
7688     };
7689     const DWORD exp_indices27[] = {0, 1, 2, 1, 3, 2};
7690     const DWORD exp_face_remap27[] = {0, 1};
7691     const DWORD exp_vertex_remap27[] = {0, 1, 2, 4, -1, -1};
7692     const DWORD exp_new_num_vertices27 = ARRAY_SIZE(exp_vertices27);
7693     /* Test 28. Weld one normal with UDEC3. */
7694     const DWORD dword_udec3_zero = init_udec3_dword(0, 0, 0, 1);
7695     const DWORD dword_udec3_1023 = init_udec3_dword(1023, 1023, 1023, 1);
7696     const DWORD dword_udec3_1022 = init_udec3_dword(1022, 1022, 1022, 1);
7697     const struct vertex_normal_udec3 vertices28[] =
7698     {
7699         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7700         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7701         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7702 
7703         {{ 3.0f,  3.0f,  0.f}, dword_udec3_1023},
7704         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7705         {{ 1.0f,  0.0f,  0.f}, dword_udec3_1022},
7706     };
7707     const DWORD indices28[] = {0, 1, 2, 3, 4, 5};
7708     const DWORD attributes28[] = {0, 0};
7709     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
7710     const UINT num_faces28 = ARRAY_SIZE(indices28) / VERTS_PER_FACE;
7711     DWORD flags28 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7712     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};
7713     const DWORD adjacency28[] = {-1, 1, -1, -1, -1, 0};
7714     const struct vertex_normal_udec3 exp_vertices28[] =
7715     {
7716         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7717         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7718         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7719 
7720         {{ 2.0f,  3.0f,  0.f}, dword_udec3_1023},
7721         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7722     };
7723     const DWORD exp_indices28[] = {0, 1, 2, 3, 4, 2};
7724     const DWORD exp_face_remap28[] = {0, 1};
7725     const DWORD exp_vertex_remap28[] = {0, 1, 2, 3, 4, -1};
7726     const DWORD exp_new_num_vertices28 = ARRAY_SIZE(exp_vertices28);
7727     /* Test 29. Weld one normal with DEC3N. */
7728     const DWORD dword_dec3n_zero = init_dec3n_dword(0, 0, 0, 1);
7729     const DWORD dword_dec3n_511 = init_dec3n_dword(511, 511, 511, 1);
7730     const DWORD dword_dec3n_510 = init_dec3n_dword(510, 510, 510, 1);
7731     const struct vertex_normal_dec3n vertices29[] =
7732     {
7733         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7734         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7735         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7736 
7737         {{ 3.0f,  3.0f,  0.f}, dword_dec3n_511},
7738         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7739         {{ 1.0f,  0.0f,  0.f}, dword_dec3n_510},
7740     };
7741     const DWORD indices29[] = {0, 1, 2, 3, 4, 5};
7742     const DWORD attributes29[] = {0, 0};
7743     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
7744     const UINT num_faces29 = ARRAY_SIZE(indices29) / VERTS_PER_FACE;
7745     DWORD flags29 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7746     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};
7747     const DWORD adjacency29[] = {-1, 1, -1, -1, -1, 0};
7748     const struct vertex_normal_dec3n exp_vertices29[] =
7749     {
7750         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7751         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7752         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7753 
7754         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_511},
7755         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7756     };
7757     const DWORD exp_indices29[] = {0, 1, 2, 3, 4, 2};
7758     const DWORD exp_face_remap29[] = {0, 1};
7759     const DWORD exp_vertex_remap29[] = {0, 1, 2, 3, 4, -1};
7760     const DWORD exp_new_num_vertices29 = ARRAY_SIZE(exp_vertices29);
7761     /* All mesh data */
7762     DWORD *adjacency_out = NULL;
7763     DWORD *face_remap = NULL;
7764     ID3DXMesh *mesh = NULL;
7765     ID3DXBuffer *vertex_remap = NULL;
7766     struct
7767     {
7768         const BYTE *vertices;
7769         const DWORD *indices;
7770         const DWORD *attributes;
7771         const DWORD num_vertices;
7772         const DWORD num_faces;
7773         const DWORD options;
7774         D3DVERTEXELEMENT9 *declaration;
7775         const UINT vertex_size;
7776         const DWORD flags;
7777         const D3DXWELDEPSILONS *epsilons;
7778         const DWORD *adjacency;
7779         const BYTE *exp_vertices;
7780         const DWORD *exp_indices;
7781         const DWORD *exp_face_remap;
7782         const DWORD *exp_vertex_remap;
7783         const DWORD exp_new_num_vertices;
7784     }
7785     tc[] =
7786     {
7787         {
7788             (BYTE*)vertices0,
7789             indices0,
7790             attributes0,
7791             num_vertices0,
7792             num_faces0,
7793             options,
7794             declaration_normal,
7795             vertex_size_normal,
7796             flags0,
7797             NULL,
7798             adjacency0,
7799             (BYTE*)exp_vertices0,
7800             exp_indices0,
7801             exp_face_remap0,
7802             exp_vertex_remap0,
7803             exp_new_num_vertices0
7804         },
7805         {
7806             (BYTE*)vertices1,
7807             indices1,
7808             attributes1,
7809             num_vertices1,
7810             num_faces1,
7811             options,
7812             declaration_normal,
7813             vertex_size_normal,
7814             flags1,
7815             NULL,
7816             adjacency1,
7817             (BYTE*)exp_vertices1,
7818             exp_indices1,
7819             exp_face_remap1,
7820             exp_vertex_remap1,
7821             exp_new_num_vertices1
7822         },
7823         {
7824             (BYTE*)vertices2,
7825             indices2,
7826             attributes2,
7827             num_vertices2,
7828             num_faces2,
7829             options,
7830             declaration_normal,
7831             vertex_size_normal,
7832             flags2,
7833             &epsilons2,
7834             adjacency2,
7835             (BYTE*)exp_vertices2,
7836             exp_indices2,
7837             exp_face_remap2,
7838             exp_vertex_remap2,
7839             exp_new_num_vertices2
7840         },
7841         {
7842             (BYTE*)vertices3,
7843             indices3,
7844             attributes3,
7845             num_vertices3,
7846             num_faces3,
7847             options,
7848             declaration_normal,
7849             vertex_size_normal,
7850             flags3,
7851             &epsilons3,
7852             adjacency3,
7853             (BYTE*)exp_vertices3,
7854             exp_indices3,
7855             exp_face_remap3,
7856             exp_vertex_remap3,
7857             exp_new_num_vertices3
7858         },
7859         {
7860             (BYTE*)vertices4,
7861             indices4,
7862             attributes4,
7863             num_vertices4,
7864             num_faces4,
7865             options,
7866             declaration_normal,
7867             vertex_size_normal,
7868             flags4,
7869             &epsilons4,
7870             adjacency4,
7871             (BYTE*)exp_vertices4,
7872             exp_indices4,
7873             exp_face_remap4,
7874             exp_vertex_remap4,
7875             exp_new_num_vertices4
7876         },
7877         /* Unusual ordering. */
7878         {
7879             (BYTE*)vertices5,
7880             indices5,
7881             attributes5,
7882             num_vertices5,
7883             num_faces5,
7884             options,
7885             declaration_normal,
7886             vertex_size_normal,
7887             flags5,
7888             NULL,
7889             adjacency5,
7890             (BYTE*)exp_vertices5,
7891             exp_indices5,
7892             exp_face_remap5,
7893             exp_vertex_remap5,
7894             exp_new_num_vertices5
7895         },
7896         {
7897             (BYTE*)vertices6,
7898             indices6,
7899             attributes6,
7900             num_vertices6,
7901             num_faces6,
7902             options,
7903             declaration_normal,
7904             vertex_size_normal,
7905             flags6,
7906             &epsilons6,
7907             adjacency6,
7908             (BYTE*)exp_vertices6,
7909             exp_indices6,
7910             exp_face_remap6,
7911             exp_vertex_remap6,
7912             exp_new_num_vertices6
7913         },
7914         {
7915             (BYTE*)vertices6,
7916             (DWORD*)indices6_16bit,
7917             attributes6,
7918             num_vertices6,
7919             num_faces6,
7920             options_16bit,
7921             declaration_normal,
7922             vertex_size_normal,
7923             flags6,
7924             &epsilons6,
7925             adjacency6,
7926             (BYTE*)exp_vertices6,
7927             exp_indices6,
7928             exp_face_remap6,
7929             exp_vertex_remap6,
7930             exp_new_num_vertices6
7931         },
7932         {
7933             (BYTE*)vertices8,
7934             indices8,
7935             attributes8,
7936             num_vertices8,
7937             num_faces8,
7938             options,
7939             declaration_normal,
7940             vertex_size_normal,
7941             flags8,
7942             &epsilons8,
7943             adjacency8,
7944             (BYTE*)exp_vertices8,
7945             exp_indices8,
7946             exp_face_remap8,
7947             exp_vertex_remap8,
7948             exp_new_num_vertices8
7949         },
7950         {
7951             (BYTE*)vertices9,
7952             indices9,
7953             attributes9,
7954             num_vertices9,
7955             num_faces9,
7956             options,
7957             declaration_normal,
7958             vertex_size_normal,
7959             flags9,
7960             &epsilons9,
7961             adjacency9,
7962             (BYTE*)exp_vertices9,
7963             exp_indices9,
7964             exp_face_remap9,
7965             exp_vertex_remap9,
7966             exp_new_num_vertices9
7967         },
7968         {
7969             (BYTE*)vertices10,
7970             indices10,
7971             attributes10,
7972             num_vertices10,
7973             num_faces10,
7974             options,
7975             declaration_blendweight,
7976             vertex_size_blendweight,
7977             flags10,
7978             &epsilons10,
7979             adjacency10,
7980             (BYTE*)exp_vertices10,
7981             exp_indices10,
7982             exp_face_remap10,
7983             exp_vertex_remap10,
7984             exp_new_num_vertices10
7985         },
7986         {
7987             (BYTE*)vertices11,
7988             indices11,
7989             attributes11,
7990             num_vertices11,
7991             num_faces11,
7992             options,
7993             declaration_texcoord,
7994             vertex_size_texcoord,
7995             flags11,
7996             &epsilons11,
7997             adjacency11,
7998             (BYTE*)exp_vertices11,
7999             exp_indices11,
8000             exp_face_remap11,
8001             exp_vertex_remap11,
8002             exp_new_num_vertices11
8003         },
8004         {
8005             (BYTE*)vertices12,
8006             indices12,
8007             attributes12,
8008             num_vertices12,
8009             num_faces12,
8010             options,
8011             declaration_color,
8012             vertex_size_color,
8013             flags12,
8014             &epsilons12,
8015             adjacency12,
8016             (BYTE*)exp_vertices12,
8017             exp_indices12,
8018             exp_face_remap12,
8019             exp_vertex_remap12,
8020             exp_new_num_vertices12
8021         },
8022         {
8023             (BYTE*)vertices13,
8024             indices13,
8025             attributes13,
8026             num_vertices13,
8027             num_faces13,
8028             options,
8029             declaration_normal3,
8030             vertex_size_normal,
8031             flags13,
8032             &epsilons13,
8033             adjacency13,
8034             (BYTE*)exp_vertices13,
8035             exp_indices13,
8036             exp_face_remap13,
8037             exp_vertex_remap13,
8038             exp_new_num_vertices13
8039         },
8040         {
8041             (BYTE*)vertices14,
8042             indices14,
8043             attributes14,
8044             num_vertices14,
8045             num_faces14,
8046             options,
8047             declaration_color,
8048             vertex_size_color,
8049             flags14,
8050             &epsilons14,
8051             adjacency14,
8052             (BYTE*)exp_vertices14,
8053             exp_indices14,
8054             exp_face_remap14,
8055             exp_vertex_remap14,
8056             exp_new_num_vertices14
8057         },
8058         {
8059             (BYTE*)vertices15,
8060             indices15,
8061             attributes15,
8062             num_vertices15,
8063             num_faces15,
8064             options,
8065             declaration_color_ubyte4n,
8066             vertex_size_color_ubyte4, /* UBYTE4 same size as UBYTE4N */
8067             flags15,
8068             &epsilons15,
8069             adjacency15,
8070             (BYTE*)exp_vertices15,
8071             exp_indices15,
8072             exp_face_remap15,
8073             exp_vertex_remap15,
8074             exp_new_num_vertices15
8075         },
8076         {
8077             (BYTE*)vertices16,
8078             indices16,
8079             attributes16,
8080             num_vertices16,
8081             num_faces16,
8082             options,
8083             declaration_color_ubyte4,
8084             vertex_size_color_ubyte4,
8085             flags16,
8086             &epsilons16,
8087             adjacency16,
8088             (BYTE*)exp_vertices16,
8089             exp_indices16,
8090             exp_face_remap16,
8091             exp_vertex_remap16,
8092             exp_new_num_vertices16
8093         },
8094         {
8095             (BYTE*)vertices17,
8096             indices17,
8097             attributes17,
8098             num_vertices17,
8099             num_faces17,
8100             options,
8101             declaration_texcoord_short2,
8102             vertex_size_texcoord_short2,
8103             flags17,
8104             &epsilons17,
8105             adjacency17,
8106             (BYTE*)exp_vertices17,
8107             exp_indices17,
8108             exp_face_remap17,
8109             exp_vertex_remap17,
8110             exp_new_num_vertices17
8111         },
8112         {
8113             (BYTE*)vertices18,
8114             indices18,
8115             attributes18,
8116             num_vertices18,
8117             num_faces18,
8118             options,
8119             declaration_texcoord_short2n,
8120             vertex_size_texcoord_short2, /* SHORT2 same size as SHORT2N */
8121             flags18,
8122             &epsilons18,
8123             adjacency18,
8124             (BYTE*)exp_vertices18,
8125             exp_indices18,
8126             exp_face_remap18,
8127             exp_vertex_remap18,
8128             exp_new_num_vertices18
8129         },
8130         {
8131             (BYTE*)vertices19,
8132             indices19,
8133             attributes19,
8134             num_vertices19,
8135             num_faces19,
8136             options,
8137             declaration_texcoord_ushort2n,
8138             vertex_size_texcoord_short2, /* SHORT2 same size as USHORT2N */
8139             flags19,
8140             &epsilons19,
8141             adjacency19,
8142             (BYTE*)exp_vertices19,
8143             exp_indices19,
8144             exp_face_remap19,
8145             exp_vertex_remap19,
8146             exp_new_num_vertices19
8147         },
8148         {
8149             (BYTE*)vertices20,
8150             indices20,
8151             attributes20,
8152             num_vertices20,
8153             num_faces20,
8154             options,
8155             declaration_normal_short4,
8156             vertex_size_normal_short4,
8157             flags20,
8158             &epsilons20,
8159             adjacency20,
8160             (BYTE*)exp_vertices20,
8161             exp_indices20,
8162             exp_face_remap20,
8163             exp_vertex_remap20,
8164             exp_new_num_vertices20
8165         },
8166         {
8167             (BYTE*)vertices21,
8168             indices21,
8169             attributes21,
8170             num_vertices21,
8171             num_faces21,
8172             options,
8173             declaration_normal_short4n,
8174             vertex_size_normal_short4, /* SHORT4 same size as SHORT4N */
8175             flags21,
8176             &epsilons21,
8177             adjacency21,
8178             (BYTE*)exp_vertices21,
8179             exp_indices21,
8180             exp_face_remap21,
8181             exp_vertex_remap21,
8182             exp_new_num_vertices21
8183         },
8184         {
8185             (BYTE*)vertices22,
8186             indices22,
8187             attributes22,
8188             num_vertices22,
8189             num_faces22,
8190             options,
8191             declaration_normal_ushort4n,
8192             vertex_size_normal_short4, /* SHORT4 same size as USHORT4N */
8193             flags22,
8194             &epsilons22,
8195             adjacency22,
8196             (BYTE*)exp_vertices22,
8197             exp_indices22,
8198             exp_face_remap22,
8199             exp_vertex_remap22,
8200             exp_new_num_vertices22
8201         },
8202         {
8203             (BYTE*)vertices23,
8204             indices23,
8205             attributes23,
8206             num_vertices23,
8207             num_faces23,
8208             options,
8209             declaration_texcoord_float16_2,
8210             vertex_size_texcoord_float16_2,
8211             flags23,
8212             &epsilons23,
8213             adjacency23,
8214             (BYTE*)exp_vertices23,
8215             exp_indices23,
8216             exp_face_remap23,
8217             exp_vertex_remap23,
8218             exp_new_num_vertices23
8219         },
8220         {
8221             (BYTE*)vertices24,
8222             indices24,
8223             attributes24,
8224             num_vertices24,
8225             num_faces24,
8226             options,
8227             declaration_texcoord_float16_4,
8228             vertex_size_texcoord_float16_4,
8229             flags24,
8230             &epsilons24,
8231             adjacency24,
8232             (BYTE*)exp_vertices24,
8233             exp_indices24,
8234             exp_face_remap24,
8235             exp_vertex_remap24,
8236             exp_new_num_vertices24
8237         },
8238         {
8239             (BYTE*)vertices25,
8240             indices25,
8241             attributes25,
8242             num_vertices25,
8243             num_faces25,
8244             options,
8245             declaration_texcoord10,
8246             vertex_size_texcoord,
8247             flags25,
8248             &epsilons25,
8249             adjacency25,
8250             (BYTE*)exp_vertices25,
8251             exp_indices25,
8252             exp_face_remap25,
8253             exp_vertex_remap25,
8254             exp_new_num_vertices25
8255         },
8256         {
8257             (BYTE*)vertices26,
8258             indices26,
8259             attributes26,
8260             num_vertices26,
8261             num_faces26,
8262             options,
8263             declaration_color2,
8264             vertex_size_color,
8265             flags26,
8266             &epsilons26,
8267             adjacency26,
8268             (BYTE*)exp_vertices26,
8269             exp_indices26,
8270             exp_face_remap26,
8271             exp_vertex_remap26,
8272             exp_new_num_vertices26
8273         },
8274         {
8275             (BYTE*)vertices27,
8276             indices27,
8277             attributes27,
8278             num_vertices27,
8279             num_faces27,
8280             options,
8281             declaration_color1,
8282             vertex_size_color,
8283             flags27,
8284             &epsilons27,
8285             adjacency27,
8286             (BYTE*)exp_vertices27,
8287             exp_indices27,
8288             exp_face_remap27,
8289             exp_vertex_remap27,
8290             exp_new_num_vertices27
8291         },
8292         {
8293             (BYTE*)vertices28,
8294             indices28,
8295             attributes28,
8296             num_vertices28,
8297             num_faces28,
8298             options,
8299             declaration_normal_udec3,
8300             vertex_size_normal_udec3,
8301             flags28,
8302             &epsilons28,
8303             adjacency28,
8304             (BYTE*)exp_vertices28,
8305             exp_indices28,
8306             exp_face_remap28,
8307             exp_vertex_remap28,
8308             exp_new_num_vertices28
8309         },
8310         {
8311             (BYTE*)vertices29,
8312             indices29,
8313             attributes29,
8314             num_vertices29,
8315             num_faces29,
8316             options,
8317             declaration_normal_dec3n,
8318             vertex_size_normal_dec3n,
8319             flags29,
8320             &epsilons29,
8321             adjacency29,
8322             (BYTE*)exp_vertices29,
8323             exp_indices29,
8324             exp_face_remap29,
8325             exp_vertex_remap29,
8326             exp_new_num_vertices29
8327         }
8328     };
8329 #ifdef __REACTOS__
8330 #undef up
8331 #endif
8332 
8333     test_context = new_test_context();
8334     if (!test_context)
8335     {
8336         skip("Couldn't create test context\n");
8337         goto cleanup;
8338     }
8339 
8340     for (i = 0; i < ARRAY_SIZE(tc); i++)
8341     {
8342         DWORD j;
8343         DWORD *vertex_remap_ptr;
8344         DWORD new_num_vertices;
8345 
8346         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
8347                             tc[i].declaration, test_context->device, &mesh,
8348                             tc[i].vertices, tc[i].vertex_size,
8349                             tc[i].indices, tc[i].attributes);
8350         if (FAILED(hr))
8351         {
8352             skip("Couldn't initialize test mesh %d.\n", i);
8353             goto cleanup;
8354         }
8355 
8356         /* Allocate out parameters */
8357         adjacency_out = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency_out));
8358         if (!adjacency_out)
8359         {
8360             skip("Couldn't allocate adjacency_out array.\n");
8361             goto cleanup;
8362         }
8363         face_remap = HeapAlloc(GetProcessHeap(), 0, tc[i].num_faces * sizeof(*face_remap));
8364         if (!face_remap)
8365         {
8366             skip("Couldn't allocate face_remap array.\n");
8367             goto cleanup;
8368         }
8369 
8370         hr = D3DXWeldVertices(mesh, tc[i].flags, tc[i].epsilons, tc[i].adjacency,
8371                               adjacency_out, face_remap, &vertex_remap);
8372         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
8373         /* Check number of vertices*/
8374         new_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
8375         ok(new_num_vertices == tc[i].exp_new_num_vertices,
8376            "Mesh %d: new_num_vertices == %d, expected %d.\n",
8377            i, new_num_vertices, tc[i].exp_new_num_vertices);
8378         /* Check index buffer */
8379         if (tc[i].options & D3DXMESH_32BIT)
8380         {
8381             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices);
8382             if (FAILED(hr))
8383             {
8384                 skip("Couldn't lock index buffer.\n");
8385                 goto cleanup;
8386             }
8387             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8388             {
8389                 ok(indices[j] == tc[i].exp_indices[j],
8390                    "Mesh %d: indices[%d] == %d, expected %d\n",
8391                    i, j, indices[j], tc[i].exp_indices[j]);
8392             }
8393         }
8394         else
8395         {
8396             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices_16bit);
8397             if (FAILED(hr))
8398             {
8399                 skip("Couldn't lock index buffer.\n");
8400                 goto cleanup;
8401             }
8402             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8403             {
8404                 ok(indices_16bit[j] == tc[i].exp_indices[j],
8405                    "Mesh %d: indices_16bit[%d] == %d, expected %d\n",
8406                    i, j, indices_16bit[j], tc[i].exp_indices[j]);
8407             }
8408         }
8409         mesh->lpVtbl->UnlockIndexBuffer(mesh);
8410         indices = NULL;
8411         indices_16bit = NULL;
8412         /* Check adjacency_out */
8413         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8414         {
8415             ok(adjacency_out[j] == tc[i].adjacency[j],
8416                "Mesh %d: adjacency_out[%d] == %d, expected %d\n",
8417                i, j, adjacency_out[j], tc[i].adjacency[j]);
8418         }
8419         /* Check face_remap */
8420         for (j = 0; j < tc[i].num_faces; j++)
8421         {
8422             ok(face_remap[j] == tc[i].exp_face_remap[j],
8423                "Mesh %d: face_remap[%d] == %d, expected %d\n",
8424                i, j, face_remap[j], tc[i].exp_face_remap[j]);
8425         }
8426         /* Check vertex_remap */
8427         vertex_remap_ptr = vertex_remap->lpVtbl->GetBufferPointer(vertex_remap);
8428         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8429         {
8430             ok(vertex_remap_ptr[j] == tc[i].exp_vertex_remap[j],
8431                "Mesh %d: vertex_remap_ptr[%d] == %d, expected %d\n",
8432                i, j, vertex_remap_ptr[j], tc[i].exp_vertex_remap[j]);
8433         }
8434         /* Check vertex buffer */
8435         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void*)&vertices);
8436         if (FAILED(hr))
8437         {
8438             skip("Couldn't lock vertex buffer.\n");
8439             goto cleanup;
8440         }
8441         /* Check contents of re-ordered vertex buffer */
8442         for (j = 0; j < tc[i].exp_new_num_vertices; j++)
8443         {
8444             int index = tc[i].vertex_size*j;
8445             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].declaration);
8446         }
8447         mesh->lpVtbl->UnlockVertexBuffer(mesh);
8448         vertices = NULL;
8449 
8450         /* Free mesh and output data */
8451         HeapFree(GetProcessHeap(), 0, adjacency_out);
8452         adjacency_out = NULL;
8453         HeapFree(GetProcessHeap(), 0, face_remap);
8454         face_remap = NULL;
8455         vertex_remap->lpVtbl->Release(vertex_remap);
8456         vertex_remap = NULL;
8457         mesh->lpVtbl->Release(mesh);
8458         mesh = NULL;
8459     }
8460 
8461 cleanup:
8462     HeapFree(GetProcessHeap(), 0, adjacency_out);
8463     HeapFree(GetProcessHeap(), 0, face_remap);
8464     if (indices) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8465     if (indices_16bit) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8466     if (mesh) mesh->lpVtbl->Release(mesh);
8467     if (vertex_remap) vertex_remap->lpVtbl->Release(vertex_remap);
8468     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
8469     free_test_context(test_context);
8470 }
8471 
8472 static void test_clone_mesh(void)
8473 {
8474     HRESULT hr;
8475     struct test_context *test_context = NULL;
8476     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
8477     D3DVERTEXELEMENT9 declaration_pn[] =
8478     {
8479         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8480         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8481         D3DDECL_END()
8482     };
8483     D3DVERTEXELEMENT9 declaration_pntc[] =
8484     {
8485         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8486         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8487         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8488         D3DDECL_END()
8489     };
8490     D3DVERTEXELEMENT9 declaration_ptcn[] =
8491     {
8492         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8493         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8494         {0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8495         D3DDECL_END()
8496     };
8497     D3DVERTEXELEMENT9 declaration_ptc[] =
8498     {
8499         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8500         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8501         D3DDECL_END()
8502     };
8503     D3DVERTEXELEMENT9 declaration_ptc_float16_2[] =
8504     {
8505         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8506         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8507         D3DDECL_END()
8508     };
8509     D3DVERTEXELEMENT9 declaration_ptc_float16_4[] =
8510     {
8511         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8512         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8513         D3DDECL_END()
8514     };
8515     D3DVERTEXELEMENT9 declaration_ptc_float1[] =
8516     {
8517         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8518         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8519         D3DDECL_END()
8520     };
8521     D3DVERTEXELEMENT9 declaration_ptc_float3[] =
8522     {
8523         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8524         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8525         D3DDECL_END()
8526     };
8527     D3DVERTEXELEMENT9 declaration_ptc_float4[] =
8528     {
8529         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8530         {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8531         D3DDECL_END()
8532     };
8533     D3DVERTEXELEMENT9 declaration_ptc_d3dcolor[] =
8534     {
8535         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8536         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8537         D3DDECL_END()
8538     };
8539     D3DVERTEXELEMENT9 declaration_ptc_ubyte4[] =
8540     {
8541         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8542         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8543         D3DDECL_END()
8544     };
8545     D3DVERTEXELEMENT9 declaration_ptc_ubyte4n[] =
8546     {
8547         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8548         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8549         D3DDECL_END()
8550     };
8551     D3DVERTEXELEMENT9 declaration_ptc_short2[] =
8552     {
8553         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8554         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8555         D3DDECL_END()
8556     };
8557     D3DVERTEXELEMENT9 declaration_ptc_short4[] =
8558     {
8559         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8560         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8561         D3DDECL_END()
8562     };
8563     D3DVERTEXELEMENT9 declaration_ptc_short2n[] =
8564     {
8565         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8566         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8567         D3DDECL_END()
8568     };
8569     D3DVERTEXELEMENT9 declaration_ptc_short4n[] =
8570     {
8571         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8572         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8573         D3DDECL_END()
8574     };
8575     D3DVERTEXELEMENT9 declaration_ptc_ushort2n[] =
8576     {
8577         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8578         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8579         D3DDECL_END()
8580     };
8581     D3DVERTEXELEMENT9 declaration_ptc_ushort4n[] =
8582     {
8583         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8584         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8585         D3DDECL_END()
8586     };
8587     D3DVERTEXELEMENT9 declaration_ptc_float16_2_partialu[] =
8588     {
8589         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8590         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_PARTIALU, D3DDECLUSAGE_TEXCOORD, 0},
8591         D3DDECL_END()
8592     };
8593     D3DVERTEXELEMENT9 declaration_pntc1[] =
8594     {
8595         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8596         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8597         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
8598         D3DDECL_END()
8599     };
8600     const unsigned int VERTS_PER_FACE = 3;
8601     BYTE *vertices = NULL;
8602     INT i;
8603     struct vertex_pn
8604     {
8605         D3DXVECTOR3 position;
8606         D3DXVECTOR3 normal;
8607     };
8608     struct vertex_pntc
8609     {
8610         D3DXVECTOR3 position;
8611         D3DXVECTOR3 normal;
8612         D3DXVECTOR2 texcoords;
8613     };
8614     struct vertex_ptcn
8615     {
8616         D3DXVECTOR3 position;
8617         D3DXVECTOR2 texcoords;
8618         D3DXVECTOR3 normal;
8619     };
8620     struct vertex_ptc
8621     {
8622         D3DXVECTOR3 position;
8623         D3DXVECTOR2 texcoords;
8624     };
8625     struct vertex_ptc_float16_2
8626     {
8627         D3DXVECTOR3 position;
8628         WORD texcoords[2]; /* float16_2 */
8629     };
8630     struct vertex_ptc_float16_4
8631     {
8632         D3DXVECTOR3 position;
8633         WORD texcoords[4]; /* float16_4 */
8634     };
8635     struct vertex_ptc_float1
8636     {
8637         D3DXVECTOR3 position;
8638         FLOAT texcoords;
8639     };
8640     struct vertex_ptc_float3
8641     {
8642         D3DXVECTOR3 position;
8643         FLOAT texcoords[3];
8644     };
8645     struct vertex_ptc_float4
8646     {
8647         D3DXVECTOR3 position;
8648         FLOAT texcoords[4];
8649     };
8650     struct vertex_ptc_d3dcolor
8651     {
8652         D3DXVECTOR3 position;
8653         BYTE texcoords[4];
8654     };
8655     struct vertex_ptc_ubyte4
8656     {
8657         D3DXVECTOR3 position;
8658         BYTE texcoords[4];
8659     };
8660     struct vertex_ptc_ubyte4n
8661     {
8662         D3DXVECTOR3 position;
8663         BYTE texcoords[4];
8664     };
8665     struct vertex_ptc_short2
8666     {
8667         D3DXVECTOR3 position;
8668         SHORT texcoords[2];
8669     };
8670     struct vertex_ptc_short4
8671     {
8672         D3DXVECTOR3 position;
8673         SHORT texcoords[4];
8674     };
8675     struct vertex_ptc_ushort2n
8676     {
8677         D3DXVECTOR3 position;
8678         USHORT texcoords[2];
8679     };
8680     struct vertex_ptc_ushort4n
8681     {
8682         D3DXVECTOR3 position;
8683         USHORT texcoords[4];
8684     };
8685     struct vertex_ptc_udec3
8686     {
8687         D3DXVECTOR3 position;
8688         DWORD texcoords;
8689     };
8690     struct vertex_ptc_dec3n
8691     {
8692         D3DXVECTOR3 position;
8693         DWORD texcoords;
8694     };
8695 #ifndef __REACTOS__
8696     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
8697     D3DXVECTOR2 zero_vec2 = {0.0f, 0.0f};
8698 #else
8699 #define up {0.0f, 0.0f, 1.0f}
8700 #define zero_vec2 {0.0f, 0.0f}
8701 #endif
8702     /* Test 0. Check that a mesh can be cloned if the new declaration is the
8703      * same as the one used to create the mesh.
8704      *
8705      * 0--1 3
8706      * | / /|
8707      * |/ / |
8708      * 2 5--4
8709      */
8710     const struct vertex_pn vertices0[] =
8711     {
8712         {{ 0.0f,  3.0f,  0.f}, up},
8713         {{ 2.0f,  3.0f,  0.f}, up},
8714         {{ 0.0f,  0.0f,  0.f}, up},
8715 
8716         {{ 3.0f,  3.0f,  0.f}, up},
8717         {{ 3.0f,  0.0f,  0.f}, up},
8718         {{ 1.0f,  0.0f,  0.f}, up},
8719     };
8720     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
8721     const UINT num_faces0 = ARRAY_SIZE(vertices0) / VERTS_PER_FACE;
8722     const UINT vertex_size0 = sizeof(*vertices0);
8723     /* Test 1. Check that 16-bit indices are handled. */
8724     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
8725     /* Test 2. Check that the size of each vertex is increased and the data
8726      * moved if the new declaration adds an element after the original elements.
8727      */
8728     const struct vertex_pntc exp_vertices2[] =
8729     {
8730         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8731         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8732         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8733 
8734         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8735         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8736         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8737     };
8738     const UINT exp_vertex_size2 = sizeof(*exp_vertices2);
8739     /* Test 3. Check that the size of each vertex is increased and the data
8740      * moved if the new declaration adds an element between the original
8741      * elements.
8742      */
8743     const struct vertex_ptcn exp_vertices3[] =
8744     {
8745         {{ 0.0f,  3.0f,  0.f}, zero_vec2, up},
8746         {{ 2.0f,  3.0f,  0.f}, zero_vec2, up},
8747         {{ 0.0f,  0.0f,  0.f}, zero_vec2, up},
8748 
8749         {{ 3.0f,  3.0f,  0.f}, zero_vec2, up},
8750         {{ 3.0f,  0.0f,  0.f}, zero_vec2, up},
8751         {{ 1.0f,  0.0f,  0.f}, zero_vec2, up},
8752     };
8753     const UINT exp_vertex_size3 = sizeof(*exp_vertices3);
8754     /* Test 4. Test that data types can be converted, e.g. FLOAT2 to FLOAT16_2. */
8755     const struct vertex_ptc vertices4[] =
8756     {
8757         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8758         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8759         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8760 
8761         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8762         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8763         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8764     };
8765     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
8766     const UINT num_faces4 = ARRAY_SIZE(vertices4) / VERTS_PER_FACE;
8767     const UINT vertex_size4 = sizeof(*vertices4);
8768     const struct vertex_ptc_float16_2 exp_vertices4[] =
8769     {
8770         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8771         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
8772         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
8773 
8774         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
8775         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8776         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
8777     };
8778     const UINT exp_vertex_size4 = sizeof(*exp_vertices4);
8779     /* Test 5. Convert FLOAT2 to FLOAT16_4. */
8780     const struct vertex_ptc vertices5[] =
8781     {
8782         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8783         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8784         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8785 
8786         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8787         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8788         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8789     };
8790     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
8791     const UINT num_faces5 = ARRAY_SIZE(vertices5) / VERTS_PER_FACE;
8792     const UINT vertex_size5 = sizeof(*vertices5);
8793     const struct vertex_ptc_float16_4 exp_vertices5[] =
8794     {
8795         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8796         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0, 0x3c00}}, /* {0.5f, 0.7f, 0.0f, 1.0f} */
8797         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0, 0x3c00}}, /* {-0.2f, -0.3f, 0.0f, 1.0f} */
8798 
8799         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0, 0x3c00}}, /* {0.2f, 0.3f, 0.0f, 1.0f} */
8800         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8801         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0, 0x3c00}}, /* {0.1f, 0.2f, 0.0f, 1.0f} */
8802     };
8803     const UINT exp_vertex_size5 = sizeof(*exp_vertices5);
8804     /* Test 6. Convert FLOAT2 to FLOAT1. */
8805     const struct vertex_ptc vertices6[] =
8806     {
8807         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8808         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8809         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8810 
8811         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8812         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8813         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8814     };
8815     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
8816     const UINT num_faces6 = ARRAY_SIZE(vertices6) / VERTS_PER_FACE;
8817     const UINT vertex_size6 = sizeof(*vertices6);
8818     const struct vertex_ptc_float1 exp_vertices6[] =
8819     {
8820         {{ 0.0f,  3.0f,  0.f},  1.0f},
8821         {{ 2.0f,  3.0f,  0.f},  0.5f},
8822         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8823 
8824         {{ 3.0f,  3.0f,  0.f},  0.2f},
8825         {{ 3.0f,  0.0f,  0.f},  1.0f},
8826         {{ 1.0f,  0.0f,  0.f},  0.1f},
8827     };
8828     const UINT exp_vertex_size6 = sizeof(*exp_vertices6);
8829     /* Test 7. Convert FLOAT2 to FLOAT3. */
8830     const struct vertex_ptc vertices7[] =
8831     {
8832         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8833         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8834         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8835 
8836         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8837         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8838         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8839     };
8840     const UINT num_vertices7 = ARRAY_SIZE(vertices7);
8841     const UINT num_faces7 = ARRAY_SIZE(vertices7) / VERTS_PER_FACE;
8842     const UINT vertex_size7 = sizeof(*vertices7);
8843     const struct vertex_ptc_float3 exp_vertices7[] =
8844     {
8845         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8846         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f}},
8847         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f}},
8848 
8849         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f}},
8850         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8851         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f}},
8852     };
8853     const UINT exp_vertex_size7 = sizeof(*exp_vertices7);
8854     /* Test 8. Convert FLOAT2 to FLOAT4. */
8855     const struct vertex_ptc vertices8[] =
8856     {
8857         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8858         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8859         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8860 
8861         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8862         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8863         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8864     };
8865     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
8866     const UINT num_faces8 = ARRAY_SIZE(vertices8) / VERTS_PER_FACE;
8867     const UINT vertex_size8 = sizeof(*vertices8);
8868     const struct vertex_ptc_float4 exp_vertices8[] =
8869     {
8870         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
8871         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f, 1.0f}},
8872         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f, 1.0f}},
8873 
8874         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f, 1.0f}},
8875         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
8876         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f, 1.0f}},
8877     };
8878     const UINT exp_vertex_size8 = sizeof(*exp_vertices8);
8879     /* Test 9. Convert FLOAT2 to D3DCOLOR. */
8880     const struct vertex_ptc vertices9[] =
8881     {
8882         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8883         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8884         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.6f}},
8885 
8886         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8887         {{ 3.0f,  0.0f,  0.f}, { 2.0f, 256.0f}},
8888         {{ 1.0f,  0.0f,  0.f}, { 0.11f,  0.2f}},
8889     };
8890     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
8891     const UINT num_faces9 = ARRAY_SIZE(vertices9) / VERTS_PER_FACE;
8892     const UINT vertex_size9 = sizeof(*vertices9);
8893     const struct vertex_ptc_d3dcolor exp_vertices9[] =
8894     {
8895         {{ 0.0f,  3.0f,  0.f}, {0, 255, 255, 255}},
8896         {{ 2.0f,  3.0f,  0.f}, {0, 179, 128, 255}},
8897         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
8898 
8899         {{ 3.0f,  3.0f,  0.f}, {0, 77, 51, 255}},
8900         {{ 3.0f,  0.0f,  0.f}, {0, 255, 255, 255}},
8901         {{ 1.0f,  0.0f,  0.f}, {0, 51, 28, 255}},
8902     };
8903     const UINT exp_vertex_size9 = sizeof(*exp_vertices9);
8904     /* Test 10. Convert FLOAT2 to UBYTE4. */
8905     const struct vertex_ptc vertices10[] =
8906     {
8907         {{ 0.0f,  3.0f,  0.f}, { 0.0f,  1.0f}},
8908         {{ 2.0f,  3.0f,  0.f}, { 2.0f,  3.0f}},
8909         {{ 0.0f,  0.0f,  0.f}, { 254.0f,  255.0f}},
8910 
8911         {{ 3.0f,  3.0f,  0.f}, { 256.0f, 257.0f}},
8912         {{ 3.0f,  0.0f,  0.f}, { 1.4f, 1.5f}},
8913         {{ 1.0f,  0.0f,  0.f}, {-4.0f, -5.0f}},
8914     };
8915     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
8916     const UINT num_faces10 = ARRAY_SIZE(vertices10) / VERTS_PER_FACE;
8917     const UINT vertex_size10 = sizeof(*vertices10);
8918     const struct vertex_ptc_ubyte4 exp_vertices10[] =
8919     {
8920         {{ 0.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8921         {{ 2.0f,  3.0f,  0.f}, {2, 3, 0, 1}},
8922         {{ 0.0f,  0.0f,  0.f}, {254, 255, 0, 1}},
8923 
8924         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8925         {{ 3.0f,  0.0f,  0.f}, {1, 2, 0, 1}},
8926         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
8927     };
8928     const UINT exp_vertex_size10 = sizeof(*exp_vertices10);
8929     /* Test 11. Convert FLOAT2 to SHORT2. */
8930     const struct vertex_ptc vertices11[] =
8931     {
8932         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
8933         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
8934         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
8935 
8936         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8937         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
8938         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
8939 
8940         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
8941         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
8942         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
8943     };
8944     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
8945     const UINT num_faces11 = ARRAY_SIZE(vertices11) / VERTS_PER_FACE;
8946     const UINT vertex_size11 = sizeof(*vertices11);
8947     const struct vertex_ptc_short2 exp_vertices11[] =
8948     {
8949         {{ 0.0f,  3.0f,  0.f}, {1, 0}},
8950         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
8951         {{ 0.0f,  0.0f,  0.f}, {0, -4}},
8952 
8953         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1}},
8954         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN}},
8955         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
8956 
8957         {{ 4.0f,  3.0f,  0.f}, {-2, 1}},
8958         {{ 6.0f,  0.0f,  0.f}, {32765, -32767}},
8959         {{ 4.0f,  0.0f,  0.f}, {-4, 1}},
8960     };
8961     const UINT exp_vertex_size11 = sizeof(*exp_vertices11);
8962     /* Test 12. Convert FLOAT2 to SHORT4. */
8963     const struct vertex_ptc vertices12[] =
8964     {
8965         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
8966         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
8967         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
8968 
8969         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8970         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
8971         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
8972 
8973         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
8974         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
8975         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
8976     };
8977     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
8978     const UINT num_faces12 = ARRAY_SIZE(vertices12) / VERTS_PER_FACE;
8979     const UINT vertex_size12 = sizeof(*vertices12);
8980     const struct vertex_ptc_short4 exp_vertices12[] =
8981     {
8982         {{ 0.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
8983         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8984         {{ 0.0f,  0.0f,  0.f}, {0, -4, 0, 1}},
8985 
8986         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1, 0, 1}},
8987         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN, 0, 1}},
8988         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, 0, 1}},
8989 
8990         {{ 4.0f,  3.0f,  0.f}, {-2, 1, 0, 1}},
8991         {{ 6.0f,  0.0f,  0.f}, {32765, -32767, 0, 1}},
8992         {{ 4.0f,  0.0f,  0.f}, {-4, 1, 0, 1}},
8993     };
8994     const UINT exp_vertex_size12 = sizeof(*exp_vertices12);
8995     /* Test 13. Convert FLOAT2 to UBYTE4N. */
8996     const struct vertex_ptc vertices13[] =
8997     {
8998         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  2.0f}},
8999         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9000         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.5f}},
9001 
9002         {{ 3.0f,  3.0f,  0.f}, {-0.6f,  -1.0f}},
9003         {{ 3.0f,  0.0f,  0.f}, {UCHAR_MAX,  UCHAR_MAX + 1}},
9004         {{ 1.0f,  0.0f,  0.f}, {2 * UCHAR_MAX, -UCHAR_MAX}},
9005     };
9006     const UINT num_vertices13 = ARRAY_SIZE(vertices13);
9007     const UINT num_faces13 = ARRAY_SIZE(vertices13) / VERTS_PER_FACE;
9008     const UINT vertex_size13 = sizeof(*vertices13);
9009     const struct vertex_ptc_ubyte4n exp_vertices13[] =
9010     {
9011         {{ 0.0f,  3.0f,  0.f}, {255, 255, 0, 255}},
9012         {{ 2.0f,  3.0f,  0.f}, {128, 179, 0, 255}},
9013         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9014 
9015         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, 255}},
9016         {{ 3.0f,  0.0f,  0.f}, {255, 255, 0, 255}},
9017         {{ 1.0f,  0.0f,  0.f}, {255, 0, 0, 255}},
9018     };
9019     const UINT exp_vertex_size13 = sizeof(*exp_vertices13);
9020     /* Test 14. Convert FLOAT2 to SHORT2N. */
9021     const struct vertex_ptc vertices14[] =
9022     {
9023         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9024         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9025         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9026 
9027         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9028         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
9029         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9030     };
9031     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
9032     const UINT num_faces14 = ARRAY_SIZE(vertices14) / VERTS_PER_FACE;
9033     const UINT vertex_size14 = sizeof(*vertices14);
9034     const struct vertex_ptc_short2 exp_vertices14[] =
9035     {
9036         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX}},
9037         {{ 2.0f,  3.0f,  0.f}, {13107, 16384}},
9038         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2}},
9039 
9040         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383}},
9041         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3}},
9042         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2}},
9043     };
9044     const UINT exp_vertex_size14 = sizeof(*exp_vertices14);
9045     /* Test 15. Convert FLOAT2 to SHORT4N. */
9046     const struct vertex_ptc vertices15[] =
9047     {
9048         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9049         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9050         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9051 
9052         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9053         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
9054         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9055     };
9056     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
9057     const UINT num_faces15 = ARRAY_SIZE(vertices15) / VERTS_PER_FACE;
9058     const UINT vertex_size15 = sizeof(*vertices15);
9059     const struct vertex_ptc_short4 exp_vertices15[] =
9060     {
9061         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX, 0, SHRT_MAX}},
9062         {{ 2.0f,  3.0f,  0.f}, {13107, 16384, 0, SHRT_MAX}},
9063         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2, 0, SHRT_MAX}},
9064 
9065         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383, 0, SHRT_MAX}},
9066         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3, 0, SHRT_MAX}},
9067         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2, 0, SHRT_MAX}},
9068     };
9069     const UINT exp_vertex_size15 = sizeof(*exp_vertices15);
9070     /* Test 16. Convert FLOAT2 to USHORT2N. */
9071     const struct vertex_ptc vertices16[] =
9072     {
9073         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9074         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9075         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9076 
9077         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9078         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
9079         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
9080     };
9081     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
9082     const UINT num_faces16 = ARRAY_SIZE(vertices16) / VERTS_PER_FACE;
9083     const UINT vertex_size16 = sizeof(*vertices16);
9084     const struct vertex_ptc_ushort2n exp_vertices16[] =
9085     {
9086         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX}},
9087         {{ 2.0f,  3.0f,  0.f}, {26214, 32768}},
9088         {{ 0.0f,  0.0f,  0.f}, {39321, 0}},
9089 
9090         {{ 3.0f,  3.0f,  0.f}, {0, 0}},
9091         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1}},
9092         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0}},
9093     };
9094     const UINT exp_vertex_size16 = sizeof(*exp_vertices16);
9095     /* Test 17. Convert FLOAT2 to USHORT4N. */
9096     const struct vertex_ptc vertices17[] =
9097     {
9098         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9099         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9100         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9101 
9102         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9103         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
9104         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
9105     };
9106     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
9107     const UINT num_faces17 = ARRAY_SIZE(vertices17) / VERTS_PER_FACE;
9108     const UINT vertex_size17 = sizeof(*vertices17);
9109     const struct vertex_ptc_ushort4n exp_vertices17[] =
9110     {
9111         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX, 0, USHRT_MAX}},
9112         {{ 2.0f,  3.0f,  0.f}, {26214, 32768, 0, USHRT_MAX}},
9113         {{ 0.0f,  0.0f,  0.f}, {39321, 0, 0, USHRT_MAX}},
9114 
9115         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, USHRT_MAX}},
9116         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1, 0, USHRT_MAX}},
9117         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0, 0, USHRT_MAX}},
9118     };
9119     const UINT exp_vertex_size17 = sizeof(*exp_vertices17);
9120     /* Test 18. Test that the method field is compared by converting a FLOAT2 to
9121      * FLOAT16_2. where the method field has been change from
9122      * D3DDECLMETHOD_DEFAULT to D3DDECLMETHOD_PARTIALU. */
9123     const struct vertex_ptc vertices18[] =
9124     {
9125         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9126         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9127         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
9128 
9129         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9130         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
9131         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
9132     };
9133     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
9134     const UINT num_faces18 = ARRAY_SIZE(vertices18) / VERTS_PER_FACE;
9135     const UINT vertex_size18 = sizeof(*vertices18);
9136     const struct vertex_ptc_float16_2 exp_vertices18[] =
9137     {
9138         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9139         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9140         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9141 
9142         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9143         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9144         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9145     };
9146     const UINT exp_vertex_size18 = sizeof(*exp_vertices18);
9147     /* Test 19. Test that data is lost if usage index changes, e.g. TEXCOORD0
9148      * TEXCOORD1. */
9149     const struct vertex_pntc vertices19[] =
9150     {
9151         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
9152         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
9153         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
9154 
9155         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
9156         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
9157         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
9158     };
9159     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
9160     const UINT num_faces19 = ARRAY_SIZE(vertices19) / VERTS_PER_FACE;
9161     const UINT vertex_size19 = sizeof(*vertices19);
9162     const struct vertex_pntc exp_vertices19[] =
9163     {
9164         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
9165         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
9166         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
9167 
9168         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
9169         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
9170         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
9171     };
9172     const UINT exp_vertex_size19 = sizeof(*exp_vertices19);
9173     /* Test 20. Another test that data is lost if usage index changes, e.g.
9174      * TEXCOORD1 to TEXCOORD0. */
9175     const struct vertex_pntc vertices20[] =
9176     {
9177         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
9178         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
9179         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
9180 
9181         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
9182         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
9183         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
9184     };
9185     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
9186     const UINT num_faces20 = ARRAY_SIZE(vertices20) / VERTS_PER_FACE;
9187     const UINT vertex_size20 = sizeof(*vertices20);
9188     const struct vertex_pntc exp_vertices20[] =
9189     {
9190         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
9191         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
9192         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
9193 
9194         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
9195         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
9196         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
9197     };
9198     const UINT exp_vertex_size20 = sizeof(*exp_vertices20);
9199     /* Test 21. Convert FLOAT1 to FLOAT2. */
9200     const struct vertex_ptc_float1 vertices21[] =
9201     {
9202         {{ 0.0f,  3.0f,  0.f},  1.0f},
9203         {{ 2.0f,  3.0f,  0.f},  0.5f},
9204         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9205 
9206         {{ 3.0f,  3.0f,  0.f},  0.2f},
9207         {{ 3.0f,  0.0f,  0.f},  1.0f},
9208         {{ 1.0f,  0.0f,  0.f},  0.1f},
9209     };
9210     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
9211     const UINT num_faces21 = ARRAY_SIZE(vertices21) / VERTS_PER_FACE;
9212     const UINT vertex_size21 = sizeof(*vertices21);
9213     const struct vertex_ptc exp_vertices21[] =
9214     {
9215         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f}},
9216         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f}},
9217         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f}},
9218 
9219         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f}},
9220         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f}},
9221         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f}},
9222     };
9223     const UINT exp_vertex_size21 = sizeof(*exp_vertices21);
9224     /* Test 22. Convert FLOAT1 to FLOAT3. */
9225     const struct vertex_ptc_float1 vertices22[] =
9226     {
9227         {{ 0.0f,  3.0f,  0.f},  1.0f},
9228         {{ 2.0f,  3.0f,  0.f},  0.5f},
9229         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9230 
9231         {{ 3.0f,  3.0f,  0.f},  0.2f},
9232         {{ 3.0f,  0.0f,  0.f},  1.0f},
9233         {{ 1.0f,  0.0f,  0.f},  0.1f},
9234     };
9235     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
9236     const UINT num_faces22 = ARRAY_SIZE(vertices22) / VERTS_PER_FACE;
9237     const UINT vertex_size22 = sizeof(*vertices22);
9238     const struct vertex_ptc_float3 exp_vertices22[] =
9239     {
9240         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
9241         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f}},
9242         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f}},
9243 
9244         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f}},
9245         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
9246         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f}},
9247     };
9248     const UINT exp_vertex_size22 = sizeof(*exp_vertices22);
9249     /* Test 23. Convert FLOAT1 to FLOAT4. */
9250     const struct vertex_ptc_float1 vertices23[] =
9251     {
9252         {{ 0.0f,  3.0f,  0.f},  1.0f},
9253         {{ 2.0f,  3.0f,  0.f},  0.5f},
9254         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9255 
9256         {{ 3.0f,  3.0f,  0.f},  0.2f},
9257         {{ 3.0f,  0.0f,  0.f},  1.0f},
9258         {{ 1.0f,  0.0f,  0.f},  0.1f},
9259     };
9260     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
9261     const UINT num_faces23 = ARRAY_SIZE(vertices23) / VERTS_PER_FACE;
9262     const UINT vertex_size23 = sizeof(*vertices23);
9263     const struct vertex_ptc_float4 exp_vertices23[] =
9264     {
9265         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
9266         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f, 1.0f}},
9267         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f, 1.0f}},
9268 
9269         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f, 1.0f}},
9270         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
9271         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f, 1.0f}},
9272     };
9273     const UINT exp_vertex_size23 = sizeof(*exp_vertices23);
9274     /* Test 24. Convert FLOAT1 to D3DCOLOR. */
9275     const struct vertex_ptc_float1 vertices24[] =
9276     {
9277         {{ 0.0f,  3.0f,  0.f},  1.0f},
9278         {{ 2.0f,  3.0f,  0.f},  0.5f},
9279         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9280 
9281         {{ 3.0f,  3.0f,  0.f},  0.2f},
9282         {{ 3.0f,  0.0f,  0.f},  1.0f},
9283         {{ 1.0f,  0.0f,  0.f},  0.11f},
9284     };
9285     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
9286     const UINT num_faces24 = ARRAY_SIZE(vertices24) / VERTS_PER_FACE;
9287     const UINT vertex_size24 = sizeof(*vertices24);
9288     const struct vertex_ptc_d3dcolor exp_vertices24[] =
9289     {
9290         {{ 0.0f,  3.0f,  0.f}, {0, 0, 255, 255}},
9291         {{ 2.0f,  3.0f,  0.f}, {0, 0, 128, 255}},
9292         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9293 
9294         {{ 3.0f,  3.0f,  0.f}, {0, 0, 51, 255}},
9295         {{ 3.0f,  0.0f,  0.f}, {0, 0, 255, 255}},
9296         {{ 1.0f,  0.0f,  0.f}, {0, 0, 28, 255}},
9297     };
9298     const UINT exp_vertex_size24 = sizeof(*exp_vertices24);
9299     /* Test 25. Convert FLOAT1 to ubyte4. */
9300     const struct vertex_ptc_float1 vertices25[] =
9301     {
9302         {{ 0.0f,  3.0f,  0.f}, 0.0f},
9303         {{ 2.0f,  3.0f,  0.f}, 1.4f},
9304         {{ 0.0f,  0.0f,  0.f}, 1.5f},
9305 
9306         {{ 3.0f,  3.0f,  0.f}, 255.0f},
9307         {{ 3.0f,  0.0f,  0.f}, 256.0f},
9308         {{ 1.0f,  0.0f,  0.f}, -1.0f},
9309     };
9310     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
9311     const UINT num_faces25 = ARRAY_SIZE(vertices25) / VERTS_PER_FACE;
9312     const UINT vertex_size25 = sizeof(*vertices25);
9313     const struct vertex_ptc_ubyte4 exp_vertices25[] =
9314     {
9315         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 1}},
9316         {{ 2.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
9317         {{ 0.0f,  0.0f,  0.f}, {2, 0, 0, 1}},
9318 
9319         {{ 3.0f,  3.0f,  0.f}, {255, 0, 0, 1}},
9320         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9321         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9322     };
9323     const UINT exp_vertex_size25 = sizeof(*exp_vertices25);
9324     /* Test 26. Convert FLOAT4 to D3DCOLOR. */
9325     const struct vertex_ptc_float4 vertices26[] =
9326     {
9327         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.5f}},
9328         {{ 2.0f,  3.0f,  0.f}, {-0.4f, -0.5f, -1.0f, -2.0f}},
9329         {{ 0.0f,  0.0f,  0.f}, {254.0f, 255.0f, 256.0f, 257.0f}},
9330 
9331         {{ 3.0f,  3.0f,  0.f}, {0.1f, 0.2f, 0.3f, 0.4f}},
9332         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.6f, 0.7f, 0.8f}},
9333         {{ 1.0f,  0.0f,  0.f}, {0.9f, 0.99f, 0.995f, 0.999f}},
9334     };
9335     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
9336     const UINT num_faces26 = ARRAY_SIZE(vertices26) / VERTS_PER_FACE;
9337     const UINT vertex_size26 = sizeof(*vertices26);
9338     const struct vertex_ptc_d3dcolor exp_vertices26[] =
9339     {
9340         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9341         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9342         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9343 
9344         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9345         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9346         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9347     };
9348     const UINT exp_vertex_size26 = sizeof(*exp_vertices26);
9349     /* Test 27. Convert D3DCOLOR to FLOAT4. */
9350     const struct vertex_ptc_d3dcolor vertices27[] =
9351     {
9352         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9353         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9354         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9355 
9356         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9357         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9358         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9359     };
9360     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
9361     const UINT num_faces27 = ARRAY_SIZE(vertices27) / VERTS_PER_FACE;
9362     const UINT vertex_size27 = sizeof(*vertices27);
9363     const struct vertex_ptc_float4 exp_vertices27[] =
9364     {
9365         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.501961f}},
9366         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9367         {{ 0.0f,  0.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9368 
9369         {{ 3.0f,  3.0f,  0.f}, {0.101961f, 0.2f, 0.301961f, 0.4f}},
9370         {{ 3.0f,  0.0f,  0.f}, {0.501961f, 0.6f, 0.701961f, 0.8f}},
9371         {{ 1.0f,  0.0f,  0.f}, {0.901961f, 0.988235f, 0.996078f, 1.0f}},
9372     };
9373     const UINT exp_vertex_size27 = sizeof(*exp_vertices27);
9374     /* Test 28. Convert UBYTE4 to FLOAT4. */
9375     const struct vertex_ptc_ubyte4 vertices28[] =
9376     {
9377         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9378         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9379         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9380 
9381         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9382         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9383         {{ 1.0f,  0.0f,  0.f}, {50, 60, 127, 255}},
9384     };
9385     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
9386     const UINT num_faces28 = ARRAY_SIZE(vertices28) / VERTS_PER_FACE;
9387     const UINT vertex_size28 = sizeof(*vertices28);
9388     const struct vertex_ptc_float4 exp_vertices28[] =
9389     {
9390         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9391         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9392         {{ 0.0f,  0.0f,  0.f}, {1.0f,  0.0f, 1.0f, 0.0f}},
9393 
9394         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9395         {{ 3.0f,  0.0f,  0.f}, {10.0f, 20.0f, 30.0f, 40.0f}},
9396         {{ 1.0f,  0.0f,  0.f}, {50.0f, 60.0f, 127.0f, 255.0f}},
9397     };
9398     const UINT exp_vertex_size28 = sizeof(*exp_vertices28);
9399     /* Test 29. Convert SHORT2 to FLOAT4. */
9400     const struct vertex_ptc_short2 vertices29[] =
9401     {
9402         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9403         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9404         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9405 
9406         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9407         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX}},
9408         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9409     };
9410     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
9411     const UINT num_faces29 = ARRAY_SIZE(vertices29) / VERTS_PER_FACE;
9412     const UINT vertex_size29 = sizeof(*vertices29);
9413     const struct vertex_ptc_float4 exp_vertices29[] =
9414     {
9415         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9416         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9417         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 0.0f, 1.0f}},
9418 
9419         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9420         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 0.0f, 1.0f}},
9421         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, 0.0f, 1.0f}},
9422     };
9423     const UINT exp_vertex_size29 = sizeof(*exp_vertices29);
9424     /* Test 29. Convert SHORT4 to FLOAT4. */
9425     const struct vertex_ptc_short4 vertices30[] =
9426     {
9427         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9428         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9429         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9430 
9431         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9432         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1, 0}},
9433         {{ 1.0f,  0.0f,  0.f}, {-42, 42, SHRT_MAX, SHRT_MIN}},
9434     };
9435     const UINT num_vertices30 = ARRAY_SIZE(vertices30);
9436     const UINT num_faces30 = ARRAY_SIZE(vertices30) / VERTS_PER_FACE;
9437     const UINT vertex_size30 = sizeof(*vertices30);
9438     const struct vertex_ptc_float4 exp_vertices30[] =
9439     {
9440         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9441         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9442         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9443 
9444         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9445         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1.0f, 0.0f}},
9446         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, SHRT_MAX, SHRT_MIN}},
9447     };
9448     const UINT exp_vertex_size30 = sizeof(*exp_vertices30);
9449     /* Test 31. Convert UBYTE4N to FLOAT4. */
9450     const struct vertex_ptc_ubyte4n vertices31[] =
9451     {
9452         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9453         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9454         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9455 
9456         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9457         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9458         {{ 1.0f,  0.0f,  0.f}, {50, 60, 70, UCHAR_MAX}},
9459     };
9460     const UINT num_vertices31 = ARRAY_SIZE(vertices31);
9461     const UINT num_faces31 = ARRAY_SIZE(vertices31) / VERTS_PER_FACE;
9462     const UINT vertex_size31 = sizeof(*vertices31);
9463     const struct vertex_ptc_float4 exp_vertices31[] =
9464     {
9465         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9466         {{ 2.0f,  3.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX}},
9467         {{ 0.0f,  0.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX, 0.0f}},
9468 
9469         {{ 3.0f,  3.0f,  0.f}, {0.0f, (FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX}},
9470         {{ 3.0f,  0.0f,  0.f}, {(FLOAT)10/UCHAR_MAX, (FLOAT)20/UCHAR_MAX, (FLOAT)30/UCHAR_MAX, (FLOAT)40/UCHAR_MAX}},
9471         {{ 1.0f,  0.0f,  0.f}, {(FLOAT)50/UCHAR_MAX, (FLOAT)60/UCHAR_MAX, (FLOAT)70/UCHAR_MAX, 1.0f}},
9472     };
9473     const UINT exp_vertex_size31 = sizeof(*exp_vertices31);
9474     /* Test 32. Convert SHORT2N to FLOAT4. */
9475     const struct vertex_ptc_short2 vertices32[] =
9476     {
9477         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9478         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9479         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9480 
9481         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9482         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
9483         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9484     };
9485     const UINT num_vertices32 = ARRAY_SIZE(vertices32);
9486     const UINT num_faces32 = ARRAY_SIZE(vertices32) / VERTS_PER_FACE;
9487     const UINT vertex_size32 = sizeof(*vertices32);
9488     const struct vertex_ptc_float4 exp_vertices32[] =
9489     {
9490         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9491         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9492         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 0.0f, 1.0f}},
9493 
9494         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9495         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, 0.0f, 1.0f}},
9496         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 0.0f, 1.0f}},
9497     };
9498     const UINT exp_vertex_size32 = sizeof(*exp_vertices32);
9499     /* Test 33. Convert SHORT4N to FLOAT4. */
9500     const struct vertex_ptc_short4 vertices33[] =
9501     {
9502         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9503         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9504         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9505 
9506         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9507         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, SHRT_MIN + 1, SHRT_MAX}},
9508         {{ 1.0f,  0.0f,  0.f}, {-42, 42, 1, 1}},
9509     };
9510     const UINT num_vertices33 = ARRAY_SIZE(vertices33);
9511     const UINT num_faces33 = ARRAY_SIZE(vertices33) / VERTS_PER_FACE;
9512     const UINT vertex_size33 = sizeof(*vertices33);
9513     const struct vertex_ptc_float4 exp_vertices33[] =
9514     {
9515         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9516         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX}},
9517         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX, 0.0f}},
9518 
9519         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9520         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, -1.0f, 1.0f}},
9521         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9522     };
9523     const UINT exp_vertex_size33 = sizeof(*exp_vertices33);
9524     /* Test 34. Convert FLOAT16_2 to FLOAT4. */
9525     const struct vertex_ptc_float16_2 vertices34[] =
9526     {
9527         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9528         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9529         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9530 
9531         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9532         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9533         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9534     };
9535     const UINT num_vertices34 = ARRAY_SIZE(vertices34);
9536     const UINT num_faces34 = ARRAY_SIZE(vertices34) / VERTS_PER_FACE;
9537     const UINT vertex_size34 = sizeof(*vertices34);
9538     const struct vertex_ptc_float4 exp_vertices34[] =
9539     {
9540         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9541         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.700195f, 0.0f, 1.0f}},
9542         {{ 0.0f,  0.0f,  0.f}, {-0.199951f, -0.300049f, 0.0f, 1.0f}},
9543 
9544         {{ 3.0f,  3.0f,  0.f}, {0.199951f, 0.300049f, 0.0f, 1.0f}},
9545         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9546         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.0f, 1.0f}},
9547     };
9548     const UINT exp_vertex_size34 = sizeof(*exp_vertices34);
9549     /* Test 35. Convert FLOAT16_4 to FLOAT4. */
9550     const struct vertex_ptc_float16_4 vertices35[] =
9551     {
9552         {{ 0.0f,  3.0f,  0.f}, {0x0000, 0x0000, 0x0000, 0x0000}},
9553         {{ 2.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
9554         {{ 0.0f,  0.0f,  0.f}, {0x3c00, 0x0000, 0x3c00, 0x0000}},
9555 
9556         {{ 3.0f,  3.0f,  0.f}, {0x0000, 0x3c00, 0x0000, 0x3c00}},
9557         {{ 3.0f,  0.0f,  0.f}, {0x3800, 0x399a, 0xb266, 0xb4cd}},
9558         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
9559     };
9560     const UINT num_vertices35 = ARRAY_SIZE(vertices35);
9561     const UINT num_faces35 = ARRAY_SIZE(vertices35) / VERTS_PER_FACE;
9562     const UINT vertex_size35 = sizeof(*vertices35);
9563     const struct vertex_ptc_float4 exp_vertices35[] =
9564     {
9565         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9566         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9567         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9568 
9569         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9570         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.700195f, -0.199951f, -0.300049f}},
9571         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.099976f, 0.199951f}},
9572     };
9573     const UINT exp_vertex_size35 = sizeof(*exp_vertices35);
9574     /* Test 36. Check that vertex buffer sharing is ok. */
9575     const struct vertex_pn vertices36[] =
9576     {
9577         {{ 0.0f,  3.0f,  0.f}, up},
9578         {{ 2.0f,  3.0f,  0.f}, up},
9579         {{ 0.0f,  0.0f,  0.f}, up},
9580     };
9581     const UINT num_vertices36 = ARRAY_SIZE(vertices36);
9582     const UINT num_faces36 = ARRAY_SIZE(vertices36) / VERTS_PER_FACE;
9583     const UINT vertex_size36 = sizeof(*vertices36);
9584     const DWORD clone_options36 = options | D3DXMESH_VB_SHARE;
9585     /* Common mesh data */
9586     ID3DXMesh *mesh = NULL;
9587     ID3DXMesh *mesh_clone = NULL;
9588     struct
9589     {
9590         const BYTE *vertices;
9591         const DWORD *indices;
9592         const DWORD *attributes;
9593         const UINT num_vertices;
9594         const UINT num_faces;
9595         const UINT vertex_size;
9596         const DWORD create_options;
9597         const DWORD clone_options;
9598         D3DVERTEXELEMENT9 *declaration;
9599         D3DVERTEXELEMENT9 *new_declaration;
9600         const BYTE *exp_vertices;
9601         const UINT exp_vertex_size;
9602     }
9603     tc[] =
9604     {
9605         {
9606             (BYTE*)vertices0,
9607             NULL,
9608             NULL,
9609             num_vertices0,
9610             num_faces0,
9611             vertex_size0,
9612             options,
9613             options,
9614             declaration_pn,
9615             declaration_pn,
9616             (BYTE*)vertices0,
9617             vertex_size0
9618         },
9619         {
9620             (BYTE*)vertices0,
9621             NULL,
9622             NULL,
9623             num_vertices0,
9624             num_faces0,
9625             vertex_size0,
9626             options_16bit,
9627             options_16bit,
9628             declaration_pn,
9629             declaration_pn,
9630             (BYTE*)vertices0,
9631             vertex_size0
9632         },
9633         {
9634             (BYTE*)vertices0,
9635             NULL,
9636             NULL,
9637             num_vertices0,
9638             num_faces0,
9639             vertex_size0,
9640             options,
9641             options,
9642             declaration_pn,
9643             declaration_pntc,
9644             (BYTE*)exp_vertices2,
9645             exp_vertex_size2
9646         },
9647         {
9648             (BYTE*)vertices0,
9649             NULL,
9650             NULL,
9651             num_vertices0,
9652             num_faces0,
9653             vertex_size0,
9654             options,
9655             options,
9656             declaration_pn,
9657             declaration_ptcn,
9658             (BYTE*)exp_vertices3,
9659             exp_vertex_size3
9660         },
9661         {
9662             (BYTE*)vertices4,
9663             NULL,
9664             NULL,
9665             num_vertices4,
9666             num_faces4,
9667             vertex_size4,
9668             options,
9669             options,
9670             declaration_ptc,
9671             declaration_ptc_float16_2,
9672             (BYTE*)exp_vertices4,
9673             exp_vertex_size4
9674         },
9675         {
9676             (BYTE*)vertices5,
9677             NULL,
9678             NULL,
9679             num_vertices5,
9680             num_faces5,
9681             vertex_size5,
9682             options,
9683             options,
9684             declaration_ptc,
9685             declaration_ptc_float16_4,
9686             (BYTE*)exp_vertices5,
9687             exp_vertex_size5
9688         },
9689         {
9690             (BYTE*)vertices6,
9691             NULL,
9692             NULL,
9693             num_vertices6,
9694             num_faces6,
9695             vertex_size6,
9696             options,
9697             options,
9698             declaration_ptc,
9699             declaration_ptc_float1,
9700             (BYTE*)exp_vertices6,
9701             exp_vertex_size6
9702         },
9703         {
9704             (BYTE*)vertices7,
9705             NULL,
9706             NULL,
9707             num_vertices7,
9708             num_faces7,
9709             vertex_size7,
9710             options,
9711             options,
9712             declaration_ptc,
9713             declaration_ptc_float3,
9714             (BYTE*)exp_vertices7,
9715             exp_vertex_size7
9716         },
9717         {
9718             (BYTE*)vertices8,
9719             NULL,
9720             NULL,
9721             num_vertices8,
9722             num_faces8,
9723             vertex_size8,
9724             options,
9725             options,
9726             declaration_ptc,
9727             declaration_ptc_float4,
9728             (BYTE*)exp_vertices8,
9729             exp_vertex_size8
9730         },
9731         {
9732             (BYTE*)vertices9,
9733             NULL,
9734             NULL,
9735             num_vertices9,
9736             num_faces9,
9737             vertex_size9,
9738             options,
9739             options,
9740             declaration_ptc,
9741             declaration_ptc_d3dcolor,
9742             (BYTE*)exp_vertices9,
9743             exp_vertex_size9
9744         },
9745         {
9746             (BYTE*)vertices10,
9747             NULL,
9748             NULL,
9749             num_vertices10,
9750             num_faces10,
9751             vertex_size10,
9752             options,
9753             options,
9754             declaration_ptc,
9755             declaration_ptc_ubyte4,
9756             (BYTE*)exp_vertices10,
9757             exp_vertex_size10
9758         },
9759         {
9760             (BYTE*)vertices11,
9761             NULL,
9762             NULL,
9763             num_vertices11,
9764             num_faces11,
9765             vertex_size11,
9766             options,
9767             options,
9768             declaration_ptc,
9769             declaration_ptc_short2,
9770             (BYTE*)exp_vertices11,
9771             exp_vertex_size11
9772         },
9773         {
9774             (BYTE*)vertices12,
9775             NULL,
9776             NULL,
9777             num_vertices12,
9778             num_faces12,
9779             vertex_size12,
9780             options,
9781             options,
9782             declaration_ptc,
9783             declaration_ptc_short4,
9784             (BYTE*)exp_vertices12,
9785             exp_vertex_size12
9786         },
9787         {
9788             (BYTE*)vertices13,
9789             NULL,
9790             NULL,
9791             num_vertices13,
9792             num_faces13,
9793             vertex_size13,
9794             options,
9795             options,
9796             declaration_ptc,
9797             declaration_ptc_ubyte4n,
9798             (BYTE*)exp_vertices13,
9799             exp_vertex_size13
9800         },
9801         {
9802             (BYTE*)vertices14,
9803             NULL,
9804             NULL,
9805             num_vertices14,
9806             num_faces14,
9807             vertex_size14,
9808             options,
9809             options,
9810             declaration_ptc,
9811             declaration_ptc_short2n,
9812             (BYTE*)exp_vertices14,
9813             exp_vertex_size14
9814         },
9815         {
9816             (BYTE*)vertices15,
9817             NULL,
9818             NULL,
9819             num_vertices15,
9820             num_faces15,
9821             vertex_size15,
9822             options,
9823             options,
9824             declaration_ptc,
9825             declaration_ptc_short4n,
9826             (BYTE*)exp_vertices15,
9827             exp_vertex_size15
9828         },
9829         {
9830             (BYTE*)vertices16,
9831             NULL,
9832             NULL,
9833             num_vertices16,
9834             num_faces16,
9835             vertex_size16,
9836             options,
9837             options,
9838             declaration_ptc,
9839             declaration_ptc_ushort2n,
9840             (BYTE*)exp_vertices16,
9841             exp_vertex_size16
9842         },
9843         {
9844             (BYTE*)vertices17,
9845             NULL,
9846             NULL,
9847             num_vertices17,
9848             num_faces17,
9849             vertex_size17,
9850             options,
9851             options,
9852             declaration_ptc,
9853             declaration_ptc_ushort4n,
9854             (BYTE*)exp_vertices17,
9855             exp_vertex_size17
9856         },
9857         {
9858             (BYTE*)vertices18,
9859             NULL,
9860             NULL,
9861             num_vertices18,
9862             num_faces18,
9863             vertex_size18,
9864             options,
9865             options,
9866             declaration_ptc,
9867             declaration_ptc_float16_2_partialu,
9868             (BYTE*)exp_vertices18,
9869             exp_vertex_size18
9870         },
9871         {
9872             (BYTE*)vertices19,
9873             NULL,
9874             NULL,
9875             num_vertices19,
9876             num_faces19,
9877             vertex_size19,
9878             options,
9879             options,
9880             declaration_pntc,
9881             declaration_pntc1,
9882             (BYTE*)exp_vertices19,
9883             exp_vertex_size19
9884         },
9885         {
9886             (BYTE*)vertices20,
9887             NULL,
9888             NULL,
9889             num_vertices20,
9890             num_faces20,
9891             vertex_size20,
9892             options,
9893             options,
9894             declaration_pntc1,
9895             declaration_pntc,
9896             (BYTE*)exp_vertices20,
9897             exp_vertex_size20
9898         },
9899         {
9900             (BYTE*)vertices21,
9901             NULL,
9902             NULL,
9903             num_vertices21,
9904             num_faces21,
9905             vertex_size21,
9906             options,
9907             options,
9908             declaration_ptc_float1,
9909             declaration_ptc,
9910             (BYTE*)exp_vertices21,
9911             exp_vertex_size21
9912         },
9913         {
9914             (BYTE*)vertices22,
9915             NULL,
9916             NULL,
9917             num_vertices22,
9918             num_faces22,
9919             vertex_size22,
9920             options,
9921             options,
9922             declaration_ptc_float1,
9923             declaration_ptc_float3,
9924             (BYTE*)exp_vertices22,
9925             exp_vertex_size22
9926         },
9927         {
9928             (BYTE*)vertices23,
9929             NULL,
9930             NULL,
9931             num_vertices23,
9932             num_faces23,
9933             vertex_size23,
9934             options,
9935             options,
9936             declaration_ptc_float1,
9937             declaration_ptc_float4,
9938             (BYTE*)exp_vertices23,
9939             exp_vertex_size23
9940         },
9941         {
9942             (BYTE*)vertices24,
9943             NULL,
9944             NULL,
9945             num_vertices24,
9946             num_faces24,
9947             vertex_size24,
9948             options,
9949             options,
9950             declaration_ptc_float1,
9951             declaration_ptc_d3dcolor,
9952             (BYTE*)exp_vertices24,
9953             exp_vertex_size24
9954         },
9955         {
9956             (BYTE*)vertices25,
9957             NULL,
9958             NULL,
9959             num_vertices25,
9960             num_faces25,
9961             vertex_size25,
9962             options,
9963             options,
9964             declaration_ptc_float1,
9965             declaration_ptc_ubyte4,
9966             (BYTE*)exp_vertices25,
9967             exp_vertex_size25
9968         },
9969         {
9970             (BYTE*)vertices26,
9971             NULL,
9972             NULL,
9973             num_vertices26,
9974             num_faces26,
9975             vertex_size26,
9976             options,
9977             options,
9978             declaration_ptc_float4,
9979             declaration_ptc_d3dcolor,
9980             (BYTE*)exp_vertices26,
9981             exp_vertex_size26
9982         },
9983         {
9984             (BYTE*)vertices27,
9985             NULL,
9986             NULL,
9987             num_vertices27,
9988             num_faces27,
9989             vertex_size27,
9990             options,
9991             options,
9992             declaration_ptc_d3dcolor,
9993             declaration_ptc_float4,
9994             (BYTE*)exp_vertices27,
9995             exp_vertex_size27
9996         },
9997         {
9998             (BYTE*)vertices28,
9999             NULL,
10000             NULL,
10001             num_vertices28,
10002             num_faces28,
10003             vertex_size28,
10004             options,
10005             options,
10006             declaration_ptc_ubyte4,
10007             declaration_ptc_float4,
10008             (BYTE*)exp_vertices28,
10009             exp_vertex_size28
10010         },
10011         {
10012             (BYTE*)vertices29,
10013             NULL,
10014             NULL,
10015             num_vertices29,
10016             num_faces29,
10017             vertex_size29,
10018             options,
10019             options,
10020             declaration_ptc_short2,
10021             declaration_ptc_float4,
10022             (BYTE*)exp_vertices29,
10023             exp_vertex_size29
10024         },
10025         {
10026             (BYTE*)vertices30,
10027             NULL,
10028             NULL,
10029             num_vertices30,
10030             num_faces30,
10031             vertex_size30,
10032             options,
10033             options,
10034             declaration_ptc_short4,
10035             declaration_ptc_float4,
10036             (BYTE*)exp_vertices30,
10037             exp_vertex_size30
10038         },
10039         {
10040             (BYTE*)vertices31,
10041             NULL,
10042             NULL,
10043             num_vertices31,
10044             num_faces31,
10045             vertex_size31,
10046             options,
10047             options,
10048             declaration_ptc_ubyte4n,
10049             declaration_ptc_float4,
10050             (BYTE*)exp_vertices31,
10051             exp_vertex_size31
10052         },
10053         {
10054             (BYTE*)vertices32,
10055             NULL,
10056             NULL,
10057             num_vertices32,
10058             num_faces32,
10059             vertex_size32,
10060             options,
10061             options,
10062             declaration_ptc_short2n,
10063             declaration_ptc_float4,
10064             (BYTE*)exp_vertices32,
10065             exp_vertex_size32
10066         },
10067         {
10068             (BYTE*)vertices33,
10069             NULL,
10070             NULL,
10071             num_vertices33,
10072             num_faces33,
10073             vertex_size33,
10074             options,
10075             options,
10076             declaration_ptc_short4n,
10077             declaration_ptc_float4,
10078             (BYTE*)exp_vertices33,
10079             exp_vertex_size33
10080         },
10081         {
10082             (BYTE*)vertices34,
10083             NULL,
10084             NULL,
10085             num_vertices34,
10086             num_faces34,
10087             vertex_size34,
10088             options,
10089             options,
10090             declaration_ptc_float16_2,
10091             declaration_ptc_float4,
10092             (BYTE*)exp_vertices34,
10093             exp_vertex_size34
10094         },
10095         {
10096             (BYTE*)vertices35,
10097             NULL,
10098             NULL,
10099             num_vertices35,
10100             num_faces35,
10101             vertex_size35,
10102             options,
10103             options,
10104             declaration_ptc_float16_4,
10105             declaration_ptc_float4,
10106             (BYTE*)exp_vertices35,
10107             exp_vertex_size35
10108         },
10109         {
10110             (BYTE*)vertices36,
10111             NULL,
10112             NULL,
10113             num_vertices36,
10114             num_faces36,
10115             vertex_size36,
10116             options,
10117             clone_options36,
10118             declaration_pn,
10119             declaration_pn,
10120             (BYTE*)vertices36,
10121             vertex_size36
10122         },
10123     };
10124 #ifdef __REACTOS__
10125 #undef up
10126 #undef zero_vec2
10127 #endif
10128 
10129     test_context = new_test_context();
10130     if (!test_context)
10131     {
10132         skip("Couldn't create test context\n");
10133         goto cleanup;
10134     }
10135 
10136     for (i = 0; i < ARRAY_SIZE(tc); i++)
10137     {
10138         UINT j;
10139         D3DVERTEXELEMENT9 new_declaration[MAX_FVF_DECL_SIZE];
10140         UINT exp_new_decl_length, new_decl_length;
10141         UINT exp_new_decl_size, new_decl_size;
10142 
10143         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10144                               tc[i].create_options,
10145                               tc[i].declaration,
10146                               test_context->device, &mesh,
10147                               tc[i].vertices, tc[i].vertex_size,
10148                               tc[i].indices, tc[i].attributes);
10149         if (FAILED(hr))
10150         {
10151             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10152             goto cleanup;
10153         }
10154 
10155         hr = mesh->lpVtbl->CloneMesh(mesh, tc[i].clone_options, tc[i].new_declaration,
10156                                      test_context->device, &mesh_clone);
10157         ok(hr == D3D_OK, "CloneMesh test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
10158 
10159         hr = mesh_clone->lpVtbl->GetDeclaration(mesh_clone, new_declaration);
10160         ok(hr == D3D_OK, "GetDeclaration test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
10161         /* Check declaration elements */
10162         for (j = 0; tc[i].new_declaration[j].Stream != 0xFF; j++)
10163         {
10164             ok(memcmp(&tc[i].new_declaration[j], &new_declaration[j], sizeof(*new_declaration)) == 0,
10165                "Test case %d failed. Declaration element %d did not match.\n", i, j);
10166         }
10167 
10168         /* Check declaration length */
10169         exp_new_decl_length = D3DXGetDeclLength(tc[i].new_declaration);
10170         new_decl_length = D3DXGetDeclLength(new_declaration);
10171         ok(new_decl_length == exp_new_decl_length,
10172            "Test case %d failed. Got new declaration length %d, expected %d\n",
10173            i, new_decl_length, exp_new_decl_length);
10174 
10175         /* Check declaration size */
10176         exp_new_decl_size = D3DXGetDeclVertexSize(tc[i].new_declaration, 0);
10177         new_decl_size = D3DXGetDeclVertexSize(new_declaration, 0);
10178         ok(new_decl_size == exp_new_decl_size,
10179            "Test case %d failed. Got new declaration size %d, expected %d\n",
10180            i, new_decl_size, exp_new_decl_size);
10181 
10182         /* Check vertex data in cloned mesh */
10183         hr = mesh_clone->lpVtbl->LockVertexBuffer(mesh_clone, 0, (void**)&vertices);
10184         if (FAILED(hr))
10185         {
10186             skip("Couldn't lock cloned vertex buffer.\n");
10187             goto cleanup;
10188         }
10189         for (j = 0; j < tc[i].num_vertices; j++)
10190         {
10191             UINT index = tc[i].exp_vertex_size * j;
10192             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].new_declaration);
10193         }
10194         hr = mesh_clone->lpVtbl->UnlockVertexBuffer(mesh_clone);
10195         if (FAILED(hr))
10196         {
10197             skip("Couldn't unlock vertex buffer.\n");
10198             goto cleanup;
10199         }
10200         vertices = NULL;
10201         mesh->lpVtbl->Release(mesh);
10202         mesh = NULL;
10203         mesh_clone->lpVtbl->Release(mesh_clone);
10204         mesh_clone = NULL;
10205     }
10206 
10207     /* The following test shows that it is not possible to share a vertex buffer
10208      * with D3DXMESH_VB_SHARE and change the vertex declaration at the same
10209      * time. It reuses the test data from test 2.
10210      */
10211     hr = init_test_mesh(tc[2].num_faces, tc[2].num_vertices,
10212                         tc[2].create_options,
10213                         tc[2].declaration,
10214                         test_context->device, &mesh,
10215                         tc[2].vertices, tc[2].vertex_size,
10216                         tc[2].indices, tc[2].attributes);
10217     if (FAILED(hr))
10218     {
10219         skip("Couldn't initialize test mesh for D3DXMESH_VB_SHARE case."
10220              " Got %x expected D3D_OK\n", hr);
10221         goto cleanup;
10222     }
10223 
10224     hr = mesh->lpVtbl->CloneMesh(mesh, tc[2].create_options | D3DXMESH_VB_SHARE,
10225                                  tc[2].new_declaration, test_context->device,
10226                                  &mesh_clone);
10227     ok(hr == D3DERR_INVALIDCALL, "CloneMesh D3DXMESH_VB_SHARE with new"
10228        " declaration. Got %x, expected D3DERR_INVALIDCALL\n",
10229        hr);
10230     mesh->lpVtbl->Release(mesh);
10231     mesh = NULL;
10232     mesh_clone = NULL;
10233 
10234 cleanup:
10235     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
10236     if (mesh) mesh->lpVtbl->Release(mesh);
10237     if (mesh_clone) mesh_clone->lpVtbl->Release(mesh_clone);
10238     free_test_context(test_context);
10239 }
10240 
10241 static void test_valid_mesh(void)
10242 {
10243     HRESULT hr;
10244     struct test_context *test_context = NULL;
10245     UINT i;
10246     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
10247     const D3DVERTEXELEMENT9 declaration[] =
10248     {
10249         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10250         D3DDECL_END()
10251     };
10252     const unsigned int VERTS_PER_FACE = 3;
10253     /* mesh0 (one face)
10254      *
10255      * 0--1
10256      * | /
10257      * |/
10258      * 2
10259      */
10260     const D3DXVECTOR3 vertices0[] =
10261     {
10262         { 0.0f,  3.0f,  0.f},
10263         { 2.0f,  3.0f,  0.f},
10264         { 0.0f,  0.0f,  0.f},
10265     };
10266     const DWORD indices0[] = {0, 1, 2};
10267     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
10268     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
10269     const DWORD adjacency0[] = {-1, -1, -1};
10270     const HRESULT exp_hr0 = D3D_OK;
10271     /* mesh1 (Simple bow-tie)
10272      *
10273      * 0--1 1--3
10274      * | /   \ |
10275      * |/     \|
10276      * 2       4
10277      */
10278     const D3DXVECTOR3 vertices1[] =
10279     {
10280         { 0.0f,  3.0f,  0.f},
10281         { 2.0f,  3.0f,  0.f},
10282         { 0.0f,  0.0f,  0.f},
10283 
10284         { 4.0f,  3.0f,  0.f},
10285         { 4.0f,  0.0f,  0.f},
10286     };
10287     const DWORD indices1[] = {0, 1, 2, 1, 3, 4};
10288     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
10289     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
10290     const DWORD adjacency1[] = {-1, -1, -1, -1, -1, -1};
10291     const HRESULT exp_hr1 = D3DXERR_INVALIDMESH;
10292     /* Common mesh data */
10293     ID3DXMesh *mesh = NULL;
10294     UINT vertex_size = sizeof(D3DXVECTOR3);
10295     ID3DXBuffer *errors_and_warnings = NULL;
10296     struct
10297     {
10298         const D3DXVECTOR3 *vertices;
10299         const DWORD *indices;
10300         const UINT num_vertices;
10301         const UINT num_faces;
10302         const DWORD *adjacency;
10303         const HRESULT exp_hr;
10304     }
10305     tc[] =
10306     {
10307         {
10308             vertices0,
10309             indices0,
10310             num_vertices0,
10311             num_faces0,
10312             adjacency0,
10313             exp_hr0,
10314         },
10315         {
10316             vertices1,
10317             indices1,
10318             num_vertices1,
10319             num_faces1,
10320             adjacency1,
10321             exp_hr1,
10322         },
10323     };
10324 
10325     test_context = new_test_context();
10326     if (!test_context)
10327     {
10328         skip("Couldn't create test context\n");
10329         goto cleanup;
10330     }
10331 
10332     for (i = 0; i < ARRAY_SIZE(tc); i++)
10333     {
10334         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10335                             options, declaration,
10336                             test_context->device, &mesh,
10337                             tc[i].vertices, vertex_size,
10338                             tc[i].indices, NULL);
10339         if (FAILED(hr))
10340         {
10341             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10342             goto cleanup;
10343         }
10344 
10345         hr = D3DXValidMesh(mesh, tc[i].adjacency, &errors_and_warnings);
10346         todo_wine ok(hr == tc[i].exp_hr, "D3DXValidMesh test case %d failed. "
10347                      "Got %x\n, expected %x\n", i, hr, tc[i].exp_hr);
10348 
10349         /* Note errors_and_warnings is deliberately not checked because that
10350          * would require copying wast amounts of the text output. */
10351         if (errors_and_warnings)
10352         {
10353             ID3DXBuffer_Release(errors_and_warnings);
10354             errors_and_warnings = NULL;
10355         }
10356         mesh->lpVtbl->Release(mesh);
10357         mesh = NULL;
10358     }
10359 
10360 cleanup:
10361     if (mesh) mesh->lpVtbl->Release(mesh);
10362     free_test_context(test_context);
10363 }
10364 
10365 static void test_optimize_faces(void)
10366 {
10367     HRESULT hr;
10368     UINT i;
10369     DWORD smallest_face_remap;
10370     /* mesh0
10371      *
10372      * 0--1
10373      * | /
10374      * |/
10375      * 2
10376      */
10377     const DWORD indices0[] = {0, 1, 2};
10378     const UINT num_faces0 = 1;
10379     const UINT num_vertices0 = 3;
10380     const DWORD exp_face_remap0[] = {0};
10381     /* mesh1
10382      *
10383      * 0--1 3
10384      * | / /|
10385      * |/ / |
10386      * 2 5--4
10387      */
10388     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
10389     const UINT num_faces1 = 2;
10390     const UINT num_vertices1 = 6;
10391     const DWORD exp_face_remap1[] = {1, 0};
10392     /* mesh2
10393      *
10394      * 0--1
10395      * | /|
10396      * |/ |
10397      * 2--3
10398      */
10399     const DWORD indices2[] = {0, 1, 2, 1, 3, 2};
10400     const UINT num_faces2 = 2;
10401     const UINT num_vertices2 = 4;
10402     const DWORD exp_face_remap2[] = {1, 0};
10403     /* mesh3
10404      *
10405      * 0--1
10406      * | /|
10407      * |/ |
10408      * 2--3
10409      * | /|
10410      * |/ |
10411      * 4--5
10412      */
10413     const DWORD indices3[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
10414     const UINT num_faces3 = 4;
10415     const UINT num_vertices3 = 6;
10416     const DWORD exp_face_remap3[] = {3, 2, 1, 0};
10417     /* mesh4
10418      *
10419      * 0--1
10420      * | /|
10421      * |/ |
10422      * 2--3
10423      * | /|
10424      * |/ |
10425      * 4--5
10426      */
10427     const WORD indices4[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
10428     const UINT num_faces4 = 4;
10429     const UINT num_vertices4 = 6;
10430     const DWORD exp_face_remap4[] = {3, 2, 1, 0};
10431     /* Test cases are stored in the tc array */
10432     struct
10433     {
10434         const VOID *indices;
10435         const UINT num_faces;
10436         const UINT num_vertices;
10437         const BOOL indices_are_32bit;
10438         const DWORD *exp_face_remap;
10439     }
10440     tc[] =
10441     {
10442         {
10443             indices0,
10444             num_faces0,
10445             num_vertices0,
10446             TRUE,
10447             exp_face_remap0
10448         },
10449         {
10450             indices1,
10451             num_faces1,
10452             num_vertices1,
10453             TRUE,
10454             exp_face_remap1
10455         },
10456         {
10457             indices2,
10458             num_faces2,
10459             num_vertices2,
10460             TRUE,
10461             exp_face_remap2
10462         },
10463         {
10464             indices3,
10465             num_faces3,
10466             num_vertices3,
10467             TRUE,
10468             exp_face_remap3
10469         },
10470         {
10471             indices4,
10472             num_faces4,
10473             num_vertices4,
10474             FALSE,
10475             exp_face_remap4
10476         },
10477     };
10478 
10479     /* Go through all test cases */
10480     for (i = 0; i < ARRAY_SIZE(tc); i++)
10481     {
10482         DWORD j;
10483         DWORD *face_remap;
10484         face_remap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
10485                                tc[i].num_faces*sizeof(*face_remap));
10486 
10487         hr = D3DXOptimizeFaces(tc[i].indices, tc[i].num_faces,
10488                                tc[i].num_vertices, tc[i].indices_are_32bit,
10489                                face_remap);
10490         ok(hr == D3D_OK, "D3DXOptimizeFaces test case %d failed. "
10491            "Got %x\n, expected D3D_OK\n", i, hr);
10492 
10493         /* Compare face remap with expected face remap */
10494         for (j = 0; j < tc[i].num_faces; j++)
10495         {
10496             ok(tc[i].exp_face_remap[j] == face_remap[j],
10497                "Test case %d: Got face %d at %d, expected %d\n", i,
10498                face_remap[j], j, tc[i].exp_face_remap[j]);
10499         }
10500 
10501         HeapFree(GetProcessHeap(), 0, face_remap);
10502     }
10503 
10504     /* face_remap must not be NULL */
10505     hr = D3DXOptimizeFaces(tc[0].indices, tc[0].num_faces,
10506                            tc[0].num_vertices, tc[0].indices_are_32bit,
10507                            NULL);
10508     ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeFaces passed NULL face_remap "
10509        "pointer. Got %x\n, expected D3DERR_INVALIDCALL\n", hr);
10510 
10511     /* Number of faces must be smaller than 2^15 */
10512     hr = D3DXOptimizeFaces(tc[0].indices, 2 << 15,
10513                            tc[0].num_vertices, FALSE,
10514                            &smallest_face_remap);
10515     ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeFaces should not accept 2^15 "
10516     "faces when using 16-bit indices. Got %x\n, expected D3DERR_INVALIDCALL\n", hr);
10517 }
10518 
10519 static HRESULT clear_normals(ID3DXMesh *mesh)
10520 {
10521     HRESULT hr;
10522     BYTE *vertices;
10523     size_t normal_size;
10524     DWORD i, num_vertices, vertex_stride;
10525     const D3DXVECTOR4 normal = {NAN, NAN, NAN, NAN};
10526     D3DVERTEXELEMENT9 *normal_declaration = NULL;
10527     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
10528 
10529     if (FAILED(hr = mesh->lpVtbl->GetDeclaration(mesh, declaration)))
10530         return hr;
10531 
10532     for (i = 0; declaration[i].Stream != 0xff; i++)
10533     {
10534         if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
10535         {
10536             normal_declaration = &declaration[i];
10537             break;
10538         }
10539     }
10540 
10541     if (!normal_declaration)
10542         return D3DERR_INVALIDCALL;
10543 
10544     if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
10545     {
10546         normal_size = sizeof(D3DXVECTOR3);
10547     }
10548     else if (normal_declaration->Type == D3DDECLTYPE_FLOAT4)
10549     {
10550         normal_size = sizeof(D3DXVECTOR4);
10551     }
10552     else
10553     {
10554         trace("Cannot clear normals\n");
10555         return E_NOTIMPL;
10556     }
10557 
10558     num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
10559     vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
10560 
10561     if (FAILED(hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
10562         return hr;
10563 
10564     vertices += normal_declaration->Offset;
10565 
10566     for (i = 0; i < num_vertices; i++, vertices += vertex_stride)
10567         memcpy(vertices, &normal, normal_size);
10568 
10569     return mesh->lpVtbl->UnlockVertexBuffer(mesh);
10570 }
10571 
10572 static void compare_normals(unsigned int line, const char *test_name,
10573         ID3DXMesh *mesh, const D3DXVECTOR3 *normals, unsigned int num_normals)
10574 {
10575     unsigned int i;
10576     BYTE *vertices;
10577     DWORD num_vertices, vertex_stride;
10578     D3DVERTEXELEMENT9 *normal_declaration = NULL;
10579     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
10580 
10581     if (FAILED(mesh->lpVtbl->GetDeclaration(mesh, declaration)))
10582     {
10583         ok_(__FILE__, line)(0, "%s: Failed to get declaration\n", test_name);
10584         return;
10585     }
10586 
10587     for (i = 0; declaration[i].Stream != 0xff; i++)
10588     {
10589         if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
10590         {
10591             normal_declaration = &declaration[i];
10592             break;
10593         }
10594     }
10595 
10596     if (!normal_declaration)
10597     {
10598         ok_(__FILE__, line)(0, "%s: Mesh has no normals\n", test_name);
10599         return;
10600     }
10601 
10602     if (normal_declaration->Type != D3DDECLTYPE_FLOAT3 && normal_declaration->Type != D3DDECLTYPE_FLOAT4)
10603     {
10604         ok_(__FILE__, line)(0, "%s: Mesh has invalid normals type\n", test_name);
10605         return;
10606     }
10607 
10608     num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
10609     vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
10610 
10611     ok_(__FILE__, line)(num_vertices == num_normals, "%s: Expected %u vertices, got %u\n", test_name,
10612             num_normals, num_vertices);
10613 
10614     if (FAILED(mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
10615     {
10616         ok_(__FILE__, line)(0, "%s: Failed to compare normals\n", test_name);
10617         return;
10618     }
10619 
10620     vertices += normal_declaration->Offset;
10621 
10622     for (i = 0; i < min(num_vertices, num_normals); i++, vertices += vertex_stride)
10623     {
10624         if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
10625         {
10626             const D3DXVECTOR3 *n = (D3DXVECTOR3 *)vertices;
10627             ok_(__FILE__, line)(compare_vec3(*n, normals[i]),
10628                     "%s: normal %2u, expected (%f, %f, %f), got (%f, %f, %f)\n",
10629                     test_name, i, normals[i].x, normals[i].y, normals[i].z, n->x, n->y, n->z);
10630         }
10631         else
10632         {
10633             const D3DXVECTOR4 *n = (D3DXVECTOR4 *)vertices;
10634             const D3DXVECTOR4 normal = {normals[i].x, normals[i].y, normals[i].z, 1.0f};
10635             ok_(__FILE__, line)(compare_vec4(*n, normal),
10636                     "%s: normal %2u, expected (%f, %f, %f, %f), got (%f, %f, %f, %f)\n",
10637                     test_name, i, normals[i].x, normals[i].y, normals[i].z, 1.0f,
10638                     n->x, n->y, n->z, n->w);
10639         }
10640     }
10641 
10642     mesh->lpVtbl->UnlockVertexBuffer(mesh);
10643 }
10644 
10645 static HRESULT compute_normals_D3DXComputeNormals(ID3DXMesh *mesh, const DWORD *adjacency)
10646 {
10647     return D3DXComputeNormals((ID3DXBaseMesh *)mesh, adjacency);
10648 }
10649 
10650 static HRESULT compute_normals_D3DXComputeTangentFrameEx(ID3DXMesh *mesh, const DWORD *adjacency)
10651 {
10652     return D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10653             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
10654             adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL);
10655 }
10656 
10657 static void test_compute_normals(void)
10658 {
10659     HRESULT hr;
10660     ULONG refcount;
10661     ID3DXMesh *mesh, *cloned_mesh;
10662     ID3DXBuffer *adjacency;
10663     IDirect3DDevice9 *device;
10664     struct test_context *test_context;
10665     unsigned int i;
10666 
10667     static const struct compute_normals_func
10668     {
10669         const char *name;
10670         HRESULT (*apply)(ID3DXMesh *mesh, const DWORD *adjacency);
10671     }
10672     compute_normals_funcs[] =
10673     {
10674         {"D3DXComputeNormals",        compute_normals_D3DXComputeNormals       },
10675         {"D3DXComputeTangentFrameEx", compute_normals_D3DXComputeTangentFrameEx}
10676     };
10677 
10678     static const D3DXVECTOR3 box_normals[24] =
10679     {
10680         {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f},
10681         { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f},
10682         { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f},
10683         { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f},
10684         { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f},
10685         { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}
10686     };
10687     const float box_normal_component = 1.0f / sqrtf(3.0f);
10688     const D3DXVECTOR3 box_normals_adjacency[24] =
10689     {
10690         {-box_normal_component, -box_normal_component, -box_normal_component},
10691         {-box_normal_component, -box_normal_component,  box_normal_component},
10692         {-box_normal_component,  box_normal_component,  box_normal_component},
10693         {-box_normal_component,  box_normal_component, -box_normal_component},
10694         {-box_normal_component,  box_normal_component, -box_normal_component},
10695         {-box_normal_component,  box_normal_component,  box_normal_component},
10696         { box_normal_component,  box_normal_component,  box_normal_component},
10697         { box_normal_component,  box_normal_component, -box_normal_component},
10698         { box_normal_component,  box_normal_component, -box_normal_component},
10699         { box_normal_component,  box_normal_component,  box_normal_component},
10700         { box_normal_component, -box_normal_component,  box_normal_component},
10701         { box_normal_component, -box_normal_component, -box_normal_component},
10702         {-box_normal_component, -box_normal_component,  box_normal_component},
10703         {-box_normal_component, -box_normal_component, -box_normal_component},
10704         { box_normal_component, -box_normal_component, -box_normal_component},
10705         { box_normal_component, -box_normal_component,  box_normal_component},
10706         {-box_normal_component, -box_normal_component,  box_normal_component},
10707         { box_normal_component, -box_normal_component,  box_normal_component},
10708         { box_normal_component,  box_normal_component,  box_normal_component},
10709         {-box_normal_component,  box_normal_component,  box_normal_component},
10710         {-box_normal_component, -box_normal_component, -box_normal_component},
10711         {-box_normal_component,  box_normal_component, -box_normal_component},
10712         { box_normal_component,  box_normal_component, -box_normal_component},
10713         { box_normal_component, -box_normal_component, -box_normal_component}
10714     };
10715     static const D3DXVECTOR3 box_normals_adjacency_area[24] =
10716     {
10717         {-0.666667f, -0.333333f, -0.666667f}, {-0.333333f, -0.666667f,  0.666667f},
10718         {-0.816496f,  0.408248f,  0.408248f}, {-0.408248f,  0.816496f, -0.408248f},
10719         {-0.408248f,  0.816496f, -0.408248f}, {-0.816496f,  0.408248f,  0.408248f},
10720         { 0.333333f,  0.666667f,  0.666667f}, { 0.666667f,  0.333333f, -0.666667f},
10721         { 0.666667f,  0.333333f, -0.666667f}, { 0.333333f,  0.666667f,  0.666667f},
10722         { 0.816496f, -0.408248f,  0.408248f}, { 0.408248f, -0.816496f, -0.408248f},
10723         {-0.333333f, -0.666667f,  0.666667f}, {-0.666667f, -0.333333f, -0.666667f},
10724         { 0.408248f, -0.816496f, -0.408248f}, { 0.816496f, -0.408248f,  0.408248f},
10725         {-0.333333f, -0.666667f,  0.666667f}, { 0.816497f, -0.408248f,  0.408248f},
10726         { 0.333333f,  0.666667f,  0.666667f}, {-0.816497f,  0.408248f,  0.408248f},
10727         {-0.666667f, -0.333333f, -0.666667f}, {-0.408248f,  0.816497f, -0.408248f},
10728         { 0.666667f,  0.333333f, -0.666667f}, { 0.408248f, -0.816496f, -0.408248f}
10729     };
10730     static const D3DXVECTOR3 box_normals_position1f[24] = {{0}};
10731     static const D3DXVECTOR3 box_normals_position2f[24] =
10732     {
10733         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
10734         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f},
10735         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
10736         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
10737         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
10738         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
10739         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
10740         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}
10741     };
10742 
10743     static const D3DXVECTOR3 sphere_normals[22] =
10744     {
10745         { 0.000000f, -0.000000f,  1.000000f}, { 0.000000f,  0.582244f,  0.813014f},
10746         { 0.582244f, -0.000000f,  0.813014f}, {-0.000000f, -0.582244f,  0.813014f},
10747         {-0.582244f,  0.000000f,  0.813014f}, {-0.000000f,  0.890608f,  0.454772f},
10748         { 0.890608f,  0.000000f,  0.454772f}, { 0.000000f, -0.890608f,  0.454772f},
10749         {-0.890608f, -0.000000f,  0.454772f}, { 0.000000f,  1.000000f, -0.000000f},
10750         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10751         {-1.000000f,  0.000000f, -0.000000f}, { 0.000000f,  0.890608f, -0.454773f},
10752         { 0.890608f, -0.000000f, -0.454772f}, {-0.000000f, -0.890608f, -0.454773f},
10753         {-0.890608f,  0.000000f, -0.454773f}, { 0.000000f,  0.582244f, -0.813015f},
10754         { 0.582244f, -0.000000f, -0.813015f}, { 0.000000f, -0.582244f, -0.813015f},
10755         {-0.582243f,  0.000000f, -0.813015f}, { 0.000000f,  0.000000f, -1.000000f}
10756     };
10757     static const D3DXVECTOR3 sphere_normals_area[22] =
10758     {
10759         { 0.000000f, -0.000000f,  1.000000f}, {-0.215311f,  0.554931f,  0.803550f},
10760         { 0.554931f,  0.215311f,  0.803550f}, { 0.215311f, -0.554931f,  0.803550f},
10761         {-0.554931f, -0.215311f,  0.803550f}, {-0.126638f,  0.872121f,  0.472618f},
10762         { 0.872121f,  0.126638f,  0.472618f}, { 0.126638f, -0.872121f,  0.472618f},
10763         {-0.872121f, -0.126637f,  0.472618f}, { 0.000000f,  1.000000f, -0.000000f},
10764         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10765         {-1.000000f,  0.000000f, -0.000000f}, { 0.126638f,  0.872121f, -0.472618f},
10766         { 0.872121f, -0.126638f, -0.472618f}, {-0.126638f, -0.872121f, -0.472618f},
10767         {-0.872121f,  0.126638f, -0.472618f}, { 0.215311f,  0.554931f, -0.803550f},
10768         { 0.554931f, -0.215311f, -0.803550f}, {-0.215311f, -0.554931f, -0.803550f},
10769         {-0.554931f,  0.215311f, -0.803550f}, { 0.000000f,  0.000000f, -1.000000f}
10770     };
10771     static const D3DXVECTOR3 sphere_normals_equal[22] =
10772     {
10773         { 0.000000f, -0.000000f,  1.000000f}, {-0.134974f,  0.522078f,  0.842150f},
10774         { 0.522078f,  0.134974f,  0.842150f}, { 0.134974f, -0.522078f,  0.842150f},
10775         {-0.522078f, -0.134974f,  0.842150f}, {-0.026367f,  0.857121f,  0.514440f},
10776         { 0.857121f,  0.026367f,  0.514440f}, { 0.026367f, -0.857121f,  0.514440f},
10777         {-0.857121f, -0.026367f,  0.514440f}, { 0.000000f,  1.000000f, -0.000000f},
10778         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10779         {-1.000000f,  0.000000f, -0.000000f}, { 0.026367f,  0.857121f, -0.514440f},
10780         { 0.857121f, -0.026367f, -0.514440f}, {-0.026367f, -0.857121f, -0.514440f},
10781         {-0.857121f,  0.026367f, -0.514440f}, { 0.134975f,  0.522078f, -0.842150f},
10782         { 0.522078f, -0.134975f, -0.842150f}, {-0.134974f, -0.522078f, -0.842150f},
10783         {-0.522078f,  0.134974f, -0.842150f}, { 0.000000f,  0.000000f, -1.000000f}
10784     };
10785 
10786     static const D3DVERTEXELEMENT9 position3f_normal1f_declaration[] =
10787     {
10788         {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10789         {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10790         D3DDECL_END()
10791     };
10792     static const D3DVERTEXELEMENT9 position3f_normal2f_declaration[] =
10793     {
10794         {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10795         {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10796         D3DDECL_END()
10797     };
10798     static const D3DVERTEXELEMENT9 normal4f_position3f_declaration[] =
10799     {
10800         {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10801         {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10802         D3DDECL_END()
10803     };
10804     static const D3DVERTEXELEMENT9 position1f_normal3f_declaration[] =
10805     {
10806         {0, 0,                   D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10807         {0, sizeof(float),       D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10808         D3DDECL_END()
10809     };
10810     static const D3DVERTEXELEMENT9 position2f_normal3f_declaration[] =
10811     {
10812         {0, 0,                   D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10813         {0, sizeof(D3DXVECTOR2), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10814         D3DDECL_END()
10815     };
10816     static const D3DVERTEXELEMENT9 position4f_normal3f_declaration[] =
10817     {
10818         {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10819         {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10820         D3DDECL_END()
10821     };
10822 
10823     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
10824     {
10825         hr = compute_normals_funcs[i].apply(NULL, NULL);
10826         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", compute_normals_funcs[i].name, hr);
10827     }
10828 
10829     if (!(test_context = new_test_context()))
10830     {
10831         skip("Couldn't create test context\n");
10832         return;
10833     }
10834     device = test_context->device;
10835 
10836     hr = D3DXCreateBox(device, 1.0f, 1.0f, 1.0f, &mesh, &adjacency);
10837     ok(SUCCEEDED(hr), "D3DXCreateBox failed %#x\n", hr);
10838 
10839     /* Check wrong input */
10840     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10841             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10842     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10843 
10844     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DDECLUSAGE_NORMAL, 0,
10845             D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA | D3DXTANGENT_WEIGHT_EQUAL,
10846             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10847     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10848 
10849     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10850             D3DDECLUSAGE_NORMAL, 0, 0, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10851     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10852 
10853     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10854             D3DDECLUSAGE_NORMAL, 1, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
10855             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10856     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10857 
10858     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10859             D3DX_DEFAULT, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
10860             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10861     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10862 
10863     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10864             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_CALCULATE_NORMALS,
10865             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10866     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10867 
10868     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
10869     {
10870         const struct compute_normals_func *func = &compute_normals_funcs[i];
10871 
10872         /* Mesh without normals */
10873         hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_XYZ, device, &cloned_mesh);
10874         ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
10875 
10876         hr = func->apply(cloned_mesh, NULL);
10877         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
10878 
10879         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10880         ok(!refcount, "Mesh has %u references left\n", refcount);
10881 
10882         /* Mesh without positions */
10883         hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_NORMAL, device, &cloned_mesh);
10884         ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
10885 
10886         hr = func->apply(cloned_mesh, NULL);
10887         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
10888 
10889         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10890         ok(!refcount, "Mesh has %u references left\n", refcount);
10891 
10892         /* Mesh with D3DDECLTYPE_FLOAT1 normals */
10893         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal1f_declaration, device, &cloned_mesh);
10894         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10895 
10896         hr = func->apply(cloned_mesh, NULL);
10897         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
10898 
10899         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10900         ok(!refcount, "Mesh has %u references left\n", refcount);
10901 
10902         /* Mesh with D3DDECLTYPE_FLOAT2 normals */
10903         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal2f_declaration, device, &cloned_mesh);
10904         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10905 
10906         hr = func->apply(cloned_mesh, NULL);
10907         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
10908 
10909         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10910         ok(!refcount, "Mesh has %u references left\n", refcount);
10911 
10912         /* Mesh without adjacency data */
10913         hr = clear_normals(mesh);
10914         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10915 
10916         hr = func->apply(mesh, NULL);
10917         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10918 
10919         compare_normals(__LINE__, func->name, mesh, box_normals, ARRAY_SIZE(box_normals));
10920 
10921         /* Mesh with adjacency data */
10922         hr = clear_normals(mesh);
10923         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10924 
10925         hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
10926         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10927 
10928         compare_normals(__LINE__, func->name, mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
10929 
10930         /* Mesh with custom vertex format, D3DDECLTYPE_FLOAT4 normals and adjacency */
10931         hr = mesh->lpVtbl->CloneMesh(mesh, 0, normal4f_position3f_declaration, device, &cloned_mesh);
10932         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10933 
10934         hr = clear_normals(cloned_mesh);
10935         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10936 
10937         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
10938         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10939 
10940         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
10941 
10942         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10943         ok(!refcount, "Mesh has %u references left\n", refcount);
10944 
10945         /* Mesh with D3DDECLTYPE_FLOAT1 positions and D3DDECLTYPE_FLOAT3 normals */
10946         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position1f_normal3f_declaration, device, &cloned_mesh);
10947         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10948 
10949         hr = clear_normals(cloned_mesh);
10950         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10951 
10952         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
10953         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10954 
10955         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position1f, ARRAY_SIZE(box_normals_position1f));
10956 
10957         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10958         ok(!refcount, "Mesh has %u references left\n", refcount);
10959 
10960         /* Mesh with D3DDECLTYPE_FLOAT2 positions and D3DDECLTYPE_FLOAT3 normals */
10961         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position2f_normal3f_declaration, device, &cloned_mesh);
10962         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10963 
10964         hr = clear_normals(cloned_mesh);
10965         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10966 
10967         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
10968         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10969 
10970         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position2f, ARRAY_SIZE(box_normals_position2f));
10971 
10972         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10973         ok(!refcount, "Mesh has %u references left\n", refcount);
10974 
10975         /* Mesh with D3DDECLTYPE_FLOAT4 positions and D3DDECLTYPE_FLOAT3 normals */
10976         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position4f_normal3f_declaration, device, &cloned_mesh);
10977         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10978 
10979         hr = clear_normals(cloned_mesh);
10980         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10981 
10982         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
10983         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10984 
10985         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
10986 
10987         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10988         ok(!refcount, "Mesh has %u references left\n", refcount);
10989     }
10990 
10991     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10992             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
10993             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10994     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
10995 
10996     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
10997 
10998     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10999             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11000             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11001     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11002 
11003     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
11004 
11005     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11006             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11007             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11008     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11009 
11010     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
11011 
11012     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11013             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11014             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11015     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11016 
11017     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
11018 
11019     refcount = mesh->lpVtbl->Release(mesh);
11020     ok(!refcount, "Mesh has %u references left\n", refcount);
11021     refcount = ID3DXBuffer_Release(adjacency);
11022     ok(!refcount, "Buffer has %u references left\n", refcount);
11023 
11024     hr = D3DXCreateSphere(device, 1.0f, 4, 6, &mesh, &adjacency);
11025     ok(SUCCEEDED(hr), "D3DXCreateSphere failed %#x\n", hr);
11026 
11027     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
11028     {
11029         const struct compute_normals_func *func = &compute_normals_funcs[i];
11030 
11031         /* Sphere without adjacency data */
11032         hr = clear_normals(mesh);
11033         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11034 
11035         hr = func->apply(mesh, NULL);
11036         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11037 
11038         compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
11039 
11040         /* Sphere with adjacency data */
11041         hr = clear_normals(mesh);
11042         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11043 
11044         hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11045         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11046 
11047         compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
11048     }
11049 
11050     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11051             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11052             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11053     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11054 
11055     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
11056 
11057     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11058             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11059             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11060     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11061 
11062     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
11063 
11064     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11065             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11066             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11067     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11068 
11069     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
11070 
11071     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11072             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11073             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11074     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11075 
11076     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
11077 
11078     refcount = mesh->lpVtbl->Release(mesh);
11079     ok(!refcount, "Mesh has %u references left\n", refcount);
11080     refcount = ID3DXBuffer_Release(adjacency);
11081     ok(!refcount, "Buffer has %u references left\n", refcount);
11082 
11083     free_test_context(test_context);
11084 }
11085 
11086 static void D3DXCreateAnimationControllerTest(void)
11087 {
11088     HRESULT hr;
11089     ID3DXAnimationController *animation;
11090     UINT value;
11091 
11092     hr = D3DXCreateAnimationController(0, 0, 0, 0, NULL);
11093     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11094 
11095     animation = (void*)0xdeadbeef;
11096     hr = D3DXCreateAnimationController(0, 1, 1, 1, &animation);
11097     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11098     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11099 
11100     animation = (void*)0xdeadbeef;
11101     hr = D3DXCreateAnimationController(1, 0, 1, 1, &animation);
11102     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11103     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11104 
11105     animation = (void*)0xdeadbeef;
11106     hr = D3DXCreateAnimationController(1, 1, 0, 1, &animation);
11107     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11108     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11109 
11110     animation = (void*)0xdeadbeef;
11111     hr = D3DXCreateAnimationController(1, 1, 1, 0, &animation);
11112     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11113     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11114 
11115     hr = D3DXCreateAnimationController(1, 1, 1, 1, &animation);
11116     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11117 
11118     value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
11119     ok(value == 1, "Got unexpected value %u.\n", value);
11120 
11121     value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
11122     ok(value == 1, "Got unexpected value %u.\n", value);
11123 
11124     value = animation->lpVtbl->GetMaxNumTracks(animation);
11125     ok(value == 1, "Got unexpected value %u.\n", value);
11126 
11127     value = animation->lpVtbl->GetMaxNumEvents(animation);
11128     ok(value == 1, "Got unexpected value %u.\n", value);
11129 
11130     animation->lpVtbl->Release(animation);
11131 
11132     hr = D3DXCreateAnimationController(100, 101, 102, 103, &animation);
11133     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11134 
11135     value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
11136     ok(value == 100, "Got unexpected value %u.\n", value);
11137 
11138     value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
11139     ok(value == 101, "Got unexpected value %u.\n", value);
11140 
11141     value = animation->lpVtbl->GetMaxNumTracks(animation);
11142     ok(value == 102, "Got unexpected value %u.\n", value);
11143 
11144     value = animation->lpVtbl->GetMaxNumEvents(animation);
11145     ok(value == 103, "Got unexpected value %u.\n", value);
11146 
11147     animation->lpVtbl->Release(animation);
11148 }
11149 
11150 static void test_D3DXFrameFind(void)
11151 {
11152     static char n1[] = "name1";
11153     static char n2[] = "name2";
11154     static char n3[] = "name3";
11155     static char n4[] = "name4";
11156     static char n5[] = "name5";
11157     static char n6[] = "name6";
11158     static char N1[] = "Name1";
11159     D3DXFRAME root, sibling, sibling2, child, *ret;
11160     D3DXFRAME child2, child3;
11161 
11162     ret = D3DXFrameFind(NULL, NULL);
11163     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11164 
11165     ret = D3DXFrameFind(NULL, "test");
11166     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11167 
11168     memset(&root, 0, sizeof(root));
11169 
11170     ret = D3DXFrameFind(&root, NULL);
11171     ok(ret == &root, "Unexpected frame, %p.\n", ret);
11172 
11173     root.Name = n1;
11174     ret = D3DXFrameFind(&root, NULL);
11175     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11176 
11177     ret = D3DXFrameFind(&root, n1);
11178     ok(ret == &root, "Unexpected frame, %p.\n", ret);
11179 
11180     ret = D3DXFrameFind(&root, N1);
11181     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11182 
11183     /* Test siblings order traversal. */
11184     memset(&sibling, 0, sizeof(sibling));
11185     sibling.Name = n2;
11186     root.pFrameSibling = &sibling;
11187     ret = D3DXFrameFind(&root, n2);
11188     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11189 
11190     memset(&sibling2, 0, sizeof(sibling2));
11191     sibling2.Name = n2;
11192     sibling.pFrameSibling = &sibling2;
11193     ret = D3DXFrameFind(&root, n2);
11194     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11195 
11196     sibling2.Name = n3;
11197     ret = D3DXFrameFind(&root, n3);
11198     ok(ret == &sibling2, "Unexpected frame, %p.\n", ret);
11199 
11200     /* Siblings first. */
11201     memset(&child, 0, sizeof(child));
11202     child.Name = n2;
11203     root.pFrameFirstChild = &child;
11204     ret = D3DXFrameFind(&root, n2);
11205     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11206 
11207     child.Name = n4;
11208     ret = D3DXFrameFind(&root, n4);
11209     ok(ret == &child, "Unexpected frame, %p.\n", ret);
11210 
11211     /* Link a grandchild and another one for sibling. */
11212     memset(&child2, 0, sizeof(child2));
11213     memset(&child3, 0, sizeof(child3));
11214     child2.Name = child3.Name = n5;
11215     sibling.pFrameFirstChild = &child2;
11216     child.pFrameFirstChild = &child3;
11217     ret = D3DXFrameFind(&root, n5);
11218     ok(ret == &child2, "Unexpected frame, %p.\n", ret);
11219 
11220     child3.Name = n6;
11221     ret = D3DXFrameFind(&root, n6);
11222     ok(ret == &child3, "Unexpected frame, %p.\n", ret);
11223 }
11224 
11225 START_TEST(mesh)
11226 {
11227     D3DXBoundProbeTest();
11228     D3DXComputeBoundingBoxTest();
11229     D3DXComputeBoundingSphereTest();
11230     D3DXGetFVFVertexSizeTest();
11231     D3DXIntersectTriTest();
11232     D3DXCreateMeshTest();
11233     D3DXCreateMeshFVFTest();
11234     D3DXLoadMeshTest();
11235     D3DXCreateBoxTest();
11236     D3DXCreatePolygonTest();
11237     D3DXCreateSphereTest();
11238     D3DXCreateCylinderTest();
11239     D3DXCreateTextTest();
11240     D3DXCreateTorusTest();
11241     D3DXCreateAnimationControllerTest();
11242     test_get_decl_length();
11243     test_get_decl_vertex_size();
11244     test_fvf_decl_conversion();
11245     D3DXGenerateAdjacencyTest();
11246     test_update_semantics();
11247     test_create_skin_info();
11248     test_convert_adjacency_to_point_reps();
11249     test_convert_point_reps_to_adjacency();
11250     test_weld_vertices();
11251     test_clone_mesh();
11252     test_valid_mesh();
11253     test_optimize_faces();
11254     test_compute_normals();
11255     test_D3DXFrameFind();
11256 }
11257