1 /*
2  * Copyright 2008 David Adam
3  * Copyright 2008 Luis Busquets
4  * Copyright 2009 Henri Verbeet for CodeWeavers
5  * Copyright 2011 Michael Mc Donnell
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #define COBJMACROS
23 #include <stdio.h>
24 #include <float.h>
25 #include <limits.h>
26 #include "wine/test.h"
27 #include "d3dx9.h"
28 #include "initguid.h"
29 #include "rmxftmpl.h"
30 #include "rmxfguid.h"
31 
32 #ifndef NAN
33 /* From wine/port.h */
34 static inline float __port_nan(void)
35 {
36     static const unsigned __nan_bytes = 0x7fc00000;
37     return *(const float *)&__nan_bytes;
38 }
39 #define NAN __port_nan()
40 #endif
41 
42 /* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose
43  * function call traces of ID3DXAllocateHierarchy callbacks. */
44 #define TRACECALLBACK if(winetest_debug > 1) trace
45 
46 #define admitted_error 0.0001f
47 
48 #define compare_vertex_sizes(type, exp) \
49     got=D3DXGetFVFVertexSize(type); \
50     ok(got==exp, "Expected: %d, Got: %d\n", exp, got);
51 
52 #define compare_float(got, exp) \
53     do { \
54         float _got = (got); \
55         float _exp = (exp); \
56         ok(_got == _exp, "Expected: %g, Got: %g\n", _exp, _got); \
57     } while (0)
58 
59 static BOOL compare(FLOAT u, FLOAT v)
60 {
61     return (fabs(u-v) < admitted_error);
62 }
63 
64 static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v)
65 {
66     return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
67 }
68 
69 static BOOL compare_vec4(D3DXVECTOR4 u, D3DXVECTOR4 v)
70 {
71     return compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) && compare(u.w, v.w);
72 }
73 
74 #define check_floats(got, exp, dim) check_floats_(__LINE__, "", got, exp, dim)
75 static void check_floats_(int line, const char *prefix, const float *got, const float *exp, int dim)
76 {
77     int i;
78     char exp_buffer[256] = "";
79     char got_buffer[256] = "";
80     char *exp_buffer_ptr = exp_buffer;
81     char *got_buffer_ptr = got_buffer;
82     BOOL equal = TRUE;
83 
84     for (i = 0; i < dim; i++) {
85         if (i) {
86             exp_buffer_ptr += sprintf(exp_buffer_ptr, ", ");
87             got_buffer_ptr += sprintf(got_buffer_ptr, ", ");
88         }
89         equal = equal && compare(*exp, *got);
90         exp_buffer_ptr += sprintf(exp_buffer_ptr, "%g", *exp);
91         got_buffer_ptr += sprintf(got_buffer_ptr, "%g", *got);
92         exp++; got++;
93     }
94     ok_(__FILE__,line)(equal, "%sExpected (%s), got (%s)", prefix, exp_buffer, got_buffer);
95 }
96 
97 struct vertex
98 {
99     D3DXVECTOR3 position;
100     D3DXVECTOR3 normal;
101 };
102 
103 typedef WORD face[3];
104 
105 static BOOL compare_face(face a, face b)
106 {
107     return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
108 }
109 
110 struct test_context
111 {
112     HWND hwnd;
113     IDirect3D9 *d3d;
114     IDirect3DDevice9 *device;
115 };
116 
117 /* Initializes a test context struct. Use it to initialize DirectX.
118  *
119  * Returns NULL if an error occurred.
120  */
121 static struct test_context *new_test_context(void)
122 {
123     HRESULT hr;
124     HWND hwnd = NULL;
125     IDirect3D9 *d3d = NULL;
126     IDirect3DDevice9 *device = NULL;
127     D3DPRESENT_PARAMETERS d3dpp = {0};
128     struct test_context *test_context;
129 
130     if (!(hwnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
131             640, 480, NULL, NULL, NULL, NULL)))
132     {
133         skip("Couldn't create application window\n");
134         goto error;
135     }
136 
137     d3d = Direct3DCreate9(D3D_SDK_VERSION);
138     if (!d3d)
139     {
140         skip("Couldn't create IDirect3D9 object\n");
141         goto error;
142     }
143 
144     memset(&d3dpp, 0, sizeof(d3dpp));
145     d3dpp.Windowed = TRUE;
146     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
147     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
148                                  D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
149     if (FAILED(hr))
150     {
151         skip("Couldn't create IDirect3DDevice9 object %#x\n", hr);
152         goto error;
153     }
154 
155     test_context = HeapAlloc(GetProcessHeap(), 0, sizeof(*test_context));
156     if (!test_context)
157     {
158         skip("Couldn't allocate memory for test_context\n");
159         goto error;
160     }
161     test_context->hwnd = hwnd;
162     test_context->d3d = d3d;
163     test_context->device = device;
164 
165     return test_context;
166 
167 error:
168     if (device)
169         IDirect3DDevice9_Release(device);
170 
171     if (d3d)
172         IDirect3D9_Release(d3d);
173 
174     if (hwnd)
175         DestroyWindow(hwnd);
176 
177     return NULL;
178 }
179 
180 static void free_test_context(struct test_context *test_context)
181 {
182     if (!test_context)
183         return;
184 
185     if (test_context->device)
186         IDirect3DDevice9_Release(test_context->device);
187 
188     if (test_context->d3d)
189         IDirect3D9_Release(test_context->d3d);
190 
191     if (test_context->hwnd)
192         DestroyWindow(test_context->hwnd);
193 
194     HeapFree(GetProcessHeap(), 0, test_context);
195 }
196 
197 struct mesh
198 {
199     DWORD number_of_vertices;
200     struct vertex *vertices;
201 
202     DWORD number_of_faces;
203     face *faces;
204 
205     DWORD fvf;
206     UINT vertex_size;
207 };
208 
209 static void free_mesh(struct mesh *mesh)
210 {
211     HeapFree(GetProcessHeap(), 0, mesh->faces);
212     HeapFree(GetProcessHeap(), 0, mesh->vertices);
213 }
214 
215 static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
216 {
217     mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
218     if (!mesh->vertices)
219     {
220         return FALSE;
221     }
222     mesh->number_of_vertices = number_of_vertices;
223 
224     mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
225     if (!mesh->faces)
226     {
227         HeapFree(GetProcessHeap(), 0, mesh->vertices);
228         return FALSE;
229     }
230     mesh->number_of_faces = number_of_faces;
231 
232     return TRUE;
233 }
234 
235 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
236 {
237     HRESULT hr;
238     DWORD number_of_vertices, number_of_faces;
239     IDirect3DVertexBuffer9 *vertex_buffer;
240     IDirect3DIndexBuffer9 *index_buffer;
241     D3DVERTEXBUFFER_DESC vertex_buffer_description;
242     D3DINDEXBUFFER_DESC index_buffer_description;
243     struct vertex *vertices;
244     face *faces;
245     int expected, i;
246 
247     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
248     ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
249        name, number_of_vertices, mesh->number_of_vertices);
250 
251     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
252     ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
253        name, number_of_faces, mesh->number_of_faces);
254 
255     /* vertex buffer */
256     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
257     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
258 
259     if (hr != D3D_OK)
260     {
261         skip("Couldn't get vertex buffer\n");
262     }
263     else
264     {
265         hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
266         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
267 
268         if (hr != D3D_OK)
269         {
270             skip("Couldn't get vertex buffer description\n");
271         }
272         else
273         {
274             ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
275                name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
276             ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
277                name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
278             ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
279             ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
280                name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
281             ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
282                name, vertex_buffer_description.FVF, mesh->fvf);
283             if (mesh->fvf == 0)
284             {
285                 expected = number_of_vertices * mesh->vertex_size;
286             }
287             else
288             {
289                 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
290             }
291             ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
292                name, vertex_buffer_description.Size, expected);
293         }
294 
295         /* specify offset and size to avoid potential overruns */
296         hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
297                 (void **)&vertices, D3DLOCK_DISCARD);
298         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
299 
300         if (hr != D3D_OK)
301         {
302             skip("Couldn't lock vertex buffer\n");
303         }
304         else
305         {
306             for (i = 0; i < number_of_vertices; i++)
307             {
308                 ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
309                    "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
310                    vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
311                    mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
312                 ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
313                    "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
314                    vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
315                    mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
316             }
317 
318             IDirect3DVertexBuffer9_Unlock(vertex_buffer);
319         }
320 
321         IDirect3DVertexBuffer9_Release(vertex_buffer);
322     }
323 
324     /* index buffer */
325     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
326     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
327 
328     if (!index_buffer)
329     {
330         skip("Couldn't get index buffer\n");
331     }
332     else
333     {
334         hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
335         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
336 
337         if (hr != D3D_OK)
338         {
339             skip("Couldn't get index buffer description\n");
340         }
341         else
342         {
343             ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
344                name, index_buffer_description.Format, D3DFMT_INDEX16);
345             ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
346                name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
347             ok(index_buffer_description.Usage == 0, "Test %s, result %#x, expected %#x.\n",
348                     name, index_buffer_description.Usage, 0);
349             ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
350                name, index_buffer_description.Pool, D3DPOOL_MANAGED);
351             expected = number_of_faces * sizeof(WORD) * 3;
352             ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
353                name, index_buffer_description.Size, expected);
354         }
355 
356         /* specify offset and size to avoid potential overruns */
357         hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
358                 (void **)&faces, D3DLOCK_DISCARD);
359         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
360 
361         if (hr != D3D_OK)
362         {
363             skip("Couldn't lock index buffer\n");
364         }
365         else
366         {
367             for (i = 0; i < number_of_faces; i++)
368             {
369                 ok(compare_face(faces[i], mesh->faces[i]),
370                    "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
371                    faces[i][0], faces[i][1], faces[i][2],
372                    mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
373             }
374 
375             IDirect3DIndexBuffer9_Unlock(index_buffer);
376         }
377 
378         IDirect3DIndexBuffer9_Release(index_buffer);
379     }
380 }
381 
382 static void D3DXBoundProbeTest(void)
383 {
384     BOOL result;
385     D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
386     FLOAT radius;
387 
388 /*____________Test the Box case___________________________*/
389     bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
390     top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
391 
392     raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
393     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
394     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
395     ok(result == TRUE, "expected TRUE, received FALSE\n");
396 
397     raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
398     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
399     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
400     ok(result == FALSE, "expected FALSE, received TRUE\n");
401 
402     rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
403     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
404     ok(result == TRUE, "expected TRUE, received FALSE\n");
405 
406     bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
407     top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
408     rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
409     raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
410     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
411     ok(result == FALSE, "expected FALSE, received TRUE\n");
412 
413     bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
414     top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
415 
416     raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
417     rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
418     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
419     ok(result == TRUE, "expected TRUE, received FALSE\n");
420 
421     bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
422     top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
423 
424     raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
425     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
426     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
427     ok(result == FALSE, "expected FALSE, received TRUE\n");
428 
429     raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
430     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
431     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
432     ok(result == TRUE, "expected TRUE, received FALSE\n");
433 
434 /*____________Test the Sphere case________________________*/
435     radius = sqrt(77.0f);
436     center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
437     raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
438 
439     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
440     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
441     ok(result == TRUE, "expected TRUE, received FALSE\n");
442 
443     rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
444     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
445     ok(result == FALSE, "expected FALSE, received TRUE\n");
446 
447     rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
448     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
449     ok(result == FALSE, "expected FALSE, received TRUE\n");
450 }
451 
452 static void D3DXComputeBoundingBoxTest(void)
453 {
454     D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
455     HRESULT hr;
456 
457     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
458     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
459     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
460     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
461     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
462 
463     exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
464     exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
465 
466     hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
467 
468     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
469     ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
470     ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
471 
472 /*________________________*/
473 
474     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
475     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
476     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
477     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
478     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
479 
480     exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
481     exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
482 
483     hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
484 
485     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
486     ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
487     ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
488 
489 /*________________________*/
490 
491     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
492     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
493     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
494     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
495     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
496 
497     exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
498     exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
499 
500     hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
501 
502     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
503     ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
504     ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
505 
506 /*________________________*/
507     hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
508     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
509 
510 /*________________________*/
511     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
512     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
513 
514 /*________________________*/
515     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
516     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
517 }
518 
519 static void D3DXComputeBoundingSphereTest(void)
520 {
521     D3DXVECTOR3 exp_cen, got_cen, vertex[5];
522     FLOAT exp_rad, got_rad;
523     HRESULT hr;
524 
525     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
526     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
527     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
528     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
529     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
530 
531     exp_rad = 6.928203f;
532     exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
533 
534     hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
535 
536     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
537     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
538     ok( compare_vec3(exp_cen,got_cen), "Expected center: (%f, %f, %f), got center: (%f, %f, %f)\n", exp_cen.x,exp_cen.y,exp_cen.z,got_cen.x,got_cen.y,got_cen.z);
539 
540 /*________________________*/
541 
542     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
543     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
544     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
545     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
546     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
547 
548     exp_rad = 13.707883f;
549     exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
550 
551     hr = D3DXComputeBoundingSphere(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
552 
553     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
554     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
555     ok( compare_vec3(exp_cen,got_cen), "Expected center: (%f, %f, %f), got center: (%f, %f, %f)\n", exp_cen.x,exp_cen.y,exp_cen.z,got_cen.x,got_cen.y,got_cen.z);
556 
557 /*________________________*/
558     hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
559     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
560 
561 /*________________________*/
562     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
563     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
564 
565 /*________________________*/
566     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
567     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
568 }
569 
570 static void print_elements(const D3DVERTEXELEMENT9 *elements)
571 {
572     D3DVERTEXELEMENT9 last = D3DDECL_END();
573     const D3DVERTEXELEMENT9 *ptr = elements;
574     int count = 0;
575 
576     while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
577     {
578         trace(
579             "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
580              count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
581         ptr++;
582         count++;
583     }
584 }
585 
586 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
587         unsigned int line, unsigned int test_id)
588 {
589     D3DVERTEXELEMENT9 last = D3DDECL_END();
590     unsigned int i;
591 
592     for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
593     {
594         int end1 = memcmp(&elements[i], &last, sizeof(last));
595         int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
596         int status;
597 
598         if (!end1 && !end2) break;
599 
600         status = !end1 ^ !end2;
601         ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
602                 line, test_id, end1 ? "shorter" : "longer");
603         if (status)
604         {
605             print_elements(elements);
606             break;
607         }
608 
609         status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
610         ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
611         if (status)
612         {
613             print_elements(elements);
614             break;
615         }
616     }
617 }
618 
619 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
620         HRESULT expected_hr, unsigned int line, unsigned int test_id)
621 {
622     HRESULT hr;
623     D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
624 
625     hr = D3DXDeclaratorFromFVF(test_fvf, decl);
626     ok(hr == expected_hr,
627             "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
628             line, test_id, hr, expected_hr);
629     if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
630 }
631 
632 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
633         HRESULT expected_hr, unsigned int line, unsigned int test_id)
634 {
635     HRESULT hr;
636     DWORD result_fvf = 0xdeadbeef;
637 
638     hr = D3DXFVFFromDeclarator(decl, &result_fvf);
639     ok(hr == expected_hr,
640        "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
641        line, test_id, hr, expected_hr);
642     if (SUCCEEDED(hr))
643     {
644         ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
645                 line, test_id, result_fvf, expected_fvf);
646     }
647 }
648 
649 static void test_fvf_decl_conversion(void)
650 {
651     static const struct
652     {
653         D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
654         DWORD fvf;
655     }
656     test_data[] =
657     {
658         {{
659             D3DDECL_END(),
660         }, 0},
661         {{
662             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
663             D3DDECL_END(),
664         }, D3DFVF_XYZ},
665         {{
666             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
667             D3DDECL_END(),
668         }, D3DFVF_XYZRHW},
669         {{
670             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
671             D3DDECL_END(),
672         }, D3DFVF_XYZRHW},
673         {{
674             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
675             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
676             D3DDECL_END(),
677         }, D3DFVF_XYZB1},
678         {{
679             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
680             {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
681             D3DDECL_END(),
682         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
683         {{
684             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
685             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
686             D3DDECL_END(),
687         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
688         {{
689             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
690             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
691             D3DDECL_END(),
692         }, D3DFVF_XYZB2},
693         {{
694             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
695             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
696             {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
697             D3DDECL_END(),
698         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
699         {{
700             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
701             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
702             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
703             D3DDECL_END(),
704         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
705         {{
706             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
707             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
708             D3DDECL_END(),
709         }, D3DFVF_XYZB3},
710         {{
711             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
712             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
713             {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
714             D3DDECL_END(),
715         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
716         {{
717             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
718             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
719             {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
720             D3DDECL_END(),
721         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
722         {{
723             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
724             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
725             D3DDECL_END(),
726         }, D3DFVF_XYZB4},
727         {{
728             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
729             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
730             {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
731             D3DDECL_END(),
732         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
733         {{
734             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
735             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
736             {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
737             D3DDECL_END(),
738         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
739         {{
740             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
741             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
742             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
743             D3DDECL_END(),
744         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
745         {{
746             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
747             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
748             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
749             D3DDECL_END(),
750         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
751         {{
752             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
753             D3DDECL_END(),
754         }, D3DFVF_NORMAL},
755         {{
756             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
757             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
758             D3DDECL_END(),
759         }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
760         {{
761             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
762             D3DDECL_END(),
763         }, D3DFVF_PSIZE},
764         {{
765             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
766             D3DDECL_END(),
767         }, D3DFVF_DIFFUSE},
768         {{
769             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
770             D3DDECL_END(),
771         }, D3DFVF_SPECULAR},
772         /* Make sure textures of different sizes work. */
773         {{
774             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
775             D3DDECL_END(),
776         }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
777         {{
778             {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
779             D3DDECL_END(),
780         }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
781         {{
782             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
783             D3DDECL_END(),
784         }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
785         {{
786             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
787             D3DDECL_END(),
788         }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
789         /* Make sure the TEXCOORD index works correctly - try several textures. */
790         {{
791             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
792             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
793             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
794             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
795             D3DDECL_END(),
796         }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
797                 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
798         /* Now try some combination tests. */
799         {{
800             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
801             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
802             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
803             {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
804             {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
805             {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
806             D3DDECL_END(),
807         }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
808                 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
809         {{
810             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
811             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
812             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
813             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
814             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
815             {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
816             D3DDECL_END(),
817         }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
818                 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
819     };
820     unsigned int i;
821 
822     for (i = 0; i < ARRAY_SIZE(test_data); ++i)
823     {
824         test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
825         test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
826     }
827 
828     /* Usage indices for position and normal are apparently ignored. */
829     {
830         const D3DVERTEXELEMENT9 decl[] =
831         {
832             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
833             D3DDECL_END(),
834         };
835         test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
836     }
837     {
838         const D3DVERTEXELEMENT9 decl[] =
839         {
840             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
841             D3DDECL_END(),
842         };
843         test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
844     }
845     /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
846      * there are no blend matrices. */
847     {
848         const D3DVERTEXELEMENT9 decl[] =
849         {
850             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
851             D3DDECL_END(),
852         };
853         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
854     }
855     {
856         const D3DVERTEXELEMENT9 decl[] =
857         {
858             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
859             D3DDECL_END(),
860         };
861         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
862     }
863     /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
864     {
865         const D3DVERTEXELEMENT9 decl[] =
866         {
867             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
868             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
869             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
870             D3DDECL_END(),
871         };
872         test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
873                 decl, D3D_OK, __LINE__, 0);
874     }
875     /* These are supposed to fail, both ways. */
876     {
877         const D3DVERTEXELEMENT9 decl[] =
878         {
879             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
880             D3DDECL_END(),
881         };
882         test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
883         test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
884     }
885     {
886         const D3DVERTEXELEMENT9 decl[] =
887         {
888             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
889             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
890             D3DDECL_END(),
891         };
892         test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
893         test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
894     }
895     {
896         const D3DVERTEXELEMENT9 decl[] =
897         {
898             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
899             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
900             {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
901             D3DDECL_END(),
902         };
903         test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
904         test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
905     }
906     /* Test a declaration that can't be converted to an FVF. */
907     {
908         const D3DVERTEXELEMENT9 decl[] =
909         {
910             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
911             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
912             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
913             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
914             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
915             /* 8 bytes padding */
916             {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
917             D3DDECL_END(),
918         };
919         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
920     }
921     /* Elements must be ordered by offset. */
922     {
923         const D3DVERTEXELEMENT9 decl[] =
924         {
925             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
926             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
927             D3DDECL_END(),
928         };
929         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
930     }
931     /* Basic tests for element order. */
932     {
933         const D3DVERTEXELEMENT9 decl[] =
934         {
935             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
936             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
937             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
938             D3DDECL_END(),
939         };
940         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
941     }
942     {
943         const D3DVERTEXELEMENT9 decl[] =
944         {
945             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
946             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
947             D3DDECL_END(),
948         };
949         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
950     }
951     {
952         const D3DVERTEXELEMENT9 decl[] =
953         {
954             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
955             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
956             D3DDECL_END(),
957         };
958         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
959     }
960     /* Textures must be ordered by texcoords. */
961     {
962         const D3DVERTEXELEMENT9 decl[] =
963         {
964             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
965             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
966             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
967             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
968             D3DDECL_END(),
969         };
970         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
971     }
972     /* Duplicate elements are not allowed. */
973     {
974         const D3DVERTEXELEMENT9 decl[] =
975         {
976             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
977             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
978             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
979             D3DDECL_END(),
980         };
981         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
982     }
983     /* Invalid FVFs cannot be converted to a declarator. */
984     test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
985 }
986 
987 static void D3DXGetFVFVertexSizeTest(void)
988 {
989     UINT got;
990 
991     compare_vertex_sizes (D3DFVF_XYZ, 12);
992 
993     compare_vertex_sizes (D3DFVF_XYZB3, 24);
994 
995     compare_vertex_sizes (D3DFVF_XYZB5, 32);
996 
997     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
998 
999     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
1000 
1001     compare_vertex_sizes (
1002         D3DFVF_XYZ |
1003         D3DFVF_TEX1 |
1004         D3DFVF_TEXCOORDSIZE1(0), 16);
1005     compare_vertex_sizes (
1006         D3DFVF_XYZ |
1007         D3DFVF_TEX2 |
1008         D3DFVF_TEXCOORDSIZE1(0) |
1009         D3DFVF_TEXCOORDSIZE1(1), 20);
1010 
1011     compare_vertex_sizes (
1012         D3DFVF_XYZ |
1013         D3DFVF_TEX1 |
1014         D3DFVF_TEXCOORDSIZE2(0), 20);
1015 
1016     compare_vertex_sizes (
1017         D3DFVF_XYZ |
1018         D3DFVF_TEX2 |
1019         D3DFVF_TEXCOORDSIZE2(0) |
1020         D3DFVF_TEXCOORDSIZE2(1), 28);
1021 
1022     compare_vertex_sizes (
1023         D3DFVF_XYZ |
1024         D3DFVF_TEX6 |
1025         D3DFVF_TEXCOORDSIZE2(0) |
1026         D3DFVF_TEXCOORDSIZE2(1) |
1027         D3DFVF_TEXCOORDSIZE2(2) |
1028         D3DFVF_TEXCOORDSIZE2(3) |
1029         D3DFVF_TEXCOORDSIZE2(4) |
1030         D3DFVF_TEXCOORDSIZE2(5), 60);
1031 
1032     compare_vertex_sizes (
1033         D3DFVF_XYZ |
1034         D3DFVF_TEX8 |
1035         D3DFVF_TEXCOORDSIZE2(0) |
1036         D3DFVF_TEXCOORDSIZE2(1) |
1037         D3DFVF_TEXCOORDSIZE2(2) |
1038         D3DFVF_TEXCOORDSIZE2(3) |
1039         D3DFVF_TEXCOORDSIZE2(4) |
1040         D3DFVF_TEXCOORDSIZE2(5) |
1041         D3DFVF_TEXCOORDSIZE2(6) |
1042         D3DFVF_TEXCOORDSIZE2(7), 76);
1043 
1044     compare_vertex_sizes (
1045         D3DFVF_XYZ |
1046         D3DFVF_TEX1 |
1047         D3DFVF_TEXCOORDSIZE3(0), 24);
1048 
1049     compare_vertex_sizes (
1050         D3DFVF_XYZ |
1051         D3DFVF_TEX4 |
1052         D3DFVF_TEXCOORDSIZE3(0) |
1053         D3DFVF_TEXCOORDSIZE3(1) |
1054         D3DFVF_TEXCOORDSIZE3(2) |
1055         D3DFVF_TEXCOORDSIZE3(3), 60);
1056 
1057     compare_vertex_sizes (
1058         D3DFVF_XYZ |
1059         D3DFVF_TEX1 |
1060         D3DFVF_TEXCOORDSIZE4(0), 28);
1061 
1062     compare_vertex_sizes (
1063         D3DFVF_XYZ |
1064         D3DFVF_TEX2 |
1065         D3DFVF_TEXCOORDSIZE4(0) |
1066         D3DFVF_TEXCOORDSIZE4(1), 44);
1067 
1068     compare_vertex_sizes (
1069         D3DFVF_XYZ |
1070         D3DFVF_TEX3 |
1071         D3DFVF_TEXCOORDSIZE4(0) |
1072         D3DFVF_TEXCOORDSIZE4(1) |
1073         D3DFVF_TEXCOORDSIZE4(2), 60);
1074 
1075     compare_vertex_sizes (
1076         D3DFVF_XYZB5 |
1077         D3DFVF_NORMAL |
1078         D3DFVF_DIFFUSE |
1079         D3DFVF_SPECULAR |
1080         D3DFVF_TEX8 |
1081         D3DFVF_TEXCOORDSIZE4(0) |
1082         D3DFVF_TEXCOORDSIZE4(1) |
1083         D3DFVF_TEXCOORDSIZE4(2) |
1084         D3DFVF_TEXCOORDSIZE4(3) |
1085         D3DFVF_TEXCOORDSIZE4(4) |
1086         D3DFVF_TEXCOORDSIZE4(5) |
1087         D3DFVF_TEXCOORDSIZE4(6) |
1088         D3DFVF_TEXCOORDSIZE4(7), 180);
1089 }
1090 
1091 static void D3DXIntersectTriTest(void)
1092 {
1093     BOOL exp_res, got_res;
1094     D3DXVECTOR3 position, ray, vertex[3];
1095     FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
1096 
1097     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1098     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1099     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1100 
1101     position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
1102 
1103     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1104 
1105     exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
1106 
1107     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1108     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1109     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1110     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1111     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1112 
1113     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1114     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1115 
1116     vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1117     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1118     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 0.0f;
1119 
1120     got_u = got_v = got_dist = 0.0f;
1121     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1122     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1123     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1124     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1125     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1126 
1127     vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1128     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = -0.5f;
1129     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = -1.0f;
1130     exp_u = 0.375f;
1131     exp_v = 0.5625f;
1132     exp_dist = 7.9375f;
1133     got_u = got_v = got_dist = 0.0f;
1134     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1135     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1136     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1137     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1138     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1139 
1140 
1141 /*Only positive ray is taken in account*/
1142 
1143     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1144     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1145     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1146 
1147     position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
1148 
1149     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1150 
1151     exp_res = FALSE;
1152 
1153     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1154     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1155 
1156     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1157     ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1158 
1159 /*Intersection between ray and triangle in a same plane is considered as empty*/
1160 
1161     vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1162     vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1163     vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
1164 
1165     position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
1166 
1167     ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
1168 
1169     exp_res = FALSE;
1170 
1171     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1172     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1173 
1174     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1175     ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1176 }
1177 
1178 static void D3DXCreateMeshTest(void)
1179 {
1180     HRESULT hr;
1181     IDirect3DDevice9 *device, *test_device;
1182     ID3DXMesh *d3dxmesh;
1183     int i, size;
1184     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1185     DWORD options;
1186     struct mesh mesh;
1187     struct test_context *test_context;
1188 
1189     static const D3DVERTEXELEMENT9 decl1[] =
1190     {
1191         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1192         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1193         D3DDECL_END(),
1194     };
1195 
1196     static const D3DVERTEXELEMENT9 decl2[] =
1197     {
1198         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1199         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1200         {0, 24, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
1201         {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
1202         {0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
1203         /* 8 bytes padding */
1204         {0, 44, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
1205         D3DDECL_END(),
1206     };
1207 
1208     static const D3DVERTEXELEMENT9 decl3[] =
1209     {
1210         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1211         {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1212         D3DDECL_END(),
1213     };
1214 
1215     hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1216     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1217 
1218     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1219     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1220 
1221     test_context = new_test_context();
1222     if (!test_context)
1223     {
1224         skip("Couldn't create test context\n");
1225         return;
1226     }
1227     device = test_context->device;
1228 
1229     hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1230     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1231 
1232     hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1233     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1234 
1235     hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
1236     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1237 
1238     if (hr == D3D_OK)
1239     {
1240         d3dxmesh->lpVtbl->Release(d3dxmesh);
1241     }
1242 
1243     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1244     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1245 
1246     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
1247     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1248 
1249     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1250     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1251 
1252     if (hr == D3D_OK)
1253     {
1254         /* device */
1255         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1256         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1257 
1258         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1259         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1260         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1261 
1262         if (hr == D3D_OK)
1263         {
1264             IDirect3DDevice9_Release(device);
1265         }
1266 
1267         /* declaration */
1268         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1269         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1270 
1271         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1272         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1273 
1274         if (hr == D3D_OK)
1275         {
1276             size = ARRAY_SIZE(decl1);
1277             for (i = 0; i < size - 1; i++)
1278             {
1279                 ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1280                 ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1281                 ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1282                 ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1283                 ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1284                 ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1285             }
1286             ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1287         }
1288 
1289         /* options */
1290         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1291         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1292 
1293         /* rest */
1294         if (!new_mesh(&mesh, 3, 1))
1295         {
1296             skip("Couldn't create mesh\n");
1297         }
1298         else
1299         {
1300             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1301             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1302             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1303 
1304             compare_mesh("createmesh1", d3dxmesh, &mesh);
1305 
1306             free_mesh(&mesh);
1307         }
1308 
1309         d3dxmesh->lpVtbl->Release(d3dxmesh);
1310     }
1311 
1312     /* Test a declaration that can't be converted to an FVF. */
1313     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1314     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1315 
1316     if (hr == D3D_OK)
1317     {
1318         /* device */
1319         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1320         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1321 
1322         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1323         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1324         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1325 
1326         if (hr == D3D_OK)
1327         {
1328             IDirect3DDevice9_Release(device);
1329         }
1330 
1331         /* declaration */
1332         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1333         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1334 
1335         if (hr == D3D_OK)
1336         {
1337             size = ARRAY_SIZE(decl2);
1338             for (i = 0; i < size - 1; i++)
1339             {
1340                 ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1341                 ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1342                 ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1343                 ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1344                 ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1345                 ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1346             }
1347             ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1348         }
1349 
1350         /* options */
1351         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1352         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1353 
1354         /* rest */
1355         if (!new_mesh(&mesh, 3, 1))
1356         {
1357             skip("Couldn't create mesh\n");
1358         }
1359         else
1360         {
1361             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1362             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1363             mesh.fvf = 0;
1364             mesh.vertex_size = 60;
1365 
1366             compare_mesh("createmesh2", d3dxmesh, &mesh);
1367 
1368             free_mesh(&mesh);
1369         }
1370 
1371         mesh.vertex_size = d3dxmesh->lpVtbl->GetNumBytesPerVertex(d3dxmesh);
1372         ok(mesh.vertex_size == 60, "Got vertex size %u, expected %u\n", mesh.vertex_size, 60);
1373 
1374         d3dxmesh->lpVtbl->Release(d3dxmesh);
1375     }
1376 
1377     /* Test a declaration with multiple streams. */
1378     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
1379     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1380 
1381     free_test_context(test_context);
1382 }
1383 
1384 static void D3DXCreateMeshFVFTest(void)
1385 {
1386     HRESULT hr;
1387     IDirect3DDevice9 *device, *test_device;
1388     ID3DXMesh *d3dxmesh;
1389     int i, size;
1390     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1391     DWORD options;
1392     struct mesh mesh;
1393     struct test_context *test_context;
1394 
1395     static const D3DVERTEXELEMENT9 decl[] =
1396     {
1397         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1398         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1399         D3DDECL_END(),
1400     };
1401 
1402     hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1403     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1404 
1405     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, NULL, &d3dxmesh);
1406     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1407 
1408     test_context = new_test_context();
1409     if (!test_context)
1410     {
1411         skip("Couldn't create test context\n");
1412         return;
1413     }
1414     device = test_context->device;
1415 
1416     hr = D3DXCreateMeshFVF(0, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1417     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1418 
1419     hr = D3DXCreateMeshFVF(1, 0, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1420     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1421 
1422     hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1423     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1424 
1425     if (hr == D3D_OK)
1426     {
1427         d3dxmesh->lpVtbl->Release(d3dxmesh);
1428     }
1429 
1430     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1431     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1432 
1433     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, NULL);
1434     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1435 
1436     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1437     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1438 
1439     if (hr == D3D_OK)
1440     {
1441         /* device */
1442         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1443         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1444 
1445         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1446         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1447         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1448 
1449         if (hr == D3D_OK)
1450         {
1451             IDirect3DDevice9_Release(device);
1452         }
1453 
1454         /* declaration */
1455         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1456         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1457 
1458         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1459         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1460 
1461         if (hr == D3D_OK)
1462         {
1463             size = ARRAY_SIZE(decl);
1464             for (i = 0; i < size - 1; i++)
1465             {
1466                 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1467                 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1468                 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1469                 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1470                 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1471                    test_decl[i].UsageIndex, decl[i].UsageIndex);
1472                 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1473             }
1474             ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1475         }
1476 
1477         /* options */
1478         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1479         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1480 
1481         /* rest */
1482         if (!new_mesh(&mesh, 3, 1))
1483         {
1484             skip("Couldn't create mesh\n");
1485         }
1486         else
1487         {
1488             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1489             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1490             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1491 
1492             compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1493 
1494             free_mesh(&mesh);
1495         }
1496 
1497         d3dxmesh->lpVtbl->Release(d3dxmesh);
1498     }
1499 
1500     free_test_context(test_context);
1501 }
1502 
1503 #define check_vertex_buffer(mesh, vertices, num_vertices, fvf) \
1504     check_vertex_buffer_(__LINE__, mesh, vertices, num_vertices, fvf)
1505 static void check_vertex_buffer_(int line, ID3DXMesh *mesh, const void *vertices, DWORD num_vertices, DWORD fvf)
1506 {
1507     DWORD mesh_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
1508     DWORD mesh_fvf = mesh->lpVtbl->GetFVF(mesh);
1509     const void *mesh_vertices;
1510     HRESULT hr;
1511 
1512     ok_(__FILE__,line)(fvf == mesh_fvf, "expected FVF %x, got %x\n", fvf, mesh_fvf);
1513     ok_(__FILE__,line)(num_vertices == mesh_num_vertices,
1514        "Expected %u vertices, got %u\n", num_vertices, mesh_num_vertices);
1515 
1516     hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
1517     ok_(__FILE__,line)(hr == D3D_OK, "LockVertexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1518     if (FAILED(hr))
1519         return;
1520 
1521     if (mesh_fvf == fvf) {
1522         DWORD vertex_size = D3DXGetFVFVertexSize(fvf), i;
1523 
1524         for (i = 0; i < min(num_vertices, mesh_num_vertices); i++)
1525         {
1526             const FLOAT *exp_float = vertices;
1527             const FLOAT *got_float = mesh_vertices;
1528             DWORD texcount;
1529             DWORD pos_dim = 0;
1530             int j;
1531             BOOL last_beta_dword = FALSE;
1532             char prefix[128];
1533 
1534             switch (fvf & D3DFVF_POSITION_MASK) {
1535                 case D3DFVF_XYZ: pos_dim = 3; break;
1536                 case D3DFVF_XYZRHW: pos_dim = 4; break;
1537                 case D3DFVF_XYZB1:
1538                 case D3DFVF_XYZB2:
1539                 case D3DFVF_XYZB3:
1540                 case D3DFVF_XYZB4:
1541                 case D3DFVF_XYZB5:
1542                     pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
1543                     if (fvf & (D3DFVF_LASTBETA_UBYTE4 | D3DFVF_LASTBETA_D3DCOLOR))
1544                     {
1545                         pos_dim--;
1546                         last_beta_dword = TRUE;
1547                     }
1548                     break;
1549                 case D3DFVF_XYZW: pos_dim = 4; break;
1550             }
1551             sprintf(prefix, "vertex[%u] position, ", i);
1552             check_floats_(line, prefix, got_float, exp_float, pos_dim);
1553             exp_float += pos_dim;
1554             got_float += pos_dim;
1555 
1556             if (last_beta_dword) {
1557                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1558                     "Vertex[%u]: Expected last beta %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1559                 exp_float++;
1560                 got_float++;
1561             }
1562 
1563             if (fvf & D3DFVF_NORMAL) {
1564                 sprintf(prefix, "vertex[%u] normal, ", i);
1565                 check_floats_(line, prefix, got_float, exp_float, 3);
1566                 exp_float += 3;
1567                 got_float += 3;
1568             }
1569             if (fvf & D3DFVF_PSIZE) {
1570                 ok_(__FILE__,line)(compare(*exp_float, *got_float),
1571                         "Vertex[%u]: Expected psize %g, got %g\n", i, *exp_float, *got_float);
1572                 exp_float++;
1573                 got_float++;
1574             }
1575             if (fvf & D3DFVF_DIFFUSE) {
1576                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1577                     "Vertex[%u]: Expected diffuse %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1578                 exp_float++;
1579                 got_float++;
1580             }
1581             if (fvf & D3DFVF_SPECULAR) {
1582                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1583                     "Vertex[%u]: Expected specular %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1584                 exp_float++;
1585                 got_float++;
1586             }
1587 
1588             texcount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
1589             for (j = 0; j < texcount; j++) {
1590                 DWORD dim = (((fvf >> (16 + 2 * j)) + 1) & 0x03) + 1;
1591                 sprintf(prefix, "vertex[%u] texture, ", i);
1592                 check_floats_(line, prefix, got_float, exp_float, dim);
1593                 exp_float += dim;
1594                 got_float += dim;
1595             }
1596 
1597             vertices = (BYTE*)vertices + vertex_size;
1598             mesh_vertices = (BYTE*)mesh_vertices + vertex_size;
1599         }
1600     }
1601 
1602     mesh->lpVtbl->UnlockVertexBuffer(mesh);
1603 }
1604 
1605 #define check_index_buffer(mesh, indices, num_indices, index_size) \
1606     check_index_buffer_(__LINE__, mesh, indices, num_indices, index_size)
1607 static void check_index_buffer_(int line, ID3DXMesh *mesh, const void *indices, DWORD num_indices, DWORD index_size)
1608 {
1609     DWORD mesh_index_size = (mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT) ? 4 : 2;
1610     DWORD mesh_num_indices = mesh->lpVtbl->GetNumFaces(mesh) * 3;
1611     const void *mesh_indices;
1612     HRESULT hr;
1613     DWORD i;
1614 
1615     ok_(__FILE__,line)(index_size == mesh_index_size,
1616         "Expected index size %u, got %u\n", index_size, mesh_index_size);
1617     ok_(__FILE__,line)(num_indices == mesh_num_indices,
1618         "Expected %u indices, got %u\n", num_indices, mesh_num_indices);
1619 
1620     hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
1621     ok_(__FILE__,line)(hr == D3D_OK, "LockIndexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1622     if (FAILED(hr))
1623         return;
1624 
1625     if (mesh_index_size == index_size) {
1626         for (i = 0; i < min(num_indices, mesh_num_indices); i++)
1627         {
1628             if (index_size == 4)
1629                 ok_(__FILE__,line)(*(DWORD*)indices == *(DWORD*)mesh_indices,
1630                     "Index[%u]: expected %u, got %u\n", i, *(DWORD*)indices, *(DWORD*)mesh_indices);
1631             else
1632                 ok_(__FILE__,line)(*(WORD*)indices == *(WORD*)mesh_indices,
1633                     "Index[%u]: expected %u, got %u\n", i, *(WORD*)indices, *(WORD*)mesh_indices);
1634             indices = (BYTE*)indices + index_size;
1635             mesh_indices = (BYTE*)mesh_indices + index_size;
1636         }
1637     }
1638     mesh->lpVtbl->UnlockIndexBuffer(mesh);
1639 }
1640 
1641 #define check_matrix(got, expected) check_matrix_(__LINE__, got, expected)
1642 static void check_matrix_(int line, const D3DXMATRIX *got, const D3DXMATRIX *expected)
1643 {
1644     int i, j;
1645     for (i = 0; i < 4; i++) {
1646         for (j = 0; j < 4; j++) {
1647             ok_(__FILE__,line)(compare(U(*expected).m[i][j], U(*got).m[i][j]),
1648                     "matrix[%u][%u]: expected %g, got %g\n",
1649                     i, j, U(*expected).m[i][j], U(*got).m[i][j]);
1650         }
1651     }
1652 }
1653 
1654 static void check_colorvalue_(int line, const char *prefix, const D3DCOLORVALUE got, const D3DCOLORVALUE expected)
1655 {
1656     ok_(__FILE__,line)(expected.r == got.r && expected.g == got.g && expected.b == got.b && expected.a == got.a,
1657             "%sExpected (%g, %g, %g, %g), got (%g, %g, %g, %g)\n", prefix,
1658             expected.r, expected.g, expected.b, expected.a, got.r, got.g, got.b, got.a);
1659 }
1660 
1661 #define check_materials(got, got_count, expected, expected_count) \
1662     check_materials_(__LINE__, got, got_count, expected, expected_count)
1663 static void check_materials_(int line, const D3DXMATERIAL *got, DWORD got_count, const D3DXMATERIAL *expected, DWORD expected_count)
1664 {
1665     int i;
1666     ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
1667     if (!expected) {
1668         ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
1669         return;
1670     }
1671     for (i = 0; i < min(expected_count, got_count); i++)
1672     {
1673         if (!expected[i].pTextureFilename)
1674             ok_(__FILE__,line)(got[i].pTextureFilename == NULL,
1675                     "Expected NULL pTextureFilename, got %p\n", got[i].pTextureFilename);
1676         else
1677             ok_(__FILE__,line)(!strcmp(expected[i].pTextureFilename, got[i].pTextureFilename),
1678                     "Expected '%s' for pTextureFilename, got '%s'\n", expected[i].pTextureFilename, got[i].pTextureFilename);
1679         check_colorvalue_(line, "Diffuse: ", got[i].MatD3D.Diffuse, expected[i].MatD3D.Diffuse);
1680         check_colorvalue_(line, "Ambient: ", got[i].MatD3D.Ambient, expected[i].MatD3D.Ambient);
1681         check_colorvalue_(line, "Specular: ", got[i].MatD3D.Specular, expected[i].MatD3D.Specular);
1682         check_colorvalue_(line, "Emissive: ", got[i].MatD3D.Emissive, expected[i].MatD3D.Emissive);
1683         ok_(__FILE__,line)(expected[i].MatD3D.Power == got[i].MatD3D.Power,
1684                 "Power: Expected %g, got %g\n", expected[i].MatD3D.Power, got[i].MatD3D.Power);
1685     }
1686 }
1687 
1688 #define check_generated_adjacency(mesh, got, epsilon) check_generated_adjacency_(__LINE__, mesh, got, epsilon)
1689 static void check_generated_adjacency_(int line, ID3DXMesh *mesh, const DWORD *got, FLOAT epsilon)
1690 {
1691     DWORD *expected;
1692     DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
1693     HRESULT hr;
1694 
1695     expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
1696     if (!expected) {
1697         skip_(__FILE__, line)("Out of memory\n");
1698         return;
1699     }
1700     hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
1701     ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1702     if (SUCCEEDED(hr))
1703     {
1704         int i;
1705         for (i = 0; i < num_faces; i++)
1706         {
1707             ok_(__FILE__, line)(expected[i * 3] == got[i * 3] &&
1708                     expected[i * 3 + 1] == got[i * 3 + 1] &&
1709                     expected[i * 3 + 2] == got[i * 3 + 2],
1710                     "Face %u adjacencies: Expected (%u, %u, %u), got (%u, %u, %u)\n", i,
1711                     expected[i * 3], expected[i * 3 + 1], expected[i * 3 + 2],
1712                     got[i * 3], got[i * 3 + 1], got[i * 3 + 2]);
1713         }
1714     }
1715     HeapFree(GetProcessHeap(), 0, expected);
1716 }
1717 
1718 #define check_generated_effects(materials, num_materials, effects) \
1719     check_generated_effects_(__LINE__, materials, num_materials, effects)
1720 static void check_generated_effects_(int line, const D3DXMATERIAL *materials, DWORD num_materials, const D3DXEFFECTINSTANCE *effects)
1721 {
1722     int i;
1723     static const struct {
1724         const char *name;
1725         DWORD name_size;
1726         DWORD num_bytes;
1727         DWORD value_offset;
1728     } params[] = {
1729 #define EFFECT_TABLE_ENTRY(str, field) \
1730     {str, sizeof(str), sizeof(materials->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
1731         EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
1732         EFFECT_TABLE_ENTRY("Power", Power),
1733         EFFECT_TABLE_ENTRY("Specular", Specular),
1734         EFFECT_TABLE_ENTRY("Emissive", Emissive),
1735         EFFECT_TABLE_ENTRY("Ambient", Ambient),
1736 #undef EFFECT_TABLE_ENTRY
1737     };
1738 
1739     if (!num_materials) {
1740         ok_(__FILE__, line)(effects == NULL, "Expected NULL effects, got %p\n", effects);
1741         return;
1742     }
1743     for (i = 0; i < num_materials; i++)
1744     {
1745         int j;
1746         DWORD expected_num_defaults = ARRAY_SIZE(params) + (materials[i].pTextureFilename ? 1 : 0);
1747 
1748         ok_(__FILE__,line)(expected_num_defaults == effects[i].NumDefaults,
1749                 "effect[%u] NumDefaults: Expected %u, got %u\n", i,
1750                 expected_num_defaults, effects[i].NumDefaults);
1751         for (j = 0; j < min(ARRAY_SIZE(params), effects[i].NumDefaults); j++)
1752         {
1753             int k;
1754             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1755             ok_(__FILE__,line)(!strcmp(params[j].name, got_param->pParamName),
1756                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1757                params[j].name, got_param->pParamName);
1758             ok_(__FILE__,line)(D3DXEDT_FLOATS == got_param->Type,
1759                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1760                D3DXEDT_FLOATS, got_param->Type);
1761             ok_(__FILE__,line)(params[j].num_bytes == got_param->NumBytes,
1762                "effect[%u].pDefaults[%u].NumBytes: Expected %u, got %u\n", i, j,
1763                params[j].num_bytes, got_param->NumBytes);
1764             for (k = 0; k < min(params[j].num_bytes, got_param->NumBytes) / 4; k++)
1765             {
1766                 FLOAT expected = ((FLOAT*)((BYTE*)&materials[i] + params[j].value_offset))[k];
1767                 FLOAT got = ((FLOAT*)got_param->pValue)[k];
1768                 ok_(__FILE__,line)(compare(expected, got),
1769                    "effect[%u].pDefaults[%u] float value %u: Expected %g, got %g\n", i, j, k, expected, got);
1770             }
1771         }
1772         if (effects[i].NumDefaults > ARRAY_SIZE(params)) {
1773             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1774             static const char *expected_name = "Texture0@Name";
1775 
1776             ok_(__FILE__,line)(!strcmp(expected_name, got_param->pParamName),
1777                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1778                expected_name, got_param->pParamName);
1779             ok_(__FILE__,line)(D3DXEDT_STRING == got_param->Type,
1780                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1781                D3DXEDT_STRING, got_param->Type);
1782             if (materials[i].pTextureFilename) {
1783                 ok_(__FILE__,line)(strlen(materials[i].pTextureFilename) + 1 == got_param->NumBytes,
1784                    "effect[%u] texture filename length: Expected %u, got %u\n", i,
1785                    (DWORD)strlen(materials[i].pTextureFilename) + 1, got_param->NumBytes);
1786                 ok_(__FILE__,line)(!strcmp(materials[i].pTextureFilename, got_param->pValue),
1787                    "effect[%u] texture filename: Expected '%s', got '%s'\n", i,
1788                    materials[i].pTextureFilename, (char*)got_param->pValue);
1789             }
1790         }
1791     }
1792 }
1793 
1794 static char *strdupA(const char *p)
1795 {
1796     char *ret;
1797     if (!p) return NULL;
1798     ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
1799     if (ret) strcpy(ret, p);
1800     return ret;
1801 }
1802 
1803 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
1804 {
1805     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
1806     if (frame) {
1807         HeapFree(GetProcessHeap(), 0, frame->Name);
1808         HeapFree(GetProcessHeap(), 0, frame);
1809     }
1810     return D3D_OK;
1811 }
1812 
1813 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface,
1814         const char *name, D3DXFRAME **new_frame)
1815 {
1816     D3DXFRAME *frame;
1817 
1818     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
1819     frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
1820     if (!frame)
1821         return E_OUTOFMEMORY;
1822     if (name) {
1823         frame->Name = strdupA(name);
1824         if (!frame->Name) {
1825             HeapFree(GetProcessHeap(), 0, frame);
1826             return E_OUTOFMEMORY;
1827         }
1828     }
1829     *new_frame = frame;
1830     return D3D_OK;
1831 }
1832 
1833 static HRESULT destroy_mesh_container(LPD3DXMESHCONTAINER mesh_container)
1834 {
1835     int i;
1836 
1837     if (!mesh_container)
1838         return D3D_OK;
1839     HeapFree(GetProcessHeap(), 0, mesh_container->Name);
1840     if (U(mesh_container->MeshData).pMesh)
1841         IUnknown_Release(U(mesh_container->MeshData).pMesh);
1842     if (mesh_container->pMaterials) {
1843         for (i = 0; i < mesh_container->NumMaterials; i++)
1844             HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials[i].pTextureFilename);
1845         HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials);
1846     }
1847     if (mesh_container->pEffects) {
1848         for (i = 0; i < mesh_container->NumMaterials; i++) {
1849             HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pEffectFilename);
1850             if (mesh_container->pEffects[i].pDefaults) {
1851                 int j;
1852                 for (j = 0; j < mesh_container->pEffects[i].NumDefaults; j++) {
1853                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pParamName);
1854                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pValue);
1855                 }
1856                 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults);
1857             }
1858         }
1859         HeapFree(GetProcessHeap(), 0, mesh_container->pEffects);
1860     }
1861     HeapFree(GetProcessHeap(), 0, mesh_container->pAdjacency);
1862     if (mesh_container->pSkinInfo)
1863         IUnknown_Release(mesh_container->pSkinInfo);
1864     HeapFree(GetProcessHeap(), 0, mesh_container);
1865     return D3D_OK;
1866 }
1867 
1868 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyMeshContainer(ID3DXAllocateHierarchy *iface, LPD3DXMESHCONTAINER mesh_container)
1869 {
1870     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyMeshContainer(%p, %p)\n", iface, mesh_container);
1871     return destroy_mesh_container(mesh_container);
1872 }
1873 
1874 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateMeshContainer(ID3DXAllocateHierarchy *iface,
1875         const char *name, const D3DXMESHDATA *mesh_data, const D3DXMATERIAL *materials,
1876         const D3DXEFFECTINSTANCE *effects, DWORD num_materials, const DWORD *adjacency,
1877         ID3DXSkinInfo *skin_info, D3DXMESHCONTAINER **new_mesh_container)
1878 {
1879     LPD3DXMESHCONTAINER mesh_container = NULL;
1880     int i;
1881 
1882     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateMeshContainer(%p, '%s', %u, %p, %p, %p, %d, %p, %p, %p)\n",
1883             iface, name, mesh_data->Type, U(*mesh_data).pMesh, materials, effects,
1884             num_materials, adjacency, skin_info, *new_mesh_container);
1885 
1886     mesh_container = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mesh_container));
1887     if (!mesh_container)
1888         return E_OUTOFMEMORY;
1889 
1890     if (name) {
1891         mesh_container->Name = strdupA(name);
1892         if (!mesh_container->Name)
1893             goto error;
1894     }
1895 
1896     mesh_container->NumMaterials = num_materials;
1897     if (num_materials) {
1898         mesh_container->pMaterials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*materials));
1899         if (!mesh_container->pMaterials)
1900             goto error;
1901 
1902         memcpy(mesh_container->pMaterials, materials, num_materials * sizeof(*materials));
1903         for (i = 0; i < num_materials; i++)
1904             mesh_container->pMaterials[i].pTextureFilename = NULL;
1905         for (i = 0; i < num_materials; i++) {
1906             if (materials[i].pTextureFilename) {
1907                 mesh_container->pMaterials[i].pTextureFilename = strdupA(materials[i].pTextureFilename);
1908                 if (!mesh_container->pMaterials[i].pTextureFilename)
1909                     goto error;
1910             }
1911         }
1912 
1913         mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
1914         if (!mesh_container->pEffects)
1915             goto error;
1916         for (i = 0; i < num_materials; i++) {
1917             int j;
1918             const D3DXEFFECTINSTANCE *effect_src = &effects[i];
1919             D3DXEFFECTINSTANCE *effect_dest = &mesh_container->pEffects[i];
1920 
1921             if (effect_src->pEffectFilename) {
1922                 effect_dest->pEffectFilename = strdupA(effect_src->pEffectFilename);
1923                 if (!effect_dest->pEffectFilename)
1924                     goto error;
1925             }
1926             effect_dest->pDefaults = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1927                     effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
1928             if (!effect_dest->pDefaults)
1929                 goto error;
1930             effect_dest->NumDefaults = effect_src->NumDefaults;
1931             for (j = 0; j < effect_src->NumDefaults; j++) {
1932                 const D3DXEFFECTDEFAULT *default_src = &effect_src->pDefaults[j];
1933                 D3DXEFFECTDEFAULT *default_dest = &effect_dest->pDefaults[j];
1934 
1935                 if (default_src->pParamName) {
1936                     default_dest->pParamName = strdupA(default_src->pParamName);
1937                     if (!default_dest->pParamName)
1938                         goto error;
1939                 }
1940                 default_dest->NumBytes = default_src->NumBytes;
1941                 default_dest->Type = default_src->Type;
1942                 default_dest->pValue = HeapAlloc(GetProcessHeap(), 0, default_src->NumBytes);
1943                 memcpy(default_dest->pValue, default_src->pValue, default_src->NumBytes);
1944             }
1945         }
1946     }
1947 
1948     ok(adjacency != NULL, "Expected non-NULL adjacency, got NULL\n");
1949     if (adjacency) {
1950         if (mesh_data->Type == D3DXMESHTYPE_MESH || mesh_data->Type == D3DXMESHTYPE_PMESH) {
1951             ID3DXBaseMesh *basemesh = (ID3DXBaseMesh*)U(*mesh_data).pMesh;
1952             DWORD num_faces = basemesh->lpVtbl->GetNumFaces(basemesh);
1953             size_t size = num_faces * sizeof(DWORD) * 3;
1954             mesh_container->pAdjacency = HeapAlloc(GetProcessHeap(), 0, size);
1955             if (!mesh_container->pAdjacency)
1956                 goto error;
1957             memcpy(mesh_container->pAdjacency, adjacency, size);
1958         } else {
1959             ok(mesh_data->Type == D3DXMESHTYPE_PATCHMESH, "Unknown mesh type %u\n", mesh_data->Type);
1960             if (mesh_data->Type == D3DXMESHTYPE_PATCHMESH)
1961                 trace("FIXME: copying adjacency data for patch mesh not implemented\n");
1962         }
1963     }
1964 
1965     memcpy(&mesh_container->MeshData, mesh_data, sizeof(*mesh_data));
1966     if (U(*mesh_data).pMesh)
1967         IUnknown_AddRef(U(*mesh_data).pMesh);
1968     if (skin_info) {
1969         mesh_container->pSkinInfo = skin_info;
1970         skin_info->lpVtbl->AddRef(skin_info);
1971     }
1972     *new_mesh_container = mesh_container;
1973 
1974     return S_OK;
1975 error:
1976     destroy_mesh_container(mesh_container);
1977     return E_OUTOFMEMORY;
1978 }
1979 
1980 static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
1981     ID3DXAllocateHierarchyImpl_CreateFrame,
1982     ID3DXAllocateHierarchyImpl_CreateMeshContainer,
1983     ID3DXAllocateHierarchyImpl_DestroyFrame,
1984     ID3DXAllocateHierarchyImpl_DestroyMeshContainer,
1985 };
1986 static ID3DXAllocateHierarchy alloc_hier = { &ID3DXAllocateHierarchyImpl_Vtbl };
1987 
1988 #define test_LoadMeshFromX(device, xfile_str, vertex_array, fvf, index_array, materials_array, check_adjacency) \
1989     test_LoadMeshFromX_(__LINE__, device, xfile_str, sizeof(xfile_str) - 1, vertex_array, ARRAY_SIZE(vertex_array), fvf, \
1990             index_array, ARRAY_SIZE(index_array), sizeof(*index_array), materials_array, ARRAY_SIZE(materials_array), \
1991             check_adjacency);
1992 static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char *xfile_str, size_t xfile_strlen,
1993         const void *vertices, DWORD num_vertices, DWORD fvf, const void *indices, DWORD num_indices, size_t index_size,
1994         const D3DXMATERIAL *expected_materials, DWORD expected_num_materials, BOOL check_adjacency)
1995 {
1996     HRESULT hr;
1997     ID3DXBuffer *materials = NULL;
1998     ID3DXBuffer *effects = NULL;
1999     ID3DXBuffer *adjacency = NULL;
2000     ID3DXMesh *mesh = NULL;
2001     DWORD num_materials = 0;
2002 
2003     /* Adjacency is not checked when the X file contains multiple meshes,
2004      * since calling GenerateAdjacency on the merged mesh is not equivalent
2005      * to calling GenerateAdjacency on the individual meshes and then merging
2006      * the adjacency data. */
2007     hr = D3DXLoadMeshFromXInMemory(xfile_str, xfile_strlen, D3DXMESH_MANAGED, device,
2008             check_adjacency ? &adjacency : NULL, &materials, &effects, &num_materials, &mesh);
2009     ok_(__FILE__,line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2010     if (SUCCEEDED(hr)) {
2011         D3DXMATERIAL *materials_ptr = materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL;
2012         D3DXEFFECTINSTANCE *effects_ptr = effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL;
2013         DWORD *adjacency_ptr = check_adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL;
2014 
2015         check_vertex_buffer_(line, mesh, vertices, num_vertices, fvf);
2016         check_index_buffer_(line, mesh, indices, num_indices, index_size);
2017         check_materials_(line, materials_ptr, num_materials, expected_materials, expected_num_materials);
2018         check_generated_effects_(line, materials_ptr, num_materials, effects_ptr);
2019         if (check_adjacency)
2020             check_generated_adjacency_(line, mesh, adjacency_ptr, 0.0f);
2021 
2022         if (materials) ID3DXBuffer_Release(materials);
2023         if (effects) ID3DXBuffer_Release(effects);
2024         if (adjacency) ID3DXBuffer_Release(adjacency);
2025         IUnknown_Release(mesh);
2026     }
2027 }
2028 
2029 static void D3DXLoadMeshTest(void)
2030 {
2031     static const char empty_xfile[] = "xof 0303txt 0032";
2032     /*________________________*/
2033     static const char simple_xfile[] =
2034         "xof 0303txt 0032"
2035         "Mesh {"
2036             "3;"
2037             "0.0; 0.0; 0.0;,"
2038             "0.0; 1.0; 0.0;,"
2039             "1.0; 1.0; 0.0;;"
2040             "1;"
2041             "3; 0, 1, 2;;"
2042         "}";
2043     static const WORD simple_index_buffer[] = {0, 1, 2};
2044     static const D3DXVECTOR3 simple_vertex_buffer[] = {
2045         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}
2046     };
2047     const DWORD simple_fvf = D3DFVF_XYZ;
2048     static const char framed_xfile[] =
2049         "xof 0303txt 0032"
2050         "Frame {"
2051             "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 1.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2052             "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */
2053               "1.0, 0.0, 0.0, 0.0,"
2054               "0.0, 1.0, 0.0, 0.0,"
2055               "0.0, 0.0, 1.0, 0.0,"
2056               "0.0, 0.0, 2.0, 1.0;;"
2057             "}"
2058             "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 2.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2059             "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */
2060               "1.0, 0.0, 0.0, 0.0,"
2061               "0.0, 1.0, 0.0, 0.0,"
2062               "0.0, 0.0, 1.0, 0.0,"
2063               "0.0, 0.0, 3.0, 1.0;;"
2064             "}"
2065             "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 3.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2066         "}";
2067     static const WORD framed_index_buffer[] = { 0, 1, 2 };
2068     static const D3DXVECTOR3 framed_vertex_buffers[3][3] = {
2069         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}},
2070         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}},
2071         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {3.0, 1.0, 0.0}},
2072     };
2073     static const WORD merged_index_buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
2074     /* frame transforms accumulates for D3DXLoadMeshFromX */
2075     static const D3DXVECTOR3 merged_vertex_buffer[] = {
2076         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0},
2077         {0.0, 0.0, 2.0}, {0.0, 1.0, 2.0}, {2.0, 1.0, 2.0},
2078         {0.0, 0.0, 5.0}, {0.0, 1.0, 5.0}, {3.0, 1.0, 5.0},
2079     };
2080     const DWORD framed_fvf = D3DFVF_XYZ;
2081     /*________________________*/
2082     static const char box_xfile[] =
2083         "xof 0303txt 0032"
2084         "Mesh {"
2085             "8;" /* DWORD nVertices; */
2086             /* array Vector vertices[nVertices]; */
2087             "0.0; 0.0; 0.0;,"
2088             "0.0; 0.0; 1.0;,"
2089             "0.0; 1.0; 0.0;,"
2090             "0.0; 1.0; 1.0;,"
2091             "1.0; 0.0; 0.0;,"
2092             "1.0; 0.0; 1.0;,"
2093             "1.0; 1.0; 0.0;,"
2094             "1.0; 1.0; 1.0;;"
2095             "6;" /* DWORD nFaces; */
2096             /* array MeshFace faces[nFaces]; */
2097             "4; 0, 1, 3, 2;," /* (left side) */
2098             "4; 2, 3, 7, 6;," /* (top side) */
2099             "4; 6, 7, 5, 4;," /* (right side) */
2100             "4; 1, 0, 4, 5;," /* (bottom side) */
2101             "4; 1, 5, 7, 3;," /* (back side) */
2102             "4; 0, 2, 6, 4;;" /* (front side) */
2103             "MeshNormals {"
2104               "6;" /* DWORD nNormals; */
2105               /* array Vector normals[nNormals]; */
2106               "-1.0; 0.0; 0.0;,"
2107               "0.0; 1.0; 0.0;,"
2108               "1.0; 0.0; 0.0;,"
2109               "0.0; -1.0; 0.0;,"
2110               "0.0; 0.0; 1.0;,"
2111               "0.0; 0.0; -1.0;;"
2112               "6;" /* DWORD nFaceNormals; */
2113               /* array MeshFace faceNormals[nFaceNormals]; */
2114               "4; 0, 0, 0, 0;,"
2115               "4; 1, 1, 1, 1;,"
2116               "4; 2, 2, 2, 2;,"
2117               "4; 3, 3, 3, 3;,"
2118               "4; 4, 4, 4, 4;,"
2119               "4; 5, 5, 5, 5;;"
2120             "}"
2121             "MeshMaterialList materials {"
2122               "2;" /* DWORD nMaterials; */
2123               "6;" /* DWORD nFaceIndexes; */
2124               /* array DWORD faceIndexes[nFaceIndexes]; */
2125               "0, 0, 0, 1, 1, 1;;"
2126               "Material {"
2127                 /* ColorRGBA faceColor; */
2128                 "0.0; 0.0; 1.0; 1.0;;"
2129                 /* FLOAT power; */
2130                 "0.5;"
2131                 /* ColorRGB specularColor; */
2132                 "1.0; 1.0; 1.0;;"
2133                 /* ColorRGB emissiveColor; */
2134                 "0.0; 0.0; 0.0;;"
2135               "}"
2136               "Material {"
2137                 /* ColorRGBA faceColor; */
2138                 "1.0; 1.0; 1.0; 1.0;;"
2139                 /* FLOAT power; */
2140                 "1.0;"
2141                 /* ColorRGB specularColor; */
2142                 "1.0; 1.0; 1.0;;"
2143                 /* ColorRGB emissiveColor; */
2144                 "0.0; 0.0; 0.0;;"
2145                 "TextureFilename { \"texture.jpg\"; }"
2146               "}"
2147             "}"
2148             "MeshVertexColors {"
2149               "8;" /* DWORD nVertexColors; */
2150               /* array IndexedColor vertexColors[nVertexColors]; */
2151               "0; 0.0; 0.0; 0.0; 0.0;;"
2152               "1; 0.0; 0.0; 1.0; 0.1;;"
2153               "2; 0.0; 1.0; 0.0; 0.2;;"
2154               "3; 0.0; 1.0; 1.0; 0.3;;"
2155               "4; 1.0; 0.0; 0.0; 0.4;;"
2156               "5; 1.0; 0.0; 1.0; 0.5;;"
2157               "6; 1.0; 1.0; 0.0; 0.6;;"
2158               "7; 1.0; 1.0; 1.0; 0.7;;"
2159             "}"
2160             "MeshTextureCoords {"
2161               "8;" /* DWORD nTextureCoords; */
2162               /* array Coords2d textureCoords[nTextureCoords]; */
2163               "0.0; 1.0;,"
2164               "1.0; 1.0;,"
2165               "0.0; 0.0;,"
2166               "1.0; 0.0;,"
2167               "1.0; 1.0;,"
2168               "0.0; 1.0;,"
2169               "1.0; 0.0;,"
2170               "0.0; 0.0;;"
2171             "}"
2172           "}";
2173     static const WORD box_index_buffer[] = {
2174         0, 1, 3,
2175         0, 3, 2,
2176         8, 9, 7,
2177         8, 7, 6,
2178         10, 11, 5,
2179         10, 5, 4,
2180         12, 13, 14,
2181         12, 14, 15,
2182         16, 17, 18,
2183         16, 18, 19,
2184         20, 21, 22,
2185         20, 22, 23,
2186     };
2187     static const struct {
2188         D3DXVECTOR3 position;
2189         D3DXVECTOR3 normal;
2190         D3DCOLOR diffuse;
2191         D3DXVECTOR2 tex_coords;
2192     } box_vertex_buffer[] = {
2193         {{0.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, 0x00000000, {0.0, 1.0}},
2194         {{0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2195         {{0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2196         {{0.0, 1.0, 1.0}, {-1.0, 0.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2197         {{1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2198         {{1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2199         {{1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2200         {{1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2201         {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2202         {{0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2203         {{1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2204         {{1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2205         {{0.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2206         {{0.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x00000000, {0.0, 1.0}},
2207         {{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2208         {{1.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2209         {{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x1a0000ff, {1.0, 1.0}},
2210         {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x80ff00ff, {0.0, 1.0}},
2211         {{1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0xb3ffffff, {0.0, 0.0}},
2212         {{0.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0x4d00ffff, {1.0, 0.0}},
2213         {{0.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x00000000, {0.0, 1.0}},
2214         {{0.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x3300ff00, {0.0, 0.0}},
2215         {{1.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x99ffff00, {1.0, 0.0}},
2216         {{1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x66ff0000, {1.0, 1.0}},
2217     };
2218     static const D3DXMATERIAL box_materials[] = {
2219         {
2220             {
2221                 {0.0, 0.0, 1.0, 1.0}, /* Diffuse */
2222                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2223                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2224                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2225                 0.5, /* Power */
2226             },
2227             NULL, /* pTextureFilename */
2228         },
2229         {
2230             {
2231                 {1.0, 1.0, 1.0, 1.0}, /* Diffuse */
2232                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2233                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2234                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2235                 1.0, /* Power */
2236             },
2237             (char *)"texture.jpg", /* pTextureFilename */
2238         },
2239     };
2240     static const char box_anim_xfile[] =
2241         "xof 0303txt 0032"
2242         "Mesh CubeMesh {"
2243         "8;" /* DWORD nVertices; */
2244         /* array Vector vertices[nVertices]; */
2245         "0.0; 0.0; 0.0;,"
2246         "0.0; 0.0; 1.0;,"
2247         "0.0; 1.0; 0.0;,"
2248         "0.0; 1.0; 1.0;,"
2249         "1.0; 0.0; 0.0;,"
2250         "1.0; 0.0; 1.0;,"
2251         "1.0; 1.0; 0.0;,"
2252         "1.0; 1.0; 1.0;;"
2253         "6;" /* DWORD nFaces; */
2254         /* array MeshFace faces[nFaces]; */
2255         "4; 0, 1, 3, 2;," /* left side */
2256         "4; 2, 3, 7, 6;," /* top side */
2257         "4; 6, 7, 5, 4;," /* right side */
2258         "4; 1, 0, 4, 5;," /* bottom side */
2259         "4; 1, 5, 7, 3;," /* back side */
2260         "4; 0, 2, 6, 4;;" /* front side */
2261         "MeshNormals {"
2262         "6;" /* DWORD nNormals; */
2263         /* array Vector normals[nNormals]; */
2264         "-1.0; 0.0; 0.0;,"
2265         "0.0; 1.0; 0.0;,"
2266         "1.0; 0.0; 0.0;,"
2267         "0.0; -1.0; 0.0;,"
2268         "0.0; 0.0; 1.0;,"
2269         "0.0; 0.0; -1.0;;"
2270         "6;" /* DWORD nFaceNormals; */
2271         /* array MeshFace faceNormals[nFaceNormals]; */
2272         "4; 0, 0, 0, 0;,"
2273         "4; 1, 1, 1, 1;,"
2274         "4; 2, 2, 2, 2;,"
2275         "4; 3, 3, 3, 3;,"
2276         "4; 4, 4, 4, 4;,"
2277         "4; 5, 5, 5, 5;;"
2278         "}"
2279         "MeshMaterialList materials {"
2280         "2;" /* DWORD nMaterials; */
2281         "6;" /* DWORD nFaceIndexes; */
2282         /* array DWORD faceIndexes[nFaceIndexes]; */
2283         "0, 0, 0, 1, 1, 1;;"
2284         "Material {"
2285         /* ColorRGBA faceColor; */
2286         "0.0; 0.0; 1.0; 1.0;;"
2287         /* FLOAT power; */
2288         "0.5;"
2289         /* ColorRGB specularColor; */
2290         "1.0; 1.0; 1.0;;"
2291         /* ColorRGB emissiveColor; */
2292         "0.0; 0.0; 0.0;;"
2293         "}"
2294         "Material {"
2295         /* ColorRGBA faceColor; */
2296         "1.0; 1.0; 1.0; 1.0;;"
2297         /* FLOAT power; */
2298         "1.0;"
2299         /* ColorRGB specularColor; */
2300         "1.0; 1.0; 1.0;;"
2301         /* ColorRGB emissiveColor; */
2302         "0.0; 0.0; 0.0;;"
2303         "TextureFilename { \"texture.jpg\"; }"
2304         "}"
2305         "}"
2306         "MeshVertexColors {"
2307         "8;" /* DWORD nVertexColors; */
2308         /* array IndexedColor vertexColors[nVertexColors]; */
2309         "0; 0.0; 0.0; 0.0; 0.0;;"
2310         "1; 0.0; 0.0; 1.0; 0.1;;"
2311         "2; 0.0; 1.0; 0.0; 0.2;;"
2312         "3; 0.0; 1.0; 1.0; 0.3;;"
2313         "4; 1.0; 0.0; 0.0; 0.4;;"
2314         "5; 1.0; 0.0; 1.0; 0.5;;"
2315         "6; 1.0; 1.0; 0.0; 0.6;;"
2316         "7; 1.0; 1.0; 1.0; 0.7;;"
2317         "}"
2318         "MeshTextureCoords {"
2319         "8;" /* DWORD nTextureCoords; */
2320         /* array Coords2d textureCoords[nTextureCoords]; */
2321         "0.0; 1.0;,"
2322         "1.0; 1.0;,"
2323         "0.0; 0.0;,"
2324         "1.0; 0.0;,"
2325         "1.0; 1.0;,"
2326         "0.0; 1.0;,"
2327         "1.0; 0.0;,"
2328         "0.0; 0.0;;"
2329         "}"
2330         "}"
2331         "Frame CubeFrame {"
2332         "FrameTransformMatrix {"
2333         /* Matrix4x4 frameMatrix; */
2334         "1.0, 0.0, 0.0, 0.0,"
2335         "0.0, 1.0, 0.0, 0.0,"
2336         "0.0, 0.0, 1.0, 0.0,"
2337         "0.0, 0.0, 0.0, 1.0;;"
2338         "}"
2339         "{CubeMesh}"
2340         "}"
2341         "AnimationSet AnimationSet0 {"
2342         "Animation Animation0 {"
2343         "{CubeFrame}"
2344         "AnimationKey {"
2345         "2;" /* DWORD keyType; */
2346         "9;" /* DWORD nKeys; */
2347         /* array TimedFloatKeys keys[nKeys]; */
2348         "10; 3; -100.0, 0.0, 0.0;;,"
2349         "20; 3; -75.0,  0.0, 0.0;;,"
2350         "30; 3; -50.0,  0.0, 0.0;;,"
2351         "40; 3; -25.5,  0.0, 0.0;;,"
2352         "50; 3; 0.0,    0.0, 0.0;;,"
2353         "60; 3; 25.5,   0.0, 0.0;;,"
2354         "70; 3; 50.0,   0.0, 0.0;;,"
2355         "80; 3; 75.5,   0.0, 0.0;;,"
2356         "90; 3; 100.0,  0.0, 0.0;;;"
2357         "}"
2358         "}"
2359         "}";
2360 
2361     const DWORD box_fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
2362     /*________________________*/
2363     static const D3DXMATERIAL default_materials[] = {
2364         {
2365             {
2366                 {0.5, 0.5, 0.5, 0.0}, /* Diffuse */
2367                 {0.0, 0.0, 0.0, 0.0}, /* Ambient */
2368                 {0.5, 0.5, 0.5, 0.0}, /* Specular */
2369                 {0.0, 0.0, 0.0, 0.0}, /* Emissive */
2370                 0.0, /* Power */
2371             },
2372             NULL, /* pTextureFilename */
2373         }
2374     };
2375     HRESULT hr;
2376     IDirect3DDevice9 *device = NULL;
2377     ID3DXMesh *mesh = NULL;
2378     D3DXFRAME *frame_hier = NULL;
2379     D3DXMATRIX transform;
2380     struct test_context *test_context;
2381     ID3DXAnimationController *controller;
2382 
2383     if (!(test_context = new_test_context()))
2384     {
2385         skip("Couldn't create test context\n");
2386         return;
2387     }
2388     device = test_context->device;
2389 
2390     hr = D3DXLoadMeshHierarchyFromXInMemory(NULL, sizeof(simple_xfile) - 1,
2391             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2392     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2393 
2394     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, 0,
2395             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2396     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2397 
2398     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2399             D3DXMESH_MANAGED, NULL, &alloc_hier, NULL, &frame_hier, NULL);
2400     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2401 
2402     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2403             D3DXMESH_MANAGED, device, NULL, NULL, &frame_hier, NULL);
2404     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2405 
2406     hr = D3DXLoadMeshHierarchyFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1,
2407             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2408     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2409 
2410     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2411             D3DXMESH_MANAGED, device, &alloc_hier, NULL, NULL, NULL);
2412     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2413 
2414     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2415             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2416     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2417     if (SUCCEEDED(hr)) {
2418         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2419 
2420         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2421         D3DXMatrixIdentity(&transform);
2422         check_matrix(&frame_hier->TransformationMatrix, &transform);
2423 
2424         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2425         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2426            D3DXMESHTYPE_MESH, container->MeshData.Type);
2427         mesh = U(container->MeshData).pMesh;
2428         check_vertex_buffer(mesh, simple_vertex_buffer, ARRAY_SIZE(simple_vertex_buffer), simple_fvf);
2429         check_index_buffer(mesh, simple_index_buffer, ARRAY_SIZE(simple_index_buffer), sizeof(*simple_index_buffer));
2430         check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2431         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2432         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2433         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2434         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2435         frame_hier = NULL;
2436     }
2437 
2438     controller = (ID3DXAnimationController *)0xdeadbeef;
2439     hr = D3DXLoadMeshHierarchyFromXInMemory(box_anim_xfile, sizeof(box_anim_xfile) - 1,
2440             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2441     todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2442     if (SUCCEEDED(hr))
2443     {
2444         ok(controller != NULL, "Animation Controller NULL.\n");
2445 
2446         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2447         ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2448         if (controller)
2449             controller->lpVtbl->Release(controller);
2450 
2451         frame_hier = NULL;
2452     }
2453 
2454     controller = (ID3DXAnimationController *)0xdeadbeef;
2455     hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1,
2456             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2457     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2458     if (SUCCEEDED(hr))
2459     {
2460         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2461 
2462         ok(!controller, "Animation Controller returned.\n");
2463         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2464         D3DXMatrixIdentity(&transform);
2465         check_matrix(&frame_hier->TransformationMatrix, &transform);
2466 
2467         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2468         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2469            D3DXMESHTYPE_MESH, container->MeshData.Type);
2470         mesh = U(container->MeshData).pMesh;
2471         check_vertex_buffer(mesh, box_vertex_buffer, ARRAY_SIZE(box_vertex_buffer), box_fvf);
2472         check_index_buffer(mesh, box_index_buffer, ARRAY_SIZE(box_index_buffer), sizeof(*box_index_buffer));
2473         check_materials(container->pMaterials, container->NumMaterials, box_materials, ARRAY_SIZE(box_materials));
2474         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2475         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2476         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2477         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2478         frame_hier = NULL;
2479     }
2480 
2481     hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1,
2482             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2483     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2484     if (SUCCEEDED(hr)) {
2485         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2486         int i;
2487 
2488         ok(!strcmp(frame_hier->Name, ""), "Expected '', got '%s'\n", frame_hier->Name);
2489         /* last frame transform replaces the first */
2490         D3DXMatrixIdentity(&transform);
2491         U(transform).m[3][2] = 3.0;
2492         check_matrix(&frame_hier->TransformationMatrix, &transform);
2493 
2494         for (i = 0; i < 3; i++) {
2495             ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2496             ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2497                D3DXMESHTYPE_MESH, container->MeshData.Type);
2498             mesh = U(container->MeshData).pMesh;
2499             check_vertex_buffer(mesh, framed_vertex_buffers[i], ARRAY_SIZE(framed_vertex_buffers[0]), framed_fvf);
2500             check_index_buffer(mesh, framed_index_buffer, ARRAY_SIZE(framed_index_buffer), sizeof(*framed_index_buffer));
2501             check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2502             check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2503             check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2504             container = container->pNextMeshContainer;
2505         }
2506         ok(container == NULL, "Expected NULL, got %p\n", container);
2507         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2508         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2509         frame_hier = NULL;
2510     }
2511 
2512 
2513     hr = D3DXLoadMeshFromXInMemory(NULL, 0, D3DXMESH_MANAGED,
2514                                    device, NULL, NULL, NULL, NULL, &mesh);
2515     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2516 
2517     hr = D3DXLoadMeshFromXInMemory(NULL, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2518                                    device, NULL, NULL, NULL, NULL, &mesh);
2519     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2520 
2521     hr = D3DXLoadMeshFromXInMemory(simple_xfile, 0, D3DXMESH_MANAGED,
2522                                    device, NULL, NULL, NULL, NULL, &mesh);
2523     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2524 
2525     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2526                                    device, NULL, NULL, NULL, NULL, NULL);
2527     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2528 
2529     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2530                                    NULL, NULL, NULL, NULL, NULL, &mesh);
2531     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2532 
2533     hr = D3DXLoadMeshFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1, D3DXMESH_MANAGED,
2534                                    device, NULL, NULL, NULL, NULL, &mesh);
2535     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2536 
2537     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2538                                    device, NULL, NULL, NULL, NULL, &mesh);
2539     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2540     if (SUCCEEDED(hr))
2541         IUnknown_Release(mesh);
2542 
2543     test_LoadMeshFromX(device, simple_xfile, simple_vertex_buffer, simple_fvf, simple_index_buffer, default_materials, TRUE);
2544     test_LoadMeshFromX(device, box_xfile, box_vertex_buffer, box_fvf, box_index_buffer, box_materials, TRUE);
2545     test_LoadMeshFromX(device, framed_xfile, merged_vertex_buffer, framed_fvf, merged_index_buffer, default_materials, FALSE);
2546 
2547     free_test_context(test_context);
2548 }
2549 
2550 static BOOL compute_box(struct mesh *mesh, float width, float height, float depth)
2551 {
2552     unsigned int i, face;
2553     static const D3DXVECTOR3 unit_box[] =
2554     {
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         {-1.0f, -1.0f,  1.0f}, {-1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f,  1.0f},
2559         {-1.0f, -1.0f,  1.0f}, { 1.0f, -1.0f,  1.0f}, { 1.0f,  1.0f,  1.0f}, {-1.0f,  1.0f,  1.0f},
2560         {-1.0f, -1.0f, -1.0f}, {-1.0f,  1.0f, -1.0f}, { 1.0f,  1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}
2561     };
2562     static const D3DXVECTOR3 normals[] =
2563     {
2564         {-1.0f,  0.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f,  0.0f},
2565         { 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, -1.0f}
2566     };
2567 
2568     if (!new_mesh(mesh, 24, 12))
2569     {
2570         return FALSE;
2571     }
2572 
2573     width /= 2.0f;
2574     height /= 2.0f;
2575     depth /= 2.0f;
2576 
2577     for (i = 0; i < 24; i++)
2578     {
2579         mesh->vertices[i].position.x = width * unit_box[i].x;
2580         mesh->vertices[i].position.y = height * unit_box[i].y;
2581         mesh->vertices[i].position.z = depth * unit_box[i].z;
2582         mesh->vertices[i].normal.x = normals[i / 4].x;
2583         mesh->vertices[i].normal.y = normals[i / 4].y;
2584         mesh->vertices[i].normal.z = normals[i / 4].z;
2585     }
2586 
2587     face = 0;
2588     for (i = 0; i < 12; i++)
2589     {
2590         mesh->faces[i][0] = face++;
2591         mesh->faces[i][1] = face++;
2592         mesh->faces[i][2] = (i % 2) ? face - 4 : face;
2593     }
2594 
2595     return TRUE;
2596 }
2597 
2598 static void test_box(IDirect3DDevice9 *device, float width, float height, float depth)
2599 {
2600     HRESULT hr;
2601     ID3DXMesh *box;
2602     struct mesh mesh;
2603     char name[256];
2604 
2605     hr = D3DXCreateBox(device, width, height, depth, &box, NULL);
2606     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2607     if (hr != D3D_OK)
2608     {
2609         skip("Couldn't create box\n");
2610         return;
2611     }
2612 
2613     if (!compute_box(&mesh, width, height, depth))
2614     {
2615         skip("Couldn't create mesh\n");
2616         box->lpVtbl->Release(box);
2617         return;
2618     }
2619 
2620     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2621 
2622     sprintf(name, "box (%g, %g, %g)", width, height, depth);
2623     compare_mesh(name, box, &mesh);
2624 
2625     free_mesh(&mesh);
2626 
2627     box->lpVtbl->Release(box);
2628 }
2629 static void D3DXCreateBoxTest(void)
2630 {
2631     HRESULT hr;
2632     IDirect3DDevice9* device;
2633     ID3DXMesh* box;
2634     ID3DXBuffer* ppBuffer;
2635     DWORD *buffer;
2636     static const DWORD adjacency[36]=
2637         {6, 9, 1, 2, 10, 0,
2638          1, 9, 3, 4, 10, 2,
2639          3, 8, 5, 7, 11, 4,
2640          0, 11, 7, 5, 8, 6,
2641          7, 4, 9, 2, 0, 8,
2642          1, 3, 11, 5, 6, 10};
2643     unsigned int i;
2644     struct test_context *test_context;
2645 
2646     if (!(test_context = new_test_context()))
2647     {
2648         skip("Couldn't create test context\n");
2649         return;
2650     }
2651     device = test_context->device;
2652 
2653     hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
2654     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2655 
2656     hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
2657     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2658 
2659     hr = D3DXCreateBox(device,-2.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     hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
2666     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2667 
2668     ppBuffer = NULL;
2669     hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
2670     ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2671 
2672     buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
2673     for(i=0; i<36; i++)
2674         ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
2675 
2676     box->lpVtbl->Release(box);
2677     ID3DXBuffer_Release(ppBuffer);
2678 
2679     test_box(device, 10.9f, 20.0f, 4.9f);
2680 
2681     free_test_context(test_context);
2682 }
2683 
2684 static BOOL compute_polygon(struct mesh *mesh, float length, unsigned int sides)
2685 {
2686     unsigned int i;
2687     float angle, scale;
2688 
2689     if (!new_mesh(mesh, sides + 1, sides))
2690         return FALSE;
2691 
2692     angle = D3DX_PI / sides;
2693     scale = 0.5f * length / sinf(angle);
2694     angle *= 2.0f;
2695 
2696     mesh->vertices[0].position.x = 0.0f;
2697     mesh->vertices[0].position.y = 0.0f;
2698     mesh->vertices[0].position.z = 0.0f;
2699     mesh->vertices[0].normal.x = 0.0f;
2700     mesh->vertices[0].normal.y = 0.0f;
2701     mesh->vertices[0].normal.z = 1.0f;
2702 
2703     for (i = 0; i < sides; ++i)
2704     {
2705         mesh->vertices[i + 1].position.x = cosf(angle * i) * scale;
2706         mesh->vertices[i + 1].position.y = sinf(angle * i) * scale;
2707         mesh->vertices[i + 1].position.z = 0.0f;
2708         mesh->vertices[i + 1].normal.x = 0.0f;
2709         mesh->vertices[i + 1].normal.y = 0.0f;
2710         mesh->vertices[i + 1].normal.z = 1.0f;
2711 
2712         mesh->faces[i][0] = 0;
2713         mesh->faces[i][1] = i + 1;
2714         mesh->faces[i][2] = i + 2;
2715     }
2716 
2717     mesh->faces[sides - 1][2] = 1;
2718 
2719     return TRUE;
2720 }
2721 
2722 static void test_polygon(IDirect3DDevice9 *device, float length, unsigned int sides)
2723 {
2724     HRESULT hr;
2725     ID3DXMesh *polygon;
2726     struct mesh mesh;
2727     char name[64];
2728 
2729     hr = D3DXCreatePolygon(device, length, sides, &polygon, NULL);
2730     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2731     if (hr != D3D_OK)
2732     {
2733         skip("Couldn't create polygon\n");
2734         return;
2735     }
2736 
2737     if (!compute_polygon(&mesh, length, sides))
2738     {
2739         skip("Couldn't create mesh\n");
2740         polygon->lpVtbl->Release(polygon);
2741         return;
2742     }
2743 
2744     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2745 
2746     sprintf(name, "polygon (%g, %u)", length, sides);
2747     compare_mesh(name, polygon, &mesh);
2748 
2749     free_mesh(&mesh);
2750 
2751     polygon->lpVtbl->Release(polygon);
2752 }
2753 
2754 static void D3DXCreatePolygonTest(void)
2755 {
2756     HRESULT hr;
2757     IDirect3DDevice9 *device;
2758     ID3DXMesh *polygon;
2759     ID3DXBuffer *adjacency;
2760     DWORD (*buffer)[3], buffer_size;
2761     unsigned int i;
2762     struct test_context *test_context;
2763 
2764     if (!(test_context = new_test_context()))
2765     {
2766         skip("Couldn't create test context\n");
2767         return;
2768     }
2769     device = test_context->device;
2770 
2771     hr = D3DXCreatePolygon(device, 2.0f, 11, NULL, &adjacency);
2772     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2773 
2774     hr = D3DXCreatePolygon(NULL, 2.0f, 11, &polygon, &adjacency);
2775     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2776 
2777     hr = D3DXCreatePolygon(device, -2.0f, 11, &polygon, &adjacency);
2778     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2779 
2780     polygon = (void *)0xdeadbeef;
2781     adjacency = (void *)0xdeadbeef;
2782     hr = D3DXCreatePolygon(device, 2.0f, 0, &polygon, &adjacency);
2783     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2784     ok(polygon == (void *)0xdeadbeef, "Polygon was changed to %p\n", polygon);
2785     ok(adjacency == (void *)0xdeadbeef, "Adjacency was changed to %p\n", adjacency);
2786 
2787     hr = D3DXCreatePolygon(device, 2.0f, 2, &polygon, &adjacency);
2788     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2789 
2790     adjacency = NULL;
2791     hr = D3DXCreatePolygon(device, 3.0f, 11, &polygon, &adjacency);
2792     ok(hr == D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2793 
2794     buffer_size = ID3DXBuffer_GetBufferSize(adjacency);
2795     ok(buffer_size == 33 * sizeof(DWORD), "Wrong adjacency buffer size %u\n", buffer_size);
2796 
2797     buffer = ID3DXBuffer_GetBufferPointer(adjacency);
2798     for (i = 0; i < 11; ++i)
2799     {
2800         ok(buffer[i][0] == (i + 10) % 11, "Wrong adjacency[%d][0] = %u\n", i, buffer[i][0]);
2801         ok(buffer[i][1] == ~0U, "Wrong adjacency[%d][1] = %u\n", i, buffer[i][1]);
2802         ok(buffer[i][2] == (i + 1) % 11, "Wrong adjacency[%d][2] = %u\n", i, buffer[i][2]);
2803     }
2804 
2805     polygon->lpVtbl->Release(polygon);
2806     ID3DXBuffer_Release(adjacency);
2807 
2808     test_polygon(device, 2.0f, 3);
2809     test_polygon(device, 10.0f, 3);
2810     test_polygon(device, 10.0f, 5);
2811     test_polygon(device, 10.0f, 10);
2812     test_polygon(device, 20.0f, 10);
2813     test_polygon(device, 20.0f, 32000);
2814 
2815     free_test_context(test_context);
2816 }
2817 
2818 struct sincos_table
2819 {
2820     float *sin;
2821     float *cos;
2822 };
2823 
2824 static void free_sincos_table(struct sincos_table *sincos_table)
2825 {
2826     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
2827     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2828 }
2829 
2830 /* pre compute sine and cosine tables; caller must free */
2831 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
2832 {
2833     float angle;
2834     int i;
2835 
2836     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2837     if (!sincos_table->sin)
2838     {
2839         return FALSE;
2840     }
2841     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2842     if (!sincos_table->cos)
2843     {
2844         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2845         return FALSE;
2846     }
2847 
2848     angle = angle_start;
2849     for (i = 0; i < n; i++)
2850     {
2851         sincos_table->sin[i] = sin(angle);
2852         sincos_table->cos[i] = cos(angle);
2853         angle += angle_step;
2854     }
2855 
2856     return TRUE;
2857 }
2858 
2859 static WORD vertex_index(UINT slices, int slice, int stack)
2860 {
2861     return stack*slices+slice+1;
2862 }
2863 
2864 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
2865 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
2866 {
2867     float theta_step, theta_start;
2868     struct sincos_table theta;
2869     float phi_step, phi_start;
2870     struct sincos_table phi;
2871     DWORD number_of_vertices, number_of_faces;
2872     DWORD vertex, face;
2873     int slice, stack;
2874 
2875     /* theta = angle on xy plane wrt x axis */
2876     theta_step = D3DX_PI / stacks;
2877     theta_start = theta_step;
2878 
2879     /* phi = angle on xz plane wrt z axis */
2880     phi_step = -2 * D3DX_PI / slices;
2881     phi_start = D3DX_PI / 2;
2882 
2883     if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
2884     {
2885         return FALSE;
2886     }
2887     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
2888     {
2889         free_sincos_table(&theta);
2890         return FALSE;
2891     }
2892 
2893     number_of_vertices = 2 + slices * (stacks-1);
2894     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
2895 
2896     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2897     {
2898         free_sincos_table(&phi);
2899         free_sincos_table(&theta);
2900         return FALSE;
2901     }
2902 
2903     vertex = 0;
2904     face = 0;
2905 
2906     mesh->vertices[vertex].normal.x = 0.0f;
2907     mesh->vertices[vertex].normal.y = 0.0f;
2908     mesh->vertices[vertex].normal.z = 1.0f;
2909     mesh->vertices[vertex].position.x = 0.0f;
2910     mesh->vertices[vertex].position.y = 0.0f;
2911     mesh->vertices[vertex].position.z = radius;
2912     vertex++;
2913 
2914     for (stack = 0; stack < stacks - 1; stack++)
2915     {
2916         for (slice = 0; slice < slices; slice++)
2917         {
2918             mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
2919             mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
2920             mesh->vertices[vertex].normal.z = theta.cos[stack];
2921             mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
2922             mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
2923             mesh->vertices[vertex].position.z = radius * theta.cos[stack];
2924             vertex++;
2925 
2926             if (slice > 0)
2927             {
2928                 if (stack == 0)
2929                 {
2930                     /* top stack is triangle fan */
2931                     mesh->faces[face][0] = 0;
2932                     mesh->faces[face][1] = slice + 1;
2933                     mesh->faces[face][2] = slice;
2934                     face++;
2935                 }
2936                 else
2937                 {
2938                     /* stacks in between top and bottom are quad strips */
2939                     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2940                     mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2941                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2942                     face++;
2943 
2944                     mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2945                     mesh->faces[face][1] = vertex_index(slices, slice, stack);
2946                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2947                     face++;
2948                 }
2949             }
2950         }
2951 
2952         if (stack == 0)
2953         {
2954             mesh->faces[face][0] = 0;
2955             mesh->faces[face][1] = 1;
2956             mesh->faces[face][2] = slice;
2957             face++;
2958         }
2959         else
2960         {
2961             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2962             mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2963             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2964             face++;
2965 
2966             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2967             mesh->faces[face][1] = vertex_index(slices, 0, stack);
2968             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2969             face++;
2970         }
2971     }
2972 
2973     mesh->vertices[vertex].position.x = 0.0f;
2974     mesh->vertices[vertex].position.y = 0.0f;
2975     mesh->vertices[vertex].position.z = -radius;
2976     mesh->vertices[vertex].normal.x = 0.0f;
2977     mesh->vertices[vertex].normal.y = 0.0f;
2978     mesh->vertices[vertex].normal.z = -1.0f;
2979 
2980     /* bottom stack is triangle fan */
2981     for (slice = 1; slice < slices; slice++)
2982     {
2983         mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2984         mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2985         mesh->faces[face][2] = vertex;
2986         face++;
2987     }
2988 
2989     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2990     mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2991     mesh->faces[face][2] = vertex;
2992 
2993     free_sincos_table(&phi);
2994     free_sincos_table(&theta);
2995 
2996     return TRUE;
2997 }
2998 
2999 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
3000 {
3001     HRESULT hr;
3002     ID3DXMesh *sphere;
3003     struct mesh mesh;
3004     char name[256];
3005 
3006     hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
3007     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3008     if (hr != D3D_OK)
3009     {
3010         skip("Couldn't create sphere\n");
3011         return;
3012     }
3013 
3014     if (!compute_sphere(&mesh, radius, slices, stacks))
3015     {
3016         skip("Couldn't create mesh\n");
3017         sphere->lpVtbl->Release(sphere);
3018         return;
3019     }
3020 
3021     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3022 
3023     sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
3024     compare_mesh(name, sphere, &mesh);
3025 
3026     free_mesh(&mesh);
3027 
3028     sphere->lpVtbl->Release(sphere);
3029 }
3030 
3031 static void D3DXCreateSphereTest(void)
3032 {
3033     HRESULT hr;
3034     IDirect3DDevice9* device;
3035     ID3DXMesh* sphere = NULL;
3036     struct test_context *test_context;
3037 
3038     hr = D3DXCreateSphere(NULL, 0.0f, 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.1f, 0, 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, 1, 0, NULL, NULL);
3045     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3046 
3047     hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
3048     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3049 
3050     if (!(test_context = new_test_context()))
3051     {
3052         skip("Couldn't create test context\n");
3053         return;
3054     }
3055     device = test_context->device;
3056 
3057     hr = D3DXCreateSphere(device, 1.0f, 1, 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, 2, 1, &sphere, NULL);
3061     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3062 
3063     hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
3064     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3065 
3066     hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
3067     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3068 
3069     test_sphere(device, 0.0f, 2, 2);
3070     test_sphere(device, 1.0f, 2, 2);
3071     test_sphere(device, 1.0f, 3, 2);
3072     test_sphere(device, 1.0f, 4, 4);
3073     test_sphere(device, 1.0f, 3, 4);
3074     test_sphere(device, 5.0f, 6, 7);
3075     test_sphere(device, 10.0f, 11, 12);
3076 
3077     free_test_context(test_context);
3078 }
3079 
3080 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3081 {
3082     float theta_step, theta_start;
3083     struct sincos_table theta;
3084     FLOAT delta_radius, radius, radius_step;
3085     FLOAT z, z_step, z_normal;
3086     DWORD number_of_vertices, number_of_faces;
3087     DWORD vertex, face;
3088     int slice, stack;
3089 
3090     /* theta = angle on xy plane wrt x axis */
3091     theta_step = -2 * D3DX_PI / slices;
3092     theta_start = D3DX_PI / 2;
3093 
3094     if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
3095     {
3096         return FALSE;
3097     }
3098 
3099     number_of_vertices = 2 + (slices * (3 + stacks));
3100     number_of_faces = 2 * slices + stacks * (2 * slices);
3101 
3102     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
3103     {
3104         free_sincos_table(&theta);
3105         return FALSE;
3106     }
3107 
3108     vertex = 0;
3109     face = 0;
3110 
3111     delta_radius = radius1 - radius2;
3112     radius = radius1;
3113     radius_step = delta_radius / stacks;
3114 
3115     z = -length / 2;
3116     z_step = length / stacks;
3117     z_normal = delta_radius / length;
3118     if (isnan(z_normal))
3119     {
3120         z_normal = 0.0f;
3121     }
3122 
3123     mesh->vertices[vertex].normal.x = 0.0f;
3124     mesh->vertices[vertex].normal.y = 0.0f;
3125     mesh->vertices[vertex].normal.z = -1.0f;
3126     mesh->vertices[vertex].position.x = 0.0f;
3127     mesh->vertices[vertex].position.y = 0.0f;
3128     mesh->vertices[vertex++].position.z = z;
3129 
3130     for (slice = 0; slice < slices; slice++, vertex++)
3131     {
3132         mesh->vertices[vertex].normal.x = 0.0f;
3133         mesh->vertices[vertex].normal.y = 0.0f;
3134         mesh->vertices[vertex].normal.z = -1.0f;
3135         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3136         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3137         mesh->vertices[vertex].position.z = z;
3138 
3139         if (slice > 0)
3140         {
3141             mesh->faces[face][0] = 0;
3142             mesh->faces[face][1] = slice;
3143             mesh->faces[face++][2] = slice + 1;
3144         }
3145     }
3146 
3147     mesh->faces[face][0] = 0;
3148     mesh->faces[face][1] = slice;
3149     mesh->faces[face++][2] = 1;
3150 
3151     for (stack = 1; stack <= stacks+1; stack++)
3152     {
3153         for (slice = 0; slice < slices; slice++, vertex++)
3154         {
3155             mesh->vertices[vertex].normal.x = theta.cos[slice];
3156             mesh->vertices[vertex].normal.y = theta.sin[slice];
3157             mesh->vertices[vertex].normal.z = z_normal;
3158             D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
3159             mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3160             mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3161             mesh->vertices[vertex].position.z = z;
3162 
3163             if (stack > 1 && slice > 0)
3164             {
3165                 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3166                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3167                 mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
3168 
3169                 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
3170                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3171                 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3172             }
3173         }
3174 
3175         if (stack > 1)
3176         {
3177             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3178             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3179             mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
3180 
3181             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
3182             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3183             mesh->faces[face++][2] = vertex_index(slices, 0, stack);
3184         }
3185 
3186         if (stack < stacks + 1)
3187         {
3188             z += z_step;
3189             radius -= radius_step;
3190         }
3191     }
3192 
3193     for (slice = 0; slice < slices; slice++, vertex++)
3194     {
3195         mesh->vertices[vertex].normal.x = 0.0f;
3196         mesh->vertices[vertex].normal.y = 0.0f;
3197         mesh->vertices[vertex].normal.z = 1.0f;
3198         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3199         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3200         mesh->vertices[vertex].position.z = z;
3201 
3202         if (slice > 0)
3203         {
3204             mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3205             mesh->faces[face][1] = number_of_vertices - 1;
3206             mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3207         }
3208     }
3209 
3210     mesh->vertices[vertex].position.x = 0.0f;
3211     mesh->vertices[vertex].position.y = 0.0f;
3212     mesh->vertices[vertex].position.z = z;
3213     mesh->vertices[vertex].normal.x = 0.0f;
3214     mesh->vertices[vertex].normal.y = 0.0f;
3215     mesh->vertices[vertex].normal.z = 1.0f;
3216 
3217     mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3218     mesh->faces[face][1] = number_of_vertices - 1;
3219     mesh->faces[face][2] = vertex_index(slices, 0, stack);
3220 
3221     free_sincos_table(&theta);
3222 
3223     return TRUE;
3224 }
3225 
3226 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3227 {
3228     HRESULT hr;
3229     ID3DXMesh *cylinder;
3230     struct mesh mesh;
3231     char name[256];
3232 
3233     hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
3234     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3235     if (hr != D3D_OK)
3236     {
3237         skip("Couldn't create cylinder\n");
3238         return;
3239     }
3240 
3241     if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
3242     {
3243         skip("Couldn't create mesh\n");
3244         cylinder->lpVtbl->Release(cylinder);
3245         return;
3246     }
3247 
3248     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3249 
3250     sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
3251     compare_mesh(name, cylinder, &mesh);
3252 
3253     free_mesh(&mesh);
3254 
3255     cylinder->lpVtbl->Release(cylinder);
3256 }
3257 
3258 static void D3DXCreateCylinderTest(void)
3259 {
3260     HRESULT hr;
3261     IDirect3DDevice9* device;
3262     ID3DXMesh* cylinder = NULL;
3263     struct test_context *test_context;
3264 
3265     hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
3266     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3267 
3268     hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3269     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3270 
3271     if (!(test_context = new_test_context()))
3272     {
3273         skip("Couldn't create test context\n");
3274         return;
3275     }
3276     device = test_context->device;
3277 
3278     hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3279     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3280 
3281     hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3282     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3283 
3284     if (SUCCEEDED(hr) && cylinder)
3285     {
3286         cylinder->lpVtbl->Release(cylinder);
3287     }
3288 
3289     hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
3290     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3291 
3292     hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
3293     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3294 
3295     if (SUCCEEDED(hr) && cylinder)
3296     {
3297         cylinder->lpVtbl->Release(cylinder);
3298     }
3299 
3300     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
3301     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3302 
3303     /* Test with length == 0.0f succeeds */
3304     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
3305     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3306 
3307     if (SUCCEEDED(hr) && cylinder)
3308     {
3309         cylinder->lpVtbl->Release(cylinder);
3310     }
3311 
3312     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &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, 0, &cylinder, NULL);
3316     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3317 
3318     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
3319     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3320 
3321     test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
3322     test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
3323     test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
3324     test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
3325     test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
3326     test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
3327 
3328     free_test_context(test_context);
3329 }
3330 
3331 static BOOL compute_torus(struct mesh *mesh, float innerradius, float outerradius, UINT sides, UINT rings)
3332 {
3333     float phi, phi_step, sin_phi, cos_phi;
3334     float theta, theta_step, sin_theta, cos_theta;
3335     unsigned int numvert, numfaces, i, j;
3336 
3337     numvert = sides * rings;
3338     numfaces = numvert * 2;
3339 
3340     if (!new_mesh(mesh, numvert, numfaces))
3341         return FALSE;
3342 
3343     phi_step = D3DX_PI / sides * 2.0f;
3344     theta_step = D3DX_PI / rings * -2.0f;
3345 
3346     theta = 0.0f;
3347 
3348     for (i = 0; i < rings; ++i)
3349     {
3350         phi = 0.0f;
3351 
3352         cos_theta = cosf(theta);
3353         sin_theta = sinf(theta);
3354 
3355         for (j = 0; j < sides; ++j)
3356         {
3357             sin_phi = sinf(phi);
3358             cos_phi = cosf(phi);
3359 
3360             mesh->vertices[i * sides + j].position.x = (innerradius * cos_phi + outerradius) * cos_theta;
3361             mesh->vertices[i * sides + j].position.y = (innerradius * cos_phi + outerradius) * sin_theta;
3362             mesh->vertices[i * sides + j].position.z = innerradius * sin_phi;
3363             mesh->vertices[i * sides + j].normal.x = cos_phi * cos_theta;
3364             mesh->vertices[i * sides + j].normal.y = cos_phi * sin_theta;
3365             mesh->vertices[i * sides + j].normal.z = sin_phi;
3366 
3367             phi += phi_step;
3368         }
3369 
3370         theta += theta_step;
3371     }
3372 
3373     for (i = 0; i < numfaces - sides * 2; ++i)
3374     {
3375         mesh->faces[i][0] = i % 2 ? i / 2 + sides : i / 2;
3376         mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3377         mesh->faces[i][2] = (i + 1) % (sides * 2) ? (i + 1) / 2 + sides : (i + 1) / 2;
3378     }
3379 
3380     for (j = 0; i < numfaces; ++i, ++j)
3381     {
3382         mesh->faces[i][0] = i % 2 ? j / 2 : i / 2;
3383         mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3384         mesh->faces[i][2] = i == numfaces - 1 ? 0 : (j + 1) / 2;
3385     }
3386 
3387     return TRUE;
3388 }
3389 
3390 static void test_torus(IDirect3DDevice9 *device, float innerradius, float outerradius, UINT sides, UINT rings)
3391 {
3392     HRESULT hr;
3393     ID3DXMesh *torus;
3394     struct mesh mesh;
3395     char name[256];
3396 
3397     hr = D3DXCreateTorus(device, innerradius, outerradius, sides, rings, &torus, NULL);
3398     ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK)\n", hr);
3399     if (hr != D3D_OK)
3400     {
3401         skip("Couldn't create torus\n");
3402         return;
3403     }
3404 
3405     if (!compute_torus(&mesh, innerradius, outerradius, sides, rings))
3406     {
3407         skip("Couldn't create mesh\n");
3408         torus->lpVtbl->Release(torus);
3409         return;
3410     }
3411 
3412     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3413 
3414     sprintf(name, "torus (%g, %g, %u, %u)", innerradius, outerradius, sides, rings);
3415     compare_mesh(name, torus, &mesh);
3416 
3417     free_mesh(&mesh);
3418 
3419     torus->lpVtbl->Release(torus);
3420 }
3421 
3422 static void D3DXCreateTorusTest(void)
3423 {
3424     HRESULT hr;
3425     IDirect3DDevice9* device;
3426     ID3DXMesh* torus = NULL;
3427     struct test_context *test_context;
3428 
3429     if (!(test_context = new_test_context()))
3430     {
3431         skip("Couldn't create test context\n");
3432         return;
3433     }
3434     device = test_context->device;
3435 
3436     hr = D3DXCreateTorus(NULL, 0.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, -1.0f, 0.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, -1.0f, 3, 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, 2, 3, &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, 2, &torus, NULL);
3449     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3450 
3451     hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 3, NULL, NULL);
3452     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3453 
3454     test_torus(device, 0.0f, 0.0f, 3, 3);
3455     test_torus(device, 1.0f, 1.0f, 3, 3);
3456     test_torus(device, 1.0f, 1.0f, 32, 64);
3457     test_torus(device, 0.0f, 1.0f, 5, 5);
3458     test_torus(device, 1.0f, 0.0f, 5, 5);
3459     test_torus(device, 5.0f, 0.2f, 8, 8);
3460     test_torus(device, 0.2f, 1.0f, 60, 3);
3461     test_torus(device, 0.2f, 1.0f, 8, 70);
3462 
3463     free_test_context(test_context);
3464 }
3465 
3466 struct dynamic_array
3467 {
3468     int count, capacity;
3469     void *items;
3470 };
3471 
3472 enum pointtype {
3473     POINTTYPE_CURVE = 0,
3474     POINTTYPE_CORNER,
3475     POINTTYPE_CURVE_START,
3476     POINTTYPE_CURVE_END,
3477     POINTTYPE_CURVE_MIDDLE,
3478 };
3479 
3480 struct point2d
3481 {
3482     D3DXVECTOR2 pos;
3483     enum pointtype corner;
3484 };
3485 
3486 /* is a dynamic_array */
3487 struct outline
3488 {
3489     int count, capacity;
3490     struct point2d *items;
3491 };
3492 
3493 /* is a dynamic_array */
3494 struct outline_array
3495 {
3496     int count, capacity;
3497     struct outline *items;
3498 };
3499 
3500 struct glyphinfo
3501 {
3502     struct outline_array outlines;
3503     float offset_x;
3504 };
3505 
3506 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
3507 {
3508     if (count > array->capacity) {
3509         void *new_buffer;
3510         int new_capacity;
3511         if (array->items && array->capacity) {
3512             new_capacity = max(array->capacity * 2, count);
3513             new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
3514         } else {
3515             new_capacity = max(16, count);
3516             new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
3517         }
3518         if (!new_buffer)
3519             return FALSE;
3520         array->items = new_buffer;
3521         array->capacity = new_capacity;
3522     }
3523     return TRUE;
3524 }
3525 
3526 static struct point2d *add_point(struct outline *array)
3527 {
3528     struct point2d *item;
3529 
3530     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3531         return NULL;
3532 
3533     item = &array->items[array->count++];
3534     ZeroMemory(item, sizeof(*item));
3535     return item;
3536 }
3537 
3538 static struct outline *add_outline(struct outline_array *array)
3539 {
3540     struct outline *item;
3541 
3542     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3543         return NULL;
3544 
3545     item = &array->items[array->count++];
3546     ZeroMemory(item, sizeof(*item));
3547     return item;
3548 }
3549 
3550 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
3551 {
3552     D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
3553     while (count--) {
3554         D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
3555         pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
3556         pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
3557         pt++;
3558     }
3559     return ret;
3560 }
3561 
3562 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
3563                                  const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
3564                                  float max_deviation)
3565 {
3566     D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
3567     float deviation;
3568 
3569     D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
3570     D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
3571     D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
3572 
3573     deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
3574     if (deviation < max_deviation) {
3575         struct point2d *pt = add_point(outline);
3576         if (!pt) return E_OUTOFMEMORY;
3577         pt->pos = *p2;
3578         pt->corner = POINTTYPE_CURVE;
3579         /* the end point is omitted because the end line merges into the next segment of
3580          * the split bezier curve, and the end of the split bezier curve is added outside
3581          * this recursive function. */
3582     } else {
3583         HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
3584         if (hr != S_OK) return hr;
3585         hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
3586         if (hr != S_OK) return hr;
3587     }
3588 
3589     return S_OK;
3590 }
3591 
3592 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
3593 {
3594     /* dot product = cos(theta) */
3595     return D3DXVec2Dot(dir1, dir2) > cos_theta;
3596 }
3597 
3598 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
3599 {
3600     return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
3601 }
3602 
3603 static BOOL attempt_line_merge(struct outline *outline,
3604                                int pt_index,
3605                                const D3DXVECTOR2 *nextpt,
3606                                BOOL to_curve)
3607 {
3608     D3DXVECTOR2 curdir, lastdir;
3609     struct point2d *prevpt, *pt;
3610     BOOL ret = FALSE;
3611     const float cos_half = cos(D3DXToRadian(0.5f));
3612 
3613     pt = &outline->items[pt_index];
3614     pt_index = (pt_index - 1 + outline->count) % outline->count;
3615     prevpt = &outline->items[pt_index];
3616 
3617     if (to_curve)
3618         pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
3619 
3620     if (outline->count < 2)
3621         return FALSE;
3622 
3623     /* remove last point if the next line continues the last line */
3624     unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3625     unit_vec2(&curdir, &pt->pos, nextpt);
3626     if (is_direction_similar(&lastdir, &curdir, cos_half))
3627     {
3628         outline->count--;
3629         if (pt->corner == POINTTYPE_CURVE_END)
3630             prevpt->corner = pt->corner;
3631         if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
3632             prevpt->corner = POINTTYPE_CURVE_MIDDLE;
3633         pt = prevpt;
3634 
3635         ret = TRUE;
3636         if (outline->count < 2)
3637             return ret;
3638 
3639         pt_index = (pt_index - 1 + outline->count) % outline->count;
3640         prevpt = &outline->items[pt_index];
3641         unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3642         unit_vec2(&curdir, &pt->pos, nextpt);
3643     }
3644     return ret;
3645 }
3646 
3647 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
3648                               float max_deviation, float emsquare)
3649 {
3650     const float cos_45 = cos(D3DXToRadian(45.0f));
3651     const float cos_90 = cos(D3DXToRadian(90.0f));
3652     TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
3653 
3654     while ((char *)header < (char *)raw_outline + datasize)
3655     {
3656         TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
3657         struct point2d *lastpt, *pt;
3658         D3DXVECTOR2 lastdir;
3659         D3DXVECTOR2 *pt_flt;
3660         int j;
3661         struct outline *outline = add_outline(&glyph->outlines);
3662 
3663         if (!outline)
3664             return E_OUTOFMEMORY;
3665 
3666         pt = add_point(outline);
3667         if (!pt)
3668             return E_OUTOFMEMORY;
3669         pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
3670         pt->pos = *pt_flt;
3671         pt->corner = POINTTYPE_CORNER;
3672 
3673         if (header->dwType != TT_POLYGON_TYPE)
3674             trace("Unknown header type %d\n", header->dwType);
3675 
3676         while ((char *)curve < (char *)header + header->cb)
3677         {
3678             D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
3679             BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
3680 
3681             if (!curve->cpfx) {
3682                 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3683                 continue;
3684             }
3685 
3686             pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
3687 
3688             attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
3689 
3690             if (to_curve)
3691             {
3692                 HRESULT hr;
3693                 int count = curve->cpfx;
3694                 j = 0;
3695 
3696                 while (count > 2)
3697                 {
3698                     D3DXVECTOR2 bezier_end;
3699 
3700                     D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
3701                     hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
3702                     if (hr != S_OK)
3703                         return hr;
3704                     bezier_start = bezier_end;
3705                     count--;
3706                     j++;
3707                 }
3708                 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
3709                 if (hr != S_OK)
3710                     return hr;
3711 
3712                 pt = add_point(outline);
3713                 if (!pt)
3714                     return E_OUTOFMEMORY;
3715                 j++;
3716                 pt->pos = pt_flt[j];
3717                 pt->corner = POINTTYPE_CURVE_END;
3718             } else {
3719                 for (j = 0; j < curve->cpfx; j++)
3720                 {
3721                     pt = add_point(outline);
3722                     if (!pt)
3723                         return E_OUTOFMEMORY;
3724                     pt->pos = pt_flt[j];
3725                     pt->corner = POINTTYPE_CORNER;
3726                 }
3727             }
3728 
3729             curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3730         }
3731 
3732         /* remove last point if the next line continues the last line */
3733         if (outline->count >= 3) {
3734             BOOL to_curve;
3735 
3736             lastpt = &outline->items[outline->count - 1];
3737             pt = &outline->items[0];
3738             if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
3739                 if (lastpt->corner == POINTTYPE_CURVE_END)
3740                 {
3741                     if (pt->corner == POINTTYPE_CURVE_START)
3742                         pt->corner = POINTTYPE_CURVE_MIDDLE;
3743                     else
3744                         pt->corner = POINTTYPE_CURVE_END;
3745                 }
3746                 outline->count--;
3747             } else {
3748                 /* outline closed with a line from end to start point */
3749                 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
3750             }
3751             lastpt = &outline->items[0];
3752             to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
3753             if (lastpt->corner == POINTTYPE_CURVE_START)
3754                 lastpt->corner = POINTTYPE_CORNER;
3755             pt = &outline->items[1];
3756             if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
3757                 *lastpt = outline->items[outline->count];
3758         }
3759 
3760         lastpt = &outline->items[outline->count - 1];
3761         pt = &outline->items[0];
3762         unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
3763         for (j = 0; j < outline->count; j++)
3764         {
3765             D3DXVECTOR2 curdir;
3766 
3767             lastpt = pt;
3768             pt = &outline->items[(j + 1) % outline->count];
3769             unit_vec2(&curdir, &lastpt->pos, &pt->pos);
3770 
3771             switch (lastpt->corner)
3772             {
3773                 case POINTTYPE_CURVE_START:
3774                 case POINTTYPE_CURVE_END:
3775                     if (!is_direction_similar(&lastdir, &curdir, cos_45))
3776                         lastpt->corner = POINTTYPE_CORNER;
3777                     break;
3778                 case POINTTYPE_CURVE_MIDDLE:
3779                     if (!is_direction_similar(&lastdir, &curdir, cos_90))
3780                         lastpt->corner = POINTTYPE_CORNER;
3781                     else
3782                         lastpt->corner = POINTTYPE_CURVE;
3783                     break;
3784                 default:
3785                     break;
3786             }
3787             lastdir = curdir;
3788         }
3789 
3790         header = (TTPOLYGONHEADER *)((char *)header + header->cb);
3791     }
3792     return S_OK;
3793 }
3794 
3795 static void free_outline(struct outline *outline)
3796 {
3797     HeapFree(GetProcessHeap(), 0, outline->items);
3798 }
3799 
3800 static void free_glyphinfo(struct glyphinfo *glyph)
3801 {
3802     unsigned int i;
3803 
3804     for (i = 0; i < glyph->outlines.count; ++i)
3805         free_outline(&glyph->outlines.items[i]);
3806     HeapFree(GetProcessHeap(), 0, glyph->outlines.items);
3807 }
3808 
3809 static void compute_text_mesh(struct mesh *mesh, const char *text,
3810         float deviation, float extrusion, float otmEMSquare, const struct glyphinfo *glyphs)
3811 {
3812     DWORD nb_vertices, nb_faces;
3813     DWORD nb_corners, nb_outline_points;
3814     int textlen = 0;
3815     int i;
3816     struct vertex *vertex_ptr;
3817     face *face_ptr;
3818 
3819     textlen = strlen(text);
3820 
3821     /* corner points need an extra vertex for the different side faces normals */
3822     nb_corners = 0;
3823     nb_outline_points = 0;
3824     for (i = 0; i < textlen; i++)
3825     {
3826         int j;
3827         for (j = 0; j < glyphs[i].outlines.count; j++)
3828         {
3829             int k;
3830             struct outline *outline = &glyphs[i].outlines.items[j];
3831             nb_outline_points += outline->count;
3832             nb_corners++; /* first outline point always repeated as a corner */
3833             for (k = 1; k < outline->count; k++)
3834                 if (outline->items[k].corner)
3835                     nb_corners++;
3836         }
3837     }
3838 
3839     nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
3840     nb_faces = nb_outline_points * 2;
3841 
3842     ok(new_mesh(mesh, nb_vertices, nb_faces), "Failed to create reference text mesh.\n");
3843 
3844     /* convert 2D vertices and faces into 3D mesh */
3845     vertex_ptr = mesh->vertices;
3846     face_ptr = mesh->faces;
3847     for (i = 0; i < textlen; i++)
3848     {
3849         int j;
3850 
3851         /* side vertices and faces */
3852         for (j = 0; j < glyphs[i].outlines.count; j++)
3853         {
3854             struct vertex *outline_vertices = vertex_ptr;
3855             struct outline *outline = &glyphs[i].outlines.items[j];
3856             int k;
3857             struct point2d *prevpt = &outline->items[outline->count - 1];
3858             struct point2d *pt = &outline->items[0];
3859 
3860             for (k = 1; k <= outline->count; k++)
3861             {
3862                 struct vertex vtx;
3863                 struct point2d *nextpt = &outline->items[k % outline->count];
3864                 WORD vtx_idx = vertex_ptr - mesh->vertices;
3865                 D3DXVECTOR2 vec;
3866 
3867                 if (pt->corner == POINTTYPE_CURVE_START)
3868                     D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
3869                 else if (pt->corner)
3870                     D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3871                 else
3872                     D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
3873                 D3DXVec2Normalize(&vec, &vec);
3874                 vtx.normal.x = -vec.y;
3875                 vtx.normal.y = vec.x;
3876                 vtx.normal.z = 0;
3877 
3878                 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
3879                 vtx.position.y = pt->pos.y;
3880                 vtx.position.z = 0;
3881                 *vertex_ptr++ = vtx;
3882 
3883                 vtx.position.z = -extrusion;
3884                 *vertex_ptr++ = vtx;
3885 
3886                 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
3887                 vtx.position.y = nextpt->pos.y;
3888                 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
3889                     vtx.position.z = -extrusion;
3890                     *vertex_ptr++ = vtx;
3891                     vtx.position.z = 0;
3892                     *vertex_ptr++ = vtx;
3893 
3894                     (*face_ptr)[0] = vtx_idx;
3895                     (*face_ptr)[1] = vtx_idx + 2;
3896                     (*face_ptr)[2] = vtx_idx + 1;
3897                     face_ptr++;
3898 
3899                     (*face_ptr)[0] = vtx_idx;
3900                     (*face_ptr)[1] = vtx_idx + 3;
3901                     (*face_ptr)[2] = vtx_idx + 2;
3902                     face_ptr++;
3903                 } else {
3904                     if (nextpt->corner) {
3905                         if (nextpt->corner == POINTTYPE_CURVE_END) {
3906                             struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
3907                             D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
3908                         } else {
3909                             D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3910                         }
3911                         D3DXVec2Normalize(&vec, &vec);
3912                         vtx.normal.x = -vec.y;
3913                         vtx.normal.y = vec.x;
3914 
3915                         vtx.position.z = 0;
3916                         *vertex_ptr++ = vtx;
3917                         vtx.position.z = -extrusion;
3918                         *vertex_ptr++ = vtx;
3919                     }
3920 
3921                     (*face_ptr)[0] = vtx_idx;
3922                     (*face_ptr)[1] = vtx_idx + 3;
3923                     (*face_ptr)[2] = vtx_idx + 1;
3924                     face_ptr++;
3925 
3926                     (*face_ptr)[0] = vtx_idx;
3927                     (*face_ptr)[1] = vtx_idx + 2;
3928                     (*face_ptr)[2] = vtx_idx + 3;
3929                     face_ptr++;
3930                 }
3931 
3932                 prevpt = pt;
3933                 pt = nextpt;
3934             }
3935             if (!pt->corner) {
3936                 *vertex_ptr++ = *outline_vertices++;
3937                 *vertex_ptr++ = *outline_vertices++;
3938             }
3939         }
3940 
3941         /* FIXME: compute expected faces */
3942         /* Add placeholder to separate glyph outlines */
3943         vertex_ptr->position.x = 0;
3944         vertex_ptr->position.y = 0;
3945         vertex_ptr->position.z = 0;
3946         vertex_ptr->normal.x = 0;
3947         vertex_ptr->normal.y = 0;
3948         vertex_ptr->normal.z = 1;
3949         vertex_ptr++;
3950     }
3951 }
3952 
3953 static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh,
3954         size_t textlen, float extrusion, const struct glyphinfo *glyphs)
3955 {
3956     HRESULT hr;
3957     DWORD number_of_vertices, number_of_faces;
3958     IDirect3DVertexBuffer9 *vertex_buffer = NULL;
3959     IDirect3DIndexBuffer9 *index_buffer = NULL;
3960     D3DVERTEXBUFFER_DESC vertex_buffer_description;
3961     D3DINDEXBUFFER_DESC index_buffer_description;
3962     struct vertex *vertices = NULL;
3963     face *faces = NULL;
3964     int expected, i;
3965     int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
3966 
3967     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
3968     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
3969 
3970     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
3971     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
3972     hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
3973     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
3974     ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, unexpected format %u.\n",
3975             name, vertex_buffer_description.Format);
3976     ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, unexpected resource type %u.\n",
3977             name, vertex_buffer_description.Type);
3978     ok(!vertex_buffer_description.Usage, "Test %s, unexpected usage %#x.\n", name, vertex_buffer_description.Usage);
3979     ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, unexpected pool %u.\n",
3980             name, vertex_buffer_description.Pool);
3981     ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, unexpected FVF %#x (expected %#x).\n",
3982             name, vertex_buffer_description.FVF, mesh->fvf);
3983     if (!mesh->fvf)
3984         expected = number_of_vertices * mesh->vertex_size;
3985     else
3986         expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
3987     ok(vertex_buffer_description.Size == expected, "Test %s, unexpected size %u (expected %u).\n",
3988             name, vertex_buffer_description.Size, expected);
3989 
3990     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
3991     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
3992     hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
3993     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
3994     ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, unexpected format %u.\n",
3995             name, index_buffer_description.Format);
3996     ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, unexpected resource type %u.\n",
3997             name, index_buffer_description.Type);
3998     ok(!index_buffer_description.Usage, "Test %s, unexpected usage %#x.\n",
3999             name, index_buffer_description.Usage);
4000     ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, unexpected pool %u.\n",
4001             name, index_buffer_description.Pool);
4002     expected = number_of_faces * sizeof(WORD) * 3;
4003     ok(index_buffer_description.Size == expected, "Test %s, unexpected size %u.\n",
4004             name, index_buffer_description.Size);
4005 
4006     hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
4007             (void **)&vertices, D3DLOCK_DISCARD);
4008     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4009     hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
4010             (void **)&faces, D3DLOCK_DISCARD);
4011     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4012     face_idx1 = 0;
4013     vtx_idx2 = 0;
4014     face_idx2 = 0;
4015     vtx_idx1 = 0;
4016     for (i = 0; i < textlen; i++)
4017     {
4018         int nb_outline_vertices1, nb_outline_faces1;
4019         int nb_outline_vertices2, nb_outline_faces2;
4020         int nb_back_vertices, nb_back_faces;
4021         int first_vtx1, first_vtx2;
4022         int first_face1, first_face2;
4023         int j;
4024 
4025         first_vtx1 = vtx_idx1;
4026         first_vtx2 = vtx_idx2;
4027         /* Glyphs without outlines do not generate any vertices. */
4028         if (glyphs[i].outlines.count > 0)
4029         {
4030             for (; vtx_idx1 < number_of_vertices; vtx_idx1++)
4031             {
4032                 if (vertices[vtx_idx1].normal.z != 0)
4033                     break;
4034             }
4035 
4036             for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++)
4037             {
4038                 if (mesh->vertices[vtx_idx2].normal.z != 0)
4039                     break;
4040             }
4041         }
4042         nb_outline_vertices1 = vtx_idx1 - first_vtx1;
4043         nb_outline_vertices2 = vtx_idx2 - first_vtx2;
4044         ok(nb_outline_vertices1 == nb_outline_vertices2,
4045            "Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
4046            nb_outline_vertices1, nb_outline_vertices2);
4047 
4048         for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
4049         {
4050             vtx_idx1 = first_vtx1 + j;
4051             vtx_idx2 = first_vtx2 + j;
4052             ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
4053                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4054                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
4055                mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
4056             ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
4057                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4058                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4059                mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
4060         }
4061         vtx_idx1 = first_vtx1 + nb_outline_vertices1;
4062         vtx_idx2 = first_vtx2 + nb_outline_vertices2;
4063 
4064         first_face1 = face_idx1;
4065         first_face2 = face_idx2;
4066         for (; face_idx1 < number_of_faces; face_idx1++)
4067         {
4068             if (faces[face_idx1][0] >= vtx_idx1 ||
4069                 faces[face_idx1][1] >= vtx_idx1 ||
4070                 faces[face_idx1][2] >= vtx_idx1)
4071                 break;
4072         }
4073         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
4074         {
4075             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
4076                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
4077                 mesh->faces[face_idx2][2] >= vtx_idx2)
4078                 break;
4079         }
4080         nb_outline_faces1 = face_idx1 - first_face1;
4081         nb_outline_faces2 = face_idx2 - first_face2;
4082         ok(nb_outline_faces1 == nb_outline_faces2,
4083            "Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
4084            nb_outline_faces1, nb_outline_faces2);
4085 
4086         for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
4087         {
4088             face_idx1 = first_face1 + j;
4089             face_idx2 = first_face2 + j;
4090             ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
4091                faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
4092                faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
4093                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
4094                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
4095                mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
4096                mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
4097                mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
4098         }
4099         face_idx1 = first_face1 + nb_outline_faces1;
4100         face_idx2 = first_face2 + nb_outline_faces2;
4101 
4102         /* partial test on back vertices and faces  */
4103         first_vtx1 = vtx_idx1;
4104         for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
4105             struct vertex vtx;
4106 
4107             if (vertices[vtx_idx1].normal.z != 1.0f)
4108                 break;
4109 
4110             vtx.position.z = 0.0f;
4111             vtx.normal.x = 0.0f;
4112             vtx.normal.y = 0.0f;
4113             vtx.normal.z = 1.0f;
4114             ok(compare(vertices[vtx_idx1].position.z, vtx.position.z),
4115                "Test %s, glyph %d, vertex position.z %d, result %g, expected %g\n", name, i, vtx_idx1,
4116                vertices[vtx_idx1].position.z, vtx.position.z);
4117             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
4118                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4119                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4120                vtx.normal.x, vtx.normal.y, vtx.normal.z);
4121         }
4122         nb_back_vertices = vtx_idx1 - first_vtx1;
4123         first_face1 = face_idx1;
4124         for (; face_idx1 < number_of_faces; face_idx1++)
4125         {
4126             const D3DXVECTOR3 *vtx1, *vtx2, *vtx3;
4127             D3DXVECTOR3 normal;
4128             D3DXVECTOR3 v1 = {0, 0, 0};
4129             D3DXVECTOR3 v2 = {0, 0, 0};
4130             D3DXVECTOR3 forward = {0.0f, 0.0f, 1.0f};
4131 
4132             if (faces[face_idx1][0] >= vtx_idx1 ||
4133                 faces[face_idx1][1] >= vtx_idx1 ||
4134                 faces[face_idx1][2] >= vtx_idx1)
4135                 break;
4136 
4137             vtx1 = &vertices[faces[face_idx1][0]].position;
4138             vtx2 = &vertices[faces[face_idx1][1]].position;
4139             vtx3 = &vertices[faces[face_idx1][2]].position;
4140 
4141             D3DXVec3Subtract(&v1, vtx2, vtx1);
4142             D3DXVec3Subtract(&v2, vtx3, vtx2);
4143             D3DXVec3Cross(&normal, &v1, &v2);
4144             D3DXVec3Normalize(&normal, &normal);
4145             ok(!D3DXVec3Length(&normal) || compare_vec3(normal, forward),
4146                "Test %s, glyph %d, face %d normal, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, face_idx1,
4147                normal.x, normal.y, normal.z, forward.x, forward.y, forward.z);
4148         }
4149         nb_back_faces = face_idx1 - first_face1;
4150 
4151         /* compare front and back faces & vertices */
4152         if (extrusion == 0.0f) {
4153             /* Oddly there are only back faces in this case */
4154             nb_back_vertices /= 2;
4155             nb_back_faces /= 2;
4156             face_idx1 -= nb_back_faces;
4157             vtx_idx1 -= nb_back_vertices;
4158         }
4159         for (j = 0; j < nb_back_vertices; j++)
4160         {
4161             struct vertex vtx = vertices[first_vtx1];
4162             vtx.position.z = -extrusion;
4163             vtx.normal.x = 0.0f;
4164             vtx.normal.y = 0.0f;
4165             vtx.normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
4166             ok(compare_vec3(vertices[vtx_idx1].position, vtx.position),
4167                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4168                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
4169                vtx.position.x, vtx.position.y, vtx.position.z);
4170             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
4171                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4172                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4173                vtx.normal.x, vtx.normal.y, vtx.normal.z);
4174             vtx_idx1++;
4175             first_vtx1++;
4176         }
4177         for (j = 0; j < nb_back_faces; j++)
4178         {
4179             int f1, f2;
4180             if (extrusion == 0.0f) {
4181                 f1 = 1;
4182                 f2 = 2;
4183             } else {
4184                 f1 = 2;
4185                 f2 = 1;
4186             }
4187             ok(faces[face_idx1][0] == faces[first_face1][0] + nb_back_vertices &&
4188                faces[face_idx1][1] == faces[first_face1][f1] + nb_back_vertices &&
4189                faces[face_idx1][2] == faces[first_face1][f2] + nb_back_vertices,
4190                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
4191                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
4192                faces[first_face1][0] - nb_back_faces,
4193                faces[first_face1][f1] - nb_back_faces,
4194                faces[first_face1][f2] - nb_back_faces);
4195             first_face1++;
4196             face_idx1++;
4197         }
4198 
4199         /* skip to the outline for the next glyph */
4200         for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
4201             if (mesh->vertices[vtx_idx2].normal.z == 0)
4202                 break;
4203         }
4204         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
4205         {
4206             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
4207                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
4208                 mesh->faces[face_idx2][2] >= vtx_idx2) break;
4209         }
4210     }
4211 
4212     IDirect3DIndexBuffer9_Unlock(index_buffer);
4213     IDirect3DVertexBuffer9_Unlock(vertex_buffer);
4214     IDirect3DIndexBuffer9_Release(index_buffer);
4215     IDirect3DVertexBuffer9_Release(vertex_buffer);
4216 }
4217 
4218 static void test_createtext(IDirect3DDevice9 *device, HDC hdc, const char *text, float deviation, float extrusion)
4219 {
4220     static const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
4221     HRESULT hr;
4222     ID3DXMesh *d3dxmesh = NULL;
4223     struct mesh mesh = {0};
4224     char name[256];
4225     OUTLINETEXTMETRICA otm;
4226     GLYPHMETRICS gm;
4227     struct glyphinfo *glyphs;
4228     GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
4229     int i;
4230     LOGFONTA lf;
4231     float offset_x;
4232     size_t textlen;
4233     HFONT font = NULL, oldfont = NULL;
4234     char *raw_outline;
4235 
4236     sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion);
4237 
4238     hr = D3DXCreateTextA(device, hdc, text, deviation, extrusion, &d3dxmesh, NULL, glyphmetrics_float);
4239     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
4240 
4241     /* must select a modified font having lfHeight = otm.otmEMSquare before
4242      * calling GetGlyphOutline to get the expected values */
4243     ok(GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf), "Failed to get current DC font.\n");
4244     ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "Failed to get DC font outline.\n");
4245     lf.lfHeight = otm.otmEMSquare;
4246     lf.lfWidth = 0;
4247     ok(!!(font = CreateFontIndirectA(&lf)), "Failed to create font.\n");
4248 
4249     textlen = strlen(text);
4250     glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
4251     oldfont = SelectObject(hdc, font);
4252 
4253     for (i = 0; i < textlen; i++)
4254     {
4255         GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
4256         compare_float(glyphmetrics_float[i].gmfBlackBoxX, gm.gmBlackBoxX / (float)otm.otmEMSquare);
4257         compare_float(glyphmetrics_float[i].gmfBlackBoxY, gm.gmBlackBoxY / (float)otm.otmEMSquare);
4258         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.x, gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare);
4259         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.y, gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare);
4260         compare_float(glyphmetrics_float[i].gmfCellIncX, gm.gmCellIncX / (float)otm.otmEMSquare);
4261         compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
4262     }
4263 
4264     if (deviation == 0.0f)
4265         deviation = 1.0f / otm.otmEMSquare;
4266 
4267     offset_x = 0.0f;
4268     for (i = 0; i < textlen; i++)
4269     {
4270         DWORD datasize;
4271 
4272         glyphs[i].offset_x = offset_x;
4273 
4274         datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
4275         ok(datasize != GDI_ERROR, "Failed to retrieve GDI glyph outline size.\n");
4276         raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
4277         datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
4278         ok(datasize != GDI_ERROR, "Failed to retrieve GDI glyph outline.\n");
4279         create_outline(&glyphs[i], raw_outline, datasize, deviation, otm.otmEMSquare);
4280         HeapFree(GetProcessHeap(), 0, raw_outline);
4281 
4282         offset_x += gm.gmCellIncX / (float)otm.otmEMSquare;
4283     }
4284 
4285     SelectObject(hdc, oldfont);
4286 
4287     compute_text_mesh(&mesh, text, deviation, extrusion, otm.otmEMSquare, glyphs);
4288     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
4289 
4290     compare_text_outline_mesh(name, d3dxmesh, &mesh, textlen, extrusion, glyphs);
4291 
4292     free_mesh(&mesh);
4293     d3dxmesh->lpVtbl->Release(d3dxmesh);
4294     DeleteObject(font);
4295     HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
4296 
4297     for (i = 0; i < textlen; i++)
4298         free_glyphinfo(&glyphs[i]);
4299     HeapFree(GetProcessHeap(), 0, glyphs);
4300 }
4301 
4302 static void D3DXCreateTextTest(void)
4303 {
4304     HRESULT hr;
4305     HDC hdc;
4306     IDirect3DDevice9* device;
4307     ID3DXMesh* d3dxmesh = NULL;
4308     HFONT hFont;
4309     OUTLINETEXTMETRICA otm;
4310     int number_of_vertices;
4311     int number_of_faces;
4312     struct test_context *test_context;
4313 
4314     if (!(test_context = new_test_context()))
4315     {
4316         skip("Couldn't create test context\n");
4317         return;
4318     }
4319     device = test_context->device;
4320 
4321     hdc = CreateCompatibleDC(NULL);
4322 
4323     hFont = CreateFontA(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
4324             CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
4325     SelectObject(hdc, hFont);
4326     GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
4327 
4328     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, 0.4f, NULL, NULL, NULL);
4329     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4330 
4331     /* D3DXCreateTextA page faults from passing NULL text */
4332 
4333     hr = D3DXCreateTextW(device, hdc, NULL, 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(device, hdc, " ", 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(NULL, hdc, "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, NULL, "wine", 0.001f, 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", -FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4349     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4350 
4351     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, -FLT_MIN, &d3dxmesh, NULL, NULL);
4352     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4353 
4354     /* deviation = 0.0f treated as if deviation = 1.0f / otm.otmEMSquare */
4355     hr = D3DXCreateTextA(device, hdc, "wine", 1.0f / otm.otmEMSquare, 0.4f, &d3dxmesh, NULL, NULL);
4356     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4357     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
4358     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
4359     d3dxmesh->lpVtbl->Release(d3dxmesh);
4360 
4361     hr = D3DXCreateTextA(device, hdc, "wine", 0.0f, 0.4f, &d3dxmesh, NULL, NULL);
4362     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4363     ok(number_of_vertices == d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh),
4364        "Got %d vertices, expected %d\n",
4365        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_vertices);
4366     ok(number_of_faces == d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh),
4367        "Got %d faces, expected %d\n",
4368        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_faces);
4369     d3dxmesh->lpVtbl->Release(d3dxmesh);
4370 
4371 if (0)
4372 {
4373     /* too much detail requested, so will appear to hang */
4374     trace("Waiting for D3DXCreateText to finish with deviation = FLT_MIN ...\n");
4375     hr = D3DXCreateTextA(device, hdc, "wine", FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4376     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4377     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4378     trace("D3DXCreateText finish with deviation = FLT_MIN\n");
4379 }
4380 
4381     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4382     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4383     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4384 
4385     test_createtext(device, hdc, "wine", FLT_MAX, 0.4f);
4386     test_createtext(device, hdc, "wine", 0.001f, FLT_MIN);
4387     test_createtext(device, hdc, "wine", 0.001f, 0.0f);
4388     test_createtext(device, hdc, "wine", 0.001f, FLT_MAX);
4389     test_createtext(device, hdc, "wine", 0.0f, 1.0f);
4390     test_createtext(device, hdc, " wine", 1.0f, 0.0f);
4391     test_createtext(device, hdc, "wine ", 1.0f, 0.0f);
4392     test_createtext(device, hdc, "wi ne", 1.0f, 0.0f);
4393 
4394     DeleteDC(hdc);
4395     DeleteObject(hFont);
4396 
4397     free_test_context(test_context);
4398 }
4399 
4400 static void test_get_decl_length(void)
4401 {
4402     static const D3DVERTEXELEMENT9 declaration1[] =
4403     {
4404         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4405         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4406         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4407         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4408         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4409         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4410         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4411         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4412         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4413         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4414         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4415         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4416         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4417         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4418         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4419         D3DDECL_END(),
4420     };
4421     static const D3DVERTEXELEMENT9 declaration2[] =
4422     {
4423         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4424         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4425         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4426         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4427         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4428         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4429         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4430         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4431         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4432         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4433         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4434         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4435         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4436         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4437         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4438         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4439         D3DDECL_END(),
4440     };
4441     UINT size;
4442 
4443     size = D3DXGetDeclLength(declaration1);
4444     ok(size == 15, "Got size %u, expected 15.\n", size);
4445 
4446     size = D3DXGetDeclLength(declaration2);
4447     ok(size == 16, "Got size %u, expected 16.\n", size);
4448 }
4449 
4450 static void test_get_decl_vertex_size(void)
4451 {
4452     static const D3DVERTEXELEMENT9 declaration1[] =
4453     {
4454         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4455         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4456         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4457         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4458         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4459         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4460         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4461         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4462         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4463         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4464         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4465         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4466         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4467         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4468         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4469         D3DDECL_END(),
4470     };
4471     static const D3DVERTEXELEMENT9 declaration2[] =
4472     {
4473         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4474         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4475         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4476         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4477         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4478         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4479         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4480         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4481         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4482         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4483         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4484         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4485         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4486         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4487         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4488         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4489         D3DDECL_END(),
4490     };
4491     static const UINT sizes1[] =
4492     {
4493         4,  8,  12, 16,
4494         4,  4,  4,  8,
4495         4,  4,  8,  4,
4496         4,  4,  8,  0,
4497     };
4498     static const UINT sizes2[] =
4499     {
4500         12, 16, 20, 24,
4501         12, 12, 16, 16,
4502     };
4503     unsigned int i;
4504     UINT size;
4505 
4506     size = D3DXGetDeclVertexSize(NULL, 0);
4507     ok(size == 0, "Got size %#x, expected 0.\n", size);
4508 
4509     for (i = 0; i < 16; ++i)
4510     {
4511         size = D3DXGetDeclVertexSize(declaration1, i);
4512         ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
4513     }
4514 
4515     for (i = 0; i < 8; ++i)
4516     {
4517         size = D3DXGetDeclVertexSize(declaration2, i);
4518         ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
4519     }
4520 }
4521 
4522 static void D3DXGenerateAdjacencyTest(void)
4523 {
4524     HRESULT hr;
4525     IDirect3DDevice9 *device;
4526     ID3DXMesh *d3dxmesh = NULL;
4527     D3DXVECTOR3 *vertices = NULL;
4528     WORD *indices = NULL;
4529     int i;
4530     struct {
4531         DWORD num_vertices;
4532         D3DXVECTOR3 vertices[6];
4533         DWORD num_faces;
4534         WORD indices[3 * 3];
4535         FLOAT epsilon;
4536         DWORD adjacency[3 * 3];
4537     } test_data[] = {
4538         { /* for epsilon < 0, indices must match for faces to be adjacent */
4539             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}},
4540             2, {0, 1, 2,  0, 2, 3},
4541             -1.0,
4542             {-1, -1, 1,  0, -1, -1},
4543         },
4544         {
4545             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}},
4546             2, {0, 1, 2,  3, 4, 5},
4547             -1.0,
4548             {-1, -1, -1,  -1, -1, -1},
4549         },
4550         { /* for epsilon == 0, indices or vertices must match for faces to be adjacent */
4551             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}},
4552             2, {0, 1, 2,  3, 4, 5},
4553             0.0,
4554             {-1, -1, 1,  0, -1, -1},
4555         },
4556         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4557             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}},
4558             2, {0, 1, 2,  3, 4, 5},
4559             0.25,
4560             {-1, -1, -1,  -1, -1, -1},
4561         },
4562         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4563             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}},
4564             2, {0, 1, 2,  3, 4, 5},
4565             0.250001,
4566             {-1, -1, 1,  0, -1, -1},
4567         },
4568         { /* length between vertices are compared to epsilon, not the individual dimension deltas */
4569             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}},
4570             2, {0, 1, 2,  3, 4, 5},
4571             0.353, /* < sqrt(0.25*0.25 + 0.25*0.25) */
4572             {-1, -1, -1,  -1, -1, -1},
4573         },
4574         {
4575             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}},
4576             2, {0, 1, 2,  3, 4, 5},
4577             0.354, /* > sqrt(0.25*0.25 + 0.25*0.25) */
4578             {-1, -1, 1,  0, -1, -1},
4579         },
4580         { /* adjacent faces must have opposite winding orders at the shared edge */
4581             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}},
4582             2, {0, 1, 2,  0, 3, 2},
4583             0.0,
4584             {-1, -1, -1,  -1, -1, -1},
4585         },
4586     };
4587     struct test_context *test_context;
4588 
4589     if (!(test_context = new_test_context()))
4590     {
4591         skip("Couldn't create test context\n");
4592         return;
4593     }
4594     device = test_context->device;
4595 
4596     for (i = 0; i < ARRAY_SIZE(test_data); i++)
4597     {
4598         DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
4599         int j;
4600 
4601         if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4602         d3dxmesh = NULL;
4603 
4604         hr = D3DXCreateMeshFVF(test_data[i].num_faces, test_data[i].num_vertices, 0, D3DFVF_XYZ, device, &d3dxmesh);
4605         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4606 
4607         hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&vertices);
4608         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4609         if (FAILED(hr)) continue;
4610         CopyMemory(vertices, test_data[i].vertices, test_data[i].num_vertices * sizeof(test_data[0].vertices[0]));
4611         d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
4612 
4613         hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&indices);
4614         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4615         if (FAILED(hr)) continue;
4616         CopyMemory(indices, test_data[i].indices, test_data[i].num_faces * 3 * sizeof(test_data[0].indices[0]));
4617         d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
4618 
4619         if (i == 0) {
4620             hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, NULL);
4621             ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4622         }
4623 
4624         hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, test_data[i].epsilon, adjacency);
4625         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4626         if (FAILED(hr)) continue;
4627 
4628         for (j = 0; j < test_data[i].num_faces * 3; j++)
4629             ok(adjacency[j] == test_data[i].adjacency[j],
4630                "Test %d adjacency %d: Got result %u, expected %u\n", i, j,
4631                adjacency[j], test_data[i].adjacency[j]);
4632     }
4633     if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4634 
4635     free_test_context(test_context);
4636 }
4637 
4638 static void test_update_semantics(void)
4639 {
4640     HRESULT hr;
4641     struct test_context *test_context = NULL;
4642     ID3DXMesh *mesh = NULL;
4643     D3DVERTEXELEMENT9 declaration0[] =
4644     {
4645          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4646          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4647          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4648          D3DDECL_END()
4649     };
4650     D3DVERTEXELEMENT9 declaration_pos_type_color[] =
4651     {
4652          {0, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4653          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4654          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4655          D3DDECL_END()
4656     };
4657     D3DVERTEXELEMENT9 declaration_smaller[] =
4658     {
4659          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4660          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4661          D3DDECL_END()
4662     };
4663     D3DVERTEXELEMENT9 declaration_larger[] =
4664     {
4665          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4666          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4667          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4668          {0, 40, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4669          D3DDECL_END()
4670     };
4671     D3DVERTEXELEMENT9 declaration_multiple_streams[] =
4672     {
4673          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4674          {1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4675          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4676          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4677 
4678          D3DDECL_END()
4679     };
4680     D3DVERTEXELEMENT9 declaration_double_usage[] =
4681     {
4682          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4683          {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4684          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4685          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4686          D3DDECL_END()
4687     };
4688     D3DVERTEXELEMENT9 declaration_undefined_type[] =
4689     {
4690          {0, 0, D3DDECLTYPE_UNUSED+1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4691          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4692          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4693          D3DDECL_END()
4694     };
4695     D3DVERTEXELEMENT9 declaration_not_4_byte_aligned_offset[] =
4696     {
4697          {0, 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4698          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4699          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4700          D3DDECL_END()
4701     };
4702     static const struct
4703     {
4704         D3DXVECTOR3 position0;
4705         D3DXVECTOR3 position1;
4706         D3DXVECTOR3 normal;
4707         DWORD color;
4708     }
4709     vertices[] =
4710     {
4711         { { 0.0f,  1.0f,  0.f}, { 1.0f,  0.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xffff0000 },
4712         { { 1.0f, -1.0f,  0.f}, {-1.0f, -1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff00ff00 },
4713         { {-1.0f, -1.0f,  0.f}, {-1.0f,  1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff0000ff },
4714     };
4715     unsigned int faces[] = {0, 1, 2};
4716     unsigned int attributes[] = {0};
4717     unsigned int num_faces = ARRAY_SIZE(faces) / 3;
4718     unsigned int num_vertices = ARRAY_SIZE(vertices);
4719     int offset = sizeof(D3DXVECTOR3);
4720     DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4721     void *vertex_buffer;
4722     void *index_buffer;
4723     DWORD *attributes_buffer;
4724     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
4725     D3DVERTEXELEMENT9 *decl_ptr;
4726     DWORD exp_vertex_size = sizeof(*vertices);
4727     DWORD vertex_size = 0;
4728     int equal;
4729     int i = 0;
4730     int *decl_mem;
4731     int filler_a = 0xaaaaaaaa;
4732     int filler_b = 0xbbbbbbbb;
4733 
4734     test_context = new_test_context();
4735     if (!test_context)
4736     {
4737         skip("Couldn't create a test_context\n");
4738         goto cleanup;
4739     }
4740 
4741     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration0,
4742                         test_context->device, &mesh);
4743     if (FAILED(hr))
4744     {
4745         skip("Couldn't create test mesh %#x\n", hr);
4746         goto cleanup;
4747     }
4748 
4749     mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
4750     memcpy(vertex_buffer, vertices, sizeof(vertices));
4751     mesh->lpVtbl->UnlockVertexBuffer(mesh);
4752 
4753     mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
4754     memcpy(index_buffer, faces, sizeof(faces));
4755     mesh->lpVtbl->UnlockIndexBuffer(mesh);
4756 
4757     mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
4758     memcpy(attributes_buffer, attributes, sizeof(attributes));
4759     mesh->lpVtbl->UnlockAttributeBuffer(mesh);
4760 
4761     /* Get the declaration and try to change it */
4762     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4763     if (FAILED(hr))
4764     {
4765         skip("Couldn't get vertex declaration %#x\n", hr);
4766         goto cleanup;
4767     }
4768     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4769     ok(equal == 0, "Vertex declarations were not equal\n");
4770 
4771     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4772     {
4773         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4774         {
4775             /* Use second vertex position instead of first */
4776             decl_ptr->Offset = offset;
4777         }
4778     }
4779 
4780     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4781     ok(hr == D3D_OK, "Test UpdateSemantics, got %#x expected %#x\n", hr, D3D_OK);
4782 
4783     /* Check that declaration was written by getting it again */
4784     memset(declaration, 0, sizeof(declaration));
4785     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4786     if (FAILED(hr))
4787     {
4788         skip("Couldn't get vertex declaration %#x\n", hr);
4789         goto cleanup;
4790     }
4791 
4792     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4793     {
4794         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4795         {
4796             ok(decl_ptr->Offset == offset, "Test UpdateSemantics, got offset %d expected %d\n",
4797                decl_ptr->Offset, offset);
4798         }
4799     }
4800 
4801     /* Check that GetDeclaration only writes up to the D3DDECL_END() marker and
4802      * not the full MAX_FVF_DECL_SIZE elements.
4803      */
4804     memset(declaration, filler_a, sizeof(declaration));
4805     memcpy(declaration, declaration0, sizeof(declaration0));
4806     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4807     ok(hr == D3D_OK, "Test UpdateSemantics, "
4808        "got %#x expected D3D_OK\n", hr);
4809     memset(declaration, filler_b, sizeof(declaration));
4810     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4811     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4812     decl_mem = (int*)declaration;
4813     for (i = sizeof(declaration0)/sizeof(*decl_mem); i < sizeof(declaration)/sizeof(*decl_mem); i++)
4814     {
4815         equal = memcmp(&decl_mem[i], &filler_b, sizeof(filler_b));
4816         ok(equal == 0,
4817            "GetDeclaration wrote past the D3DDECL_END() marker. "
4818            "Got %#x, expected  %#x\n", decl_mem[i], filler_b);
4819         if (equal != 0) break;
4820     }
4821 
4822     /* UpdateSemantics does not check for overlapping fields */
4823     memset(declaration, 0, sizeof(declaration));
4824     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4825     if (FAILED(hr))
4826     {
4827         skip("Couldn't get vertex declaration %#x\n", hr);
4828         goto cleanup;
4829     }
4830 
4831     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4832     {
4833         if (decl_ptr->Type == D3DDECLTYPE_FLOAT3)
4834         {
4835             decl_ptr->Type = D3DDECLTYPE_FLOAT4;
4836         }
4837     }
4838 
4839     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4840     ok(hr == D3D_OK, "Test UpdateSemantics for overlapping fields, "
4841        "got %#x expected D3D_OK\n", hr);
4842 
4843     /* Set the position type to color instead of float3 */
4844     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_pos_type_color);
4845     ok(hr == D3D_OK, "Test UpdateSemantics position type color, "
4846        "got %#x expected D3D_OK\n", hr);
4847 
4848     /* The following test cases show that NULL, smaller or larger declarations,
4849      * and declarations with non-zero Stream values are not accepted.
4850      * UpdateSemantics returns D3DERR_INVALIDCALL and the previously set
4851      * declaration will be used by DrawSubset, GetNumBytesPerVertex, and
4852      * GetDeclaration.
4853      */
4854 
4855     /* Null declaration (invalid declaration) */
4856     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4857     hr = mesh->lpVtbl->UpdateSemantics(mesh, NULL);
4858     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics null pointer declaration, "
4859        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4860     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4861     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4862        vertex_size, exp_vertex_size);
4863     memset(declaration, 0, sizeof(declaration));
4864     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4865     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4866     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4867     ok(equal == 0, "Vertex declarations were not equal\n");
4868 
4869     /* Smaller vertex declaration (invalid declaration) */
4870     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4871     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_smaller);
4872     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics for smaller vertex declaration, "
4873        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4874     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4875     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4876        vertex_size, exp_vertex_size);
4877     memset(declaration, 0, sizeof(declaration));
4878     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4879     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4880     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4881     ok(equal == 0, "Vertex declarations were not equal\n");
4882 
4883     /* Larger vertex declaration (invalid declaration) */
4884     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4885     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_larger);
4886     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics for larger vertex declaration, "
4887        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4888     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4889     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4890        vertex_size, exp_vertex_size);
4891     memset(declaration, 0, sizeof(declaration));
4892     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4893     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4894     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4895     ok(equal == 0, "Vertex declarations were not equal\n");
4896 
4897     /* Use multiple streams and keep the same vertex size (invalid declaration) */
4898     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4899     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_multiple_streams);
4900     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics using multiple streams, "
4901                  "got %#x expected D3DERR_INVALIDCALL\n", hr);
4902     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4903     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4904        vertex_size, exp_vertex_size);
4905     memset(declaration, 0, sizeof(declaration));
4906     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4907     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4908     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4909     ok(equal == 0, "Vertex declarations were not equal\n");
4910 
4911     /* The next following test cases show that some invalid declarations are
4912      * accepted with a D3D_OK. An access violation is thrown on Windows if
4913      * DrawSubset is called. The methods GetNumBytesPerVertex and GetDeclaration
4914      * are not affected, which indicates that the declaration is cached.
4915      */
4916 
4917     /* Double usage (invalid declaration) */
4918     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4919     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_double_usage);
4920     ok(hr == D3D_OK, "Test UpdateSemantics double usage, "
4921        "got %#x expected D3D_OK\n", hr);
4922     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4923     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4924        vertex_size, exp_vertex_size);
4925     memset(declaration, 0, sizeof(declaration));
4926     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4927     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4928     equal = memcmp(declaration, declaration_double_usage, sizeof(declaration_double_usage));
4929     ok(equal == 0, "Vertex declarations were not equal\n");
4930 
4931     /* Set the position to an undefined type (invalid declaration) */
4932     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4933     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_undefined_type);
4934     ok(hr == D3D_OK, "Test UpdateSemantics undefined type, "
4935        "got %#x expected D3D_OK\n", hr);
4936     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4937     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4938        vertex_size, exp_vertex_size);
4939     memset(declaration, 0, sizeof(declaration));
4940     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4941     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4942     equal = memcmp(declaration, declaration_undefined_type, sizeof(declaration_undefined_type));
4943     ok(equal == 0, "Vertex declarations were not equal\n");
4944 
4945     /* Use a not 4 byte aligned offset (invalid declaration) */
4946     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4947     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_not_4_byte_aligned_offset);
4948     ok(hr == D3D_OK, "Test UpdateSemantics not 4 byte aligned offset, "
4949        "got %#x expected D3D_OK\n", hr);
4950     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4951     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4952        vertex_size, exp_vertex_size);
4953     memset(declaration, 0, sizeof(declaration));
4954     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4955     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4956     equal = memcmp(declaration, declaration_not_4_byte_aligned_offset,
4957                    sizeof(declaration_not_4_byte_aligned_offset));
4958     ok(equal == 0, "Vertex declarations were not equal\n");
4959 
4960 cleanup:
4961     if (mesh)
4962         mesh->lpVtbl->Release(mesh);
4963 
4964     free_test_context(test_context);
4965 }
4966 
4967 static void test_create_skin_info(void)
4968 {
4969     HRESULT hr;
4970     ID3DXSkinInfo *skininfo = NULL;
4971     D3DVERTEXELEMENT9 empty_declaration[] = { D3DDECL_END() };
4972     D3DVERTEXELEMENT9 declaration_out[MAX_FVF_DECL_SIZE];
4973     const D3DVERTEXELEMENT9 declaration_with_nonzero_stream[] = {
4974         {1, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
4975         D3DDECL_END()
4976     };
4977 
4978     hr = D3DXCreateSkinInfo(0, empty_declaration, 0, &skininfo);
4979     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4980     if (skininfo) IUnknown_Release(skininfo);
4981     skininfo = NULL;
4982 
4983     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
4984     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4985 
4986     hr = D3DXCreateSkinInfo(1, declaration_with_nonzero_stream, 1, &skininfo);
4987     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4988 
4989     hr = D3DXCreateSkinInfoFVF(1, 0, 1, &skininfo);
4990     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4991     if (skininfo)
4992     {
4993         DWORD dword_result;
4994         float flt_result;
4995         const char *string_result;
4996         D3DXMATRIX *transform;
4997         D3DXMATRIX identity_matrix;
4998 
4999         /* test initial values */
5000         hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5001         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5002         if (SUCCEEDED(hr))
5003             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
5004 
5005         dword_result = skininfo->lpVtbl->GetNumBones(skininfo);
5006         ok(dword_result == 1, "Expected 1, got %u\n", dword_result);
5007 
5008         flt_result = skininfo->lpVtbl->GetMinBoneInfluence(skininfo);
5009         ok(flt_result == 0.0f, "Expected 0.0, got %g\n", flt_result);
5010 
5011         string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5012         ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
5013 
5014         dword_result = skininfo->lpVtbl->GetFVF(skininfo);
5015         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5016 
5017         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 0);
5018         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5019 
5020         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 1);
5021         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5022 
5023         transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, -1);
5024         ok(transform == NULL, "Expected NULL, got %p\n", transform);
5025 
5026         {
5027             /* test [GS]etBoneOffsetMatrix */
5028             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 1, &identity_matrix);
5029             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5030 
5031             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, NULL);
5032             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5033 
5034             D3DXMatrixIdentity(&identity_matrix);
5035             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, &identity_matrix);
5036             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5037 
5038             transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, 0);
5039             check_matrix(transform, &identity_matrix);
5040         }
5041 
5042         {
5043             /* test [GS]etBoneName */
5044             const char *name_in = "testBoneName";
5045             const char *string_result2;
5046 
5047             hr = skininfo->lpVtbl->SetBoneName(skininfo, 1, name_in);
5048             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5049 
5050             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, NULL);
5051             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5052 
5053             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, name_in);
5054             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5055 
5056             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5057             ok(string_result != NULL, "Expected non-NULL string, got %p\n", string_result);
5058             ok(!strcmp(string_result, name_in), "Expected '%s', got '%s'\n", name_in, string_result);
5059 
5060             string_result2 = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5061             ok(string_result == string_result2, "Expected %p, got %p\n", string_result, string_result2);
5062 
5063             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 1);
5064             ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
5065         }
5066 
5067         {
5068             /* test [GS]etBoneInfluence */
5069             DWORD vertices[2];
5070             FLOAT weights[2];
5071             int i;
5072             DWORD num_influences;
5073             DWORD exp_vertices[2];
5074             FLOAT exp_weights[2];
5075 
5076             /* vertex and weight arrays untouched when num_influences is 0 */
5077             vertices[0] = 0xdeadbeef;
5078             weights[0] = FLT_MAX;
5079             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5080             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5081             ok(vertices[0] == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", vertices[0]);
5082             ok(weights[0] == FLT_MAX, "expected %g, got %g\n", FLT_MAX, weights[0]);
5083 
5084             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 1, vertices, weights);
5085             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5086 
5087             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, NULL);
5088             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5089 
5090             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, NULL);
5091             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5092 
5093             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, weights);
5094             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5095 
5096 
5097             /* no vertex or weight value checking */
5098             exp_vertices[0] = 0;
5099             exp_vertices[1] = 0x87654321;
5100             exp_weights[0] = 0.5;
5101             exp_weights[1] = NAN;
5102             num_influences = 2;
5103 
5104             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 1, num_influences, vertices, weights);
5105             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5106 
5107             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, weights);
5108             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5109 
5110             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, vertices, NULL);
5111             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5112 
5113             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, NULL);
5114             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5115 
5116             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, exp_vertices, exp_weights);
5117             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5118 
5119             memset(vertices, 0, sizeof(vertices));
5120             memset(weights, 0, sizeof(weights));
5121             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5122             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5123             for (i = 0; i < num_influences; i++) {
5124                 ok(exp_vertices[i] == vertices[i],
5125                    "influence[%d]: expected vertex %u, got %u\n", i, exp_vertices[i], vertices[i]);
5126                 ok((isnan(exp_weights[i]) && isnan(weights[i])) || exp_weights[i] == weights[i],
5127                    "influence[%d]: expected weights %g, got %g\n", i, exp_weights[i], weights[i]);
5128             }
5129 
5130             /* vertices and weights aren't returned after setting num_influences to 0 */
5131             memset(vertices, 0, sizeof(vertices));
5132             memset(weights, 0, sizeof(weights));
5133             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, 0, vertices, weights);
5134             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5135 
5136             vertices[0] = 0xdeadbeef;
5137             weights[0] = FLT_MAX;
5138             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5139             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5140             ok(vertices[0] == 0xdeadbeef, "expected vertex 0xdeadbeef, got %u\n", vertices[0]);
5141             ok(weights[0] == FLT_MAX, "expected weight %g, got %g\n", FLT_MAX, weights[0]);
5142         }
5143 
5144         {
5145             /* test [GS]etFVF and [GS]etDeclaration */
5146             D3DVERTEXELEMENT9 declaration_in[MAX_FVF_DECL_SIZE];
5147             DWORD fvf = D3DFVF_XYZ;
5148             DWORD got_fvf;
5149 
5150             hr = skininfo->lpVtbl->SetDeclaration(skininfo, NULL);
5151             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5152 
5153             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_with_nonzero_stream);
5154             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5155 
5156             hr = skininfo->lpVtbl->SetFVF(skininfo, 0);
5157             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5158 
5159             hr = D3DXDeclaratorFromFVF(fvf, declaration_in);
5160             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5161             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_in);
5162             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5163             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5164             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
5165             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5166             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5167             compare_elements(declaration_out, declaration_in, __LINE__, 0);
5168 
5169             hr = skininfo->lpVtbl->SetDeclaration(skininfo, empty_declaration);
5170             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5171             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5172             ok(got_fvf == 0, "Expected 0, got %#x\n", got_fvf);
5173             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5174             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5175             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
5176 
5177             hr = skininfo->lpVtbl->SetFVF(skininfo, fvf);
5178             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5179             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5180             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
5181             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5182             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5183             compare_elements(declaration_out, declaration_in, __LINE__, 0);
5184         }
5185     }
5186     if (skininfo) IUnknown_Release(skininfo);
5187     skininfo = NULL;
5188 
5189     hr = D3DXCreateSkinInfoFVF(1, D3DFVF_XYZ, 1, NULL);
5190     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5191 
5192     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
5193     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5194 }
5195 
5196 static void test_convert_adjacency_to_point_reps(void)
5197 {
5198     HRESULT hr;
5199     struct test_context *test_context = NULL;
5200     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5201     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5202     const D3DVERTEXELEMENT9 declaration[] =
5203     {
5204         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5205         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5206         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5207         D3DDECL_END()
5208     };
5209     const unsigned int VERTS_PER_FACE = 3;
5210     void *vertex_buffer;
5211     void *index_buffer;
5212     DWORD *attributes_buffer;
5213     int i, j;
5214     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5215     struct vertex_pnc
5216     {
5217         D3DXVECTOR3 position;
5218         D3DXVECTOR3 normal;
5219         enum color color; /* In case of manual visual inspection */
5220     };
5221 #ifndef __REACTOS__
5222     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5223 #else
5224 #define up {0.0f, 0.0f, 1.0f}
5225 #endif
5226     /* mesh0 (one face)
5227      *
5228      * 0--1
5229      * | /
5230      * |/
5231      * 2
5232      */
5233     const struct vertex_pnc vertices0[] =
5234     {
5235         {{ 0.0f,  3.0f,  0.f}, up, RED},
5236         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5237         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5238     };
5239     const DWORD indices0[] = {0, 1, 2};
5240     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5241     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
5242     const DWORD adjacency0[] = {-1, -1, -1};
5243     const DWORD exp_point_rep0[] = {0, 1, 2};
5244     /* mesh1 (right)
5245      *
5246      * 0--1 3
5247      * | / /|
5248      * |/ / |
5249      * 2 5--4
5250      */
5251     const struct vertex_pnc vertices1[] =
5252     {
5253         {{ 0.0f,  3.0f,  0.f}, up, RED},
5254         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5255         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5256 
5257         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5258         {{ 3.0f,  0.0f,  0.f}, up, RED},
5259         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5260     };
5261     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5262     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5263     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
5264     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
5265     const DWORD exp_point_rep1[] = {0, 1, 2, 1, 4, 2};
5266     /* mesh2 (left)
5267      *
5268      *    3 0--1
5269      *   /| | /
5270      *  / | |/
5271      * 5--4 2
5272      */
5273     const struct vertex_pnc vertices2[] =
5274     {
5275         {{ 0.0f,  3.0f,  0.f}, up, RED},
5276         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5277         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5278 
5279         {{-1.0f,  3.0f,  0.f}, up, RED},
5280         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5281         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5282     };
5283     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5284     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5285     const unsigned int num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
5286     const DWORD adjacency2[] = {-1, -1, 1, 0, -1, -1};
5287     const DWORD exp_point_rep2[] = {0, 1, 2, 0, 2, 5};
5288     /* mesh3 (above)
5289      *
5290      *    3
5291      *   /|
5292      *  / |
5293      * 5--4
5294      * 0--1
5295      * | /
5296      * |/
5297      * 2
5298      */
5299     struct vertex_pnc vertices3[] =
5300     {
5301         {{ 0.0f,  3.0f,  0.f}, up, RED},
5302         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5303         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5304 
5305         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5306         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5307         {{ 0.0f,  4.0f,  0.f}, up, RED},
5308     };
5309     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5310     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5311     const unsigned int num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
5312     const DWORD adjacency3[] = {1, -1, -1, -1, 0, -1};
5313     const DWORD exp_point_rep3[] = {0, 1, 2, 3, 1, 0};
5314     /* mesh4 (below, tip against tip)
5315      *
5316      * 0--1
5317      * | /
5318      * |/
5319      * 2
5320      * 3
5321      * |\
5322      * | \
5323      * 5--4
5324      */
5325     struct vertex_pnc vertices4[] =
5326     {
5327         {{ 0.0f,  3.0f,  0.f}, up, RED},
5328         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5329         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5330 
5331         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5332         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5333         {{ 0.0f, -7.0f,  0.f}, up, RED},
5334     };
5335     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5336     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5337     const unsigned int num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
5338     const DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
5339     const DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
5340     /* mesh5 (gap in mesh)
5341      *
5342      *    0      3-----4  15
5343      *   / \      \   /  /  \
5344      *  /   \      \ /  /    \
5345      * 2-----1      5 17-----16
5346      * 6-----7      9 12-----13
5347      *  \   /      / \  \    /
5348      *   \ /      /   \  \  /
5349      *    8     10-----11 14
5350      *
5351      */
5352     const struct vertex_pnc vertices5[] =
5353     {
5354         {{ 0.0f,  1.0f,  0.f}, up, RED},
5355         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5356         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5357 
5358         {{ 0.1f,  1.0f,  0.f}, up, RED},
5359         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5360         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5361 
5362         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5363         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5364         {{ 0.0f, -3.1f,  0.f}, up, RED},
5365 
5366         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5367         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5368         {{ 0.1f, -3.1f,  0.f}, up, RED},
5369 
5370         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5371         {{ 3.2f, -1.1f,  0.f}, up, RED},
5372         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5373 
5374         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5375         {{ 3.2f, -1.0f,  0.f}, up, RED},
5376         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5377     };
5378     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5379     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5380     const unsigned int num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
5381     const DWORD adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5382     const DWORD exp_point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5383     const WORD indices5_16bit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5384     /* mesh6 (indices re-ordering)
5385      *
5386      * 0--1 6 3
5387      * | / /| |\
5388      * |/ / | | \
5389      * 2 8--7 5--4
5390      */
5391     const struct vertex_pnc vertices6[] =
5392     {
5393         {{ 0.0f,  3.0f,  0.f}, up, RED},
5394         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5395         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5396 
5397         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5398         {{ 3.0f,  0.0f,  0.f}, up, RED},
5399         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5400 
5401         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5402         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5403         {{ 4.0f,  0.0f,  0.f}, up, RED},
5404     };
5405     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5406     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5407     const unsigned int num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
5408     const DWORD adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5409     const DWORD exp_point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5410     /* mesh7 (expands collapsed triangle)
5411      *
5412      * 0--1 3
5413      * | / /|
5414      * |/ / |
5415      * 2 5--4
5416      */
5417     const struct vertex_pnc vertices7[] =
5418     {
5419         {{ 0.0f,  3.0f,  0.f}, up, RED},
5420         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5421         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5422 
5423         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5424         {{ 3.0f,  0.0f,  0.f}, up, RED},
5425         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5426     };
5427     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5428     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5429     const unsigned int num_faces7 = ARRAY_SIZE(indices7) / VERTS_PER_FACE;
5430     const DWORD adjacency7[] = {-1, -1, -1, -1, -1, -1};
5431     const DWORD exp_point_rep7[] = {0, 1, 2, 3, 4, 5};
5432     /* mesh8 (indices re-ordering and double replacement)
5433      *
5434      * 0--1 9  6
5435      * | / /|  |\
5436      * |/ / |  | \
5437      * 2 11-10 8--7
5438      *         3--4
5439      *         | /
5440      *         |/
5441      *         5
5442      */
5443     const struct vertex_pnc vertices8[] =
5444     {
5445         {{ 0.0f,  3.0f,  0.f}, up, RED},
5446         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5447         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5448 
5449         {{ 4.0,  -4.0,  0.f}, up, RED},
5450         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5451         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5452 
5453         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5454         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5455         {{ 4.0f,  0.0f,  0.f}, up, RED},
5456 
5457         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5458         {{ 3.0f,  0.0f,  0.f}, up, RED},
5459         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5460     };
5461     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5462     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5463     const unsigned int num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
5464     const DWORD adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5465     const DWORD exp_point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5466     /* mesh9 (right, shared vertices)
5467      *
5468      * 0--1
5469      * | /|
5470      * |/ |
5471      * 2--3
5472      */
5473     const struct vertex_pnc vertices9[] =
5474     {
5475         {{ 0.0f,  3.0f,  0.f}, up, RED},
5476         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5477         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5478 
5479         {{ 2.0f,  0.0f,  0.f}, up, RED},
5480     };
5481     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5482     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5483     const unsigned int num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
5484     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
5485     const DWORD exp_point_rep9[] = {0, 1, 2, 3};
5486     /* All mesh data */
5487     ID3DXMesh *mesh = NULL;
5488     ID3DXMesh *mesh_null_check = NULL;
5489     unsigned int attributes[] = {0};
5490     struct
5491     {
5492         const struct vertex_pnc *vertices;
5493         const DWORD *indices;
5494         const DWORD num_vertices;
5495         const DWORD num_faces;
5496         const DWORD *adjacency;
5497         const DWORD *exp_point_reps;
5498         const DWORD options;
5499     }
5500     tc[] =
5501     {
5502         {
5503             vertices0,
5504             indices0,
5505             num_vertices0,
5506             num_faces0,
5507             adjacency0,
5508             exp_point_rep0,
5509             options
5510         },
5511         {
5512             vertices1,
5513             indices1,
5514             num_vertices1,
5515             num_faces1,
5516             adjacency1,
5517             exp_point_rep1,
5518             options
5519         },
5520         {
5521             vertices2,
5522             indices2,
5523             num_vertices2,
5524             num_faces2,
5525             adjacency2,
5526             exp_point_rep2,
5527             options
5528         },
5529         {
5530             vertices3,
5531             indices3,
5532             num_vertices3,
5533             num_faces3,
5534             adjacency3,
5535             exp_point_rep3,
5536             options
5537         },
5538         {
5539             vertices4,
5540             indices4,
5541             num_vertices4,
5542             num_faces4,
5543             adjacency4,
5544             exp_point_rep4,
5545             options
5546         },
5547         {
5548             vertices5,
5549             indices5,
5550             num_vertices5,
5551             num_faces5,
5552             adjacency5,
5553             exp_point_rep5,
5554             options
5555         },
5556         {
5557             vertices6,
5558             indices6,
5559             num_vertices6,
5560             num_faces6,
5561             adjacency6,
5562             exp_point_rep6,
5563             options
5564         },
5565         {
5566             vertices7,
5567             indices7,
5568             num_vertices7,
5569             num_faces7,
5570             adjacency7,
5571             exp_point_rep7,
5572             options
5573         },
5574         {
5575             vertices8,
5576             indices8,
5577             num_vertices8,
5578             num_faces8,
5579             adjacency8,
5580             exp_point_rep8,
5581             options
5582         },
5583         {
5584             vertices9,
5585             indices9,
5586             num_vertices9,
5587             num_faces9,
5588             adjacency9,
5589             exp_point_rep9,
5590             options
5591         },
5592         {
5593             vertices5,
5594             (DWORD*)indices5_16bit,
5595             num_vertices5,
5596             num_faces5,
5597             adjacency5,
5598             exp_point_rep5,
5599             options_16bit
5600         },
5601     };
5602     DWORD *point_reps = NULL;
5603 
5604     test_context = new_test_context();
5605     if (!test_context)
5606     {
5607         skip("Couldn't create test context\n");
5608         goto cleanup;
5609     }
5610 
5611     for (i = 0; i < ARRAY_SIZE(tc); i++)
5612     {
5613         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options, declaration,
5614                             test_context->device, &mesh);
5615         if (FAILED(hr))
5616         {
5617             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5618             goto cleanup;
5619         }
5620 
5621         if (i == 0) /* Save first mesh for later NULL checks */
5622             mesh_null_check = mesh;
5623 
5624         point_reps = HeapAlloc(GetProcessHeap(), 0, tc[i].num_vertices * sizeof(*point_reps));
5625         if (!point_reps)
5626         {
5627             skip("Couldn't allocate point reps array.\n");
5628             goto cleanup;
5629         }
5630 
5631         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5632         if (FAILED(hr))
5633         {
5634             skip("Couldn't lock vertex buffer.\n");
5635             goto cleanup;
5636         }
5637         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5638         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5639         if (FAILED(hr))
5640         {
5641             skip("Couldn't unlock vertex buffer.\n");
5642             goto cleanup;
5643         }
5644 
5645         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5646         if (FAILED(hr))
5647         {
5648             skip("Couldn't lock index buffer.\n");
5649             goto cleanup;
5650         }
5651         if (tc[i].options & D3DXMESH_32BIT)
5652         {
5653             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5654         }
5655         else
5656         {
5657             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5658         }
5659         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5660         if (FAILED(hr)) {
5661             skip("Couldn't unlock index buffer.\n");
5662             goto cleanup;
5663         }
5664 
5665         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5666         if (FAILED(hr))
5667         {
5668             skip("Couldn't lock attributes buffer.\n");
5669             goto cleanup;
5670         }
5671         memcpy(attributes_buffer, attributes, sizeof(attributes));
5672         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5673         if (FAILED(hr))
5674         {
5675             skip("Couldn't unlock attributes buffer.\n");
5676             goto cleanup;
5677         }
5678 
5679         /* Convert adjacency to point representation */
5680         for (j = 0; j < tc[i].num_vertices; j++) point_reps[j] = -1;
5681         hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacency, point_reps);
5682         ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
5683            "Got %x expected D3D_OK\n", i, hr);
5684 
5685         /* Check point representation */
5686         for (j = 0; j < tc[i].num_vertices; j++)
5687         {
5688             ok(point_reps[j] == tc[i].exp_point_reps[j],
5689                "Unexpected point representation at (%d, %d)."
5690                " Got %d expected %d\n",
5691                i, j, point_reps[j], tc[i].exp_point_reps[j]);
5692         }
5693 
5694         HeapFree(GetProcessHeap(), 0, point_reps);
5695         point_reps = NULL;
5696 
5697         if (i != 0) /* First mesh will be freed during cleanup */
5698             mesh->lpVtbl->Release(mesh);
5699     }
5700 
5701     /* NULL checks */
5702     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacency, NULL);
5703     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
5704        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5705     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, NULL);
5706     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. "
5707        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5708 
5709 cleanup:
5710     if (mesh_null_check)
5711         mesh_null_check->lpVtbl->Release(mesh_null_check);
5712     HeapFree(GetProcessHeap(), 0, point_reps);
5713     free_test_context(test_context);
5714 #ifdef __REACTOS__
5715 #undef up
5716 #endif
5717 }
5718 
5719 static void test_convert_point_reps_to_adjacency(void)
5720 {
5721     HRESULT hr;
5722     struct test_context *test_context = NULL;
5723     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5724     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5725     const D3DVERTEXELEMENT9 declaration[] =
5726     {
5727         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5728         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5729         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5730         D3DDECL_END()
5731     };
5732     const unsigned int VERTS_PER_FACE = 3;
5733     void *vertex_buffer;
5734     void *index_buffer;
5735     DWORD *attributes_buffer;
5736     int i, j;
5737     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5738     struct vertex_pnc
5739     {
5740         D3DXVECTOR3 position;
5741         D3DXVECTOR3 normal;
5742         enum color color; /* In case of manual visual inspection */
5743     };
5744 #ifndef __REACTOS__
5745     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5746 #else
5747 #define up {0.0f, 0.0f, 1.0f}
5748 #endif
5749 
5750     /* mesh0 (one face)
5751      *
5752      * 0--1
5753      * | /
5754      * |/
5755      * 2
5756      */
5757     const struct vertex_pnc vertices0[] =
5758     {
5759         {{ 0.0f,  3.0f,  0.f}, up, RED},
5760         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5761         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5762     };
5763     const DWORD indices0[] = {0, 1, 2};
5764     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5765     const unsigned int num_faces0 = num_vertices0 / VERTS_PER_FACE;
5766     const DWORD exp_adjacency0[] = {-1, -1, -1};
5767     const DWORD exp_id_adjacency0[] = {-1, -1, -1};
5768     const DWORD point_rep0[] = {0, 1, 2};
5769     /* mesh1 (right)
5770      *
5771      * 0--1 3
5772      * | / /|
5773      * |/ / |
5774      * 2 5--4
5775      */
5776     const struct vertex_pnc vertices1[] =
5777     {
5778         {{ 0.0f,  3.0f,  0.f}, up, RED},
5779         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5780         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5781 
5782         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5783         {{ 3.0f,  0.0f,  0.f}, up, RED},
5784         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5785     };
5786     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5787     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5788     const unsigned int num_faces1 = num_vertices1 / VERTS_PER_FACE;
5789     const DWORD exp_adjacency1[] = {-1, 1, -1, -1, -1, 0};
5790     const DWORD exp_id_adjacency1[] = {-1, -1, -1, -1, -1, -1};
5791     const DWORD point_rep1[] = {0, 1, 2, 1, 4, 2};
5792     /* mesh2 (left)
5793      *
5794      *    3 0--1
5795      *   /| | /
5796      *  / | |/
5797      * 5--4 2
5798      */
5799     const struct vertex_pnc vertices2[] =
5800     {
5801         {{ 0.0f,  3.0f,  0.f}, up, RED},
5802         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5803         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5804 
5805         {{-1.0f,  3.0f,  0.f}, up, RED},
5806         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5807         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5808     };
5809     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5810     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5811     const unsigned int num_faces2 = num_vertices2 / VERTS_PER_FACE;
5812     const DWORD exp_adjacency2[] = {-1, -1, 1, 0, -1, -1};
5813     const DWORD exp_id_adjacency2[] = {-1, -1, -1, -1, -1, -1};
5814     const DWORD point_rep2[] = {0, 1, 2, 0, 2, 5};
5815     /* mesh3 (above)
5816      *
5817      *    3
5818      *   /|
5819      *  / |
5820      * 5--4
5821      * 0--1
5822      * | /
5823      * |/
5824      * 2
5825      */
5826     struct vertex_pnc vertices3[] =
5827     {
5828         {{ 0.0f,  3.0f,  0.f}, up, RED},
5829         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5830         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5831 
5832         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5833         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5834         {{ 0.0f,  4.0f,  0.f}, up, RED},
5835     };
5836     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5837     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5838     const unsigned int num_faces3 = num_vertices3 / VERTS_PER_FACE;
5839     const DWORD exp_adjacency3[] = {1, -1, -1, -1, 0, -1};
5840     const DWORD exp_id_adjacency3[] = {-1, -1, -1, -1, -1, -1};
5841     const DWORD point_rep3[] = {0, 1, 2, 3, 1, 0};
5842     /* mesh4 (below, tip against tip)
5843      *
5844      * 0--1
5845      * | /
5846      * |/
5847      * 2
5848      * 3
5849      * |\
5850      * | \
5851      * 5--4
5852      */
5853     struct vertex_pnc vertices4[] =
5854     {
5855         {{ 0.0f,  3.0f,  0.f}, up, RED},
5856         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5857         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5858 
5859         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5860         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5861         {{ 0.0f, -7.0f,  0.f}, up, RED},
5862     };
5863     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5864     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5865     const unsigned int num_faces4 = num_vertices4 / VERTS_PER_FACE;
5866     const DWORD exp_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5867     const DWORD exp_id_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5868     const DWORD point_rep4[] = {0, 1, 2, 3, 4, 5};
5869     /* mesh5 (gap in mesh)
5870      *
5871      *    0      3-----4  15
5872      *   / \      \   /  /  \
5873      *  /   \      \ /  /    \
5874      * 2-----1      5 17-----16
5875      * 6-----7      9 12-----13
5876      *  \   /      / \  \    /
5877      *   \ /      /   \  \  /
5878      *    8     10-----11 14
5879      *
5880      */
5881     const struct vertex_pnc vertices5[] =
5882     {
5883         {{ 0.0f,  1.0f,  0.f}, up, RED},
5884         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5885         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5886 
5887         {{ 0.1f,  1.0f,  0.f}, up, RED},
5888         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5889         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5890 
5891         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5892         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5893         {{ 0.0f, -3.1f,  0.f}, up, RED},
5894 
5895         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5896         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5897         {{ 0.1f, -3.1f,  0.f}, up, RED},
5898 
5899         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5900         {{ 3.2f, -1.1f,  0.f}, up, RED},
5901         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5902 
5903         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5904         {{ 3.2f, -1.0f,  0.f}, up, RED},
5905         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5906     };
5907     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5908     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5909     const unsigned int num_faces5 = num_vertices5 / VERTS_PER_FACE;
5910     const DWORD exp_adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5911     const DWORD exp_id_adjacency5[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5912     const DWORD point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5913     /* mesh6 (indices re-ordering)
5914      *
5915      * 0--1 6 3
5916      * | / /| |\
5917      * |/ / | | \
5918      * 2 8--7 5--4
5919      */
5920     const struct vertex_pnc vertices6[] =
5921     {
5922         {{ 0.0f,  3.0f,  0.f}, up, RED},
5923         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5924         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5925 
5926         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5927         {{ 3.0f,  0.0f,  0.f}, up, RED},
5928         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5929 
5930         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5931         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5932         {{ 4.0f,  0.0f,  0.f}, up, RED},
5933     };
5934     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5935     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5936     const unsigned int num_faces6 = num_vertices6 / VERTS_PER_FACE;
5937     const DWORD exp_adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5938     const DWORD exp_id_adjacency6[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1};
5939     const DWORD point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5940     /* mesh7 (expands collapsed triangle)
5941      *
5942      * 0--1 3
5943      * | / /|
5944      * |/ / |
5945      * 2 5--4
5946      */
5947     const struct vertex_pnc vertices7[] =
5948     {
5949         {{ 0.0f,  3.0f,  0.f}, up, RED},
5950         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5951         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5952 
5953         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5954         {{ 3.0f,  0.0f,  0.f}, up, RED},
5955         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5956     };
5957     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5958     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5959     const unsigned int num_faces7 = num_vertices7 / VERTS_PER_FACE;
5960     const DWORD exp_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5961     const DWORD exp_id_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5962     const DWORD point_rep7[] = {0, 1, 2, 3, 4, 5};
5963     /* mesh8 (indices re-ordering and double replacement)
5964      *
5965      * 0--1 9  6
5966      * | / /|  |\
5967      * |/ / |  | \
5968      * 2 11-10 8--7
5969      *         3--4
5970      *         | /
5971      *         |/
5972      *         5
5973      */
5974     const struct vertex_pnc vertices8[] =
5975     {
5976         {{ 0.0f,  3.0f,  0.f}, up, RED},
5977         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5978         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5979 
5980         {{ 4.0,  -4.0,  0.f}, up, RED},
5981         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5982         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5983 
5984         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5985         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5986         {{ 4.0f,  0.0f,  0.f}, up, RED},
5987 
5988         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5989         {{ 3.0f,  0.0f,  0.f}, up, RED},
5990         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5991     };
5992     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5993     const WORD indices8_16bit[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5994     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5995     const unsigned int num_faces8 = num_vertices8 / VERTS_PER_FACE;
5996     const DWORD exp_adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5997     const DWORD exp_id_adjacency8[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5998     const DWORD point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5999      /* mesh9 (right, shared vertices)
6000      *
6001      * 0--1
6002      * | /|
6003      * |/ |
6004      * 2--3
6005      */
6006     const struct vertex_pnc vertices9[] =
6007     {
6008         {{ 0.0f,  3.0f,  0.f}, up, RED},
6009         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6010         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6011 
6012         {{ 2.0f,  0.0f,  0.f}, up, RED},
6013     };
6014     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
6015     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
6016     const unsigned int num_faces9 = 2;
6017     const DWORD exp_adjacency9[] = {-1, 1, -1, -1, -1, 0};
6018     const DWORD exp_id_adjacency9[] = {-1, 1, -1, -1, -1, 0};
6019     const DWORD point_rep9[] = {0, 1, 2, 3};
6020     /* All mesh data */
6021     ID3DXMesh *mesh = NULL;
6022     ID3DXMesh *mesh_null_check = NULL;
6023     unsigned int attributes[] = {0};
6024     struct
6025     {
6026         const struct vertex_pnc *vertices;
6027         const DWORD *indices;
6028         const DWORD num_vertices;
6029         const DWORD num_faces;
6030         const DWORD *point_reps;
6031         const DWORD *exp_adjacency;
6032         const DWORD *exp_id_adjacency;
6033         const DWORD options;
6034     }
6035     tc[] =
6036     {
6037         {
6038             vertices0,
6039             indices0,
6040             num_vertices0,
6041             num_faces0,
6042             point_rep0,
6043             exp_adjacency0,
6044             exp_id_adjacency0,
6045             options
6046         },
6047         {
6048             vertices1,
6049             indices1,
6050             num_vertices1,
6051             num_faces1,
6052             point_rep1,
6053             exp_adjacency1,
6054             exp_id_adjacency1,
6055             options
6056         },
6057         {
6058             vertices2,
6059             indices2,
6060             num_vertices2,
6061             num_faces2,
6062             point_rep2,
6063             exp_adjacency2,
6064             exp_id_adjacency2,
6065             options
6066         },
6067         {
6068             vertices3,
6069             indices3,
6070             num_vertices3,
6071             num_faces3,
6072             point_rep3,
6073             exp_adjacency3,
6074             exp_id_adjacency3,
6075             options
6076         },
6077         {
6078             vertices4,
6079             indices4,
6080             num_vertices4,
6081             num_faces4,
6082             point_rep4,
6083             exp_adjacency4,
6084             exp_id_adjacency4,
6085             options
6086         },
6087         {
6088             vertices5,
6089             indices5,
6090             num_vertices5,
6091             num_faces5,
6092             point_rep5,
6093             exp_adjacency5,
6094             exp_id_adjacency5,
6095             options
6096         },
6097         {
6098             vertices6,
6099             indices6,
6100             num_vertices6,
6101             num_faces6,
6102             point_rep6,
6103             exp_adjacency6,
6104             exp_id_adjacency6,
6105             options
6106         },
6107         {
6108             vertices7,
6109             indices7,
6110             num_vertices7,
6111             num_faces7,
6112             point_rep7,
6113             exp_adjacency7,
6114             exp_id_adjacency7,
6115             options
6116         },
6117         {
6118             vertices8,
6119             indices8,
6120             num_vertices8,
6121             num_faces8,
6122             point_rep8,
6123             exp_adjacency8,
6124             exp_id_adjacency8,
6125             options
6126         },
6127         {
6128             vertices9,
6129             indices9,
6130             num_vertices9,
6131             num_faces9,
6132             point_rep9,
6133             exp_adjacency9,
6134             exp_id_adjacency9,
6135             options
6136         },
6137         {
6138             vertices8,
6139             (DWORD*)indices8_16bit,
6140             num_vertices8,
6141             num_faces8,
6142             point_rep8,
6143             exp_adjacency8,
6144             exp_id_adjacency8,
6145             options_16bit
6146         },
6147     };
6148     DWORD *adjacency = NULL;
6149 #ifdef __REACTOS__
6150 #undef up
6151 #endif
6152 
6153     test_context = new_test_context();
6154     if (!test_context)
6155     {
6156         skip("Couldn't create test context\n");
6157         goto cleanup;
6158     }
6159 
6160     for (i = 0; i < ARRAY_SIZE(tc); i++)
6161     {
6162         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
6163                             declaration, test_context->device, &mesh);
6164         if (FAILED(hr))
6165         {
6166             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
6167             goto cleanup;
6168         }
6169 
6170         if (i == 0) /* Save first mesh for later NULL checks */
6171             mesh_null_check = mesh;
6172 
6173         adjacency = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
6174         if (!adjacency)
6175         {
6176             skip("Couldn't allocate adjacency array.\n");
6177             goto cleanup;
6178         }
6179 
6180         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
6181         if (FAILED(hr))
6182         {
6183             skip("Couldn't lock vertex buffer.\n");
6184             goto cleanup;
6185         }
6186         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
6187         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6188         if (FAILED(hr))
6189         {
6190             skip("Couldn't unlock vertex buffer.\n");
6191             goto cleanup;
6192         }
6193         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6194         if (FAILED(hr))
6195         {
6196             skip("Couldn't lock index buffer.\n");
6197             goto cleanup;
6198         }
6199         if (tc[i].options & D3DXMESH_32BIT)
6200         {
6201             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
6202         }
6203         else
6204         {
6205             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
6206         }
6207         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6208         if (FAILED(hr)) {
6209             skip("Couldn't unlock index buffer.\n");
6210             goto cleanup;
6211         }
6212 
6213         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6214         if (FAILED(hr))
6215         {
6216             skip("Couldn't lock attributes buffer.\n");
6217             goto cleanup;
6218         }
6219         memcpy(attributes_buffer, attributes, sizeof(attributes));
6220         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6221         if (FAILED(hr))
6222         {
6223             skip("Couldn't unlock attributes buffer.\n");
6224             goto cleanup;
6225         }
6226 
6227         /* Convert point representation to adjacency*/
6228         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
6229 
6230         hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
6231         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
6232            "Got %x expected D3D_OK\n", i, hr);
6233         /* Check adjacency */
6234         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
6235         {
6236             ok(adjacency[j] == tc[i].exp_adjacency[j],
6237                "Unexpected adjacency information at (%d, %d)."
6238                " Got %d expected %d\n",
6239                i, j, adjacency[j], tc[i].exp_adjacency[j]);
6240         }
6241 
6242         /* NULL point representation is considered identity. */
6243         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
6244         hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
6245         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
6246                      "Got %x expected D3D_OK\n", hr);
6247         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
6248         {
6249             ok(adjacency[j] == tc[i].exp_id_adjacency[j],
6250                "Unexpected adjacency information (id) at (%d, %d)."
6251                " Got %d expected %d\n",
6252                i, j, adjacency[j], tc[i].exp_id_adjacency[j]);
6253         }
6254 
6255         HeapFree(GetProcessHeap(), 0, adjacency);
6256         adjacency = NULL;
6257         if (i != 0) /* First mesh will be freed during cleanup */
6258             mesh->lpVtbl->Release(mesh);
6259     }
6260 
6261     /* NULL checks */
6262     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
6263     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
6264        "Got %x expected D3DERR_INVALIDCALL\n", hr);
6265     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
6266     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
6267        "Got %x expected D3DERR_INVALIDCALL\n", hr);
6268 
6269 cleanup:
6270     if (mesh_null_check)
6271         mesh_null_check->lpVtbl->Release(mesh_null_check);
6272     HeapFree(GetProcessHeap(), 0, adjacency);
6273     free_test_context(test_context);
6274 }
6275 
6276 static HRESULT init_test_mesh(const DWORD num_faces, const DWORD num_vertices,
6277                               const DWORD options,
6278                               const D3DVERTEXELEMENT9 *declaration,
6279                               IDirect3DDevice9 *device, ID3DXMesh **mesh_ptr,
6280                               const void *vertices, const DWORD vertex_size,
6281                               const DWORD *indices, const DWORD *attributes)
6282 {
6283     HRESULT hr;
6284     void *vertex_buffer;
6285     void *index_buffer;
6286     DWORD *attributes_buffer;
6287     ID3DXMesh *mesh = NULL;
6288 
6289     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration, device, mesh_ptr);
6290     if (FAILED(hr))
6291     {
6292         skip("Couldn't create mesh. Got %x expected D3D_OK\n", hr);
6293         goto cleanup;
6294     }
6295     mesh = *mesh_ptr;
6296 
6297     hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
6298     if (FAILED(hr))
6299     {
6300         skip("Couldn't lock vertex buffer.\n");
6301         goto cleanup;
6302     }
6303     memcpy(vertex_buffer, vertices, num_vertices * vertex_size);
6304     hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6305     if (FAILED(hr))
6306     {
6307         skip("Couldn't unlock vertex buffer.\n");
6308         goto cleanup;
6309     }
6310 
6311     hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6312     if (FAILED(hr))
6313     {
6314         skip("Couldn't lock index buffer.\n");
6315         goto cleanup;
6316     }
6317     if (options & D3DXMESH_32BIT)
6318     {
6319         if (indices)
6320             memcpy(index_buffer, indices, 3 * num_faces * sizeof(DWORD));
6321         else
6322         {
6323             /* Fill index buffer with 0, 1, 2, ...*/
6324             DWORD *indices_32bit = (DWORD*)index_buffer;
6325             UINT i;
6326             for (i = 0; i < 3 * num_faces; i++)
6327                 indices_32bit[i] = i;
6328         }
6329     }
6330     else
6331     {
6332         if (indices)
6333             memcpy(index_buffer, indices, 3 * num_faces * sizeof(WORD));
6334         else
6335         {
6336             /* Fill index buffer with 0, 1, 2, ...*/
6337             WORD *indices_16bit = (WORD*)index_buffer;
6338             UINT i;
6339             for (i = 0; i < 3 * num_faces; i++)
6340                 indices_16bit[i] = i;
6341         }
6342     }
6343     hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6344     if (FAILED(hr)) {
6345         skip("Couldn't unlock index buffer.\n");
6346         goto cleanup;
6347     }
6348 
6349     hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6350     if (FAILED(hr))
6351     {
6352         skip("Couldn't lock attributes buffer.\n");
6353         goto cleanup;
6354     }
6355 
6356     if (attributes)
6357         memcpy(attributes_buffer, attributes, num_faces * sizeof(*attributes));
6358     else
6359         memset(attributes_buffer, 0, num_faces * sizeof(*attributes));
6360 
6361     hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6362     if (FAILED(hr))
6363     {
6364         skip("Couldn't unlock attributes buffer.\n");
6365         goto cleanup;
6366     }
6367 
6368     hr = D3D_OK;
6369 cleanup:
6370     return hr;
6371 }
6372 
6373 /* Using structs instead of bit-fields in order to avoid compiler issues. */
6374 struct udec3
6375 {
6376     UINT x;
6377     UINT y;
6378     UINT z;
6379     UINT w;
6380 };
6381 
6382 struct dec3n
6383 {
6384     INT x;
6385     INT y;
6386     INT z;
6387     INT w;
6388 };
6389 
6390 static DWORD init_udec3_dword(UINT x, UINT y, UINT z, UINT w)
6391 {
6392     DWORD d = 0;
6393 
6394     d |= x & 0x3ff;
6395     d |= (y << 10) & 0xffc00;
6396     d |= (z << 20) & 0x3ff00000;
6397     d |= (w << 30) & 0xc0000000;
6398 
6399     return d;
6400 }
6401 
6402 static DWORD init_dec3n_dword(INT x, INT y, INT z, INT w)
6403 {
6404     DWORD d = 0;
6405 
6406     d |= x & 0x3ff;
6407     d |= (y << 10) & 0xffc00;
6408     d |= (z << 20) & 0x3ff00000;
6409     d |= (w << 30) & 0xc0000000;
6410 
6411     return d;
6412 }
6413 
6414 static struct udec3 dword_to_udec3(DWORD d)
6415 {
6416     struct udec3 v;
6417 
6418     v.x = d & 0x3ff;
6419     v.y = (d & 0xffc00) >> 10;
6420     v.z = (d & 0x3ff00000) >> 20;
6421     v.w = (d & 0xc0000000) >> 30;
6422 
6423     return v;
6424 }
6425 
6426 static struct dec3n dword_to_dec3n(DWORD d)
6427 {
6428     struct dec3n v;
6429 
6430     v.x = d & 0x3ff;
6431     v.y = (d & 0xffc00) >> 10;
6432     v.z = (d & 0x3ff00000) >> 20;
6433     v.w = (d & 0xc0000000) >> 30;
6434 
6435     return v;
6436 }
6437 
6438 static void check_vertex_components(int line, int mesh_number, int vertex_number, BYTE *got_ptr, const BYTE *exp_ptr, D3DVERTEXELEMENT9 *declaration)
6439 {
6440     const char *usage_strings[] =
6441     {
6442         "position",
6443         "blend weight",
6444         "blend indices",
6445         "normal",
6446         "point size",
6447         "texture coordinates",
6448         "tangent",
6449         "binormal",
6450         "tessellation factor",
6451         "position transformed",
6452         "color",
6453         "fog",
6454         "depth",
6455         "sample"
6456     };
6457     D3DVERTEXELEMENT9 *decl_ptr;
6458     const float PRECISION = 1e-5f;
6459 
6460     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
6461     {
6462         switch (decl_ptr->Type)
6463         {
6464             case D3DDECLTYPE_FLOAT1:
6465             {
6466                 FLOAT *got = (FLOAT*)(got_ptr + decl_ptr->Offset);
6467                 FLOAT *exp = (FLOAT*)(exp_ptr + decl_ptr->Offset);
6468                 FLOAT diff = fabsf(*got - *exp);
6469                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got %f for vertex %d %s, expected %f.\n",
6470                     mesh_number, *got, vertex_number, usage_strings[decl_ptr->Usage], *exp);
6471                 break;
6472             }
6473             case D3DDECLTYPE_FLOAT2:
6474             {
6475                 D3DXVECTOR2 *got = (D3DXVECTOR2*)(got_ptr + decl_ptr->Offset);
6476                 D3DXVECTOR2 *exp = (D3DXVECTOR2*)(exp_ptr + decl_ptr->Offset);
6477                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6478                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f) for vertex %d %s, expected (%f, %f).\n",
6479                     mesh_number, got->x, got->y, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y);
6480                 break;
6481             }
6482             case D3DDECLTYPE_FLOAT3:
6483             {
6484                 D3DXVECTOR3 *got = (D3DXVECTOR3*)(got_ptr + decl_ptr->Offset);
6485                 D3DXVECTOR3 *exp = (D3DXVECTOR3*)(exp_ptr + decl_ptr->Offset);
6486                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6487                 diff = max(diff, fabsf(got->z - exp->z));
6488                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f) for vertex %d %s, expected (%f, %f, %f).\n",
6489                     mesh_number, got->x, got->y, got->z, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y, exp->z);
6490                 break;
6491             }
6492             case D3DDECLTYPE_FLOAT4:
6493             {
6494                 D3DXVECTOR4 *got = (D3DXVECTOR4*)(got_ptr + decl_ptr->Offset);
6495                 D3DXVECTOR4 *exp = (D3DXVECTOR4*)(exp_ptr + decl_ptr->Offset);
6496                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6497                 diff = max(diff, fabsf(got->z - exp->z));
6498                 diff = max(diff, fabsf(got->w - exp->w));
6499                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f, %f) for vertex %d %s, expected (%f, %f, %f, %f).\n",
6500                     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);
6501                 break;
6502             }
6503             case D3DDECLTYPE_D3DCOLOR:
6504             {
6505                 BYTE *got = got_ptr + decl_ptr->Offset;
6506                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6507                 BOOL same_color = got[0] == exp[0] && got[1] == exp[1]
6508                                   && got[2] == exp[2] && got[3] == exp[3];
6509                 const char *color_types[] = {"diffuse", "specular", "undefined color"};
6510                 BYTE usage_index = decl_ptr->UsageIndex;
6511                 if (usage_index > 1) usage_index = 2;
6512                 ok_(__FILE__,line)(same_color, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6513                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, color_types[usage_index], exp[0], exp[1], exp[2], exp[3]);
6514                 break;
6515             }
6516             case D3DDECLTYPE_UBYTE4:
6517             case D3DDECLTYPE_UBYTE4N:
6518             {
6519                 BYTE *got = got_ptr + decl_ptr->Offset;
6520                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6521                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6522                             && got[2] == exp[2] && got[3] == exp[3];
6523                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6524                     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]);
6525                 break;
6526             }
6527             case D3DDECLTYPE_SHORT2:
6528             case D3DDECLTYPE_SHORT2N:
6529             {
6530                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6531                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6532                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6533                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd) for vertex %d %s, expected (%hd, %hd).\n",
6534                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6535                 break;
6536             }
6537             case D3DDECLTYPE_SHORT4:
6538             case D3DDECLTYPE_SHORT4N:
6539             {
6540                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6541                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6542                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6543                             && got[2] == exp[2] && got[3] == exp[3];
6544                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd, %hd, %hd) for vertex %d %s, expected (%hd, %hd, %hd, %hd).\n",
6545                     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]);
6546                 break;
6547             }
6548             case D3DDECLTYPE_USHORT2N:
6549             {
6550                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6551                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6552                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6553                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu) for vertex %d %s, expected (%hu, %hu).\n",
6554                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6555                 break;
6556             }
6557             case D3DDECLTYPE_USHORT4N:
6558             {
6559                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6560                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6561                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6562                             && got[2] == exp[2] && got[3] == exp[3];
6563                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu, %hu, %hu) for vertex %d %s, expected (%hu, %hu, %hu, %hu).\n",
6564                     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]);
6565                 break;
6566             }
6567             case D3DDECLTYPE_UDEC3:
6568             {
6569                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6570                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6571                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6572                 struct udec3 got_udec3 = dword_to_udec3(*got);
6573                 struct udec3 exp_udec3 = dword_to_udec3(*exp);
6574                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6575                     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);
6576 
6577                 break;
6578             }
6579             case D3DDECLTYPE_DEC3N:
6580             {
6581                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6582                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6583                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6584                 struct dec3n got_dec3n = dword_to_dec3n(*got);
6585                 struct dec3n exp_dec3n = dword_to_dec3n(*exp);
6586                 ok_(__FILE__,line)(same, "Mesh %d: Got (%d, %d, %d, %d) for vertex %d %s, expected (%d, %d, %d, %d).\n",
6587                     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);
6588                 break;
6589             }
6590             case D3DDECLTYPE_FLOAT16_2:
6591             {
6592                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6593                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6594                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6595                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx) for vertex %d %s, expected (%hx, %hx).\n",
6596                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6597                 break;
6598             }
6599             case D3DDECLTYPE_FLOAT16_4:
6600             {
6601                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6602                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6603                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6604                             && got[2] == exp[2] && got[3] == exp[3];
6605                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx, %hx, %hx) for vertex %d %s, expected (%hx, %hx, %hx, %hx).\n",
6606                     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]);
6607                 break;
6608             }
6609             default:
6610                 break;
6611         }
6612     }
6613 }
6614 
6615 static void test_weld_vertices(void)
6616 {
6617     HRESULT hr;
6618     struct test_context *test_context = NULL;
6619     DWORD i;
6620     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
6621     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
6622     BYTE *vertices = NULL;
6623     DWORD *indices = NULL;
6624     WORD *indices_16bit = NULL;
6625     const UINT VERTS_PER_FACE = 3;
6626 #ifndef __REACTOS__
6627     const D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
6628 #else
6629 #define up {0.0f, 0.0f, 1.0f}
6630 #endif
6631     struct vertex_normal
6632     {
6633         D3DXVECTOR3 position;
6634         D3DXVECTOR3 normal;
6635     };
6636     struct vertex_blendweight
6637     {
6638         D3DXVECTOR3 position;
6639         FLOAT blendweight;
6640     };
6641     struct vertex_texcoord
6642     {
6643         D3DXVECTOR3 position;
6644         D3DXVECTOR2 texcoord;
6645     };
6646     struct vertex_color
6647     {
6648         D3DXVECTOR3 position;
6649         DWORD color;
6650     };
6651     struct vertex_color_ubyte4
6652     {
6653         D3DXVECTOR3 position;
6654         BYTE color[4];
6655     };
6656     struct vertex_texcoord_short2
6657     {
6658         D3DXVECTOR3 position;
6659         SHORT texcoord[2];
6660     };
6661     struct vertex_texcoord_ushort2n
6662     {
6663         D3DXVECTOR3 position;
6664         USHORT texcoord[2];
6665     };
6666     struct vertex_normal_short4
6667     {
6668         D3DXVECTOR3 position;
6669         SHORT normal[4];
6670     };
6671     struct vertex_texcoord_float16_2
6672     {
6673         D3DXVECTOR3 position;
6674         WORD texcoord[2];
6675     };
6676     struct vertex_texcoord_float16_4
6677     {
6678         D3DXVECTOR3 position;
6679         WORD texcoord[4];
6680     };
6681     struct vertex_normal_udec3
6682     {
6683         D3DXVECTOR3 position;
6684         DWORD normal;
6685     };
6686     struct vertex_normal_dec3n
6687     {
6688         D3DXVECTOR3 position;
6689         DWORD normal;
6690     };
6691     UINT vertex_size_normal = sizeof(struct vertex_normal);
6692     UINT vertex_size_blendweight = sizeof(struct vertex_blendweight);
6693     UINT vertex_size_texcoord = sizeof(struct vertex_texcoord);
6694     UINT vertex_size_color = sizeof(struct vertex_color);
6695     UINT vertex_size_color_ubyte4 = sizeof(struct vertex_color_ubyte4);
6696     UINT vertex_size_texcoord_short2 = sizeof(struct vertex_texcoord_short2);
6697     UINT vertex_size_normal_short4 = sizeof(struct vertex_normal_short4);
6698     UINT vertex_size_texcoord_float16_2 = sizeof(struct vertex_texcoord_float16_2);
6699     UINT vertex_size_texcoord_float16_4 = sizeof(struct vertex_texcoord_float16_4);
6700     UINT vertex_size_normal_udec3 = sizeof(struct vertex_normal_udec3);
6701     UINT vertex_size_normal_dec3n = sizeof(struct vertex_normal_dec3n);
6702     D3DVERTEXELEMENT9 declaration_normal[] =
6703     {
6704         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6705         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6706         D3DDECL_END()
6707     };
6708     D3DVERTEXELEMENT9 declaration_normal3[] =
6709     {
6710         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 3},
6711         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6712         D3DDECL_END()
6713     };
6714     D3DVERTEXELEMENT9 declaration_blendweight[] =
6715     {
6716         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6717         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
6718         D3DDECL_END()
6719     };
6720     D3DVERTEXELEMENT9 declaration_texcoord[] =
6721     {
6722         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6723         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6724         D3DDECL_END()
6725     };
6726     D3DVERTEXELEMENT9 declaration_color[] =
6727     {
6728         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6729         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6730         D3DDECL_END()
6731     };
6732     D3DVERTEXELEMENT9 declaration_color_ubyte4n[] =
6733     {
6734         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6735         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6736         D3DDECL_END()
6737     };
6738     D3DVERTEXELEMENT9 declaration_color_ubyte4[] =
6739     {
6740         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6741         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6742         D3DDECL_END()
6743     };
6744     D3DVERTEXELEMENT9 declaration_texcoord_short2[] =
6745     {
6746         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6747         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6748         D3DDECL_END()
6749     };
6750     D3DVERTEXELEMENT9 declaration_texcoord_short2n[] =
6751     {
6752         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6753         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6754         D3DDECL_END()
6755     };
6756     D3DVERTEXELEMENT9 declaration_texcoord_ushort2n[] =
6757     {
6758         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6759         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6760         D3DDECL_END()
6761     };
6762     D3DVERTEXELEMENT9 declaration_normal_short4[] =
6763     {
6764         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6765         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6766         D3DDECL_END()
6767     };
6768     D3DVERTEXELEMENT9 declaration_normal_short4n[] =
6769     {
6770         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6771         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6772         D3DDECL_END()
6773     };
6774     D3DVERTEXELEMENT9 declaration_normal_ushort4n[] =
6775     {
6776         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6777         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6778         D3DDECL_END()
6779     };
6780     D3DVERTEXELEMENT9 declaration_texcoord10[] =
6781     {
6782         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6783         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 10},
6784         D3DDECL_END()
6785     };
6786     D3DVERTEXELEMENT9 declaration_color2[] =
6787     {
6788         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6789         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
6790         D3DDECL_END()
6791     };
6792     D3DVERTEXELEMENT9 declaration_color1[] =
6793     {
6794         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6795         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
6796         D3DDECL_END()
6797     };
6798     D3DVERTEXELEMENT9 declaration_texcoord_float16_2[] =
6799     {
6800         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6801         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6802         D3DDECL_END()
6803     };
6804     D3DVERTEXELEMENT9 declaration_texcoord_float16_4[] =
6805     {
6806         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6807         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6808         D3DDECL_END()
6809     };
6810     D3DVERTEXELEMENT9 declaration_normal_udec3[] =
6811    {
6812         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6813         {0, 12, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6814         D3DDECL_END()
6815     };
6816     D3DVERTEXELEMENT9 declaration_normal_dec3n[] =
6817     {
6818         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6819         {0, 12, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6820         D3DDECL_END()
6821     };
6822     /* Test 0. One face and no welding.
6823      *
6824      * 0--1
6825      * | /
6826      * |/
6827      * 2
6828      */
6829     const struct vertex vertices0[] =
6830     {
6831         {{ 0.0f,  3.0f,  0.f}, up},
6832         {{ 2.0f,  3.0f,  0.f}, up},
6833         {{ 0.0f,  0.0f,  0.f}, up},
6834     };
6835     const DWORD indices0[] = {0, 1, 2};
6836     const DWORD attributes0[] = {0};
6837     const DWORD exp_indices0[] = {0, 1, 2};
6838     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
6839     const UINT num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
6840     const DWORD flags0 = D3DXWELDEPSILONS_WELDALL;
6841     /* epsilons0 is NULL */
6842     const DWORD adjacency0[] = {-1, -1, -1};
6843     const struct vertex exp_vertices0[] =
6844     {
6845         {{ 0.0f,  3.0f,  0.f}, up},
6846         {{ 2.0f,  3.0f,  0.f}, up},
6847         {{ 0.0f,  0.0f,  0.f}, up},
6848     };
6849     const DWORD exp_face_remap0[] = {0};
6850     const DWORD exp_vertex_remap0[] = {0, 1, 2};
6851     const DWORD exp_new_num_vertices0 = ARRAY_SIZE(exp_vertices0);
6852     /* Test 1. Two vertices should be removed without regard to epsilon.
6853      *
6854      * 0--1 3
6855      * | / /|
6856      * |/ / |
6857      * 2 5--4
6858      */
6859     const struct vertex_normal vertices1[] =
6860     {
6861         {{ 0.0f,  3.0f,  0.f}, up},
6862         {{ 2.0f,  3.0f,  0.f}, up},
6863         {{ 0.0f,  0.0f,  0.f}, up},
6864 
6865         {{ 3.0f,  3.0f,  0.f}, up},
6866         {{ 3.0f,  0.0f,  0.f}, up},
6867         {{ 1.0f,  0.0f,  0.f}, up},
6868     };
6869     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
6870     const DWORD attributes1[] = {0, 0};
6871     const UINT num_vertices1 = ARRAY_SIZE(vertices1);
6872     const UINT num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
6873     const DWORD flags1 = D3DXWELDEPSILONS_WELDALL;
6874     /* epsilons1 is NULL */
6875     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
6876     const struct vertex_normal exp_vertices1[] =
6877     {
6878         {{ 0.0f,  3.0f,  0.f}, up},
6879         {{ 2.0f,  3.0f,  0.f}, up},
6880         {{ 0.0f,  0.0f,  0.f}, up},
6881 
6882         {{ 3.0f,  0.0f,  0.f}, up}
6883     };
6884     const DWORD exp_indices1[] = {0, 1, 2, 1, 3, 2};
6885     const DWORD exp_face_remap1[] = {0, 1};
6886     const DWORD exp_vertex_remap1[] = {0, 1, 2, 4, -1, -1};
6887     const DWORD exp_new_num_vertices1 = ARRAY_SIZE(exp_vertices1);
6888     /* Test 2. Two faces. No vertices should be removed because of normal
6889      * epsilon, but the positions should be replaced. */
6890     const struct vertex_normal vertices2[] =
6891     {
6892         {{ 0.0f,  3.0f,  0.f}, up},
6893         {{ 2.0f,  3.0f,  0.f}, up},
6894         {{ 0.0f,  0.0f,  0.f}, up},
6895 
6896         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6897         {{ 3.0f,  0.0f,  0.f}, up},
6898         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6899     };
6900     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
6901     const DWORD attributes2[] = {0, 0};
6902     const UINT num_vertices2 = ARRAY_SIZE(vertices2);
6903     const UINT num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
6904     DWORD flags2 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6905     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};
6906     const DWORD adjacency2[] = {-1, 1, -1, -1, -1, 0};
6907     const struct vertex_normal exp_vertices2[] =
6908     {
6909         {{ 0.0f,  3.0f,  0.f}, up},
6910         {{ 2.0f,  3.0f,  0.f}, up},
6911         {{ 0.0f,  0.0f,  0.f}, up},
6912 
6913         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6914         {{ 3.0f,  0.0f,  0.f}, up},
6915         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6916     };
6917     const DWORD exp_indices2[] = {0, 1, 2, 3, 4, 5};
6918     const DWORD exp_face_remap2[] = {0, 1};
6919     const DWORD exp_vertex_remap2[] = {0, 1, 2, 3, 4, 5};
6920     const DWORD exp_new_num_vertices2 = ARRAY_SIZE(exp_vertices2);
6921     /* Test 3. Two faces. One vertex should be removed because of normal epsilon. */
6922     const struct vertex_normal vertices3[] =
6923     {
6924         {{ 0.0f,  3.0f,  0.f}, up},
6925         {{ 2.0f,  3.0f,  0.f}, up},
6926         {{ 0.0f,  0.0f,  0.f}, up},
6927 
6928         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6929         {{ 3.0f,  0.0f,  0.f}, up},
6930         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6931     };
6932     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
6933     const DWORD attributes3[] = {0, 0};
6934     const UINT num_vertices3 = ARRAY_SIZE(vertices3);
6935     const UINT num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
6936     DWORD flags3 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6937     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};
6938     const DWORD adjacency3[] = {-1, 1, -1, -1, -1, 0};
6939     const struct vertex_normal exp_vertices3[] =
6940     {
6941         {{ 0.0f,  3.0f,  0.f}, up},
6942         {{ 2.0f,  3.0f,  0.f}, up},
6943         {{ 0.0f,  0.0f,  0.f}, up},
6944 
6945         {{ 3.0f,  0.0f,  0.f}, up},
6946         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6947     };
6948     const DWORD exp_indices3[] = {0, 1, 2, 1, 3, 4};
6949     const DWORD exp_face_remap3[] = {0, 1};
6950     const DWORD exp_vertex_remap3[] = {0, 1, 2, 4, 5, -1};
6951     const DWORD exp_new_num_vertices3 = ARRAY_SIZE(exp_vertices3);
6952     /* Test 4  Two faces. Two vertices should be removed. */
6953     const struct vertex_normal vertices4[] =
6954     {
6955         {{ 0.0f,  3.0f,  0.f}, up},
6956         {{ 2.0f,  3.0f,  0.f}, up},
6957         {{ 0.0f,  0.0f,  0.f}, up},
6958 
6959         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6960         {{ 3.0f,  0.0f,  0.f}, up},
6961         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6962     };
6963     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
6964     const DWORD attributes4[] = {0, 0};
6965     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
6966     const UINT num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
6967     DWORD flags4 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6968     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};
6969     const DWORD adjacency4[] = {-1, 1, -1, -1, -1, 0};
6970     const struct vertex_normal exp_vertices4[] =
6971     {
6972         {{ 0.0f,  3.0f,  0.f}, up},
6973         {{ 2.0f,  3.0f,  0.f}, up},
6974         {{ 0.0f,  0.0f,  0.f}, up},
6975 
6976         {{ 3.0f,  0.0f,  0.f}, up},
6977     };
6978     const DWORD exp_indices4[] = {0, 1, 2, 1, 3, 2};
6979     const DWORD exp_face_remap4[] = {0, 1};
6980     const DWORD exp_vertex_remap4[] = {0, 1, 2, 4, -1, -1};
6981     const DWORD exp_new_num_vertices4 = ARRAY_SIZE(exp_vertices4);
6982     /* Test 5. Odd face ordering.
6983      *
6984      * 0--1 6 3
6985      * | / /| |\
6986      * |/ / | | \
6987      * 2 8--7 5--4
6988      */
6989     const struct vertex_normal vertices5[] =
6990     {
6991         {{ 0.0f,  3.0f,  0.f}, up},
6992         {{ 2.0f,  3.0f,  0.f}, up},
6993         {{ 0.0f,  0.0f,  0.f}, up},
6994 
6995         {{ 3.0f,  3.0f,  0.f}, up},
6996         {{ 3.0f,  0.0f,  0.f}, up},
6997         {{ 1.0f,  0.0f,  0.f}, up},
6998 
6999         {{ 4.0f,  3.0f,  0.f}, up},
7000         {{ 6.0f,  0.0f,  0.f}, up},
7001         {{ 4.0f,  0.0f,  0.f}, up},
7002     };
7003     const DWORD indices5[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
7004     const DWORD exp_indices5[] = {0, 1, 2, 1, 4, 2, 1, 3, 4};
7005     const DWORD attributes5[] = {0, 0, 0};
7006     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
7007     const UINT num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
7008     DWORD flags5 = D3DXWELDEPSILONS_WELDALL;
7009     const DWORD adjacency5[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
7010     const struct vertex_normal exp_vertices5[] =
7011     {
7012         {{ 0.0f,  3.0f,  0.f}, up},
7013         {{ 2.0f,  3.0f,  0.f}, up},
7014         {{ 0.0f,  0.0f,  0.f}, up},
7015 
7016         {{ 3.0f,  0.0f,  0.f}, up},
7017         {{ 1.0f,  0.0f,  0.f}, up},
7018     };
7019     const DWORD exp_face_remap5[] = {0, 1, 2};
7020     const DWORD exp_vertex_remap5[] = {0, 1, 2, 4, 5, -1, -1, -1, -1};
7021     const DWORD exp_new_num_vertices5 = ARRAY_SIZE(exp_vertices5);
7022     /* Test 6. Two faces. Do not remove flag is used, so no vertices should be
7023      * removed. */
7024     const struct vertex_normal vertices6[] =
7025     {
7026         {{ 0.0f,  3.0f,  0.f}, up},
7027         {{ 2.0f,  3.0f,  0.f}, up},
7028         {{ 0.0f,  0.0f,  0.f}, up},
7029 
7030         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7031         {{ 3.0f,  0.0f,  0.f}, up},
7032         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7033     };
7034     const DWORD indices6[] = {0, 1, 2, 3, 4, 5};
7035     const DWORD attributes6[] = {0, 0};
7036     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
7037     const UINT num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
7038     DWORD flags6 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTREMOVEVERTICES;
7039     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};
7040     const DWORD adjacency6[] = {-1, 1, -1, -1, -1, 0};
7041     const struct vertex_normal exp_vertices6[] =
7042     {
7043         {{ 0.0f,  3.0f,  0.f}, up},
7044         {{ 2.0f,  3.0f,  0.f}, up},
7045         {{ 0.0f,  0.0f,  0.f}, up},
7046 
7047         {{ 2.0f,  3.0f,  0.f}, up},
7048         {{ 3.0f,  0.0f,  0.f}, up},
7049         {{ 0.0f,  0.0f,  0.f}, up},
7050 
7051     };
7052     const DWORD exp_indices6[] = {0, 1, 2, 3, 4, 5};
7053     const DWORD exp_face_remap6[] = {0, 1};
7054     const DWORD exp_vertex_remap6[] = {0, 1, 2, 3, 4, 5};
7055     const DWORD exp_new_num_vertices6 = ARRAY_SIZE(exp_vertices6);
7056     /* Test 7. Same as test 6 but with 16 bit indices. */
7057     const WORD indices6_16bit[] = {0, 1, 2, 3, 4, 5};
7058     /* Test 8. No flags. Same result as D3DXWELDEPSILONS_WELDPARTIALMATCHES. */
7059     const struct vertex_normal vertices8[] =
7060     {
7061         {{ 0.0f,  3.0f,  0.f}, up},
7062         {{ 2.0f,  3.0f,  0.f}, up},
7063         {{ 0.0f,  0.0f,  0.f}, up},
7064 
7065         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7066         {{ 3.0f,  0.0f,  0.f}, up},
7067         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7068     };
7069     const DWORD indices8[] = {0, 1, 2, 1, 3, 4};
7070     const DWORD attributes8[] = {0, 0};
7071     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
7072     const UINT num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
7073     DWORD flags8 = 0;
7074     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};
7075     const DWORD adjacency8[] = {-1, 1, -1, -1, -1, 0};
7076     const struct vertex_normal exp_vertices8[] =
7077     {
7078         {{ 0.0f,  3.0f,  0.f}, up},
7079         {{ 2.0f,  3.0f,  0.f}, up},
7080         {{ 0.0f,  0.0f,  0.f}, up},
7081 
7082         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7083         {{ 3.0f,  0.0f,  0.f}, up},
7084     };
7085     const DWORD exp_indices8[] = {0, 1, 2, 1, 3, 4};
7086     const DWORD exp_face_remap8[] = {0, 1};
7087     const DWORD exp_vertex_remap8[] = {0, 1, 2, 3, 4, -1};
7088     const DWORD exp_new_num_vertices8 = ARRAY_SIZE(exp_vertices8);
7089     /* Test 9. Vertices are removed even though they belong to separate
7090      * attribute groups if D3DXWELDEPSILONS_DONOTSPLIT is set. */
7091     const struct vertex_normal vertices9[] =
7092     {
7093         {{ 0.0f,  3.0f,  0.f}, up},
7094         {{ 2.0f,  3.0f,  0.f}, up},
7095         {{ 0.0f,  0.0f,  0.f}, up},
7096 
7097         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7098         {{ 3.0f,  0.0f,  0.f}, up},
7099         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7100     };
7101     const DWORD indices9[] = {0, 1, 2, 3, 4, 5};
7102     const DWORD attributes9[] = {0, 1};
7103     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
7104     const UINT num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
7105     DWORD flags9 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTSPLIT;
7106     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};
7107     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
7108     const struct vertex_normal exp_vertices9[] =
7109     {
7110         {{ 0.0f,  3.0f,  0.f}, up},
7111         {{ 2.0f,  3.0f,  0.f}, up},
7112         {{ 0.0f,  0.0f,  0.f}, up},
7113 
7114         {{ 3.0f,  0.0f,  0.f}, up},
7115     };
7116     const DWORD exp_indices9[] = {0, 1, 2, 1, 3, 2};
7117     const DWORD exp_face_remap9[] = {0, 1};
7118     const DWORD exp_vertex_remap9[] = {0, 1, 2, 4, -1, -1};
7119     const DWORD exp_new_num_vertices9 = ARRAY_SIZE(exp_vertices9);
7120     /* Test 10. Weld blendweight (FLOAT1). */
7121     const struct vertex_blendweight vertices10[] =
7122     {
7123         {{ 0.0f,  3.0f,  0.f}, 1.0f},
7124         {{ 2.0f,  3.0f,  0.f}, 1.0f},
7125         {{ 0.0f,  0.0f,  0.f}, 1.0f},
7126 
7127         {{ 3.0f,  3.0f,  0.f}, 0.9},
7128         {{ 3.0f,  0.0f,  0.f}, 1.0},
7129         {{ 1.0f,  0.0f,  0.f}, 0.4},
7130     };
7131     const DWORD indices10[] = {0, 1, 2, 3, 4, 5};
7132     const DWORD attributes10[] = {0, 0};
7133     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
7134     const UINT num_faces10 = ARRAY_SIZE(indices10) / VERTS_PER_FACE;
7135     DWORD flags10 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7136     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};
7137     const DWORD adjacency10[] = {-1, 1, -1, -1, -1, 0};
7138     const struct vertex_blendweight exp_vertices10[] =
7139     {
7140         {{ 0.0f,  3.0f,  0.f}, 1.0f},
7141         {{ 2.0f,  3.0f,  0.f}, 1.0f},
7142         {{ 0.0f,  0.0f,  0.f}, 1.0f},
7143 
7144         {{ 3.0f,  0.0f,  0.f}, 1.0},
7145         {{ 0.0f,  0.0f,  0.f}, 0.4},
7146     };
7147     const DWORD exp_indices10[] = {0, 1, 2, 1, 3, 4};
7148     const DWORD exp_face_remap10[] = {0, 1};
7149     const DWORD exp_vertex_remap10[] = {0, 1, 2, 4, 5, -1};
7150     const DWORD exp_new_num_vertices10 = ARRAY_SIZE(exp_vertices10);
7151     /* Test 11. Weld texture coordinates. */
7152     const struct vertex_texcoord vertices11[] =
7153     {
7154         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7155         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7156         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7157 
7158         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7159         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7160         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7161     };
7162     const DWORD indices11[] = {0, 1, 2, 3, 4, 5};
7163     const DWORD attributes11[] = {0, 0};
7164     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
7165     const UINT num_faces11 = ARRAY_SIZE(indices11) / VERTS_PER_FACE;
7166     DWORD flags11 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7167     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};
7168     const DWORD adjacency11[] = {-1, 1, -1, -1, -1, 0};
7169     const struct vertex_texcoord exp_vertices11[] =
7170     {
7171         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7172         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7173         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7174 
7175         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7176         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7177     };
7178     const DWORD exp_indices11[] = {0, 1, 2, 1, 3, 4};
7179     const DWORD exp_face_remap11[] = {0, 1};
7180     const DWORD exp_vertex_remap11[] = {0, 1, 2, 4, 5, -1};
7181     const DWORD exp_new_num_vertices11 = ARRAY_SIZE(exp_vertices11);
7182     /* Test 12. Weld with color. */
7183     const struct vertex_color vertices12[] =
7184     {
7185         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7186         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7187         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7188 
7189         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7190         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7191         {{ 1.0f,  0.0f,  0.f}, 0x88888888},
7192     };
7193     const DWORD indices12[] = {0, 1, 2, 3, 4, 5};
7194     const DWORD attributes12[] = {0, 0};
7195     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
7196     const UINT num_faces12 = ARRAY_SIZE(indices12) / VERTS_PER_FACE;
7197     DWORD flags12 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7198     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};
7199     const DWORD adjacency12[] = {-1, 1, -1, -1, -1, 0};
7200     const struct vertex_color exp_vertices12[] =
7201     {
7202         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7203         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7204         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7205 
7206         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7207         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7208     };
7209     const DWORD exp_indices12[] = {0, 1, 2, 3, 4, 2};
7210     const DWORD exp_face_remap12[] = {0, 1};
7211     const DWORD exp_vertex_remap12[] = {0, 1, 2, 3, 4, -1};
7212     const DWORD exp_new_num_vertices12 = ARRAY_SIZE(exp_vertices12);
7213     /* Test 13. Two faces. One vertex should be removed because of normal epsilon.
7214      * This is similar to test 3, but the declaration has been changed to NORMAL3.
7215      */
7216     const struct vertex_normal vertices13[] =
7217     {
7218         {{ 0.0f,  3.0f,  0.f}, up},
7219         {{ 2.0f,  3.0f,  0.f}, up},
7220         {{ 0.0f,  0.0f,  0.f}, up},
7221 
7222         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7223         {{ 3.0f,  0.0f,  0.f}, up},
7224         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7225     };
7226     const DWORD indices13[] = {0, 1, 2, 3, 4, 5};
7227     const DWORD attributes13[] = {0, 0};
7228     const UINT num_vertices13 = ARRAY_SIZE(vertices3);
7229     const UINT num_faces13 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
7230     DWORD flags13 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7231     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};
7232     const DWORD adjacency13[] = {-1, 1, -1, -1, -1, 0};
7233     const struct vertex_normal exp_vertices13[] =
7234     {
7235         {{ 0.0f,  3.0f,  0.f}, up},
7236         {{ 2.0f,  3.0f,  0.f}, up},
7237         {{ 0.0f,  0.0f,  0.f}, up},
7238 
7239         {{ 3.0f,  0.0f,  0.f}, up},
7240         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7241     };
7242     const DWORD exp_indices13[] = {0, 1, 2, 1, 3, 4};
7243     const DWORD exp_face_remap13[] = {0, 1};
7244     const DWORD exp_vertex_remap13[] = {0, 1, 2, 4, 5, -1};
7245     const DWORD exp_new_num_vertices13 = ARRAY_SIZE(exp_vertices13);
7246     /* Test 14. Another test for welding with color. */
7247     const struct vertex_color vertices14[] =
7248     {
7249         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7250         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7251         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7252 
7253         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7254         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7255         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7256     };
7257     const DWORD indices14[] = {0, 1, 2, 3, 4, 5};
7258     const DWORD attributes14[] = {0, 0};
7259     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
7260     const UINT num_faces14 = ARRAY_SIZE(indices14) / VERTS_PER_FACE;
7261     DWORD flags14 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7262     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};
7263     const DWORD adjacency14[] = {-1, 1, -1, -1, -1, 0};
7264     const struct vertex_color exp_vertices14[] =
7265     {
7266         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7267         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7268         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7269 
7270         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7271         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7272     };
7273     const DWORD exp_indices14[] = {0, 1, 2, 3, 4, 2};
7274     const DWORD exp_face_remap14[] = {0, 1};
7275     const DWORD exp_vertex_remap14[] = {0, 1, 2, 3, 4, -1};
7276     const DWORD exp_new_num_vertices14 = ARRAY_SIZE(exp_vertices14);
7277     /* Test 15. Weld with color, but as UBYTE4N instead of D3DCOLOR. It shows
7278      * that UBYTE4N and D3DCOLOR are compared the same way.
7279      */
7280     const struct vertex_color_ubyte4 vertices15[] =
7281     {
7282         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7283         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7284         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7285 
7286         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7287         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7288         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7289     };
7290     const DWORD indices15[] = {0, 1, 2, 3, 4, 5};
7291     const DWORD attributes15[] = {0, 0};
7292     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
7293     const UINT num_faces15 = ARRAY_SIZE(indices15) / VERTS_PER_FACE;
7294     DWORD flags15 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7295     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};
7296     const DWORD adjacency15[] = {-1, 1, -1, -1, -1, 0};
7297     const struct vertex_color_ubyte4 exp_vertices15[] =
7298     {
7299         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7300         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7301         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7302 
7303         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7304         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7305     };
7306     const DWORD exp_indices15[] = {0, 1, 2, 3, 4, 2};
7307     const DWORD exp_face_remap15[] = {0, 1};
7308     const DWORD exp_vertex_remap15[] = {0, 1, 2, 3, 4, -1};
7309     const DWORD exp_new_num_vertices15 = ARRAY_SIZE(exp_vertices15);
7310     /* Test 16. Weld with color, but as UBYTE4 instead of D3DCOLOR. It shows
7311      * that UBYTE4 is not normalized and that epsilon is truncated and compared
7312      * directly to each of the four bytes.
7313      */
7314     const struct vertex_color_ubyte4 vertices16[] =
7315     {
7316         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7317         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7318         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7319 
7320         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7321         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7322         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7323     };
7324     const DWORD indices16[] = {0, 1, 2, 3, 4, 5};
7325     const DWORD attributes16[] = {0, 0};
7326     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
7327     const UINT num_faces16 = ARRAY_SIZE(indices16) / VERTS_PER_FACE;
7328     DWORD flags16 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7329     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};
7330     const DWORD adjacency16[] = {-1, 1, -1, -1, -1, 0};
7331     const struct vertex_color_ubyte4 exp_vertices16[] =
7332     {
7333         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7334         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7335         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7336 
7337         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7338         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7339     };
7340     const DWORD exp_indices16[] = {0, 1, 2, 3, 4, 2};
7341     const DWORD exp_face_remap16[] = {0, 1};
7342     const DWORD exp_vertex_remap16[] = {0, 1, 2, 3, 4, -1};
7343     const DWORD exp_new_num_vertices16 = ARRAY_SIZE(exp_vertices16);
7344     /* Test 17. Weld texture coordinates but as SHORT2 instead of D3DXVECTOR2.*/
7345     const struct vertex_texcoord_short2 vertices17[] =
7346     {
7347         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7348         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7349         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7350 
7351         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7352         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7353         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7354     };
7355     const DWORD indices17[] = {0, 1, 2, 3, 4, 5};
7356     const DWORD attributes17[] = {0, 0};
7357     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
7358     const UINT num_faces17 = ARRAY_SIZE(indices17) / VERTS_PER_FACE;
7359     DWORD flags17 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7360     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};
7361     const DWORD adjacency17[] = {-1, 1, -1, -1, -1, 0};
7362     const struct vertex_texcoord_short2 exp_vertices17[] =
7363     {
7364         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7365         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7366         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7367 
7368         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7369         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7370     };
7371     const DWORD exp_indices17[] = {0, 1, 2, 3, 4, 2};
7372     const DWORD exp_face_remap17[] = {0, 1};
7373     const DWORD exp_vertex_remap17[] = {0, 1, 2, 3, 4, -1};
7374     const DWORD exp_new_num_vertices17 = ARRAY_SIZE(exp_vertices17);
7375     /* Test 18. Weld texture coordinates but as SHORT2N instead of D3DXVECTOR2. */
7376     const struct vertex_texcoord_short2 vertices18[] =
7377     {
7378         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7379         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7380         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7381 
7382         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7383         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7384         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7385     };
7386     const DWORD indices18[] = {0, 1, 2, 3, 4, 5};
7387     const DWORD attributes18[] = {0, 0};
7388     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
7389     const UINT num_faces18 = ARRAY_SIZE(indices18) / VERTS_PER_FACE;
7390     DWORD flags18 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7391     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};
7392     const DWORD adjacency18[] = {-1, 1, -1, -1, -1, 0};
7393     const struct vertex_texcoord_short2 exp_vertices18[] =
7394     {
7395         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7396         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7397         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7398 
7399         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7400         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7401     };
7402     const DWORD exp_indices18[] = {0, 1, 2, 3, 4, 2};
7403     const DWORD exp_face_remap18[] = {0, 1};
7404     const DWORD exp_vertex_remap18[] = {0, 1, 2, 3, 4, -1};
7405     const DWORD exp_new_num_vertices18 = ARRAY_SIZE(exp_vertices18);
7406     /* Test 19.  Weld texture coordinates but as USHORT2N instead of D3DXVECTOR2. */
7407     const struct vertex_texcoord_ushort2n vertices19[] =
7408     {
7409         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7410         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7411         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7412 
7413         {{ 3.0f,  3.0f,  0.f}, {65535, 65535}},
7414         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7415         {{ 1.0f,  0.0f,  0.f}, {65534, 65534}},
7416     };
7417     const DWORD indices19[] = {0, 1, 2, 3, 4, 5};
7418     const DWORD attributes19[] = {0, 0};
7419     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
7420     const UINT num_faces19 = ARRAY_SIZE(indices19) / VERTS_PER_FACE;
7421     DWORD flags19 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7422     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};
7423     const DWORD adjacency19[] = {-1, 1, -1, -1, -1, 0};
7424     const struct vertex_texcoord_ushort2n exp_vertices19[] =
7425     {
7426         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7427         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7428         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7429 
7430         {{ 2.0f,  3.0f,  0.f}, {65535, 65535}},
7431         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7432     };
7433     const DWORD exp_indices19[] = {0, 1, 2, 3, 4, 2};
7434     const DWORD exp_face_remap19[] = {0, 1};
7435     const DWORD exp_vertex_remap19[] = {0, 1, 2, 3, 4, -1};
7436     const DWORD exp_new_num_vertices19 = ARRAY_SIZE(exp_vertices19);
7437     /* Test 20.  Weld normal as SHORT4 instead of D3DXVECTOR3. */
7438     const struct vertex_normal_short4 vertices20[] =
7439     {
7440         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7441         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7442         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7443 
7444         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7445         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7446         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7447     };
7448     const DWORD indices20[] = {0, 1, 2, 3, 4, 5};
7449     const DWORD attributes20[] = {0, 0};
7450     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
7451     const UINT num_faces20 = ARRAY_SIZE(indices20) / VERTS_PER_FACE;
7452     DWORD flags20 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7453     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};
7454     const DWORD adjacency20[] = {-1, 1, -1, -1, -1, 0};
7455     const struct vertex_normal_short4 exp_vertices20[] =
7456     {
7457         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7458         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7459         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7460 
7461         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7462         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7463     };
7464     const DWORD exp_indices20[] = {0, 1, 2, 3, 4, 2};
7465     const DWORD exp_face_remap20[] = {0, 1};
7466     const DWORD exp_vertex_remap20[] = {0, 1, 2, 3, 4, -1};
7467     const DWORD exp_new_num_vertices20 = ARRAY_SIZE(exp_vertices20);
7468     /* Test 21.  Weld normal as SHORT4N instead of D3DXVECTOR3. */
7469     const struct vertex_normal_short4 vertices21[] =
7470     {
7471         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7472         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7473         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7474 
7475         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7476         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7477         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7478     };
7479     const DWORD indices21[] = {0, 1, 2, 3, 4, 5};
7480     const DWORD attributes21[] = {0, 0};
7481     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
7482     const UINT num_faces21 = ARRAY_SIZE(indices21) / VERTS_PER_FACE;
7483     DWORD flags21 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7484     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};
7485     const DWORD adjacency21[] = {-1, 1, -1, -1, -1, 0};
7486     const struct vertex_normal_short4 exp_vertices21[] =
7487     {
7488         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7489         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7490         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7491 
7492         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7493         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7494     };
7495     const DWORD exp_indices21[] = {0, 1, 2, 3, 4, 2};
7496     const DWORD exp_face_remap21[] = {0, 1};
7497     const DWORD exp_vertex_remap21[] = {0, 1, 2, 3, 4, -1};
7498     const DWORD exp_new_num_vertices21 = ARRAY_SIZE(exp_vertices21);
7499     /* Test 22.  Weld normal as USHORT4N instead of D3DXVECTOR3. */
7500     const struct vertex_normal_short4 vertices22[] =
7501     {
7502         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7503         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7504         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7505 
7506         {{ 3.0f,  3.0f,  0.f}, {-1, -1, -1, -1}},
7507         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7508         {{ 1.0f,  0.0f,  0.f}, {-2, -2, -2, -2}},
7509     };
7510     const DWORD indices22[] = {0, 1, 2, 3, 4, 5};
7511     const DWORD attributes22[] = {0, 0};
7512     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
7513     const UINT num_faces22 = ARRAY_SIZE(indices22) / VERTS_PER_FACE;
7514     DWORD flags22 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7515     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};
7516     const DWORD adjacency22[] = {-1, 1, -1, -1, -1, 0};
7517     const struct vertex_normal_short4 exp_vertices22[] =
7518     {
7519         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7520         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7521         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7522 
7523         {{ 2.0f,  3.0f,  0.f}, {-1, -1, -1, -1}},
7524         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7525     };
7526     const DWORD exp_indices22[] = {0, 1, 2, 3, 4, 2};
7527     const DWORD exp_face_remap22[] = {0, 1};
7528     const DWORD exp_vertex_remap22[] = {0, 1, 2, 3, 4, -1};
7529     const DWORD exp_new_num_vertices22 = ARRAY_SIZE(exp_vertices22);
7530     /* Test 23. Weld texture coordinates as FLOAT16_2. Similar to test 11, but
7531      * with texture coordinates converted to float16 in hex. */
7532     const struct vertex_texcoord_float16_2 vertices23[] =
7533     {
7534         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7535         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7536         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7537 
7538         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
7539         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7540         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7541     };
7542     const DWORD indices23[] = {0, 1, 2, 3, 4, 5};
7543     const DWORD attributes23[] = {0, 0};
7544     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
7545     const UINT num_faces23 = ARRAY_SIZE(indices23) / VERTS_PER_FACE;
7546     DWORD flags23 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7547     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};
7548     const DWORD adjacency23[] = {-1, 1, -1, -1, -1, 0};
7549     const struct vertex_texcoord_float16_2 exp_vertices23[] =
7550     {
7551         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7552         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7553         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7554 
7555         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7556         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7557     };
7558     const DWORD exp_indices23[] = {0, 1, 2, 1, 3, 4};
7559     const DWORD exp_face_remap23[] = {0, 1};
7560     const DWORD exp_vertex_remap23[] = {0, 1, 2, 4, 5, -1};
7561     const DWORD exp_new_num_vertices23 = ARRAY_SIZE(exp_vertices23);
7562     /* Test 24. Weld texture coordinates as FLOAT16_4. Similar to test 24. */
7563     const struct vertex_texcoord_float16_4 vertices24[] =
7564     {
7565         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7566         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7567         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7568 
7569         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0x3266, 0x34cd}},
7570         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7571         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7572     };
7573     const DWORD indices24[] = {0, 1, 2, 3, 4, 5};
7574     const DWORD attributes24[] = {0, 0};
7575     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
7576     const UINT num_faces24 = ARRAY_SIZE(indices24) / VERTS_PER_FACE;
7577     DWORD flags24 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7578     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};
7579     const DWORD adjacency24[] = {-1, 1, -1, -1, -1, 0};
7580     const struct vertex_texcoord_float16_4 exp_vertices24[] =
7581     {
7582         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7583         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7584         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7585 
7586         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7587         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7588     };
7589     const DWORD exp_indices24[] = {0, 1, 2, 1, 3, 4};
7590     const DWORD exp_face_remap24[] = {0, 1};
7591     const DWORD exp_vertex_remap24[] = {0, 1, 2, 4, 5, -1};
7592     const DWORD exp_new_num_vertices24 = ARRAY_SIZE(exp_vertices24);
7593     /* Test 25. Weld texture coordinates with usage index 10 (TEXCOORD10). The
7594      * usage index is capped at 7, so the epsilon for TEXCOORD7 is used instead.
7595      */
7596     const struct vertex_texcoord vertices25[] =
7597     {
7598         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7599         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7600         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7601 
7602         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7603         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7604         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7605     };
7606     const DWORD indices25[] = {0, 1, 2, 3, 4, 5};
7607     const DWORD attributes25[] = {0, 0};
7608     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
7609     const UINT num_faces25 = ARRAY_SIZE(indices25) / VERTS_PER_FACE;
7610     DWORD flags25 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7611     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};
7612     const DWORD adjacency25[] = {-1, 1, -1, -1, -1, 0};
7613     const struct vertex_texcoord exp_vertices25[] =
7614     {
7615         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7616         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7617         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7618 
7619         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7620         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7621     };
7622     const DWORD exp_indices25[] = {0, 1, 2, 1, 3, 4};
7623     const DWORD exp_face_remap25[] = {0, 1};
7624     const DWORD exp_vertex_remap25[] = {0, 1, 2, 4, 5, -1};
7625     const DWORD exp_new_num_vertices25 = ARRAY_SIZE(exp_vertices25);
7626     /* Test 26. Weld color with usage index larger than 1. Shows that none of
7627      * the epsilon values are used. */
7628     const struct vertex_color vertices26[] =
7629     {
7630         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7631         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7632         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7633 
7634         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7635         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7636         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7637     };
7638     const DWORD indices26[] = {0, 1, 2, 3, 4, 5};
7639     const DWORD attributes26[] = {0, 0};
7640     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
7641     const UINT num_faces26 = ARRAY_SIZE(indices26) / VERTS_PER_FACE;
7642     DWORD flags26 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7643     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};
7644     const DWORD adjacency26[] = {-1, 1, -1, -1, -1, 0};
7645     const struct vertex_color exp_vertices26[] =
7646     {
7647         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7648         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7649         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7650 
7651         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7652         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7653         {{ 0.0f,  0.0f,  0.f}, 0x01010101},
7654     };
7655     const DWORD exp_indices26[] = {0, 1, 2, 3, 4, 5};
7656     const DWORD exp_face_remap26[] = {0, 1};
7657     const DWORD exp_vertex_remap26[] = {0, 1, 2, 3, 4, 5};
7658     const DWORD exp_new_num_vertices26 = ARRAY_SIZE(exp_vertices26);
7659     /* Test 27. Weld color with usage index 1 (specular). */
7660     /* Previously this test used float color values and index > 1 but that case
7661      * appears to be effectively unhandled in native so the test gave
7662      * inconsistent results. */
7663     const struct vertex_color vertices27[] =
7664     {
7665         {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
7666         {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
7667         {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
7668 
7669         {{ 3.0f,  3.0f,  0.0f}, 0x11213141},
7670         {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
7671         {{ 1.0f,  0.0f,  0.0f}, 0x51617181},
7672     };
7673     const DWORD indices27[] = {0, 1, 2, 3, 4, 5};
7674     const DWORD attributes27[] = {0, 0};
7675     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
7676     const UINT num_faces27 = ARRAY_SIZE(indices27) / VERTS_PER_FACE;
7677     DWORD flags27 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7678     const D3DXWELDEPSILONS epsilons27 =
7679     {
7680         1.1f, 0.0f, 0.0f, 0.0f, 2.0f / 255.0f, 0.0f,
7681         {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f
7682     };
7683     const DWORD adjacency27[] = {-1, 1, -1, -1, -1, 0};
7684     const struct vertex_color exp_vertices27[] =
7685     {
7686         {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
7687         {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
7688         {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
7689 
7690         {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
7691     };
7692     const DWORD exp_indices27[] = {0, 1, 2, 1, 3, 2};
7693     const DWORD exp_face_remap27[] = {0, 1};
7694     const DWORD exp_vertex_remap27[] = {0, 1, 2, 4, -1, -1};
7695     const DWORD exp_new_num_vertices27 = ARRAY_SIZE(exp_vertices27);
7696     /* Test 28. Weld one normal with UDEC3. */
7697     const DWORD dword_udec3_zero = init_udec3_dword(0, 0, 0, 1);
7698     const DWORD dword_udec3_1023 = init_udec3_dword(1023, 1023, 1023, 1);
7699     const DWORD dword_udec3_1022 = init_udec3_dword(1022, 1022, 1022, 1);
7700     const struct vertex_normal_udec3 vertices28[] =
7701     {
7702         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7703         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7704         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7705 
7706         {{ 3.0f,  3.0f,  0.f}, dword_udec3_1023},
7707         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7708         {{ 1.0f,  0.0f,  0.f}, dword_udec3_1022},
7709     };
7710     const DWORD indices28[] = {0, 1, 2, 3, 4, 5};
7711     const DWORD attributes28[] = {0, 0};
7712     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
7713     const UINT num_faces28 = ARRAY_SIZE(indices28) / VERTS_PER_FACE;
7714     DWORD flags28 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7715     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};
7716     const DWORD adjacency28[] = {-1, 1, -1, -1, -1, 0};
7717     const struct vertex_normal_udec3 exp_vertices28[] =
7718     {
7719         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7720         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7721         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7722 
7723         {{ 2.0f,  3.0f,  0.f}, dword_udec3_1023},
7724         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7725     };
7726     const DWORD exp_indices28[] = {0, 1, 2, 3, 4, 2};
7727     const DWORD exp_face_remap28[] = {0, 1};
7728     const DWORD exp_vertex_remap28[] = {0, 1, 2, 3, 4, -1};
7729     const DWORD exp_new_num_vertices28 = ARRAY_SIZE(exp_vertices28);
7730     /* Test 29. Weld one normal with DEC3N. */
7731     const DWORD dword_dec3n_zero = init_dec3n_dword(0, 0, 0, 1);
7732     const DWORD dword_dec3n_511 = init_dec3n_dword(511, 511, 511, 1);
7733     const DWORD dword_dec3n_510 = init_dec3n_dword(510, 510, 510, 1);
7734     const struct vertex_normal_dec3n vertices29[] =
7735     {
7736         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7737         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7738         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7739 
7740         {{ 3.0f,  3.0f,  0.f}, dword_dec3n_511},
7741         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7742         {{ 1.0f,  0.0f,  0.f}, dword_dec3n_510},
7743     };
7744     const DWORD indices29[] = {0, 1, 2, 3, 4, 5};
7745     const DWORD attributes29[] = {0, 0};
7746     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
7747     const UINT num_faces29 = ARRAY_SIZE(indices29) / VERTS_PER_FACE;
7748     DWORD flags29 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7749     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};
7750     const DWORD adjacency29[] = {-1, 1, -1, -1, -1, 0};
7751     const struct vertex_normal_dec3n exp_vertices29[] =
7752     {
7753         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7754         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7755         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7756 
7757         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_511},
7758         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7759     };
7760     const DWORD exp_indices29[] = {0, 1, 2, 3, 4, 2};
7761     const DWORD exp_face_remap29[] = {0, 1};
7762     const DWORD exp_vertex_remap29[] = {0, 1, 2, 3, 4, -1};
7763     const DWORD exp_new_num_vertices29 = ARRAY_SIZE(exp_vertices29);
7764     /* All mesh data */
7765     DWORD *adjacency_out = NULL;
7766     DWORD *face_remap = NULL;
7767     ID3DXMesh *mesh = NULL;
7768     ID3DXBuffer *vertex_remap = NULL;
7769     struct
7770     {
7771         const BYTE *vertices;
7772         const DWORD *indices;
7773         const DWORD *attributes;
7774         const DWORD num_vertices;
7775         const DWORD num_faces;
7776         const DWORD options;
7777         D3DVERTEXELEMENT9 *declaration;
7778         const UINT vertex_size;
7779         const DWORD flags;
7780         const D3DXWELDEPSILONS *epsilons;
7781         const DWORD *adjacency;
7782         const BYTE *exp_vertices;
7783         const DWORD *exp_indices;
7784         const DWORD *exp_face_remap;
7785         const DWORD *exp_vertex_remap;
7786         const DWORD exp_new_num_vertices;
7787     }
7788     tc[] =
7789     {
7790         {
7791             (BYTE*)vertices0,
7792             indices0,
7793             attributes0,
7794             num_vertices0,
7795             num_faces0,
7796             options,
7797             declaration_normal,
7798             vertex_size_normal,
7799             flags0,
7800             NULL,
7801             adjacency0,
7802             (BYTE*)exp_vertices0,
7803             exp_indices0,
7804             exp_face_remap0,
7805             exp_vertex_remap0,
7806             exp_new_num_vertices0
7807         },
7808         {
7809             (BYTE*)vertices1,
7810             indices1,
7811             attributes1,
7812             num_vertices1,
7813             num_faces1,
7814             options,
7815             declaration_normal,
7816             vertex_size_normal,
7817             flags1,
7818             NULL,
7819             adjacency1,
7820             (BYTE*)exp_vertices1,
7821             exp_indices1,
7822             exp_face_remap1,
7823             exp_vertex_remap1,
7824             exp_new_num_vertices1
7825         },
7826         {
7827             (BYTE*)vertices2,
7828             indices2,
7829             attributes2,
7830             num_vertices2,
7831             num_faces2,
7832             options,
7833             declaration_normal,
7834             vertex_size_normal,
7835             flags2,
7836             &epsilons2,
7837             adjacency2,
7838             (BYTE*)exp_vertices2,
7839             exp_indices2,
7840             exp_face_remap2,
7841             exp_vertex_remap2,
7842             exp_new_num_vertices2
7843         },
7844         {
7845             (BYTE*)vertices3,
7846             indices3,
7847             attributes3,
7848             num_vertices3,
7849             num_faces3,
7850             options,
7851             declaration_normal,
7852             vertex_size_normal,
7853             flags3,
7854             &epsilons3,
7855             adjacency3,
7856             (BYTE*)exp_vertices3,
7857             exp_indices3,
7858             exp_face_remap3,
7859             exp_vertex_remap3,
7860             exp_new_num_vertices3
7861         },
7862         {
7863             (BYTE*)vertices4,
7864             indices4,
7865             attributes4,
7866             num_vertices4,
7867             num_faces4,
7868             options,
7869             declaration_normal,
7870             vertex_size_normal,
7871             flags4,
7872             &epsilons4,
7873             adjacency4,
7874             (BYTE*)exp_vertices4,
7875             exp_indices4,
7876             exp_face_remap4,
7877             exp_vertex_remap4,
7878             exp_new_num_vertices4
7879         },
7880         /* Unusual ordering. */
7881         {
7882             (BYTE*)vertices5,
7883             indices5,
7884             attributes5,
7885             num_vertices5,
7886             num_faces5,
7887             options,
7888             declaration_normal,
7889             vertex_size_normal,
7890             flags5,
7891             NULL,
7892             adjacency5,
7893             (BYTE*)exp_vertices5,
7894             exp_indices5,
7895             exp_face_remap5,
7896             exp_vertex_remap5,
7897             exp_new_num_vertices5
7898         },
7899         {
7900             (BYTE*)vertices6,
7901             indices6,
7902             attributes6,
7903             num_vertices6,
7904             num_faces6,
7905             options,
7906             declaration_normal,
7907             vertex_size_normal,
7908             flags6,
7909             &epsilons6,
7910             adjacency6,
7911             (BYTE*)exp_vertices6,
7912             exp_indices6,
7913             exp_face_remap6,
7914             exp_vertex_remap6,
7915             exp_new_num_vertices6
7916         },
7917         {
7918             (BYTE*)vertices6,
7919             (DWORD*)indices6_16bit,
7920             attributes6,
7921             num_vertices6,
7922             num_faces6,
7923             options_16bit,
7924             declaration_normal,
7925             vertex_size_normal,
7926             flags6,
7927             &epsilons6,
7928             adjacency6,
7929             (BYTE*)exp_vertices6,
7930             exp_indices6,
7931             exp_face_remap6,
7932             exp_vertex_remap6,
7933             exp_new_num_vertices6
7934         },
7935         {
7936             (BYTE*)vertices8,
7937             indices8,
7938             attributes8,
7939             num_vertices8,
7940             num_faces8,
7941             options,
7942             declaration_normal,
7943             vertex_size_normal,
7944             flags8,
7945             &epsilons8,
7946             adjacency8,
7947             (BYTE*)exp_vertices8,
7948             exp_indices8,
7949             exp_face_remap8,
7950             exp_vertex_remap8,
7951             exp_new_num_vertices8
7952         },
7953         {
7954             (BYTE*)vertices9,
7955             indices9,
7956             attributes9,
7957             num_vertices9,
7958             num_faces9,
7959             options,
7960             declaration_normal,
7961             vertex_size_normal,
7962             flags9,
7963             &epsilons9,
7964             adjacency9,
7965             (BYTE*)exp_vertices9,
7966             exp_indices9,
7967             exp_face_remap9,
7968             exp_vertex_remap9,
7969             exp_new_num_vertices9
7970         },
7971         {
7972             (BYTE*)vertices10,
7973             indices10,
7974             attributes10,
7975             num_vertices10,
7976             num_faces10,
7977             options,
7978             declaration_blendweight,
7979             vertex_size_blendweight,
7980             flags10,
7981             &epsilons10,
7982             adjacency10,
7983             (BYTE*)exp_vertices10,
7984             exp_indices10,
7985             exp_face_remap10,
7986             exp_vertex_remap10,
7987             exp_new_num_vertices10
7988         },
7989         {
7990             (BYTE*)vertices11,
7991             indices11,
7992             attributes11,
7993             num_vertices11,
7994             num_faces11,
7995             options,
7996             declaration_texcoord,
7997             vertex_size_texcoord,
7998             flags11,
7999             &epsilons11,
8000             adjacency11,
8001             (BYTE*)exp_vertices11,
8002             exp_indices11,
8003             exp_face_remap11,
8004             exp_vertex_remap11,
8005             exp_new_num_vertices11
8006         },
8007         {
8008             (BYTE*)vertices12,
8009             indices12,
8010             attributes12,
8011             num_vertices12,
8012             num_faces12,
8013             options,
8014             declaration_color,
8015             vertex_size_color,
8016             flags12,
8017             &epsilons12,
8018             adjacency12,
8019             (BYTE*)exp_vertices12,
8020             exp_indices12,
8021             exp_face_remap12,
8022             exp_vertex_remap12,
8023             exp_new_num_vertices12
8024         },
8025         {
8026             (BYTE*)vertices13,
8027             indices13,
8028             attributes13,
8029             num_vertices13,
8030             num_faces13,
8031             options,
8032             declaration_normal3,
8033             vertex_size_normal,
8034             flags13,
8035             &epsilons13,
8036             adjacency13,
8037             (BYTE*)exp_vertices13,
8038             exp_indices13,
8039             exp_face_remap13,
8040             exp_vertex_remap13,
8041             exp_new_num_vertices13
8042         },
8043         {
8044             (BYTE*)vertices14,
8045             indices14,
8046             attributes14,
8047             num_vertices14,
8048             num_faces14,
8049             options,
8050             declaration_color,
8051             vertex_size_color,
8052             flags14,
8053             &epsilons14,
8054             adjacency14,
8055             (BYTE*)exp_vertices14,
8056             exp_indices14,
8057             exp_face_remap14,
8058             exp_vertex_remap14,
8059             exp_new_num_vertices14
8060         },
8061         {
8062             (BYTE*)vertices15,
8063             indices15,
8064             attributes15,
8065             num_vertices15,
8066             num_faces15,
8067             options,
8068             declaration_color_ubyte4n,
8069             vertex_size_color_ubyte4, /* UBYTE4 same size as UBYTE4N */
8070             flags15,
8071             &epsilons15,
8072             adjacency15,
8073             (BYTE*)exp_vertices15,
8074             exp_indices15,
8075             exp_face_remap15,
8076             exp_vertex_remap15,
8077             exp_new_num_vertices15
8078         },
8079         {
8080             (BYTE*)vertices16,
8081             indices16,
8082             attributes16,
8083             num_vertices16,
8084             num_faces16,
8085             options,
8086             declaration_color_ubyte4,
8087             vertex_size_color_ubyte4,
8088             flags16,
8089             &epsilons16,
8090             adjacency16,
8091             (BYTE*)exp_vertices16,
8092             exp_indices16,
8093             exp_face_remap16,
8094             exp_vertex_remap16,
8095             exp_new_num_vertices16
8096         },
8097         {
8098             (BYTE*)vertices17,
8099             indices17,
8100             attributes17,
8101             num_vertices17,
8102             num_faces17,
8103             options,
8104             declaration_texcoord_short2,
8105             vertex_size_texcoord_short2,
8106             flags17,
8107             &epsilons17,
8108             adjacency17,
8109             (BYTE*)exp_vertices17,
8110             exp_indices17,
8111             exp_face_remap17,
8112             exp_vertex_remap17,
8113             exp_new_num_vertices17
8114         },
8115         {
8116             (BYTE*)vertices18,
8117             indices18,
8118             attributes18,
8119             num_vertices18,
8120             num_faces18,
8121             options,
8122             declaration_texcoord_short2n,
8123             vertex_size_texcoord_short2, /* SHORT2 same size as SHORT2N */
8124             flags18,
8125             &epsilons18,
8126             adjacency18,
8127             (BYTE*)exp_vertices18,
8128             exp_indices18,
8129             exp_face_remap18,
8130             exp_vertex_remap18,
8131             exp_new_num_vertices18
8132         },
8133         {
8134             (BYTE*)vertices19,
8135             indices19,
8136             attributes19,
8137             num_vertices19,
8138             num_faces19,
8139             options,
8140             declaration_texcoord_ushort2n,
8141             vertex_size_texcoord_short2, /* SHORT2 same size as USHORT2N */
8142             flags19,
8143             &epsilons19,
8144             adjacency19,
8145             (BYTE*)exp_vertices19,
8146             exp_indices19,
8147             exp_face_remap19,
8148             exp_vertex_remap19,
8149             exp_new_num_vertices19
8150         },
8151         {
8152             (BYTE*)vertices20,
8153             indices20,
8154             attributes20,
8155             num_vertices20,
8156             num_faces20,
8157             options,
8158             declaration_normal_short4,
8159             vertex_size_normal_short4,
8160             flags20,
8161             &epsilons20,
8162             adjacency20,
8163             (BYTE*)exp_vertices20,
8164             exp_indices20,
8165             exp_face_remap20,
8166             exp_vertex_remap20,
8167             exp_new_num_vertices20
8168         },
8169         {
8170             (BYTE*)vertices21,
8171             indices21,
8172             attributes21,
8173             num_vertices21,
8174             num_faces21,
8175             options,
8176             declaration_normal_short4n,
8177             vertex_size_normal_short4, /* SHORT4 same size as SHORT4N */
8178             flags21,
8179             &epsilons21,
8180             adjacency21,
8181             (BYTE*)exp_vertices21,
8182             exp_indices21,
8183             exp_face_remap21,
8184             exp_vertex_remap21,
8185             exp_new_num_vertices21
8186         },
8187         {
8188             (BYTE*)vertices22,
8189             indices22,
8190             attributes22,
8191             num_vertices22,
8192             num_faces22,
8193             options,
8194             declaration_normal_ushort4n,
8195             vertex_size_normal_short4, /* SHORT4 same size as USHORT4N */
8196             flags22,
8197             &epsilons22,
8198             adjacency22,
8199             (BYTE*)exp_vertices22,
8200             exp_indices22,
8201             exp_face_remap22,
8202             exp_vertex_remap22,
8203             exp_new_num_vertices22
8204         },
8205         {
8206             (BYTE*)vertices23,
8207             indices23,
8208             attributes23,
8209             num_vertices23,
8210             num_faces23,
8211             options,
8212             declaration_texcoord_float16_2,
8213             vertex_size_texcoord_float16_2,
8214             flags23,
8215             &epsilons23,
8216             adjacency23,
8217             (BYTE*)exp_vertices23,
8218             exp_indices23,
8219             exp_face_remap23,
8220             exp_vertex_remap23,
8221             exp_new_num_vertices23
8222         },
8223         {
8224             (BYTE*)vertices24,
8225             indices24,
8226             attributes24,
8227             num_vertices24,
8228             num_faces24,
8229             options,
8230             declaration_texcoord_float16_4,
8231             vertex_size_texcoord_float16_4,
8232             flags24,
8233             &epsilons24,
8234             adjacency24,
8235             (BYTE*)exp_vertices24,
8236             exp_indices24,
8237             exp_face_remap24,
8238             exp_vertex_remap24,
8239             exp_new_num_vertices24
8240         },
8241         {
8242             (BYTE*)vertices25,
8243             indices25,
8244             attributes25,
8245             num_vertices25,
8246             num_faces25,
8247             options,
8248             declaration_texcoord10,
8249             vertex_size_texcoord,
8250             flags25,
8251             &epsilons25,
8252             adjacency25,
8253             (BYTE*)exp_vertices25,
8254             exp_indices25,
8255             exp_face_remap25,
8256             exp_vertex_remap25,
8257             exp_new_num_vertices25
8258         },
8259         {
8260             (BYTE*)vertices26,
8261             indices26,
8262             attributes26,
8263             num_vertices26,
8264             num_faces26,
8265             options,
8266             declaration_color2,
8267             vertex_size_color,
8268             flags26,
8269             &epsilons26,
8270             adjacency26,
8271             (BYTE*)exp_vertices26,
8272             exp_indices26,
8273             exp_face_remap26,
8274             exp_vertex_remap26,
8275             exp_new_num_vertices26
8276         },
8277         {
8278             (BYTE*)vertices27,
8279             indices27,
8280             attributes27,
8281             num_vertices27,
8282             num_faces27,
8283             options,
8284             declaration_color1,
8285             vertex_size_color,
8286             flags27,
8287             &epsilons27,
8288             adjacency27,
8289             (BYTE*)exp_vertices27,
8290             exp_indices27,
8291             exp_face_remap27,
8292             exp_vertex_remap27,
8293             exp_new_num_vertices27
8294         },
8295         {
8296             (BYTE*)vertices28,
8297             indices28,
8298             attributes28,
8299             num_vertices28,
8300             num_faces28,
8301             options,
8302             declaration_normal_udec3,
8303             vertex_size_normal_udec3,
8304             flags28,
8305             &epsilons28,
8306             adjacency28,
8307             (BYTE*)exp_vertices28,
8308             exp_indices28,
8309             exp_face_remap28,
8310             exp_vertex_remap28,
8311             exp_new_num_vertices28
8312         },
8313         {
8314             (BYTE*)vertices29,
8315             indices29,
8316             attributes29,
8317             num_vertices29,
8318             num_faces29,
8319             options,
8320             declaration_normal_dec3n,
8321             vertex_size_normal_dec3n,
8322             flags29,
8323             &epsilons29,
8324             adjacency29,
8325             (BYTE*)exp_vertices29,
8326             exp_indices29,
8327             exp_face_remap29,
8328             exp_vertex_remap29,
8329             exp_new_num_vertices29
8330         }
8331     };
8332 #ifdef __REACTOS__
8333 #undef up
8334 #endif
8335 
8336     test_context = new_test_context();
8337     if (!test_context)
8338     {
8339         skip("Couldn't create test context\n");
8340         goto cleanup;
8341     }
8342 
8343     for (i = 0; i < ARRAY_SIZE(tc); i++)
8344     {
8345         DWORD j;
8346         DWORD *vertex_remap_ptr;
8347         DWORD new_num_vertices;
8348 
8349         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
8350                             tc[i].declaration, test_context->device, &mesh,
8351                             tc[i].vertices, tc[i].vertex_size,
8352                             tc[i].indices, tc[i].attributes);
8353         if (FAILED(hr))
8354         {
8355             skip("Couldn't initialize test mesh %d.\n", i);
8356             goto cleanup;
8357         }
8358 
8359         /* Allocate out parameters */
8360         adjacency_out = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency_out));
8361         if (!adjacency_out)
8362         {
8363             skip("Couldn't allocate adjacency_out array.\n");
8364             goto cleanup;
8365         }
8366         face_remap = HeapAlloc(GetProcessHeap(), 0, tc[i].num_faces * sizeof(*face_remap));
8367         if (!face_remap)
8368         {
8369             skip("Couldn't allocate face_remap array.\n");
8370             goto cleanup;
8371         }
8372 
8373         hr = D3DXWeldVertices(mesh, tc[i].flags, tc[i].epsilons, tc[i].adjacency,
8374                               adjacency_out, face_remap, &vertex_remap);
8375         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
8376         /* Check number of vertices*/
8377         new_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
8378         ok(new_num_vertices == tc[i].exp_new_num_vertices,
8379            "Mesh %d: new_num_vertices == %d, expected %d.\n",
8380            i, new_num_vertices, tc[i].exp_new_num_vertices);
8381         /* Check index buffer */
8382         if (tc[i].options & D3DXMESH_32BIT)
8383         {
8384             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices);
8385             if (FAILED(hr))
8386             {
8387                 skip("Couldn't lock index buffer.\n");
8388                 goto cleanup;
8389             }
8390             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8391             {
8392                 ok(indices[j] == tc[i].exp_indices[j],
8393                    "Mesh %d: indices[%d] == %d, expected %d\n",
8394                    i, j, indices[j], tc[i].exp_indices[j]);
8395             }
8396         }
8397         else
8398         {
8399             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices_16bit);
8400             if (FAILED(hr))
8401             {
8402                 skip("Couldn't lock index buffer.\n");
8403                 goto cleanup;
8404             }
8405             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8406             {
8407                 ok(indices_16bit[j] == tc[i].exp_indices[j],
8408                    "Mesh %d: indices_16bit[%d] == %d, expected %d\n",
8409                    i, j, indices_16bit[j], tc[i].exp_indices[j]);
8410             }
8411         }
8412         mesh->lpVtbl->UnlockIndexBuffer(mesh);
8413         indices = NULL;
8414         indices_16bit = NULL;
8415         /* Check adjacency_out */
8416         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8417         {
8418             ok(adjacency_out[j] == tc[i].adjacency[j],
8419                "Mesh %d: adjacency_out[%d] == %d, expected %d\n",
8420                i, j, adjacency_out[j], tc[i].adjacency[j]);
8421         }
8422         /* Check face_remap */
8423         for (j = 0; j < tc[i].num_faces; j++)
8424         {
8425             ok(face_remap[j] == tc[i].exp_face_remap[j],
8426                "Mesh %d: face_remap[%d] == %d, expected %d\n",
8427                i, j, face_remap[j], tc[i].exp_face_remap[j]);
8428         }
8429         /* Check vertex_remap */
8430         vertex_remap_ptr = vertex_remap->lpVtbl->GetBufferPointer(vertex_remap);
8431         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8432         {
8433             ok(vertex_remap_ptr[j] == tc[i].exp_vertex_remap[j],
8434                "Mesh %d: vertex_remap_ptr[%d] == %d, expected %d\n",
8435                i, j, vertex_remap_ptr[j], tc[i].exp_vertex_remap[j]);
8436         }
8437         /* Check vertex buffer */
8438         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void*)&vertices);
8439         if (FAILED(hr))
8440         {
8441             skip("Couldn't lock vertex buffer.\n");
8442             goto cleanup;
8443         }
8444         /* Check contents of re-ordered vertex buffer */
8445         for (j = 0; j < tc[i].exp_new_num_vertices; j++)
8446         {
8447             int index = tc[i].vertex_size*j;
8448             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].declaration);
8449         }
8450         mesh->lpVtbl->UnlockVertexBuffer(mesh);
8451         vertices = NULL;
8452 
8453         /* Free mesh and output data */
8454         HeapFree(GetProcessHeap(), 0, adjacency_out);
8455         adjacency_out = NULL;
8456         HeapFree(GetProcessHeap(), 0, face_remap);
8457         face_remap = NULL;
8458         vertex_remap->lpVtbl->Release(vertex_remap);
8459         vertex_remap = NULL;
8460         mesh->lpVtbl->Release(mesh);
8461         mesh = NULL;
8462     }
8463 
8464 cleanup:
8465     HeapFree(GetProcessHeap(), 0, adjacency_out);
8466     HeapFree(GetProcessHeap(), 0, face_remap);
8467     if (indices) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8468     if (indices_16bit) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8469     if (mesh) mesh->lpVtbl->Release(mesh);
8470     if (vertex_remap) vertex_remap->lpVtbl->Release(vertex_remap);
8471     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
8472     free_test_context(test_context);
8473 }
8474 
8475 static void test_clone_mesh(void)
8476 {
8477     HRESULT hr;
8478     struct test_context *test_context = NULL;
8479     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
8480     D3DVERTEXELEMENT9 declaration_pn[] =
8481     {
8482         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8483         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8484         D3DDECL_END()
8485     };
8486     D3DVERTEXELEMENT9 declaration_pntc[] =
8487     {
8488         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8489         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8490         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8491         D3DDECL_END()
8492     };
8493     D3DVERTEXELEMENT9 declaration_ptcn[] =
8494     {
8495         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8496         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8497         {0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8498         D3DDECL_END()
8499     };
8500     D3DVERTEXELEMENT9 declaration_ptc[] =
8501     {
8502         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8503         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8504         D3DDECL_END()
8505     };
8506     D3DVERTEXELEMENT9 declaration_ptc_float16_2[] =
8507     {
8508         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8509         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8510         D3DDECL_END()
8511     };
8512     D3DVERTEXELEMENT9 declaration_ptc_float16_4[] =
8513     {
8514         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8515         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8516         D3DDECL_END()
8517     };
8518     D3DVERTEXELEMENT9 declaration_ptc_float1[] =
8519     {
8520         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8521         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8522         D3DDECL_END()
8523     };
8524     D3DVERTEXELEMENT9 declaration_ptc_float3[] =
8525     {
8526         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8527         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8528         D3DDECL_END()
8529     };
8530     D3DVERTEXELEMENT9 declaration_ptc_float4[] =
8531     {
8532         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8533         {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8534         D3DDECL_END()
8535     };
8536     D3DVERTEXELEMENT9 declaration_ptc_d3dcolor[] =
8537     {
8538         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8539         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8540         D3DDECL_END()
8541     };
8542     D3DVERTEXELEMENT9 declaration_ptc_ubyte4[] =
8543     {
8544         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8545         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8546         D3DDECL_END()
8547     };
8548     D3DVERTEXELEMENT9 declaration_ptc_ubyte4n[] =
8549     {
8550         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8551         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8552         D3DDECL_END()
8553     };
8554     D3DVERTEXELEMENT9 declaration_ptc_short2[] =
8555     {
8556         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8557         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8558         D3DDECL_END()
8559     };
8560     D3DVERTEXELEMENT9 declaration_ptc_short4[] =
8561     {
8562         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8563         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8564         D3DDECL_END()
8565     };
8566     D3DVERTEXELEMENT9 declaration_ptc_short2n[] =
8567     {
8568         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8569         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8570         D3DDECL_END()
8571     };
8572     D3DVERTEXELEMENT9 declaration_ptc_short4n[] =
8573     {
8574         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8575         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8576         D3DDECL_END()
8577     };
8578     D3DVERTEXELEMENT9 declaration_ptc_ushort2n[] =
8579     {
8580         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8581         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8582         D3DDECL_END()
8583     };
8584     D3DVERTEXELEMENT9 declaration_ptc_ushort4n[] =
8585     {
8586         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8587         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8588         D3DDECL_END()
8589     };
8590     D3DVERTEXELEMENT9 declaration_ptc_float16_2_partialu[] =
8591     {
8592         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8593         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_PARTIALU, D3DDECLUSAGE_TEXCOORD, 0},
8594         D3DDECL_END()
8595     };
8596     D3DVERTEXELEMENT9 declaration_pntc1[] =
8597     {
8598         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8599         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8600         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
8601         D3DDECL_END()
8602     };
8603     const unsigned int VERTS_PER_FACE = 3;
8604     BYTE *vertices = NULL;
8605     INT i;
8606     struct vertex_pn
8607     {
8608         D3DXVECTOR3 position;
8609         D3DXVECTOR3 normal;
8610     };
8611     struct vertex_pntc
8612     {
8613         D3DXVECTOR3 position;
8614         D3DXVECTOR3 normal;
8615         D3DXVECTOR2 texcoords;
8616     };
8617     struct vertex_ptcn
8618     {
8619         D3DXVECTOR3 position;
8620         D3DXVECTOR2 texcoords;
8621         D3DXVECTOR3 normal;
8622     };
8623     struct vertex_ptc
8624     {
8625         D3DXVECTOR3 position;
8626         D3DXVECTOR2 texcoords;
8627     };
8628     struct vertex_ptc_float16_2
8629     {
8630         D3DXVECTOR3 position;
8631         WORD texcoords[2]; /* float16_2 */
8632     };
8633     struct vertex_ptc_float16_4
8634     {
8635         D3DXVECTOR3 position;
8636         WORD texcoords[4]; /* float16_4 */
8637     };
8638     struct vertex_ptc_float1
8639     {
8640         D3DXVECTOR3 position;
8641         FLOAT texcoords;
8642     };
8643     struct vertex_ptc_float3
8644     {
8645         D3DXVECTOR3 position;
8646         FLOAT texcoords[3];
8647     };
8648     struct vertex_ptc_float4
8649     {
8650         D3DXVECTOR3 position;
8651         FLOAT texcoords[4];
8652     };
8653     struct vertex_ptc_d3dcolor
8654     {
8655         D3DXVECTOR3 position;
8656         BYTE texcoords[4];
8657     };
8658     struct vertex_ptc_ubyte4
8659     {
8660         D3DXVECTOR3 position;
8661         BYTE texcoords[4];
8662     };
8663     struct vertex_ptc_ubyte4n
8664     {
8665         D3DXVECTOR3 position;
8666         BYTE texcoords[4];
8667     };
8668     struct vertex_ptc_short2
8669     {
8670         D3DXVECTOR3 position;
8671         SHORT texcoords[2];
8672     };
8673     struct vertex_ptc_short4
8674     {
8675         D3DXVECTOR3 position;
8676         SHORT texcoords[4];
8677     };
8678     struct vertex_ptc_ushort2n
8679     {
8680         D3DXVECTOR3 position;
8681         USHORT texcoords[2];
8682     };
8683     struct vertex_ptc_ushort4n
8684     {
8685         D3DXVECTOR3 position;
8686         USHORT texcoords[4];
8687     };
8688     struct vertex_ptc_udec3
8689     {
8690         D3DXVECTOR3 position;
8691         DWORD texcoords;
8692     };
8693     struct vertex_ptc_dec3n
8694     {
8695         D3DXVECTOR3 position;
8696         DWORD texcoords;
8697     };
8698 #ifndef __REACTOS__
8699     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
8700     D3DXVECTOR2 zero_vec2 = {0.0f, 0.0f};
8701 #else
8702 #define up {0.0f, 0.0f, 1.0f}
8703 #define zero_vec2 {0.0f, 0.0f}
8704 #endif
8705     /* Test 0. Check that a mesh can be cloned if the new declaration is the
8706      * same as the one used to create the mesh.
8707      *
8708      * 0--1 3
8709      * | / /|
8710      * |/ / |
8711      * 2 5--4
8712      */
8713     const struct vertex_pn vertices0[] =
8714     {
8715         {{ 0.0f,  3.0f,  0.f}, up},
8716         {{ 2.0f,  3.0f,  0.f}, up},
8717         {{ 0.0f,  0.0f,  0.f}, up},
8718 
8719         {{ 3.0f,  3.0f,  0.f}, up},
8720         {{ 3.0f,  0.0f,  0.f}, up},
8721         {{ 1.0f,  0.0f,  0.f}, up},
8722     };
8723     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
8724     const UINT num_faces0 = ARRAY_SIZE(vertices0) / VERTS_PER_FACE;
8725     const UINT vertex_size0 = sizeof(*vertices0);
8726     /* Test 1. Check that 16-bit indices are handled. */
8727     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
8728     /* Test 2. Check that the size of each vertex is increased and the data
8729      * moved if the new declaration adds an element after the original elements.
8730      */
8731     const struct vertex_pntc exp_vertices2[] =
8732     {
8733         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8734         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8735         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8736 
8737         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8738         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8739         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8740     };
8741     const UINT exp_vertex_size2 = sizeof(*exp_vertices2);
8742     /* Test 3. Check that the size of each vertex is increased and the data
8743      * moved if the new declaration adds an element between the original
8744      * elements.
8745      */
8746     const struct vertex_ptcn exp_vertices3[] =
8747     {
8748         {{ 0.0f,  3.0f,  0.f}, zero_vec2, up},
8749         {{ 2.0f,  3.0f,  0.f}, zero_vec2, up},
8750         {{ 0.0f,  0.0f,  0.f}, zero_vec2, up},
8751 
8752         {{ 3.0f,  3.0f,  0.f}, zero_vec2, up},
8753         {{ 3.0f,  0.0f,  0.f}, zero_vec2, up},
8754         {{ 1.0f,  0.0f,  0.f}, zero_vec2, up},
8755     };
8756     const UINT exp_vertex_size3 = sizeof(*exp_vertices3);
8757     /* Test 4. Test that data types can be converted, e.g. FLOAT2 to FLOAT16_2. */
8758     const struct vertex_ptc vertices4[] =
8759     {
8760         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8761         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8762         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8763 
8764         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8765         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8766         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8767     };
8768     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
8769     const UINT num_faces4 = ARRAY_SIZE(vertices4) / VERTS_PER_FACE;
8770     const UINT vertex_size4 = sizeof(*vertices4);
8771     const struct vertex_ptc_float16_2 exp_vertices4[] =
8772     {
8773         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8774         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
8775         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
8776 
8777         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
8778         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8779         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
8780     };
8781     const UINT exp_vertex_size4 = sizeof(*exp_vertices4);
8782     /* Test 5. Convert FLOAT2 to FLOAT16_4. */
8783     const struct vertex_ptc vertices5[] =
8784     {
8785         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8786         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8787         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8788 
8789         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8790         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8791         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8792     };
8793     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
8794     const UINT num_faces5 = ARRAY_SIZE(vertices5) / VERTS_PER_FACE;
8795     const UINT vertex_size5 = sizeof(*vertices5);
8796     const struct vertex_ptc_float16_4 exp_vertices5[] =
8797     {
8798         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8799         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0, 0x3c00}}, /* {0.5f, 0.7f, 0.0f, 1.0f} */
8800         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0, 0x3c00}}, /* {-0.2f, -0.3f, 0.0f, 1.0f} */
8801 
8802         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0, 0x3c00}}, /* {0.2f, 0.3f, 0.0f, 1.0f} */
8803         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8804         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0, 0x3c00}}, /* {0.1f, 0.2f, 0.0f, 1.0f} */
8805     };
8806     const UINT exp_vertex_size5 = sizeof(*exp_vertices5);
8807     /* Test 6. Convert FLOAT2 to FLOAT1. */
8808     const struct vertex_ptc vertices6[] =
8809     {
8810         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8811         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8812         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8813 
8814         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8815         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8816         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8817     };
8818     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
8819     const UINT num_faces6 = ARRAY_SIZE(vertices6) / VERTS_PER_FACE;
8820     const UINT vertex_size6 = sizeof(*vertices6);
8821     const struct vertex_ptc_float1 exp_vertices6[] =
8822     {
8823         {{ 0.0f,  3.0f,  0.f},  1.0f},
8824         {{ 2.0f,  3.0f,  0.f},  0.5f},
8825         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8826 
8827         {{ 3.0f,  3.0f,  0.f},  0.2f},
8828         {{ 3.0f,  0.0f,  0.f},  1.0f},
8829         {{ 1.0f,  0.0f,  0.f},  0.1f},
8830     };
8831     const UINT exp_vertex_size6 = sizeof(*exp_vertices6);
8832     /* Test 7. Convert FLOAT2 to FLOAT3. */
8833     const struct vertex_ptc vertices7[] =
8834     {
8835         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8836         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8837         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8838 
8839         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8840         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8841         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8842     };
8843     const UINT num_vertices7 = ARRAY_SIZE(vertices7);
8844     const UINT num_faces7 = ARRAY_SIZE(vertices7) / VERTS_PER_FACE;
8845     const UINT vertex_size7 = sizeof(*vertices7);
8846     const struct vertex_ptc_float3 exp_vertices7[] =
8847     {
8848         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8849         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f}},
8850         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f}},
8851 
8852         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f}},
8853         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8854         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f}},
8855     };
8856     const UINT exp_vertex_size7 = sizeof(*exp_vertices7);
8857     /* Test 8. Convert FLOAT2 to FLOAT4. */
8858     const struct vertex_ptc vertices8[] =
8859     {
8860         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8861         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8862         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8863 
8864         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8865         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8866         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8867     };
8868     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
8869     const UINT num_faces8 = ARRAY_SIZE(vertices8) / VERTS_PER_FACE;
8870     const UINT vertex_size8 = sizeof(*vertices8);
8871     const struct vertex_ptc_float4 exp_vertices8[] =
8872     {
8873         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
8874         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f, 1.0f}},
8875         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f, 1.0f}},
8876 
8877         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f, 1.0f}},
8878         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
8879         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f, 1.0f}},
8880     };
8881     const UINT exp_vertex_size8 = sizeof(*exp_vertices8);
8882     /* Test 9. Convert FLOAT2 to D3DCOLOR. */
8883     const struct vertex_ptc vertices9[] =
8884     {
8885         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8886         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8887         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.6f}},
8888 
8889         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8890         {{ 3.0f,  0.0f,  0.f}, { 2.0f, 256.0f}},
8891         {{ 1.0f,  0.0f,  0.f}, { 0.11f,  0.2f}},
8892     };
8893     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
8894     const UINT num_faces9 = ARRAY_SIZE(vertices9) / VERTS_PER_FACE;
8895     const UINT vertex_size9 = sizeof(*vertices9);
8896     const struct vertex_ptc_d3dcolor exp_vertices9[] =
8897     {
8898         {{ 0.0f,  3.0f,  0.f}, {0, 255, 255, 255}},
8899         {{ 2.0f,  3.0f,  0.f}, {0, 179, 128, 255}},
8900         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
8901 
8902         {{ 3.0f,  3.0f,  0.f}, {0, 77, 51, 255}},
8903         {{ 3.0f,  0.0f,  0.f}, {0, 255, 255, 255}},
8904         {{ 1.0f,  0.0f,  0.f}, {0, 51, 28, 255}},
8905     };
8906     const UINT exp_vertex_size9 = sizeof(*exp_vertices9);
8907     /* Test 10. Convert FLOAT2 to UBYTE4. */
8908     const struct vertex_ptc vertices10[] =
8909     {
8910         {{ 0.0f,  3.0f,  0.f}, { 0.0f,  1.0f}},
8911         {{ 2.0f,  3.0f,  0.f}, { 2.0f,  3.0f}},
8912         {{ 0.0f,  0.0f,  0.f}, { 254.0f,  255.0f}},
8913 
8914         {{ 3.0f,  3.0f,  0.f}, { 256.0f, 257.0f}},
8915         {{ 3.0f,  0.0f,  0.f}, { 1.4f, 1.5f}},
8916         {{ 1.0f,  0.0f,  0.f}, {-4.0f, -5.0f}},
8917     };
8918     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
8919     const UINT num_faces10 = ARRAY_SIZE(vertices10) / VERTS_PER_FACE;
8920     const UINT vertex_size10 = sizeof(*vertices10);
8921     const struct vertex_ptc_ubyte4 exp_vertices10[] =
8922     {
8923         {{ 0.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8924         {{ 2.0f,  3.0f,  0.f}, {2, 3, 0, 1}},
8925         {{ 0.0f,  0.0f,  0.f}, {254, 255, 0, 1}},
8926 
8927         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8928         {{ 3.0f,  0.0f,  0.f}, {1, 2, 0, 1}},
8929         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
8930     };
8931     const UINT exp_vertex_size10 = sizeof(*exp_vertices10);
8932     /* Test 11. Convert FLOAT2 to SHORT2. */
8933     const struct vertex_ptc vertices11[] =
8934     {
8935         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
8936         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
8937         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
8938 
8939         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8940         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
8941         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
8942 
8943         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
8944         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
8945         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
8946     };
8947     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
8948     const UINT num_faces11 = ARRAY_SIZE(vertices11) / VERTS_PER_FACE;
8949     const UINT vertex_size11 = sizeof(*vertices11);
8950     const struct vertex_ptc_short2 exp_vertices11[] =
8951     {
8952         {{ 0.0f,  3.0f,  0.f}, {1, 0}},
8953         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
8954         {{ 0.0f,  0.0f,  0.f}, {0, -4}},
8955 
8956         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1}},
8957         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN}},
8958         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
8959 
8960         {{ 4.0f,  3.0f,  0.f}, {-2, 1}},
8961         {{ 6.0f,  0.0f,  0.f}, {32765, -32767}},
8962         {{ 4.0f,  0.0f,  0.f}, {-4, 1}},
8963     };
8964     const UINT exp_vertex_size11 = sizeof(*exp_vertices11);
8965     /* Test 12. Convert FLOAT2 to SHORT4. */
8966     const struct vertex_ptc vertices12[] =
8967     {
8968         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
8969         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
8970         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
8971 
8972         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8973         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
8974         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
8975 
8976         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
8977         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
8978         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
8979     };
8980     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
8981     const UINT num_faces12 = ARRAY_SIZE(vertices12) / VERTS_PER_FACE;
8982     const UINT vertex_size12 = sizeof(*vertices12);
8983     const struct vertex_ptc_short4 exp_vertices12[] =
8984     {
8985         {{ 0.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
8986         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8987         {{ 0.0f,  0.0f,  0.f}, {0, -4, 0, 1}},
8988 
8989         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1, 0, 1}},
8990         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN, 0, 1}},
8991         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, 0, 1}},
8992 
8993         {{ 4.0f,  3.0f,  0.f}, {-2, 1, 0, 1}},
8994         {{ 6.0f,  0.0f,  0.f}, {32765, -32767, 0, 1}},
8995         {{ 4.0f,  0.0f,  0.f}, {-4, 1, 0, 1}},
8996     };
8997     const UINT exp_vertex_size12 = sizeof(*exp_vertices12);
8998     /* Test 13. Convert FLOAT2 to UBYTE4N. */
8999     const struct vertex_ptc vertices13[] =
9000     {
9001         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  2.0f}},
9002         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9003         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.5f}},
9004 
9005         {{ 3.0f,  3.0f,  0.f}, {-0.6f,  -1.0f}},
9006         {{ 3.0f,  0.0f,  0.f}, {UCHAR_MAX,  UCHAR_MAX + 1}},
9007         {{ 1.0f,  0.0f,  0.f}, {2 * UCHAR_MAX, -UCHAR_MAX}},
9008     };
9009     const UINT num_vertices13 = ARRAY_SIZE(vertices13);
9010     const UINT num_faces13 = ARRAY_SIZE(vertices13) / VERTS_PER_FACE;
9011     const UINT vertex_size13 = sizeof(*vertices13);
9012     const struct vertex_ptc_ubyte4n exp_vertices13[] =
9013     {
9014         {{ 0.0f,  3.0f,  0.f}, {255, 255, 0, 255}},
9015         {{ 2.0f,  3.0f,  0.f}, {128, 179, 0, 255}},
9016         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9017 
9018         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, 255}},
9019         {{ 3.0f,  0.0f,  0.f}, {255, 255, 0, 255}},
9020         {{ 1.0f,  0.0f,  0.f}, {255, 0, 0, 255}},
9021     };
9022     const UINT exp_vertex_size13 = sizeof(*exp_vertices13);
9023     /* Test 14. Convert FLOAT2 to SHORT2N. */
9024     const struct vertex_ptc vertices14[] =
9025     {
9026         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9027         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9028         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9029 
9030         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9031         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
9032         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9033     };
9034     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
9035     const UINT num_faces14 = ARRAY_SIZE(vertices14) / VERTS_PER_FACE;
9036     const UINT vertex_size14 = sizeof(*vertices14);
9037     const struct vertex_ptc_short2 exp_vertices14[] =
9038     {
9039         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX}},
9040         {{ 2.0f,  3.0f,  0.f}, {13107, 16384}},
9041         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2}},
9042 
9043         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383}},
9044         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3}},
9045         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2}},
9046     };
9047     const UINT exp_vertex_size14 = sizeof(*exp_vertices14);
9048     /* Test 15. Convert FLOAT2 to SHORT4N. */
9049     const struct vertex_ptc vertices15[] =
9050     {
9051         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9052         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9053         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9054 
9055         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9056         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
9057         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9058     };
9059     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
9060     const UINT num_faces15 = ARRAY_SIZE(vertices15) / VERTS_PER_FACE;
9061     const UINT vertex_size15 = sizeof(*vertices15);
9062     const struct vertex_ptc_short4 exp_vertices15[] =
9063     {
9064         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX, 0, SHRT_MAX}},
9065         {{ 2.0f,  3.0f,  0.f}, {13107, 16384, 0, SHRT_MAX}},
9066         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2, 0, SHRT_MAX}},
9067 
9068         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383, 0, SHRT_MAX}},
9069         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3, 0, SHRT_MAX}},
9070         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2, 0, SHRT_MAX}},
9071     };
9072     const UINT exp_vertex_size15 = sizeof(*exp_vertices15);
9073     /* Test 16. Convert FLOAT2 to USHORT2N. */
9074     const struct vertex_ptc vertices16[] =
9075     {
9076         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9077         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9078         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9079 
9080         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9081         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
9082         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
9083     };
9084     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
9085     const UINT num_faces16 = ARRAY_SIZE(vertices16) / VERTS_PER_FACE;
9086     const UINT vertex_size16 = sizeof(*vertices16);
9087     const struct vertex_ptc_ushort2n exp_vertices16[] =
9088     {
9089         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX}},
9090         {{ 2.0f,  3.0f,  0.f}, {26214, 32768}},
9091         {{ 0.0f,  0.0f,  0.f}, {39321, 0}},
9092 
9093         {{ 3.0f,  3.0f,  0.f}, {0, 0}},
9094         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1}},
9095         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0}},
9096     };
9097     const UINT exp_vertex_size16 = sizeof(*exp_vertices16);
9098     /* Test 17. Convert FLOAT2 to USHORT4N. */
9099     const struct vertex_ptc vertices17[] =
9100     {
9101         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9102         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9103         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9104 
9105         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9106         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
9107         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
9108     };
9109     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
9110     const UINT num_faces17 = ARRAY_SIZE(vertices17) / VERTS_PER_FACE;
9111     const UINT vertex_size17 = sizeof(*vertices17);
9112     const struct vertex_ptc_ushort4n exp_vertices17[] =
9113     {
9114         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX, 0, USHRT_MAX}},
9115         {{ 2.0f,  3.0f,  0.f}, {26214, 32768, 0, USHRT_MAX}},
9116         {{ 0.0f,  0.0f,  0.f}, {39321, 0, 0, USHRT_MAX}},
9117 
9118         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, USHRT_MAX}},
9119         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1, 0, USHRT_MAX}},
9120         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0, 0, USHRT_MAX}},
9121     };
9122     const UINT exp_vertex_size17 = sizeof(*exp_vertices17);
9123     /* Test 18. Test that the method field is compared by converting a FLOAT2 to
9124      * FLOAT16_2. where the method field has been change from
9125      * D3DDECLMETHOD_DEFAULT to D3DDECLMETHOD_PARTIALU. */
9126     const struct vertex_ptc vertices18[] =
9127     {
9128         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9129         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9130         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
9131 
9132         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9133         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
9134         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
9135     };
9136     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
9137     const UINT num_faces18 = ARRAY_SIZE(vertices18) / VERTS_PER_FACE;
9138     const UINT vertex_size18 = sizeof(*vertices18);
9139     const struct vertex_ptc_float16_2 exp_vertices18[] =
9140     {
9141         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9142         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9143         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9144 
9145         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9146         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9147         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9148     };
9149     const UINT exp_vertex_size18 = sizeof(*exp_vertices18);
9150     /* Test 19. Test that data is lost if usage index changes, e.g. TEXCOORD0
9151      * TEXCOORD1. */
9152     const struct vertex_pntc vertices19[] =
9153     {
9154         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
9155         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
9156         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
9157 
9158         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
9159         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
9160         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
9161     };
9162     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
9163     const UINT num_faces19 = ARRAY_SIZE(vertices19) / VERTS_PER_FACE;
9164     const UINT vertex_size19 = sizeof(*vertices19);
9165     const struct vertex_pntc exp_vertices19[] =
9166     {
9167         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
9168         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
9169         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
9170 
9171         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
9172         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
9173         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
9174     };
9175     const UINT exp_vertex_size19 = sizeof(*exp_vertices19);
9176     /* Test 20. Another test that data is lost if usage index changes, e.g.
9177      * TEXCOORD1 to TEXCOORD0. */
9178     const struct vertex_pntc vertices20[] =
9179     {
9180         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
9181         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
9182         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
9183 
9184         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
9185         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
9186         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
9187     };
9188     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
9189     const UINT num_faces20 = ARRAY_SIZE(vertices20) / VERTS_PER_FACE;
9190     const UINT vertex_size20 = sizeof(*vertices20);
9191     const struct vertex_pntc exp_vertices20[] =
9192     {
9193         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
9194         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
9195         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
9196 
9197         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
9198         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
9199         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
9200     };
9201     const UINT exp_vertex_size20 = sizeof(*exp_vertices20);
9202     /* Test 21. Convert FLOAT1 to FLOAT2. */
9203     const struct vertex_ptc_float1 vertices21[] =
9204     {
9205         {{ 0.0f,  3.0f,  0.f},  1.0f},
9206         {{ 2.0f,  3.0f,  0.f},  0.5f},
9207         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9208 
9209         {{ 3.0f,  3.0f,  0.f},  0.2f},
9210         {{ 3.0f,  0.0f,  0.f},  1.0f},
9211         {{ 1.0f,  0.0f,  0.f},  0.1f},
9212     };
9213     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
9214     const UINT num_faces21 = ARRAY_SIZE(vertices21) / VERTS_PER_FACE;
9215     const UINT vertex_size21 = sizeof(*vertices21);
9216     const struct vertex_ptc exp_vertices21[] =
9217     {
9218         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f}},
9219         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f}},
9220         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f}},
9221 
9222         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f}},
9223         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f}},
9224         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f}},
9225     };
9226     const UINT exp_vertex_size21 = sizeof(*exp_vertices21);
9227     /* Test 22. Convert FLOAT1 to FLOAT3. */
9228     const struct vertex_ptc_float1 vertices22[] =
9229     {
9230         {{ 0.0f,  3.0f,  0.f},  1.0f},
9231         {{ 2.0f,  3.0f,  0.f},  0.5f},
9232         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9233 
9234         {{ 3.0f,  3.0f,  0.f},  0.2f},
9235         {{ 3.0f,  0.0f,  0.f},  1.0f},
9236         {{ 1.0f,  0.0f,  0.f},  0.1f},
9237     };
9238     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
9239     const UINT num_faces22 = ARRAY_SIZE(vertices22) / VERTS_PER_FACE;
9240     const UINT vertex_size22 = sizeof(*vertices22);
9241     const struct vertex_ptc_float3 exp_vertices22[] =
9242     {
9243         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
9244         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f}},
9245         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f}},
9246 
9247         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f}},
9248         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
9249         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f}},
9250     };
9251     const UINT exp_vertex_size22 = sizeof(*exp_vertices22);
9252     /* Test 23. Convert FLOAT1 to FLOAT4. */
9253     const struct vertex_ptc_float1 vertices23[] =
9254     {
9255         {{ 0.0f,  3.0f,  0.f},  1.0f},
9256         {{ 2.0f,  3.0f,  0.f},  0.5f},
9257         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9258 
9259         {{ 3.0f,  3.0f,  0.f},  0.2f},
9260         {{ 3.0f,  0.0f,  0.f},  1.0f},
9261         {{ 1.0f,  0.0f,  0.f},  0.1f},
9262     };
9263     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
9264     const UINT num_faces23 = ARRAY_SIZE(vertices23) / VERTS_PER_FACE;
9265     const UINT vertex_size23 = sizeof(*vertices23);
9266     const struct vertex_ptc_float4 exp_vertices23[] =
9267     {
9268         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
9269         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f, 1.0f}},
9270         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f, 1.0f}},
9271 
9272         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f, 1.0f}},
9273         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
9274         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f, 1.0f}},
9275     };
9276     const UINT exp_vertex_size23 = sizeof(*exp_vertices23);
9277     /* Test 24. Convert FLOAT1 to D3DCOLOR. */
9278     const struct vertex_ptc_float1 vertices24[] =
9279     {
9280         {{ 0.0f,  3.0f,  0.f},  1.0f},
9281         {{ 2.0f,  3.0f,  0.f},  0.5f},
9282         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9283 
9284         {{ 3.0f,  3.0f,  0.f},  0.2f},
9285         {{ 3.0f,  0.0f,  0.f},  1.0f},
9286         {{ 1.0f,  0.0f,  0.f},  0.11f},
9287     };
9288     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
9289     const UINT num_faces24 = ARRAY_SIZE(vertices24) / VERTS_PER_FACE;
9290     const UINT vertex_size24 = sizeof(*vertices24);
9291     const struct vertex_ptc_d3dcolor exp_vertices24[] =
9292     {
9293         {{ 0.0f,  3.0f,  0.f}, {0, 0, 255, 255}},
9294         {{ 2.0f,  3.0f,  0.f}, {0, 0, 128, 255}},
9295         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9296 
9297         {{ 3.0f,  3.0f,  0.f}, {0, 0, 51, 255}},
9298         {{ 3.0f,  0.0f,  0.f}, {0, 0, 255, 255}},
9299         {{ 1.0f,  0.0f,  0.f}, {0, 0, 28, 255}},
9300     };
9301     const UINT exp_vertex_size24 = sizeof(*exp_vertices24);
9302     /* Test 25. Convert FLOAT1 to ubyte4. */
9303     const struct vertex_ptc_float1 vertices25[] =
9304     {
9305         {{ 0.0f,  3.0f,  0.f}, 0.0f},
9306         {{ 2.0f,  3.0f,  0.f}, 1.4f},
9307         {{ 0.0f,  0.0f,  0.f}, 1.5f},
9308 
9309         {{ 3.0f,  3.0f,  0.f}, 255.0f},
9310         {{ 3.0f,  0.0f,  0.f}, 256.0f},
9311         {{ 1.0f,  0.0f,  0.f}, -1.0f},
9312     };
9313     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
9314     const UINT num_faces25 = ARRAY_SIZE(vertices25) / VERTS_PER_FACE;
9315     const UINT vertex_size25 = sizeof(*vertices25);
9316     const struct vertex_ptc_ubyte4 exp_vertices25[] =
9317     {
9318         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 1}},
9319         {{ 2.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
9320         {{ 0.0f,  0.0f,  0.f}, {2, 0, 0, 1}},
9321 
9322         {{ 3.0f,  3.0f,  0.f}, {255, 0, 0, 1}},
9323         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9324         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9325     };
9326     const UINT exp_vertex_size25 = sizeof(*exp_vertices25);
9327     /* Test 26. Convert FLOAT4 to D3DCOLOR. */
9328     const struct vertex_ptc_float4 vertices26[] =
9329     {
9330         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.5f}},
9331         {{ 2.0f,  3.0f,  0.f}, {-0.4f, -0.5f, -1.0f, -2.0f}},
9332         {{ 0.0f,  0.0f,  0.f}, {254.0f, 255.0f, 256.0f, 257.0f}},
9333 
9334         {{ 3.0f,  3.0f,  0.f}, {0.1f, 0.2f, 0.3f, 0.4f}},
9335         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.6f, 0.7f, 0.8f}},
9336         {{ 1.0f,  0.0f,  0.f}, {0.9f, 0.99f, 0.995f, 0.999f}},
9337     };
9338     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
9339     const UINT num_faces26 = ARRAY_SIZE(vertices26) / VERTS_PER_FACE;
9340     const UINT vertex_size26 = sizeof(*vertices26);
9341     const struct vertex_ptc_d3dcolor exp_vertices26[] =
9342     {
9343         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9344         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9345         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9346 
9347         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9348         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9349         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9350     };
9351     const UINT exp_vertex_size26 = sizeof(*exp_vertices26);
9352     /* Test 27. Convert D3DCOLOR to FLOAT4. */
9353     const struct vertex_ptc_d3dcolor vertices27[] =
9354     {
9355         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9356         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9357         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9358 
9359         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9360         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9361         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9362     };
9363     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
9364     const UINT num_faces27 = ARRAY_SIZE(vertices27) / VERTS_PER_FACE;
9365     const UINT vertex_size27 = sizeof(*vertices27);
9366     const struct vertex_ptc_float4 exp_vertices27[] =
9367     {
9368         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.501961f}},
9369         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9370         {{ 0.0f,  0.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9371 
9372         {{ 3.0f,  3.0f,  0.f}, {0.101961f, 0.2f, 0.301961f, 0.4f}},
9373         {{ 3.0f,  0.0f,  0.f}, {0.501961f, 0.6f, 0.701961f, 0.8f}},
9374         {{ 1.0f,  0.0f,  0.f}, {0.901961f, 0.988235f, 0.996078f, 1.0f}},
9375     };
9376     const UINT exp_vertex_size27 = sizeof(*exp_vertices27);
9377     /* Test 28. Convert UBYTE4 to FLOAT4. */
9378     const struct vertex_ptc_ubyte4 vertices28[] =
9379     {
9380         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9381         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9382         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9383 
9384         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9385         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9386         {{ 1.0f,  0.0f,  0.f}, {50, 60, 127, 255}},
9387     };
9388     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
9389     const UINT num_faces28 = ARRAY_SIZE(vertices28) / VERTS_PER_FACE;
9390     const UINT vertex_size28 = sizeof(*vertices28);
9391     const struct vertex_ptc_float4 exp_vertices28[] =
9392     {
9393         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9394         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9395         {{ 0.0f,  0.0f,  0.f}, {1.0f,  0.0f, 1.0f, 0.0f}},
9396 
9397         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9398         {{ 3.0f,  0.0f,  0.f}, {10.0f, 20.0f, 30.0f, 40.0f}},
9399         {{ 1.0f,  0.0f,  0.f}, {50.0f, 60.0f, 127.0f, 255.0f}},
9400     };
9401     const UINT exp_vertex_size28 = sizeof(*exp_vertices28);
9402     /* Test 29. Convert SHORT2 to FLOAT4. */
9403     const struct vertex_ptc_short2 vertices29[] =
9404     {
9405         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9406         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9407         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9408 
9409         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9410         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX}},
9411         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9412     };
9413     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
9414     const UINT num_faces29 = ARRAY_SIZE(vertices29) / VERTS_PER_FACE;
9415     const UINT vertex_size29 = sizeof(*vertices29);
9416     const struct vertex_ptc_float4 exp_vertices29[] =
9417     {
9418         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9419         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9420         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 0.0f, 1.0f}},
9421 
9422         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9423         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 0.0f, 1.0f}},
9424         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, 0.0f, 1.0f}},
9425     };
9426     const UINT exp_vertex_size29 = sizeof(*exp_vertices29);
9427     /* Test 29. Convert SHORT4 to FLOAT4. */
9428     const struct vertex_ptc_short4 vertices30[] =
9429     {
9430         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9431         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9432         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9433 
9434         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9435         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1, 0}},
9436         {{ 1.0f,  0.0f,  0.f}, {-42, 42, SHRT_MAX, SHRT_MIN}},
9437     };
9438     const UINT num_vertices30 = ARRAY_SIZE(vertices30);
9439     const UINT num_faces30 = ARRAY_SIZE(vertices30) / VERTS_PER_FACE;
9440     const UINT vertex_size30 = sizeof(*vertices30);
9441     const struct vertex_ptc_float4 exp_vertices30[] =
9442     {
9443         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9444         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9445         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9446 
9447         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9448         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1.0f, 0.0f}},
9449         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, SHRT_MAX, SHRT_MIN}},
9450     };
9451     const UINT exp_vertex_size30 = sizeof(*exp_vertices30);
9452     /* Test 31. Convert UBYTE4N to FLOAT4. */
9453     const struct vertex_ptc_ubyte4n vertices31[] =
9454     {
9455         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9456         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9457         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9458 
9459         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9460         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9461         {{ 1.0f,  0.0f,  0.f}, {50, 60, 70, UCHAR_MAX}},
9462     };
9463     const UINT num_vertices31 = ARRAY_SIZE(vertices31);
9464     const UINT num_faces31 = ARRAY_SIZE(vertices31) / VERTS_PER_FACE;
9465     const UINT vertex_size31 = sizeof(*vertices31);
9466     const struct vertex_ptc_float4 exp_vertices31[] =
9467     {
9468         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9469         {{ 2.0f,  3.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX}},
9470         {{ 0.0f,  0.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX, 0.0f}},
9471 
9472         {{ 3.0f,  3.0f,  0.f}, {0.0f, (FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX}},
9473         {{ 3.0f,  0.0f,  0.f}, {(FLOAT)10/UCHAR_MAX, (FLOAT)20/UCHAR_MAX, (FLOAT)30/UCHAR_MAX, (FLOAT)40/UCHAR_MAX}},
9474         {{ 1.0f,  0.0f,  0.f}, {(FLOAT)50/UCHAR_MAX, (FLOAT)60/UCHAR_MAX, (FLOAT)70/UCHAR_MAX, 1.0f}},
9475     };
9476     const UINT exp_vertex_size31 = sizeof(*exp_vertices31);
9477     /* Test 32. Convert SHORT2N to FLOAT4. */
9478     const struct vertex_ptc_short2 vertices32[] =
9479     {
9480         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9481         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9482         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9483 
9484         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9485         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
9486         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9487     };
9488     const UINT num_vertices32 = ARRAY_SIZE(vertices32);
9489     const UINT num_faces32 = ARRAY_SIZE(vertices32) / VERTS_PER_FACE;
9490     const UINT vertex_size32 = sizeof(*vertices32);
9491     const struct vertex_ptc_float4 exp_vertices32[] =
9492     {
9493         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9494         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9495         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 0.0f, 1.0f}},
9496 
9497         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9498         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, 0.0f, 1.0f}},
9499         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 0.0f, 1.0f}},
9500     };
9501     const UINT exp_vertex_size32 = sizeof(*exp_vertices32);
9502     /* Test 33. Convert SHORT4N to FLOAT4. */
9503     const struct vertex_ptc_short4 vertices33[] =
9504     {
9505         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9506         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9507         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9508 
9509         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9510         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, SHRT_MIN + 1, SHRT_MAX}},
9511         {{ 1.0f,  0.0f,  0.f}, {-42, 42, 1, 1}},
9512     };
9513     const UINT num_vertices33 = ARRAY_SIZE(vertices33);
9514     const UINT num_faces33 = ARRAY_SIZE(vertices33) / VERTS_PER_FACE;
9515     const UINT vertex_size33 = sizeof(*vertices33);
9516     const struct vertex_ptc_float4 exp_vertices33[] =
9517     {
9518         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9519         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX}},
9520         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX, 0.0f}},
9521 
9522         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9523         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, -1.0f, 1.0f}},
9524         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9525     };
9526     const UINT exp_vertex_size33 = sizeof(*exp_vertices33);
9527     /* Test 34. Convert FLOAT16_2 to FLOAT4. */
9528     const struct vertex_ptc_float16_2 vertices34[] =
9529     {
9530         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9531         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9532         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9533 
9534         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9535         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9536         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9537     };
9538     const UINT num_vertices34 = ARRAY_SIZE(vertices34);
9539     const UINT num_faces34 = ARRAY_SIZE(vertices34) / VERTS_PER_FACE;
9540     const UINT vertex_size34 = sizeof(*vertices34);
9541     const struct vertex_ptc_float4 exp_vertices34[] =
9542     {
9543         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9544         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.700195f, 0.0f, 1.0f}},
9545         {{ 0.0f,  0.0f,  0.f}, {-0.199951f, -0.300049f, 0.0f, 1.0f}},
9546 
9547         {{ 3.0f,  3.0f,  0.f}, {0.199951f, 0.300049f, 0.0f, 1.0f}},
9548         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9549         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.0f, 1.0f}},
9550     };
9551     const UINT exp_vertex_size34 = sizeof(*exp_vertices34);
9552     /* Test 35. Convert FLOAT16_4 to FLOAT4. */
9553     const struct vertex_ptc_float16_4 vertices35[] =
9554     {
9555         {{ 0.0f,  3.0f,  0.f}, {0x0000, 0x0000, 0x0000, 0x0000}},
9556         {{ 2.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
9557         {{ 0.0f,  0.0f,  0.f}, {0x3c00, 0x0000, 0x3c00, 0x0000}},
9558 
9559         {{ 3.0f,  3.0f,  0.f}, {0x0000, 0x3c00, 0x0000, 0x3c00}},
9560         {{ 3.0f,  0.0f,  0.f}, {0x3800, 0x399a, 0xb266, 0xb4cd}},
9561         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
9562     };
9563     const UINT num_vertices35 = ARRAY_SIZE(vertices35);
9564     const UINT num_faces35 = ARRAY_SIZE(vertices35) / VERTS_PER_FACE;
9565     const UINT vertex_size35 = sizeof(*vertices35);
9566     const struct vertex_ptc_float4 exp_vertices35[] =
9567     {
9568         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9569         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9570         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9571 
9572         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9573         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.700195f, -0.199951f, -0.300049f}},
9574         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.099976f, 0.199951f}},
9575     };
9576     const UINT exp_vertex_size35 = sizeof(*exp_vertices35);
9577     /* Test 36. Check that vertex buffer sharing is ok. */
9578     const struct vertex_pn vertices36[] =
9579     {
9580         {{ 0.0f,  3.0f,  0.f}, up},
9581         {{ 2.0f,  3.0f,  0.f}, up},
9582         {{ 0.0f,  0.0f,  0.f}, up},
9583     };
9584     const UINT num_vertices36 = ARRAY_SIZE(vertices36);
9585     const UINT num_faces36 = ARRAY_SIZE(vertices36) / VERTS_PER_FACE;
9586     const UINT vertex_size36 = sizeof(*vertices36);
9587     const DWORD clone_options36 = options | D3DXMESH_VB_SHARE;
9588     /* Common mesh data */
9589     ID3DXMesh *mesh = NULL;
9590     ID3DXMesh *mesh_clone = NULL;
9591     struct
9592     {
9593         const BYTE *vertices;
9594         const DWORD *indices;
9595         const DWORD *attributes;
9596         const UINT num_vertices;
9597         const UINT num_faces;
9598         const UINT vertex_size;
9599         const DWORD create_options;
9600         const DWORD clone_options;
9601         D3DVERTEXELEMENT9 *declaration;
9602         D3DVERTEXELEMENT9 *new_declaration;
9603         const BYTE *exp_vertices;
9604         const UINT exp_vertex_size;
9605     }
9606     tc[] =
9607     {
9608         {
9609             (BYTE*)vertices0,
9610             NULL,
9611             NULL,
9612             num_vertices0,
9613             num_faces0,
9614             vertex_size0,
9615             options,
9616             options,
9617             declaration_pn,
9618             declaration_pn,
9619             (BYTE*)vertices0,
9620             vertex_size0
9621         },
9622         {
9623             (BYTE*)vertices0,
9624             NULL,
9625             NULL,
9626             num_vertices0,
9627             num_faces0,
9628             vertex_size0,
9629             options_16bit,
9630             options_16bit,
9631             declaration_pn,
9632             declaration_pn,
9633             (BYTE*)vertices0,
9634             vertex_size0
9635         },
9636         {
9637             (BYTE*)vertices0,
9638             NULL,
9639             NULL,
9640             num_vertices0,
9641             num_faces0,
9642             vertex_size0,
9643             options,
9644             options,
9645             declaration_pn,
9646             declaration_pntc,
9647             (BYTE*)exp_vertices2,
9648             exp_vertex_size2
9649         },
9650         {
9651             (BYTE*)vertices0,
9652             NULL,
9653             NULL,
9654             num_vertices0,
9655             num_faces0,
9656             vertex_size0,
9657             options,
9658             options,
9659             declaration_pn,
9660             declaration_ptcn,
9661             (BYTE*)exp_vertices3,
9662             exp_vertex_size3
9663         },
9664         {
9665             (BYTE*)vertices4,
9666             NULL,
9667             NULL,
9668             num_vertices4,
9669             num_faces4,
9670             vertex_size4,
9671             options,
9672             options,
9673             declaration_ptc,
9674             declaration_ptc_float16_2,
9675             (BYTE*)exp_vertices4,
9676             exp_vertex_size4
9677         },
9678         {
9679             (BYTE*)vertices5,
9680             NULL,
9681             NULL,
9682             num_vertices5,
9683             num_faces5,
9684             vertex_size5,
9685             options,
9686             options,
9687             declaration_ptc,
9688             declaration_ptc_float16_4,
9689             (BYTE*)exp_vertices5,
9690             exp_vertex_size5
9691         },
9692         {
9693             (BYTE*)vertices6,
9694             NULL,
9695             NULL,
9696             num_vertices6,
9697             num_faces6,
9698             vertex_size6,
9699             options,
9700             options,
9701             declaration_ptc,
9702             declaration_ptc_float1,
9703             (BYTE*)exp_vertices6,
9704             exp_vertex_size6
9705         },
9706         {
9707             (BYTE*)vertices7,
9708             NULL,
9709             NULL,
9710             num_vertices7,
9711             num_faces7,
9712             vertex_size7,
9713             options,
9714             options,
9715             declaration_ptc,
9716             declaration_ptc_float3,
9717             (BYTE*)exp_vertices7,
9718             exp_vertex_size7
9719         },
9720         {
9721             (BYTE*)vertices8,
9722             NULL,
9723             NULL,
9724             num_vertices8,
9725             num_faces8,
9726             vertex_size8,
9727             options,
9728             options,
9729             declaration_ptc,
9730             declaration_ptc_float4,
9731             (BYTE*)exp_vertices8,
9732             exp_vertex_size8
9733         },
9734         {
9735             (BYTE*)vertices9,
9736             NULL,
9737             NULL,
9738             num_vertices9,
9739             num_faces9,
9740             vertex_size9,
9741             options,
9742             options,
9743             declaration_ptc,
9744             declaration_ptc_d3dcolor,
9745             (BYTE*)exp_vertices9,
9746             exp_vertex_size9
9747         },
9748         {
9749             (BYTE*)vertices10,
9750             NULL,
9751             NULL,
9752             num_vertices10,
9753             num_faces10,
9754             vertex_size10,
9755             options,
9756             options,
9757             declaration_ptc,
9758             declaration_ptc_ubyte4,
9759             (BYTE*)exp_vertices10,
9760             exp_vertex_size10
9761         },
9762         {
9763             (BYTE*)vertices11,
9764             NULL,
9765             NULL,
9766             num_vertices11,
9767             num_faces11,
9768             vertex_size11,
9769             options,
9770             options,
9771             declaration_ptc,
9772             declaration_ptc_short2,
9773             (BYTE*)exp_vertices11,
9774             exp_vertex_size11
9775         },
9776         {
9777             (BYTE*)vertices12,
9778             NULL,
9779             NULL,
9780             num_vertices12,
9781             num_faces12,
9782             vertex_size12,
9783             options,
9784             options,
9785             declaration_ptc,
9786             declaration_ptc_short4,
9787             (BYTE*)exp_vertices12,
9788             exp_vertex_size12
9789         },
9790         {
9791             (BYTE*)vertices13,
9792             NULL,
9793             NULL,
9794             num_vertices13,
9795             num_faces13,
9796             vertex_size13,
9797             options,
9798             options,
9799             declaration_ptc,
9800             declaration_ptc_ubyte4n,
9801             (BYTE*)exp_vertices13,
9802             exp_vertex_size13
9803         },
9804         {
9805             (BYTE*)vertices14,
9806             NULL,
9807             NULL,
9808             num_vertices14,
9809             num_faces14,
9810             vertex_size14,
9811             options,
9812             options,
9813             declaration_ptc,
9814             declaration_ptc_short2n,
9815             (BYTE*)exp_vertices14,
9816             exp_vertex_size14
9817         },
9818         {
9819             (BYTE*)vertices15,
9820             NULL,
9821             NULL,
9822             num_vertices15,
9823             num_faces15,
9824             vertex_size15,
9825             options,
9826             options,
9827             declaration_ptc,
9828             declaration_ptc_short4n,
9829             (BYTE*)exp_vertices15,
9830             exp_vertex_size15
9831         },
9832         {
9833             (BYTE*)vertices16,
9834             NULL,
9835             NULL,
9836             num_vertices16,
9837             num_faces16,
9838             vertex_size16,
9839             options,
9840             options,
9841             declaration_ptc,
9842             declaration_ptc_ushort2n,
9843             (BYTE*)exp_vertices16,
9844             exp_vertex_size16
9845         },
9846         {
9847             (BYTE*)vertices17,
9848             NULL,
9849             NULL,
9850             num_vertices17,
9851             num_faces17,
9852             vertex_size17,
9853             options,
9854             options,
9855             declaration_ptc,
9856             declaration_ptc_ushort4n,
9857             (BYTE*)exp_vertices17,
9858             exp_vertex_size17
9859         },
9860         {
9861             (BYTE*)vertices18,
9862             NULL,
9863             NULL,
9864             num_vertices18,
9865             num_faces18,
9866             vertex_size18,
9867             options,
9868             options,
9869             declaration_ptc,
9870             declaration_ptc_float16_2_partialu,
9871             (BYTE*)exp_vertices18,
9872             exp_vertex_size18
9873         },
9874         {
9875             (BYTE*)vertices19,
9876             NULL,
9877             NULL,
9878             num_vertices19,
9879             num_faces19,
9880             vertex_size19,
9881             options,
9882             options,
9883             declaration_pntc,
9884             declaration_pntc1,
9885             (BYTE*)exp_vertices19,
9886             exp_vertex_size19
9887         },
9888         {
9889             (BYTE*)vertices20,
9890             NULL,
9891             NULL,
9892             num_vertices20,
9893             num_faces20,
9894             vertex_size20,
9895             options,
9896             options,
9897             declaration_pntc1,
9898             declaration_pntc,
9899             (BYTE*)exp_vertices20,
9900             exp_vertex_size20
9901         },
9902         {
9903             (BYTE*)vertices21,
9904             NULL,
9905             NULL,
9906             num_vertices21,
9907             num_faces21,
9908             vertex_size21,
9909             options,
9910             options,
9911             declaration_ptc_float1,
9912             declaration_ptc,
9913             (BYTE*)exp_vertices21,
9914             exp_vertex_size21
9915         },
9916         {
9917             (BYTE*)vertices22,
9918             NULL,
9919             NULL,
9920             num_vertices22,
9921             num_faces22,
9922             vertex_size22,
9923             options,
9924             options,
9925             declaration_ptc_float1,
9926             declaration_ptc_float3,
9927             (BYTE*)exp_vertices22,
9928             exp_vertex_size22
9929         },
9930         {
9931             (BYTE*)vertices23,
9932             NULL,
9933             NULL,
9934             num_vertices23,
9935             num_faces23,
9936             vertex_size23,
9937             options,
9938             options,
9939             declaration_ptc_float1,
9940             declaration_ptc_float4,
9941             (BYTE*)exp_vertices23,
9942             exp_vertex_size23
9943         },
9944         {
9945             (BYTE*)vertices24,
9946             NULL,
9947             NULL,
9948             num_vertices24,
9949             num_faces24,
9950             vertex_size24,
9951             options,
9952             options,
9953             declaration_ptc_float1,
9954             declaration_ptc_d3dcolor,
9955             (BYTE*)exp_vertices24,
9956             exp_vertex_size24
9957         },
9958         {
9959             (BYTE*)vertices25,
9960             NULL,
9961             NULL,
9962             num_vertices25,
9963             num_faces25,
9964             vertex_size25,
9965             options,
9966             options,
9967             declaration_ptc_float1,
9968             declaration_ptc_ubyte4,
9969             (BYTE*)exp_vertices25,
9970             exp_vertex_size25
9971         },
9972         {
9973             (BYTE*)vertices26,
9974             NULL,
9975             NULL,
9976             num_vertices26,
9977             num_faces26,
9978             vertex_size26,
9979             options,
9980             options,
9981             declaration_ptc_float4,
9982             declaration_ptc_d3dcolor,
9983             (BYTE*)exp_vertices26,
9984             exp_vertex_size26
9985         },
9986         {
9987             (BYTE*)vertices27,
9988             NULL,
9989             NULL,
9990             num_vertices27,
9991             num_faces27,
9992             vertex_size27,
9993             options,
9994             options,
9995             declaration_ptc_d3dcolor,
9996             declaration_ptc_float4,
9997             (BYTE*)exp_vertices27,
9998             exp_vertex_size27
9999         },
10000         {
10001             (BYTE*)vertices28,
10002             NULL,
10003             NULL,
10004             num_vertices28,
10005             num_faces28,
10006             vertex_size28,
10007             options,
10008             options,
10009             declaration_ptc_ubyte4,
10010             declaration_ptc_float4,
10011             (BYTE*)exp_vertices28,
10012             exp_vertex_size28
10013         },
10014         {
10015             (BYTE*)vertices29,
10016             NULL,
10017             NULL,
10018             num_vertices29,
10019             num_faces29,
10020             vertex_size29,
10021             options,
10022             options,
10023             declaration_ptc_short2,
10024             declaration_ptc_float4,
10025             (BYTE*)exp_vertices29,
10026             exp_vertex_size29
10027         },
10028         {
10029             (BYTE*)vertices30,
10030             NULL,
10031             NULL,
10032             num_vertices30,
10033             num_faces30,
10034             vertex_size30,
10035             options,
10036             options,
10037             declaration_ptc_short4,
10038             declaration_ptc_float4,
10039             (BYTE*)exp_vertices30,
10040             exp_vertex_size30
10041         },
10042         {
10043             (BYTE*)vertices31,
10044             NULL,
10045             NULL,
10046             num_vertices31,
10047             num_faces31,
10048             vertex_size31,
10049             options,
10050             options,
10051             declaration_ptc_ubyte4n,
10052             declaration_ptc_float4,
10053             (BYTE*)exp_vertices31,
10054             exp_vertex_size31
10055         },
10056         {
10057             (BYTE*)vertices32,
10058             NULL,
10059             NULL,
10060             num_vertices32,
10061             num_faces32,
10062             vertex_size32,
10063             options,
10064             options,
10065             declaration_ptc_short2n,
10066             declaration_ptc_float4,
10067             (BYTE*)exp_vertices32,
10068             exp_vertex_size32
10069         },
10070         {
10071             (BYTE*)vertices33,
10072             NULL,
10073             NULL,
10074             num_vertices33,
10075             num_faces33,
10076             vertex_size33,
10077             options,
10078             options,
10079             declaration_ptc_short4n,
10080             declaration_ptc_float4,
10081             (BYTE*)exp_vertices33,
10082             exp_vertex_size33
10083         },
10084         {
10085             (BYTE*)vertices34,
10086             NULL,
10087             NULL,
10088             num_vertices34,
10089             num_faces34,
10090             vertex_size34,
10091             options,
10092             options,
10093             declaration_ptc_float16_2,
10094             declaration_ptc_float4,
10095             (BYTE*)exp_vertices34,
10096             exp_vertex_size34
10097         },
10098         {
10099             (BYTE*)vertices35,
10100             NULL,
10101             NULL,
10102             num_vertices35,
10103             num_faces35,
10104             vertex_size35,
10105             options,
10106             options,
10107             declaration_ptc_float16_4,
10108             declaration_ptc_float4,
10109             (BYTE*)exp_vertices35,
10110             exp_vertex_size35
10111         },
10112         {
10113             (BYTE*)vertices36,
10114             NULL,
10115             NULL,
10116             num_vertices36,
10117             num_faces36,
10118             vertex_size36,
10119             options,
10120             clone_options36,
10121             declaration_pn,
10122             declaration_pn,
10123             (BYTE*)vertices36,
10124             vertex_size36
10125         },
10126     };
10127 #ifdef __REACTOS__
10128 #undef up
10129 #undef zero_vec2
10130 #endif
10131 
10132     test_context = new_test_context();
10133     if (!test_context)
10134     {
10135         skip("Couldn't create test context\n");
10136         goto cleanup;
10137     }
10138 
10139     for (i = 0; i < ARRAY_SIZE(tc); i++)
10140     {
10141         UINT j;
10142         D3DVERTEXELEMENT9 new_declaration[MAX_FVF_DECL_SIZE];
10143         UINT exp_new_decl_length, new_decl_length;
10144         UINT exp_new_decl_size, new_decl_size;
10145 
10146         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10147                               tc[i].create_options,
10148                               tc[i].declaration,
10149                               test_context->device, &mesh,
10150                               tc[i].vertices, tc[i].vertex_size,
10151                               tc[i].indices, tc[i].attributes);
10152         if (FAILED(hr))
10153         {
10154             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10155             goto cleanup;
10156         }
10157 
10158         hr = mesh->lpVtbl->CloneMesh(mesh, tc[i].clone_options, tc[i].new_declaration,
10159                                      test_context->device, &mesh_clone);
10160         ok(hr == D3D_OK, "CloneMesh test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
10161 
10162         hr = mesh_clone->lpVtbl->GetDeclaration(mesh_clone, new_declaration);
10163         ok(hr == D3D_OK, "GetDeclaration test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
10164         /* Check declaration elements */
10165         for (j = 0; tc[i].new_declaration[j].Stream != 0xFF; j++)
10166         {
10167             ok(memcmp(&tc[i].new_declaration[j], &new_declaration[j], sizeof(*new_declaration)) == 0,
10168                "Test case %d failed. Declaration element %d did not match.\n", i, j);
10169         }
10170 
10171         /* Check declaration length */
10172         exp_new_decl_length = D3DXGetDeclLength(tc[i].new_declaration);
10173         new_decl_length = D3DXGetDeclLength(new_declaration);
10174         ok(new_decl_length == exp_new_decl_length,
10175            "Test case %d failed. Got new declaration length %d, expected %d\n",
10176            i, new_decl_length, exp_new_decl_length);
10177 
10178         /* Check declaration size */
10179         exp_new_decl_size = D3DXGetDeclVertexSize(tc[i].new_declaration, 0);
10180         new_decl_size = D3DXGetDeclVertexSize(new_declaration, 0);
10181         ok(new_decl_size == exp_new_decl_size,
10182            "Test case %d failed. Got new declaration size %d, expected %d\n",
10183            i, new_decl_size, exp_new_decl_size);
10184 
10185         /* Check vertex data in cloned mesh */
10186         hr = mesh_clone->lpVtbl->LockVertexBuffer(mesh_clone, 0, (void**)&vertices);
10187         if (FAILED(hr))
10188         {
10189             skip("Couldn't lock cloned vertex buffer.\n");
10190             goto cleanup;
10191         }
10192         for (j = 0; j < tc[i].num_vertices; j++)
10193         {
10194             UINT index = tc[i].exp_vertex_size * j;
10195             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].new_declaration);
10196         }
10197         hr = mesh_clone->lpVtbl->UnlockVertexBuffer(mesh_clone);
10198         if (FAILED(hr))
10199         {
10200             skip("Couldn't unlock vertex buffer.\n");
10201             goto cleanup;
10202         }
10203         vertices = NULL;
10204         mesh->lpVtbl->Release(mesh);
10205         mesh = NULL;
10206         mesh_clone->lpVtbl->Release(mesh_clone);
10207         mesh_clone = NULL;
10208     }
10209 
10210     /* The following test shows that it is not possible to share a vertex buffer
10211      * with D3DXMESH_VB_SHARE and change the vertex declaration at the same
10212      * time. It reuses the test data from test 2.
10213      */
10214     hr = init_test_mesh(tc[2].num_faces, tc[2].num_vertices,
10215                         tc[2].create_options,
10216                         tc[2].declaration,
10217                         test_context->device, &mesh,
10218                         tc[2].vertices, tc[2].vertex_size,
10219                         tc[2].indices, tc[2].attributes);
10220     if (FAILED(hr))
10221     {
10222         skip("Couldn't initialize test mesh for D3DXMESH_VB_SHARE case."
10223              " Got %x expected D3D_OK\n", hr);
10224         goto cleanup;
10225     }
10226 
10227     hr = mesh->lpVtbl->CloneMesh(mesh, tc[2].create_options | D3DXMESH_VB_SHARE,
10228                                  tc[2].new_declaration, test_context->device,
10229                                  &mesh_clone);
10230     ok(hr == D3DERR_INVALIDCALL, "CloneMesh D3DXMESH_VB_SHARE with new"
10231        " declaration. Got %x, expected D3DERR_INVALIDCALL\n",
10232        hr);
10233     mesh->lpVtbl->Release(mesh);
10234     mesh = NULL;
10235     mesh_clone = NULL;
10236 
10237 cleanup:
10238     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
10239     if (mesh) mesh->lpVtbl->Release(mesh);
10240     if (mesh_clone) mesh_clone->lpVtbl->Release(mesh_clone);
10241     free_test_context(test_context);
10242 }
10243 
10244 static void test_valid_mesh(void)
10245 {
10246     HRESULT hr;
10247     struct test_context *test_context = NULL;
10248     UINT i;
10249     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
10250     const D3DVERTEXELEMENT9 declaration[] =
10251     {
10252         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10253         D3DDECL_END()
10254     };
10255     const unsigned int VERTS_PER_FACE = 3;
10256     /* mesh0 (one face)
10257      *
10258      * 0--1
10259      * | /
10260      * |/
10261      * 2
10262      */
10263     const D3DXVECTOR3 vertices0[] =
10264     {
10265         { 0.0f,  3.0f,  0.f},
10266         { 2.0f,  3.0f,  0.f},
10267         { 0.0f,  0.0f,  0.f},
10268     };
10269     const DWORD indices0[] = {0, 1, 2};
10270     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
10271     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
10272     const DWORD adjacency0[] = {-1, -1, -1};
10273     const HRESULT exp_hr0 = D3D_OK;
10274     /* mesh1 (Simple bow-tie)
10275      *
10276      * 0--1 1--3
10277      * | /   \ |
10278      * |/     \|
10279      * 2       4
10280      */
10281     const D3DXVECTOR3 vertices1[] =
10282     {
10283         { 0.0f,  3.0f,  0.f},
10284         { 2.0f,  3.0f,  0.f},
10285         { 0.0f,  0.0f,  0.f},
10286 
10287         { 4.0f,  3.0f,  0.f},
10288         { 4.0f,  0.0f,  0.f},
10289     };
10290     const DWORD indices1[] = {0, 1, 2, 1, 3, 4};
10291     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
10292     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
10293     const DWORD adjacency1[] = {-1, -1, -1, -1, -1, -1};
10294     const HRESULT exp_hr1 = D3DXERR_INVALIDMESH;
10295     /* Common mesh data */
10296     ID3DXMesh *mesh = NULL;
10297     UINT vertex_size = sizeof(D3DXVECTOR3);
10298     ID3DXBuffer *errors_and_warnings = NULL;
10299     struct
10300     {
10301         const D3DXVECTOR3 *vertices;
10302         const DWORD *indices;
10303         const UINT num_vertices;
10304         const UINT num_faces;
10305         const DWORD *adjacency;
10306         const HRESULT exp_hr;
10307     }
10308     tc[] =
10309     {
10310         {
10311             vertices0,
10312             indices0,
10313             num_vertices0,
10314             num_faces0,
10315             adjacency0,
10316             exp_hr0,
10317         },
10318         {
10319             vertices1,
10320             indices1,
10321             num_vertices1,
10322             num_faces1,
10323             adjacency1,
10324             exp_hr1,
10325         },
10326     };
10327 
10328     test_context = new_test_context();
10329     if (!test_context)
10330     {
10331         skip("Couldn't create test context\n");
10332         goto cleanup;
10333     }
10334 
10335     for (i = 0; i < ARRAY_SIZE(tc); i++)
10336     {
10337         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10338                             options, declaration,
10339                             test_context->device, &mesh,
10340                             tc[i].vertices, vertex_size,
10341                             tc[i].indices, NULL);
10342         if (FAILED(hr))
10343         {
10344             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10345             goto cleanup;
10346         }
10347 
10348         hr = D3DXValidMesh(mesh, tc[i].adjacency, &errors_and_warnings);
10349         todo_wine ok(hr == tc[i].exp_hr, "D3DXValidMesh test case %d failed. "
10350                      "Got %x\n, expected %x\n", i, hr, tc[i].exp_hr);
10351 
10352         /* Note errors_and_warnings is deliberately not checked because that
10353          * would require copying wast amounts of the text output. */
10354         if (errors_and_warnings)
10355         {
10356             ID3DXBuffer_Release(errors_and_warnings);
10357             errors_and_warnings = NULL;
10358         }
10359         mesh->lpVtbl->Release(mesh);
10360         mesh = NULL;
10361     }
10362 
10363 cleanup:
10364     if (mesh) mesh->lpVtbl->Release(mesh);
10365     free_test_context(test_context);
10366 }
10367 
10368 static void test_optimize_faces(void)
10369 {
10370     HRESULT hr;
10371     UINT i;
10372     DWORD smallest_face_remap;
10373     /* mesh0
10374      *
10375      * 0--1
10376      * | /
10377      * |/
10378      * 2
10379      */
10380     const DWORD indices0[] = {0, 1, 2};
10381     const UINT num_faces0 = 1;
10382     const UINT num_vertices0 = 3;
10383     const DWORD exp_face_remap0[] = {0};
10384     /* mesh1
10385      *
10386      * 0--1 3
10387      * | / /|
10388      * |/ / |
10389      * 2 5--4
10390      */
10391     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
10392     const UINT num_faces1 = 2;
10393     const UINT num_vertices1 = 6;
10394     const DWORD exp_face_remap1[] = {1, 0};
10395     /* mesh2
10396      *
10397      * 0--1
10398      * | /|
10399      * |/ |
10400      * 2--3
10401      */
10402     const DWORD indices2[] = {0, 1, 2, 1, 3, 2};
10403     const UINT num_faces2 = 2;
10404     const UINT num_vertices2 = 4;
10405     const DWORD exp_face_remap2[] = {1, 0};
10406     /* mesh3
10407      *
10408      * 0--1
10409      * | /|
10410      * |/ |
10411      * 2--3
10412      * | /|
10413      * |/ |
10414      * 4--5
10415      */
10416     const DWORD indices3[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
10417     const UINT num_faces3 = 4;
10418     const UINT num_vertices3 = 6;
10419     const DWORD exp_face_remap3[] = {3, 2, 1, 0};
10420     /* mesh4
10421      *
10422      * 0--1
10423      * | /|
10424      * |/ |
10425      * 2--3
10426      * | /|
10427      * |/ |
10428      * 4--5
10429      */
10430     const WORD indices4[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
10431     const UINT num_faces4 = 4;
10432     const UINT num_vertices4 = 6;
10433     const DWORD exp_face_remap4[] = {3, 2, 1, 0};
10434     /* Test cases are stored in the tc array */
10435     struct
10436     {
10437         const VOID *indices;
10438         const UINT num_faces;
10439         const UINT num_vertices;
10440         const BOOL indices_are_32bit;
10441         const DWORD *exp_face_remap;
10442     }
10443     tc[] =
10444     {
10445         {
10446             indices0,
10447             num_faces0,
10448             num_vertices0,
10449             TRUE,
10450             exp_face_remap0
10451         },
10452         {
10453             indices1,
10454             num_faces1,
10455             num_vertices1,
10456             TRUE,
10457             exp_face_remap1
10458         },
10459         {
10460             indices2,
10461             num_faces2,
10462             num_vertices2,
10463             TRUE,
10464             exp_face_remap2
10465         },
10466         {
10467             indices3,
10468             num_faces3,
10469             num_vertices3,
10470             TRUE,
10471             exp_face_remap3
10472         },
10473         {
10474             indices4,
10475             num_faces4,
10476             num_vertices4,
10477             FALSE,
10478             exp_face_remap4
10479         },
10480     };
10481 
10482     /* Go through all test cases */
10483     for (i = 0; i < ARRAY_SIZE(tc); i++)
10484     {
10485         DWORD j;
10486         DWORD *face_remap;
10487         face_remap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
10488                                tc[i].num_faces*sizeof(*face_remap));
10489 
10490         hr = D3DXOptimizeFaces(tc[i].indices, tc[i].num_faces,
10491                                tc[i].num_vertices, tc[i].indices_are_32bit,
10492                                face_remap);
10493         ok(hr == D3D_OK, "D3DXOptimizeFaces test case %d failed. "
10494            "Got %x\n, expected D3D_OK\n", i, hr);
10495 
10496         /* Compare face remap with expected face remap */
10497         for (j = 0; j < tc[i].num_faces; j++)
10498         {
10499             ok(tc[i].exp_face_remap[j] == face_remap[j],
10500                "Test case %d: Got face %d at %d, expected %d\n", i,
10501                face_remap[j], j, tc[i].exp_face_remap[j]);
10502         }
10503 
10504         HeapFree(GetProcessHeap(), 0, face_remap);
10505     }
10506 
10507     /* face_remap must not be NULL */
10508     hr = D3DXOptimizeFaces(tc[0].indices, tc[0].num_faces,
10509                            tc[0].num_vertices, tc[0].indices_are_32bit,
10510                            NULL);
10511     ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeFaces passed NULL face_remap "
10512        "pointer. Got %x\n, expected D3DERR_INVALIDCALL\n", hr);
10513 
10514     /* Number of faces must be smaller than 2^15 */
10515     hr = D3DXOptimizeFaces(tc[0].indices, 2 << 15,
10516                            tc[0].num_vertices, FALSE,
10517                            &smallest_face_remap);
10518     ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeFaces should not accept 2^15 "
10519     "faces when using 16-bit indices. Got %x\n, expected D3DERR_INVALIDCALL\n", hr);
10520 }
10521 
10522 static HRESULT clear_normals(ID3DXMesh *mesh)
10523 {
10524     HRESULT hr;
10525     BYTE *vertices;
10526     size_t normal_size;
10527     DWORD i, num_vertices, vertex_stride;
10528     const D3DXVECTOR4 normal = {NAN, NAN, NAN, NAN};
10529     D3DVERTEXELEMENT9 *normal_declaration = NULL;
10530     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
10531 
10532     if (FAILED(hr = mesh->lpVtbl->GetDeclaration(mesh, declaration)))
10533         return hr;
10534 
10535     for (i = 0; declaration[i].Stream != 0xff; i++)
10536     {
10537         if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
10538         {
10539             normal_declaration = &declaration[i];
10540             break;
10541         }
10542     }
10543 
10544     if (!normal_declaration)
10545         return D3DERR_INVALIDCALL;
10546 
10547     if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
10548     {
10549         normal_size = sizeof(D3DXVECTOR3);
10550     }
10551     else if (normal_declaration->Type == D3DDECLTYPE_FLOAT4)
10552     {
10553         normal_size = sizeof(D3DXVECTOR4);
10554     }
10555     else
10556     {
10557         trace("Cannot clear normals\n");
10558         return E_NOTIMPL;
10559     }
10560 
10561     num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
10562     vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
10563 
10564     if (FAILED(hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
10565         return hr;
10566 
10567     vertices += normal_declaration->Offset;
10568 
10569     for (i = 0; i < num_vertices; i++, vertices += vertex_stride)
10570         memcpy(vertices, &normal, normal_size);
10571 
10572     return mesh->lpVtbl->UnlockVertexBuffer(mesh);
10573 }
10574 
10575 static void compare_normals(unsigned int line, const char *test_name,
10576         ID3DXMesh *mesh, const D3DXVECTOR3 *normals, unsigned int num_normals)
10577 {
10578     unsigned int i;
10579     BYTE *vertices;
10580     DWORD num_vertices, vertex_stride;
10581     D3DVERTEXELEMENT9 *normal_declaration = NULL;
10582     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
10583 
10584     if (FAILED(mesh->lpVtbl->GetDeclaration(mesh, declaration)))
10585     {
10586         ok_(__FILE__, line)(0, "%s: Failed to get declaration\n", test_name);
10587         return;
10588     }
10589 
10590     for (i = 0; declaration[i].Stream != 0xff; i++)
10591     {
10592         if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
10593         {
10594             normal_declaration = &declaration[i];
10595             break;
10596         }
10597     }
10598 
10599     if (!normal_declaration)
10600     {
10601         ok_(__FILE__, line)(0, "%s: Mesh has no normals\n", test_name);
10602         return;
10603     }
10604 
10605     if (normal_declaration->Type != D3DDECLTYPE_FLOAT3 && normal_declaration->Type != D3DDECLTYPE_FLOAT4)
10606     {
10607         ok_(__FILE__, line)(0, "%s: Mesh has invalid normals type\n", test_name);
10608         return;
10609     }
10610 
10611     num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
10612     vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
10613 
10614     ok_(__FILE__, line)(num_vertices == num_normals, "%s: Expected %u vertices, got %u\n", test_name,
10615             num_normals, num_vertices);
10616 
10617     if (FAILED(mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
10618     {
10619         ok_(__FILE__, line)(0, "%s: Failed to compare normals\n", test_name);
10620         return;
10621     }
10622 
10623     vertices += normal_declaration->Offset;
10624 
10625     for (i = 0; i < min(num_vertices, num_normals); i++, vertices += vertex_stride)
10626     {
10627         if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
10628         {
10629             const D3DXVECTOR3 *n = (D3DXVECTOR3 *)vertices;
10630             ok_(__FILE__, line)(compare_vec3(*n, normals[i]),
10631                     "%s: normal %2u, expected (%f, %f, %f), got (%f, %f, %f)\n",
10632                     test_name, i, normals[i].x, normals[i].y, normals[i].z, n->x, n->y, n->z);
10633         }
10634         else
10635         {
10636             const D3DXVECTOR4 *n = (D3DXVECTOR4 *)vertices;
10637             const D3DXVECTOR4 normal = {normals[i].x, normals[i].y, normals[i].z, 1.0f};
10638             ok_(__FILE__, line)(compare_vec4(*n, normal),
10639                     "%s: normal %2u, expected (%f, %f, %f, %f), got (%f, %f, %f, %f)\n",
10640                     test_name, i, normals[i].x, normals[i].y, normals[i].z, 1.0f,
10641                     n->x, n->y, n->z, n->w);
10642         }
10643     }
10644 
10645     mesh->lpVtbl->UnlockVertexBuffer(mesh);
10646 }
10647 
10648 static HRESULT compute_normals_D3DXComputeNormals(ID3DXMesh *mesh, const DWORD *adjacency)
10649 {
10650     return D3DXComputeNormals((ID3DXBaseMesh *)mesh, adjacency);
10651 }
10652 
10653 static HRESULT compute_normals_D3DXComputeTangentFrameEx(ID3DXMesh *mesh, const DWORD *adjacency)
10654 {
10655     return D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10656             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
10657             adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL);
10658 }
10659 
10660 static void test_compute_normals(void)
10661 {
10662     HRESULT hr;
10663     ULONG refcount;
10664     ID3DXMesh *mesh, *cloned_mesh;
10665     ID3DXBuffer *adjacency;
10666     IDirect3DDevice9 *device;
10667     struct test_context *test_context;
10668     unsigned int i;
10669 
10670     static const struct compute_normals_func
10671     {
10672         const char *name;
10673         HRESULT (*apply)(ID3DXMesh *mesh, const DWORD *adjacency);
10674     }
10675     compute_normals_funcs[] =
10676     {
10677         {"D3DXComputeNormals",        compute_normals_D3DXComputeNormals       },
10678         {"D3DXComputeTangentFrameEx", compute_normals_D3DXComputeTangentFrameEx}
10679     };
10680 
10681     static const D3DXVECTOR3 box_normals[24] =
10682     {
10683         {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f},
10684         { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f},
10685         { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f},
10686         { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f},
10687         { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f},
10688         { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}
10689     };
10690     const float box_normal_component = 1.0f / sqrtf(3.0f);
10691     const D3DXVECTOR3 box_normals_adjacency[24] =
10692     {
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         {-box_normal_component,  box_normal_component, -box_normal_component},
10715         { box_normal_component,  box_normal_component, -box_normal_component},
10716         { box_normal_component, -box_normal_component, -box_normal_component}
10717     };
10718     static const D3DXVECTOR3 box_normals_adjacency_area[24] =
10719     {
10720         {-0.666667f, -0.333333f, -0.666667f}, {-0.333333f, -0.666667f,  0.666667f},
10721         {-0.816496f,  0.408248f,  0.408248f}, {-0.408248f,  0.816496f, -0.408248f},
10722         {-0.408248f,  0.816496f, -0.408248f}, {-0.816496f,  0.408248f,  0.408248f},
10723         { 0.333333f,  0.666667f,  0.666667f}, { 0.666667f,  0.333333f, -0.666667f},
10724         { 0.666667f,  0.333333f, -0.666667f}, { 0.333333f,  0.666667f,  0.666667f},
10725         { 0.816496f, -0.408248f,  0.408248f}, { 0.408248f, -0.816496f, -0.408248f},
10726         {-0.333333f, -0.666667f,  0.666667f}, {-0.666667f, -0.333333f, -0.666667f},
10727         { 0.408248f, -0.816496f, -0.408248f}, { 0.816496f, -0.408248f,  0.408248f},
10728         {-0.333333f, -0.666667f,  0.666667f}, { 0.816497f, -0.408248f,  0.408248f},
10729         { 0.333333f,  0.666667f,  0.666667f}, {-0.816497f,  0.408248f,  0.408248f},
10730         {-0.666667f, -0.333333f, -0.666667f}, {-0.408248f,  0.816497f, -0.408248f},
10731         { 0.666667f,  0.333333f, -0.666667f}, { 0.408248f, -0.816496f, -0.408248f}
10732     };
10733     static const D3DXVECTOR3 box_normals_position1f[24] = {{0}};
10734     static const D3DXVECTOR3 box_normals_position2f[24] =
10735     {
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         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
10742         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
10743         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}
10744     };
10745 
10746     static const D3DXVECTOR3 sphere_normals[22] =
10747     {
10748         { 0.000000f, -0.000000f,  1.000000f}, { 0.000000f,  0.582244f,  0.813014f},
10749         { 0.582244f, -0.000000f,  0.813014f}, {-0.000000f, -0.582244f,  0.813014f},
10750         {-0.582244f,  0.000000f,  0.813014f}, {-0.000000f,  0.890608f,  0.454772f},
10751         { 0.890608f,  0.000000f,  0.454772f}, { 0.000000f, -0.890608f,  0.454772f},
10752         {-0.890608f, -0.000000f,  0.454772f}, { 0.000000f,  1.000000f, -0.000000f},
10753         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10754         {-1.000000f,  0.000000f, -0.000000f}, { 0.000000f,  0.890608f, -0.454773f},
10755         { 0.890608f, -0.000000f, -0.454772f}, {-0.000000f, -0.890608f, -0.454773f},
10756         {-0.890608f,  0.000000f, -0.454773f}, { 0.000000f,  0.582244f, -0.813015f},
10757         { 0.582244f, -0.000000f, -0.813015f}, { 0.000000f, -0.582244f, -0.813015f},
10758         {-0.582243f,  0.000000f, -0.813015f}, { 0.000000f,  0.000000f, -1.000000f}
10759     };
10760     static const D3DXVECTOR3 sphere_normals_area[22] =
10761     {
10762         { 0.000000f, -0.000000f,  1.000000f}, {-0.215311f,  0.554931f,  0.803550f},
10763         { 0.554931f,  0.215311f,  0.803550f}, { 0.215311f, -0.554931f,  0.803550f},
10764         {-0.554931f, -0.215311f,  0.803550f}, {-0.126638f,  0.872121f,  0.472618f},
10765         { 0.872121f,  0.126638f,  0.472618f}, { 0.126638f, -0.872121f,  0.472618f},
10766         {-0.872121f, -0.126637f,  0.472618f}, { 0.000000f,  1.000000f, -0.000000f},
10767         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10768         {-1.000000f,  0.000000f, -0.000000f}, { 0.126638f,  0.872121f, -0.472618f},
10769         { 0.872121f, -0.126638f, -0.472618f}, {-0.126638f, -0.872121f, -0.472618f},
10770         {-0.872121f,  0.126638f, -0.472618f}, { 0.215311f,  0.554931f, -0.803550f},
10771         { 0.554931f, -0.215311f, -0.803550f}, {-0.215311f, -0.554931f, -0.803550f},
10772         {-0.554931f,  0.215311f, -0.803550f}, { 0.000000f,  0.000000f, -1.000000f}
10773     };
10774     static const D3DXVECTOR3 sphere_normals_equal[22] =
10775     {
10776         { 0.000000f, -0.000000f,  1.000000f}, {-0.134974f,  0.522078f,  0.842150f},
10777         { 0.522078f,  0.134974f,  0.842150f}, { 0.134974f, -0.522078f,  0.842150f},
10778         {-0.522078f, -0.134974f,  0.842150f}, {-0.026367f,  0.857121f,  0.514440f},
10779         { 0.857121f,  0.026367f,  0.514440f}, { 0.026367f, -0.857121f,  0.514440f},
10780         {-0.857121f, -0.026367f,  0.514440f}, { 0.000000f,  1.000000f, -0.000000f},
10781         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10782         {-1.000000f,  0.000000f, -0.000000f}, { 0.026367f,  0.857121f, -0.514440f},
10783         { 0.857121f, -0.026367f, -0.514440f}, {-0.026367f, -0.857121f, -0.514440f},
10784         {-0.857121f,  0.026367f, -0.514440f}, { 0.134975f,  0.522078f, -0.842150f},
10785         { 0.522078f, -0.134975f, -0.842150f}, {-0.134974f, -0.522078f, -0.842150f},
10786         {-0.522078f,  0.134974f, -0.842150f}, { 0.000000f,  0.000000f, -1.000000f}
10787     };
10788 
10789     static const D3DVERTEXELEMENT9 position3f_normal1f_declaration[] =
10790     {
10791         {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10792         {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10793         D3DDECL_END()
10794     };
10795     static const D3DVERTEXELEMENT9 position3f_normal2f_declaration[] =
10796     {
10797         {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10798         {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10799         D3DDECL_END()
10800     };
10801     static const D3DVERTEXELEMENT9 normal4f_position3f_declaration[] =
10802     {
10803         {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10804         {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10805         D3DDECL_END()
10806     };
10807     static const D3DVERTEXELEMENT9 position1f_normal3f_declaration[] =
10808     {
10809         {0, 0,                   D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10810         {0, sizeof(float),       D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10811         D3DDECL_END()
10812     };
10813     static const D3DVERTEXELEMENT9 position2f_normal3f_declaration[] =
10814     {
10815         {0, 0,                   D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10816         {0, sizeof(D3DXVECTOR2), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10817         D3DDECL_END()
10818     };
10819     static const D3DVERTEXELEMENT9 position4f_normal3f_declaration[] =
10820     {
10821         {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10822         {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10823         D3DDECL_END()
10824     };
10825 
10826     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
10827     {
10828         hr = compute_normals_funcs[i].apply(NULL, NULL);
10829         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", compute_normals_funcs[i].name, hr);
10830     }
10831 
10832     if (!(test_context = new_test_context()))
10833     {
10834         skip("Couldn't create test context\n");
10835         return;
10836     }
10837     device = test_context->device;
10838 
10839     hr = D3DXCreateBox(device, 1.0f, 1.0f, 1.0f, &mesh, &adjacency);
10840     ok(SUCCEEDED(hr), "D3DXCreateBox failed %#x\n", hr);
10841 
10842     /* Check wrong input */
10843     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10844             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10845     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10846 
10847     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DDECLUSAGE_NORMAL, 0,
10848             D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA | D3DXTANGENT_WEIGHT_EQUAL,
10849             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10850     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10851 
10852     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10853             D3DDECLUSAGE_NORMAL, 0, 0, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10854     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10855 
10856     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10857             D3DDECLUSAGE_NORMAL, 1, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
10858             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10859     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10860 
10861     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10862             D3DX_DEFAULT, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
10863             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10864     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10865 
10866     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10867             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_CALCULATE_NORMALS,
10868             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10869     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
10870 
10871     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
10872     {
10873         const struct compute_normals_func *func = &compute_normals_funcs[i];
10874 
10875         /* Mesh without normals */
10876         hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_XYZ, device, &cloned_mesh);
10877         ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
10878 
10879         hr = func->apply(cloned_mesh, NULL);
10880         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
10881 
10882         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10883         ok(!refcount, "Mesh has %u references left\n", refcount);
10884 
10885         /* Mesh without positions */
10886         hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_NORMAL, device, &cloned_mesh);
10887         ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
10888 
10889         hr = func->apply(cloned_mesh, NULL);
10890         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
10891 
10892         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10893         ok(!refcount, "Mesh has %u references left\n", refcount);
10894 
10895         /* Mesh with D3DDECLTYPE_FLOAT1 normals */
10896         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal1f_declaration, device, &cloned_mesh);
10897         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10898 
10899         hr = func->apply(cloned_mesh, NULL);
10900         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
10901 
10902         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10903         ok(!refcount, "Mesh has %u references left\n", refcount);
10904 
10905         /* Mesh with D3DDECLTYPE_FLOAT2 normals */
10906         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal2f_declaration, device, &cloned_mesh);
10907         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10908 
10909         hr = func->apply(cloned_mesh, NULL);
10910         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
10911 
10912         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10913         ok(!refcount, "Mesh has %u references left\n", refcount);
10914 
10915         /* Mesh without adjacency data */
10916         hr = clear_normals(mesh);
10917         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10918 
10919         hr = func->apply(mesh, NULL);
10920         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10921 
10922         compare_normals(__LINE__, func->name, mesh, box_normals, ARRAY_SIZE(box_normals));
10923 
10924         /* Mesh with adjacency data */
10925         hr = clear_normals(mesh);
10926         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10927 
10928         hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
10929         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10930 
10931         compare_normals(__LINE__, func->name, mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
10932 
10933         /* Mesh with custom vertex format, D3DDECLTYPE_FLOAT4 normals and adjacency */
10934         hr = mesh->lpVtbl->CloneMesh(mesh, 0, normal4f_position3f_declaration, device, &cloned_mesh);
10935         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10936 
10937         hr = clear_normals(cloned_mesh);
10938         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10939 
10940         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
10941         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10942 
10943         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
10944 
10945         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10946         ok(!refcount, "Mesh has %u references left\n", refcount);
10947 
10948         /* Mesh with D3DDECLTYPE_FLOAT1 positions and D3DDECLTYPE_FLOAT3 normals */
10949         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position1f_normal3f_declaration, device, &cloned_mesh);
10950         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10951 
10952         hr = clear_normals(cloned_mesh);
10953         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10954 
10955         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
10956         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10957 
10958         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position1f, ARRAY_SIZE(box_normals_position1f));
10959 
10960         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10961         ok(!refcount, "Mesh has %u references left\n", refcount);
10962 
10963         /* Mesh with D3DDECLTYPE_FLOAT2 positions and D3DDECLTYPE_FLOAT3 normals */
10964         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position2f_normal3f_declaration, device, &cloned_mesh);
10965         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10966 
10967         hr = clear_normals(cloned_mesh);
10968         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10969 
10970         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
10971         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10972 
10973         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position2f, ARRAY_SIZE(box_normals_position2f));
10974 
10975         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10976         ok(!refcount, "Mesh has %u references left\n", refcount);
10977 
10978         /* Mesh with D3DDECLTYPE_FLOAT4 positions and D3DDECLTYPE_FLOAT3 normals */
10979         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position4f_normal3f_declaration, device, &cloned_mesh);
10980         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
10981 
10982         hr = clear_normals(cloned_mesh);
10983         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
10984 
10985         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
10986         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
10987 
10988         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
10989 
10990         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
10991         ok(!refcount, "Mesh has %u references left\n", refcount);
10992     }
10993 
10994     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10995             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
10996             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
10997     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
10998 
10999     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
11000 
11001     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11002             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11003             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11004     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11005 
11006     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
11007 
11008     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11009             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11010             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11011     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11012 
11013     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
11014 
11015     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11016             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11017             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11018     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11019 
11020     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
11021 
11022     refcount = mesh->lpVtbl->Release(mesh);
11023     ok(!refcount, "Mesh has %u references left\n", refcount);
11024     refcount = ID3DXBuffer_Release(adjacency);
11025     ok(!refcount, "Buffer has %u references left\n", refcount);
11026 
11027     hr = D3DXCreateSphere(device, 1.0f, 4, 6, &mesh, &adjacency);
11028     ok(SUCCEEDED(hr), "D3DXCreateSphere failed %#x\n", hr);
11029 
11030     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
11031     {
11032         const struct compute_normals_func *func = &compute_normals_funcs[i];
11033 
11034         /* Sphere without adjacency data */
11035         hr = clear_normals(mesh);
11036         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11037 
11038         hr = func->apply(mesh, NULL);
11039         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11040 
11041         compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
11042 
11043         /* Sphere with adjacency data */
11044         hr = clear_normals(mesh);
11045         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11046 
11047         hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11048         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11049 
11050         compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
11051     }
11052 
11053     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11054             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11055             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11056     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11057 
11058     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
11059 
11060     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11061             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11062             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11063     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11064 
11065     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
11066 
11067     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11068             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11069             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11070     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11071 
11072     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
11073 
11074     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11075             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11076             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11077     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11078 
11079     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
11080 
11081     refcount = mesh->lpVtbl->Release(mesh);
11082     ok(!refcount, "Mesh has %u references left\n", refcount);
11083     refcount = ID3DXBuffer_Release(adjacency);
11084     ok(!refcount, "Buffer has %u references left\n", refcount);
11085 
11086     free_test_context(test_context);
11087 }
11088 
11089 static void D3DXCreateAnimationControllerTest(void)
11090 {
11091     HRESULT hr;
11092     ID3DXAnimationController *animation;
11093     UINT value;
11094 
11095     hr = D3DXCreateAnimationController(0, 0, 0, 0, NULL);
11096     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11097 
11098     animation = (void*)0xdeadbeef;
11099     hr = D3DXCreateAnimationController(0, 1, 1, 1, &animation);
11100     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11101     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11102 
11103     animation = (void*)0xdeadbeef;
11104     hr = D3DXCreateAnimationController(1, 0, 1, 1, &animation);
11105     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11106     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11107 
11108     animation = (void*)0xdeadbeef;
11109     hr = D3DXCreateAnimationController(1, 1, 0, 1, &animation);
11110     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11111     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11112 
11113     animation = (void*)0xdeadbeef;
11114     hr = D3DXCreateAnimationController(1, 1, 1, 0, &animation);
11115     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11116     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11117 
11118     hr = D3DXCreateAnimationController(1, 1, 1, 1, &animation);
11119     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11120 
11121     value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
11122     ok(value == 1, "Got unexpected value %u.\n", value);
11123 
11124     value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
11125     ok(value == 1, "Got unexpected value %u.\n", value);
11126 
11127     value = animation->lpVtbl->GetMaxNumTracks(animation);
11128     ok(value == 1, "Got unexpected value %u.\n", value);
11129 
11130     value = animation->lpVtbl->GetMaxNumEvents(animation);
11131     ok(value == 1, "Got unexpected value %u.\n", value);
11132 
11133     animation->lpVtbl->Release(animation);
11134 
11135     hr = D3DXCreateAnimationController(100, 101, 102, 103, &animation);
11136     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11137 
11138     value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
11139     ok(value == 100, "Got unexpected value %u.\n", value);
11140 
11141     value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
11142     ok(value == 101, "Got unexpected value %u.\n", value);
11143 
11144     value = animation->lpVtbl->GetMaxNumTracks(animation);
11145     ok(value == 102, "Got unexpected value %u.\n", value);
11146 
11147     value = animation->lpVtbl->GetMaxNumEvents(animation);
11148     ok(value == 103, "Got unexpected value %u.\n", value);
11149 
11150     animation->lpVtbl->Release(animation);
11151 }
11152 
11153 static void test_D3DXFrameFind(void)
11154 {
11155     static char n1[] = "name1";
11156     static char n2[] = "name2";
11157     static char n3[] = "name3";
11158     static char n4[] = "name4";
11159     static char n5[] = "name5";
11160     static char n6[] = "name6";
11161     static char N1[] = "Name1";
11162     D3DXFRAME root, sibling, sibling2, child, *ret;
11163     D3DXFRAME child2, child3;
11164 
11165     ret = D3DXFrameFind(NULL, NULL);
11166     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11167 
11168     ret = D3DXFrameFind(NULL, "test");
11169     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11170 
11171     memset(&root, 0, sizeof(root));
11172 
11173     ret = D3DXFrameFind(&root, NULL);
11174     ok(ret == &root, "Unexpected frame, %p.\n", ret);
11175 
11176     root.Name = n1;
11177     ret = D3DXFrameFind(&root, NULL);
11178     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11179 
11180     ret = D3DXFrameFind(&root, n1);
11181     ok(ret == &root, "Unexpected frame, %p.\n", ret);
11182 
11183     ret = D3DXFrameFind(&root, N1);
11184     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11185 
11186     /* Test siblings order traversal. */
11187     memset(&sibling, 0, sizeof(sibling));
11188     sibling.Name = n2;
11189     root.pFrameSibling = &sibling;
11190     ret = D3DXFrameFind(&root, n2);
11191     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11192 
11193     memset(&sibling2, 0, sizeof(sibling2));
11194     sibling2.Name = n2;
11195     sibling.pFrameSibling = &sibling2;
11196     ret = D3DXFrameFind(&root, n2);
11197     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11198 
11199     sibling2.Name = n3;
11200     ret = D3DXFrameFind(&root, n3);
11201     ok(ret == &sibling2, "Unexpected frame, %p.\n", ret);
11202 
11203     /* Siblings first. */
11204     memset(&child, 0, sizeof(child));
11205     child.Name = n2;
11206     root.pFrameFirstChild = &child;
11207     ret = D3DXFrameFind(&root, n2);
11208     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11209 
11210     child.Name = n4;
11211     ret = D3DXFrameFind(&root, n4);
11212     ok(ret == &child, "Unexpected frame, %p.\n", ret);
11213 
11214     /* Link a grandchild and another one for sibling. */
11215     memset(&child2, 0, sizeof(child2));
11216     memset(&child3, 0, sizeof(child3));
11217     child2.Name = child3.Name = n5;
11218     sibling.pFrameFirstChild = &child2;
11219     child.pFrameFirstChild = &child3;
11220     ret = D3DXFrameFind(&root, n5);
11221     ok(ret == &child2, "Unexpected frame, %p.\n", ret);
11222 
11223     child3.Name = n6;
11224     ret = D3DXFrameFind(&root, n6);
11225     ok(ret == &child3, "Unexpected frame, %p.\n", ret);
11226 }
11227 
11228 static ID3DXFileData *get_mesh_data(const void *memory, SIZE_T length)
11229 {
11230     ID3DXFileData *file_data, *ret = NULL;
11231     ID3DXFileEnumObject *enum_obj = NULL;
11232     D3DXF_FILELOADMEMORY source;
11233     ID3DXFile *file;
11234     SIZE_T i, count;
11235     GUID guid;
11236 
11237     if (FAILED(D3DXFileCreate(&file)))
11238         return NULL;
11239 
11240     if (FAILED(file->lpVtbl->RegisterTemplates(file, D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
11241         goto cleanup;
11242 
11243     source.lpMemory = memory;
11244     source.dSize = length;
11245     if (FAILED(file->lpVtbl->CreateEnumObject(file, &source, D3DXF_FILELOAD_FROMMEMORY, &enum_obj)))
11246         goto cleanup;
11247 
11248     if (FAILED(enum_obj->lpVtbl->GetChildren(enum_obj, &count)))
11249         goto cleanup;
11250 
11251     for (i = 0; i < count; ++i)
11252     {
11253         if (FAILED(enum_obj->lpVtbl->GetChild(enum_obj, i, &file_data)))
11254             goto cleanup;
11255 
11256         if (SUCCEEDED(file_data->lpVtbl->GetType(file_data, &guid))
11257                 && IsEqualGUID(&guid, &TID_D3DRMMesh))
11258         {
11259             ret = file_data;
11260             break;
11261         }
11262         else
11263         {
11264             file_data->lpVtbl->Release(file_data);
11265         }
11266     }
11267 
11268 cleanup:
11269     if (enum_obj)
11270         enum_obj->lpVtbl->Release(enum_obj);
11271     file->lpVtbl->Release(file);
11272 
11273     return ret;
11274 }
11275 
11276 static void test_load_skin_mesh_from_xof(void)
11277 {
11278     static const char simple_xfile[] =
11279         "xof 0303txt 0032"
11280         "Mesh {"
11281             "3;"
11282             "0.0; 0.0; 0.0;,"
11283             "0.0; 1.0; 0.0;,"
11284             "1.0; 1.0; 0.0;;"
11285             "1;"
11286             "3; 0, 1, 2;;"
11287         "}";
11288     static const D3DVERTEXELEMENT9 expected_declaration[] =
11289     {
11290         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
11291         D3DDECL_END(),
11292     };
11293     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
11294     ID3DXBuffer *adjacency, *materials, *effects;
11295     DWORD max_influences[3], count, fvf;
11296     D3DPRESENT_PARAMETERS d3dpp;
11297     IDirect3DDevice9 *device;
11298     ID3DXSkinInfo *skin_info;
11299     ID3DXFileData *file_data;
11300     const char *bone_name;
11301     D3DXMATRIX *matrix;
11302     float influence;
11303     ID3DXMesh *mesh;
11304     IDirect3D9 *d3d;
11305     ULONG refcount;
11306     HRESULT hr;
11307     HWND hwnd;
11308 
11309     if (!(hwnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
11310             640, 480, NULL, NULL, NULL, NULL)))
11311     {
11312         skip("Failed to create application window.\n");
11313         return;
11314     }
11315 
11316     d3d = Direct3DCreate9(D3D_SDK_VERSION);
11317     if (!d3d)
11318     {
11319         skip("Failed to create d3d object.\n");
11320         DestroyWindow(hwnd);
11321         return;
11322     }
11323 
11324     memset(&d3dpp, 0, sizeof(d3dpp));
11325     d3dpp.Windowed = TRUE;
11326     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
11327 
11328     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
11329             D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
11330     IDirect3D9_Release(d3d);
11331     if (FAILED(hr))
11332     {
11333         skip("Failed to create device, hr %#x.\n", hr);
11334         DestroyWindow(hwnd);
11335         return;
11336     }
11337 
11338     file_data = get_mesh_data(simple_xfile, sizeof(simple_xfile) - 1);
11339     ok(!!file_data, "Failed to load mesh data.\n");
11340 
11341     adjacency = materials = effects = (void *)0xdeadbeef;
11342     count = ~0u;
11343     skin_info = (void *)0xdeadbeef;
11344     mesh = (void *)0xdeadbeef;
11345 
11346     hr = D3DXLoadSkinMeshFromXof(file_data, 0, device, &adjacency, &materials, &effects, &count,
11347             &skin_info, &mesh);
11348     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
11349     ok(!!adjacency, "Got unexpected value %p.\n", adjacency);
11350     ok(!materials, "Got unexpected value %p.\n", materials);
11351     ok(!effects, "Got unexpected value %p.\n", effects);
11352     ok(!count, "Got unexpected value %u.\n", count);
11353     ok(!!skin_info, "Got unexpected value %p.\n", skin_info);
11354     ok(!!mesh, "Got unexpected value %p.\n", mesh);
11355     count = mesh->lpVtbl->GetNumVertices(mesh);
11356     ok(count == 3, "Got unexpected value %u.\n", count);
11357     count = mesh->lpVtbl->GetNumFaces(mesh);
11358     ok(count == 1, "Got unexpected value %u.\n", count);
11359 
11360     hr = skin_info->lpVtbl->GetDeclaration(skin_info, declaration);
11361     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
11362     compare_elements(declaration, expected_declaration, __LINE__, 0);
11363 
11364     fvf = skin_info->lpVtbl->GetFVF(skin_info);
11365     ok(fvf == D3DFVF_XYZ, "Got unexpected value %u.\n", fvf);
11366 
11367     count = skin_info->lpVtbl->GetNumBones(skin_info);
11368     ok(!count, "Got unexpected value %u.\n", count);
11369 
11370     influence = skin_info->lpVtbl->GetMinBoneInfluence(skin_info);
11371     ok(!influence, "Got unexpected value %.8e.\n", influence);
11372 
11373     memset(max_influences, 0x55, sizeof(max_influences));
11374     hr = skin_info->lpVtbl->GetMaxVertexInfluences(skin_info, max_influences);
11375     todo_wine ok(hr == D3D_OK, "Got unexpected value %#x.\n", hr);
11376     todo_wine ok(!max_influences[0], "Got unexpected value %u.\n", max_influences[0]);
11377     ok(max_influences[1] == 0x55555555, "Got unexpected value %u.\n", max_influences[1]);
11378     ok(max_influences[2] == 0x55555555, "Got unexpected value %u.\n", max_influences[2]);
11379 
11380     bone_name = skin_info->lpVtbl->GetBoneName(skin_info, 0);
11381     ok(!bone_name, "Got unexpected value %p.\n", bone_name);
11382 
11383     count = skin_info->lpVtbl->GetNumBoneInfluences(skin_info, 0);
11384     ok(!count, "Got unexpected value %u.\n", count);
11385 
11386     count = skin_info->lpVtbl->GetNumBoneInfluences(skin_info, 1);
11387     ok(!count, "Got unexpected value %u.\n", count);
11388 
11389     matrix = skin_info->lpVtbl->GetBoneOffsetMatrix(skin_info, -1);
11390     ok(!matrix, "Got unexpected value %p.\n", matrix);
11391 
11392     matrix = skin_info->lpVtbl->GetBoneOffsetMatrix(skin_info, 0);
11393     ok(!matrix, "Got unexpected value %p.\n", matrix);
11394 
11395     skin_info->lpVtbl->Release(skin_info);
11396     mesh->lpVtbl->Release(mesh);
11397     adjacency->lpVtbl->Release(adjacency);
11398     file_data->lpVtbl->Release(file_data);
11399     refcount = IDirect3DDevice9_Release(device);
11400     ok(!refcount, "Device has %u references left.\n", refcount);
11401     DestroyWindow(hwnd);
11402 }
11403 
11404 START_TEST(mesh)
11405 {
11406     D3DXBoundProbeTest();
11407     D3DXComputeBoundingBoxTest();
11408     D3DXComputeBoundingSphereTest();
11409     D3DXGetFVFVertexSizeTest();
11410     D3DXIntersectTriTest();
11411     D3DXCreateMeshTest();
11412     D3DXCreateMeshFVFTest();
11413     D3DXLoadMeshTest();
11414     D3DXCreateBoxTest();
11415     D3DXCreatePolygonTest();
11416     D3DXCreateSphereTest();
11417     D3DXCreateCylinderTest();
11418     D3DXCreateTextTest();
11419     D3DXCreateTorusTest();
11420     D3DXCreateAnimationControllerTest();
11421     test_get_decl_length();
11422     test_get_decl_vertex_size();
11423     test_fvf_decl_conversion();
11424     D3DXGenerateAdjacencyTest();
11425     test_update_semantics();
11426     test_create_skin_info();
11427     test_convert_adjacency_to_point_reps();
11428     test_convert_point_reps_to_adjacency();
11429     test_weld_vertices();
11430     test_clone_mesh();
11431     test_valid_mesh();
11432     test_optimize_faces();
11433     test_compute_normals();
11434     test_D3DXFrameFind();
11435     test_load_skin_mesh_from_xof();
11436 }
11437