d3dx9/tests: Show D3DXMESH_VB_SHARE with new declaration should fail.
[wine] / dlls / d3dx9_36 / tests / mesh.c
1 /*
2  * Copyright 2008 David Adam
3  * Copyright 2008 Luis Busquets
4  * Copyright 2009 Henri Verbeet for CodeWeavers
5  * Copyright 2011 Michael Mc Donnell
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define COBJMACROS
23 #include <stdio.h>
24 #include <float.h>
25 #include <limits.h>
26 #include "wine/test.h"
27 #include "d3dx9.h"
28
29 /* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose
30  * function call traces of ID3DXAllocateHierarchy callbacks. */
31 #define TRACECALLBACK if(winetest_debug > 1) trace
32
33 #define admitted_error 0.0001f
34
35 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
36
37 #define compare_vertex_sizes(type, exp) \
38     got=D3DXGetFVFVertexSize(type); \
39     ok(got==exp, "Expected: %d, Got: %d\n", exp, got);
40
41 #define compare_float(got, exp) \
42     do { \
43         float _got = (got); \
44         float _exp = (exp); \
45         ok(_got == _exp, "Expected: %g, Got: %g\n", _exp, _got); \
46     } while (0)
47
48 static BOOL compare(FLOAT u, FLOAT v)
49 {
50     return (fabs(u-v) < admitted_error);
51 }
52
53 static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v)
54 {
55     return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
56 }
57
58 #define check_floats(got, exp, dim) check_floats_(__LINE__, "", got, exp, dim)
59 static void check_floats_(int line, const char *prefix, const float *got, const float *exp, int dim)
60 {
61     int i;
62     char exp_buffer[256] = "";
63     char got_buffer[256] = "";
64     char *exp_buffer_ptr = exp_buffer;
65     char *got_buffer_ptr = got_buffer;
66     BOOL equal = TRUE;
67
68     for (i = 0; i < dim; i++) {
69         if (i) {
70             exp_buffer_ptr += sprintf(exp_buffer_ptr, ", ");
71             got_buffer_ptr += sprintf(got_buffer_ptr, ", ");
72         }
73         equal = equal && compare(*exp, *got);
74         exp_buffer_ptr += sprintf(exp_buffer_ptr, "%g", *exp);
75         got_buffer_ptr += sprintf(got_buffer_ptr, "%g", *got);
76         exp++, got++;
77     }
78     ok_(__FILE__,line)(equal, "%sExpected (%s), got (%s)", prefix, exp_buffer, got_buffer);
79 }
80
81 struct vertex
82 {
83     D3DXVECTOR3 position;
84     D3DXVECTOR3 normal;
85 };
86
87 typedef WORD face[3];
88
89 static BOOL compare_face(face a, face b)
90 {
91     return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
92 }
93
94 struct test_context
95 {
96     HWND hwnd;
97     IDirect3D9 *d3d;
98     IDirect3DDevice9 *device;
99 };
100
101 /* Initializes a test context struct. Use it to initialize DirectX.
102  *
103  * Returns NULL if an error occurred.
104  */
105 static struct test_context *new_test_context(void)
106 {
107     HRESULT hr;
108     HWND hwnd = NULL;
109     IDirect3D9 *d3d = NULL;
110     IDirect3DDevice9 *device = NULL;
111     D3DPRESENT_PARAMETERS d3dpp = {0};
112     struct test_context *test_context;
113
114     hwnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
115     if (!hwnd)
116     {
117         skip("Couldn't create application window\n");
118         goto error;
119     }
120
121     d3d = Direct3DCreate9(D3D_SDK_VERSION);
122     if (!d3d)
123     {
124         skip("Couldn't create IDirect3D9 object\n");
125         goto error;
126     }
127
128     memset(&d3dpp, 0, sizeof(d3dpp));
129     d3dpp.Windowed = TRUE;
130     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
131     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
132                                  D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
133     if (FAILED(hr))
134     {
135         skip("Couldn't create IDirect3DDevice9 object %#x\n", hr);
136         goto error;
137     }
138
139     test_context = HeapAlloc(GetProcessHeap(), 0, sizeof(*test_context));
140     if (!test_context)
141     {
142         skip("Couldn't allocate memory for test_context\n");
143         goto error;
144     }
145     test_context->hwnd = hwnd;
146     test_context->d3d = d3d;
147     test_context->device = device;
148
149     return test_context;
150
151 error:
152     if (device)
153         IDirect3DDevice9_Release(device);
154
155     if (d3d)
156         IDirect3D9_Release(d3d);
157
158     if (hwnd)
159         DestroyWindow(hwnd);
160
161     return NULL;
162 }
163
164 static void free_test_context(struct test_context *test_context)
165 {
166     if (!test_context)
167         return;
168
169     if (test_context->device)
170         IDirect3DDevice9_Release(test_context->device);
171
172     if (test_context->d3d)
173         IDirect3D9_Release(test_context->d3d);
174
175     if (test_context->hwnd)
176         DestroyWindow(test_context->hwnd);
177
178     HeapFree(GetProcessHeap(), 0, test_context);
179 }
180
181 struct mesh
182 {
183     DWORD number_of_vertices;
184     struct vertex *vertices;
185
186     DWORD number_of_faces;
187     face *faces;
188
189     DWORD fvf;
190     UINT vertex_size;
191 };
192
193 static void free_mesh(struct mesh *mesh)
194 {
195     HeapFree(GetProcessHeap(), 0, mesh->faces);
196     HeapFree(GetProcessHeap(), 0, mesh->vertices);
197 }
198
199 static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
200 {
201     mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
202     if (!mesh->vertices)
203     {
204         return FALSE;
205     }
206     mesh->number_of_vertices = number_of_vertices;
207
208     mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
209     if (!mesh->faces)
210     {
211         HeapFree(GetProcessHeap(), 0, mesh->vertices);
212         return FALSE;
213     }
214     mesh->number_of_faces = number_of_faces;
215
216     return TRUE;
217 }
218
219 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
220 {
221     HRESULT hr;
222     DWORD number_of_vertices, number_of_faces;
223     IDirect3DVertexBuffer9 *vertex_buffer;
224     IDirect3DIndexBuffer9 *index_buffer;
225     D3DVERTEXBUFFER_DESC vertex_buffer_description;
226     D3DINDEXBUFFER_DESC index_buffer_description;
227     struct vertex *vertices;
228     face *faces;
229     int expected, i;
230
231     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
232     ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
233        name, number_of_vertices, mesh->number_of_vertices);
234
235     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
236     ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
237        name, number_of_faces, mesh->number_of_faces);
238
239     /* vertex buffer */
240     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
241     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
242
243     if (hr != D3D_OK)
244     {
245         skip("Couldn't get vertex buffer\n");
246     }
247     else
248     {
249         hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
250         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
251
252         if (hr != D3D_OK)
253         {
254             skip("Couldn't get vertex buffer description\n");
255         }
256         else
257         {
258             ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
259                name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
260             ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
261                name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
262             ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
263             ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
264                name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
265             ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
266                name, vertex_buffer_description.FVF, mesh->fvf);
267             if (mesh->fvf == 0)
268             {
269                 expected = number_of_vertices * mesh->vertex_size;
270             }
271             else
272             {
273                 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
274             }
275             ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
276                name, vertex_buffer_description.Size, expected);
277         }
278
279         /* specify offset and size to avoid potential overruns */
280         hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
281                                          (LPVOID *)&vertices, D3DLOCK_DISCARD);
282         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
283
284         if (hr != D3D_OK)
285         {
286             skip("Couldn't lock vertex buffer\n");
287         }
288         else
289         {
290             for (i = 0; i < number_of_vertices; i++)
291             {
292                 ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
293                    "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
294                    vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
295                    mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
296                 ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
297                    "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
298                    vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
299                    mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
300             }
301
302             IDirect3DVertexBuffer9_Unlock(vertex_buffer);
303         }
304
305         IDirect3DVertexBuffer9_Release(vertex_buffer);
306     }
307
308     /* index buffer */
309     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
310     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
311
312     if (!index_buffer)
313     {
314         skip("Couldn't get index buffer\n");
315     }
316     else
317     {
318         hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
319         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
320
321         if (hr != D3D_OK)
322         {
323             skip("Couldn't get index buffer description\n");
324         }
325         else
326         {
327             ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
328                name, index_buffer_description.Format, D3DFMT_INDEX16);
329             ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
330                name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
331             todo_wine ok(index_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, index_buffer_description.Usage, 0);
332             ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
333                name, index_buffer_description.Pool, D3DPOOL_MANAGED);
334             expected = number_of_faces * sizeof(WORD) * 3;
335             ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
336                name, index_buffer_description.Size, expected);
337         }
338
339         /* specify offset and size to avoid potential overruns */
340         hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
341                                         (LPVOID *)&faces, D3DLOCK_DISCARD);
342         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
343
344         if (hr != D3D_OK)
345         {
346             skip("Couldn't lock index buffer\n");
347         }
348         else
349         {
350             for (i = 0; i < number_of_faces; i++)
351             {
352                 ok(compare_face(faces[i], mesh->faces[i]),
353                    "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
354                    faces[i][0], faces[i][1], faces[i][2],
355                    mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
356             }
357
358             IDirect3DIndexBuffer9_Unlock(index_buffer);
359         }
360
361         IDirect3DIndexBuffer9_Release(index_buffer);
362     }
363 }
364
365 static void D3DXBoundProbeTest(void)
366 {
367     BOOL result;
368     D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
369     FLOAT radius;
370
371 /*____________Test the Box case___________________________*/
372     bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
373     top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
374
375     raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
376     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
377     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
378     ok(result == TRUE, "expected TRUE, received FALSE\n");
379
380     raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
381     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
382     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
383     ok(result == FALSE, "expected FALSE, received TRUE\n");
384
385     rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
386     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
387     ok(result == TRUE, "expected TRUE, received FALSE\n");
388
389     bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
390     top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
391     rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
392     raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
393     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
394     ok(result == FALSE, "expected FALSE, received TRUE\n");
395
396     bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
397     top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
398
399     raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
400     rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
401     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
402     ok(result == TRUE, "expected TRUE, received FALSE\n");
403
404     bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
405     top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
406
407     raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
408     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
409     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
410     ok(result == FALSE, "expected FALSE, received TRUE\n");
411
412     raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
413     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
414     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
415     ok(result == TRUE, "expected TRUE, received FALSE\n");
416
417 /*____________Test the Sphere case________________________*/
418     radius = sqrt(77.0f);
419     center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
420     raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
421
422     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
423     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
424     ok(result == TRUE, "expected TRUE, received FALSE\n");
425
426     rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
427     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
428     ok(result == FALSE, "expected FALSE, received TRUE\n");
429
430     rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
431     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
432     ok(result == FALSE, "expected FALSE, received TRUE\n");
433 }
434
435 static void D3DXComputeBoundingBoxTest(void)
436 {
437     D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
438     HRESULT hr;
439
440     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
441     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
442     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
443     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
444     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
445
446     exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
447     exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
448
449     hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
450
451     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
452     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);
453     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);
454
455 /*________________________*/
456
457     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
458     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
459     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
460     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
461     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
462
463     exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
464     exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
465
466     hr = D3DXComputeBoundingBox(&vertex[0],5,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 = -0.9f; exp_min.z = -3.8f;
481     exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
482
483     hr = D3DXComputeBoundingBox(&vertex[0],4,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     hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
491     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
492
493 /*________________________*/
494     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
495     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
496
497 /*________________________*/
498     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
499     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
500 }
501
502 static void D3DXComputeBoundingSphereTest(void)
503 {
504     D3DXVECTOR3 exp_cen, got_cen, vertex[5];
505     FLOAT exp_rad, got_rad;
506     HRESULT hr;
507
508     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
509     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
510     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
511     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
512     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
513
514     exp_rad = 6.928203f;
515     exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
516
517     hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
518
519     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
520     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
521     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);
522
523 /*________________________*/
524
525     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
526     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
527     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
528     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
529     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
530
531     exp_rad = 13.707883f;
532     exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
533
534     hr = D3DXComputeBoundingSphere(&vertex[0],5,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     hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
542     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
543
544 /*________________________*/
545     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
546     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
547
548 /*________________________*/
549     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
550     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
551 }
552
553 static void print_elements(const D3DVERTEXELEMENT9 *elements)
554 {
555     D3DVERTEXELEMENT9 last = D3DDECL_END();
556     const D3DVERTEXELEMENT9 *ptr = elements;
557     int count = 0;
558
559     while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
560     {
561         trace(
562             "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
563              count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
564         ptr++;
565         count++;
566     }
567 }
568
569 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
570         unsigned int line, unsigned int test_id)
571 {
572     D3DVERTEXELEMENT9 last = D3DDECL_END();
573     unsigned int i;
574
575     for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
576     {
577         int end1 = memcmp(&elements[i], &last, sizeof(last));
578         int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
579         int status;
580
581         if (!end1 && !end2) break;
582
583         status = !end1 ^ !end2;
584         ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
585                 line, test_id, end1 ? "shorter" : "longer");
586         if (status)
587         {
588             print_elements(elements);
589             break;
590         }
591
592         status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
593         ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
594         if (status)
595         {
596             print_elements(elements);
597             break;
598         }
599     }
600 }
601
602 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
603         HRESULT expected_hr, unsigned int line, unsigned int test_id)
604 {
605     HRESULT hr;
606     D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
607
608     hr = D3DXDeclaratorFromFVF(test_fvf, decl);
609     ok(hr == expected_hr,
610             "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
611             line, test_id, hr, expected_hr);
612     if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
613 }
614
615 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
616         HRESULT expected_hr, unsigned int line, unsigned int test_id)
617 {
618     HRESULT hr;
619     DWORD result_fvf = 0xdeadbeef;
620
621     hr = D3DXFVFFromDeclarator(decl, &result_fvf);
622     ok(hr == expected_hr,
623        "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
624        line, test_id, hr, expected_hr);
625     if (SUCCEEDED(hr))
626     {
627         ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
628                 line, test_id, result_fvf, expected_fvf);
629     }
630 }
631
632 static void test_fvf_decl_conversion(void)
633 {
634     static const struct
635     {
636         D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
637         DWORD fvf;
638     }
639     test_data[] =
640     {
641         {{
642             D3DDECL_END(),
643         }, 0},
644         {{
645             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
646             D3DDECL_END(),
647         }, D3DFVF_XYZ},
648         {{
649             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
650             D3DDECL_END(),
651         }, D3DFVF_XYZRHW},
652         {{
653             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
654             D3DDECL_END(),
655         }, D3DFVF_XYZRHW},
656         {{
657             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
658             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
659             D3DDECL_END(),
660         }, D3DFVF_XYZB1},
661         {{
662             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
663             {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
664             D3DDECL_END(),
665         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
666         {{
667             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
668             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
669             D3DDECL_END(),
670         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
671         {{
672             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
673             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
674             D3DDECL_END(),
675         }, D3DFVF_XYZB2},
676         {{
677             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
678             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
679             {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
680             D3DDECL_END(),
681         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
682         {{
683             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
684             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
685             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
686             D3DDECL_END(),
687         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
688         {{
689             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
690             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
691             D3DDECL_END(),
692         }, D3DFVF_XYZB3},
693         {{
694             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
695             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
696             {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
697             D3DDECL_END(),
698         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
699         {{
700             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
701             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
702             {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
703             D3DDECL_END(),
704         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
705         {{
706             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
707             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
708             D3DDECL_END(),
709         }, D3DFVF_XYZB4},
710         {{
711             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
712             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
713             {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
714             D3DDECL_END(),
715         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
716         {{
717             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
718             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
719             {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
720             D3DDECL_END(),
721         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
722         {{
723             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
724             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
725             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
726             D3DDECL_END(),
727         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
728         {{
729             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
730             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
731             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
732             D3DDECL_END(),
733         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
734         {{
735             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
736             D3DDECL_END(),
737         }, D3DFVF_NORMAL},
738         {{
739             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
740             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
741             D3DDECL_END(),
742         }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
743         {{
744             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
745             D3DDECL_END(),
746         }, D3DFVF_PSIZE},
747         {{
748             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
749             D3DDECL_END(),
750         }, D3DFVF_DIFFUSE},
751         {{
752             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
753             D3DDECL_END(),
754         }, D3DFVF_SPECULAR},
755         /* Make sure textures of different sizes work. */
756         {{
757             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
758             D3DDECL_END(),
759         }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
760         {{
761             {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
762             D3DDECL_END(),
763         }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
764         {{
765             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
766             D3DDECL_END(),
767         }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
768         {{
769             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
770             D3DDECL_END(),
771         }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
772         /* Make sure the TEXCOORD index works correctly - try several textures. */
773         {{
774             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
775             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
776             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
777             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
778             D3DDECL_END(),
779         }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
780                 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
781         /* Now try some combination tests. */
782         {{
783             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
784             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
785             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
786             {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
787             {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
788             {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
789             D3DDECL_END(),
790         }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
791                 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
792         {{
793             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
794             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
795             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
796             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
797             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
798             {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
799             D3DDECL_END(),
800         }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
801                 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
802     };
803     unsigned int i;
804
805     for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
806     {
807         test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
808         test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
809     }
810
811     /* Usage indices for position and normal are apparently ignored. */
812     {
813         const D3DVERTEXELEMENT9 decl[] =
814         {
815             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
816             D3DDECL_END(),
817         };
818         test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
819     }
820     {
821         const D3DVERTEXELEMENT9 decl[] =
822         {
823             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
824             D3DDECL_END(),
825         };
826         test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
827     }
828     /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
829      * there are no blend matrices. */
830     {
831         const D3DVERTEXELEMENT9 decl[] =
832         {
833             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
834             D3DDECL_END(),
835         };
836         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
837     }
838     {
839         const D3DVERTEXELEMENT9 decl[] =
840         {
841             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
842             D3DDECL_END(),
843         };
844         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
845     }
846     /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
847     {
848         const D3DVERTEXELEMENT9 decl[] =
849         {
850             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
851             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
852             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
853             D3DDECL_END(),
854         };
855         test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
856                 decl, D3D_OK, __LINE__, 0);
857     }
858     /* These are supposed to fail, both ways. */
859     {
860         const D3DVERTEXELEMENT9 decl[] =
861         {
862             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
863             D3DDECL_END(),
864         };
865         test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
866         test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
867     }
868     {
869         const D3DVERTEXELEMENT9 decl[] =
870         {
871             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
872             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
873             D3DDECL_END(),
874         };
875         test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
876         test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
877     }
878     {
879         const D3DVERTEXELEMENT9 decl[] =
880         {
881             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
882             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
883             {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
884             D3DDECL_END(),
885         };
886         test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
887         test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
888     }
889     /* Test a declaration that can't be converted to an FVF. */
890     {
891         const D3DVERTEXELEMENT9 decl[] =
892         {
893             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
894             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
895             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
896             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
897             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
898             /* 8 bytes padding */
899             {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
900             D3DDECL_END(),
901         };
902         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
903     }
904     /* Elements must be ordered by offset. */
905     {
906         const D3DVERTEXELEMENT9 decl[] =
907         {
908             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
909             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
910             D3DDECL_END(),
911         };
912         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
913     }
914     /* Basic tests for element order. */
915     {
916         const D3DVERTEXELEMENT9 decl[] =
917         {
918             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
919             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
920             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
921             D3DDECL_END(),
922         };
923         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
924     }
925     {
926         const D3DVERTEXELEMENT9 decl[] =
927         {
928             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
929             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
930             D3DDECL_END(),
931         };
932         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
933     }
934     {
935         const D3DVERTEXELEMENT9 decl[] =
936         {
937             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
938             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
939             D3DDECL_END(),
940         };
941         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
942     }
943     /* Textures must be ordered by texcoords. */
944     {
945         const D3DVERTEXELEMENT9 decl[] =
946         {
947             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
948             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
949             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
950             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
951             D3DDECL_END(),
952         };
953         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
954     }
955     /* Duplicate elements are not allowed. */
956     {
957         const D3DVERTEXELEMENT9 decl[] =
958         {
959             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
960             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
961             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
962             D3DDECL_END(),
963         };
964         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
965     }
966     /* Invalid FVFs cannot be converted to a declarator. */
967     test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
968 }
969
970 static void D3DXGetFVFVertexSizeTest(void)
971 {
972     UINT got;
973
974     compare_vertex_sizes (D3DFVF_XYZ, 12);
975
976     compare_vertex_sizes (D3DFVF_XYZB3, 24);
977
978     compare_vertex_sizes (D3DFVF_XYZB5, 32);
979
980     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
981
982     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
983
984     compare_vertex_sizes (
985         D3DFVF_XYZ |
986         D3DFVF_TEX1 |
987         D3DFVF_TEXCOORDSIZE1(0), 16);
988     compare_vertex_sizes (
989         D3DFVF_XYZ |
990         D3DFVF_TEX2 |
991         D3DFVF_TEXCOORDSIZE1(0) |
992         D3DFVF_TEXCOORDSIZE1(1), 20);
993
994     compare_vertex_sizes (
995         D3DFVF_XYZ |
996         D3DFVF_TEX1 |
997         D3DFVF_TEXCOORDSIZE2(0), 20);
998
999     compare_vertex_sizes (
1000         D3DFVF_XYZ |
1001         D3DFVF_TEX2 |
1002         D3DFVF_TEXCOORDSIZE2(0) |
1003         D3DFVF_TEXCOORDSIZE2(1), 28);
1004
1005     compare_vertex_sizes (
1006         D3DFVF_XYZ |
1007         D3DFVF_TEX6 |
1008         D3DFVF_TEXCOORDSIZE2(0) |
1009         D3DFVF_TEXCOORDSIZE2(1) |
1010         D3DFVF_TEXCOORDSIZE2(2) |
1011         D3DFVF_TEXCOORDSIZE2(3) |
1012         D3DFVF_TEXCOORDSIZE2(4) |
1013         D3DFVF_TEXCOORDSIZE2(5), 60);
1014
1015     compare_vertex_sizes (
1016         D3DFVF_XYZ |
1017         D3DFVF_TEX8 |
1018         D3DFVF_TEXCOORDSIZE2(0) |
1019         D3DFVF_TEXCOORDSIZE2(1) |
1020         D3DFVF_TEXCOORDSIZE2(2) |
1021         D3DFVF_TEXCOORDSIZE2(3) |
1022         D3DFVF_TEXCOORDSIZE2(4) |
1023         D3DFVF_TEXCOORDSIZE2(5) |
1024         D3DFVF_TEXCOORDSIZE2(6) |
1025         D3DFVF_TEXCOORDSIZE2(7), 76);
1026
1027     compare_vertex_sizes (
1028         D3DFVF_XYZ |
1029         D3DFVF_TEX1 |
1030         D3DFVF_TEXCOORDSIZE3(0), 24);
1031
1032     compare_vertex_sizes (
1033         D3DFVF_XYZ |
1034         D3DFVF_TEX4 |
1035         D3DFVF_TEXCOORDSIZE3(0) |
1036         D3DFVF_TEXCOORDSIZE3(1) |
1037         D3DFVF_TEXCOORDSIZE3(2) |
1038         D3DFVF_TEXCOORDSIZE3(3), 60);
1039
1040     compare_vertex_sizes (
1041         D3DFVF_XYZ |
1042         D3DFVF_TEX1 |
1043         D3DFVF_TEXCOORDSIZE4(0), 28);
1044
1045     compare_vertex_sizes (
1046         D3DFVF_XYZ |
1047         D3DFVF_TEX2 |
1048         D3DFVF_TEXCOORDSIZE4(0) |
1049         D3DFVF_TEXCOORDSIZE4(1), 44);
1050
1051     compare_vertex_sizes (
1052         D3DFVF_XYZ |
1053         D3DFVF_TEX3 |
1054         D3DFVF_TEXCOORDSIZE4(0) |
1055         D3DFVF_TEXCOORDSIZE4(1) |
1056         D3DFVF_TEXCOORDSIZE4(2), 60);
1057
1058     compare_vertex_sizes (
1059         D3DFVF_XYZB5 |
1060         D3DFVF_NORMAL |
1061         D3DFVF_DIFFUSE |
1062         D3DFVF_SPECULAR |
1063         D3DFVF_TEX8 |
1064         D3DFVF_TEXCOORDSIZE4(0) |
1065         D3DFVF_TEXCOORDSIZE4(1) |
1066         D3DFVF_TEXCOORDSIZE4(2) |
1067         D3DFVF_TEXCOORDSIZE4(3) |
1068         D3DFVF_TEXCOORDSIZE4(4) |
1069         D3DFVF_TEXCOORDSIZE4(5) |
1070         D3DFVF_TEXCOORDSIZE4(6) |
1071         D3DFVF_TEXCOORDSIZE4(7), 180);
1072 }
1073
1074 static void D3DXIntersectTriTest(void)
1075 {
1076     BOOL exp_res, got_res;
1077     D3DXVECTOR3 position, ray, vertex[3];
1078     FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
1079
1080     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1081     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1082     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1083
1084     position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
1085
1086     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1087
1088     exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
1089
1090     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1091     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1092     ok( compare(exp_u,got_u), "Expected u = %f, got %f\n",exp_u,got_u);
1093     ok( compare(exp_v,got_v), "Expected v = %f, got %f\n",exp_v,got_v);
1094     ok( compare(exp_dist,got_dist), "Expected distance = %f, got %f\n",exp_dist,got_dist);
1095
1096 /*Only positive ray is taken in account*/
1097
1098     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1099     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1100     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1101
1102     position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
1103
1104     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1105
1106     exp_res = FALSE;
1107
1108     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1109     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1110
1111 /*Intersection between ray and triangle in a same plane is considered as empty*/
1112
1113     vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1114     vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1115     vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
1116
1117     position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
1118
1119     ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
1120
1121     exp_res = FALSE;
1122
1123     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1124     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1125 }
1126
1127 static void D3DXCreateMeshTest(void)
1128 {
1129     HRESULT hr;
1130     HWND wnd;
1131     IDirect3D9 *d3d;
1132     IDirect3DDevice9 *device, *test_device;
1133     D3DPRESENT_PARAMETERS d3dpp;
1134     ID3DXMesh *d3dxmesh;
1135     int i, size;
1136     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1137     DWORD options;
1138     struct mesh mesh;
1139
1140     static const D3DVERTEXELEMENT9 decl1[3] = {
1141         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1142         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1143         D3DDECL_END(), };
1144
1145     static const D3DVERTEXELEMENT9 decl2[] = {
1146         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1147         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1148         {0, 24, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
1149         {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
1150         {0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
1151         /* 8 bytes padding */
1152         {0, 44, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
1153         D3DDECL_END(),
1154     };
1155
1156     static const D3DVERTEXELEMENT9 decl3[] = {
1157         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1158         {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1159         D3DDECL_END(),
1160     };
1161
1162     hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1163     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1164
1165     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1166     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1167
1168     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1169     if (!wnd)
1170     {
1171         skip("Couldn't create application window\n");
1172         return;
1173     }
1174     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1175     if (!d3d)
1176     {
1177         skip("Couldn't create IDirect3D9 object\n");
1178         DestroyWindow(wnd);
1179         return;
1180     }
1181
1182     ZeroMemory(&d3dpp, sizeof(d3dpp));
1183     d3dpp.Windowed = TRUE;
1184     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1185     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1186     if (FAILED(hr))
1187     {
1188         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1189         IDirect3D9_Release(d3d);
1190         DestroyWindow(wnd);
1191         return;
1192     }
1193
1194     hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1195     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1196
1197     hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1198     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1199
1200     hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
1201     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1202
1203     if (hr == D3D_OK)
1204     {
1205         d3dxmesh->lpVtbl->Release(d3dxmesh);
1206     }
1207
1208     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1209     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1210
1211     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
1212     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1213
1214     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1215     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1216
1217     if (hr == D3D_OK)
1218     {
1219         /* device */
1220         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1221         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1222
1223         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1224         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1225         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1226
1227         if (hr == D3D_OK)
1228         {
1229             IDirect3DDevice9_Release(device);
1230         }
1231
1232         /* declaration */
1233         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1234         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1235
1236         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1237         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1238
1239         if (hr == D3D_OK)
1240         {
1241             size = sizeof(decl1) / sizeof(decl1[0]);
1242             for (i = 0; i < size - 1; i++)
1243             {
1244                 ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1245                 ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1246                 ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1247                 ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1248                 ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1249                 ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1250             }
1251             ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1252         }
1253
1254         /* options */
1255         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1256         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1257
1258         /* rest */
1259         if (!new_mesh(&mesh, 3, 1))
1260         {
1261             skip("Couldn't create mesh\n");
1262         }
1263         else
1264         {
1265             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1266             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1267             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1268
1269             compare_mesh("createmesh1", d3dxmesh, &mesh);
1270
1271             free_mesh(&mesh);
1272         }
1273
1274         d3dxmesh->lpVtbl->Release(d3dxmesh);
1275     }
1276
1277     /* Test a declaration that can't be converted to an FVF. */
1278     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1279     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1280
1281     if (hr == D3D_OK)
1282     {
1283         /* device */
1284         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1285         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1286
1287         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1288         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1289         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1290
1291         if (hr == D3D_OK)
1292         {
1293             IDirect3DDevice9_Release(device);
1294         }
1295
1296         /* declaration */
1297         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1298         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1299
1300         if (hr == D3D_OK)
1301         {
1302             size = sizeof(decl2) / sizeof(decl2[0]);
1303             for (i = 0; i < size - 1; i++)
1304             {
1305                 ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1306                 ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1307                 ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1308                 ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1309                 ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1310                 ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1311             }
1312             ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1313         }
1314
1315         /* options */
1316         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1317         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1318
1319         /* rest */
1320         if (!new_mesh(&mesh, 3, 1))
1321         {
1322             skip("Couldn't create mesh\n");
1323         }
1324         else
1325         {
1326             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1327             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1328             mesh.fvf = 0;
1329             mesh.vertex_size = 60;
1330
1331             compare_mesh("createmesh2", d3dxmesh, &mesh);
1332
1333             free_mesh(&mesh);
1334         }
1335
1336         mesh.vertex_size = d3dxmesh->lpVtbl->GetNumBytesPerVertex(d3dxmesh);
1337         ok(mesh.vertex_size == 60, "Got vertex size %u, expected %u\n", mesh.vertex_size, 60);
1338
1339         d3dxmesh->lpVtbl->Release(d3dxmesh);
1340     }
1341
1342     /* Test a declaration with multiple streams. */
1343     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
1344     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1345
1346     IDirect3DDevice9_Release(device);
1347     IDirect3D9_Release(d3d);
1348     DestroyWindow(wnd);
1349 }
1350
1351 static void D3DXCreateMeshFVFTest(void)
1352 {
1353     HRESULT hr;
1354     HWND wnd;
1355     IDirect3D9 *d3d;
1356     IDirect3DDevice9 *device, *test_device;
1357     D3DPRESENT_PARAMETERS d3dpp;
1358     ID3DXMesh *d3dxmesh;
1359     int i, size;
1360     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1361     DWORD options;
1362     struct mesh mesh;
1363
1364     static const D3DVERTEXELEMENT9 decl[3] = {
1365         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1366         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1367         D3DDECL_END(), };
1368
1369     hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1370     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1371
1372     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, NULL, &d3dxmesh);
1373     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1374
1375     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1376     if (!wnd)
1377     {
1378         skip("Couldn't create application window\n");
1379         return;
1380     }
1381     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1382     if (!d3d)
1383     {
1384         skip("Couldn't create IDirect3D9 object\n");
1385         DestroyWindow(wnd);
1386         return;
1387     }
1388
1389     ZeroMemory(&d3dpp, sizeof(d3dpp));
1390     d3dpp.Windowed = TRUE;
1391     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1392     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1393     if (FAILED(hr))
1394     {
1395         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1396         IDirect3D9_Release(d3d);
1397         DestroyWindow(wnd);
1398         return;
1399     }
1400
1401     hr = D3DXCreateMeshFVF(0, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1402     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1403
1404     hr = D3DXCreateMeshFVF(1, 0, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1405     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1406
1407     hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1408     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1409
1410     if (hr == D3D_OK)
1411     {
1412         d3dxmesh->lpVtbl->Release(d3dxmesh);
1413     }
1414
1415     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1416     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1417
1418     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, NULL);
1419     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1420
1421     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1422     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1423
1424     if (hr == D3D_OK)
1425     {
1426         /* device */
1427         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1428         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1429
1430         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1431         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1432         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1433
1434         if (hr == D3D_OK)
1435         {
1436             IDirect3DDevice9_Release(device);
1437         }
1438
1439         /* declaration */
1440         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1441         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1442
1443         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1444         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1445
1446         if (hr == D3D_OK)
1447         {
1448             size = sizeof(decl) / sizeof(decl[0]);
1449             for (i = 0; i < size - 1; i++)
1450             {
1451                 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1452                 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1453                 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1454                 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1455                 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1456                    test_decl[i].UsageIndex, decl[i].UsageIndex);
1457                 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1458             }
1459             ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1460         }
1461
1462         /* options */
1463         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1464         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1465
1466         /* rest */
1467         if (!new_mesh(&mesh, 3, 1))
1468         {
1469             skip("Couldn't create mesh\n");
1470         }
1471         else
1472         {
1473             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1474             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1475             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1476
1477             compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1478
1479             free_mesh(&mesh);
1480         }
1481
1482         d3dxmesh->lpVtbl->Release(d3dxmesh);
1483     }
1484
1485     IDirect3DDevice9_Release(device);
1486     IDirect3D9_Release(d3d);
1487     DestroyWindow(wnd);
1488 }
1489
1490 #define check_vertex_buffer(mesh, vertices, num_vertices, fvf) \
1491     check_vertex_buffer_(__LINE__, mesh, vertices, num_vertices, fvf)
1492 static void check_vertex_buffer_(int line, ID3DXMesh *mesh, const void *vertices, DWORD num_vertices, DWORD fvf)
1493 {
1494     DWORD mesh_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
1495     DWORD mesh_fvf = mesh->lpVtbl->GetFVF(mesh);
1496     const void *mesh_vertices;
1497     HRESULT hr;
1498
1499     ok_(__FILE__,line)(fvf == mesh_fvf, "expected FVF %x, got %x\n", fvf, mesh_fvf);
1500     ok_(__FILE__,line)(num_vertices == mesh_num_vertices,
1501        "Expected %u vertices, got %u\n", num_vertices, mesh_num_vertices);
1502
1503     hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
1504     ok_(__FILE__,line)(hr == D3D_OK, "LockVertexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1505     if (FAILED(hr))
1506         return;
1507
1508     if (mesh_fvf == fvf) {
1509         DWORD vertex_size = D3DXGetFVFVertexSize(fvf);
1510         int i;
1511         for (i = 0; i < min(num_vertices, mesh_num_vertices); i++)
1512         {
1513             const FLOAT *exp_float = vertices;
1514             const FLOAT *got_float = mesh_vertices;
1515             DWORD texcount;
1516             DWORD pos_dim = 0;
1517             int j;
1518             BOOL last_beta_dword = FALSE;
1519             char prefix[128];
1520
1521             switch (fvf & D3DFVF_POSITION_MASK) {
1522                 case D3DFVF_XYZ: pos_dim = 3; break;
1523                 case D3DFVF_XYZRHW: pos_dim = 4; break;
1524                 case D3DFVF_XYZB1:
1525                 case D3DFVF_XYZB2:
1526                 case D3DFVF_XYZB3:
1527                 case D3DFVF_XYZB4:
1528                 case D3DFVF_XYZB5:
1529                     pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
1530                     if (fvf & (D3DFVF_LASTBETA_UBYTE4 | D3DFVF_LASTBETA_D3DCOLOR))
1531                     {
1532                         pos_dim--;
1533                         last_beta_dword = TRUE;
1534                     }
1535                     break;
1536                 case D3DFVF_XYZW: pos_dim = 4; break;
1537             }
1538             sprintf(prefix, "vertex[%u] position, ", i);
1539             check_floats_(line, prefix, got_float, exp_float, pos_dim);
1540             exp_float += pos_dim;
1541             got_float += pos_dim;
1542
1543             if (last_beta_dword) {
1544                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1545                     "Vertex[%u]: Expected last beta %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1546                 exp_float++;
1547                 got_float++;
1548             }
1549
1550             if (fvf & D3DFVF_NORMAL) {
1551                 sprintf(prefix, "vertex[%u] normal, ", i);
1552                 check_floats_(line, prefix, got_float, exp_float, 3);
1553                 exp_float += 3;
1554                 got_float += 3;
1555             }
1556             if (fvf & D3DFVF_PSIZE) {
1557                 ok_(__FILE__,line)(compare(*exp_float, *got_float),
1558                         "Vertex[%u]: Expected psize %g, got %g\n", i, *exp_float, *got_float);
1559                 exp_float++;
1560                 got_float++;
1561             }
1562             if (fvf & D3DFVF_DIFFUSE) {
1563                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1564                     "Vertex[%u]: Expected diffuse %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1565                 exp_float++;
1566                 got_float++;
1567             }
1568             if (fvf & D3DFVF_SPECULAR) {
1569                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1570                     "Vertex[%u]: Expected specular %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1571                 exp_float++;
1572                 got_float++;
1573             }
1574
1575             texcount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
1576             for (j = 0; j < texcount; j++) {
1577                 DWORD dim = (((fvf >> (16 + 2 * j)) + 1) & 0x03) + 1;
1578                 sprintf(prefix, "vertex[%u] texture, ", i);
1579                 check_floats_(line, prefix, got_float, exp_float, dim);
1580                 exp_float += dim;
1581                 got_float += dim;
1582             }
1583
1584             vertices = (BYTE*)vertices + vertex_size;
1585             mesh_vertices = (BYTE*)mesh_vertices + vertex_size;
1586         }
1587     }
1588
1589     mesh->lpVtbl->UnlockVertexBuffer(mesh);
1590 }
1591
1592 #define check_index_buffer(mesh, indices, num_indices, index_size) \
1593     check_index_buffer_(__LINE__, mesh, indices, num_indices, index_size)
1594 static void check_index_buffer_(int line, ID3DXMesh *mesh, const void *indices, DWORD num_indices, DWORD index_size)
1595 {
1596     DWORD mesh_index_size = (mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT) ? 4 : 2;
1597     DWORD mesh_num_indices = mesh->lpVtbl->GetNumFaces(mesh) * 3;
1598     const void *mesh_indices;
1599     HRESULT hr;
1600     DWORD i;
1601
1602     ok_(__FILE__,line)(index_size == mesh_index_size,
1603         "Expected index size %u, got %u\n", index_size, mesh_index_size);
1604     ok_(__FILE__,line)(num_indices == mesh_num_indices,
1605         "Expected %u indices, got %u\n", num_indices, mesh_num_indices);
1606
1607     hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
1608     ok_(__FILE__,line)(hr == D3D_OK, "LockIndexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1609     if (FAILED(hr))
1610         return;
1611
1612     if (mesh_index_size == index_size) {
1613         for (i = 0; i < min(num_indices, mesh_num_indices); i++)
1614         {
1615             if (index_size == 4)
1616                 ok_(__FILE__,line)(*(DWORD*)indices == *(DWORD*)mesh_indices,
1617                     "Index[%u]: expected %u, got %u\n", i, *(DWORD*)indices, *(DWORD*)mesh_indices);
1618             else
1619                 ok_(__FILE__,line)(*(WORD*)indices == *(WORD*)mesh_indices,
1620                     "Index[%u]: expected %u, got %u\n", i, *(WORD*)indices, *(WORD*)mesh_indices);
1621             indices = (BYTE*)indices + index_size;
1622             mesh_indices = (BYTE*)mesh_indices + index_size;
1623         }
1624     }
1625     mesh->lpVtbl->UnlockIndexBuffer(mesh);
1626 }
1627
1628 #define check_matrix(got, expected) check_matrix_(__LINE__, got, expected)
1629 static void check_matrix_(int line, const D3DXMATRIX *got, const D3DXMATRIX *expected)
1630 {
1631     int i, j;
1632     for (i = 0; i < 4; i++) {
1633         for (j = 0; j < 4; j++) {
1634             ok_(__FILE__,line)(compare(U(*expected).m[i][j], U(*got).m[i][j]),
1635                     "matrix[%u][%u]: expected %g, got %g\n",
1636                     i, j, U(*expected).m[i][j], U(*got).m[i][j]);
1637         }
1638     }
1639 }
1640
1641 static void check_colorvalue_(int line, const char *prefix, const D3DCOLORVALUE got, const D3DCOLORVALUE expected)
1642 {
1643     ok_(__FILE__,line)(expected.r == got.r && expected.g == got.g && expected.b == got.b && expected.a == got.a,
1644             "%sExpected (%g, %g, %g, %g), got (%g, %g, %g, %g)\n", prefix,
1645             expected.r, expected.g, expected.b, expected.a, got.r, got.g, got.b, got.a);
1646 }
1647
1648 #define check_materials(got, got_count, expected, expected_count) \
1649     check_materials_(__LINE__, got, got_count, expected, expected_count)
1650 static void check_materials_(int line, const D3DXMATERIAL *got, DWORD got_count, const D3DXMATERIAL *expected, DWORD expected_count)
1651 {
1652     int i;
1653     ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
1654     if (!expected) {
1655         ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
1656         return;
1657     }
1658     for (i = 0; i < min(expected_count, got_count); i++)
1659     {
1660         if (!expected[i].pTextureFilename)
1661             ok_(__FILE__,line)(got[i].pTextureFilename == NULL,
1662                     "Expected NULL pTextureFilename, got %p\n", got[i].pTextureFilename);
1663         else
1664             ok_(__FILE__,line)(!strcmp(expected[i].pTextureFilename, got[i].pTextureFilename),
1665                     "Expected '%s' for pTextureFilename, got '%s'\n", expected[i].pTextureFilename, got[i].pTextureFilename);
1666         check_colorvalue_(line, "Diffuse: ", got[i].MatD3D.Diffuse, expected[i].MatD3D.Diffuse);
1667         check_colorvalue_(line, "Ambient: ", got[i].MatD3D.Ambient, expected[i].MatD3D.Ambient);
1668         check_colorvalue_(line, "Specular: ", got[i].MatD3D.Specular, expected[i].MatD3D.Specular);
1669         check_colorvalue_(line, "Emissive: ", got[i].MatD3D.Emissive, expected[i].MatD3D.Emissive);
1670         ok_(__FILE__,line)(expected[i].MatD3D.Power == got[i].MatD3D.Power,
1671                 "Power: Expected %g, got %g\n", expected[i].MatD3D.Power, got[i].MatD3D.Power);
1672     }
1673 }
1674
1675 #define check_generated_adjacency(mesh, got, epsilon) check_generated_adjacency_(__LINE__, mesh, got, epsilon)
1676 static void check_generated_adjacency_(int line, ID3DXMesh *mesh, const DWORD *got, FLOAT epsilon)
1677 {
1678     DWORD *expected;
1679     DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
1680     HRESULT hr;
1681
1682     expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
1683     if (!expected) {
1684         skip_(__FILE__, line)("Out of memory\n");
1685         return;
1686     }
1687     hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
1688     ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1689     if (SUCCEEDED(hr))
1690     {
1691         int i;
1692         for (i = 0; i < num_faces; i++)
1693         {
1694             ok_(__FILE__, line)(expected[i * 3] == got[i * 3] &&
1695                     expected[i * 3 + 1] == got[i * 3 + 1] &&
1696                     expected[i * 3 + 2] == got[i * 3 + 2],
1697                     "Face %u adjacencies: Expected (%u, %u, %u), got (%u, %u, %u)\n", i,
1698                     expected[i * 3], expected[i * 3 + 1], expected[i * 3 + 2],
1699                     got[i * 3], got[i * 3 + 1], got[i * 3 + 2]);
1700         }
1701     }
1702     HeapFree(GetProcessHeap(), 0, expected);
1703 }
1704
1705 #define check_generated_effects(materials, num_materials, effects) \
1706     check_generated_effects_(__LINE__, materials, num_materials, effects)
1707 static void check_generated_effects_(int line, const D3DXMATERIAL *materials, DWORD num_materials, const D3DXEFFECTINSTANCE *effects)
1708 {
1709     int i;
1710     static const struct {
1711         const char *name;
1712         DWORD name_size;
1713         DWORD num_bytes;
1714         DWORD value_offset;
1715     } params[] = {
1716 #define EFFECT_TABLE_ENTRY(str, field) \
1717     {str, sizeof(str), sizeof(materials->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
1718         EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
1719         EFFECT_TABLE_ENTRY("Power", Power),
1720         EFFECT_TABLE_ENTRY("Specular", Specular),
1721         EFFECT_TABLE_ENTRY("Emissive", Emissive),
1722         EFFECT_TABLE_ENTRY("Ambient", Ambient),
1723 #undef EFFECT_TABLE_ENTRY
1724     };
1725
1726     if (!num_materials) {
1727         ok_(__FILE__, line)(effects == NULL, "Expected NULL effects, got %p\n", effects);
1728         return;
1729     }
1730     for (i = 0; i < num_materials; i++)
1731     {
1732         int j;
1733         DWORD expected_num_defaults = ARRAY_SIZE(params) + (materials[i].pTextureFilename ? 1 : 0);
1734
1735         ok_(__FILE__,line)(expected_num_defaults == effects[i].NumDefaults,
1736                 "effect[%u] NumDefaults: Expected %u, got %u\n", i,
1737                 expected_num_defaults, effects[i].NumDefaults);
1738         for (j = 0; j < min(ARRAY_SIZE(params), effects[i].NumDefaults); j++)
1739         {
1740             int k;
1741             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1742             ok_(__FILE__,line)(!strcmp(params[j].name, got_param->pParamName),
1743                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1744                params[j].name, got_param->pParamName);
1745             ok_(__FILE__,line)(D3DXEDT_FLOATS == got_param->Type,
1746                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1747                D3DXEDT_FLOATS, got_param->Type);
1748             ok_(__FILE__,line)(params[j].num_bytes == got_param->NumBytes,
1749                "effect[%u].pDefaults[%u].NumBytes: Expected %u, got %u\n", i, j,
1750                params[j].num_bytes, got_param->NumBytes);
1751             for (k = 0; k < min(params[j].num_bytes, got_param->NumBytes) / 4; k++)
1752             {
1753                 FLOAT expected = ((FLOAT*)((BYTE*)&materials[i] + params[j].value_offset))[k];
1754                 FLOAT got = ((FLOAT*)got_param->pValue)[k];
1755                 ok_(__FILE__,line)(compare(expected, got),
1756                    "effect[%u].pDefaults[%u] float value %u: Expected %g, got %g\n", i, j, k, expected, got);
1757             }
1758         }
1759         if (effects[i].NumDefaults > ARRAY_SIZE(params)) {
1760             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1761             static const char *expected_name = "Texture0@Name";
1762
1763             ok_(__FILE__,line)(!strcmp(expected_name, got_param->pParamName),
1764                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1765                expected_name, got_param->pParamName);
1766             ok_(__FILE__,line)(D3DXEDT_STRING == got_param->Type,
1767                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1768                D3DXEDT_STRING, got_param->Type);
1769             if (materials[i].pTextureFilename) {
1770                 ok_(__FILE__,line)(strlen(materials[i].pTextureFilename) + 1 == got_param->NumBytes,
1771                    "effect[%u] texture filename length: Expected %u, got %u\n", i,
1772                    (DWORD)strlen(materials[i].pTextureFilename) + 1, got_param->NumBytes);
1773                 ok_(__FILE__,line)(!strcmp(materials[i].pTextureFilename, got_param->pValue),
1774                    "effect[%u] texture filename: Expected '%s', got '%s'\n", i,
1775                    materials[i].pTextureFilename, (char*)got_param->pValue);
1776             }
1777         }
1778     }
1779 }
1780
1781 static LPSTR strdupA(LPCSTR p)
1782 {
1783     LPSTR ret;
1784     if (!p) return NULL;
1785     ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
1786     if (ret) strcpy(ret, p);
1787     return ret;
1788 }
1789
1790 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
1791 {
1792     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
1793     if (frame) {
1794         HeapFree(GetProcessHeap(), 0, frame->Name);
1795         HeapFree(GetProcessHeap(), 0, frame);
1796     }
1797     return D3D_OK;
1798 }
1799
1800 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface, LPCSTR name, LPD3DXFRAME *new_frame)
1801 {
1802     LPD3DXFRAME frame;
1803
1804     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
1805     frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
1806     if (!frame)
1807         return E_OUTOFMEMORY;
1808     if (name) {
1809         frame->Name = strdupA(name);
1810         if (!frame->Name) {
1811             HeapFree(GetProcessHeap(), 0, frame);
1812             return E_OUTOFMEMORY;
1813         }
1814     }
1815     *new_frame = frame;
1816     return D3D_OK;
1817 }
1818
1819 static HRESULT destroy_mesh_container(LPD3DXMESHCONTAINER mesh_container)
1820 {
1821     int i;
1822
1823     if (!mesh_container)
1824         return D3D_OK;
1825     HeapFree(GetProcessHeap(), 0, mesh_container->Name);
1826     if (U(mesh_container->MeshData).pMesh)
1827         IUnknown_Release(U(mesh_container->MeshData).pMesh);
1828     if (mesh_container->pMaterials) {
1829         for (i = 0; i < mesh_container->NumMaterials; i++)
1830             HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials[i].pTextureFilename);
1831         HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials);
1832     }
1833     if (mesh_container->pEffects) {
1834         for (i = 0; i < mesh_container->NumMaterials; i++) {
1835             HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pEffectFilename);
1836             if (mesh_container->pEffects[i].pDefaults) {
1837                 int j;
1838                 for (j = 0; j < mesh_container->pEffects[i].NumDefaults; j++) {
1839                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pParamName);
1840                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pValue);
1841                 }
1842                 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults);
1843             }
1844         }
1845         HeapFree(GetProcessHeap(), 0, mesh_container->pEffects);
1846     }
1847     HeapFree(GetProcessHeap(), 0, mesh_container->pAdjacency);
1848     if (mesh_container->pSkinInfo)
1849         IUnknown_Release(mesh_container->pSkinInfo);
1850     HeapFree(GetProcessHeap(), 0, mesh_container);
1851     return D3D_OK;
1852 }
1853
1854 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_DestroyMeshContainer(ID3DXAllocateHierarchy *iface, LPD3DXMESHCONTAINER mesh_container)
1855 {
1856     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyMeshContainer(%p, %p)\n", iface, mesh_container);
1857     return destroy_mesh_container(mesh_container);
1858 }
1859
1860 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_CreateMeshContainer(ID3DXAllocateHierarchy *iface,
1861         LPCSTR name, CONST D3DXMESHDATA *mesh_data, CONST D3DXMATERIAL *materials,
1862         CONST D3DXEFFECTINSTANCE *effects, DWORD num_materials, CONST DWORD *adjacency,
1863         LPD3DXSKININFO skin_info, LPD3DXMESHCONTAINER *new_mesh_container)
1864 {
1865     LPD3DXMESHCONTAINER mesh_container = NULL;
1866     int i;
1867
1868     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateMeshContainer(%p, '%s', %u, %p, %p, %p, %d, %p, %p, %p)\n",
1869             iface, name, mesh_data->Type, U(*mesh_data).pMesh, materials, effects,
1870             num_materials, adjacency, skin_info, *new_mesh_container);
1871
1872     mesh_container = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mesh_container));
1873     if (!mesh_container)
1874         return E_OUTOFMEMORY;
1875
1876     if (name) {
1877         mesh_container->Name = strdupA(name);
1878         if (!mesh_container->Name)
1879             goto error;
1880     }
1881
1882     mesh_container->NumMaterials = num_materials;
1883     if (num_materials) {
1884         mesh_container->pMaterials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*materials));
1885         if (!mesh_container->pMaterials)
1886             goto error;
1887
1888         memcpy(mesh_container->pMaterials, materials, num_materials * sizeof(*materials));
1889         for (i = 0; i < num_materials; i++)
1890             mesh_container->pMaterials[i].pTextureFilename = NULL;
1891         for (i = 0; i < num_materials; i++) {
1892             if (materials[i].pTextureFilename) {
1893                 mesh_container->pMaterials[i].pTextureFilename = strdupA(materials[i].pTextureFilename);
1894                 if (!mesh_container->pMaterials[i].pTextureFilename)
1895                     goto error;
1896             }
1897         }
1898
1899         mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
1900         if (!mesh_container->pEffects)
1901             goto error;
1902         for (i = 0; i < num_materials; i++) {
1903             int j;
1904             const D3DXEFFECTINSTANCE *effect_src = &effects[i];
1905             D3DXEFFECTINSTANCE *effect_dest = &mesh_container->pEffects[i];
1906
1907             if (effect_src->pEffectFilename) {
1908                 effect_dest->pEffectFilename = strdupA(effect_src->pEffectFilename);
1909                 if (!effect_dest->pEffectFilename)
1910                     goto error;
1911             }
1912             effect_dest->pDefaults = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1913                     effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
1914             if (!effect_dest->pDefaults)
1915                 goto error;
1916             effect_dest->NumDefaults = effect_src->NumDefaults;
1917             for (j = 0; j < effect_src->NumDefaults; j++) {
1918                 const D3DXEFFECTDEFAULT *default_src = &effect_src->pDefaults[j];
1919                 D3DXEFFECTDEFAULT *default_dest = &effect_dest->pDefaults[j];
1920
1921                 if (default_src->pParamName) {
1922                     default_dest->pParamName = strdupA(default_src->pParamName);
1923                     if (!default_dest->pParamName)
1924                         goto error;
1925                 }
1926                 default_dest->NumBytes = default_src->NumBytes;
1927                 default_dest->Type = default_src->Type;
1928                 default_dest->pValue = HeapAlloc(GetProcessHeap(), 0, default_src->NumBytes);
1929                 memcpy(default_dest->pValue, default_src->pValue, default_src->NumBytes);
1930             }
1931         }
1932     }
1933
1934     ok(adjacency != NULL, "Expected non-NULL adjacency, got NULL\n");
1935     if (adjacency) {
1936         if (mesh_data->Type == D3DXMESHTYPE_MESH || mesh_data->Type == D3DXMESHTYPE_PMESH) {
1937             ID3DXBaseMesh *basemesh = (ID3DXBaseMesh*)U(*mesh_data).pMesh;
1938             DWORD num_faces = basemesh->lpVtbl->GetNumFaces(basemesh);
1939             size_t size = num_faces * sizeof(DWORD) * 3;
1940             mesh_container->pAdjacency = HeapAlloc(GetProcessHeap(), 0, size);
1941             if (!mesh_container->pAdjacency)
1942                 goto error;
1943             memcpy(mesh_container->pAdjacency, adjacency, size);
1944         } else {
1945             ok(mesh_data->Type == D3DXMESHTYPE_PATCHMESH, "Unknown mesh type %u\n", mesh_data->Type);
1946             if (mesh_data->Type == D3DXMESHTYPE_PATCHMESH)
1947                 trace("FIXME: copying adjacency data for patch mesh not implemented\n");
1948         }
1949     }
1950
1951     memcpy(&mesh_container->MeshData, mesh_data, sizeof(*mesh_data));
1952     if (U(*mesh_data).pMesh)
1953         IUnknown_AddRef(U(*mesh_data).pMesh);
1954     if (skin_info) {
1955         mesh_container->pSkinInfo = skin_info;
1956         skin_info->lpVtbl->AddRef(skin_info);
1957     }
1958     *new_mesh_container = mesh_container;
1959
1960     return S_OK;
1961 error:
1962     destroy_mesh_container(mesh_container);
1963     return E_OUTOFMEMORY;
1964 }
1965
1966 static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
1967     ID3DXAllocateHierarchyImpl_CreateFrame,
1968     ID3DXAllocateHierarchyImpl_CreateMeshContainer,
1969     ID3DXAllocateHierarchyImpl_DestroyFrame,
1970     ID3DXAllocateHierarchyImpl_DestroyMeshContainer,
1971 };
1972 static ID3DXAllocateHierarchy alloc_hier = { &ID3DXAllocateHierarchyImpl_Vtbl };
1973
1974 #define test_LoadMeshFromX(device, xfile_str, vertex_array, fvf, index_array, materials_array, check_adjacency) \
1975     test_LoadMeshFromX_(__LINE__, device, xfile_str, sizeof(xfile_str) - 1, vertex_array, ARRAY_SIZE(vertex_array), fvf, \
1976             index_array, ARRAY_SIZE(index_array), sizeof(*index_array), materials_array, ARRAY_SIZE(materials_array), \
1977             check_adjacency);
1978 static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char *xfile_str, size_t xfile_strlen,
1979         const void *vertices, DWORD num_vertices, DWORD fvf, const void *indices, DWORD num_indices, size_t index_size,
1980         const D3DXMATERIAL *expected_materials, DWORD expected_num_materials, BOOL check_adjacency)
1981 {
1982     HRESULT hr;
1983     ID3DXBuffer *materials = NULL;
1984     ID3DXBuffer *effects = NULL;
1985     ID3DXBuffer *adjacency = NULL;
1986     ID3DXMesh *mesh = NULL;
1987     DWORD num_materials = 0;
1988
1989     /* Adjacency is not checked when the X file contains multiple meshes,
1990      * since calling GenerateAdjacency on the merged mesh is not equivalent
1991      * to calling GenerateAdjacency on the individual meshes and then merging
1992      * the adjacency data. */
1993     hr = D3DXLoadMeshFromXInMemory(xfile_str, xfile_strlen, D3DXMESH_MANAGED, device,
1994             check_adjacency ? &adjacency : NULL, &materials, &effects, &num_materials, &mesh);
1995     ok_(__FILE__,line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1996     if (SUCCEEDED(hr)) {
1997         D3DXMATERIAL *materials_ptr = materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL;
1998         D3DXEFFECTINSTANCE *effects_ptr = effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL;
1999         DWORD *adjacency_ptr = check_adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL;
2000
2001         check_vertex_buffer_(line, mesh, vertices, num_vertices, fvf);
2002         check_index_buffer_(line, mesh, indices, num_indices, index_size);
2003         check_materials_(line, materials_ptr, num_materials, expected_materials, expected_num_materials);
2004         check_generated_effects_(line, materials_ptr, num_materials, effects_ptr);
2005         if (check_adjacency)
2006             check_generated_adjacency_(line, mesh, adjacency_ptr, 0.0f);
2007
2008         if (materials) ID3DXBuffer_Release(materials);
2009         if (effects) ID3DXBuffer_Release(effects);
2010         if (adjacency) ID3DXBuffer_Release(adjacency);
2011         IUnknown_Release(mesh);
2012     }
2013 }
2014
2015 static void D3DXLoadMeshTest(void)
2016 {
2017     static const char empty_xfile[] = "xof 0303txt 0032";
2018     /*________________________*/
2019     static const char simple_xfile[] =
2020         "xof 0303txt 0032"
2021         "Mesh {"
2022             "3;"
2023             "0.0; 0.0; 0.0;,"
2024             "0.0; 1.0; 0.0;,"
2025             "1.0; 1.0; 0.0;;"
2026             "1;"
2027             "3; 0, 1, 2;;"
2028         "}";
2029     static const WORD simple_index_buffer[] = {0, 1, 2};
2030     static const D3DXVECTOR3 simple_vertex_buffer[] = {
2031         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}
2032     };
2033     const DWORD simple_fvf = D3DFVF_XYZ;
2034     static const char framed_xfile[] =
2035         "xof 0303txt 0032"
2036         "Frame {"
2037             "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;; }"
2038             "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */
2039               "1.0, 0.0, 0.0, 0.0,"
2040               "0.0, 1.0, 0.0, 0.0,"
2041               "0.0, 0.0, 1.0, 0.0,"
2042               "0.0, 0.0, 2.0, 1.0;;"
2043             "}"
2044             "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;; }"
2045             "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */
2046               "1.0, 0.0, 0.0, 0.0,"
2047               "0.0, 1.0, 0.0, 0.0,"
2048               "0.0, 0.0, 1.0, 0.0,"
2049               "0.0, 0.0, 3.0, 1.0;;"
2050             "}"
2051             "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;; }"
2052         "}";
2053     static const WORD framed_index_buffer[] = { 0, 1, 2 };
2054     static const D3DXVECTOR3 framed_vertex_buffers[3][3] = {
2055         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}},
2056         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}},
2057         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {3.0, 1.0, 0.0}},
2058     };
2059     static const WORD merged_index_buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
2060     /* frame transforms accumulates for D3DXLoadMeshFromX */
2061     static const D3DXVECTOR3 merged_vertex_buffer[] = {
2062         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0},
2063         {0.0, 0.0, 2.0}, {0.0, 1.0, 2.0}, {2.0, 1.0, 2.0},
2064         {0.0, 0.0, 5.0}, {0.0, 1.0, 5.0}, {3.0, 1.0, 5.0},
2065     };
2066     const DWORD framed_fvf = D3DFVF_XYZ;
2067     /*________________________*/
2068     static const char box_xfile[] =
2069         "xof 0303txt 0032"
2070         "Mesh {"
2071             "8;" /* DWORD nVertices; */
2072             /* array Vector vertices[nVertices]; */
2073             "0.0; 0.0; 0.0;,"
2074             "0.0; 0.0; 1.0;,"
2075             "0.0; 1.0; 0.0;,"
2076             "0.0; 1.0; 1.0;,"
2077             "1.0; 0.0; 0.0;,"
2078             "1.0; 0.0; 1.0;,"
2079             "1.0; 1.0; 0.0;,"
2080             "1.0; 1.0; 1.0;;"
2081             "6;" /* DWORD nFaces; */
2082             /* array MeshFace faces[nFaces]; */
2083             "4; 0, 1, 3, 2;," /* (left side) */
2084             "4; 2, 3, 7, 6;," /* (top side) */
2085             "4; 6, 7, 5, 4;," /* (right side) */
2086             "4; 1, 0, 4, 5;," /* (bottom side) */
2087             "4; 1, 5, 7, 3;," /* (back side) */
2088             "4; 0, 2, 6, 4;;" /* (front side) */
2089             "MeshNormals {"
2090               "6;" /* DWORD nNormals; */
2091               /* array Vector normals[nNormals]; */
2092               "-1.0; 0.0; 0.0;,"
2093               "0.0; 1.0; 0.0;,"
2094               "1.0; 0.0; 0.0;,"
2095               "0.0; -1.0; 0.0;,"
2096               "0.0; 0.0; 1.0;,"
2097               "0.0; 0.0; -1.0;;"
2098               "6;" /* DWORD nFaceNormals; */
2099               /* array MeshFace faceNormals[nFaceNormals]; */
2100               "4; 0, 0, 0, 0;,"
2101               "4; 1, 1, 1, 1;,"
2102               "4; 2, 2, 2, 2;,"
2103               "4; 3, 3, 3, 3;,"
2104               "4; 4, 4, 4, 4;,"
2105               "4; 5, 5, 5, 5;;"
2106             "}"
2107             "MeshMaterialList materials {"
2108               "2;" /* DWORD nMaterials; */
2109               "6;" /* DWORD nFaceIndexes; */
2110               /* array DWORD faceIndexes[nFaceIndexes]; */
2111               "0, 0, 0, 1, 1, 1;;"
2112               "Material {"
2113                 /* ColorRGBA faceColor; */
2114                 "0.0; 0.0; 1.0; 1.0;;"
2115                 /* FLOAT power; */
2116                 "0.5;"
2117                 /* ColorRGB specularColor; */
2118                 "1.0; 1.0; 1.0;;"
2119                 /* ColorRGB emissiveColor; */
2120                 "0.0; 0.0; 0.0;;"
2121               "}"
2122               "Material {"
2123                 /* ColorRGBA faceColor; */
2124                 "1.0; 1.0; 1.0; 1.0;;"
2125                 /* FLOAT power; */
2126                 "1.0;"
2127                 /* ColorRGB specularColor; */
2128                 "1.0; 1.0; 1.0;;"
2129                 /* ColorRGB emissiveColor; */
2130                 "0.0; 0.0; 0.0;;"
2131                 "TextureFilename { \"texture.jpg\"; }"
2132               "}"
2133             "}"
2134             "MeshVertexColors {"
2135               "8;" /* DWORD nVertexColors; */
2136               /* array IndexedColor vertexColors[nVertexColors]; */
2137               "0; 0.0; 0.0; 0.0; 0.0;;"
2138               "1; 0.0; 0.0; 1.0; 0.1;;"
2139               "2; 0.0; 1.0; 0.0; 0.2;;"
2140               "3; 0.0; 1.0; 1.0; 0.3;;"
2141               "4; 1.0; 0.0; 0.0; 0.4;;"
2142               "5; 1.0; 0.0; 1.0; 0.5;;"
2143               "6; 1.0; 1.0; 0.0; 0.6;;"
2144               "7; 1.0; 1.0; 1.0; 0.7;;"
2145             "}"
2146             "MeshTextureCoords {"
2147               "8;" /* DWORD nTextureCoords; */
2148               /* array Coords2d textureCoords[nTextureCoords]; */
2149               "0.0; 1.0;,"
2150               "1.0; 1.0;,"
2151               "0.0; 0.0;,"
2152               "1.0; 0.0;,"
2153               "1.0; 1.0;,"
2154               "0.0; 1.0;,"
2155               "1.0; 0.0;,"
2156               "0.0; 0.0;;"
2157             "}"
2158           "}";
2159     static const WORD box_index_buffer[] = {
2160         0, 1, 3,
2161         0, 3, 2,
2162         8, 9, 7,
2163         8, 7, 6,
2164         10, 11, 5,
2165         10, 5, 4,
2166         12, 13, 14,
2167         12, 14, 15,
2168         16, 17, 18,
2169         16, 18, 19,
2170         20, 21, 22,
2171         20, 22, 23,
2172     };
2173     static const struct {
2174         D3DXVECTOR3 position;
2175         D3DXVECTOR3 normal;
2176         D3DCOLOR diffuse;
2177         D3DXVECTOR2 tex_coords;
2178     } box_vertex_buffer[] = {
2179         {{0.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, 0x00000000, {0.0, 1.0}},
2180         {{0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2181         {{0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2182         {{0.0, 1.0, 1.0}, {-1.0, 0.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2183         {{1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2184         {{1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2185         {{1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2186         {{1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2187         {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2188         {{0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2189         {{1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2190         {{1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2191         {{0.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2192         {{0.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x00000000, {0.0, 1.0}},
2193         {{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2194         {{1.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2195         {{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x1a0000ff, {1.0, 1.0}},
2196         {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x80ff00ff, {0.0, 1.0}},
2197         {{1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0xb3ffffff, {0.0, 0.0}},
2198         {{0.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0x4d00ffff, {1.0, 0.0}},
2199         {{0.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x00000000, {0.0, 1.0}},
2200         {{0.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x3300ff00, {0.0, 0.0}},
2201         {{1.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x99ffff00, {1.0, 0.0}},
2202         {{1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x66ff0000, {1.0, 1.0}},
2203     };
2204     static const D3DXMATERIAL box_materials[] = {
2205         {
2206             {
2207                 {0.0, 0.0, 1.0, 1.0}, /* Diffuse */
2208                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2209                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2210                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2211                 0.5, /* Power */
2212             },
2213             NULL, /* pTextureFilename */
2214         },
2215         {
2216             {
2217                 {1.0, 1.0, 1.0, 1.0}, /* Diffuse */
2218                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2219                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2220                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2221                 1.0, /* Power */
2222             },
2223             (char *)"texture.jpg", /* pTextureFilename */
2224         },
2225     };
2226     const DWORD box_fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
2227     /*________________________*/
2228     static const D3DXMATERIAL default_materials[] = {
2229         {
2230             {
2231                 {0.5, 0.5, 0.5, 0.0}, /* Diffuse */
2232                 {0.0, 0.0, 0.0, 0.0}, /* Ambient */
2233                 {0.5, 0.5, 0.5, 0.0}, /* Specular */
2234                 {0.0, 0.0, 0.0, 0.0}, /* Emissive */
2235                 0.0, /* Power */
2236             },
2237             NULL, /* pTextureFilename */
2238         }
2239     };
2240     HRESULT hr;
2241     HWND wnd = NULL;
2242     IDirect3D9 *d3d = NULL;
2243     IDirect3DDevice9 *device = NULL;
2244     D3DPRESENT_PARAMETERS d3dpp;
2245     ID3DXMesh *mesh = NULL;
2246     D3DXFRAME *frame_hier = NULL;
2247     D3DXMATRIX transform;
2248
2249     wnd = CreateWindow("static", "d3dx9_test", WS_POPUP, 0, 0, 1000, 1000, NULL, NULL, NULL, NULL);
2250     if (!wnd)
2251     {
2252         skip("Couldn't create application window\n");
2253         return;
2254     }
2255     d3d = Direct3DCreate9(D3D_SDK_VERSION);
2256     if (!d3d)
2257     {
2258         skip("Couldn't create IDirect3D9 object\n");
2259         goto cleanup;
2260     }
2261
2262     ZeroMemory(&d3dpp, sizeof(d3dpp));
2263     d3dpp.Windowed = TRUE;
2264     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2265     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2266     if (FAILED(hr))
2267     {
2268         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2269         goto cleanup;
2270     }
2271
2272     hr = D3DXLoadMeshHierarchyFromXInMemory(NULL, sizeof(simple_xfile) - 1,
2273             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2274     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2275
2276     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, 0,
2277             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2278     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2279
2280     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2281             D3DXMESH_MANAGED, NULL, &alloc_hier, NULL, &frame_hier, NULL);
2282     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2283
2284     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2285             D3DXMESH_MANAGED, device, NULL, NULL, &frame_hier, NULL);
2286     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2287
2288     hr = D3DXLoadMeshHierarchyFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1,
2289             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2290     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2291
2292     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2293             D3DXMESH_MANAGED, device, &alloc_hier, NULL, NULL, NULL);
2294     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2295
2296     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2297             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2298     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2299     if (SUCCEEDED(hr)) {
2300         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2301
2302         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2303         D3DXMatrixIdentity(&transform);
2304         check_matrix(&frame_hier->TransformationMatrix, &transform);
2305
2306         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2307         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2308            D3DXMESHTYPE_MESH, container->MeshData.Type);
2309         mesh = U(container->MeshData).pMesh;
2310         check_vertex_buffer(mesh, simple_vertex_buffer, ARRAY_SIZE(simple_vertex_buffer), simple_fvf);
2311         check_index_buffer(mesh, simple_index_buffer, ARRAY_SIZE(simple_index_buffer), sizeof(*simple_index_buffer));
2312         check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2313         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2314         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2315         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2316         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2317         frame_hier = NULL;
2318     }
2319
2320     hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1,
2321             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2322     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2323     if (SUCCEEDED(hr)) {
2324         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2325
2326         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2327         D3DXMatrixIdentity(&transform);
2328         check_matrix(&frame_hier->TransformationMatrix, &transform);
2329
2330         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2331         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2332            D3DXMESHTYPE_MESH, container->MeshData.Type);
2333         mesh = U(container->MeshData).pMesh;
2334         check_vertex_buffer(mesh, box_vertex_buffer, ARRAY_SIZE(box_vertex_buffer), box_fvf);
2335         check_index_buffer(mesh, box_index_buffer, ARRAY_SIZE(box_index_buffer), sizeof(*box_index_buffer));
2336         check_materials(container->pMaterials, container->NumMaterials, box_materials, ARRAY_SIZE(box_materials));
2337         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2338         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2339         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2340         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2341         frame_hier = NULL;
2342     }
2343
2344     hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1,
2345             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2346     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2347     if (SUCCEEDED(hr)) {
2348         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2349         int i;
2350
2351         ok(!strcmp(frame_hier->Name, ""), "Expected '', got '%s'\n", frame_hier->Name);
2352         /* last frame transform replaces the first */
2353         D3DXMatrixIdentity(&transform);
2354         U(transform).m[3][2] = 3.0;
2355         check_matrix(&frame_hier->TransformationMatrix, &transform);
2356
2357         for (i = 0; i < 3; i++) {
2358             ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2359             ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2360                D3DXMESHTYPE_MESH, container->MeshData.Type);
2361             mesh = U(container->MeshData).pMesh;
2362             check_vertex_buffer(mesh, framed_vertex_buffers[i], ARRAY_SIZE(framed_vertex_buffers[0]), framed_fvf);
2363             check_index_buffer(mesh, framed_index_buffer, ARRAY_SIZE(framed_index_buffer), sizeof(*framed_index_buffer));
2364             check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2365             check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2366             check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2367             container = container->pNextMeshContainer;
2368         }
2369         ok(container == NULL, "Expected NULL, got %p\n", container);
2370         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2371         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2372         frame_hier = NULL;
2373     }
2374
2375
2376     hr = D3DXLoadMeshFromXInMemory(NULL, 0, D3DXMESH_MANAGED,
2377                                    device, NULL, NULL, NULL, NULL, &mesh);
2378     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2379
2380     hr = D3DXLoadMeshFromXInMemory(NULL, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2381                                    device, NULL, NULL, NULL, NULL, &mesh);
2382     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2383
2384     hr = D3DXLoadMeshFromXInMemory(simple_xfile, 0, D3DXMESH_MANAGED,
2385                                    device, NULL, NULL, NULL, NULL, &mesh);
2386     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2387
2388     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2389                                    device, NULL, NULL, NULL, NULL, NULL);
2390     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2391
2392     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2393                                    NULL, NULL, NULL, NULL, NULL, &mesh);
2394     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2395
2396     hr = D3DXLoadMeshFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1, D3DXMESH_MANAGED,
2397                                    device, NULL, NULL, NULL, NULL, &mesh);
2398     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2399
2400     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2401                                    device, NULL, NULL, NULL, NULL, &mesh);
2402     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2403     if (SUCCEEDED(hr))
2404         IUnknown_Release(mesh);
2405
2406     test_LoadMeshFromX(device, simple_xfile, simple_vertex_buffer, simple_fvf, simple_index_buffer, default_materials, TRUE);
2407     test_LoadMeshFromX(device, box_xfile, box_vertex_buffer, box_fvf, box_index_buffer, box_materials, TRUE);
2408     test_LoadMeshFromX(device, framed_xfile, merged_vertex_buffer, framed_fvf, merged_index_buffer, default_materials, FALSE);
2409
2410 cleanup:
2411     if (device) IDirect3DDevice9_Release(device);
2412     if (d3d) IDirect3D9_Release(d3d);
2413     if (wnd) DestroyWindow(wnd);
2414 }
2415
2416 static void D3DXCreateBoxTest(void)
2417 {
2418     HRESULT hr;
2419     HWND wnd;
2420     WNDCLASS wc={0};
2421     IDirect3D9* d3d;
2422     IDirect3DDevice9* device;
2423     D3DPRESENT_PARAMETERS d3dpp;
2424     ID3DXMesh* box;
2425     ID3DXBuffer* ppBuffer;
2426     DWORD *buffer;
2427     static const DWORD adjacency[36]=
2428         {6, 9, 1, 2, 10, 0,
2429          1, 9, 3, 4, 10, 2,
2430          3, 8, 5, 7, 11, 4,
2431          0, 11, 7, 5, 8, 6,
2432          7, 4, 9, 2, 0, 8,
2433          1, 3, 11, 5, 6, 10};
2434     unsigned int i;
2435
2436     wc.lpfnWndProc = DefWindowProcA;
2437     wc.lpszClassName = "d3dx9_test_wc";
2438     if (!RegisterClass(&wc))
2439     {
2440         skip("RegisterClass failed\n");
2441         return;
2442     }
2443
2444     wnd = CreateWindow("d3dx9_test_wc", "d3dx9_test",
2445                         WS_SYSMENU | WS_POPUP , 0, 0, 640, 480, 0, 0, 0, 0);
2446     ok(wnd != NULL, "Expected to have a window, received NULL\n");
2447     if (!wnd)
2448     {
2449         skip("Couldn't create application window\n");
2450         return;
2451     }
2452
2453     d3d = Direct3DCreate9(D3D_SDK_VERSION);
2454     if (!d3d)
2455     {
2456         skip("Couldn't create IDirect3D9 object\n");
2457         DestroyWindow(wnd);
2458         return;
2459     }
2460
2461     memset(&d3dpp, 0, sizeof(d3dpp));
2462     d3dpp.Windowed = TRUE;
2463     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2464     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2465     if (FAILED(hr))
2466     {
2467         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2468         IDirect3D9_Release(d3d);
2469         DestroyWindow(wnd);
2470         return;
2471     }
2472
2473     hr = D3DXCreateBuffer(36 * sizeof(DWORD), &ppBuffer);
2474     ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2475     if (FAILED(hr)) goto end;
2476
2477     hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
2478     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2479
2480     hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
2481     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2482
2483     hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
2484     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2485
2486     hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
2487     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2488
2489     hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
2490     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2491
2492     hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
2493     todo_wine ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2494
2495     if (FAILED(hr))
2496     {
2497         skip("D3DXCreateBox failed\n");
2498         goto end;
2499     }
2500
2501     buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
2502     for(i=0; i<36; i++)
2503         todo_wine ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
2504
2505     box->lpVtbl->Release(box);
2506
2507 end:
2508     IDirect3DDevice9_Release(device);
2509     IDirect3D9_Release(d3d);
2510     ID3DXBuffer_Release(ppBuffer);
2511     DestroyWindow(wnd);
2512 }
2513
2514 struct sincos_table
2515 {
2516     float *sin;
2517     float *cos;
2518 };
2519
2520 static void free_sincos_table(struct sincos_table *sincos_table)
2521 {
2522     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
2523     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2524 }
2525
2526 /* pre compute sine and cosine tables; caller must free */
2527 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
2528 {
2529     float angle;
2530     int i;
2531
2532     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2533     if (!sincos_table->sin)
2534     {
2535         return FALSE;
2536     }
2537     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2538     if (!sincos_table->cos)
2539     {
2540         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2541         return FALSE;
2542     }
2543
2544     angle = angle_start;
2545     for (i = 0; i < n; i++)
2546     {
2547         sincos_table->sin[i] = sin(angle);
2548         sincos_table->cos[i] = cos(angle);
2549         angle += angle_step;
2550     }
2551
2552     return TRUE;
2553 }
2554
2555 static WORD vertex_index(UINT slices, int slice, int stack)
2556 {
2557     return stack*slices+slice+1;
2558 }
2559
2560 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
2561 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
2562 {
2563     float theta_step, theta_start;
2564     struct sincos_table theta;
2565     float phi_step, phi_start;
2566     struct sincos_table phi;
2567     DWORD number_of_vertices, number_of_faces;
2568     DWORD vertex, face;
2569     int slice, stack;
2570
2571     /* theta = angle on xy plane wrt x axis */
2572     theta_step = M_PI / stacks;
2573     theta_start = theta_step;
2574
2575     /* phi = angle on xz plane wrt z axis */
2576     phi_step = -2 * M_PI / slices;
2577     phi_start = M_PI / 2;
2578
2579     if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
2580     {
2581         return FALSE;
2582     }
2583     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
2584     {
2585         free_sincos_table(&theta);
2586         return FALSE;
2587     }
2588
2589     number_of_vertices = 2 + slices * (stacks-1);
2590     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
2591
2592     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2593     {
2594         free_sincos_table(&phi);
2595         free_sincos_table(&theta);
2596         return FALSE;
2597     }
2598
2599     vertex = 0;
2600     face = 0;
2601
2602     mesh->vertices[vertex].normal.x = 0.0f;
2603     mesh->vertices[vertex].normal.y = 0.0f;
2604     mesh->vertices[vertex].normal.z = 1.0f;
2605     mesh->vertices[vertex].position.x = 0.0f;
2606     mesh->vertices[vertex].position.y = 0.0f;
2607     mesh->vertices[vertex].position.z = radius;
2608     vertex++;
2609
2610     for (stack = 0; stack < stacks - 1; stack++)
2611     {
2612         for (slice = 0; slice < slices; slice++)
2613         {
2614             mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
2615             mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
2616             mesh->vertices[vertex].normal.z = theta.cos[stack];
2617             mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
2618             mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
2619             mesh->vertices[vertex].position.z = radius * theta.cos[stack];
2620             vertex++;
2621
2622             if (slice > 0)
2623             {
2624                 if (stack == 0)
2625                 {
2626                     /* top stack is triangle fan */
2627                     mesh->faces[face][0] = 0;
2628                     mesh->faces[face][1] = slice + 1;
2629                     mesh->faces[face][2] = slice;
2630                     face++;
2631                 }
2632                 else
2633                 {
2634                     /* stacks in between top and bottom are quad strips */
2635                     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2636                     mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2637                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2638                     face++;
2639
2640                     mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2641                     mesh->faces[face][1] = vertex_index(slices, slice, stack);
2642                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2643                     face++;
2644                 }
2645             }
2646         }
2647
2648         if (stack == 0)
2649         {
2650             mesh->faces[face][0] = 0;
2651             mesh->faces[face][1] = 1;
2652             mesh->faces[face][2] = slice;
2653             face++;
2654         }
2655         else
2656         {
2657             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2658             mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2659             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2660             face++;
2661
2662             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2663             mesh->faces[face][1] = vertex_index(slices, 0, stack);
2664             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2665             face++;
2666         }
2667     }
2668
2669     mesh->vertices[vertex].position.x = 0.0f;
2670     mesh->vertices[vertex].position.y = 0.0f;
2671     mesh->vertices[vertex].position.z = -radius;
2672     mesh->vertices[vertex].normal.x = 0.0f;
2673     mesh->vertices[vertex].normal.y = 0.0f;
2674     mesh->vertices[vertex].normal.z = -1.0f;
2675
2676     /* bottom stack is triangle fan */
2677     for (slice = 1; slice < slices; slice++)
2678     {
2679         mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2680         mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2681         mesh->faces[face][2] = vertex;
2682         face++;
2683     }
2684
2685     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2686     mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2687     mesh->faces[face][2] = vertex;
2688
2689     free_sincos_table(&phi);
2690     free_sincos_table(&theta);
2691
2692     return TRUE;
2693 }
2694
2695 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
2696 {
2697     HRESULT hr;
2698     ID3DXMesh *sphere;
2699     struct mesh mesh;
2700     char name[256];
2701
2702     hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
2703     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2704     if (hr != D3D_OK)
2705     {
2706         skip("Couldn't create sphere\n");
2707         return;
2708     }
2709
2710     if (!compute_sphere(&mesh, radius, slices, stacks))
2711     {
2712         skip("Couldn't create mesh\n");
2713         sphere->lpVtbl->Release(sphere);
2714         return;
2715     }
2716
2717     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2718
2719     sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
2720     compare_mesh(name, sphere, &mesh);
2721
2722     free_mesh(&mesh);
2723
2724     sphere->lpVtbl->Release(sphere);
2725 }
2726
2727 static void D3DXCreateSphereTest(void)
2728 {
2729     HRESULT hr;
2730     HWND wnd;
2731     IDirect3D9* d3d;
2732     IDirect3DDevice9* device;
2733     D3DPRESENT_PARAMETERS d3dpp;
2734     ID3DXMesh* sphere = NULL;
2735
2736     hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
2737     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2738
2739     hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
2740     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2741
2742     hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
2743     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2744
2745     hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
2746     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2747
2748     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
2749     d3d = Direct3DCreate9(D3D_SDK_VERSION);
2750     if (!wnd)
2751     {
2752         skip("Couldn't create application window\n");
2753         return;
2754     }
2755     if (!d3d)
2756     {
2757         skip("Couldn't create IDirect3D9 object\n");
2758         DestroyWindow(wnd);
2759         return;
2760     }
2761
2762     ZeroMemory(&d3dpp, sizeof(d3dpp));
2763     d3dpp.Windowed = TRUE;
2764     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2765     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2766     if (FAILED(hr))
2767     {
2768         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2769         IDirect3D9_Release(d3d);
2770         DestroyWindow(wnd);
2771         return;
2772     }
2773
2774     hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
2775     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2776
2777     hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
2778     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2779
2780     hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
2781     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2782
2783     hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
2784     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2785
2786     test_sphere(device, 0.0f, 2, 2);
2787     test_sphere(device, 1.0f, 2, 2);
2788     test_sphere(device, 1.0f, 3, 2);
2789     test_sphere(device, 1.0f, 4, 4);
2790     test_sphere(device, 1.0f, 3, 4);
2791     test_sphere(device, 5.0f, 6, 7);
2792     test_sphere(device, 10.0f, 11, 12);
2793
2794     IDirect3DDevice9_Release(device);
2795     IDirect3D9_Release(d3d);
2796     DestroyWindow(wnd);
2797 }
2798
2799 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
2800 {
2801     float theta_step, theta_start;
2802     struct sincos_table theta;
2803     FLOAT delta_radius, radius, radius_step;
2804     FLOAT z, z_step, z_normal;
2805     DWORD number_of_vertices, number_of_faces;
2806     DWORD vertex, face;
2807     int slice, stack;
2808
2809     /* theta = angle on xy plane wrt x axis */
2810     theta_step = -2 * M_PI / slices;
2811     theta_start = M_PI / 2;
2812
2813     if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
2814     {
2815         return FALSE;
2816     }
2817
2818     number_of_vertices = 2 + (slices * (3 + stacks));
2819     number_of_faces = 2 * slices + stacks * (2 * slices);
2820
2821     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2822     {
2823         free_sincos_table(&theta);
2824         return FALSE;
2825     }
2826
2827     vertex = 0;
2828     face = 0;
2829
2830     delta_radius = radius1 - radius2;
2831     radius = radius1;
2832     radius_step = delta_radius / stacks;
2833
2834     z = -length / 2;
2835     z_step = length / stacks;
2836     z_normal = delta_radius / length;
2837     if (isnan(z_normal))
2838     {
2839         z_normal = 0.0f;
2840     }
2841
2842     mesh->vertices[vertex].normal.x = 0.0f;
2843     mesh->vertices[vertex].normal.y = 0.0f;
2844     mesh->vertices[vertex].normal.z = -1.0f;
2845     mesh->vertices[vertex].position.x = 0.0f;
2846     mesh->vertices[vertex].position.y = 0.0f;
2847     mesh->vertices[vertex++].position.z = z;
2848
2849     for (slice = 0; slice < slices; slice++, vertex++)
2850     {
2851         mesh->vertices[vertex].normal.x = 0.0f;
2852         mesh->vertices[vertex].normal.y = 0.0f;
2853         mesh->vertices[vertex].normal.z = -1.0f;
2854         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2855         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2856         mesh->vertices[vertex].position.z = z;
2857
2858         if (slice > 0)
2859         {
2860             mesh->faces[face][0] = 0;
2861             mesh->faces[face][1] = slice;
2862             mesh->faces[face++][2] = slice + 1;
2863         }
2864     }
2865
2866     mesh->faces[face][0] = 0;
2867     mesh->faces[face][1] = slice;
2868     mesh->faces[face++][2] = 1;
2869
2870     for (stack = 1; stack <= stacks+1; stack++)
2871     {
2872         for (slice = 0; slice < slices; slice++, vertex++)
2873         {
2874             mesh->vertices[vertex].normal.x = theta.cos[slice];
2875             mesh->vertices[vertex].normal.y = theta.sin[slice];
2876             mesh->vertices[vertex].normal.z = z_normal;
2877             D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
2878             mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2879             mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2880             mesh->vertices[vertex].position.z = z;
2881
2882             if (stack > 1 && slice > 0)
2883             {
2884                 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2885                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2886                 mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
2887
2888                 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2889                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2890                 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
2891             }
2892         }
2893
2894         if (stack > 1)
2895         {
2896             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2897             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2898             mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
2899
2900             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2901             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2902             mesh->faces[face++][2] = vertex_index(slices, 0, stack);
2903         }
2904
2905         if (stack < stacks + 1)
2906         {
2907             z += z_step;
2908             radius -= radius_step;
2909         }
2910     }
2911
2912     for (slice = 0; slice < slices; slice++, vertex++)
2913     {
2914         mesh->vertices[vertex].normal.x = 0.0f;
2915         mesh->vertices[vertex].normal.y = 0.0f;
2916         mesh->vertices[vertex].normal.z = 1.0f;
2917         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2918         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2919         mesh->vertices[vertex].position.z = z;
2920
2921         if (slice > 0)
2922         {
2923             mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
2924             mesh->faces[face][1] = number_of_vertices - 1;
2925             mesh->faces[face++][2] = vertex_index(slices, slice, stack);
2926         }
2927     }
2928
2929     mesh->vertices[vertex].position.x = 0.0f;
2930     mesh->vertices[vertex].position.y = 0.0f;
2931     mesh->vertices[vertex].position.z = z;
2932     mesh->vertices[vertex].normal.x = 0.0f;
2933     mesh->vertices[vertex].normal.y = 0.0f;
2934     mesh->vertices[vertex].normal.z = 1.0f;
2935
2936     mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
2937     mesh->faces[face][1] = number_of_vertices - 1;
2938     mesh->faces[face][2] = vertex_index(slices, 0, stack);
2939
2940     free_sincos_table(&theta);
2941
2942     return TRUE;
2943 }
2944
2945 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
2946 {
2947     HRESULT hr;
2948     ID3DXMesh *cylinder;
2949     struct mesh mesh;
2950     char name[256];
2951
2952     hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
2953     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2954     if (hr != D3D_OK)
2955     {
2956         skip("Couldn't create cylinder\n");
2957         return;
2958     }
2959
2960     if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
2961     {
2962         skip("Couldn't create mesh\n");
2963         cylinder->lpVtbl->Release(cylinder);
2964         return;
2965     }
2966
2967     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2968
2969     sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
2970     compare_mesh(name, cylinder, &mesh);
2971
2972     free_mesh(&mesh);
2973
2974     cylinder->lpVtbl->Release(cylinder);
2975 }
2976
2977 static void D3DXCreateCylinderTest(void)
2978 {
2979     HRESULT hr;
2980     HWND wnd;
2981     IDirect3D9* d3d;
2982     IDirect3DDevice9* device;
2983     D3DPRESENT_PARAMETERS d3dpp;
2984     ID3DXMesh* cylinder = NULL;
2985
2986     hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
2987     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2988
2989     hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
2990     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2991
2992     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
2993     d3d = Direct3DCreate9(D3D_SDK_VERSION);
2994     if (!wnd)
2995     {
2996         skip("Couldn't create application window\n");
2997         return;
2998     }
2999     if (!d3d)
3000     {
3001         skip("Couldn't create IDirect3D9 object\n");
3002         DestroyWindow(wnd);
3003         return;
3004     }
3005
3006     ZeroMemory(&d3dpp, sizeof(d3dpp));
3007     d3dpp.Windowed = TRUE;
3008     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
3009     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
3010     if (FAILED(hr))
3011     {
3012         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
3013         IDirect3D9_Release(d3d);
3014         DestroyWindow(wnd);
3015         return;
3016     }
3017
3018     hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3019     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3020
3021     hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3022     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3023
3024     if (SUCCEEDED(hr) && cylinder)
3025     {
3026         cylinder->lpVtbl->Release(cylinder);
3027     }
3028
3029     hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
3030     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3031
3032     hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
3033     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3034
3035     if (SUCCEEDED(hr) && cylinder)
3036     {
3037         cylinder->lpVtbl->Release(cylinder);
3038     }
3039
3040     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
3041     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3042
3043     /* Test with length == 0.0f succeeds */
3044     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
3045     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3046
3047     if (SUCCEEDED(hr) && cylinder)
3048     {
3049         cylinder->lpVtbl->Release(cylinder);
3050     }
3051
3052     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
3053     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3054
3055     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
3056     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3057
3058     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
3059     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3060
3061     test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
3062     test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
3063     test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
3064     test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
3065     test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
3066     test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
3067
3068     IDirect3DDevice9_Release(device);
3069     IDirect3D9_Release(d3d);
3070     DestroyWindow(wnd);
3071 }
3072
3073 struct dynamic_array
3074 {
3075     int count, capacity;
3076     void *items;
3077 };
3078
3079 enum pointtype {
3080     POINTTYPE_CURVE = 0,
3081     POINTTYPE_CORNER,
3082     POINTTYPE_CURVE_START,
3083     POINTTYPE_CURVE_END,
3084     POINTTYPE_CURVE_MIDDLE,
3085 };
3086
3087 struct point2d
3088 {
3089     D3DXVECTOR2 pos;
3090     enum pointtype corner;
3091 };
3092
3093 /* is a dynamic_array */
3094 struct outline
3095 {
3096     int count, capacity;
3097     struct point2d *items;
3098 };
3099
3100 /* is a dynamic_array */
3101 struct outline_array
3102 {
3103     int count, capacity;
3104     struct outline *items;
3105 };
3106
3107 struct glyphinfo
3108 {
3109     struct outline_array outlines;
3110     float offset_x;
3111 };
3112
3113 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
3114 {
3115     if (count > array->capacity) {
3116         void *new_buffer;
3117         int new_capacity;
3118         if (array->items && array->capacity) {
3119             new_capacity = max(array->capacity * 2, count);
3120             new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
3121         } else {
3122             new_capacity = max(16, count);
3123             new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
3124         }
3125         if (!new_buffer)
3126             return FALSE;
3127         array->items = new_buffer;
3128         array->capacity = new_capacity;
3129     }
3130     return TRUE;
3131 }
3132
3133 static struct point2d *add_point(struct outline *array)
3134 {
3135     struct point2d *item;
3136
3137     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3138         return NULL;
3139
3140     item = &array->items[array->count++];
3141     ZeroMemory(item, sizeof(*item));
3142     return item;
3143 }
3144
3145 static struct outline *add_outline(struct outline_array *array)
3146 {
3147     struct outline *item;
3148
3149     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3150         return NULL;
3151
3152     item = &array->items[array->count++];
3153     ZeroMemory(item, sizeof(*item));
3154     return item;
3155 }
3156
3157 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
3158 {
3159     D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
3160     while (count--) {
3161         D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
3162         pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
3163         pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
3164         pt++;
3165     }
3166     return ret;
3167 }
3168
3169 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
3170                                  const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
3171                                  float max_deviation)
3172 {
3173     D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
3174     float deviation;
3175
3176     D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
3177     D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
3178     D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
3179
3180     deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
3181     if (deviation < max_deviation) {
3182         struct point2d *pt = add_point(outline);
3183         if (!pt) return E_OUTOFMEMORY;
3184         pt->pos = *p2;
3185         pt->corner = POINTTYPE_CURVE;
3186         /* the end point is omitted because the end line merges into the next segment of
3187          * the split bezier curve, and the end of the split bezier curve is added outside
3188          * this recursive function. */
3189     } else {
3190         HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
3191         if (hr != S_OK) return hr;
3192         hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
3193         if (hr != S_OK) return hr;
3194     }
3195
3196     return S_OK;
3197 }
3198
3199 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
3200 {
3201     /* dot product = cos(theta) */
3202     return D3DXVec2Dot(dir1, dir2) > cos_theta;
3203 }
3204
3205 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
3206 {
3207     return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
3208 }
3209
3210 static BOOL attempt_line_merge(struct outline *outline,
3211                                int pt_index,
3212                                const D3DXVECTOR2 *nextpt,
3213                                BOOL to_curve)
3214 {
3215     D3DXVECTOR2 curdir, lastdir;
3216     struct point2d *prevpt, *pt;
3217     BOOL ret = FALSE;
3218     const float cos_half = cos(D3DXToRadian(0.5f));
3219
3220     pt = &outline->items[pt_index];
3221     pt_index = (pt_index - 1 + outline->count) % outline->count;
3222     prevpt = &outline->items[pt_index];
3223
3224     if (to_curve)
3225         pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
3226
3227     if (outline->count < 2)
3228         return FALSE;
3229
3230     /* remove last point if the next line continues the last line */
3231     unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3232     unit_vec2(&curdir, &pt->pos, nextpt);
3233     if (is_direction_similar(&lastdir, &curdir, cos_half))
3234     {
3235         outline->count--;
3236         if (pt->corner == POINTTYPE_CURVE_END)
3237             prevpt->corner = pt->corner;
3238         if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
3239             prevpt->corner = POINTTYPE_CURVE_MIDDLE;
3240         pt = prevpt;
3241
3242         ret = TRUE;
3243         if (outline->count < 2)
3244             return ret;
3245
3246         pt_index = (pt_index - 1 + outline->count) % outline->count;
3247         prevpt = &outline->items[pt_index];
3248         unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3249         unit_vec2(&curdir, &pt->pos, nextpt);
3250     }
3251     return ret;
3252 }
3253
3254 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
3255                               float max_deviation, float emsquare)
3256 {
3257     const float cos_45 = cos(D3DXToRadian(45.0f));
3258     const float cos_90 = cos(D3DXToRadian(90.0f));
3259     TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
3260
3261     while ((char *)header < (char *)raw_outline + datasize)
3262     {
3263         TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
3264         struct point2d *lastpt, *pt;
3265         D3DXVECTOR2 lastdir;
3266         D3DXVECTOR2 *pt_flt;
3267         int j;
3268         struct outline *outline = add_outline(&glyph->outlines);
3269
3270         if (!outline)
3271             return E_OUTOFMEMORY;
3272
3273         pt = add_point(outline);
3274         if (!pt)
3275             return E_OUTOFMEMORY;
3276         pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
3277         pt->pos = *pt_flt;
3278         pt->corner = POINTTYPE_CORNER;
3279
3280         if (header->dwType != TT_POLYGON_TYPE)
3281             trace("Unknown header type %d\n", header->dwType);
3282
3283         while ((char *)curve < (char *)header + header->cb)
3284         {
3285             D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
3286             BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
3287
3288             if (!curve->cpfx) {
3289                 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3290                 continue;
3291             }
3292
3293             pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
3294
3295             attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
3296
3297             if (to_curve)
3298             {
3299                 HRESULT hr;
3300                 int count = curve->cpfx;
3301                 j = 0;
3302
3303                 while (count > 2)
3304                 {
3305                     D3DXVECTOR2 bezier_end;
3306
3307                     D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
3308                     hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
3309                     if (hr != S_OK)
3310                         return hr;
3311                     bezier_start = bezier_end;
3312                     count--;
3313                     j++;
3314                 }
3315                 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
3316                 if (hr != S_OK)
3317                     return hr;
3318
3319                 pt = add_point(outline);
3320                 if (!pt)
3321                     return E_OUTOFMEMORY;
3322                 j++;
3323                 pt->pos = pt_flt[j];
3324                 pt->corner = POINTTYPE_CURVE_END;
3325             } else {
3326                 for (j = 0; j < curve->cpfx; j++)
3327                 {
3328                     pt = add_point(outline);
3329                     if (!pt)
3330                         return E_OUTOFMEMORY;
3331                     pt->pos = pt_flt[j];
3332                     pt->corner = POINTTYPE_CORNER;
3333                 }
3334             }
3335
3336             curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3337         }
3338
3339         /* remove last point if the next line continues the last line */
3340         if (outline->count >= 3) {
3341             BOOL to_curve;
3342
3343             lastpt = &outline->items[outline->count - 1];
3344             pt = &outline->items[0];
3345             if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
3346                 if (lastpt->corner == POINTTYPE_CURVE_END)
3347                 {
3348                     if (pt->corner == POINTTYPE_CURVE_START)
3349                         pt->corner = POINTTYPE_CURVE_MIDDLE;
3350                     else
3351                         pt->corner = POINTTYPE_CURVE_END;
3352                 }
3353                 outline->count--;
3354                 lastpt = &outline->items[outline->count - 1];
3355             } else {
3356                 /* outline closed with a line from end to start point */
3357                 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
3358             }
3359             lastpt = &outline->items[0];
3360             to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
3361             if (lastpt->corner == POINTTYPE_CURVE_START)
3362                 lastpt->corner = POINTTYPE_CORNER;
3363             pt = &outline->items[1];
3364             if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
3365                 *lastpt = outline->items[outline->count];
3366         }
3367
3368         lastpt = &outline->items[outline->count - 1];
3369         pt = &outline->items[0];
3370         unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
3371         for (j = 0; j < outline->count; j++)
3372         {
3373             D3DXVECTOR2 curdir;
3374
3375             lastpt = pt;
3376             pt = &outline->items[(j + 1) % outline->count];
3377             unit_vec2(&curdir, &lastpt->pos, &pt->pos);
3378
3379             switch (lastpt->corner)
3380             {
3381                 case POINTTYPE_CURVE_START:
3382                 case POINTTYPE_CURVE_END:
3383                     if (!is_direction_similar(&lastdir, &curdir, cos_45))
3384                         lastpt->corner = POINTTYPE_CORNER;
3385                     break;
3386                 case POINTTYPE_CURVE_MIDDLE:
3387                     if (!is_direction_similar(&lastdir, &curdir, cos_90))
3388                         lastpt->corner = POINTTYPE_CORNER;
3389                     else
3390                         lastpt->corner = POINTTYPE_CURVE;
3391                     break;
3392                 default:
3393                     break;
3394             }
3395             lastdir = curdir;
3396         }
3397
3398         header = (TTPOLYGONHEADER *)((char *)header + header->cb);
3399     }
3400     return S_OK;
3401 }
3402
3403 static BOOL compute_text_mesh(struct mesh *mesh, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion, FLOAT otmEMSquare)
3404 {
3405     HRESULT hr = E_FAIL;
3406     DWORD nb_vertices, nb_faces;
3407     DWORD nb_corners, nb_outline_points;
3408     int textlen = 0;
3409     float offset_x;
3410     char *raw_outline = NULL;
3411     struct glyphinfo *glyphs = NULL;
3412     GLYPHMETRICS gm;
3413     int i;
3414     struct vertex *vertex_ptr;
3415     face *face_ptr;
3416
3417     if (deviation == 0.0f)
3418         deviation = 1.0f / otmEMSquare;
3419
3420     textlen = strlen(text);
3421     glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
3422     if (!glyphs) {
3423         hr = E_OUTOFMEMORY;
3424         goto error;
3425     }
3426
3427     offset_x = 0.0f;
3428     for (i = 0; i < textlen; i++)
3429     {
3430         /* get outline points from data returned from GetGlyphOutline */
3431         const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
3432         int datasize;
3433
3434         glyphs[i].offset_x = offset_x;
3435
3436         datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
3437         if (datasize < 0) {
3438             hr = E_FAIL;
3439             goto error;
3440         }
3441         HeapFree(GetProcessHeap(), 0, raw_outline);
3442         raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
3443         if (!glyphs) {
3444             hr = E_OUTOFMEMORY;
3445             goto error;
3446         }
3447         datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
3448
3449         create_outline(&glyphs[i], raw_outline, datasize, deviation, otmEMSquare);
3450
3451         offset_x += gm.gmCellIncX / (float)otmEMSquare;
3452     }
3453
3454     /* corner points need an extra vertex for the different side faces normals */
3455     nb_corners = 0;
3456     nb_outline_points = 0;
3457     for (i = 0; i < textlen; i++)
3458     {
3459         int j;
3460         for (j = 0; j < glyphs[i].outlines.count; j++)
3461         {
3462             int k;
3463             struct outline *outline = &glyphs[i].outlines.items[j];
3464             nb_outline_points += outline->count;
3465             nb_corners++; /* first outline point always repeated as a corner */
3466             for (k = 1; k < outline->count; k++)
3467                 if (outline->items[k].corner)
3468                     nb_corners++;
3469         }
3470     }
3471
3472     nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
3473     nb_faces = nb_outline_points * 2;
3474
3475     if (!new_mesh(mesh, nb_vertices, nb_faces))
3476         goto error;
3477
3478     /* convert 2D vertices and faces into 3D mesh */
3479     vertex_ptr = mesh->vertices;
3480     face_ptr = mesh->faces;
3481     for (i = 0; i < textlen; i++)
3482     {
3483         int j;
3484
3485         /* side vertices and faces */
3486         for (j = 0; j < glyphs[i].outlines.count; j++)
3487         {
3488             struct vertex *outline_vertices = vertex_ptr;
3489             struct outline *outline = &glyphs[i].outlines.items[j];
3490             int k;
3491             struct point2d *prevpt = &outline->items[outline->count - 1];
3492             struct point2d *pt = &outline->items[0];
3493
3494             for (k = 1; k <= outline->count; k++)
3495             {
3496                 struct vertex vtx;
3497                 struct point2d *nextpt = &outline->items[k % outline->count];
3498                 WORD vtx_idx = vertex_ptr - mesh->vertices;
3499                 D3DXVECTOR2 vec;
3500
3501                 if (pt->corner == POINTTYPE_CURVE_START)
3502                     D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
3503                 else if (pt->corner)
3504                     D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3505                 else
3506                     D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
3507                 D3DXVec2Normalize(&vec, &vec);
3508                 vtx.normal.x = -vec.y;
3509                 vtx.normal.y = vec.x;
3510                 vtx.normal.z = 0;
3511
3512                 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
3513                 vtx.position.y = pt->pos.y;
3514                 vtx.position.z = 0;
3515                 *vertex_ptr++ = vtx;
3516
3517                 vtx.position.z = -extrusion;
3518                 *vertex_ptr++ = vtx;
3519
3520                 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
3521                 vtx.position.y = nextpt->pos.y;
3522                 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
3523                     vtx.position.z = -extrusion;
3524                     *vertex_ptr++ = vtx;
3525                     vtx.position.z = 0;
3526                     *vertex_ptr++ = vtx;
3527
3528                     (*face_ptr)[0] = vtx_idx;
3529                     (*face_ptr)[1] = vtx_idx + 2;
3530                     (*face_ptr)[2] = vtx_idx + 1;
3531                     face_ptr++;
3532
3533                     (*face_ptr)[0] = vtx_idx;
3534                     (*face_ptr)[1] = vtx_idx + 3;
3535                     (*face_ptr)[2] = vtx_idx + 2;
3536                     face_ptr++;
3537                 } else {
3538                     if (nextpt->corner) {
3539                         if (nextpt->corner == POINTTYPE_CURVE_END) {
3540                             struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
3541                             D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
3542                         } else {
3543                             D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3544                         }
3545                         D3DXVec2Normalize(&vec, &vec);
3546                         vtx.normal.x = -vec.y;
3547                         vtx.normal.y = vec.x;
3548
3549                         vtx.position.z = 0;
3550                         *vertex_ptr++ = vtx;
3551                         vtx.position.z = -extrusion;
3552                         *vertex_ptr++ = vtx;
3553                     }
3554
3555                     (*face_ptr)[0] = vtx_idx;
3556                     (*face_ptr)[1] = vtx_idx + 3;
3557                     (*face_ptr)[2] = vtx_idx + 1;
3558                     face_ptr++;
3559
3560                     (*face_ptr)[0] = vtx_idx;
3561                     (*face_ptr)[1] = vtx_idx + 2;
3562                     (*face_ptr)[2] = vtx_idx + 3;
3563                     face_ptr++;
3564                 }
3565
3566                 prevpt = pt;
3567                 pt = nextpt;
3568             }
3569             if (!pt->corner) {
3570                 *vertex_ptr++ = *outline_vertices++;
3571                 *vertex_ptr++ = *outline_vertices++;
3572             }
3573         }
3574
3575         /* FIXME: compute expected faces */
3576         /* Add placeholder to separate glyph outlines */
3577         vertex_ptr->position.x = 0;
3578         vertex_ptr->position.y = 0;
3579         vertex_ptr->position.z = 0;
3580         vertex_ptr->normal.x = 0;
3581         vertex_ptr->normal.y = 0;
3582         vertex_ptr->normal.z = 1;
3583         vertex_ptr++;
3584     }
3585
3586     hr = D3D_OK;
3587 error:
3588     if (glyphs) {
3589         for (i = 0; i < textlen; i++)
3590         {
3591             int j;
3592             for (j = 0; j < glyphs[i].outlines.count; j++)
3593                 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items[j].items);
3594             HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items);
3595         }
3596         HeapFree(GetProcessHeap(), 0, glyphs);
3597     }
3598     HeapFree(GetProcessHeap(), 0, raw_outline);
3599
3600     return hr == D3D_OK;
3601 }
3602
3603 static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh, int textlen, float extrusion)
3604 {
3605     HRESULT hr;
3606     DWORD number_of_vertices, number_of_faces;
3607     IDirect3DVertexBuffer9 *vertex_buffer = NULL;
3608     IDirect3DIndexBuffer9 *index_buffer = NULL;
3609     D3DVERTEXBUFFER_DESC vertex_buffer_description;
3610     D3DINDEXBUFFER_DESC index_buffer_description;
3611     struct vertex *vertices = NULL;
3612     face *faces = NULL;
3613     int expected, i;
3614     int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
3615
3616     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
3617     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
3618
3619     /* vertex buffer */
3620     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
3621     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3622     if (hr != D3D_OK)
3623     {
3624         skip("Couldn't get vertex buffers\n");
3625         goto error;
3626     }
3627
3628     hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
3629     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3630
3631     if (hr != D3D_OK)
3632     {
3633         skip("Couldn't get vertex buffer description\n");
3634     }
3635     else
3636     {
3637         ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
3638            name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
3639         ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
3640            name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
3641         ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
3642         ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
3643            name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
3644         ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
3645            name, vertex_buffer_description.FVF, mesh->fvf);
3646         if (mesh->fvf == 0)
3647         {
3648             expected = number_of_vertices * mesh->vertex_size;
3649         }
3650         else
3651         {
3652             expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
3653         }
3654         ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
3655            name, vertex_buffer_description.Size, expected);
3656     }
3657
3658     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
3659     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3660     if (hr != D3D_OK)
3661     {
3662         skip("Couldn't get index buffer\n");
3663         goto error;
3664     }
3665
3666     hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
3667     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3668
3669     if (hr != D3D_OK)
3670     {
3671         skip("Couldn't get index buffer description\n");
3672     }
3673     else
3674     {
3675         ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
3676            name, index_buffer_description.Format, D3DFMT_INDEX16);
3677         ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
3678            name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
3679         todo_wine ok(index_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, index_buffer_description.Usage, 0);
3680         ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
3681            name, index_buffer_description.Pool, D3DPOOL_MANAGED);
3682         expected = number_of_faces * sizeof(WORD) * 3;
3683         ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
3684            name, index_buffer_description.Size, expected);
3685     }
3686
3687     /* specify offset and size to avoid potential overruns */
3688     hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
3689                                      (LPVOID *)&vertices, D3DLOCK_DISCARD);
3690     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3691     if (hr != D3D_OK)
3692     {
3693         skip("Couldn't lock vertex buffer\n");
3694         goto error;
3695     }
3696     hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
3697                                     (LPVOID *)&faces, D3DLOCK_DISCARD);
3698     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3699     if (hr != D3D_OK)
3700     {
3701         skip("Couldn't lock index buffer\n");
3702         goto error;
3703     }
3704
3705     face_idx1 = 0;
3706     vtx_idx2 = 0;
3707     face_idx2 = 0;
3708     vtx_idx1 = 0;
3709     for (i = 0; i < textlen; i++)
3710     {
3711         int nb_outline_vertices1, nb_outline_faces1;
3712         int nb_outline_vertices2, nb_outline_faces2;
3713         int nb_back_vertices, nb_back_faces;
3714         int first_vtx1, first_vtx2;
3715         int first_face1, first_face2;
3716         int j;
3717
3718         first_vtx1 = vtx_idx1;
3719         first_vtx2 = vtx_idx2;
3720         for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
3721             if (vertices[vtx_idx1].normal.z != 0)
3722                 break;
3723         }
3724         for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
3725             if (mesh->vertices[vtx_idx2].normal.z != 0)
3726                 break;
3727         }
3728         nb_outline_vertices1 = vtx_idx1 - first_vtx1;
3729         nb_outline_vertices2 = vtx_idx2 - first_vtx2;
3730         ok(nb_outline_vertices1 == nb_outline_vertices2,
3731            "Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
3732            nb_outline_vertices1, nb_outline_vertices2);
3733
3734         for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
3735         {
3736             vtx_idx1 = first_vtx1 + j;
3737             vtx_idx2 = first_vtx2 + j;
3738             ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
3739                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3740                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
3741                mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
3742             ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
3743                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3744                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3745                mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
3746         }
3747         vtx_idx1 = first_vtx1 + nb_outline_vertices1;
3748         vtx_idx2 = first_vtx2 + nb_outline_vertices2;
3749
3750         first_face1 = face_idx1;
3751         first_face2 = face_idx2;
3752         for (; face_idx1 < number_of_faces; face_idx1++)
3753         {
3754             if (faces[face_idx1][0] >= vtx_idx1 ||
3755                 faces[face_idx1][1] >= vtx_idx1 ||
3756                 faces[face_idx1][2] >= vtx_idx1)
3757                 break;
3758         }
3759         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
3760         {
3761             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
3762                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
3763                 mesh->faces[face_idx2][2] >= vtx_idx2)
3764                 break;
3765         }
3766         nb_outline_faces1 = face_idx1 - first_face1;
3767         nb_outline_faces2 = face_idx2 - first_face2;
3768         ok(nb_outline_faces1 == nb_outline_faces2,
3769            "Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
3770            nb_outline_faces1, nb_outline_faces2);
3771
3772         for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
3773         {
3774             face_idx1 = first_face1 + j;
3775             face_idx2 = first_face2 + j;
3776             ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
3777                faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
3778                faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
3779                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
3780                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
3781                mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
3782                mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
3783                mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
3784         }
3785         face_idx1 = first_face1 + nb_outline_faces1;
3786         face_idx2 = first_face2 + nb_outline_faces2;
3787
3788         /* partial test on back vertices and faces  */
3789         first_vtx1 = vtx_idx1;
3790         for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
3791             struct vertex vtx;
3792
3793             if (vertices[vtx_idx1].normal.z != 1.0f)
3794                 break;
3795
3796             vtx.position.z = 0.0f;
3797             vtx.normal.x = 0.0f;
3798             vtx.normal.y = 0.0f;
3799             vtx.normal.z = 1.0f;
3800             ok(compare(vertices[vtx_idx1].position.z, vtx.position.z),
3801                "Test %s, glyph %d, vertex position.z %d, result %g, expected %g\n", name, i, vtx_idx1,
3802                vertices[vtx_idx1].position.z, vtx.position.z);
3803             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
3804                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3805                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3806                vtx.normal.x, vtx.normal.y, vtx.normal.z);
3807         }
3808         nb_back_vertices = vtx_idx1 - first_vtx1;
3809         first_face1 = face_idx1;
3810         for (; face_idx1 < number_of_faces; face_idx1++)
3811         {
3812             const D3DXVECTOR3 *vtx1, *vtx2, *vtx3;
3813             D3DXVECTOR3 normal;
3814             D3DXVECTOR3 v1 = {0, 0, 0};
3815             D3DXVECTOR3 v2 = {0, 0, 0};
3816             D3DXVECTOR3 forward = {0.0f, 0.0f, 1.0f};
3817
3818             if (faces[face_idx1][0] >= vtx_idx1 ||
3819                 faces[face_idx1][1] >= vtx_idx1 ||
3820                 faces[face_idx1][2] >= vtx_idx1)
3821                 break;
3822
3823             vtx1 = &vertices[faces[face_idx1][0]].position;
3824             vtx2 = &vertices[faces[face_idx1][1]].position;
3825             vtx3 = &vertices[faces[face_idx1][2]].position;
3826
3827             D3DXVec3Subtract(&v1, vtx2, vtx1);
3828             D3DXVec3Subtract(&v2, vtx3, vtx2);
3829             D3DXVec3Cross(&normal, &v1, &v2);
3830             D3DXVec3Normalize(&normal, &normal);
3831             ok(!D3DXVec3Length(&normal) || compare_vec3(normal, forward),
3832                "Test %s, glyph %d, face %d normal, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, face_idx1,
3833                normal.x, normal.y, normal.z, forward.x, forward.y, forward.z);
3834         }
3835         nb_back_faces = face_idx1 - first_face1;
3836
3837         /* compare front and back faces & vertices */
3838         if (extrusion == 0.0f) {
3839             /* Oddly there are only back faces in this case */
3840             nb_back_vertices /= 2;
3841             nb_back_faces /= 2;
3842             face_idx1 -= nb_back_faces;
3843             vtx_idx1 -= nb_back_vertices;
3844         }
3845         for (j = 0; j < nb_back_vertices; j++)
3846         {
3847             struct vertex vtx = vertices[first_vtx1];
3848             vtx.position.z = -extrusion;
3849             vtx.normal.x = 0.0f;
3850             vtx.normal.y = 0.0f;
3851             vtx.normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
3852             ok(compare_vec3(vertices[vtx_idx1].position, vtx.position),
3853                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3854                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
3855                vtx.position.x, vtx.position.y, vtx.position.z);
3856             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
3857                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3858                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3859                vtx.normal.x, vtx.normal.y, vtx.normal.z);
3860             vtx_idx1++;
3861             first_vtx1++;
3862         }
3863         for (j = 0; j < nb_back_faces; j++)
3864         {
3865             int f1, f2;
3866             if (extrusion == 0.0f) {
3867                 f1 = 1;
3868                 f2 = 2;
3869             } else {
3870                 f1 = 2;
3871                 f2 = 1;
3872             }
3873             ok(faces[face_idx1][0] == faces[first_face1][0] + nb_back_vertices &&
3874                faces[face_idx1][1] == faces[first_face1][f1] + nb_back_vertices &&
3875                faces[face_idx1][2] == faces[first_face1][f2] + nb_back_vertices,
3876                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
3877                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
3878                faces[first_face1][0] - nb_back_faces,
3879                faces[first_face1][f1] - nb_back_faces,
3880                faces[first_face1][f2] - nb_back_faces);
3881             first_face1++;
3882             face_idx1++;
3883         }
3884
3885         /* skip to the outline for the next glyph */
3886         for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
3887             if (mesh->vertices[vtx_idx2].normal.z == 0)
3888                 break;
3889         }
3890         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
3891         {
3892             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
3893                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
3894                 mesh->faces[face_idx2][2] >= vtx_idx2) break;
3895         }
3896     }
3897
3898 error:
3899     if (vertices) IDirect3DVertexBuffer9_Unlock(vertex_buffer);
3900     if (faces) IDirect3DIndexBuffer9_Unlock(index_buffer);
3901     if (index_buffer) IDirect3DIndexBuffer9_Release(index_buffer);
3902     if (vertex_buffer) IDirect3DVertexBuffer9_Release(vertex_buffer);
3903 }
3904
3905 static void test_createtext(IDirect3DDevice9 *device, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion)
3906 {
3907     HRESULT hr;
3908     ID3DXMesh *d3dxmesh;
3909     struct mesh mesh;
3910     char name[256];
3911     OUTLINETEXTMETRIC otm;
3912     GLYPHMETRICS gm;
3913     GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
3914     int i;
3915     LOGFONT lf;
3916     HFONT font = NULL, oldfont = NULL;
3917
3918     sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion);
3919
3920     hr = D3DXCreateText(device, hdc, text, deviation, extrusion, &d3dxmesh, NULL, glyphmetrics_float);
3921     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3922     if (hr != D3D_OK)
3923     {
3924         skip("Couldn't create text with D3DXCreateText\n");
3925         return;
3926     }
3927
3928     /* must select a modified font having lfHeight = otm.otmEMSquare before
3929      * calling GetGlyphOutline to get the expected values */
3930     if (!GetObject(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf) ||
3931         !GetOutlineTextMetrics(hdc, sizeof(otm), &otm))
3932     {
3933         d3dxmesh->lpVtbl->Release(d3dxmesh);
3934         skip("Couldn't get text outline\n");
3935         return;
3936     }
3937     lf.lfHeight = otm.otmEMSquare;
3938     lf.lfWidth = 0;
3939     font = CreateFontIndirect(&lf);
3940     if (!font) {
3941         d3dxmesh->lpVtbl->Release(d3dxmesh);
3942         skip("Couldn't create the modified font\n");
3943         return;
3944     }
3945     oldfont = SelectObject(hdc, font);
3946
3947     for (i = 0; i < strlen(text); i++)
3948     {
3949         const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
3950         GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
3951         compare_float(glyphmetrics_float[i].gmfBlackBoxX, gm.gmBlackBoxX / (float)otm.otmEMSquare);
3952         compare_float(glyphmetrics_float[i].gmfBlackBoxY, gm.gmBlackBoxY / (float)otm.otmEMSquare);
3953         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.x, gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare);
3954         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.y, gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare);
3955         compare_float(glyphmetrics_float[i].gmfCellIncX, gm.gmCellIncX / (float)otm.otmEMSquare);
3956         compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
3957     }
3958
3959     ZeroMemory(&mesh, sizeof(mesh));
3960     if (!compute_text_mesh(&mesh, hdc, text, deviation, extrusion, otm.otmEMSquare))
3961     {
3962         skip("Couldn't create mesh\n");
3963         d3dxmesh->lpVtbl->Release(d3dxmesh);
3964         return;
3965     }
3966     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3967
3968     compare_text_outline_mesh(name, d3dxmesh, &mesh, strlen(text), extrusion);
3969
3970     free_mesh(&mesh);
3971
3972     d3dxmesh->lpVtbl->Release(d3dxmesh);
3973     SelectObject(hdc, oldfont);
3974     HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
3975 }
3976
3977 static void D3DXCreateTextTest(void)
3978 {
3979     HRESULT hr;
3980     HWND wnd;
3981     HDC hdc;
3982     IDirect3D9* d3d;
3983     IDirect3DDevice9* device;
3984     D3DPRESENT_PARAMETERS d3dpp;
3985     ID3DXMesh* d3dxmesh = NULL;
3986     HFONT hFont;
3987     OUTLINETEXTMETRIC otm;
3988     int number_of_vertices;
3989     int number_of_faces;
3990
3991     wnd = CreateWindow("static", "d3dx9_test", WS_POPUP, 0, 0, 1000, 1000, NULL, NULL, NULL, NULL);
3992     d3d = Direct3DCreate9(D3D_SDK_VERSION);
3993     if (!wnd)
3994     {
3995         skip("Couldn't create application window\n");
3996         return;
3997     }
3998     if (!d3d)
3999     {
4000         skip("Couldn't create IDirect3D9 object\n");
4001         DestroyWindow(wnd);
4002         return;
4003     }
4004
4005     ZeroMemory(&d3dpp, sizeof(d3dpp));
4006     d3dpp.Windowed = TRUE;
4007     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
4008     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
4009     if (FAILED(hr))
4010     {
4011         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
4012         IDirect3D9_Release(d3d);
4013         DestroyWindow(wnd);
4014         return;
4015     }
4016
4017     hdc = CreateCompatibleDC(NULL);
4018
4019     hFont = CreateFont(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
4020                        OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
4021                        "Arial");
4022     SelectObject(hdc, hFont);
4023     GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
4024
4025     hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, NULL, NULL, NULL);
4026     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4027
4028     /* D3DXCreateTextA page faults from passing NULL text */
4029
4030     hr = D3DXCreateTextW(device, hdc, NULL, 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4031     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4032
4033     hr = D3DXCreateText(device, hdc, "", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4034     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4035
4036     hr = D3DXCreateText(device, hdc, " ", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4037     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4038
4039     hr = D3DXCreateText(NULL, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4040     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4041
4042     hr = D3DXCreateText(device, NULL, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4043     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4044
4045     hr = D3DXCreateText(device, hdc, "wine", -FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4046     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4047
4048     hr = D3DXCreateText(device, hdc, "wine", 0.001f, -FLT_MIN, &d3dxmesh, NULL, NULL);
4049     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4050
4051     /* deviation = 0.0f treated as if deviation = 1.0f / otm.otmEMSquare */
4052     hr = D3DXCreateText(device, hdc, "wine", 1.0f / otm.otmEMSquare, 0.4f, &d3dxmesh, NULL, NULL);
4053     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4054     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
4055     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
4056     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4057
4058     hr = D3DXCreateText(device, hdc, "wine", 0.0f, 0.4f, &d3dxmesh, NULL, NULL);
4059     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4060     ok(number_of_vertices == d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh),
4061        "Got %d vertices, expected %d\n",
4062        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_vertices);
4063     ok(number_of_faces == d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh),
4064        "Got %d faces, expected %d\n",
4065        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_faces);
4066     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4067
4068 #if 0
4069     /* too much detail requested, so will appear to hang */
4070     trace("Waiting for D3DXCreateText to finish with deviation = FLT_MIN ...\n");
4071     hr = D3DXCreateText(device, hdc, "wine", FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4072     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4073     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4074     trace("D3DXCreateText finish with deviation = FLT_MIN\n");
4075 #endif
4076
4077     hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4078     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4079     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4080
4081     test_createtext(device, hdc, "wine", FLT_MAX, 0.4f);
4082     test_createtext(device, hdc, "wine", 0.001f, FLT_MIN);
4083     test_createtext(device, hdc, "wine", 0.001f, 0.0f);
4084     test_createtext(device, hdc, "wine", 0.001f, FLT_MAX);
4085     test_createtext(device, hdc, "wine", 0.0f, 1.0f);
4086
4087     DeleteDC(hdc);
4088
4089     IDirect3DDevice9_Release(device);
4090     IDirect3D9_Release(d3d);
4091     DestroyWindow(wnd);
4092 }
4093
4094 static void test_get_decl_length(void)
4095 {
4096     static const D3DVERTEXELEMENT9 declaration1[] =
4097     {
4098         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4099         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4100         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4101         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4102         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4103         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4104         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4105         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4106         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4107         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4108         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4109         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4110         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4111         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4112         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4113         D3DDECL_END(),
4114     };
4115     static const D3DVERTEXELEMENT9 declaration2[] =
4116     {
4117         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4118         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4119         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4120         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4121         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4122         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4123         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4124         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4125         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4126         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4127         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4128         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4129         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4130         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4131         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4132         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4133         D3DDECL_END(),
4134     };
4135     UINT size;
4136
4137     size = D3DXGetDeclLength(declaration1);
4138     ok(size == 15, "Got size %u, expected 15.\n", size);
4139
4140     size = D3DXGetDeclLength(declaration2);
4141     ok(size == 16, "Got size %u, expected 16.\n", size);
4142 }
4143
4144 static void test_get_decl_vertex_size(void)
4145 {
4146     static const D3DVERTEXELEMENT9 declaration1[] =
4147     {
4148         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4149         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4150         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4151         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4152         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4153         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4154         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4155         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4156         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4157         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4158         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4159         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4160         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4161         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4162         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4163         D3DDECL_END(),
4164     };
4165     static const D3DVERTEXELEMENT9 declaration2[] =
4166     {
4167         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4168         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4169         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4170         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4171         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4172         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4173         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4174         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4175         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4176         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4177         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4178         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4179         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4180         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4181         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4182         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4183         D3DDECL_END(),
4184     };
4185     static const UINT sizes1[] =
4186     {
4187         4,  8,  12, 16,
4188         4,  4,  4,  8,
4189         4,  4,  8,  4,
4190         4,  4,  8,  0,
4191     };
4192     static const UINT sizes2[] =
4193     {
4194         12, 16, 20, 24,
4195         12, 12, 16, 16,
4196     };
4197     unsigned int i;
4198     UINT size;
4199
4200     size = D3DXGetDeclVertexSize(NULL, 0);
4201     ok(size == 0, "Got size %#x, expected 0.\n", size);
4202
4203     for (i = 0; i < 16; ++i)
4204     {
4205         size = D3DXGetDeclVertexSize(declaration1, i);
4206         ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
4207     }
4208
4209     for (i = 0; i < 8; ++i)
4210     {
4211         size = D3DXGetDeclVertexSize(declaration2, i);
4212         ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
4213     }
4214 }
4215
4216 static void D3DXGenerateAdjacencyTest(void)
4217 {
4218     HRESULT hr;
4219     HWND wnd;
4220     IDirect3D9 *d3d;
4221     IDirect3DDevice9 *device;
4222     D3DPRESENT_PARAMETERS d3dpp;
4223     ID3DXMesh *d3dxmesh = NULL;
4224     D3DXVECTOR3 *vertices = NULL;
4225     WORD *indices = NULL;
4226     int i;
4227     struct {
4228         DWORD num_vertices;
4229         D3DXVECTOR3 vertices[6];
4230         DWORD num_faces;
4231         WORD indices[3 * 3];
4232         FLOAT epsilon;
4233         DWORD adjacency[3 * 3];
4234     } test_data[] = {
4235         { /* for epsilon < 0, indices must match for faces to be adjacent */
4236             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}},
4237             2, {0, 1, 2,  0, 2, 3},
4238             -1.0,
4239             {-1, -1, 1,  0, -1, -1},
4240         },
4241         {
4242             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}},
4243             2, {0, 1, 2,  3, 4, 5},
4244             -1.0,
4245             {-1, -1, -1,  -1, -1, -1},
4246         },
4247         { /* for epsilon == 0, indices or vertices must match for faces to be adjacent */
4248             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}},
4249             2, {0, 1, 2,  3, 4, 5},
4250             0.0,
4251             {-1, -1, 1,  0, -1, -1},
4252         },
4253         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4254             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}},
4255             2, {0, 1, 2,  3, 4, 5},
4256             0.25,
4257             {-1, -1, -1,  -1, -1, -1},
4258         },
4259         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4260             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}},
4261             2, {0, 1, 2,  3, 4, 5},
4262             0.250001,
4263             {-1, -1, 1,  0, -1, -1},
4264         },
4265         { /* length between vertices are compared to epsilon, not the individual dimension deltas */
4266             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}},
4267             2, {0, 1, 2,  3, 4, 5},
4268             0.353, /* < sqrt(0.25*0.25 + 0.25*0.25) */
4269             {-1, -1, -1,  -1, -1, -1},
4270         },
4271         {
4272             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}},
4273             2, {0, 1, 2,  3, 4, 5},
4274             0.354, /* > sqrt(0.25*0.25 + 0.25*0.25) */
4275             {-1, -1, 1,  0, -1, -1},
4276         },
4277         { /* adjacent faces must have opposite winding orders at the shared edge */
4278             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}},
4279             2, {0, 1, 2,  0, 3, 2},
4280             0.0,
4281             {-1, -1, -1,  -1, -1, -1},
4282         },
4283     };
4284
4285     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
4286     if (!wnd)
4287     {
4288         skip("Couldn't create application window\n");
4289         return;
4290     }
4291     d3d = Direct3DCreate9(D3D_SDK_VERSION);
4292     if (!d3d)
4293     {
4294         skip("Couldn't create IDirect3D9 object\n");
4295         DestroyWindow(wnd);
4296         return;
4297     }
4298
4299     ZeroMemory(&d3dpp, sizeof(d3dpp));
4300     d3dpp.Windowed = TRUE;
4301     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
4302     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
4303     if (FAILED(hr))
4304     {
4305         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
4306         IDirect3D9_Release(d3d);
4307         DestroyWindow(wnd);
4308         return;
4309     }
4310
4311     for (i = 0; i < ARRAY_SIZE(test_data); i++)
4312     {
4313         DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
4314         int j;
4315
4316         if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4317         d3dxmesh = NULL;
4318
4319         hr = D3DXCreateMeshFVF(test_data[i].num_faces, test_data[i].num_vertices, 0, D3DFVF_XYZ, device, &d3dxmesh);
4320         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4321
4322         hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&vertices);
4323         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4324         if (FAILED(hr)) continue;
4325         CopyMemory(vertices, test_data[i].vertices, test_data[i].num_vertices * sizeof(test_data[0].vertices[0]));
4326         d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
4327
4328         hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&indices);
4329         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4330         if (FAILED(hr)) continue;
4331         CopyMemory(indices, test_data[i].indices, test_data[i].num_faces * 3 * sizeof(test_data[0].indices[0]));
4332         d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
4333
4334         if (i == 0) {
4335             hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, NULL);
4336             ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4337         }
4338
4339         hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, test_data[i].epsilon, adjacency);
4340         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4341         if (FAILED(hr)) continue;
4342
4343         for (j = 0; j < test_data[i].num_faces * 3; j++)
4344             ok(adjacency[j] == test_data[i].adjacency[j],
4345                "Test %d adjacency %d: Got result %u, expected %u\n", i, j,
4346                adjacency[j], test_data[i].adjacency[j]);
4347     }
4348     if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4349 }
4350
4351 static void test_update_semantics(void)
4352 {
4353     HRESULT hr;
4354     struct test_context *test_context = NULL;
4355     ID3DXMesh *mesh = NULL;
4356     D3DVERTEXELEMENT9 declaration0[] =
4357     {
4358          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4359          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4360          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4361          D3DDECL_END()
4362     };
4363     D3DVERTEXELEMENT9 declaration_pos_type_color[] =
4364     {
4365          {0, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4366          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4367          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4368          D3DDECL_END()
4369     };
4370     D3DVERTEXELEMENT9 declaration_smaller[] =
4371     {
4372          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4373          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4374          D3DDECL_END()
4375     };
4376     D3DVERTEXELEMENT9 declaration_larger[] =
4377     {
4378          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4379          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4380          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4381          {0, 40, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4382          D3DDECL_END()
4383     };
4384     D3DVERTEXELEMENT9 declaration_multiple_streams[] =
4385     {
4386          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4387          {1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4388          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4389          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4390
4391          D3DDECL_END()
4392     };
4393     D3DVERTEXELEMENT9 declaration_double_usage[] =
4394     {
4395          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4396          {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4397          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4398          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4399          D3DDECL_END()
4400     };
4401     D3DVERTEXELEMENT9 declaration_undefined_type[] =
4402     {
4403          {0, 0, D3DDECLTYPE_UNUSED+1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4404          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4405          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4406          D3DDECL_END()
4407     };
4408     D3DVERTEXELEMENT9 declaration_not_4_byte_aligned_offset[] =
4409     {
4410          {0, 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4411          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4412          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4413          D3DDECL_END()
4414     };
4415     static const struct
4416     {
4417         D3DXVECTOR3 position0;
4418         D3DXVECTOR3 position1;
4419         D3DXVECTOR3 normal;
4420         DWORD color;
4421     }
4422     vertices[] =
4423     {
4424         { { 0.0f,  1.0f,  0.f}, { 1.0f,  0.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xffff0000 },
4425         { { 1.0f, -1.0f,  0.f}, {-1.0f, -1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff00ff00 },
4426         { {-1.0f, -1.0f,  0.f}, {-1.0f,  1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff0000ff },
4427     };
4428     unsigned int faces[] = {0, 1, 2};
4429     unsigned int attributes[] = {0};
4430     unsigned int num_faces = ARRAY_SIZE(faces) / 3;
4431     unsigned int num_vertices = ARRAY_SIZE(vertices);
4432     int offset = sizeof(D3DXVECTOR3);
4433     DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4434     void *vertex_buffer;
4435     void *index_buffer;
4436     DWORD *attributes_buffer;
4437     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
4438     D3DVERTEXELEMENT9 *decl_ptr;
4439     DWORD exp_vertex_size = sizeof(*vertices);
4440     DWORD vertex_size = 0;
4441     int equal;
4442     int i = 0;
4443     int *decl_mem;
4444     int filler_a = 0xaaaaaaaa;
4445     int filler_b = 0xbbbbbbbb;
4446
4447     test_context = new_test_context();
4448     if (!test_context)
4449     {
4450         skip("Couldn't create a test_context\n");
4451         goto cleanup;
4452     }
4453
4454     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration0,
4455                         test_context->device, &mesh);
4456     if (FAILED(hr))
4457     {
4458         skip("Couldn't create test mesh %#x\n", hr);
4459         goto cleanup;
4460     }
4461
4462     mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
4463     memcpy(vertex_buffer, vertices, sizeof(vertices));
4464     mesh->lpVtbl->UnlockVertexBuffer(mesh);
4465
4466     mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
4467     memcpy(index_buffer, faces, sizeof(faces));
4468     mesh->lpVtbl->UnlockIndexBuffer(mesh);
4469
4470     mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
4471     memcpy(attributes_buffer, attributes, sizeof(attributes));
4472     mesh->lpVtbl->UnlockAttributeBuffer(mesh);
4473
4474     /* Get the declaration and try to change it */
4475     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4476     if (FAILED(hr))
4477     {
4478         skip("Couldn't get vertex declaration %#x\n", hr);
4479         goto cleanup;
4480     }
4481     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4482     ok(equal == 0, "Vertex declarations were not equal\n");
4483
4484     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4485     {
4486         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4487         {
4488             /* Use second vertex position instead of first */
4489             decl_ptr->Offset = offset;
4490         }
4491     }
4492
4493     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4494     ok(hr == D3D_OK, "Test UpdateSematics, got %#x expected %#x\n", hr, D3D_OK);
4495
4496     /* Check that declaration was written by getting it again */
4497     memset(declaration, 0, sizeof(declaration));
4498     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4499     if (FAILED(hr))
4500     {
4501         skip("Couldn't get vertex declaration %#x\n", hr);
4502         goto cleanup;
4503     }
4504
4505     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4506     {
4507         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4508         {
4509             ok(decl_ptr->Offset == offset, "Test UpdateSematics, got offset %d expected %d\n",
4510                decl_ptr->Offset, offset);
4511         }
4512     }
4513
4514     /* Check that GetDeclaration only writes up to the D3DDECL_END() marker and
4515      * not the full MAX_FVF_DECL_SIZE elements.
4516      */
4517     memset(declaration, filler_a, sizeof(declaration));
4518     memcpy(declaration, declaration0, sizeof(declaration0));
4519     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4520     ok(hr == D3D_OK, "Test UpdateSematics, "
4521        "got %#x expected D3D_OK\n", hr);
4522     memset(declaration, filler_b, sizeof(declaration));
4523     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4524     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4525     decl_mem = (int*)declaration;
4526     for (i = sizeof(declaration0)/sizeof(*decl_mem); i < sizeof(declaration)/sizeof(*decl_mem); i++)
4527     {
4528         equal = memcmp(&decl_mem[i], &filler_b, sizeof(filler_b));
4529         ok(equal == 0,
4530            "GetDeclaration wrote past the D3DDECL_END() marker. "
4531            "Got %#x, expected  %#x\n", decl_mem[i], filler_b);
4532         if (equal != 0) break;
4533     }
4534
4535     /* UpdateSemantics does not check for overlapping fields */
4536     memset(declaration, 0, sizeof(declaration));
4537     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4538     if (FAILED(hr))
4539     {
4540         skip("Couldn't get vertex declaration %#x\n", hr);
4541         goto cleanup;
4542     }
4543
4544     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4545     {
4546         if (decl_ptr->Type == D3DDECLTYPE_FLOAT3)
4547         {
4548             decl_ptr->Type = D3DDECLTYPE_FLOAT4;
4549         }
4550     }
4551
4552     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4553     ok(hr == D3D_OK, "Test UpdateSematics for overlapping fields, "
4554        "got %#x expected D3D_OK\n", hr);
4555
4556     /* Set the position type to color instead of float3 */
4557     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_pos_type_color);
4558     ok(hr == D3D_OK, "Test UpdateSematics position type color, "
4559        "got %#x expected D3D_OK\n", hr);
4560
4561     /* The following test cases show that NULL, smaller or larger declarations,
4562      * and declarations with non-zero Stream values are not accepted.
4563      * UpdateSemantics returns D3DERR_INVALIDCALL and the previously set
4564      * declaration will be used by DrawSubset, GetNumBytesPerVertex, and
4565      * GetDeclaration.
4566      */
4567
4568     /* Null declaration (invalid declaration) */
4569     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4570     hr = mesh->lpVtbl->UpdateSemantics(mesh, NULL);
4571     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics null pointer declaration, "
4572        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4573     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4574     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4575        vertex_size, exp_vertex_size);
4576     memset(declaration, 0, sizeof(declaration));
4577     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4578     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4579     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4580     ok(equal == 0, "Vertex declarations were not equal\n");
4581
4582     /* Smaller vertex declaration (invalid declaration) */
4583     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4584     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_smaller);
4585     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics for smaller vertex declaration, "
4586        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4587     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4588     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4589        vertex_size, exp_vertex_size);
4590     memset(declaration, 0, sizeof(declaration));
4591     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4592     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4593     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4594     ok(equal == 0, "Vertex declarations were not equal\n");
4595
4596     /* Larger vertex declaration (invalid declaration) */
4597     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4598     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_larger);
4599     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics for larger vertex declaration, "
4600        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4601     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4602     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4603        vertex_size, exp_vertex_size);
4604     memset(declaration, 0, sizeof(declaration));
4605     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4606     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4607     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4608     ok(equal == 0, "Vertex declarations were not equal\n");
4609
4610     /* Use multiple streams and keep the same vertex size (invalid declaration) */
4611     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4612     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_multiple_streams);
4613     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics using multiple streams, "
4614                  "got %#x expected D3DERR_INVALIDCALL\n", hr);
4615     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4616     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4617        vertex_size, exp_vertex_size);
4618     memset(declaration, 0, sizeof(declaration));
4619     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4620     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4621     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4622     ok(equal == 0, "Vertex declarations were not equal\n");
4623
4624     /* The next following test cases show that some invalid declarations are
4625      * accepted with a D3D_OK. An access violation is thrown on Windows if
4626      * DrawSubset is called. The methods GetNumBytesPerVertex and GetDeclaration
4627      * are not affected, which indicates that the declaration is cached.
4628      */
4629
4630     /* Double usage (invalid declaration) */
4631     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4632     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_double_usage);
4633     ok(hr == D3D_OK, "Test UpdateSematics double usage, "
4634        "got %#x expected D3D_OK\n", hr);
4635     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4636     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4637        vertex_size, exp_vertex_size);
4638     memset(declaration, 0, sizeof(declaration));
4639     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4640     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4641     equal = memcmp(declaration, declaration_double_usage, sizeof(declaration_double_usage));
4642     ok(equal == 0, "Vertex declarations were not equal\n");
4643
4644     /* Set the position to an undefined type (invalid declaration) */
4645     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4646     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_undefined_type);
4647     ok(hr == D3D_OK, "Test UpdateSematics undefined type, "
4648        "got %#x expected D3D_OK\n", hr);
4649     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4650     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4651        vertex_size, exp_vertex_size);
4652     memset(declaration, 0, sizeof(declaration));
4653     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4654     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4655     equal = memcmp(declaration, declaration_undefined_type, sizeof(declaration_undefined_type));
4656     ok(equal == 0, "Vertex declarations were not equal\n");
4657
4658     /* Use a not 4 byte aligned offset (invalid declaration) */
4659     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4660     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_not_4_byte_aligned_offset);
4661     ok(hr == D3D_OK, "Test UpdateSematics not 4 byte aligned offset, "
4662        "got %#x expected D3D_OK\n", hr);
4663     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4664     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4665        vertex_size, exp_vertex_size);
4666     memset(declaration, 0, sizeof(declaration));
4667     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4668     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4669     equal = memcmp(declaration, declaration_not_4_byte_aligned_offset,
4670                    sizeof(declaration_not_4_byte_aligned_offset));
4671     ok(equal == 0, "Vertex declarations were not equal\n");
4672
4673 cleanup:
4674     if (mesh)
4675         mesh->lpVtbl->Release(mesh);
4676
4677     free_test_context(test_context);
4678 }
4679
4680 static void test_create_skin_info(void)
4681 {
4682     HRESULT hr;
4683     ID3DXSkinInfo *skininfo = NULL;
4684     D3DVERTEXELEMENT9 empty_declaration[] = { D3DDECL_END() };
4685     D3DVERTEXELEMENT9 declaration_out[MAX_FVF_DECL_SIZE];
4686     const D3DVERTEXELEMENT9 declaration_with_nonzero_stream[] = {
4687         {1, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
4688         D3DDECL_END()
4689     };
4690
4691     hr = D3DXCreateSkinInfo(0, empty_declaration, 0, &skininfo);
4692     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4693     if (skininfo) IUnknown_Release(skininfo);
4694     skininfo = NULL;
4695
4696     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
4697     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4698
4699     hr = D3DXCreateSkinInfo(1, declaration_with_nonzero_stream, 1, &skininfo);
4700     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4701
4702     hr = D3DXCreateSkinInfoFVF(1, 0, 1, &skininfo);
4703     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4704     if (skininfo) {
4705         DWORD dword_result;
4706         FLOAT flt_result;
4707         LPCSTR string_result;
4708         D3DXMATRIX *transform;
4709         D3DXMATRIX identity_matrix;
4710
4711         /* test initial values */
4712         hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4713         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4714         if (SUCCEEDED(hr))
4715             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
4716
4717         dword_result = skininfo->lpVtbl->GetNumBones(skininfo);
4718         ok(dword_result == 1, "Expected 1, got %u\n", dword_result);
4719
4720         flt_result = skininfo->lpVtbl->GetMinBoneInfluence(skininfo);
4721         ok(flt_result == 0.0f, "Expected 0.0, got %g\n", flt_result);
4722
4723         string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4724         ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
4725
4726         dword_result = skininfo->lpVtbl->GetFVF(skininfo);
4727         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4728
4729         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 0);
4730         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4731
4732         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 1);
4733         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4734
4735         transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, -1);
4736         ok(transform == NULL, "Expected NULL, got %p\n", transform);
4737
4738         {
4739             /* test [GS]etBoneOffsetMatrix */
4740             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 1, &identity_matrix);
4741             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4742
4743             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, NULL);
4744             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4745
4746             D3DXMatrixIdentity(&identity_matrix);
4747             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, &identity_matrix);
4748             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4749
4750             transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, 0);
4751             check_matrix(transform, &identity_matrix);
4752         }
4753
4754         {
4755             /* test [GS]etBoneName */
4756             const char *name_in = "testBoneName";
4757             const char *string_result2;
4758
4759             hr = skininfo->lpVtbl->SetBoneName(skininfo, 1, name_in);
4760             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4761
4762             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, NULL);
4763             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4764
4765             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, name_in);
4766             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4767
4768             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4769             ok(string_result != NULL, "Expected non-NULL string, got %p\n", string_result);
4770             ok(!strcmp(string_result, name_in), "Expected '%s', got '%s'\n", name_in, string_result);
4771
4772             string_result2 = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4773             ok(string_result == string_result2, "Expected %p, got %p\n", string_result, string_result2);
4774
4775             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 1);
4776             ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
4777         }
4778
4779         {
4780             /* test [GS]etBoneInfluence */
4781             DWORD vertices[2];
4782             FLOAT weights[2];
4783             int i;
4784             DWORD num_influences;
4785             DWORD exp_vertices[2];
4786             FLOAT exp_weights[2];
4787
4788             /* vertex and weight arrays untouched when num_influences is 0 */
4789             vertices[0] = 0xdeadbeef;
4790             weights[0] = FLT_MAX;
4791             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4792             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4793             ok(vertices[0] == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", vertices[0]);
4794             ok(weights[0] == FLT_MAX, "expected %g, got %g\n", FLT_MAX, weights[0]);
4795
4796             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 1, vertices, weights);
4797             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4798
4799             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, NULL);
4800             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4801
4802             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, NULL);
4803             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4804
4805             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, weights);
4806             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4807
4808
4809             /* no vertex or weight value checking */
4810             exp_vertices[0] = 0;
4811             exp_vertices[1] = 0x87654321;
4812             exp_weights[0] = 0.5;
4813             exp_weights[1] = 0.0f / 0.0f; /* NAN */
4814             num_influences = 2;
4815
4816             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 1, num_influences, vertices, weights);
4817             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4818
4819             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, weights);
4820             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4821
4822             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, vertices, NULL);
4823             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4824
4825             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, NULL);
4826             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4827
4828             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, exp_vertices, exp_weights);
4829             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4830
4831             memset(vertices, 0, sizeof(vertices));
4832             memset(weights, 0, sizeof(weights));
4833             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4834             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4835             for (i = 0; i < num_influences; i++) {
4836                 ok(exp_vertices[i] == vertices[i],
4837                    "influence[%d]: expected vertex %u, got %u\n", i, exp_vertices[i], vertices[i]);
4838                 ok((isnan(exp_weights[i]) && isnan(weights[i])) || exp_weights[i] == weights[i],
4839                    "influence[%d]: expected weights %g, got %g\n", i, exp_weights[i], weights[i]);
4840             }
4841
4842             /* vertices and weights aren't returned after setting num_influences to 0 */
4843             memset(vertices, 0, sizeof(vertices));
4844             memset(weights, 0, sizeof(weights));
4845             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, 0, vertices, weights);
4846             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4847
4848             vertices[0] = 0xdeadbeef;
4849             weights[0] = FLT_MAX;
4850             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4851             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4852             ok(vertices[0] == 0xdeadbeef, "expected vertex 0xdeadbeef, got %u\n", vertices[0]);
4853             ok(weights[0] == FLT_MAX, "expected weight %g, got %g\n", FLT_MAX, weights[0]);
4854         }
4855
4856         {
4857             /* test [GS]etFVF and [GS]etDeclaration */
4858             D3DVERTEXELEMENT9 declaration_in[MAX_FVF_DECL_SIZE];
4859             DWORD fvf = D3DFVF_XYZ;
4860             DWORD got_fvf;
4861
4862             hr = skininfo->lpVtbl->SetDeclaration(skininfo, NULL);
4863             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4864
4865             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_with_nonzero_stream);
4866             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4867
4868             hr = skininfo->lpVtbl->SetFVF(skininfo, 0);
4869             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4870
4871             hr = D3DXDeclaratorFromFVF(fvf, declaration_in);
4872             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4873             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_in);
4874             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4875             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4876             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
4877             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4878             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4879             compare_elements(declaration_out, declaration_in, __LINE__, 0);
4880
4881             hr = skininfo->lpVtbl->SetDeclaration(skininfo, empty_declaration);
4882             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4883             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4884             ok(got_fvf == 0, "Expected 0, got %#x\n", got_fvf);
4885             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4886             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4887             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
4888
4889             hr = skininfo->lpVtbl->SetFVF(skininfo, fvf);
4890             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4891             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4892             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
4893             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4894             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4895             compare_elements(declaration_out, declaration_in, __LINE__, 0);
4896         }
4897     }
4898     if (skininfo) IUnknown_Release(skininfo);
4899     skininfo = NULL;
4900
4901     hr = D3DXCreateSkinInfoFVF(1, D3DFVF_XYZ, 1, NULL);
4902     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4903
4904     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
4905     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4906 }
4907
4908 static void test_convert_adjacency_to_point_reps(void)
4909 {
4910     HRESULT hr;
4911     struct test_context *test_context = NULL;
4912     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4913     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
4914     const D3DVERTEXELEMENT9 declaration[] =
4915     {
4916         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4917         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4918         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4919         D3DDECL_END()
4920     };
4921     const unsigned int VERTS_PER_FACE = 3;
4922     void *vertex_buffer;
4923     void *index_buffer;
4924     DWORD *attributes_buffer;
4925     int i, j;
4926     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
4927     struct vertex_pnc
4928     {
4929         D3DXVECTOR3 position;
4930         D3DXVECTOR3 normal;
4931         enum color color; /* In case of manual visual inspection */
4932     };
4933     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
4934     /* mesh0 (one face)
4935      *
4936      * 0--1
4937      * | /
4938      * |/
4939      * 2
4940      */
4941     const struct vertex_pnc vertices0[] =
4942     {
4943         {{ 0.0f,  3.0f,  0.f}, up, RED},
4944         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
4945         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
4946     };
4947     const DWORD indices0[] = {0, 1, 2};
4948     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
4949     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
4950     const DWORD adjacency0[] = {-1, -1, -1};
4951     const DWORD exp_point_rep0[] = {0, 1, 2};
4952     /* mesh1 (right)
4953      *
4954      * 0--1 3
4955      * | / /|
4956      * |/ / |
4957      * 2 5--4
4958      */
4959     const struct vertex_pnc vertices1[] =
4960     {
4961         {{ 0.0f,  3.0f,  0.f}, up, RED},
4962         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
4963         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
4964
4965         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
4966         {{ 3.0f,  0.0f,  0.f}, up, RED},
4967         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
4968     };
4969     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
4970     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
4971     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
4972     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
4973     const DWORD exp_point_rep1[] = {0, 1, 2, 1, 4, 2};
4974     /* mesh2 (left)
4975      *
4976      *    3 0--1
4977      *   /| | /
4978      *  / | |/
4979      * 5--4 2
4980      */
4981     const struct vertex_pnc vertices2[] =
4982     {
4983         {{ 0.0f,  3.0f,  0.f}, up, RED},
4984         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
4985         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
4986
4987         {{-1.0f,  3.0f,  0.f}, up, RED},
4988         {{-1.0f,  0.0f,  0.f}, up, GREEN},
4989         {{-3.0f,  0.0f,  0.f}, up, BLUE},
4990     };
4991     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
4992     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
4993     const unsigned int num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
4994     const DWORD adjacency2[] = {-1, -1, 1, 0, -1, -1};
4995     const DWORD exp_point_rep2[] = {0, 1, 2, 0, 2, 5};
4996     /* mesh3 (above)
4997      *
4998      *    3
4999      *   /|
5000      *  / |
5001      * 5--4
5002      * 0--1
5003      * | /
5004      * |/
5005      * 2
5006      */
5007     struct vertex_pnc vertices3[] =
5008     {
5009         {{ 0.0f,  3.0f,  0.f}, up, RED},
5010         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5011         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5012
5013         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5014         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5015         {{ 0.0f,  4.0f,  0.f}, up, RED},
5016     };
5017     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5018     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5019     const unsigned int num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
5020     const DWORD adjacency3[] = {1, -1, -1, -1, 0, -1};
5021     const DWORD exp_point_rep3[] = {0, 1, 2, 3, 1, 0};
5022     /* mesh4 (below, tip against tip)
5023      *
5024      * 0--1
5025      * | /
5026      * |/
5027      * 2
5028      * 3
5029      * |\
5030      * | \
5031      * 5--4
5032      */
5033     struct vertex_pnc vertices4[] =
5034     {
5035         {{ 0.0f,  3.0f,  0.f}, up, RED},
5036         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5037         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5038
5039         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5040         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5041         {{ 0.0f, -7.0f,  0.f}, up, RED},
5042     };
5043     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5044     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5045     const unsigned int num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
5046     const DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
5047     const DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
5048     /* mesh5 (gap in mesh)
5049      *
5050      *    0      3-----4  15
5051      *   / \      \   /  /  \
5052      *  /   \      \ /  /    \
5053      * 2-----1      5 17-----16
5054      * 6-----7      9 12-----13
5055      *  \   /      / \  \    /
5056      *   \ /      /   \  \  /
5057      *    8     10-----11 14
5058      *
5059      */
5060     const struct vertex_pnc vertices5[] =
5061     {
5062         {{ 0.0f,  1.0f,  0.f}, up, RED},
5063         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5064         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5065
5066         {{ 0.1f,  1.0f,  0.f}, up, RED},
5067         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5068         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5069
5070         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5071         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5072         {{ 0.0f, -3.1f,  0.f}, up, RED},
5073
5074         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5075         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5076         {{ 0.1f, -3.1f,  0.f}, up, RED},
5077
5078         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5079         {{ 3.2f, -1.1f,  0.f}, up, RED},
5080         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5081
5082         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5083         {{ 3.2f, -1.0f,  0.f}, up, RED},
5084         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5085     };
5086     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5087     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5088     const unsigned int num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
5089     const DWORD adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5090     const DWORD exp_point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5091     const WORD indices5_16bit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5092     /* mesh6 (indices re-ordering)
5093      *
5094      * 0--1 6 3
5095      * | / /| |\
5096      * |/ / | | \
5097      * 2 8--7 5--4
5098      */
5099     const struct vertex_pnc vertices6[] =
5100     {
5101         {{ 0.0f,  3.0f,  0.f}, up, RED},
5102         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5103         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5104
5105         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5106         {{ 3.0f,  0.0f,  0.f}, up, RED},
5107         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5108
5109         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5110         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5111         {{ 4.0f,  0.0f,  0.f}, up, RED},
5112     };
5113     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5114     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5115     const unsigned int num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
5116     const DWORD adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5117     const DWORD exp_point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5118     /* mesh7 (expands collapsed triangle)
5119      *
5120      * 0--1 3
5121      * | / /|
5122      * |/ / |
5123      * 2 5--4
5124      */
5125     const struct vertex_pnc vertices7[] =
5126     {
5127         {{ 0.0f,  3.0f,  0.f}, up, RED},
5128         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5129         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5130
5131         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5132         {{ 3.0f,  0.0f,  0.f}, up, RED},
5133         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5134     };
5135     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5136     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5137     const unsigned int num_faces7 = ARRAY_SIZE(indices7) / VERTS_PER_FACE;
5138     const DWORD adjacency7[] = {-1, -1, -1, -1, -1, -1};
5139     const DWORD exp_point_rep7[] = {0, 1, 2, 3, 4, 5};
5140     /* mesh8 (indices re-ordering and double replacement)
5141      *
5142      * 0--1 9  6
5143      * | / /|  |\
5144      * |/ / |  | \
5145      * 2 11-10 8--7
5146      *         3--4
5147      *         | /
5148      *         |/
5149      *         5
5150      */
5151     const struct vertex_pnc vertices8[] =
5152     {
5153         {{ 0.0f,  3.0f,  0.f}, up, RED},
5154         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5155         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5156
5157         {{ 4.0,  -4.0,  0.f}, up, RED},
5158         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5159         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5160
5161         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5162         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5163         {{ 4.0f,  0.0f,  0.f}, up, RED},
5164
5165         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5166         {{ 3.0f,  0.0f,  0.f}, up, RED},
5167         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5168     };
5169     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5170     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5171     const unsigned int num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
5172     const DWORD adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5173     const DWORD exp_point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5174     /* mesh9 (right, shared vertices)
5175      *
5176      * 0--1
5177      * | /|
5178      * |/ |
5179      * 2--3
5180      */
5181     const struct vertex_pnc vertices9[] =
5182     {
5183         {{ 0.0f,  3.0f,  0.f}, up, RED},
5184         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5185         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5186
5187         {{ 2.0f,  0.0f,  0.f}, up, RED},
5188     };
5189     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5190     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5191     const unsigned int num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
5192     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
5193     const DWORD exp_point_rep9[] = {0, 1, 2, 3};
5194     /* All mesh data */
5195     ID3DXMesh *mesh = NULL;
5196     ID3DXMesh *mesh_null_check = NULL;
5197     unsigned int attributes[] = {0};
5198     struct
5199     {
5200         const struct vertex_pnc *vertices;
5201         const DWORD *indices;
5202         const DWORD num_vertices;
5203         const DWORD num_faces;
5204         const DWORD *adjacency;
5205         const DWORD *exp_point_reps;
5206         const DWORD options;
5207     }
5208     tc[] =
5209     {
5210         {
5211             vertices0,
5212             indices0,
5213             num_vertices0,
5214             num_faces0,
5215             adjacency0,
5216             exp_point_rep0,
5217             options
5218         },
5219         {
5220             vertices1,
5221             indices1,
5222             num_vertices1,
5223             num_faces1,
5224             adjacency1,
5225             exp_point_rep1,
5226             options
5227         },
5228         {
5229             vertices2,
5230             indices2,
5231             num_vertices2,
5232             num_faces2,
5233             adjacency2,
5234             exp_point_rep2,
5235             options
5236         },
5237         {
5238             vertices3,
5239             indices3,
5240             num_vertices3,
5241             num_faces3,
5242             adjacency3,
5243             exp_point_rep3,
5244             options
5245         },
5246         {
5247             vertices4,
5248             indices4,
5249             num_vertices4,
5250             num_faces4,
5251             adjacency4,
5252             exp_point_rep4,
5253             options
5254         },
5255         {
5256             vertices5,
5257             indices5,
5258             num_vertices5,
5259             num_faces5,
5260             adjacency5,
5261             exp_point_rep5,
5262             options
5263         },
5264         {
5265             vertices6,
5266             indices6,
5267             num_vertices6,
5268             num_faces6,
5269             adjacency6,
5270             exp_point_rep6,
5271             options
5272         },
5273         {
5274             vertices7,
5275             indices7,
5276             num_vertices7,
5277             num_faces7,
5278             adjacency7,
5279             exp_point_rep7,
5280             options
5281         },
5282         {
5283             vertices8,
5284             indices8,
5285             num_vertices8,
5286             num_faces8,
5287             adjacency8,
5288             exp_point_rep8,
5289             options
5290         },
5291         {
5292             vertices9,
5293             indices9,
5294             num_vertices9,
5295             num_faces9,
5296             adjacency9,
5297             exp_point_rep9,
5298             options
5299         },
5300         {
5301             vertices5,
5302             (DWORD*)indices5_16bit,
5303             num_vertices5,
5304             num_faces5,
5305             adjacency5,
5306             exp_point_rep5,
5307             options_16bit
5308         },
5309     };
5310     DWORD *point_reps = NULL;
5311
5312     test_context = new_test_context();
5313     if (!test_context)
5314     {
5315         skip("Couldn't create test context\n");
5316         goto cleanup;
5317     }
5318
5319     for (i = 0; i < ARRAY_SIZE(tc); i++)
5320     {
5321         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options, declaration,
5322                             test_context->device, &mesh);
5323         if (FAILED(hr))
5324         {
5325             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5326             goto cleanup;
5327         }
5328
5329         if (i == 0) /* Save first mesh for later NULL checks */
5330             mesh_null_check = mesh;
5331
5332         point_reps = HeapAlloc(GetProcessHeap(), 0, tc[i].num_vertices * sizeof(*point_reps));
5333         if (!point_reps)
5334         {
5335             skip("Couldn't allocate point reps array.\n");
5336             goto cleanup;
5337         }
5338
5339         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5340         if (FAILED(hr))
5341         {
5342             skip("Couldn't lock vertex buffer.\n");
5343             goto cleanup;
5344         }
5345         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5346         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5347         if (FAILED(hr))
5348         {
5349             skip("Couldn't unlock vertex buffer.\n");
5350             goto cleanup;
5351         }
5352
5353         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5354         if (FAILED(hr))
5355         {
5356             skip("Couldn't lock index buffer.\n");
5357             goto cleanup;
5358         }
5359         if (tc[i].options & D3DXMESH_32BIT)
5360         {
5361             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5362         }
5363         else
5364         {
5365             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5366         }
5367         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5368         if (FAILED(hr)) {
5369             skip("Couldn't unlock index buffer.\n");
5370             goto cleanup;
5371         }
5372
5373         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5374         if (FAILED(hr))
5375         {
5376             skip("Couldn't lock attributes buffer.\n");
5377             goto cleanup;
5378         }
5379         memcpy(attributes_buffer, attributes, sizeof(attributes));
5380         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5381         if (FAILED(hr))
5382         {
5383             skip("Couldn't unlock attributes buffer.\n");
5384             goto cleanup;
5385         }
5386
5387         /* Convert adjacency to point representation */
5388         for (j = 0; j < tc[i].num_vertices; j++) point_reps[j] = -1;
5389         hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacency, point_reps);
5390         ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
5391            "Got %x expected D3D_OK\n", i, hr);
5392
5393         /* Check point representation */
5394         for (j = 0; j < tc[i].num_vertices; j++)
5395         {
5396             ok(point_reps[j] == tc[i].exp_point_reps[j],
5397                "Unexpected point representation at (%d, %d)."
5398                " Got %d expected %d\n",
5399                i, j, point_reps[j], tc[i].exp_point_reps[j]);
5400         }
5401
5402         HeapFree(GetProcessHeap(), 0, point_reps);
5403         point_reps = NULL;
5404
5405         if (i != 0) /* First mesh will be freed during cleanup */
5406             mesh->lpVtbl->Release(mesh);
5407     }
5408
5409     /* NULL checks */
5410     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacency, NULL);
5411     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
5412        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5413     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, NULL);
5414     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. "
5415        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5416
5417 cleanup:
5418     if (mesh_null_check)
5419         mesh_null_check->lpVtbl->Release(mesh_null_check);
5420     HeapFree(GetProcessHeap(), 0, point_reps);
5421     free_test_context(test_context);
5422 }
5423
5424 static void test_convert_point_reps_to_adjacency(void)
5425 {
5426     HRESULT hr;
5427     struct test_context *test_context = NULL;
5428     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5429     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5430     const D3DVERTEXELEMENT9 declaration[] =
5431     {
5432         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5433         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5434         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5435         D3DDECL_END()
5436     };
5437     const unsigned int VERTS_PER_FACE = 3;
5438     void *vertex_buffer;
5439     void *index_buffer;
5440     DWORD *attributes_buffer;
5441     int i, j;
5442     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5443     struct vertex_pnc
5444     {
5445         D3DXVECTOR3 position;
5446         D3DXVECTOR3 normal;
5447         enum color color; /* In case of manual visual inspection */
5448     };
5449     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5450     /* mesh0 (one face)
5451      *
5452      * 0--1
5453      * | /
5454      * |/
5455      * 2
5456      */
5457     const struct vertex_pnc vertices0[] =
5458     {
5459         {{ 0.0f,  3.0f,  0.f}, up, RED},
5460         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5461         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5462     };
5463     const DWORD indices0[] = {0, 1, 2};
5464     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5465     const unsigned int num_faces0 = num_vertices0 / VERTS_PER_FACE;
5466     const DWORD exp_adjacency0[] = {-1, -1, -1};
5467     const DWORD exp_id_adjacency0[] = {-1, -1, -1};
5468     const DWORD point_rep0[] = {0, 1, 2};
5469     /* mesh1 (right)
5470      *
5471      * 0--1 3
5472      * | / /|
5473      * |/ / |
5474      * 2 5--4
5475      */
5476     const struct vertex_pnc vertices1[] =
5477     {
5478         {{ 0.0f,  3.0f,  0.f}, up, RED},
5479         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5480         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5481
5482         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5483         {{ 3.0f,  0.0f,  0.f}, up, RED},
5484         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5485     };
5486     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5487     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5488     const unsigned int num_faces1 = num_vertices1 / VERTS_PER_FACE;
5489     const DWORD exp_adjacency1[] = {-1, 1, -1, -1, -1, 0};
5490     const DWORD exp_id_adjacency1[] = {-1, -1, -1, -1, -1, -1};
5491     const DWORD point_rep1[] = {0, 1, 2, 1, 4, 2};
5492     /* mesh2 (left)
5493      *
5494      *    3 0--1
5495      *   /| | /
5496      *  / | |/
5497      * 5--4 2
5498      */
5499     const struct vertex_pnc vertices2[] =
5500     {
5501         {{ 0.0f,  3.0f,  0.f}, up, RED},
5502         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5503         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5504
5505         {{-1.0f,  3.0f,  0.f}, up, RED},
5506         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5507         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5508     };
5509     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5510     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5511     const unsigned int num_faces2 = num_vertices2 / VERTS_PER_FACE;
5512     const DWORD exp_adjacency2[] = {-1, -1, 1, 0, -1, -1};
5513     const DWORD exp_id_adjacency2[] = {-1, -1, -1, -1, -1, -1};
5514     const DWORD point_rep2[] = {0, 1, 2, 0, 2, 5};
5515     /* mesh3 (above)
5516      *
5517      *    3
5518      *   /|
5519      *  / |
5520      * 5--4
5521      * 0--1
5522      * | /
5523      * |/
5524      * 2
5525      */
5526     struct vertex_pnc vertices3[] =
5527     {
5528         {{ 0.0f,  3.0f,  0.f}, up, RED},
5529         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5530         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5531
5532         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5533         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5534         {{ 0.0f,  4.0f,  0.f}, up, RED},
5535     };
5536     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5537     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5538     const unsigned int num_faces3 = num_vertices3 / VERTS_PER_FACE;
5539     const DWORD exp_adjacency3[] = {1, -1, -1, -1, 0, -1};
5540     const DWORD exp_id_adjacency3[] = {-1, -1, -1, -1, -1, -1};
5541     const DWORD point_rep3[] = {0, 1, 2, 3, 1, 0};
5542     /* mesh4 (below, tip against tip)
5543      *
5544      * 0--1
5545      * | /
5546      * |/
5547      * 2
5548      * 3
5549      * |\
5550      * | \
5551      * 5--4
5552      */
5553     struct vertex_pnc vertices4[] =
5554     {
5555         {{ 0.0f,  3.0f,  0.f}, up, RED},
5556         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5557         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5558
5559         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5560         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5561         {{ 0.0f, -7.0f,  0.f}, up, RED},
5562     };
5563     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5564     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5565     const unsigned int num_faces4 = num_vertices4 / VERTS_PER_FACE;
5566     const DWORD exp_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5567     const DWORD exp_id_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5568     const DWORD point_rep4[] = {0, 1, 2, 3, 4, 5};
5569     /* mesh5 (gap in mesh)
5570      *
5571      *    0      3-----4  15
5572      *   / \      \   /  /  \
5573      *  /   \      \ /  /    \
5574      * 2-----1      5 17-----16
5575      * 6-----7      9 12-----13
5576      *  \   /      / \  \    /
5577      *   \ /      /   \  \  /
5578      *    8     10-----11 14
5579      *
5580      */
5581     const struct vertex_pnc vertices5[] =
5582     {
5583         {{ 0.0f,  1.0f,  0.f}, up, RED},
5584         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5585         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5586
5587         {{ 0.1f,  1.0f,  0.f}, up, RED},
5588         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5589         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5590
5591         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5592         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5593         {{ 0.0f, -3.1f,  0.f}, up, RED},
5594
5595         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5596         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5597         {{ 0.1f, -3.1f,  0.f}, up, RED},
5598
5599         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5600         {{ 3.2f, -1.1f,  0.f}, up, RED},
5601         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5602
5603         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5604         {{ 3.2f, -1.0f,  0.f}, up, RED},
5605         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5606     };
5607     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5608     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5609     const unsigned int num_faces5 = num_vertices5 / VERTS_PER_FACE;
5610     const DWORD exp_adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5611     const DWORD exp_id_adjacency5[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5612     const DWORD point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5613     /* mesh6 (indices re-ordering)
5614      *
5615      * 0--1 6 3
5616      * | / /| |\
5617      * |/ / | | \
5618      * 2 8--7 5--4
5619      */
5620     const struct vertex_pnc vertices6[] =
5621     {
5622         {{ 0.0f,  3.0f,  0.f}, up, RED},
5623         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5624         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5625
5626         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5627         {{ 3.0f,  0.0f,  0.f}, up, RED},
5628         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5629
5630         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5631         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5632         {{ 4.0f,  0.0f,  0.f}, up, RED},
5633     };
5634     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5635     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5636     const unsigned int num_faces6 = num_vertices6 / VERTS_PER_FACE;
5637     const DWORD exp_adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5638     const DWORD exp_id_adjacency6[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1};
5639     const DWORD point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5640     /* mesh7 (expands collapsed triangle)
5641      *
5642      * 0--1 3
5643      * | / /|
5644      * |/ / |
5645      * 2 5--4
5646      */
5647     const struct vertex_pnc vertices7[] =
5648     {
5649         {{ 0.0f,  3.0f,  0.f}, up, RED},
5650         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5651         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5652
5653         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5654         {{ 3.0f,  0.0f,  0.f}, up, RED},
5655         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5656     };
5657     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5658     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5659     const unsigned int num_faces7 = num_vertices7 / VERTS_PER_FACE;
5660     const DWORD exp_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5661     const DWORD exp_id_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5662     const DWORD point_rep7[] = {0, 1, 2, 3, 4, 5};
5663     /* mesh8 (indices re-ordering and double replacement)
5664      *
5665      * 0--1 9  6
5666      * | / /|  |\
5667      * |/ / |  | \
5668      * 2 11-10 8--7
5669      *         3--4
5670      *         | /
5671      *         |/
5672      *         5
5673      */
5674     const struct vertex_pnc vertices8[] =
5675     {
5676         {{ 0.0f,  3.0f,  0.f}, up, RED},
5677         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5678         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5679
5680         {{ 4.0,  -4.0,  0.f}, up, RED},
5681         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5682         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5683
5684         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5685         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5686         {{ 4.0f,  0.0f,  0.f}, up, RED},
5687
5688         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5689         {{ 3.0f,  0.0f,  0.f}, up, RED},
5690         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5691     };
5692     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5693     const WORD indices8_16bit[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5694     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5695     const unsigned int num_faces8 = num_vertices8 / VERTS_PER_FACE;
5696     const DWORD exp_adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5697     const DWORD exp_id_adjacency8[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5698     const DWORD point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5699      /* mesh9 (right, shared vertices)
5700      *
5701      * 0--1
5702      * | /|
5703      * |/ |
5704      * 2--3
5705      */
5706     const struct vertex_pnc vertices9[] =
5707     {
5708         {{ 0.0f,  3.0f,  0.f}, up, RED},
5709         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5710         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5711
5712         {{ 2.0f,  0.0f,  0.f}, up, RED},
5713     };
5714     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5715     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5716     const unsigned int num_faces9 = 2;
5717     const DWORD exp_adjacency9[] = {-1, 1, -1, -1, -1, 0};
5718     const DWORD exp_id_adjacency9[] = {-1, 1, -1, -1, -1, 0};
5719     const DWORD point_rep9[] = {0, 1, 2, 3};
5720     /* All mesh data */
5721     ID3DXMesh *mesh = NULL;
5722     ID3DXMesh *mesh_null_check = NULL;
5723     unsigned int attributes[] = {0};
5724     struct
5725     {
5726         const struct vertex_pnc *vertices;
5727         const DWORD *indices;
5728         const DWORD num_vertices;
5729         const DWORD num_faces;
5730         const DWORD *point_reps;
5731         const DWORD *exp_adjacency;
5732         const DWORD *exp_id_adjacency;
5733         const DWORD options;
5734     }
5735     tc[] =
5736     {
5737         {
5738             vertices0,
5739             indices0,
5740             num_vertices0,
5741             num_faces0,
5742             point_rep0,
5743             exp_adjacency0,
5744             exp_id_adjacency0,
5745             options
5746         },
5747         {
5748             vertices1,
5749             indices1,
5750             num_vertices1,
5751             num_faces1,
5752             point_rep1,
5753             exp_adjacency1,
5754             exp_id_adjacency1,
5755             options
5756         },
5757         {
5758             vertices2,
5759             indices2,
5760             num_vertices2,
5761             num_faces2,
5762             point_rep2,
5763             exp_adjacency2,
5764             exp_id_adjacency2,
5765             options
5766         },
5767         {
5768             vertices3,
5769             indices3,
5770             num_vertices3,
5771             num_faces3,
5772             point_rep3,
5773             exp_adjacency3,
5774             exp_id_adjacency3,
5775             options
5776         },
5777         {
5778             vertices4,
5779             indices4,
5780             num_vertices4,
5781             num_faces4,
5782             point_rep4,
5783             exp_adjacency4,
5784             exp_id_adjacency4,
5785             options
5786         },
5787         {
5788             vertices5,
5789             indices5,
5790             num_vertices5,
5791             num_faces5,
5792             point_rep5,
5793             exp_adjacency5,
5794             exp_id_adjacency5,
5795             options
5796         },
5797         {
5798             vertices6,
5799             indices6,
5800             num_vertices6,
5801             num_faces6,
5802             point_rep6,
5803             exp_adjacency6,
5804             exp_id_adjacency6,
5805             options
5806         },
5807         {
5808             vertices7,
5809             indices7,
5810             num_vertices7,
5811             num_faces7,
5812             point_rep7,
5813             exp_adjacency7,
5814             exp_id_adjacency7,
5815             options
5816         },
5817         {
5818             vertices8,
5819             indices8,
5820             num_vertices8,
5821             num_faces8,
5822             point_rep8,
5823             exp_adjacency8,
5824             exp_id_adjacency8,
5825             options
5826         },
5827         {
5828             vertices9,
5829             indices9,
5830             num_vertices9,
5831             num_faces9,
5832             point_rep9,
5833             exp_adjacency9,
5834             exp_id_adjacency9,
5835             options
5836         },
5837         {
5838             vertices8,
5839             (DWORD*)indices8_16bit,
5840             num_vertices8,
5841             num_faces8,
5842             point_rep8,
5843             exp_adjacency8,
5844             exp_id_adjacency8,
5845             options_16bit
5846         },
5847     };
5848     DWORD *adjacency = NULL;
5849
5850     test_context = new_test_context();
5851     if (!test_context)
5852     {
5853         skip("Couldn't create test context\n");
5854         goto cleanup;
5855     }
5856
5857     for (i = 0; i < ARRAY_SIZE(tc); i++)
5858     {
5859         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
5860                             declaration, test_context->device, &mesh);
5861         if (FAILED(hr))
5862         {
5863             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5864             goto cleanup;
5865         }
5866
5867         if (i == 0) /* Save first mesh for later NULL checks */
5868             mesh_null_check = mesh;
5869
5870         adjacency = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
5871         if (!adjacency)
5872         {
5873             skip("Couldn't allocate adjacency array.\n");
5874             goto cleanup;
5875         }
5876
5877         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5878         if (FAILED(hr))
5879         {
5880             skip("Couldn't lock vertex buffer.\n");
5881             goto cleanup;
5882         }
5883         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5884         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5885         if (FAILED(hr))
5886         {
5887             skip("Couldn't unlock vertex buffer.\n");
5888             goto cleanup;
5889         }
5890         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5891         if (FAILED(hr))
5892         {
5893             skip("Couldn't lock index buffer.\n");
5894             goto cleanup;
5895         }
5896         if (tc[i].options & D3DXMESH_32BIT)
5897         {
5898             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5899         }
5900         else
5901         {
5902             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5903         }
5904         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5905         if (FAILED(hr)) {
5906             skip("Couldn't unlock index buffer.\n");
5907             goto cleanup;
5908         }
5909
5910         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5911         if (FAILED(hr))
5912         {
5913             skip("Couldn't lock attributes buffer.\n");
5914             goto cleanup;
5915         }
5916         memcpy(attributes_buffer, attributes, sizeof(attributes));
5917         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5918         if (FAILED(hr))
5919         {
5920             skip("Couldn't unlock attributes buffer.\n");
5921             goto cleanup;
5922         }
5923
5924         /* Convert point representation to adjacency*/
5925         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
5926
5927         hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
5928         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
5929            "Got %x expected D3D_OK\n", i, hr);
5930         /* Check adjacency */
5931         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
5932         {
5933             ok(adjacency[j] == tc[i].exp_adjacency[j],
5934                "Unexpected adjacency information at (%d, %d)."
5935                " Got %d expected %d\n",
5936                i, j, adjacency[j], tc[i].exp_adjacency[j]);
5937         }
5938
5939         /* NULL point representation is considered identity. */
5940         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
5941         hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
5942         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
5943                      "Got %x expected D3D_OK\n", hr);
5944         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
5945         {
5946             ok(adjacency[j] == tc[i].exp_id_adjacency[j],
5947                "Unexpected adjacency information (id) at (%d, %d)."
5948                " Got %d expected %d\n",
5949                i, j, adjacency[j], tc[i].exp_id_adjacency[j]);
5950         }
5951
5952         HeapFree(GetProcessHeap(), 0, adjacency);
5953         adjacency = NULL;
5954         if (i != 0) /* First mesh will be freed during cleanup */
5955             mesh->lpVtbl->Release(mesh);
5956     }
5957
5958     /* NULL checks */
5959     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
5960     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
5961        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5962     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
5963     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
5964        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5965
5966 cleanup:
5967     if (mesh_null_check)
5968         mesh_null_check->lpVtbl->Release(mesh_null_check);
5969     HeapFree(GetProcessHeap(), 0, adjacency);
5970     free_test_context(test_context);
5971 }
5972
5973 static HRESULT init_test_mesh(const DWORD num_faces, const DWORD num_vertices,
5974                               const DWORD options,
5975                               const D3DVERTEXELEMENT9 *declaration,
5976                               IDirect3DDevice9 *device, ID3DXMesh **mesh_ptr,
5977                               const void *vertices, const DWORD vertex_size,
5978                               const DWORD *indices, const DWORD *attributes)
5979 {
5980     HRESULT hr;
5981     void *vertex_buffer;
5982     void *index_buffer;
5983     DWORD *attributes_buffer;
5984     ID3DXMesh *mesh = NULL;
5985
5986     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration, device, mesh_ptr);
5987     if (FAILED(hr))
5988     {
5989         skip("Couldn't create mesh. Got %x expected D3D_OK\n", hr);
5990         goto cleanup;
5991     }
5992     mesh = *mesh_ptr;
5993
5994     hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5995     if (FAILED(hr))
5996     {
5997         skip("Couldn't lock vertex buffer.\n");
5998         goto cleanup;
5999     }
6000     memcpy(vertex_buffer, vertices, num_vertices * vertex_size);
6001     hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6002     if (FAILED(hr))
6003     {
6004         skip("Couldn't unlock vertex buffer.\n");
6005         goto cleanup;
6006     }
6007
6008     hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6009     if (FAILED(hr))
6010     {
6011         skip("Couldn't lock index buffer.\n");
6012         goto cleanup;
6013     }
6014     if (options & D3DXMESH_32BIT)
6015     {
6016         if (indices)
6017             memcpy(index_buffer, indices, 3 * num_faces * sizeof(DWORD));
6018         else
6019         {
6020             /* Fill index buffer with 0, 1, 2, ...*/
6021             DWORD *indices_32bit = (DWORD*)index_buffer;
6022             UINT i;
6023             for (i = 0; i < 3 * num_faces; i++)
6024                 indices_32bit[i] = i;
6025         }
6026     }
6027     else
6028     {
6029         if (indices)
6030             memcpy(index_buffer, indices, 3 * num_faces * sizeof(WORD));
6031         else
6032         {
6033             /* Fill index buffer with 0, 1, 2, ...*/
6034             WORD *indices_16bit = (WORD*)index_buffer;
6035             UINT i;
6036             for (i = 0; i < 3 * num_faces; i++)
6037                 indices_16bit[i] = i;
6038         }
6039     }
6040     hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6041     if (FAILED(hr)) {
6042         skip("Couldn't unlock index buffer.\n");
6043         goto cleanup;
6044     }
6045
6046     hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6047     if (FAILED(hr))
6048     {
6049         skip("Couldn't lock attributes buffer.\n");
6050         goto cleanup;
6051     }
6052
6053     if (attributes)
6054         memcpy(attributes_buffer, attributes, num_faces * sizeof(*attributes));
6055     else
6056         memset(attributes_buffer, 0, num_faces * sizeof(*attributes));
6057
6058     hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6059     if (FAILED(hr))
6060     {
6061         skip("Couldn't unlock attributes buffer.\n");
6062         goto cleanup;
6063     }
6064
6065     hr = D3D_OK;
6066 cleanup:
6067     return hr;
6068 }
6069
6070 /* Using structs instead of bit-fields in order to avoid compiler issues. */
6071 struct udec3
6072 {
6073     UINT x;
6074     UINT y;
6075     UINT z;
6076     UINT w;
6077 };
6078
6079 struct dec3n
6080 {
6081     INT x;
6082     INT y;
6083     INT z;
6084     INT w;
6085 };
6086
6087 static DWORD init_udec3_dword(UINT x, UINT y, UINT z, UINT w)
6088 {
6089     DWORD d = 0;
6090
6091     d |= x & 0x3ff;
6092     d |= (y << 10) & 0xffc00;
6093     d |= (z << 20) & 0x3ff00000;
6094     d |= (w << 30) & 0xc0000000;
6095
6096     return d;
6097 }
6098
6099 static DWORD init_dec3n_dword(INT x, INT y, INT z, INT w)
6100 {
6101     DWORD d = 0;
6102
6103     d |= x & 0x3ff;
6104     d |= (y << 10) & 0xffc00;
6105     d |= (z << 20) & 0x3ff00000;
6106     d |= (w << 30) & 0xc0000000;
6107
6108     return d;
6109 }
6110
6111 static struct udec3 dword_to_udec3(DWORD d)
6112 {
6113     struct udec3 v;
6114
6115     v.x = d & 0x3ff;
6116     v.y = (d & 0xffc00) >> 10;
6117     v.z = (d & 0x3ff00000) >> 20;
6118     v.w = (d & 0xc0000000) >> 30;
6119
6120     return v;
6121 }
6122
6123 static struct dec3n dword_to_dec3n(DWORD d)
6124 {
6125     struct dec3n v;
6126
6127     v.x = d & 0x3ff;
6128     v.y = (d & 0xffc00) >> 10;
6129     v.z = (d & 0x3ff00000) >> 20;
6130     v.w = (d & 0xc0000000) >> 30;
6131
6132     return v;
6133 }
6134
6135 static void check_vertex_components(int line, int mesh_number, int vertex_number, BYTE *got_ptr, const BYTE *exp_ptr, D3DVERTEXELEMENT9 *declaration)
6136 {
6137     const char *usage_strings[] =
6138     {
6139         "position",
6140         "blend weight",
6141         "blend indices",
6142         "normal",
6143         "point size",
6144         "texture coordinates",
6145         "tangent",
6146         "binormal",
6147         "tessellation factor",
6148         "position transformed",
6149         "color",
6150         "fog",
6151         "depth",
6152         "sample"
6153     };
6154     D3DVERTEXELEMENT9 *decl_ptr;
6155     const float PRECISION = 1e-5f;
6156
6157     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
6158     {
6159         switch (decl_ptr->Type)
6160         {
6161             case D3DDECLTYPE_FLOAT1:
6162             {
6163                 FLOAT *got = (FLOAT*)(got_ptr + decl_ptr->Offset);
6164                 FLOAT *exp = (FLOAT*)(exp_ptr + decl_ptr->Offset);
6165                 FLOAT diff = fabsf(*got - *exp);
6166                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got %f for vertex %d %s, expected %f.\n",
6167                     mesh_number, *got, vertex_number, usage_strings[decl_ptr->Usage], *exp);
6168                 break;
6169             }
6170             case D3DDECLTYPE_FLOAT2:
6171             {
6172                 D3DXVECTOR2 *got = (D3DXVECTOR2*)(got_ptr + decl_ptr->Offset);
6173                 D3DXVECTOR2 *exp = (D3DXVECTOR2*)(exp_ptr + decl_ptr->Offset);
6174                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6175                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f) for vertex %d %s, expected (%f, %f).\n",
6176                     mesh_number, got->x, got->y, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y);
6177                 break;
6178             }
6179             case D3DDECLTYPE_FLOAT3:
6180             {
6181                 D3DXVECTOR3 *got = (D3DXVECTOR3*)(got_ptr + decl_ptr->Offset);
6182                 D3DXVECTOR3 *exp = (D3DXVECTOR3*)(exp_ptr + decl_ptr->Offset);
6183                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6184                 diff = max(diff, fabsf(got->z - exp->z));
6185                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f) for vertex %d %s, expected (%f, %f, %f).\n",
6186                     mesh_number, got->x, got->y, got->z, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y, exp->z);
6187                 break;
6188             }
6189             case D3DDECLTYPE_FLOAT4:
6190             {
6191                 D3DXVECTOR4 *got = (D3DXVECTOR4*)(got_ptr + decl_ptr->Offset);
6192                 D3DXVECTOR4 *exp = (D3DXVECTOR4*)(exp_ptr + decl_ptr->Offset);
6193                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6194                 diff = max(diff, fabsf(got->z - exp->z));
6195                 diff = max(diff, fabsf(got->w - exp->w));
6196                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f, %f) for vertex %d %s, expected (%f, %f, %f, %f).\n",
6197                     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);
6198                 break;
6199             }
6200             case D3DDECLTYPE_D3DCOLOR:
6201             {
6202                 BYTE *got = got_ptr + decl_ptr->Offset;
6203                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6204                 BOOL same_color = got[0] == exp[0] && got[1] == exp[1]
6205                                   && got[2] == exp[2] && got[3] == exp[3];
6206                 const char *color_types[] = {"diffuse", "specular", "undefined color"};
6207                 BYTE usage_index = decl_ptr->UsageIndex;
6208                 if (usage_index > 1) usage_index = 2;
6209                 ok_(__FILE__,line)(same_color, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6210                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, color_types[usage_index], exp[0], exp[1], exp[2], exp[3]);
6211                 break;
6212             }
6213             case D3DDECLTYPE_UBYTE4:
6214             case D3DDECLTYPE_UBYTE4N:
6215             {
6216                 BYTE *got = got_ptr + decl_ptr->Offset;
6217                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6218                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6219                             && got[2] == exp[2] && got[3] == exp[3];
6220                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6221                     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]);
6222                 break;
6223             }
6224             case D3DDECLTYPE_SHORT2:
6225             case D3DDECLTYPE_SHORT2N:
6226             {
6227                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6228                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6229                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6230                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd) for vertex %d %s, expected (%hd, %hd).\n",
6231                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6232                 break;
6233             }
6234             case D3DDECLTYPE_SHORT4:
6235             case D3DDECLTYPE_SHORT4N:
6236             {
6237                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6238                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6239                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6240                             && got[2] == exp[2] && got[3] == exp[3];
6241                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd, %hd, %hd) for vertex %d %s, expected (%hd, %hd, %hd, %hd).\n",
6242                     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]);
6243                 break;
6244             }
6245             case D3DDECLTYPE_USHORT2N:
6246             {
6247                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6248                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6249                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6250                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu) for vertex %d %s, expected (%hu, %hu).\n",
6251                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6252                 break;
6253             }
6254             case D3DDECLTYPE_USHORT4N:
6255             {
6256                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6257                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6258                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6259                             && got[2] == exp[2] && got[3] == exp[3];
6260                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu, %hu, %hu) for vertex %d %s, expected (%hu, %hu, %hu, %hu).\n",
6261                     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]);
6262                 break;
6263             }
6264             case D3DDECLTYPE_UDEC3:
6265             {
6266                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6267                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6268                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6269                 struct udec3 got_udec3 = dword_to_udec3(*got);
6270                 struct udec3 exp_udec3 = dword_to_udec3(*exp);
6271                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6272                     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);
6273
6274                 break;
6275             }
6276             case D3DDECLTYPE_DEC3N:
6277             {
6278                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6279                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6280                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6281                 struct dec3n got_dec3n = dword_to_dec3n(*got);
6282                 struct dec3n exp_dec3n = dword_to_dec3n(*exp);
6283                 ok_(__FILE__,line)(same, "Mesh %d: Got (%d, %d, %d, %d) for vertex %d %s, expected (%d, %d, %d, %d).\n",
6284                     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);
6285                 break;
6286             }
6287             case D3DDECLTYPE_FLOAT16_2:
6288             {
6289                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6290                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6291                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6292                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx) for vertex %d %s, expected (%hx, %hx).\n",
6293                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6294                 break;
6295             }
6296             case D3DDECLTYPE_FLOAT16_4:
6297             {
6298                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6299                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6300                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6301                             && got[2] == exp[2] && got[3] == exp[3];
6302                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx, %hx, %hx) for vertex %d %s, expected (%hx, %hx, %hx, %hx).\n",
6303                     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]);
6304                 break;
6305             }
6306             default:
6307                 break;
6308         }
6309     }
6310 }
6311
6312 static void test_weld_vertices(void)
6313 {
6314     HRESULT hr;
6315     struct test_context *test_context = NULL;
6316     DWORD i;
6317     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
6318     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
6319     BYTE *vertices = NULL;
6320     DWORD *indices = NULL;
6321     WORD *indices_16bit = NULL;
6322     const UINT VERTS_PER_FACE = 3;
6323     const D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
6324     struct vertex_normal
6325     {
6326         D3DXVECTOR3 position;
6327         D3DXVECTOR3 normal;
6328     };
6329     struct vertex_blendweight
6330     {
6331         D3DXVECTOR3 position;
6332         FLOAT blendweight;
6333     };
6334     struct vertex_texcoord
6335     {
6336         D3DXVECTOR3 position;
6337         D3DXVECTOR2 texcoord;
6338     };
6339     struct vertex_color
6340     {
6341         D3DXVECTOR3 position;
6342         DWORD color;
6343     };
6344     struct vertex_color_ubyte4
6345     {
6346         D3DXVECTOR3 position;
6347         BYTE color[4];
6348     };
6349     struct vertex_texcoord_short2
6350     {
6351         D3DXVECTOR3 position;
6352         SHORT texcoord[2];
6353     };
6354     struct vertex_texcoord_ushort2n
6355     {
6356         D3DXVECTOR3 position;
6357         USHORT texcoord[2];
6358     };
6359     struct vertex_normal_short4
6360     {
6361         D3DXVECTOR3 position;
6362         SHORT normal[4];
6363     };
6364     struct vertex_color_float4
6365     {
6366         D3DXVECTOR3 position;
6367         D3DXVECTOR4 color;
6368     };
6369     struct vertex_texcoord_float16_2
6370     {
6371         D3DXVECTOR3 position;
6372         WORD texcoord[2];
6373     };
6374     struct vertex_texcoord_float16_4
6375     {
6376         D3DXVECTOR3 position;
6377         WORD texcoord[4];
6378     };
6379     struct vertex_normal_udec3
6380     {
6381         D3DXVECTOR3 position;
6382         DWORD normal;
6383     };
6384     struct vertex_normal_dec3n
6385     {
6386         D3DXVECTOR3 position;
6387         DWORD normal;
6388     };
6389     UINT vertex_size_normal = sizeof(struct vertex_normal);
6390     UINT vertex_size_blendweight = sizeof(struct vertex_blendweight);
6391     UINT vertex_size_texcoord = sizeof(struct vertex_texcoord);
6392     UINT vertex_size_color = sizeof(struct vertex_color);
6393     UINT vertex_size_color_ubyte4 = sizeof(struct vertex_color_ubyte4);
6394     UINT vertex_size_texcoord_short2 = sizeof(struct vertex_texcoord_short2);
6395     UINT vertex_size_normal_short4 = sizeof(struct vertex_normal_short4);
6396     UINT vertex_size_color_float4 = sizeof(struct vertex_color_float4);
6397     UINT vertex_size_texcoord_float16_2 = sizeof(struct vertex_texcoord_float16_2);
6398     UINT vertex_size_texcoord_float16_4 = sizeof(struct vertex_texcoord_float16_4);
6399     UINT vertex_size_normal_udec3 = sizeof(struct vertex_normal_udec3);
6400     UINT vertex_size_normal_dec3n = sizeof(struct vertex_normal_dec3n);
6401     D3DVERTEXELEMENT9 declaration_normal[] =
6402     {
6403         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6404         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6405         D3DDECL_END()
6406     };
6407     D3DVERTEXELEMENT9 declaration_normal3[] =
6408     {
6409         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 3},
6410         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6411         D3DDECL_END()
6412     };
6413     D3DVERTEXELEMENT9 declaration_blendweight[] =
6414     {
6415         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6416         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
6417         D3DDECL_END()
6418     };
6419     D3DVERTEXELEMENT9 declaration_texcoord[] =
6420     {
6421         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6422         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6423         D3DDECL_END()
6424     };
6425     D3DVERTEXELEMENT9 declaration_color[] =
6426     {
6427         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6428         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6429         D3DDECL_END()
6430     };
6431     D3DVERTEXELEMENT9 declaration_color_ubyte4n[] =
6432     {
6433         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6434         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6435         D3DDECL_END()
6436     };
6437     D3DVERTEXELEMENT9 declaration_color_ubyte4[] =
6438     {
6439         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6440         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6441         D3DDECL_END()
6442     };
6443     D3DVERTEXELEMENT9 declaration_texcoord_short2[] =
6444     {
6445         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6446         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6447         D3DDECL_END()
6448     };
6449     D3DVERTEXELEMENT9 declaration_texcoord_short2n[] =
6450     {
6451         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6452         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6453         D3DDECL_END()
6454     };
6455     D3DVERTEXELEMENT9 declaration_texcoord_ushort2n[] =
6456     {
6457         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6458         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6459         D3DDECL_END()
6460     };
6461     D3DVERTEXELEMENT9 declaration_normal_short4[] =
6462     {
6463         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6464         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6465         D3DDECL_END()
6466     };
6467     D3DVERTEXELEMENT9 declaration_normal_short4n[] =
6468     {
6469         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6470         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6471         D3DDECL_END()
6472     };
6473     D3DVERTEXELEMENT9 declaration_normal_ushort4n[] =
6474     {
6475         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6476         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6477         D3DDECL_END()
6478     };
6479     D3DVERTEXELEMENT9 declaration_texcoord10[] =
6480     {
6481         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6482         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 10},
6483         D3DDECL_END()
6484     };
6485     D3DVERTEXELEMENT9 declaration_color2[] =
6486     {
6487         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6488         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
6489         D3DDECL_END()
6490     };
6491     D3DVERTEXELEMENT9 declaration_color2_float4[] =
6492     {
6493         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6494         {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
6495         D3DDECL_END()
6496     };
6497     D3DVERTEXELEMENT9 declaration_texcoord_float16_2[] =
6498     {
6499         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6500         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6501         D3DDECL_END()
6502     };
6503     D3DVERTEXELEMENT9 declaration_texcoord_float16_4[] =
6504     {
6505         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6506         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6507         D3DDECL_END()
6508     };
6509     D3DVERTEXELEMENT9 declaration_normal_udec3[] =
6510    {
6511         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6512         {0, 12, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6513         D3DDECL_END()
6514     };
6515     D3DVERTEXELEMENT9 declaration_normal_dec3n[] =
6516     {
6517         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6518         {0, 12, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6519         D3DDECL_END()
6520     };
6521     /* Test 0. One face and no welding.
6522      *
6523      * 0--1
6524      * | /
6525      * |/
6526      * 2
6527      */
6528     const struct vertex vertices0[] =
6529     {
6530         {{ 0.0f,  3.0f,  0.f}, up},
6531         {{ 2.0f,  3.0f,  0.f}, up},
6532         {{ 0.0f,  0.0f,  0.f}, up},
6533     };
6534     const DWORD indices0[] = {0, 1, 2};
6535     const DWORD attributes0[] = {0};
6536     const DWORD exp_indices0[] = {0, 1, 2};
6537     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
6538     const UINT num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
6539     const DWORD flags0 = D3DXWELDEPSILONS_WELDALL;
6540     /* epsilons0 is NULL */
6541     const DWORD adjacency0[] = {-1, -1, -1};
6542     const struct vertex exp_vertices0[] =
6543     {
6544         {{ 0.0f,  3.0f,  0.f}, up},
6545         {{ 2.0f,  3.0f,  0.f}, up},
6546         {{ 0.0f,  0.0f,  0.f}, up},
6547     };
6548     const DWORD exp_face_remap0[] = {0};
6549     const DWORD exp_vertex_remap0[] = {0, 1, 2};
6550     const DWORD exp_new_num_vertices0 = ARRAY_SIZE(exp_vertices0);
6551     /* Test 1. Two vertices should be removed without regard to epsilon.
6552      *
6553      * 0--1 3
6554      * | / /|
6555      * |/ / |
6556      * 2 5--4
6557      */
6558     const struct vertex_normal vertices1[] =
6559     {
6560         {{ 0.0f,  3.0f,  0.f}, up},
6561         {{ 2.0f,  3.0f,  0.f}, up},
6562         {{ 0.0f,  0.0f,  0.f}, up},
6563
6564         {{ 3.0f,  3.0f,  0.f}, up},
6565         {{ 3.0f,  0.0f,  0.f}, up},
6566         {{ 1.0f,  0.0f,  0.f}, up},
6567     };
6568     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
6569     const DWORD attributes1[] = {0, 0};
6570     const UINT num_vertices1 = ARRAY_SIZE(vertices1);
6571     const UINT num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
6572     const DWORD flags1 = D3DXWELDEPSILONS_WELDALL;
6573     /* epsilons1 is NULL */
6574     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
6575     const struct vertex_normal exp_vertices1[] =
6576     {
6577         {{ 0.0f,  3.0f,  0.f}, up},
6578         {{ 2.0f,  3.0f,  0.f}, up},
6579         {{ 0.0f,  0.0f,  0.f}, up},
6580
6581         {{ 3.0f,  0.0f,  0.f}, up}
6582     };
6583     const DWORD exp_indices1[] = {0, 1, 2, 1, 3, 2};
6584     const DWORD exp_face_remap1[] = {0, 1};
6585     const DWORD exp_vertex_remap1[] = {0, 1, 2, 4, -1, -1};
6586     const DWORD exp_new_num_vertices1 = ARRAY_SIZE(exp_vertices1);
6587     /* Test 2. Two faces. No vertices should be removed because of normal
6588      * epsilon, but the positions should be replaced. */
6589     const struct vertex_normal vertices2[] =
6590     {
6591         {{ 0.0f,  3.0f,  0.f}, up},
6592         {{ 2.0f,  3.0f,  0.f}, up},
6593         {{ 0.0f,  0.0f,  0.f}, up},
6594
6595         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6596         {{ 3.0f,  0.0f,  0.f}, up},
6597         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6598     };
6599     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
6600     const DWORD attributes2[] = {0, 0};
6601     const UINT num_vertices2 = ARRAY_SIZE(vertices2);
6602     const UINT num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
6603     DWORD flags2 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6604     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};
6605     const DWORD adjacency2[] = {-1, 1, -1, -1, -1, 0};
6606     const struct vertex_normal exp_vertices2[] =
6607     {
6608         {{ 0.0f,  3.0f,  0.f}, up},
6609         {{ 2.0f,  3.0f,  0.f}, up},
6610         {{ 0.0f,  0.0f,  0.f}, up},
6611
6612         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6613         {{ 3.0f,  0.0f,  0.f}, up},
6614         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6615     };
6616     const DWORD exp_indices2[] = {0, 1, 2, 3, 4, 5};
6617     const DWORD exp_face_remap2[] = {0, 1};
6618     const DWORD exp_vertex_remap2[] = {0, 1, 2, 3, 4, 5};
6619     const DWORD exp_new_num_vertices2 = ARRAY_SIZE(exp_vertices2);
6620     /* Test 3. Two faces. One vertex should be removed because of normal epsilon. */
6621     const struct vertex_normal vertices3[] =
6622     {
6623         {{ 0.0f,  3.0f,  0.f}, up},
6624         {{ 2.0f,  3.0f,  0.f}, up},
6625         {{ 0.0f,  0.0f,  0.f}, up},
6626
6627         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6628         {{ 3.0f,  0.0f,  0.f}, up},
6629         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6630     };
6631     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
6632     const DWORD attributes3[] = {0, 0};
6633     const UINT num_vertices3 = ARRAY_SIZE(vertices3);
6634     const UINT num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
6635     DWORD flags3 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6636     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};
6637     const DWORD adjacency3[] = {-1, 1, -1, -1, -1, 0};
6638     const struct vertex_normal exp_vertices3[] =
6639     {
6640         {{ 0.0f,  3.0f,  0.f}, up},
6641         {{ 2.0f,  3.0f,  0.f}, up},
6642         {{ 0.0f,  0.0f,  0.f}, up},
6643
6644         {{ 3.0f,  0.0f,  0.f}, up},
6645         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6646     };
6647     const DWORD exp_indices3[] = {0, 1, 2, 1, 3, 4};
6648     const DWORD exp_face_remap3[] = {0, 1};
6649     const DWORD exp_vertex_remap3[] = {0, 1, 2, 4, 5, -1};
6650     const DWORD exp_new_num_vertices3 = ARRAY_SIZE(exp_vertices3);
6651     /* Test 4  Two faces. Two vertices should be removed. */
6652     const struct vertex_normal vertices4[] =
6653     {
6654         {{ 0.0f,  3.0f,  0.f}, up},
6655         {{ 2.0f,  3.0f,  0.f}, up},
6656         {{ 0.0f,  0.0f,  0.f}, up},
6657
6658         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6659         {{ 3.0f,  0.0f,  0.f}, up},
6660         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6661     };
6662     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
6663     const DWORD attributes4[] = {0, 0};
6664     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
6665     const UINT num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
6666     DWORD flags4 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6667     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};
6668     const DWORD adjacency4[] = {-1, 1, -1, -1, -1, 0};
6669     const struct vertex_normal exp_vertices4[] =
6670     {
6671         {{ 0.0f,  3.0f,  0.f}, up},
6672         {{ 2.0f,  3.0f,  0.f}, up},
6673         {{ 0.0f,  0.0f,  0.f}, up},
6674
6675         {{ 3.0f,  0.0f,  0.f}, up},
6676     };
6677     const DWORD exp_indices4[] = {0, 1, 2, 1, 3, 2};
6678     const DWORD exp_face_remap4[] = {0, 1};
6679     const DWORD exp_vertex_remap4[] = {0, 1, 2, 4, -1, -1};
6680     const DWORD exp_new_num_vertices4 = ARRAY_SIZE(exp_vertices4);
6681     /* Test 5. Odd face ordering.
6682      *
6683      * 0--1 6 3
6684      * | / /| |\
6685      * |/ / | | \
6686      * 2 8--7 5--4
6687      */
6688     const struct vertex_normal vertices5[] =
6689     {
6690         {{ 0.0f,  3.0f,  0.f}, up},
6691         {{ 2.0f,  3.0f,  0.f}, up},
6692         {{ 0.0f,  0.0f,  0.f}, up},
6693
6694         {{ 3.0f,  3.0f,  0.f}, up},
6695         {{ 3.0f,  0.0f,  0.f}, up},
6696         {{ 1.0f,  0.0f,  0.f}, up},
6697
6698         {{ 4.0f,  3.0f,  0.f}, up},
6699         {{ 6.0f,  0.0f,  0.f}, up},
6700         {{ 4.0f,  0.0f,  0.f}, up},
6701     };
6702     const DWORD indices5[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
6703     const DWORD exp_indices5[] = {0, 1, 2, 1, 4, 2, 1, 3, 4};
6704     const DWORD attributes5[] = {0, 0, 0};
6705     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
6706     const UINT num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
6707     DWORD flags5 = D3DXWELDEPSILONS_WELDALL;
6708     const DWORD adjacency5[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
6709     const struct vertex_normal exp_vertices5[] =
6710     {
6711         {{ 0.0f,  3.0f,  0.f}, up},
6712         {{ 2.0f,  3.0f,  0.f}, up},
6713         {{ 0.0f,  0.0f,  0.f}, up},
6714
6715         {{ 3.0f,  0.0f,  0.f}, up},
6716         {{ 1.0f,  0.0f,  0.f}, up},
6717     };
6718     const DWORD exp_face_remap5[] = {0, 1, 2};
6719     const DWORD exp_vertex_remap5[] = {0, 1, 2, 4, 5, -1, -1, -1, -1};
6720     const DWORD exp_new_num_vertices5 = ARRAY_SIZE(exp_vertices5);
6721     /* Test 6. Two faces. Do not remove flag is used, so no vertices should be
6722      * removed. */
6723     const struct vertex_normal vertices6[] =
6724     {
6725         {{ 0.0f,  3.0f,  0.f}, up},
6726         {{ 2.0f,  3.0f,  0.f}, up},
6727         {{ 0.0f,  0.0f,  0.f}, up},
6728
6729         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6730         {{ 3.0f,  0.0f,  0.f}, up},
6731         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6732     };
6733     const DWORD indices6[] = {0, 1, 2, 3, 4, 5};
6734     const DWORD attributes6[] = {0, 0};
6735     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
6736     const UINT num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
6737     DWORD flags6 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTREMOVEVERTICES;
6738     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};
6739     const DWORD adjacency6[] = {-1, 1, -1, -1, -1, 0};
6740     const struct vertex_normal exp_vertices6[] =
6741     {
6742         {{ 0.0f,  3.0f,  0.f}, up},
6743         {{ 2.0f,  3.0f,  0.f}, up},
6744         {{ 0.0f,  0.0f,  0.f}, up},
6745
6746         {{ 2.0f,  3.0f,  0.f}, up},
6747         {{ 3.0f,  0.0f,  0.f}, up},
6748         {{ 0.0f,  0.0f,  0.f}, up},
6749
6750     };
6751     const DWORD exp_indices6[] = {0, 1, 2, 3, 4, 5};
6752     const DWORD exp_face_remap6[] = {0, 1};
6753     const DWORD exp_vertex_remap6[] = {0, 1, 2, 3, 4, 5};
6754     const DWORD exp_new_num_vertices6 = ARRAY_SIZE(exp_vertices6);
6755     /* Test 7. Same as test 6 but with 16 bit indices. */
6756     const WORD indices6_16bit[] = {0, 1, 2, 3, 4, 5};
6757     /* Test 8. No flags. Same result as D3DXWELDEPSILONS_WELDPARTIALMATCHES. */
6758     const struct vertex_normal vertices8[] =
6759     {
6760         {{ 0.0f,  3.0f,  0.f}, up},
6761         {{ 2.0f,  3.0f,  0.f}, up},
6762         {{ 0.0f,  0.0f,  0.f}, up},
6763
6764         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6765         {{ 3.0f,  0.0f,  0.f}, up},
6766         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6767     };
6768     const DWORD indices8[] = {0, 1, 2, 1, 3, 4};
6769     const DWORD attributes8[] = {0, 0};
6770     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
6771     const UINT num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
6772     DWORD flags8 = 0;
6773     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};
6774     const DWORD adjacency8[] = {-1, 1, -1, -1, -1, 0};
6775     const struct vertex_normal exp_vertices8[] =
6776     {
6777         {{ 0.0f,  3.0f,  0.f}, up},
6778         {{ 2.0f,  3.0f,  0.f}, up},
6779         {{ 0.0f,  0.0f,  0.f}, up},
6780
6781         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6782         {{ 3.0f,  0.0f,  0.f}, up},
6783     };
6784     const DWORD exp_indices8[] = {0, 1, 2, 1, 3, 4};
6785     const DWORD exp_face_remap8[] = {0, 1};
6786     const DWORD exp_vertex_remap8[] = {0, 1, 2, 3, 4, -1};
6787     const DWORD exp_new_num_vertices8 = ARRAY_SIZE(exp_vertices8);
6788     /* Test 9. Vertices are removed even though they belong to separate
6789      * attribute groups if D3DXWELDEPSILONS_DONOTSPLIT is set. */
6790     const struct vertex_normal vertices9[] =
6791     {
6792         {{ 0.0f,  3.0f,  0.f}, up},
6793         {{ 2.0f,  3.0f,  0.f}, up},
6794         {{ 0.0f,  0.0f,  0.f}, up},
6795
6796         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6797         {{ 3.0f,  0.0f,  0.f}, up},
6798         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6799     };
6800     const DWORD indices9[] = {0, 1, 2, 3, 4, 5};
6801     const DWORD attributes9[] = {0, 1};
6802     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
6803     const UINT num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
6804     DWORD flags9 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTSPLIT;
6805     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};
6806     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
6807     const struct vertex_normal exp_vertices9[] =
6808     {
6809         {{ 0.0f,  3.0f,  0.f}, up},
6810         {{ 2.0f,  3.0f,  0.f}, up},
6811         {{ 0.0f,  0.0f,  0.f}, up},
6812
6813         {{ 3.0f,  0.0f,  0.f}, up},
6814     };
6815     const DWORD exp_indices9[] = {0, 1, 2, 1, 3, 2};
6816     const DWORD exp_face_remap9[] = {0, 1};
6817     const DWORD exp_vertex_remap9[] = {0, 1, 2, 4, -1, -1};
6818     const DWORD exp_new_num_vertices9 = ARRAY_SIZE(exp_vertices9);
6819     /* Test 10. Weld blendweight (FLOAT1). */
6820     const struct vertex_blendweight vertices10[] =
6821     {
6822         {{ 0.0f,  3.0f,  0.f}, 1.0f},
6823         {{ 2.0f,  3.0f,  0.f}, 1.0f},
6824         {{ 0.0f,  0.0f,  0.f}, 1.0f},
6825
6826         {{ 3.0f,  3.0f,  0.f}, 0.9},
6827         {{ 3.0f,  0.0f,  0.f}, 1.0},
6828         {{ 1.0f,  0.0f,  0.f}, 0.4},
6829     };
6830     const DWORD indices10[] = {0, 1, 2, 3, 4, 5};
6831     const DWORD attributes10[] = {0, 0};
6832     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
6833     const UINT num_faces10 = ARRAY_SIZE(indices10) / VERTS_PER_FACE;
6834     DWORD flags10 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6835     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};
6836     const DWORD adjacency10[] = {-1, 1, -1, -1, -1, 0};
6837     const struct vertex_blendweight exp_vertices10[] =
6838     {
6839         {{ 0.0f,  3.0f,  0.f}, 1.0f},
6840         {{ 2.0f,  3.0f,  0.f}, 1.0f},
6841         {{ 0.0f,  0.0f,  0.f}, 1.0f},
6842
6843         {{ 3.0f,  0.0f,  0.f}, 1.0},
6844         {{ 0.0f,  0.0f,  0.f}, 0.4},
6845     };
6846     const DWORD exp_indices10[] = {0, 1, 2, 1, 3, 4};
6847     const DWORD exp_face_remap10[] = {0, 1};
6848     const DWORD exp_vertex_remap10[] = {0, 1, 2, 4, 5, -1};
6849     const DWORD exp_new_num_vertices10 = ARRAY_SIZE(exp_vertices10);
6850     /* Test 11. Weld texture coordinates. */
6851     const struct vertex_texcoord vertices11[] =
6852     {
6853         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
6854         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
6855         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
6856
6857         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
6858         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
6859         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
6860     };
6861     const DWORD indices11[] = {0, 1, 2, 3, 4, 5};
6862     const DWORD attributes11[] = {0, 0};
6863     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
6864     const UINT num_faces11 = ARRAY_SIZE(indices11) / VERTS_PER_FACE;
6865     DWORD flags11 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6866     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};
6867     const DWORD adjacency11[] = {-1, 1, -1, -1, -1, 0};
6868     const struct vertex_texcoord exp_vertices11[] =
6869     {
6870         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
6871         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
6872         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
6873
6874         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
6875         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
6876     };
6877     const DWORD exp_indices11[] = {0, 1, 2, 1, 3, 4};
6878     const DWORD exp_face_remap11[] = {0, 1};
6879     const DWORD exp_vertex_remap11[] = {0, 1, 2, 4, 5, -1};
6880     const DWORD exp_new_num_vertices11 = ARRAY_SIZE(exp_vertices11);
6881     /* Test 12. Weld with color. */
6882     const struct vertex_color vertices12[] =
6883     {
6884         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6885         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6886         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6887
6888         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
6889         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6890         {{ 1.0f,  0.0f,  0.f}, 0x88888888},
6891     };
6892     const DWORD indices12[] = {0, 1, 2, 3, 4, 5};
6893     const DWORD attributes12[] = {0, 0};
6894     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
6895     const UINT num_faces12 = ARRAY_SIZE(indices12) / VERTS_PER_FACE;
6896     DWORD flags12 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6897     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};
6898     const DWORD adjacency12[] = {-1, 1, -1, -1, -1, 0};
6899     const struct vertex_color exp_vertices12[] =
6900     {
6901         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6902         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6903         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6904
6905         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
6906         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6907     };
6908     const DWORD exp_indices12[] = {0, 1, 2, 3, 4, 2};
6909     const DWORD exp_face_remap12[] = {0, 1};
6910     const DWORD exp_vertex_remap12[] = {0, 1, 2, 3, 4, -1};
6911     const DWORD exp_new_num_vertices12 = ARRAY_SIZE(exp_vertices12);
6912     /* Test 13. Two faces. One vertex should be removed because of normal epsilon.
6913      * This is similar to test 3, but the declaration has been changed to NORMAL3.
6914      */
6915     const struct vertex_normal vertices13[] =
6916     {
6917         {{ 0.0f,  3.0f,  0.f}, up},
6918         {{ 2.0f,  3.0f,  0.f}, up},
6919         {{ 0.0f,  0.0f,  0.f}, up},
6920
6921         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6922         {{ 3.0f,  0.0f,  0.f}, up},
6923         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6924     };
6925     const DWORD indices13[] = {0, 1, 2, 3, 4, 5};
6926     const DWORD attributes13[] = {0, 0};
6927     const UINT num_vertices13 = ARRAY_SIZE(vertices3);
6928     const UINT num_faces13 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
6929     DWORD flags13 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6930     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};
6931     const DWORD adjacency13[] = {-1, 1, -1, -1, -1, 0};
6932     const struct vertex_normal exp_vertices13[] =
6933     {
6934         {{ 0.0f,  3.0f,  0.f}, up},
6935         {{ 2.0f,  3.0f,  0.f}, up},
6936         {{ 0.0f,  0.0f,  0.f}, up},
6937
6938         {{ 3.0f,  0.0f,  0.f}, up},
6939         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6940     };
6941     const DWORD exp_indices13[] = {0, 1, 2, 1, 3, 4};
6942     const DWORD exp_face_remap13[] = {0, 1};
6943     const DWORD exp_vertex_remap13[] = {0, 1, 2, 4, 5, -1};
6944     const DWORD exp_new_num_vertices13 = ARRAY_SIZE(exp_vertices13);
6945     /* Test 14. Another test for welding with color. */
6946     const struct vertex_color vertices14[] =
6947     {
6948         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6949         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6950         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6951
6952         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
6953         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6954         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
6955     };
6956     const DWORD indices14[] = {0, 1, 2, 3, 4, 5};
6957     const DWORD attributes14[] = {0, 0};
6958     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
6959     const UINT num_faces14 = ARRAY_SIZE(indices14) / VERTS_PER_FACE;
6960     DWORD flags14 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6961     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};
6962     const DWORD adjacency14[] = {-1, 1, -1, -1, -1, 0};
6963     const struct vertex_color exp_vertices14[] =
6964     {
6965         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6966         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6967         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6968
6969         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
6970         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6971     };
6972     const DWORD exp_indices14[] = {0, 1, 2, 3, 4, 2};
6973     const DWORD exp_face_remap14[] = {0, 1};
6974     const DWORD exp_vertex_remap14[] = {0, 1, 2, 3, 4, -1};
6975     const DWORD exp_new_num_vertices14 = ARRAY_SIZE(exp_vertices14);
6976     /* Test 15. Weld with color, but as UBYTE4N instead of D3DCOLOR. It shows
6977      * that UBYTE4N and D3DCOLOR are compared the same way.
6978      */
6979     const struct vertex_color_ubyte4 vertices15[] =
6980     {
6981         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
6982         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
6983         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
6984
6985         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
6986         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
6987         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
6988     };
6989     const DWORD indices15[] = {0, 1, 2, 3, 4, 5};
6990     const DWORD attributes15[] = {0, 0};
6991     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
6992     const UINT num_faces15 = ARRAY_SIZE(indices15) / VERTS_PER_FACE;
6993     DWORD flags15 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6994     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};
6995     const DWORD adjacency15[] = {-1, 1, -1, -1, -1, 0};
6996     const struct vertex_color_ubyte4 exp_vertices15[] =
6997     {
6998         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
6999         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7000         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7001
7002         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7003         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7004     };
7005     const DWORD exp_indices15[] = {0, 1, 2, 3, 4, 2};
7006     const DWORD exp_face_remap15[] = {0, 1};
7007     const DWORD exp_vertex_remap15[] = {0, 1, 2, 3, 4, -1};
7008     const DWORD exp_new_num_vertices15 = ARRAY_SIZE(exp_vertices15);
7009     /* Test 16. Weld with color, but as UBYTE4 instead of D3DCOLOR. It shows
7010      * that UBYTE4 is not normalized and that epsilon is truncated and compared
7011      * directly to each of the four bytes.
7012      */
7013     const struct vertex_color_ubyte4 vertices16[] =
7014     {
7015         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7016         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7017         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7018
7019         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7020         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7021         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7022     };
7023     const DWORD indices16[] = {0, 1, 2, 3, 4, 5};
7024     const DWORD attributes16[] = {0, 0};
7025     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
7026     const UINT num_faces16 = ARRAY_SIZE(indices16) / VERTS_PER_FACE;
7027     DWORD flags16 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7028     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};
7029     const DWORD adjacency16[] = {-1, 1, -1, -1, -1, 0};
7030     const struct vertex_color_ubyte4 exp_vertices16[] =
7031     {
7032         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7033         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7034         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7035
7036         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7037         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7038     };
7039     const DWORD exp_indices16[] = {0, 1, 2, 3, 4, 2};
7040     const DWORD exp_face_remap16[] = {0, 1};
7041     const DWORD exp_vertex_remap16[] = {0, 1, 2, 3, 4, -1};
7042     const DWORD exp_new_num_vertices16 = ARRAY_SIZE(exp_vertices16);
7043     /* Test 17. Weld texture coordinates but as SHORT2 instead of D3DXVECTOR2.*/
7044     const struct vertex_texcoord_short2 vertices17[] =
7045     {
7046         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7047         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7048         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7049
7050         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7051         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7052         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7053     };
7054     const DWORD indices17[] = {0, 1, 2, 3, 4, 5};
7055     const DWORD attributes17[] = {0, 0};
7056     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
7057     const UINT num_faces17 = ARRAY_SIZE(indices17) / VERTS_PER_FACE;
7058     DWORD flags17 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7059     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};
7060     const DWORD adjacency17[] = {-1, 1, -1, -1, -1, 0};
7061     const struct vertex_texcoord_short2 exp_vertices17[] =
7062     {
7063         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7064         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7065         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7066
7067         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7068         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7069     };
7070     const DWORD exp_indices17[] = {0, 1, 2, 3, 4, 2};
7071     const DWORD exp_face_remap17[] = {0, 1};
7072     const DWORD exp_vertex_remap17[] = {0, 1, 2, 3, 4, -1};
7073     const DWORD exp_new_num_vertices17 = ARRAY_SIZE(exp_vertices17);
7074     /* Test 18. Weld texture coordinates but as SHORT2N instead of D3DXVECTOR2. */
7075     const struct vertex_texcoord_short2 vertices18[] =
7076     {
7077         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7078         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7079         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7080
7081         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7082         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7083         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7084     };
7085     const DWORD indices18[] = {0, 1, 2, 3, 4, 5};
7086     const DWORD attributes18[] = {0, 0};
7087     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
7088     const UINT num_faces18 = ARRAY_SIZE(indices18) / VERTS_PER_FACE;
7089     DWORD flags18 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7090     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};
7091     const DWORD adjacency18[] = {-1, 1, -1, -1, -1, 0};
7092     const struct vertex_texcoord_short2 exp_vertices18[] =
7093     {
7094         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7095         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7096         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7097
7098         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7099         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7100     };
7101     const DWORD exp_indices18[] = {0, 1, 2, 3, 4, 2};
7102     const DWORD exp_face_remap18[] = {0, 1};
7103     const DWORD exp_vertex_remap18[] = {0, 1, 2, 3, 4, -1};
7104     const DWORD exp_new_num_vertices18 = ARRAY_SIZE(exp_vertices18);
7105     /* Test 19.  Weld texture coordinates but as USHORT2N instead of D3DXVECTOR2. */
7106     const struct vertex_texcoord_ushort2n vertices19[] =
7107     {
7108         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7109         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7110         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7111
7112         {{ 3.0f,  3.0f,  0.f}, {65535, 65535}},
7113         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7114         {{ 1.0f,  0.0f,  0.f}, {65534, 65534}},
7115     };
7116     const DWORD indices19[] = {0, 1, 2, 3, 4, 5};
7117     const DWORD attributes19[] = {0, 0};
7118     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
7119     const UINT num_faces19 = ARRAY_SIZE(indices19) / VERTS_PER_FACE;
7120     DWORD flags19 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7121     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};
7122     const DWORD adjacency19[] = {-1, 1, -1, -1, -1, 0};
7123     const struct vertex_texcoord_ushort2n exp_vertices19[] =
7124     {
7125         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7126         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7127         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7128
7129         {{ 2.0f,  3.0f,  0.f}, {65535, 65535}},
7130         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7131     };
7132     const DWORD exp_indices19[] = {0, 1, 2, 3, 4, 2};
7133     const DWORD exp_face_remap19[] = {0, 1};
7134     const DWORD exp_vertex_remap19[] = {0, 1, 2, 3, 4, -1};
7135     const DWORD exp_new_num_vertices19 = ARRAY_SIZE(exp_vertices19);
7136     /* Test 20.  Weld normal as SHORT4 instead of D3DXVECTOR3. */
7137     const struct vertex_normal_short4 vertices20[] =
7138     {
7139         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7140         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7141         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7142
7143         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7144         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7145         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7146     };
7147     const DWORD indices20[] = {0, 1, 2, 3, 4, 5};
7148     const DWORD attributes20[] = {0, 0};
7149     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
7150     const UINT num_faces20 = ARRAY_SIZE(indices20) / VERTS_PER_FACE;
7151     DWORD flags20 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7152     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};
7153     const DWORD adjacency20[] = {-1, 1, -1, -1, -1, 0};
7154     const struct vertex_normal_short4 exp_vertices20[] =
7155     {
7156         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7157         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7158         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7159
7160         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7161         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7162     };
7163     const DWORD exp_indices20[] = {0, 1, 2, 3, 4, 2};
7164     const DWORD exp_face_remap20[] = {0, 1};
7165     const DWORD exp_vertex_remap20[] = {0, 1, 2, 3, 4, -1};
7166     const DWORD exp_new_num_vertices20 = ARRAY_SIZE(exp_vertices20);
7167     /* Test 21.  Weld normal as SHORT4N instead of D3DXVECTOR3. */
7168     const struct vertex_normal_short4 vertices21[] =
7169     {
7170         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7171         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7172         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7173
7174         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7175         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7176         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7177     };
7178     const DWORD indices21[] = {0, 1, 2, 3, 4, 5};
7179     const DWORD attributes21[] = {0, 0};
7180     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
7181     const UINT num_faces21 = ARRAY_SIZE(indices21) / VERTS_PER_FACE;
7182     DWORD flags21 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7183     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};
7184     const DWORD adjacency21[] = {-1, 1, -1, -1, -1, 0};
7185     const struct vertex_normal_short4 exp_vertices21[] =
7186     {
7187         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7188         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7189         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7190
7191         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7192         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7193     };
7194     const DWORD exp_indices21[] = {0, 1, 2, 3, 4, 2};
7195     const DWORD exp_face_remap21[] = {0, 1};
7196     const DWORD exp_vertex_remap21[] = {0, 1, 2, 3, 4, -1};
7197     const DWORD exp_new_num_vertices21 = ARRAY_SIZE(exp_vertices21);
7198     /* Test 22.  Weld normal as USHORT4N instead of D3DXVECTOR3. */
7199     const struct vertex_normal_short4 vertices22[] =
7200     {
7201         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7202         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7203         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7204
7205         {{ 3.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7206         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7207         {{ 1.0f,  0.0f,  0.f}, {65534, 65534, 65534, 65534}},
7208     };
7209     const DWORD indices22[] = {0, 1, 2, 3, 4, 5};
7210     const DWORD attributes22[] = {0, 0};
7211     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
7212     const UINT num_faces22 = ARRAY_SIZE(indices22) / VERTS_PER_FACE;
7213     DWORD flags22 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7214     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};
7215     const DWORD adjacency22[] = {-1, 1, -1, -1, -1, 0};
7216     const struct vertex_normal_short4 exp_vertices22[] =
7217     {
7218         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7219         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7220         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7221
7222         {{ 2.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7223         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7224     };
7225     const DWORD exp_indices22[] = {0, 1, 2, 3, 4, 2};
7226     const DWORD exp_face_remap22[] = {0, 1};
7227     const DWORD exp_vertex_remap22[] = {0, 1, 2, 3, 4, -1};
7228     const DWORD exp_new_num_vertices22 = ARRAY_SIZE(exp_vertices22);
7229     /* Test 23. Weld texture coordinates as FLOAT16_2. Similar to test 11, but
7230      * with texture coordinates converted to float16 in hex. */
7231     const struct vertex_texcoord_float16_2 vertices23[] =
7232     {
7233         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7234         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7235         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7236
7237         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
7238         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7239         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7240     };
7241     const DWORD indices23[] = {0, 1, 2, 3, 4, 5};
7242     const DWORD attributes23[] = {0, 0};
7243     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
7244     const UINT num_faces23 = ARRAY_SIZE(indices23) / VERTS_PER_FACE;
7245     DWORD flags23 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7246     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};
7247     const DWORD adjacency23[] = {-1, 1, -1, -1, -1, 0};
7248     const struct vertex_texcoord_float16_2 exp_vertices23[] =
7249     {
7250         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7251         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7252         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7253
7254         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7255         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7256     };
7257     const DWORD exp_indices23[] = {0, 1, 2, 1, 3, 4};
7258     const DWORD exp_face_remap23[] = {0, 1};
7259     const DWORD exp_vertex_remap23[] = {0, 1, 2, 4, 5, -1};
7260     const DWORD exp_new_num_vertices23 = ARRAY_SIZE(exp_vertices23);
7261     /* Test 24. Weld texture coordinates as FLOAT16_4. Similar to test 24. */
7262     const struct vertex_texcoord_float16_4 vertices24[] =
7263     {
7264         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7265         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7266         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7267
7268         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0x3266, 0x34cd}},
7269         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7270         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7271     };
7272     const DWORD indices24[] = {0, 1, 2, 3, 4, 5};
7273     const DWORD attributes24[] = {0, 0};
7274     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
7275     const UINT num_faces24 = ARRAY_SIZE(indices24) / VERTS_PER_FACE;
7276     DWORD flags24 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7277     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};
7278     const DWORD adjacency24[] = {-1, 1, -1, -1, -1, 0};
7279     const struct vertex_texcoord_float16_4 exp_vertices24[] =
7280     {
7281         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7282         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7283         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7284
7285         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7286         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7287     };
7288     const DWORD exp_indices24[] = {0, 1, 2, 1, 3, 4};
7289     const DWORD exp_face_remap24[] = {0, 1};
7290     const DWORD exp_vertex_remap24[] = {0, 1, 2, 4, 5, -1};
7291     const DWORD exp_new_num_vertices24 = ARRAY_SIZE(exp_vertices24);
7292     /* Test 25. Weld texture coordinates with usage index 10 (TEXCOORD10). The
7293      * usage index is capped at 7, so the epsilon for TEXCOORD7 is used instead.
7294      */
7295     const struct vertex_texcoord vertices25[] =
7296     {
7297         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7298         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7299         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7300
7301         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7302         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7303         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7304     };
7305     const DWORD indices25[] = {0, 1, 2, 3, 4, 5};
7306     const DWORD attributes25[] = {0, 0};
7307     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
7308     const UINT num_faces25 = ARRAY_SIZE(indices25) / VERTS_PER_FACE;
7309     DWORD flags25 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7310     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};
7311     const DWORD adjacency25[] = {-1, 1, -1, -1, -1, 0};
7312     const struct vertex_texcoord exp_vertices25[] =
7313     {
7314         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7315         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7316         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7317
7318         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7319         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7320     };
7321     const DWORD exp_indices25[] = {0, 1, 2, 1, 3, 4};
7322     const DWORD exp_face_remap25[] = {0, 1};
7323     const DWORD exp_vertex_remap25[] = {0, 1, 2, 4, 5, -1};
7324     const DWORD exp_new_num_vertices25 = ARRAY_SIZE(exp_vertices25);
7325     /* Test 26. Weld color with usage index larger than 1. Shows that none of
7326      * the epsilon values are used. */
7327     const struct vertex_color vertices26[] =
7328     {
7329         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7330         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7331         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7332
7333         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7334         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7335         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7336     };
7337     const DWORD indices26[] = {0, 1, 2, 3, 4, 5};
7338     const DWORD attributes26[] = {0, 0};
7339     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
7340     const UINT num_faces26 = ARRAY_SIZE(indices26) / VERTS_PER_FACE;
7341     DWORD flags26 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7342     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};
7343     const DWORD adjacency26[] = {-1, 1, -1, -1, -1, 0};
7344     const struct vertex_color exp_vertices26[] =
7345     {
7346         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7347         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7348         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7349
7350         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7351         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7352         {{ 0.0f,  0.0f,  0.f}, 0x01010101},
7353     };
7354     const DWORD exp_indices26[] = {0, 1, 2, 3, 4, 5};
7355     const DWORD exp_face_remap26[] = {0, 1};
7356     const DWORD exp_vertex_remap26[] = {0, 1, 2, 3, 4, 5};
7357     const DWORD exp_new_num_vertices26 = ARRAY_SIZE(exp_vertices26);
7358     /* Test 27. Weld color with usage index larger than 1. Check that the
7359      * default epsilon of 1e-6f is used. */
7360     D3DXVECTOR4 zero_float4 = {0.0f, 0.0f, 0.0f, 0.0f};
7361     D3DXVECTOR4 almost_zero_float4 = {0.0f + FLT_EPSILON, 0.0f + FLT_EPSILON, 0.0f + FLT_EPSILON, 0.0f + FLT_EPSILON};
7362     const struct vertex_color_float4 vertices27[] =
7363     {
7364         {{ 0.0f,  3.0f,  0.f}, zero_float4},
7365         {{ 2.0f,  3.0f,  0.f}, zero_float4},
7366         {{ 0.0f,  0.0f,  0.f}, zero_float4},
7367
7368         {{ 3.0f,  3.0f,  0.f}, almost_zero_float4},
7369         {{ 3.0f,  0.0f,  0.f}, zero_float4},
7370         {{ 1.0f,  0.0f,  0.f}, almost_zero_float4},
7371     };
7372     const DWORD indices27[] = {0, 1, 2, 3, 4, 5};
7373     const DWORD attributes27[] = {0, 0};
7374     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
7375     const UINT num_faces27 = ARRAY_SIZE(indices27) / VERTS_PER_FACE;
7376     DWORD flags27 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7377     const D3DXWELDEPSILONS epsilons27 = {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.0f}, 0.0f, 0.0f, 0.0f};
7378     const DWORD adjacency27[] = {-1, 1, -1, -1, -1, 0};
7379     const struct vertex_color_float4 exp_vertices27[] =
7380     {
7381         {{ 0.0f,  3.0f,  0.f}, zero_float4},
7382         {{ 2.0f,  3.0f,  0.f}, zero_float4},
7383         {{ 0.0f,  0.0f,  0.f}, zero_float4},
7384
7385         {{ 3.0f,  0.0f,  0.f}, zero_float4},
7386     };
7387     const DWORD exp_indices27[] = {0, 1, 2, 1, 3, 2};
7388     const DWORD exp_face_remap27[] = {0, 1};
7389     const DWORD exp_vertex_remap27[] = {0, 1, 2, 4, -1, -1};
7390     const DWORD exp_new_num_vertices27 = ARRAY_SIZE(exp_vertices27);
7391     /* Test 28. Weld one normal with UDEC3. */
7392     const DWORD dword_udec3_zero = init_udec3_dword(0, 0, 0, 1);
7393     const DWORD dword_udec3_1023 = init_udec3_dword(1023, 1023, 1023, 1);
7394     const DWORD dword_udec3_1022 = init_udec3_dword(1022, 1022, 1022, 1);
7395     const struct vertex_normal_udec3 vertices28[] =
7396     {
7397         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7398         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7399         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7400
7401         {{ 3.0f,  3.0f,  0.f}, dword_udec3_1023},
7402         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7403         {{ 1.0f,  0.0f,  0.f}, dword_udec3_1022},
7404     };
7405     const DWORD indices28[] = {0, 1, 2, 3, 4, 5};
7406     const DWORD attributes28[] = {0, 0};
7407     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
7408     const UINT num_faces28 = ARRAY_SIZE(indices28) / VERTS_PER_FACE;
7409     DWORD flags28 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7410     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};
7411     const DWORD adjacency28[] = {-1, 1, -1, -1, -1, 0};
7412     const struct vertex_normal_udec3 exp_vertices28[] =
7413     {
7414         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7415         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7416         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7417
7418         {{ 2.0f,  3.0f,  0.f}, dword_udec3_1023},
7419         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7420     };
7421     const DWORD exp_indices28[] = {0, 1, 2, 3, 4, 2};
7422     const DWORD exp_face_remap28[] = {0, 1};
7423     const DWORD exp_vertex_remap28[] = {0, 1, 2, 3, 4, -1};
7424     const DWORD exp_new_num_vertices28 = ARRAY_SIZE(exp_vertices28);
7425     /* Test 29. Weld one normal with DEC3N. */
7426     const DWORD dword_dec3n_zero = init_dec3n_dword(0, 0, 0, 1);
7427     const DWORD dword_dec3n_511 = init_dec3n_dword(511, 511, 511, 1);
7428     const DWORD dword_dec3n_510 = init_dec3n_dword(510, 510, 510, 1);
7429     const struct vertex_normal_dec3n vertices29[] =
7430     {
7431         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7432         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7433         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7434
7435         {{ 3.0f,  3.0f,  0.f}, dword_dec3n_511},
7436         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7437         {{ 1.0f,  0.0f,  0.f}, dword_dec3n_510},
7438     };
7439     const DWORD indices29[] = {0, 1, 2, 3, 4, 5};
7440     const DWORD attributes29[] = {0, 0};
7441     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
7442     const UINT num_faces29 = ARRAY_SIZE(indices29) / VERTS_PER_FACE;
7443     DWORD flags29 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7444     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};
7445     const DWORD adjacency29[] = {-1, 1, -1, -1, -1, 0};
7446     const struct vertex_normal_dec3n exp_vertices29[] =
7447     {
7448         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7449         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7450         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7451
7452         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_511},
7453         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7454     };
7455     const DWORD exp_indices29[] = {0, 1, 2, 3, 4, 2};
7456     const DWORD exp_face_remap29[] = {0, 1};
7457     const DWORD exp_vertex_remap29[] = {0, 1, 2, 3, 4, -1};
7458     const DWORD exp_new_num_vertices29 = ARRAY_SIZE(exp_vertices29);
7459     /* All mesh data */
7460     DWORD *adjacency_out = NULL;
7461     DWORD *face_remap = NULL;
7462     ID3DXMesh *mesh = NULL;
7463     ID3DXBuffer *vertex_remap = NULL;
7464     struct
7465     {
7466         const BYTE *vertices;
7467         const DWORD *indices;
7468         const DWORD *attributes;
7469         const DWORD num_vertices;
7470         const DWORD num_faces;
7471         const DWORD options;
7472         D3DVERTEXELEMENT9 *declaration;
7473         const UINT vertex_size;
7474         const DWORD flags;
7475         const D3DXWELDEPSILONS *epsilons;
7476         const DWORD *adjacency;
7477         const BYTE *exp_vertices;
7478         const DWORD *exp_indices;
7479         const DWORD *exp_face_remap;
7480         const DWORD *exp_vertex_remap;
7481         const DWORD exp_new_num_vertices;
7482     }
7483     tc[] =
7484     {
7485         {
7486             (BYTE*)vertices0,
7487             indices0,
7488             attributes0,
7489             num_vertices0,
7490             num_faces0,
7491             options,
7492             declaration_normal,
7493             vertex_size_normal,
7494             flags0,
7495             NULL,
7496             adjacency0,
7497             (BYTE*)exp_vertices0,
7498             exp_indices0,
7499             exp_face_remap0,
7500             exp_vertex_remap0,
7501             exp_new_num_vertices0
7502         },
7503         {
7504             (BYTE*)vertices1,
7505             indices1,
7506             attributes1,
7507             num_vertices1,
7508             num_faces1,
7509             options,
7510             declaration_normal,
7511             vertex_size_normal,
7512             flags1,
7513             NULL,
7514             adjacency1,
7515             (BYTE*)exp_vertices1,
7516             exp_indices1,
7517             exp_face_remap1,
7518             exp_vertex_remap1,
7519             exp_new_num_vertices1
7520         },
7521         {
7522             (BYTE*)vertices2,
7523             indices2,
7524             attributes2,
7525             num_vertices2,
7526             num_faces2,
7527             options,
7528             declaration_normal,
7529             vertex_size_normal,
7530             flags2,
7531             &epsilons2,
7532             adjacency2,
7533             (BYTE*)exp_vertices2,
7534             exp_indices2,
7535             exp_face_remap2,
7536             exp_vertex_remap2,
7537             exp_new_num_vertices2
7538         },
7539         {
7540             (BYTE*)vertices3,
7541             indices3,
7542             attributes3,
7543             num_vertices3,
7544             num_faces3,
7545             options,
7546             declaration_normal,
7547             vertex_size_normal,
7548             flags3,
7549             &epsilons3,
7550             adjacency3,
7551             (BYTE*)exp_vertices3,
7552             exp_indices3,
7553             exp_face_remap3,
7554             exp_vertex_remap3,
7555             exp_new_num_vertices3
7556         },
7557         {
7558             (BYTE*)vertices4,
7559             indices4,
7560             attributes4,
7561             num_vertices4,
7562             num_faces4,
7563             options,
7564             declaration_normal,
7565             vertex_size_normal,
7566             flags4,
7567             &epsilons4,
7568             adjacency4,
7569             (BYTE*)exp_vertices4,
7570             exp_indices4,
7571             exp_face_remap4,
7572             exp_vertex_remap4,
7573             exp_new_num_vertices4
7574         },
7575         /* Unusual ordering. */
7576         {
7577             (BYTE*)vertices5,
7578             indices5,
7579             attributes5,
7580             num_vertices5,
7581             num_faces5,
7582             options,
7583             declaration_normal,
7584             vertex_size_normal,
7585             flags5,
7586             NULL,
7587             adjacency5,
7588             (BYTE*)exp_vertices5,
7589             exp_indices5,
7590             exp_face_remap5,
7591             exp_vertex_remap5,
7592             exp_new_num_vertices5
7593         },
7594         {
7595             (BYTE*)vertices6,
7596             indices6,
7597             attributes6,
7598             num_vertices6,
7599             num_faces6,
7600             options,
7601             declaration_normal,
7602             vertex_size_normal,
7603             flags6,
7604             &epsilons6,
7605             adjacency6,
7606             (BYTE*)exp_vertices6,
7607             exp_indices6,
7608             exp_face_remap6,
7609             exp_vertex_remap6,
7610             exp_new_num_vertices6
7611         },
7612         {
7613             (BYTE*)vertices6,
7614             (DWORD*)indices6_16bit,
7615             attributes6,
7616             num_vertices6,
7617             num_faces6,
7618             options_16bit,
7619             declaration_normal,
7620             vertex_size_normal,
7621             flags6,
7622             &epsilons6,
7623             adjacency6,
7624             (BYTE*)exp_vertices6,
7625             exp_indices6,
7626             exp_face_remap6,
7627             exp_vertex_remap6,
7628             exp_new_num_vertices6
7629         },
7630         {
7631             (BYTE*)vertices8,
7632             indices8,
7633             attributes8,
7634             num_vertices8,
7635             num_faces8,
7636             options,
7637             declaration_normal,
7638             vertex_size_normal,
7639             flags8,
7640             &epsilons8,
7641             adjacency8,
7642             (BYTE*)exp_vertices8,
7643             exp_indices8,
7644             exp_face_remap8,
7645             exp_vertex_remap8,
7646             exp_new_num_vertices8
7647         },
7648         {
7649             (BYTE*)vertices9,
7650             indices9,
7651             attributes9,
7652             num_vertices9,
7653             num_faces9,
7654             options,
7655             declaration_normal,
7656             vertex_size_normal,
7657             flags9,
7658             &epsilons9,
7659             adjacency9,
7660             (BYTE*)exp_vertices9,
7661             exp_indices9,
7662             exp_face_remap9,
7663             exp_vertex_remap9,
7664             exp_new_num_vertices9
7665         },
7666         {
7667             (BYTE*)vertices10,
7668             indices10,
7669             attributes10,
7670             num_vertices10,
7671             num_faces10,
7672             options,
7673             declaration_blendweight,
7674             vertex_size_blendweight,
7675             flags10,
7676             &epsilons10,
7677             adjacency10,
7678             (BYTE*)exp_vertices10,
7679             exp_indices10,
7680             exp_face_remap10,
7681             exp_vertex_remap10,
7682             exp_new_num_vertices10
7683         },
7684         {
7685             (BYTE*)vertices11,
7686             indices11,
7687             attributes11,
7688             num_vertices11,
7689             num_faces11,
7690             options,
7691             declaration_texcoord,
7692             vertex_size_texcoord,
7693             flags11,
7694             &epsilons11,
7695             adjacency11,
7696             (BYTE*)exp_vertices11,
7697             exp_indices11,
7698             exp_face_remap11,
7699             exp_vertex_remap11,
7700             exp_new_num_vertices11
7701         },
7702         {
7703             (BYTE*)vertices12,
7704             indices12,
7705             attributes12,
7706             num_vertices12,
7707             num_faces12,
7708             options,
7709             declaration_color,
7710             vertex_size_color,
7711             flags12,
7712             &epsilons12,
7713             adjacency12,
7714             (BYTE*)exp_vertices12,
7715             exp_indices12,
7716             exp_face_remap12,
7717             exp_vertex_remap12,
7718             exp_new_num_vertices12
7719         },
7720         {
7721             (BYTE*)vertices13,
7722             indices13,
7723             attributes13,
7724             num_vertices13,
7725             num_faces13,
7726             options,
7727             declaration_normal3,
7728             vertex_size_normal,
7729             flags13,
7730             &epsilons13,
7731             adjacency13,
7732             (BYTE*)exp_vertices13,
7733             exp_indices13,
7734             exp_face_remap13,
7735             exp_vertex_remap13,
7736             exp_new_num_vertices13
7737         },
7738         {
7739             (BYTE*)vertices14,
7740             indices14,
7741             attributes14,
7742             num_vertices14,
7743             num_faces14,
7744             options,
7745             declaration_color,
7746             vertex_size_color,
7747             flags14,
7748             &epsilons14,
7749             adjacency14,
7750             (BYTE*)exp_vertices14,
7751             exp_indices14,
7752             exp_face_remap14,
7753             exp_vertex_remap14,
7754             exp_new_num_vertices14
7755         },
7756         {
7757             (BYTE*)vertices15,
7758             indices15,
7759             attributes15,
7760             num_vertices15,
7761             num_faces15,
7762             options,
7763             declaration_color_ubyte4n,
7764             vertex_size_color_ubyte4, /* UBYTE4 same size as UBYTE4N */
7765             flags15,
7766             &epsilons15,
7767             adjacency15,
7768             (BYTE*)exp_vertices15,
7769             exp_indices15,
7770             exp_face_remap15,
7771             exp_vertex_remap15,
7772             exp_new_num_vertices15
7773         },
7774         {
7775             (BYTE*)vertices16,
7776             indices16,
7777             attributes16,
7778             num_vertices16,
7779             num_faces16,
7780             options,
7781             declaration_color_ubyte4,
7782             vertex_size_color_ubyte4,
7783             flags16,
7784             &epsilons16,
7785             adjacency16,
7786             (BYTE*)exp_vertices16,
7787             exp_indices16,
7788             exp_face_remap16,
7789             exp_vertex_remap16,
7790             exp_new_num_vertices16
7791         },
7792         {
7793             (BYTE*)vertices17,
7794             indices17,
7795             attributes17,
7796             num_vertices17,
7797             num_faces17,
7798             options,
7799             declaration_texcoord_short2,
7800             vertex_size_texcoord_short2,
7801             flags17,
7802             &epsilons17,
7803             adjacency17,
7804             (BYTE*)exp_vertices17,
7805             exp_indices17,
7806             exp_face_remap17,
7807             exp_vertex_remap17,
7808             exp_new_num_vertices17
7809         },
7810         {
7811             (BYTE*)vertices18,
7812             indices18,
7813             attributes18,
7814             num_vertices18,
7815             num_faces18,
7816             options,
7817             declaration_texcoord_short2n,
7818             vertex_size_texcoord_short2, /* SHORT2 same size as SHORT2N */
7819             flags18,
7820             &epsilons18,
7821             adjacency18,
7822             (BYTE*)exp_vertices18,
7823             exp_indices18,
7824             exp_face_remap18,
7825             exp_vertex_remap18,
7826             exp_new_num_vertices18
7827         },
7828         {
7829             (BYTE*)vertices19,
7830             indices19,
7831             attributes19,
7832             num_vertices19,
7833             num_faces19,
7834             options,
7835             declaration_texcoord_ushort2n,
7836             vertex_size_texcoord_short2, /* SHORT2 same size as USHORT2N */
7837             flags19,
7838             &epsilons19,
7839             adjacency19,
7840             (BYTE*)exp_vertices19,
7841             exp_indices19,
7842             exp_face_remap19,
7843             exp_vertex_remap19,
7844             exp_new_num_vertices19
7845         },
7846         {
7847             (BYTE*)vertices20,
7848             indices20,
7849             attributes20,
7850             num_vertices20,
7851             num_faces20,
7852             options,
7853             declaration_normal_short4,
7854             vertex_size_normal_short4,
7855             flags20,
7856             &epsilons20,
7857             adjacency20,
7858             (BYTE*)exp_vertices20,
7859             exp_indices20,
7860             exp_face_remap20,
7861             exp_vertex_remap20,
7862             exp_new_num_vertices20
7863         },
7864         {
7865             (BYTE*)vertices21,
7866             indices21,
7867             attributes21,
7868             num_vertices21,
7869             num_faces21,
7870             options,
7871             declaration_normal_short4n,
7872             vertex_size_normal_short4, /* SHORT4 same size as SHORT4N */
7873             flags21,
7874             &epsilons21,
7875             adjacency21,
7876             (BYTE*)exp_vertices21,
7877             exp_indices21,
7878             exp_face_remap21,
7879             exp_vertex_remap21,
7880             exp_new_num_vertices21
7881         },
7882         {
7883             (BYTE*)vertices22,
7884             indices22,
7885             attributes22,
7886             num_vertices22,
7887             num_faces22,
7888             options,
7889             declaration_normal_ushort4n,
7890             vertex_size_normal_short4, /* SHORT4 same size as USHORT4N */
7891             flags22,
7892             &epsilons22,
7893             adjacency22,
7894             (BYTE*)exp_vertices22,
7895             exp_indices22,
7896             exp_face_remap22,
7897             exp_vertex_remap22,
7898             exp_new_num_vertices22
7899         },
7900         {
7901             (BYTE*)vertices23,
7902             indices23,
7903             attributes23,
7904             num_vertices23,
7905             num_faces23,
7906             options,
7907             declaration_texcoord_float16_2,
7908             vertex_size_texcoord_float16_2,
7909             flags23,
7910             &epsilons23,
7911             adjacency23,
7912             (BYTE*)exp_vertices23,
7913             exp_indices23,
7914             exp_face_remap23,
7915             exp_vertex_remap23,
7916             exp_new_num_vertices23
7917         },
7918         {
7919             (BYTE*)vertices24,
7920             indices24,
7921             attributes24,
7922             num_vertices24,
7923             num_faces24,
7924             options,
7925             declaration_texcoord_float16_4,
7926             vertex_size_texcoord_float16_4,
7927             flags24,
7928             &epsilons24,
7929             adjacency24,
7930             (BYTE*)exp_vertices24,
7931             exp_indices24,
7932             exp_face_remap24,
7933             exp_vertex_remap24,
7934             exp_new_num_vertices24
7935         },
7936         {
7937             (BYTE*)vertices25,
7938             indices25,
7939             attributes25,
7940             num_vertices25,
7941             num_faces25,
7942             options,
7943             declaration_texcoord10,
7944             vertex_size_texcoord,
7945             flags25,
7946             &epsilons25,
7947             adjacency25,
7948             (BYTE*)exp_vertices25,
7949             exp_indices25,
7950             exp_face_remap25,
7951             exp_vertex_remap25,
7952             exp_new_num_vertices25
7953         },
7954         {
7955             (BYTE*)vertices26,
7956             indices26,
7957             attributes26,
7958             num_vertices26,
7959             num_faces26,
7960             options,
7961             declaration_color2,
7962             vertex_size_color,
7963             flags26,
7964             &epsilons26,
7965             adjacency26,
7966             (BYTE*)exp_vertices26,
7967             exp_indices26,
7968             exp_face_remap26,
7969             exp_vertex_remap26,
7970             exp_new_num_vertices26
7971         },
7972         {
7973             (BYTE*)vertices27,
7974             indices27,
7975             attributes27,
7976             num_vertices27,
7977             num_faces27,
7978             options,
7979             declaration_color2_float4,
7980             vertex_size_color_float4,
7981             flags27,
7982             &epsilons27,
7983             adjacency27,
7984             (BYTE*)exp_vertices27,
7985             exp_indices27,
7986             exp_face_remap27,
7987             exp_vertex_remap27,
7988             exp_new_num_vertices27
7989         },
7990         {
7991             (BYTE*)vertices28,
7992             indices28,
7993             attributes28,
7994             num_vertices28,
7995             num_faces28,
7996             options,
7997             declaration_normal_udec3,
7998             vertex_size_normal_udec3,
7999             flags28,
8000             &epsilons28,
8001             adjacency28,
8002             (BYTE*)exp_vertices28,
8003             exp_indices28,
8004             exp_face_remap28,
8005             exp_vertex_remap28,
8006             exp_new_num_vertices28
8007         },
8008         {
8009             (BYTE*)vertices29,
8010             indices29,
8011             attributes29,
8012             num_vertices29,
8013             num_faces29,
8014             options,
8015             declaration_normal_dec3n,
8016             vertex_size_normal_dec3n,
8017             flags29,
8018             &epsilons29,
8019             adjacency29,
8020             (BYTE*)exp_vertices29,
8021             exp_indices29,
8022             exp_face_remap29,
8023             exp_vertex_remap29,
8024             exp_new_num_vertices29
8025         }
8026     };
8027
8028     test_context = new_test_context();
8029     if (!test_context)
8030     {
8031         skip("Couldn't create test context\n");
8032         goto cleanup;
8033     }
8034
8035     for (i = 0; i < ARRAY_SIZE(tc); i++)
8036     {
8037         DWORD j;
8038         DWORD *vertex_remap_ptr;
8039         DWORD new_num_vertices;
8040
8041         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
8042                             tc[i].declaration, test_context->device, &mesh,
8043                             tc[i].vertices, tc[i].vertex_size,
8044                             tc[i].indices, tc[i].attributes);
8045         if (FAILED(hr))
8046         {
8047             skip("Couldn't initialize test mesh %d.\n", i);
8048             goto cleanup;
8049         }
8050
8051         /* Allocate out parameters */
8052         adjacency_out = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency_out));
8053         if (!adjacency_out)
8054         {
8055             skip("Couldn't allocate adjacency_out array.\n");
8056             goto cleanup;
8057         }
8058         face_remap = HeapAlloc(GetProcessHeap(), 0, tc[i].num_faces * sizeof(*face_remap));
8059         if (!adjacency_out)
8060         {
8061             skip("Couldn't allocate face_remap array.\n");
8062             goto cleanup;
8063         }
8064         hr = D3DXCreateBuffer(tc[i].num_vertices * sizeof(DWORD), &vertex_remap);
8065         if (FAILED(hr))
8066         {
8067             skip("Couldn't create vertex_remap buffer.\n");
8068             goto cleanup;
8069         }
8070
8071         hr = D3DXWeldVertices(mesh, tc[i].flags, tc[i].epsilons, tc[i].adjacency,
8072                               adjacency_out, face_remap, &vertex_remap);
8073         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
8074         /* Check number of vertices*/
8075         new_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
8076         ok(new_num_vertices == tc[i].exp_new_num_vertices,
8077            "Mesh %d: new_num_vertices == %d, expected %d.\n",
8078            i, new_num_vertices, tc[i].exp_new_num_vertices);
8079         /* Check index buffer */
8080         if (tc[i].options & D3DXMESH_32BIT)
8081         {
8082             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices);
8083             if (FAILED(hr))
8084             {
8085                 skip("Couldn't lock index buffer.\n");
8086                 goto cleanup;
8087             }
8088             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8089             {
8090                 ok(indices[j] == tc[i].exp_indices[j],
8091                    "Mesh %d: indices[%d] == %d, expected %d\n",
8092                    i, j, indices[j], tc[i].exp_indices[j]);
8093             }
8094         }
8095         else
8096         {
8097             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices_16bit);
8098             if (FAILED(hr))
8099             {
8100                 skip("Couldn't lock index buffer.\n");
8101                 goto cleanup;
8102             }
8103             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8104             {
8105                 ok(indices_16bit[j] == tc[i].exp_indices[j],
8106                    "Mesh %d: indices_16bit[%d] == %d, expected %d\n",
8107                    i, j, indices_16bit[j], tc[i].exp_indices[j]);
8108             }
8109         }
8110         mesh->lpVtbl->UnlockIndexBuffer(mesh);
8111         indices = NULL;
8112         indices_16bit = NULL;
8113         /* Check adjacency_out */
8114         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8115         {
8116             ok(adjacency_out[j] == tc[i].adjacency[j],
8117                "Mesh %d: adjacency_out[%d] == %d, expected %d\n",
8118                i, j, adjacency_out[j], tc[i].adjacency[j]);
8119         }
8120         /* Check face_remap */
8121         for (j = 0; j < tc[i].num_faces; j++)
8122         {
8123             ok(face_remap[j] == tc[i].exp_face_remap[j],
8124                "Mesh %d: face_remap[%d] == %d, expected %d\n",
8125                i, j, face_remap[j], tc[i].exp_face_remap[j]);
8126         }
8127         /* Check vertex_remap */
8128         vertex_remap_ptr = vertex_remap->lpVtbl->GetBufferPointer(vertex_remap);
8129         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8130         {
8131             ok(vertex_remap_ptr[j] == tc[i].exp_vertex_remap[j],
8132                "Mesh %d: vertex_remap_ptr[%d] == %d, expected %d\n",
8133                i, j, vertex_remap_ptr[j], tc[i].exp_vertex_remap[j]);
8134         }
8135         /* Check vertex buffer */
8136         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void*)&vertices);
8137         if (FAILED(hr))
8138         {
8139             skip("Couldn't lock vertex buffer.\n");
8140             goto cleanup;
8141         }
8142         /* Check contents of re-ordered vertex buffer */
8143         for (j = 0; j < tc[i].exp_new_num_vertices; j++)
8144         {
8145             int index = tc[i].vertex_size*j;
8146             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].declaration);
8147         }
8148         mesh->lpVtbl->UnlockVertexBuffer(mesh);
8149         vertices = NULL;
8150
8151         /* Free mesh and output data */
8152         HeapFree(GetProcessHeap(), 0, adjacency_out);
8153         adjacency_out = NULL;
8154         HeapFree(GetProcessHeap(), 0, face_remap);
8155         face_remap = NULL;
8156         vertex_remap->lpVtbl->Release(vertex_remap);
8157         vertex_remap = NULL;
8158         mesh->lpVtbl->Release(mesh);
8159         mesh = NULL;
8160     }
8161
8162 cleanup:
8163     HeapFree(GetProcessHeap(), 0, adjacency_out);
8164     HeapFree(GetProcessHeap(), 0, face_remap);
8165     if (indices) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8166     if (indices_16bit) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8167     if (mesh) mesh->lpVtbl->Release(mesh);
8168     if (vertex_remap) vertex_remap->lpVtbl->Release(vertex_remap);
8169     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
8170     free_test_context(test_context);
8171 }
8172
8173 static void test_clone_mesh(void)
8174 {
8175     HRESULT hr;
8176     struct test_context *test_context = NULL;
8177     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
8178     D3DVERTEXELEMENT9 declaration_pn[] =
8179     {
8180         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8181         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8182         D3DDECL_END()
8183     };
8184     D3DVERTEXELEMENT9 declaration_pntc[] =
8185     {
8186         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8187         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8188         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8189         D3DDECL_END()
8190     };
8191     D3DVERTEXELEMENT9 declaration_ptcn[] =
8192     {
8193         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8194         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8195         {0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8196         D3DDECL_END()
8197     };
8198     D3DVERTEXELEMENT9 declaration_ptc[] =
8199     {
8200         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8201         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8202         D3DDECL_END()
8203     };
8204     D3DVERTEXELEMENT9 declaration_ptc_float16_2[] =
8205     {
8206         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8207         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8208         D3DDECL_END()
8209     };
8210     D3DVERTEXELEMENT9 declaration_ptc_float16_4[] =
8211     {
8212         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8213         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8214         D3DDECL_END()
8215     };
8216     D3DVERTEXELEMENT9 declaration_ptc_float1[] =
8217     {
8218         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8219         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8220         D3DDECL_END()
8221     };
8222     D3DVERTEXELEMENT9 declaration_ptc_float3[] =
8223     {
8224         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8225         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8226         D3DDECL_END()
8227     };
8228     D3DVERTEXELEMENT9 declaration_ptc_float4[] =
8229     {
8230         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8231         {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8232         D3DDECL_END()
8233     };
8234     D3DVERTEXELEMENT9 declaration_ptc_d3dcolor[] =
8235     {
8236         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8237         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8238         D3DDECL_END()
8239     };
8240     D3DVERTEXELEMENT9 declaration_ptc_ubyte4[] =
8241     {
8242         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8243         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8244         D3DDECL_END()
8245     };
8246     D3DVERTEXELEMENT9 declaration_ptc_ubyte4n[] =
8247     {
8248         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8249         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8250         D3DDECL_END()
8251     };
8252     D3DVERTEXELEMENT9 declaration_ptc_short2[] =
8253     {
8254         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8255         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8256         D3DDECL_END()
8257     };
8258     D3DVERTEXELEMENT9 declaration_ptc_short4[] =
8259     {
8260         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8261         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8262         D3DDECL_END()
8263     };
8264     D3DVERTEXELEMENT9 declaration_ptc_short2n[] =
8265     {
8266         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8267         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8268         D3DDECL_END()
8269     };
8270     D3DVERTEXELEMENT9 declaration_ptc_short4n[] =
8271     {
8272         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8273         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8274         D3DDECL_END()
8275     };
8276     D3DVERTEXELEMENT9 declaration_ptc_ushort2n[] =
8277     {
8278         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8279         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8280         D3DDECL_END()
8281     };
8282     D3DVERTEXELEMENT9 declaration_ptc_ushort4n[] =
8283     {
8284         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8285         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8286         D3DDECL_END()
8287     };
8288     D3DVERTEXELEMENT9 declaration_ptc_float16_2_partialu[] =
8289     {
8290         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8291         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_PARTIALU, D3DDECLUSAGE_TEXCOORD, 0},
8292         D3DDECL_END()
8293     };
8294     D3DVERTEXELEMENT9 declaration_pntc1[] =
8295     {
8296         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8297         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8298         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
8299         D3DDECL_END()
8300     };
8301     const unsigned int VERTS_PER_FACE = 3;
8302     BYTE *vertices = NULL;
8303     INT i;
8304     struct vertex_pn
8305     {
8306         D3DXVECTOR3 position;
8307         D3DXVECTOR3 normal;
8308     };
8309     struct vertex_pntc
8310     {
8311         D3DXVECTOR3 position;
8312         D3DXVECTOR3 normal;
8313         D3DXVECTOR2 texcoords;
8314     };
8315     struct vertex_ptcn
8316     {
8317         D3DXVECTOR3 position;
8318         D3DXVECTOR2 texcoords;
8319         D3DXVECTOR3 normal;
8320     };
8321     struct vertex_ptc
8322     {
8323         D3DXVECTOR3 position;
8324         D3DXVECTOR2 texcoords;
8325     };
8326     struct vertex_ptc_float16_2
8327     {
8328         D3DXVECTOR3 position;
8329         WORD texcoords[2]; /* float16_2 */
8330     };
8331     struct vertex_ptc_float16_4
8332     {
8333         D3DXVECTOR3 position;
8334         WORD texcoords[4]; /* float16_4 */
8335     };
8336     struct vertex_ptc_float1
8337     {
8338         D3DXVECTOR3 position;
8339         FLOAT texcoords;
8340     };
8341     struct vertex_ptc_float3
8342     {
8343         D3DXVECTOR3 position;
8344         FLOAT texcoords[3];
8345     };
8346     struct vertex_ptc_float4
8347     {
8348         D3DXVECTOR3 position;
8349         FLOAT texcoords[4];
8350     };
8351     struct vertex_ptc_d3dcolor
8352     {
8353         D3DXVECTOR3 position;
8354         BYTE texcoords[4];
8355     };
8356     struct vertex_ptc_ubyte4
8357     {
8358         D3DXVECTOR3 position;
8359         BYTE texcoords[4];
8360     };
8361     struct vertex_ptc_ubyte4n
8362     {
8363         D3DXVECTOR3 position;
8364         BYTE texcoords[4];
8365     };
8366     struct vertex_ptc_short2
8367     {
8368         D3DXVECTOR3 position;
8369         SHORT texcoords[2];
8370     };
8371     struct vertex_ptc_short4
8372     {
8373         D3DXVECTOR3 position;
8374         SHORT texcoords[4];
8375     };
8376     struct vertex_ptc_ushort2n
8377     {
8378         D3DXVECTOR3 position;
8379         USHORT texcoords[2];
8380     };
8381     struct vertex_ptc_ushort4n
8382     {
8383         D3DXVECTOR3 position;
8384         USHORT texcoords[4];
8385     };
8386     struct vertex_ptc_udec3
8387     {
8388         D3DXVECTOR3 position;
8389         DWORD texcoords;
8390     };
8391     struct vertex_ptc_dec3n
8392     {
8393         D3DXVECTOR3 position;
8394         DWORD texcoords;
8395     };
8396     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
8397     D3DXVECTOR2 zero_vec2 = {0.0f, 0.0f};
8398     /* Test 0. Check that a mesh can be cloned if the new declaration is the
8399      * same as the one used to create the mesh.
8400      *
8401      * 0--1 3
8402      * | / /|
8403      * |/ / |
8404      * 2 5--4
8405      */
8406     const struct vertex_pn vertices0[] =
8407     {
8408         {{ 0.0f,  3.0f,  0.f}, up},
8409         {{ 2.0f,  3.0f,  0.f}, up},
8410         {{ 0.0f,  0.0f,  0.f}, up},
8411
8412         {{ 3.0f,  3.0f,  0.f}, up},
8413         {{ 3.0f,  0.0f,  0.f}, up},
8414         {{ 1.0f,  0.0f,  0.f}, up},
8415     };
8416     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
8417     const UINT num_faces0 = ARRAY_SIZE(vertices0) / VERTS_PER_FACE;
8418     const UINT vertex_size0 = sizeof(*vertices0);
8419     /* Test 1. Check that 16-bit indices are handled. */
8420     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
8421     /* Test 2. Check that the size of each vertex is increased and the data
8422      * moved if the new declaration adds an element after the original elements.
8423      */
8424     const struct vertex_pntc exp_vertices2[] =
8425     {
8426         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8427         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8428         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8429
8430         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8431         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8432         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8433     };
8434     const UINT exp_vertex_size2 = sizeof(*exp_vertices2);
8435     /* Test 3. Check that the size of each vertex is increased and the data
8436      * moved if the new declaration adds an element between the original
8437      * elements.
8438      */
8439     const struct vertex_ptcn exp_vertices3[] =
8440     {
8441         {{ 0.0f,  3.0f,  0.f}, zero_vec2, up},
8442         {{ 2.0f,  3.0f,  0.f}, zero_vec2, up},
8443         {{ 0.0f,  0.0f,  0.f}, zero_vec2, up},
8444
8445         {{ 3.0f,  3.0f,  0.f}, zero_vec2, up},
8446         {{ 3.0f,  0.0f,  0.f}, zero_vec2, up},
8447         {{ 1.0f,  0.0f,  0.f}, zero_vec2, up},
8448     };
8449     const UINT exp_vertex_size3 = sizeof(*exp_vertices3);
8450     /* Test 4. Test that data types can be converted, e.g. FLOAT2 to FLOAT16_2. */
8451     const struct vertex_ptc vertices4[] =
8452     {
8453         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8454         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8455         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8456
8457         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8458         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8459         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8460     };
8461     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
8462     const UINT num_faces4 = ARRAY_SIZE(vertices4) / VERTS_PER_FACE;
8463     const UINT vertex_size4 = sizeof(*vertices4);
8464     const struct vertex_ptc_float16_2 exp_vertices4[] =
8465     {
8466         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8467         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
8468         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
8469
8470         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
8471         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8472         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
8473     };
8474     const UINT exp_vertex_size4 = sizeof(*exp_vertices4);
8475     /* Test 5. Convert FLOAT2 to FLOAT16_4. */
8476     const struct vertex_ptc vertices5[] =
8477     {
8478         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8479         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8480         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8481
8482         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8483         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8484         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8485     };
8486     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
8487     const UINT num_faces5 = ARRAY_SIZE(vertices5) / VERTS_PER_FACE;
8488     const UINT vertex_size5 = sizeof(*vertices5);
8489     const struct vertex_ptc_float16_4 exp_vertices5[] =
8490     {
8491         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8492         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0, 0x3c00}}, /* {0.5f, 0.7f, 0.0f, 1.0f} */
8493         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0, 0x3c00}}, /* {-0.2f, -0.3f, 0.0f, 1.0f} */
8494
8495         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0, 0x3c00}}, /* {0.2f, 0.3f, 0.0f, 1.0f} */
8496         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8497         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0, 0x3c00}}, /* {0.1f, 0.2f, 0.0f, 1.0f} */
8498     };
8499     const UINT exp_vertex_size5 = sizeof(*exp_vertices5);
8500     /* Test 6. Convert FLOAT2 to FLOAT1. */
8501     const struct vertex_ptc vertices6[] =
8502     {
8503         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8504         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8505         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8506
8507         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8508         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8509         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8510     };
8511     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
8512     const UINT num_faces6 = ARRAY_SIZE(vertices6) / VERTS_PER_FACE;
8513     const UINT vertex_size6 = sizeof(*vertices6);
8514     const struct vertex_ptc_float1 exp_vertices6[] =
8515     {
8516         {{ 0.0f,  3.0f,  0.f},  1.0f},
8517         {{ 2.0f,  3.0f,  0.f},  0.5f},
8518         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8519
8520         {{ 3.0f,  3.0f,  0.f},  0.2f},
8521         {{ 3.0f,  0.0f,  0.f},  1.0f},
8522         {{ 1.0f,  0.0f,  0.f},  0.1f},
8523     };
8524     const UINT exp_vertex_size6 = sizeof(*exp_vertices6);
8525     /* Test 7. Convert FLOAT2 to FLOAT3. */
8526     const struct vertex_ptc vertices7[] =
8527     {
8528         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8529         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8530         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8531
8532         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8533         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8534         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8535     };
8536     const UINT num_vertices7 = ARRAY_SIZE(vertices7);
8537     const UINT num_faces7 = ARRAY_SIZE(vertices7) / VERTS_PER_FACE;
8538     const UINT vertex_size7 = sizeof(*vertices7);
8539     const struct vertex_ptc_float3 exp_vertices7[] =
8540     {
8541         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8542         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f}},
8543         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f}},
8544
8545         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f}},
8546         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8547         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f}},
8548     };
8549     const UINT exp_vertex_size7 = sizeof(*exp_vertices7);
8550     /* Test 8. Convert FLOAT2 to FLOAT4. */
8551     const struct vertex_ptc vertices8[] =
8552     {
8553         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8554         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8555         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8556
8557         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8558         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8559         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8560     };
8561     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
8562     const UINT num_faces8 = ARRAY_SIZE(vertices8) / VERTS_PER_FACE;
8563     const UINT vertex_size8 = sizeof(*vertices8);
8564     const struct vertex_ptc_float4 exp_vertices8[] =
8565     {
8566         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
8567         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f, 1.0f}},
8568         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f, 1.0f}},
8569
8570         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f, 1.0f}},
8571         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
8572         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f, 1.0f}},
8573     };
8574     const UINT exp_vertex_size8 = sizeof(*exp_vertices8);
8575     /* Test 9. Convert FLOAT2 to D3DCOLOR. */
8576     const struct vertex_ptc vertices9[] =
8577     {
8578         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8579         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8580         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.6f}},
8581
8582         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8583         {{ 3.0f,  0.0f,  0.f}, { 2.0f, 256.0f}},
8584         {{ 1.0f,  0.0f,  0.f}, { 0.11f,  0.2f}},
8585     };
8586     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
8587     const UINT num_faces9 = ARRAY_SIZE(vertices9) / VERTS_PER_FACE;
8588     const UINT vertex_size9 = sizeof(*vertices9);
8589     const struct vertex_ptc_d3dcolor exp_vertices9[] =
8590     {
8591         {{ 0.0f,  3.0f,  0.f}, {0, 255, 255, 255}},
8592         {{ 2.0f,  3.0f,  0.f}, {0, 179, 128, 255}},
8593         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
8594
8595         {{ 3.0f,  3.0f,  0.f}, {0, 77, 51, 255}},
8596         {{ 3.0f,  0.0f,  0.f}, {0, 255, 255, 255}},
8597         {{ 1.0f,  0.0f,  0.f}, {0, 51, 28, 255}},
8598     };
8599     const UINT exp_vertex_size9 = sizeof(*exp_vertices9);
8600     /* Test 10. Convert FLOAT2 to UBYTE4. */
8601     const struct vertex_ptc vertices10[] =
8602     {
8603         {{ 0.0f,  3.0f,  0.f}, { 0.0f,  1.0f}},
8604         {{ 2.0f,  3.0f,  0.f}, { 2.0f,  3.0f}},
8605         {{ 0.0f,  0.0f,  0.f}, { 254.0f,  255.0f}},
8606
8607         {{ 3.0f,  3.0f,  0.f}, { 256.0f, 257.0f}},
8608         {{ 3.0f,  0.0f,  0.f}, { 1.4f, 1.5f}},
8609         {{ 1.0f,  0.0f,  0.f}, {-4.0f, -5.0f}},
8610     };
8611     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
8612     const UINT num_faces10 = ARRAY_SIZE(vertices10) / VERTS_PER_FACE;
8613     const UINT vertex_size10 = sizeof(*vertices10);
8614     const struct vertex_ptc_ubyte4 exp_vertices10[] =
8615     {
8616         {{ 0.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8617         {{ 2.0f,  3.0f,  0.f}, {2, 3, 0, 1}},
8618         {{ 0.0f,  0.0f,  0.f}, {254, 255, 0, 1}},
8619
8620         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8621         {{ 3.0f,  0.0f,  0.f}, {1, 2, 0, 1}},
8622         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
8623     };
8624     const UINT exp_vertex_size10 = sizeof(*exp_vertices10);
8625     /* Test 11. Convert FLOAT2 to SHORT2. */
8626     const struct vertex_ptc vertices11[] =
8627     {
8628         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
8629         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
8630         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
8631
8632         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8633         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
8634         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
8635
8636         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
8637         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
8638         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
8639     };
8640     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
8641     const UINT num_faces11 = ARRAY_SIZE(vertices11) / VERTS_PER_FACE;
8642     const UINT vertex_size11 = sizeof(*vertices11);
8643     const struct vertex_ptc_short2 exp_vertices11[] =
8644     {
8645         {{ 0.0f,  3.0f,  0.f}, {1, 0}},
8646         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
8647         {{ 0.0f,  0.0f,  0.f}, {0, -4}},
8648
8649         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1}},
8650         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN}},
8651         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
8652
8653         {{ 4.0f,  3.0f,  0.f}, {-2, 1}},
8654         {{ 6.0f,  0.0f,  0.f}, {32765, -32767}},
8655         {{ 4.0f,  0.0f,  0.f}, {-4, 1}},
8656     };
8657     const UINT exp_vertex_size11 = sizeof(*exp_vertices11);
8658     /* Test 12. Convert FLOAT2 to SHORT4. */
8659     const struct vertex_ptc vertices12[] =
8660     {
8661         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
8662         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
8663         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
8664
8665         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8666         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
8667         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
8668
8669         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
8670         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
8671         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
8672     };
8673     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
8674     const UINT num_faces12 = ARRAY_SIZE(vertices12) / VERTS_PER_FACE;
8675     const UINT vertex_size12 = sizeof(*vertices12);
8676     const struct vertex_ptc_short4 exp_vertices12[] =
8677     {
8678         {{ 0.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
8679         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8680         {{ 0.0f,  0.0f,  0.f}, {0, -4, 0, 1}},
8681
8682         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1, 0, 1}},
8683         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN, 0, 1}},
8684         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, 0, 1}},
8685
8686         {{ 4.0f,  3.0f,  0.f}, {-2, 1, 0, 1}},
8687         {{ 6.0f,  0.0f,  0.f}, {32765, -32767, 0, 1}},
8688         {{ 4.0f,  0.0f,  0.f}, {-4, 1, 0, 1}},
8689     };
8690     const UINT exp_vertex_size12 = sizeof(*exp_vertices12);
8691     /* Test 13. Convert FLOAT2 to UBYTE4N. */
8692     const struct vertex_ptc vertices13[] =
8693     {
8694         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  2.0f}},
8695         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8696         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.5f}},
8697
8698         {{ 3.0f,  3.0f,  0.f}, {-0.6f,  -1.0f}},
8699         {{ 3.0f,  0.0f,  0.f}, {UCHAR_MAX,  UCHAR_MAX + 1}},
8700         {{ 1.0f,  0.0f,  0.f}, {2 * UCHAR_MAX, -UCHAR_MAX}},
8701     };
8702     const UINT num_vertices13 = ARRAY_SIZE(vertices13);
8703     const UINT num_faces13 = ARRAY_SIZE(vertices13) / VERTS_PER_FACE;
8704     const UINT vertex_size13 = sizeof(*vertices13);
8705     const struct vertex_ptc_ubyte4n exp_vertices13[] =
8706     {
8707         {{ 0.0f,  3.0f,  0.f}, {255, 255, 0, 255}},
8708         {{ 2.0f,  3.0f,  0.f}, {128, 179, 0, 255}},
8709         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
8710
8711         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, 255}},
8712         {{ 3.0f,  0.0f,  0.f}, {255, 255, 0, 255}},
8713         {{ 1.0f,  0.0f,  0.f}, {255, 0, 0, 255}},
8714     };
8715     const UINT exp_vertex_size13 = sizeof(*exp_vertices13);
8716     /* Test 14. Convert FLOAT2 to SHORT2N. */
8717     const struct vertex_ptc vertices14[] =
8718     {
8719         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8720         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8721         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8722
8723         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8724         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
8725         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8726     };
8727     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
8728     const UINT num_faces14 = ARRAY_SIZE(vertices14) / VERTS_PER_FACE;
8729     const UINT vertex_size14 = sizeof(*vertices14);
8730     const struct vertex_ptc_short2 exp_vertices14[] =
8731     {
8732         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX}},
8733         {{ 2.0f,  3.0f,  0.f}, {13107, 16384}},
8734         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2}},
8735
8736         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383}},
8737         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3}},
8738         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2}},
8739     };
8740     const UINT exp_vertex_size14 = sizeof(*exp_vertices14);
8741     /* Test 15. Convert FLOAT2 to SHORT4N. */
8742     const struct vertex_ptc vertices15[] =
8743     {
8744         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8745         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8746         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8747
8748         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8749         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
8750         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8751     };
8752     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
8753     const UINT num_faces15 = ARRAY_SIZE(vertices15) / VERTS_PER_FACE;
8754     const UINT vertex_size15 = sizeof(*vertices15);
8755     const struct vertex_ptc_short4 exp_vertices15[] =
8756     {
8757         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX, 0, SHRT_MAX}},
8758         {{ 2.0f,  3.0f,  0.f}, {13107, 16384, 0, SHRT_MAX}},
8759         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2, 0, SHRT_MAX}},
8760
8761         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383, 0, SHRT_MAX}},
8762         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3, 0, SHRT_MAX}},
8763         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2, 0, SHRT_MAX}},
8764     };
8765     const UINT exp_vertex_size15 = sizeof(*exp_vertices15);
8766     /* Test 16. Convert FLOAT2 to USHORT2N. */
8767     const struct vertex_ptc vertices16[] =
8768     {
8769         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8770         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8771         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8772
8773         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8774         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
8775         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
8776     };
8777     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
8778     const UINT num_faces16 = ARRAY_SIZE(vertices16) / VERTS_PER_FACE;
8779     const UINT vertex_size16 = sizeof(*vertices16);
8780     const struct vertex_ptc_ushort2n exp_vertices16[] =
8781     {
8782         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX}},
8783         {{ 2.0f,  3.0f,  0.f}, {26214, 32768}},
8784         {{ 0.0f,  0.0f,  0.f}, {39321, 0}},
8785
8786         {{ 3.0f,  3.0f,  0.f}, {0, 0}},
8787         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1}},
8788         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0}},
8789     };
8790     const UINT exp_vertex_size16 = sizeof(*exp_vertices16);
8791     /* Test 17. Convert FLOAT2 to USHORT4N. */
8792     const struct vertex_ptc vertices17[] =
8793     {
8794         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8795         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8796         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8797
8798         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8799         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
8800         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
8801     };
8802     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
8803     const UINT num_faces17 = ARRAY_SIZE(vertices17) / VERTS_PER_FACE;
8804     const UINT vertex_size17 = sizeof(*vertices17);
8805     const struct vertex_ptc_ushort4n exp_vertices17[] =
8806     {
8807         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX, 0, USHRT_MAX}},
8808         {{ 2.0f,  3.0f,  0.f}, {26214, 32768, 0, USHRT_MAX}},
8809         {{ 0.0f,  0.0f,  0.f}, {39321, 0, 0, USHRT_MAX}},
8810
8811         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, USHRT_MAX}},
8812         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1, 0, USHRT_MAX}},
8813         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0, 0, USHRT_MAX}},
8814     };
8815     const UINT exp_vertex_size17 = sizeof(*exp_vertices17);
8816     /* Test 18. Test that the method field is compared by converting a FLOAT2 to
8817      * FLOAT16_2. where the method field has been change from
8818      * D3DDECLMETHOD_DEFAULT to D3DDECLMETHOD_PARTIALU. */
8819     const struct vertex_ptc vertices18[] =
8820     {
8821         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8822         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8823         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8824
8825         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8826         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8827         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8828     };
8829     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
8830     const UINT num_faces18 = ARRAY_SIZE(vertices18) / VERTS_PER_FACE;
8831     const UINT vertex_size18 = sizeof(*vertices18);
8832     const struct vertex_ptc_float16_2 exp_vertices18[] =
8833     {
8834         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8835         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
8836         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
8837
8838         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
8839         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8840         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
8841     };
8842     const UINT exp_vertex_size18 = sizeof(*exp_vertices18);
8843     /* Test 19. Test that data is lost if usage index changes, e.g. TEXCOORD0
8844      * TEXCOORD1. */
8845     const struct vertex_pntc vertices19[] =
8846     {
8847         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
8848         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
8849         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
8850
8851         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
8852         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
8853         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
8854     };
8855     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
8856     const UINT num_faces19 = ARRAY_SIZE(vertices19) / VERTS_PER_FACE;
8857     const UINT vertex_size19 = sizeof(*vertices19);
8858     const struct vertex_pntc exp_vertices19[] =
8859     {
8860         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8861         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8862         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8863
8864         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8865         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8866         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8867     };
8868     const UINT exp_vertex_size19 = sizeof(*exp_vertices19);
8869     /* Test 20. Another test that data is lost if usage index changes, e.g.
8870      * TEXCOORD1 to TEXCOORD0. */
8871     const struct vertex_pntc vertices20[] =
8872     {
8873         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
8874         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
8875         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
8876
8877         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
8878         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
8879         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
8880     };
8881     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
8882     const UINT num_faces20 = ARRAY_SIZE(vertices20) / VERTS_PER_FACE;
8883     const UINT vertex_size20 = sizeof(*vertices20);
8884     const struct vertex_pntc exp_vertices20[] =
8885     {
8886         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8887         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8888         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8889
8890         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8891         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8892         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8893     };
8894     const UINT exp_vertex_size20 = sizeof(*exp_vertices20);
8895     /* Test 21. Convert FLOAT1 to FLOAT2. */
8896     const struct vertex_ptc_float1 vertices21[] =
8897     {
8898         {{ 0.0f,  3.0f,  0.f},  1.0f},
8899         {{ 2.0f,  3.0f,  0.f},  0.5f},
8900         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8901
8902         {{ 3.0f,  3.0f,  0.f},  0.2f},
8903         {{ 3.0f,  0.0f,  0.f},  1.0f},
8904         {{ 1.0f,  0.0f,  0.f},  0.1f},
8905     };
8906     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
8907     const UINT num_faces21 = ARRAY_SIZE(vertices21) / VERTS_PER_FACE;
8908     const UINT vertex_size21 = sizeof(*vertices21);
8909     const struct vertex_ptc exp_vertices21[] =
8910     {
8911         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f}},
8912         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f}},
8913         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f}},
8914
8915         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f}},
8916         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f}},
8917         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f}},
8918     };
8919     const UINT exp_vertex_size21 = sizeof(*exp_vertices21);
8920     /* Test 22. Convert FLOAT1 to FLOAT3. */
8921     const struct vertex_ptc_float1 vertices22[] =
8922     {
8923         {{ 0.0f,  3.0f,  0.f},  1.0f},
8924         {{ 2.0f,  3.0f,  0.f},  0.5f},
8925         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8926
8927         {{ 3.0f,  3.0f,  0.f},  0.2f},
8928         {{ 3.0f,  0.0f,  0.f},  1.0f},
8929         {{ 1.0f,  0.0f,  0.f},  0.1f},
8930     };
8931     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
8932     const UINT num_faces22 = ARRAY_SIZE(vertices22) / VERTS_PER_FACE;
8933     const UINT vertex_size22 = sizeof(*vertices22);
8934     const struct vertex_ptc_float3 exp_vertices22[] =
8935     {
8936         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
8937         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f}},
8938         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f}},
8939
8940         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f}},
8941         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
8942         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f}},
8943     };
8944     const UINT exp_vertex_size22 = sizeof(*exp_vertices22);
8945     /* Test 23. Convert FLOAT1 to FLOAT4. */
8946     const struct vertex_ptc_float1 vertices23[] =
8947     {
8948         {{ 0.0f,  3.0f,  0.f},  1.0f},
8949         {{ 2.0f,  3.0f,  0.f},  0.5f},
8950         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8951
8952         {{ 3.0f,  3.0f,  0.f},  0.2f},
8953         {{ 3.0f,  0.0f,  0.f},  1.0f},
8954         {{ 1.0f,  0.0f,  0.f},  0.1f},
8955     };
8956     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
8957     const UINT num_faces23 = ARRAY_SIZE(vertices23) / VERTS_PER_FACE;
8958     const UINT vertex_size23 = sizeof(*vertices23);
8959     const struct vertex_ptc_float4 exp_vertices23[] =
8960     {
8961         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
8962         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f, 1.0f}},
8963         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f, 1.0f}},
8964
8965         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f, 1.0f}},
8966         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
8967         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f, 1.0f}},
8968     };
8969     const UINT exp_vertex_size23 = sizeof(*exp_vertices23);
8970     /* Test 24. Convert FLOAT1 to D3DCOLOR. */
8971     const struct vertex_ptc_float1 vertices24[] =
8972     {
8973         {{ 0.0f,  3.0f,  0.f},  1.0f},
8974         {{ 2.0f,  3.0f,  0.f},  0.5f},
8975         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8976
8977         {{ 3.0f,  3.0f,  0.f},  0.2f},
8978         {{ 3.0f,  0.0f,  0.f},  1.0f},
8979         {{ 1.0f,  0.0f,  0.f},  0.11f},
8980     };
8981     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
8982     const UINT num_faces24 = ARRAY_SIZE(vertices24) / VERTS_PER_FACE;
8983     const UINT vertex_size24 = sizeof(*vertices24);
8984     const struct vertex_ptc_d3dcolor exp_vertices24[] =
8985     {
8986         {{ 0.0f,  3.0f,  0.f}, {0, 0, 255, 255}},
8987         {{ 2.0f,  3.0f,  0.f}, {0, 0, 128, 255}},
8988         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
8989
8990         {{ 3.0f,  3.0f,  0.f}, {0, 0, 51, 255}},
8991         {{ 3.0f,  0.0f,  0.f}, {0, 0, 255, 255}},
8992         {{ 1.0f,  0.0f,  0.f}, {0, 0, 28, 255}},
8993     };
8994     const UINT exp_vertex_size24 = sizeof(*exp_vertices24);
8995     /* Test 25. Convert FLOAT1 to ubyte4. */
8996     const struct vertex_ptc_float1 vertices25[] =
8997     {
8998         {{ 0.0f,  3.0f,  0.f}, 0.0f},
8999         {{ 2.0f,  3.0f,  0.f}, 1.4f},
9000         {{ 0.0f,  0.0f,  0.f}, 1.5f},
9001
9002         {{ 3.0f,  3.0f,  0.f}, 255.0f},
9003         {{ 3.0f,  0.0f,  0.f}, 256.0f},
9004         {{ 1.0f,  0.0f,  0.f}, -1.0f},
9005     };
9006     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
9007     const UINT num_faces25 = ARRAY_SIZE(vertices25) / VERTS_PER_FACE;
9008     const UINT vertex_size25 = sizeof(*vertices25);
9009     const struct vertex_ptc_ubyte4 exp_vertices25[] =
9010     {
9011         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 1}},
9012         {{ 2.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
9013         {{ 0.0f,  0.0f,  0.f}, {2, 0, 0, 1}},
9014
9015         {{ 3.0f,  3.0f,  0.f}, {255, 0, 0, 1}},
9016         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9017         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9018     };
9019     const UINT exp_vertex_size25 = sizeof(*exp_vertices25);
9020     /* Test 26. Convert FLOAT4 to D3DCOLOR. */
9021     const struct vertex_ptc_float4 vertices26[] =
9022     {
9023         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.5f}},
9024         {{ 2.0f,  3.0f,  0.f}, {-0.4f, -0.5f, -1.0f, -2.0f}},
9025         {{ 0.0f,  0.0f,  0.f}, {254.0f, 255.0f, 256.0f, 257.0f}},
9026
9027         {{ 3.0f,  3.0f,  0.f}, {0.1f, 0.2f, 0.3f, 0.4f}},
9028         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.6f, 0.7f, 0.8f}},
9029         {{ 1.0f,  0.0f,  0.f}, {0.9f, 0.99f, 0.995f, 0.999f}},
9030     };
9031     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
9032     const UINT num_faces26 = ARRAY_SIZE(vertices26) / VERTS_PER_FACE;
9033     const UINT vertex_size26 = sizeof(*vertices26);
9034     const struct vertex_ptc_d3dcolor exp_vertices26[] =
9035     {
9036         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9037         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9038         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9039
9040         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9041         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9042         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9043     };
9044     const UINT exp_vertex_size26 = sizeof(*exp_vertices26);
9045     /* Test 27. Convert D3DCOLOR to FLOAT4. */
9046     const struct vertex_ptc_d3dcolor vertices27[] =
9047     {
9048         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9049         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9050         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9051
9052         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9053         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9054         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9055     };
9056     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
9057     const UINT num_faces27 = ARRAY_SIZE(vertices27) / VERTS_PER_FACE;
9058     const UINT vertex_size27 = sizeof(*vertices27);
9059     const struct vertex_ptc_float4 exp_vertices27[] =
9060     {
9061         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.501961f}},
9062         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9063         {{ 0.0f,  0.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9064
9065         {{ 3.0f,  3.0f,  0.f}, {0.101961f, 0.2f, 0.301961f, 0.4f}},
9066         {{ 3.0f,  0.0f,  0.f}, {0.501961f, 0.6f, 0.701961f, 0.8f}},
9067         {{ 1.0f,  0.0f,  0.f}, {0.901961f, 0.988235f, 0.996078f, 1.0f}},
9068     };
9069     const UINT exp_vertex_size27 = sizeof(*exp_vertices27);
9070     /* Test 28. Convert UBYTE4 to FLOAT4. */
9071     const struct vertex_ptc_ubyte4 vertices28[] =
9072     {
9073         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9074         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9075         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9076
9077         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9078         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9079         {{ 1.0f,  0.0f,  0.f}, {50, 60, 127, 255}},
9080     };
9081     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
9082     const UINT num_faces28 = ARRAY_SIZE(vertices28) / VERTS_PER_FACE;
9083     const UINT vertex_size28 = sizeof(*vertices28);
9084     const struct vertex_ptc_float4 exp_vertices28[] =
9085     {
9086         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9087         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9088         {{ 0.0f,  0.0f,  0.f}, {1.0f,  0.0f, 1.0f, 0.0f}},
9089
9090         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9091         {{ 3.0f,  0.0f,  0.f}, {10.0f, 20.0f, 30.0f, 40.0f}},
9092         {{ 1.0f,  0.0f,  0.f}, {50.0f, 60.0f, 127.0f, 255.0f}},
9093     };
9094     const UINT exp_vertex_size28 = sizeof(*exp_vertices28);
9095     /* Test 29. Convert SHORT2 to FLOAT4. */
9096     const struct vertex_ptc_short2 vertices29[] =
9097     {
9098         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9099         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9100         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9101
9102         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9103         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX}},
9104         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9105     };
9106     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
9107     const UINT num_faces29 = ARRAY_SIZE(vertices29) / VERTS_PER_FACE;
9108     const UINT vertex_size29 = sizeof(*vertices29);
9109     const struct vertex_ptc_float4 exp_vertices29[] =
9110     {
9111         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9112         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9113         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 0.0f, 1.0f}},
9114
9115         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9116         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 0.0f, 1.0f}},
9117         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, 0.0f, 1.0f}},
9118     };
9119     const UINT exp_vertex_size29 = sizeof(*exp_vertices29);
9120     /* Test 29. Convert SHORT4 to FLOAT4. */
9121     const struct vertex_ptc_short4 vertices30[] =
9122     {
9123         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9124         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9125         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9126
9127         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9128         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1, 0}},
9129         {{ 1.0f,  0.0f,  0.f}, {-42, 42, SHRT_MAX, SHRT_MIN}},
9130     };
9131     const UINT num_vertices30 = ARRAY_SIZE(vertices30);
9132     const UINT num_faces30 = ARRAY_SIZE(vertices30) / VERTS_PER_FACE;
9133     const UINT vertex_size30 = sizeof(*vertices30);
9134     const struct vertex_ptc_float4 exp_vertices30[] =
9135     {
9136         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9137         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9138         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9139
9140         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9141         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1.0f, 0.0f}},
9142         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, SHRT_MAX, SHRT_MIN}},
9143     };
9144     const UINT exp_vertex_size30 = sizeof(*exp_vertices30);
9145     /* Test 31. Convert UBYTE4N to FLOAT4. */
9146     const struct vertex_ptc_ubyte4n vertices31[] =
9147     {
9148         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9149         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9150         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9151
9152         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9153         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9154         {{ 1.0f,  0.0f,  0.f}, {50, 60, 70, UCHAR_MAX}},
9155     };
9156     const UINT num_vertices31 = ARRAY_SIZE(vertices31);
9157     const UINT num_faces31 = ARRAY_SIZE(vertices31) / VERTS_PER_FACE;
9158     const UINT vertex_size31 = sizeof(*vertices31);
9159     const struct vertex_ptc_float4 exp_vertices31[] =
9160     {
9161         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9162         {{ 2.0f,  3.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX}},
9163         {{ 0.0f,  0.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX, 0.0f}},
9164
9165         {{ 3.0f,  3.0f,  0.f}, {0.0f, (FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX}},
9166         {{ 3.0f,  0.0f,  0.f}, {(FLOAT)10/UCHAR_MAX, (FLOAT)20/UCHAR_MAX, (FLOAT)30/UCHAR_MAX, (FLOAT)40/UCHAR_MAX}},
9167         {{ 1.0f,  0.0f,  0.f}, {(FLOAT)50/UCHAR_MAX, (FLOAT)60/UCHAR_MAX, (FLOAT)70/UCHAR_MAX, 1.0f}},
9168     };
9169     const UINT exp_vertex_size31 = sizeof(*exp_vertices31);
9170     /* Test 32. Convert SHORT2N to FLOAT4. */
9171     const struct vertex_ptc_short2 vertices32[] =
9172     {
9173         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9174         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9175         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9176
9177         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9178         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
9179         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9180     };
9181     const UINT num_vertices32 = ARRAY_SIZE(vertices32);
9182     const UINT num_faces32 = ARRAY_SIZE(vertices32) / VERTS_PER_FACE;
9183     const UINT vertex_size32 = sizeof(*vertices32);
9184     const struct vertex_ptc_float4 exp_vertices32[] =
9185     {
9186         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9187         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9188         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 0.0f, 1.0f}},
9189
9190         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9191         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, 0.0f, 1.0f}},
9192         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 0.0f, 1.0f}},
9193     };
9194     const UINT exp_vertex_size32 = sizeof(*exp_vertices32);
9195     /* Test 33. Convert SHORT4N to FLOAT4. */
9196     const struct vertex_ptc_short4 vertices33[] =
9197     {
9198         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9199         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9200         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9201
9202         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9203         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, SHRT_MIN + 1, SHRT_MAX}},
9204         {{ 1.0f,  0.0f,  0.f}, {-42, 42, 1, 1}},
9205     };
9206     const UINT num_vertices33 = ARRAY_SIZE(vertices33);
9207     const UINT num_faces33 = ARRAY_SIZE(vertices33) / VERTS_PER_FACE;
9208     const UINT vertex_size33 = sizeof(*vertices33);
9209     const struct vertex_ptc_float4 exp_vertices33[] =
9210     {
9211         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9212         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX}},
9213         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX, 0.0f}},
9214
9215         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9216         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, -1.0f, 1.0f}},
9217         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9218     };
9219     const UINT exp_vertex_size33 = sizeof(*exp_vertices33);
9220     /* Test 34. Convert FLOAT16_2 to FLOAT4. */
9221     const struct vertex_ptc_float16_2 vertices34[] =
9222     {
9223         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9224         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9225         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9226
9227         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9228         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9229         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9230     };
9231     const UINT num_vertices34 = ARRAY_SIZE(vertices34);
9232     const UINT num_faces34 = ARRAY_SIZE(vertices34) / VERTS_PER_FACE;
9233     const UINT vertex_size34 = sizeof(*vertices34);
9234     const struct vertex_ptc_float4 exp_vertices34[] =
9235     {
9236         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9237         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.700195f, 0.0f, 1.0f}},
9238         {{ 0.0f,  0.0f,  0.f}, {-0.199951f, -0.300049f, 0.0f, 1.0f}},
9239
9240         {{ 3.0f,  3.0f,  0.f}, {0.199951f, 0.300049f, 0.0f, 1.0f}},
9241         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9242         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.0f, 1.0f}},
9243     };
9244     const UINT exp_vertex_size34 = sizeof(*exp_vertices34);
9245     /* Test 35. Convert FLOAT16_4 to FLOAT4. */
9246     const struct vertex_ptc_float16_4 vertices35[] =
9247     {
9248         {{ 0.0f,  3.0f,  0.f}, {0x0000, 0x0000, 0x0000, 0x0000}},
9249         {{ 2.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
9250         {{ 0.0f,  0.0f,  0.f}, {0x3c00, 0x0000, 0x3c00, 0x0000}},
9251
9252         {{ 3.0f,  3.0f,  0.f}, {0x0000, 0x3c00, 0x0000, 0x3c00}},
9253         {{ 3.0f,  0.0f,  0.f}, {0x3800, 0x399a, 0xb266, 0xb4cd}},
9254         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
9255     };
9256     const UINT num_vertices35 = ARRAY_SIZE(vertices35);
9257     const UINT num_faces35 = ARRAY_SIZE(vertices35) / VERTS_PER_FACE;
9258     const UINT vertex_size35 = sizeof(*vertices35);
9259     const struct vertex_ptc_float4 exp_vertices35[] =
9260     {
9261         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9262         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9263         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9264
9265         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9266         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.700195f, -0.199951f, -0.300049f}},
9267         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.099976f, 0.199951f}},
9268     };
9269     const UINT exp_vertex_size35 = sizeof(*exp_vertices35);
9270     /* Test 36. Check that vertex buffer sharing is ok. */
9271     const struct vertex_pn vertices36[] =
9272     {
9273         {{ 0.0f,  3.0f,  0.f}, up},
9274         {{ 2.0f,  3.0f,  0.f}, up},
9275         {{ 0.0f,  0.0f,  0.f}, up},
9276     };
9277     const UINT num_vertices36 = ARRAY_SIZE(vertices36);
9278     const UINT num_faces36 = ARRAY_SIZE(vertices36) / VERTS_PER_FACE;
9279     const UINT vertex_size36 = sizeof(*vertices36);
9280     const DWORD clone_options36 = options | D3DXMESH_VB_SHARE;
9281     /* Common mesh data */
9282     ID3DXMesh *mesh = NULL;
9283     ID3DXMesh *mesh_clone = NULL;
9284     struct
9285     {
9286         const BYTE *vertices;
9287         const DWORD *indices;
9288         const DWORD *attributes;
9289         const UINT num_vertices;
9290         const UINT num_faces;
9291         const UINT vertex_size;
9292         const DWORD create_options;
9293         const DWORD clone_options;
9294         D3DVERTEXELEMENT9 *declaration;
9295         D3DVERTEXELEMENT9 *new_declaration;
9296         const BYTE *exp_vertices;
9297         const UINT exp_vertex_size;
9298     }
9299     tc[] =
9300     {
9301         {
9302             (BYTE*)vertices0,
9303             NULL,
9304             NULL,
9305             num_vertices0,
9306             num_faces0,
9307             vertex_size0,
9308             options,
9309             options,
9310             declaration_pn,
9311             declaration_pn,
9312             (BYTE*)vertices0,
9313             vertex_size0
9314         },
9315         {
9316             (BYTE*)vertices0,
9317             NULL,
9318             NULL,
9319             num_vertices0,
9320             num_faces0,
9321             vertex_size0,
9322             options_16bit,
9323             options_16bit,
9324             declaration_pn,
9325             declaration_pn,
9326             (BYTE*)vertices0,
9327             vertex_size0
9328         },
9329         {
9330             (BYTE*)vertices0,
9331             NULL,
9332             NULL,
9333             num_vertices0,
9334             num_faces0,
9335             vertex_size0,
9336             options,
9337             options,
9338             declaration_pn,
9339             declaration_pntc,
9340             (BYTE*)exp_vertices2,
9341             exp_vertex_size2
9342         },
9343         {
9344             (BYTE*)vertices0,
9345             NULL,
9346             NULL,
9347             num_vertices0,
9348             num_faces0,
9349             vertex_size0,
9350             options,
9351             options,
9352             declaration_pn,
9353             declaration_ptcn,
9354             (BYTE*)exp_vertices3,
9355             exp_vertex_size3
9356         },
9357         {
9358             (BYTE*)vertices4,
9359             NULL,
9360             NULL,
9361             num_vertices4,
9362             num_faces4,
9363             vertex_size4,
9364             options,
9365             options,
9366             declaration_ptc,
9367             declaration_ptc_float16_2,
9368             (BYTE*)exp_vertices4,
9369             exp_vertex_size4
9370         },
9371         {
9372             (BYTE*)vertices5,
9373             NULL,
9374             NULL,
9375             num_vertices5,
9376             num_faces5,
9377             vertex_size5,
9378             options,
9379             options,
9380             declaration_ptc,
9381             declaration_ptc_float16_4,
9382             (BYTE*)exp_vertices5,
9383             exp_vertex_size5
9384         },
9385         {
9386             (BYTE*)vertices6,
9387             NULL,
9388             NULL,
9389             num_vertices6,
9390             num_faces6,
9391             vertex_size6,
9392             options,
9393             options,
9394             declaration_ptc,
9395             declaration_ptc_float1,
9396             (BYTE*)exp_vertices6,
9397             exp_vertex_size6
9398         },
9399         {
9400             (BYTE*)vertices7,
9401             NULL,
9402             NULL,
9403             num_vertices7,
9404             num_faces7,
9405             vertex_size7,
9406             options,
9407             options,
9408             declaration_ptc,
9409             declaration_ptc_float3,
9410             (BYTE*)exp_vertices7,
9411             exp_vertex_size7
9412         },
9413         {
9414             (BYTE*)vertices8,
9415             NULL,
9416             NULL,
9417             num_vertices8,
9418             num_faces8,
9419             vertex_size8,
9420             options,
9421             options,
9422             declaration_ptc,
9423             declaration_ptc_float4,
9424             (BYTE*)exp_vertices8,
9425             exp_vertex_size8
9426         },
9427         {
9428             (BYTE*)vertices9,
9429             NULL,
9430             NULL,
9431             num_vertices9,
9432             num_faces9,
9433             vertex_size9,
9434             options,
9435             options,
9436             declaration_ptc,
9437             declaration_ptc_d3dcolor,
9438             (BYTE*)exp_vertices9,
9439             exp_vertex_size9
9440         },
9441         {
9442             (BYTE*)vertices10,
9443             NULL,
9444             NULL,
9445             num_vertices10,
9446             num_faces10,
9447             vertex_size10,
9448             options,
9449             options,
9450             declaration_ptc,
9451             declaration_ptc_ubyte4,
9452             (BYTE*)exp_vertices10,
9453             exp_vertex_size10
9454         },
9455         {
9456             (BYTE*)vertices11,
9457             NULL,
9458             NULL,
9459             num_vertices11,
9460             num_faces11,
9461             vertex_size11,
9462             options,
9463             options,
9464             declaration_ptc,
9465             declaration_ptc_short2,
9466             (BYTE*)exp_vertices11,
9467             exp_vertex_size11
9468         },
9469         {
9470             (BYTE*)vertices12,
9471             NULL,
9472             NULL,
9473             num_vertices12,
9474             num_faces12,
9475             vertex_size12,
9476             options,
9477             options,
9478             declaration_ptc,
9479             declaration_ptc_short4,
9480             (BYTE*)exp_vertices12,
9481             exp_vertex_size12
9482         },
9483         {
9484             (BYTE*)vertices13,
9485             NULL,
9486             NULL,
9487             num_vertices13,
9488             num_faces13,
9489             vertex_size13,
9490             options,
9491             options,
9492             declaration_ptc,
9493             declaration_ptc_ubyte4n,
9494             (BYTE*)exp_vertices13,
9495             exp_vertex_size13
9496         },
9497         {
9498             (BYTE*)vertices14,
9499             NULL,
9500             NULL,
9501             num_vertices14,
9502             num_faces14,
9503             vertex_size14,
9504             options,
9505             options,
9506             declaration_ptc,
9507             declaration_ptc_short2n,
9508             (BYTE*)exp_vertices14,
9509             exp_vertex_size14
9510         },
9511         {
9512             (BYTE*)vertices15,
9513             NULL,
9514             NULL,
9515             num_vertices15,
9516             num_faces15,
9517             vertex_size15,
9518             options,
9519             options,
9520             declaration_ptc,
9521             declaration_ptc_short4n,
9522             (BYTE*)exp_vertices15,
9523             exp_vertex_size15
9524         },
9525         {
9526             (BYTE*)vertices16,
9527             NULL,
9528             NULL,
9529             num_vertices16,
9530             num_faces16,
9531             vertex_size16,
9532             options,
9533             options,
9534             declaration_ptc,
9535             declaration_ptc_ushort2n,
9536             (BYTE*)exp_vertices16,
9537             exp_vertex_size16
9538         },
9539         {
9540             (BYTE*)vertices17,
9541             NULL,
9542             NULL,
9543             num_vertices17,
9544             num_faces17,
9545             vertex_size17,
9546             options,
9547             options,
9548             declaration_ptc,
9549             declaration_ptc_ushort4n,
9550             (BYTE*)exp_vertices17,
9551             exp_vertex_size17
9552         },
9553         {
9554             (BYTE*)vertices18,
9555             NULL,
9556             NULL,
9557             num_vertices18,
9558             num_faces18,
9559             vertex_size18,
9560             options,
9561             options,
9562             declaration_ptc,
9563             declaration_ptc_float16_2_partialu,
9564             (BYTE*)exp_vertices18,
9565             exp_vertex_size18
9566         },
9567         {
9568             (BYTE*)vertices19,
9569             NULL,
9570             NULL,
9571             num_vertices19,
9572             num_faces19,
9573             vertex_size19,
9574             options,
9575             options,
9576             declaration_pntc,
9577             declaration_pntc1,
9578             (BYTE*)exp_vertices19,
9579             exp_vertex_size19
9580         },
9581         {
9582             (BYTE*)vertices20,
9583             NULL,
9584             NULL,
9585             num_vertices20,
9586             num_faces20,
9587             vertex_size20,
9588             options,
9589             options,
9590             declaration_pntc1,
9591             declaration_pntc,
9592             (BYTE*)exp_vertices20,
9593             exp_vertex_size20
9594         },
9595         {
9596             (BYTE*)vertices21,
9597             NULL,
9598             NULL,
9599             num_vertices21,
9600             num_faces21,
9601             vertex_size21,
9602             options,
9603             options,
9604             declaration_ptc_float1,
9605             declaration_ptc,
9606             (BYTE*)exp_vertices21,
9607             exp_vertex_size21
9608         },
9609         {
9610             (BYTE*)vertices22,
9611             NULL,
9612             NULL,
9613             num_vertices22,
9614             num_faces22,
9615             vertex_size22,
9616             options,
9617             options,
9618             declaration_ptc_float1,
9619             declaration_ptc_float3,
9620             (BYTE*)exp_vertices22,
9621             exp_vertex_size22
9622         },
9623         {
9624             (BYTE*)vertices23,
9625             NULL,
9626             NULL,
9627             num_vertices23,
9628             num_faces23,
9629             vertex_size23,
9630             options,
9631             options,
9632             declaration_ptc_float1,
9633             declaration_ptc_float4,
9634             (BYTE*)exp_vertices23,
9635             exp_vertex_size23
9636         },
9637         {
9638             (BYTE*)vertices24,
9639             NULL,
9640             NULL,
9641             num_vertices24,
9642             num_faces24,
9643             vertex_size24,
9644             options,
9645             options,
9646             declaration_ptc_float1,
9647             declaration_ptc_d3dcolor,
9648             (BYTE*)exp_vertices24,
9649             exp_vertex_size24
9650         },
9651         {
9652             (BYTE*)vertices25,
9653             NULL,
9654             NULL,
9655             num_vertices25,
9656             num_faces25,
9657             vertex_size25,
9658             options,
9659             options,
9660             declaration_ptc_float1,
9661             declaration_ptc_ubyte4,
9662             (BYTE*)exp_vertices25,
9663             exp_vertex_size25
9664         },
9665         {
9666             (BYTE*)vertices26,
9667             NULL,
9668             NULL,
9669             num_vertices26,
9670             num_faces26,
9671             vertex_size26,
9672             options,
9673             options,
9674             declaration_ptc_float4,
9675             declaration_ptc_d3dcolor,
9676             (BYTE*)exp_vertices26,
9677             exp_vertex_size26
9678         },
9679         {
9680             (BYTE*)vertices27,
9681             NULL,
9682             NULL,
9683             num_vertices27,
9684             num_faces27,
9685             vertex_size27,
9686             options,
9687             options,
9688             declaration_ptc_d3dcolor,
9689             declaration_ptc_float4,
9690             (BYTE*)exp_vertices27,
9691             exp_vertex_size27
9692         },
9693         {
9694             (BYTE*)vertices28,
9695             NULL,
9696             NULL,
9697             num_vertices28,
9698             num_faces28,
9699             vertex_size28,
9700             options,
9701             options,
9702             declaration_ptc_ubyte4,
9703             declaration_ptc_float4,
9704             (BYTE*)exp_vertices28,
9705             exp_vertex_size28
9706         },
9707         {
9708             (BYTE*)vertices29,
9709             NULL,
9710             NULL,
9711             num_vertices29,
9712             num_faces29,
9713             vertex_size29,
9714             options,
9715             options,
9716             declaration_ptc_short2,
9717             declaration_ptc_float4,
9718             (BYTE*)exp_vertices29,
9719             exp_vertex_size29
9720         },
9721         {
9722             (BYTE*)vertices30,
9723             NULL,
9724             NULL,
9725             num_vertices30,
9726             num_faces30,
9727             vertex_size30,
9728             options,
9729             options,
9730             declaration_ptc_short4,
9731             declaration_ptc_float4,
9732             (BYTE*)exp_vertices30,
9733             exp_vertex_size30
9734         },
9735         {
9736             (BYTE*)vertices31,
9737             NULL,
9738             NULL,
9739             num_vertices31,
9740             num_faces31,
9741             vertex_size31,
9742             options,
9743             options,
9744             declaration_ptc_ubyte4n,
9745             declaration_ptc_float4,
9746             (BYTE*)exp_vertices31,
9747             exp_vertex_size31
9748         },
9749         {
9750             (BYTE*)vertices32,
9751             NULL,
9752             NULL,
9753             num_vertices32,
9754             num_faces32,
9755             vertex_size32,
9756             options,
9757             options,
9758             declaration_ptc_short2n,
9759             declaration_ptc_float4,
9760             (BYTE*)exp_vertices32,
9761             exp_vertex_size32
9762         },
9763         {
9764             (BYTE*)vertices33,
9765             NULL,
9766             NULL,
9767             num_vertices33,
9768             num_faces33,
9769             vertex_size33,
9770             options,
9771             options,
9772             declaration_ptc_short4n,
9773             declaration_ptc_float4,
9774             (BYTE*)exp_vertices33,
9775             exp_vertex_size33
9776         },
9777         {
9778             (BYTE*)vertices34,
9779             NULL,
9780             NULL,
9781             num_vertices34,
9782             num_faces34,
9783             vertex_size34,
9784             options,
9785             options,
9786             declaration_ptc_float16_2,
9787             declaration_ptc_float4,
9788             (BYTE*)exp_vertices34,
9789             exp_vertex_size34
9790         },
9791         {
9792             (BYTE*)vertices35,
9793             NULL,
9794             NULL,
9795             num_vertices35,
9796             num_faces35,
9797             vertex_size35,
9798             options,
9799             options,
9800             declaration_ptc_float16_4,
9801             declaration_ptc_float4,
9802             (BYTE*)exp_vertices35,
9803             exp_vertex_size35
9804         },
9805         {
9806             (BYTE*)vertices36,
9807             NULL,
9808             NULL,
9809             num_vertices36,
9810             num_faces36,
9811             vertex_size36,
9812             options,
9813             clone_options36,
9814             declaration_pn,
9815             declaration_pn,
9816             (BYTE*)vertices36,
9817             vertex_size36
9818         },
9819     };
9820
9821     test_context = new_test_context();
9822     if (!test_context)
9823     {
9824         skip("Couldn't create test context\n");
9825         goto cleanup;
9826     }
9827
9828     for (i = 0; i < ARRAY_SIZE(tc); i++)
9829     {
9830         UINT j;
9831         D3DVERTEXELEMENT9 new_declaration[MAX_FVF_DECL_SIZE];
9832         UINT exp_new_decl_length, new_decl_length;
9833         UINT exp_new_decl_size, new_decl_size;
9834
9835         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
9836                               tc[i].create_options,
9837                               tc[i].declaration,
9838                               test_context->device, &mesh,
9839                               tc[i].vertices, tc[i].vertex_size,
9840                               tc[i].indices, tc[i].attributes);
9841         if (FAILED(hr))
9842         {
9843             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
9844             goto cleanup;
9845         }
9846
9847         hr = mesh->lpVtbl->CloneMesh(mesh, tc[i].clone_options, tc[i].new_declaration,
9848                                      test_context->device, &mesh_clone);
9849         ok(hr == D3D_OK, "CloneMesh test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
9850
9851         hr = mesh_clone->lpVtbl->GetDeclaration(mesh_clone, new_declaration);
9852         ok(hr == D3D_OK, "GetDeclaration test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
9853         /* Check declaration elements */
9854         for (j = 0; tc[i].new_declaration[j].Stream != 0xFF; j++)
9855         {
9856             ok(memcmp(&tc[i].new_declaration[j], &new_declaration[j], sizeof(*new_declaration)) == 0,
9857                "Test case %d failed. Declaration element %d did not match.\n", i, j);
9858         }
9859
9860         /* Check declaration length */
9861         exp_new_decl_length = D3DXGetDeclLength(tc[i].new_declaration);
9862         new_decl_length = D3DXGetDeclLength(new_declaration);
9863         ok(new_decl_length == exp_new_decl_length,
9864            "Test case %d failed. Got new declaration length %d, expected %d\n",
9865            i, new_decl_length, exp_new_decl_length);
9866
9867         /* Check declaration size */
9868         exp_new_decl_size = D3DXGetDeclVertexSize(tc[i].new_declaration, 0);
9869         new_decl_size = D3DXGetDeclVertexSize(new_declaration, 0);
9870         ok(new_decl_size == exp_new_decl_size,
9871            "Test case %d failed. Got new declaration size %d, expected %d\n",
9872            i, new_decl_size, exp_new_decl_size);
9873
9874         /* Check vertex data in cloned mesh */
9875         hr = mesh_clone->lpVtbl->LockVertexBuffer(mesh_clone, 0, (void**)&vertices);
9876         if (FAILED(hr))
9877         {
9878             skip("Couldn't lock cloned vertex buffer.\n");
9879             goto cleanup;
9880         }
9881         for (j = 0; j < tc[i].num_vertices; j++)
9882         {
9883             UINT index = tc[i].exp_vertex_size * j;
9884             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].new_declaration);
9885         }
9886         hr = mesh_clone->lpVtbl->UnlockVertexBuffer(mesh_clone);
9887         if (FAILED(hr))
9888         {
9889             skip("Couldn't unlock vertex buffer.\n");
9890             goto cleanup;
9891         }
9892         vertices = NULL;
9893         mesh->lpVtbl->Release(mesh);
9894         mesh = NULL;
9895         mesh_clone->lpVtbl->Release(mesh_clone);
9896         mesh_clone = NULL;
9897     }
9898
9899     /* The following test shows that it is not possible to share a vertex buffer
9900      * with D3DXMESH_VB_SHARE and change the vertex declaration at the same
9901      * time. It reuses the test data from test 2.
9902      */
9903     hr = init_test_mesh(tc[2].num_faces, tc[2].num_vertices,
9904                         tc[2].create_options,
9905                         tc[2].declaration,
9906                         test_context->device, &mesh,
9907                         tc[2].vertices, tc[2].vertex_size,
9908                         tc[2].indices, tc[2].attributes);
9909     if (FAILED(hr))
9910     {
9911         skip("Couldn't initialize test mesh for D3DXMESH_VB_SHARE case."
9912              " Got %x expected D3D_OK\n", hr);
9913         goto cleanup;
9914     }
9915
9916     hr = mesh->lpVtbl->CloneMesh(mesh, tc[2].create_options | D3DXMESH_VB_SHARE,
9917                                  tc[2].new_declaration, test_context->device,
9918                                  &mesh_clone);
9919     todo_wine ok(hr == D3DERR_INVALIDCALL, "CloneMesh D3DXMESH_VB_SHARE with new"
9920                  " declaration. Got %x, expected D3DERR_INVALIDCALL\n",
9921                  hr);
9922     mesh->lpVtbl->Release(mesh);
9923     mesh = NULL;
9924     mesh_clone = NULL;
9925
9926 cleanup:
9927     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
9928     if (mesh) mesh->lpVtbl->Release(mesh);
9929     if (mesh_clone) mesh_clone->lpVtbl->Release(mesh_clone);
9930     free_test_context(test_context);
9931 }
9932
9933 START_TEST(mesh)
9934 {
9935     D3DXBoundProbeTest();
9936     D3DXComputeBoundingBoxTest();
9937     D3DXComputeBoundingSphereTest();
9938     D3DXGetFVFVertexSizeTest();
9939     D3DXIntersectTriTest();
9940     D3DXCreateMeshTest();
9941     D3DXCreateMeshFVFTest();
9942     D3DXLoadMeshTest();
9943     D3DXCreateBoxTest();
9944     D3DXCreateSphereTest();
9945     D3DXCreateCylinderTest();
9946     D3DXCreateTextTest();
9947     test_get_decl_length();
9948     test_get_decl_vertex_size();
9949     test_fvf_decl_conversion();
9950     D3DXGenerateAdjacencyTest();
9951     test_update_semantics();
9952     test_create_skin_info();
9953     test_convert_adjacency_to_point_reps();
9954     test_convert_point_reps_to_adjacency();
9955     test_weld_vertices();
9956     test_clone_mesh();
9957 }