d3dx9: Add basic support for loading DXT formats to D3DXLoadSurfaceFromMemory().
[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             ok(index_buffer_description.Usage == 0, "Test %s, result %#x, expected %#x.\n",
332                     name, index_buffer_description.Usage, 0);
333             ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
334                name, index_buffer_description.Pool, D3DPOOL_MANAGED);
335             expected = number_of_faces * sizeof(WORD) * 3;
336             ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
337                name, index_buffer_description.Size, expected);
338         }
339
340         /* specify offset and size to avoid potential overruns */
341         hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
342                                         (LPVOID *)&faces, D3DLOCK_DISCARD);
343         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
344
345         if (hr != D3D_OK)
346         {
347             skip("Couldn't lock index buffer\n");
348         }
349         else
350         {
351             for (i = 0; i < number_of_faces; i++)
352             {
353                 ok(compare_face(faces[i], mesh->faces[i]),
354                    "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
355                    faces[i][0], faces[i][1], faces[i][2],
356                    mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
357             }
358
359             IDirect3DIndexBuffer9_Unlock(index_buffer);
360         }
361
362         IDirect3DIndexBuffer9_Release(index_buffer);
363     }
364 }
365
366 static void D3DXBoundProbeTest(void)
367 {
368     BOOL result;
369     D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
370     FLOAT radius;
371
372 /*____________Test the Box case___________________________*/
373     bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
374     top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
375
376     raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
377     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
378     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
379     ok(result == TRUE, "expected TRUE, received FALSE\n");
380
381     raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
382     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
383     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
384     ok(result == FALSE, "expected FALSE, received TRUE\n");
385
386     rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
387     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
388     ok(result == TRUE, "expected TRUE, received FALSE\n");
389
390     bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
391     top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
392     rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
393     raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
394     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
395     ok(result == FALSE, "expected FALSE, received TRUE\n");
396
397     bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
398     top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
399
400     raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
401     rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
402     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
403     ok(result == TRUE, "expected TRUE, received FALSE\n");
404
405     bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
406     top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
407
408     raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
409     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
410     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
411     ok(result == FALSE, "expected FALSE, received TRUE\n");
412
413     raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
414     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
415     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
416     ok(result == TRUE, "expected TRUE, received FALSE\n");
417
418 /*____________Test the Sphere case________________________*/
419     radius = sqrt(77.0f);
420     center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
421     raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
422
423     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
424     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
425     ok(result == TRUE, "expected TRUE, received FALSE\n");
426
427     rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
428     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
429     ok(result == FALSE, "expected FALSE, received TRUE\n");
430
431     rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
432     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
433     ok(result == FALSE, "expected FALSE, received TRUE\n");
434 }
435
436 static void D3DXComputeBoundingBoxTest(void)
437 {
438     D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
439     HRESULT hr;
440
441     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
442     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
443     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
444     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
445     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
446
447     exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
448     exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
449
450     hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
451
452     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
453     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);
454     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);
455
456 /*________________________*/
457
458     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
459     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
460     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
461     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
462     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
463
464     exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
465     exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
466
467     hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
468
469     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
470     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);
471     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);
472
473 /*________________________*/
474
475     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
476     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
477     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
478     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
479     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
480
481     exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
482     exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
483
484     hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
485
486     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
487     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);
488     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);
489
490 /*________________________*/
491     hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
492     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
493
494 /*________________________*/
495     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
496     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
497
498 /*________________________*/
499     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
500     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
501 }
502
503 static void D3DXComputeBoundingSphereTest(void)
504 {
505     D3DXVECTOR3 exp_cen, got_cen, vertex[5];
506     FLOAT exp_rad, got_rad;
507     HRESULT hr;
508
509     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
510     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
511     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
512     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
513     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
514
515     exp_rad = 6.928203f;
516     exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
517
518     hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
519
520     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
521     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
522     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);
523
524 /*________________________*/
525
526     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
527     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
528     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
529     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
530     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
531
532     exp_rad = 13.707883f;
533     exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
534
535     hr = D3DXComputeBoundingSphere(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
536
537     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
538     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
539     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);
540
541 /*________________________*/
542     hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
543     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
544
545 /*________________________*/
546     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
547     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
548
549 /*________________________*/
550     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
551     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
552 }
553
554 static void print_elements(const D3DVERTEXELEMENT9 *elements)
555 {
556     D3DVERTEXELEMENT9 last = D3DDECL_END();
557     const D3DVERTEXELEMENT9 *ptr = elements;
558     int count = 0;
559
560     while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
561     {
562         trace(
563             "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
564              count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
565         ptr++;
566         count++;
567     }
568 }
569
570 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
571         unsigned int line, unsigned int test_id)
572 {
573     D3DVERTEXELEMENT9 last = D3DDECL_END();
574     unsigned int i;
575
576     for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
577     {
578         int end1 = memcmp(&elements[i], &last, sizeof(last));
579         int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
580         int status;
581
582         if (!end1 && !end2) break;
583
584         status = !end1 ^ !end2;
585         ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
586                 line, test_id, end1 ? "shorter" : "longer");
587         if (status)
588         {
589             print_elements(elements);
590             break;
591         }
592
593         status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
594         ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
595         if (status)
596         {
597             print_elements(elements);
598             break;
599         }
600     }
601 }
602
603 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
604         HRESULT expected_hr, unsigned int line, unsigned int test_id)
605 {
606     HRESULT hr;
607     D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
608
609     hr = D3DXDeclaratorFromFVF(test_fvf, decl);
610     ok(hr == expected_hr,
611             "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
612             line, test_id, hr, expected_hr);
613     if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
614 }
615
616 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
617         HRESULT expected_hr, unsigned int line, unsigned int test_id)
618 {
619     HRESULT hr;
620     DWORD result_fvf = 0xdeadbeef;
621
622     hr = D3DXFVFFromDeclarator(decl, &result_fvf);
623     ok(hr == expected_hr,
624        "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
625        line, test_id, hr, expected_hr);
626     if (SUCCEEDED(hr))
627     {
628         ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
629                 line, test_id, result_fvf, expected_fvf);
630     }
631 }
632
633 static void test_fvf_decl_conversion(void)
634 {
635     static const struct
636     {
637         D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
638         DWORD fvf;
639     }
640     test_data[] =
641     {
642         {{
643             D3DDECL_END(),
644         }, 0},
645         {{
646             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
647             D3DDECL_END(),
648         }, D3DFVF_XYZ},
649         {{
650             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
651             D3DDECL_END(),
652         }, D3DFVF_XYZRHW},
653         {{
654             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
655             D3DDECL_END(),
656         }, D3DFVF_XYZRHW},
657         {{
658             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
659             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
660             D3DDECL_END(),
661         }, D3DFVF_XYZB1},
662         {{
663             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
664             {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
665             D3DDECL_END(),
666         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
667         {{
668             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
669             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
670             D3DDECL_END(),
671         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
672         {{
673             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
674             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
675             D3DDECL_END(),
676         }, D3DFVF_XYZB2},
677         {{
678             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
679             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
680             {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
681             D3DDECL_END(),
682         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
683         {{
684             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
685             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
686             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
687             D3DDECL_END(),
688         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
689         {{
690             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
691             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
692             D3DDECL_END(),
693         }, D3DFVF_XYZB3},
694         {{
695             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
696             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
697             {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
698             D3DDECL_END(),
699         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
700         {{
701             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
702             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
703             {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
704             D3DDECL_END(),
705         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
706         {{
707             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
708             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
709             D3DDECL_END(),
710         }, D3DFVF_XYZB4},
711         {{
712             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
713             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
714             {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
715             D3DDECL_END(),
716         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
717         {{
718             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
719             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
720             {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
721             D3DDECL_END(),
722         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
723         {{
724             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
725             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
726             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
727             D3DDECL_END(),
728         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
729         {{
730             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
731             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
732             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
733             D3DDECL_END(),
734         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
735         {{
736             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
737             D3DDECL_END(),
738         }, D3DFVF_NORMAL},
739         {{
740             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
741             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
742             D3DDECL_END(),
743         }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
744         {{
745             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
746             D3DDECL_END(),
747         }, D3DFVF_PSIZE},
748         {{
749             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
750             D3DDECL_END(),
751         }, D3DFVF_DIFFUSE},
752         {{
753             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
754             D3DDECL_END(),
755         }, D3DFVF_SPECULAR},
756         /* Make sure textures of different sizes work. */
757         {{
758             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
759             D3DDECL_END(),
760         }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
761         {{
762             {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
763             D3DDECL_END(),
764         }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
765         {{
766             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
767             D3DDECL_END(),
768         }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
769         {{
770             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
771             D3DDECL_END(),
772         }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
773         /* Make sure the TEXCOORD index works correctly - try several textures. */
774         {{
775             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
776             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
777             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
778             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
779             D3DDECL_END(),
780         }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
781                 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
782         /* Now try some combination tests. */
783         {{
784             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
785             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
786             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
787             {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
788             {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
789             {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
790             D3DDECL_END(),
791         }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
792                 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
793         {{
794             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
795             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
796             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
797             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
798             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
799             {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
800             D3DDECL_END(),
801         }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
802                 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
803     };
804     unsigned int i;
805
806     for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
807     {
808         test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
809         test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
810     }
811
812     /* Usage indices for position and normal are apparently ignored. */
813     {
814         const D3DVERTEXELEMENT9 decl[] =
815         {
816             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
817             D3DDECL_END(),
818         };
819         test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
820     }
821     {
822         const D3DVERTEXELEMENT9 decl[] =
823         {
824             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
825             D3DDECL_END(),
826         };
827         test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
828     }
829     /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
830      * there are no blend matrices. */
831     {
832         const D3DVERTEXELEMENT9 decl[] =
833         {
834             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
835             D3DDECL_END(),
836         };
837         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
838     }
839     {
840         const D3DVERTEXELEMENT9 decl[] =
841         {
842             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
843             D3DDECL_END(),
844         };
845         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
846     }
847     /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
848     {
849         const D3DVERTEXELEMENT9 decl[] =
850         {
851             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
852             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
853             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
854             D3DDECL_END(),
855         };
856         test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
857                 decl, D3D_OK, __LINE__, 0);
858     }
859     /* These are supposed to fail, both ways. */
860     {
861         const D3DVERTEXELEMENT9 decl[] =
862         {
863             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
864             D3DDECL_END(),
865         };
866         test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
867         test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
868     }
869     {
870         const D3DVERTEXELEMENT9 decl[] =
871         {
872             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
873             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
874             D3DDECL_END(),
875         };
876         test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
877         test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
878     }
879     {
880         const D3DVERTEXELEMENT9 decl[] =
881         {
882             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
883             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
884             {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
885             D3DDECL_END(),
886         };
887         test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
888         test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
889     }
890     /* Test a declaration that can't be converted to an FVF. */
891     {
892         const D3DVERTEXELEMENT9 decl[] =
893         {
894             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
895             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
896             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
897             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
898             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
899             /* 8 bytes padding */
900             {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
901             D3DDECL_END(),
902         };
903         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
904     }
905     /* Elements must be ordered by offset. */
906     {
907         const D3DVERTEXELEMENT9 decl[] =
908         {
909             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
910             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
911             D3DDECL_END(),
912         };
913         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
914     }
915     /* Basic tests for element order. */
916     {
917         const D3DVERTEXELEMENT9 decl[] =
918         {
919             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
920             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
921             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
922             D3DDECL_END(),
923         };
924         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
925     }
926     {
927         const D3DVERTEXELEMENT9 decl[] =
928         {
929             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
930             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
931             D3DDECL_END(),
932         };
933         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
934     }
935     {
936         const D3DVERTEXELEMENT9 decl[] =
937         {
938             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
939             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
940             D3DDECL_END(),
941         };
942         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
943     }
944     /* Textures must be ordered by texcoords. */
945     {
946         const D3DVERTEXELEMENT9 decl[] =
947         {
948             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
949             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
950             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
951             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
952             D3DDECL_END(),
953         };
954         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
955     }
956     /* Duplicate elements are not allowed. */
957     {
958         const D3DVERTEXELEMENT9 decl[] =
959         {
960             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
961             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
962             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
963             D3DDECL_END(),
964         };
965         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
966     }
967     /* Invalid FVFs cannot be converted to a declarator. */
968     test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
969 }
970
971 static void D3DXGetFVFVertexSizeTest(void)
972 {
973     UINT got;
974
975     compare_vertex_sizes (D3DFVF_XYZ, 12);
976
977     compare_vertex_sizes (D3DFVF_XYZB3, 24);
978
979     compare_vertex_sizes (D3DFVF_XYZB5, 32);
980
981     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
982
983     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
984
985     compare_vertex_sizes (
986         D3DFVF_XYZ |
987         D3DFVF_TEX1 |
988         D3DFVF_TEXCOORDSIZE1(0), 16);
989     compare_vertex_sizes (
990         D3DFVF_XYZ |
991         D3DFVF_TEX2 |
992         D3DFVF_TEXCOORDSIZE1(0) |
993         D3DFVF_TEXCOORDSIZE1(1), 20);
994
995     compare_vertex_sizes (
996         D3DFVF_XYZ |
997         D3DFVF_TEX1 |
998         D3DFVF_TEXCOORDSIZE2(0), 20);
999
1000     compare_vertex_sizes (
1001         D3DFVF_XYZ |
1002         D3DFVF_TEX2 |
1003         D3DFVF_TEXCOORDSIZE2(0) |
1004         D3DFVF_TEXCOORDSIZE2(1), 28);
1005
1006     compare_vertex_sizes (
1007         D3DFVF_XYZ |
1008         D3DFVF_TEX6 |
1009         D3DFVF_TEXCOORDSIZE2(0) |
1010         D3DFVF_TEXCOORDSIZE2(1) |
1011         D3DFVF_TEXCOORDSIZE2(2) |
1012         D3DFVF_TEXCOORDSIZE2(3) |
1013         D3DFVF_TEXCOORDSIZE2(4) |
1014         D3DFVF_TEXCOORDSIZE2(5), 60);
1015
1016     compare_vertex_sizes (
1017         D3DFVF_XYZ |
1018         D3DFVF_TEX8 |
1019         D3DFVF_TEXCOORDSIZE2(0) |
1020         D3DFVF_TEXCOORDSIZE2(1) |
1021         D3DFVF_TEXCOORDSIZE2(2) |
1022         D3DFVF_TEXCOORDSIZE2(3) |
1023         D3DFVF_TEXCOORDSIZE2(4) |
1024         D3DFVF_TEXCOORDSIZE2(5) |
1025         D3DFVF_TEXCOORDSIZE2(6) |
1026         D3DFVF_TEXCOORDSIZE2(7), 76);
1027
1028     compare_vertex_sizes (
1029         D3DFVF_XYZ |
1030         D3DFVF_TEX1 |
1031         D3DFVF_TEXCOORDSIZE3(0), 24);
1032
1033     compare_vertex_sizes (
1034         D3DFVF_XYZ |
1035         D3DFVF_TEX4 |
1036         D3DFVF_TEXCOORDSIZE3(0) |
1037         D3DFVF_TEXCOORDSIZE3(1) |
1038         D3DFVF_TEXCOORDSIZE3(2) |
1039         D3DFVF_TEXCOORDSIZE3(3), 60);
1040
1041     compare_vertex_sizes (
1042         D3DFVF_XYZ |
1043         D3DFVF_TEX1 |
1044         D3DFVF_TEXCOORDSIZE4(0), 28);
1045
1046     compare_vertex_sizes (
1047         D3DFVF_XYZ |
1048         D3DFVF_TEX2 |
1049         D3DFVF_TEXCOORDSIZE4(0) |
1050         D3DFVF_TEXCOORDSIZE4(1), 44);
1051
1052     compare_vertex_sizes (
1053         D3DFVF_XYZ |
1054         D3DFVF_TEX3 |
1055         D3DFVF_TEXCOORDSIZE4(0) |
1056         D3DFVF_TEXCOORDSIZE4(1) |
1057         D3DFVF_TEXCOORDSIZE4(2), 60);
1058
1059     compare_vertex_sizes (
1060         D3DFVF_XYZB5 |
1061         D3DFVF_NORMAL |
1062         D3DFVF_DIFFUSE |
1063         D3DFVF_SPECULAR |
1064         D3DFVF_TEX8 |
1065         D3DFVF_TEXCOORDSIZE4(0) |
1066         D3DFVF_TEXCOORDSIZE4(1) |
1067         D3DFVF_TEXCOORDSIZE4(2) |
1068         D3DFVF_TEXCOORDSIZE4(3) |
1069         D3DFVF_TEXCOORDSIZE4(4) |
1070         D3DFVF_TEXCOORDSIZE4(5) |
1071         D3DFVF_TEXCOORDSIZE4(6) |
1072         D3DFVF_TEXCOORDSIZE4(7), 180);
1073 }
1074
1075 static void D3DXIntersectTriTest(void)
1076 {
1077     BOOL exp_res, got_res;
1078     D3DXVECTOR3 position, ray, vertex[3];
1079     FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
1080
1081     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1082     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1083     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1084
1085     position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
1086
1087     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1088
1089     exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
1090
1091     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1092     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1093     ok( compare(exp_u,got_u), "Expected u = %f, got %f\n",exp_u,got_u);
1094     ok( compare(exp_v,got_v), "Expected v = %f, got %f\n",exp_v,got_v);
1095     ok( compare(exp_dist,got_dist), "Expected distance = %f, got %f\n",exp_dist,got_dist);
1096
1097 /*Only positive ray is taken in account*/
1098
1099     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1100     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1101     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1102
1103     position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
1104
1105     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1106
1107     exp_res = FALSE;
1108
1109     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1110     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1111
1112 /*Intersection between ray and triangle in a same plane is considered as empty*/
1113
1114     vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1115     vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1116     vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
1117
1118     position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
1119
1120     ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
1121
1122     exp_res = FALSE;
1123
1124     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1125     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1126 }
1127
1128 static void D3DXCreateMeshTest(void)
1129 {
1130     HRESULT hr;
1131     HWND wnd;
1132     IDirect3D9 *d3d;
1133     IDirect3DDevice9 *device, *test_device;
1134     D3DPRESENT_PARAMETERS d3dpp;
1135     ID3DXMesh *d3dxmesh;
1136     int i, size;
1137     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1138     DWORD options;
1139     struct mesh mesh;
1140
1141     static const D3DVERTEXELEMENT9 decl1[3] = {
1142         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1143         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1144         D3DDECL_END(), };
1145
1146     static const D3DVERTEXELEMENT9 decl2[] = {
1147         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1148         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1149         {0, 24, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
1150         {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
1151         {0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
1152         /* 8 bytes padding */
1153         {0, 44, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
1154         D3DDECL_END(),
1155     };
1156
1157     static const D3DVERTEXELEMENT9 decl3[] = {
1158         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1159         {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1160         D3DDECL_END(),
1161     };
1162
1163     hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1164     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1165
1166     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1167     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1168
1169     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1170     if (!wnd)
1171     {
1172         skip("Couldn't create application window\n");
1173         return;
1174     }
1175     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1176     if (!d3d)
1177     {
1178         skip("Couldn't create IDirect3D9 object\n");
1179         DestroyWindow(wnd);
1180         return;
1181     }
1182
1183     ZeroMemory(&d3dpp, sizeof(d3dpp));
1184     d3dpp.Windowed = TRUE;
1185     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1186     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1187     if (FAILED(hr))
1188     {
1189         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1190         IDirect3D9_Release(d3d);
1191         DestroyWindow(wnd);
1192         return;
1193     }
1194
1195     hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1196     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1197
1198     hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1199     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1200
1201     hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
1202     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1203
1204     if (hr == D3D_OK)
1205     {
1206         d3dxmesh->lpVtbl->Release(d3dxmesh);
1207     }
1208
1209     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1210     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1211
1212     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
1213     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1214
1215     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1216     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1217
1218     if (hr == D3D_OK)
1219     {
1220         /* device */
1221         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1222         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1223
1224         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1225         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1226         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1227
1228         if (hr == D3D_OK)
1229         {
1230             IDirect3DDevice9_Release(device);
1231         }
1232
1233         /* declaration */
1234         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1235         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1236
1237         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1238         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1239
1240         if (hr == D3D_OK)
1241         {
1242             size = sizeof(decl1) / sizeof(decl1[0]);
1243             for (i = 0; i < size - 1; i++)
1244             {
1245                 ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1246                 ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1247                 ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1248                 ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1249                 ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1250                 ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1251             }
1252             ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1253         }
1254
1255         /* options */
1256         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1257         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1258
1259         /* rest */
1260         if (!new_mesh(&mesh, 3, 1))
1261         {
1262             skip("Couldn't create mesh\n");
1263         }
1264         else
1265         {
1266             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1267             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1268             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1269
1270             compare_mesh("createmesh1", d3dxmesh, &mesh);
1271
1272             free_mesh(&mesh);
1273         }
1274
1275         d3dxmesh->lpVtbl->Release(d3dxmesh);
1276     }
1277
1278     /* Test a declaration that can't be converted to an FVF. */
1279     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1280     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1281
1282     if (hr == D3D_OK)
1283     {
1284         /* device */
1285         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1286         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1287
1288         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1289         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1290         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1291
1292         if (hr == D3D_OK)
1293         {
1294             IDirect3DDevice9_Release(device);
1295         }
1296
1297         /* declaration */
1298         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1299         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1300
1301         if (hr == D3D_OK)
1302         {
1303             size = sizeof(decl2) / sizeof(decl2[0]);
1304             for (i = 0; i < size - 1; i++)
1305             {
1306                 ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1307                 ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1308                 ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1309                 ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1310                 ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1311                 ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1312             }
1313             ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1314         }
1315
1316         /* options */
1317         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1318         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1319
1320         /* rest */
1321         if (!new_mesh(&mesh, 3, 1))
1322         {
1323             skip("Couldn't create mesh\n");
1324         }
1325         else
1326         {
1327             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1328             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1329             mesh.fvf = 0;
1330             mesh.vertex_size = 60;
1331
1332             compare_mesh("createmesh2", d3dxmesh, &mesh);
1333
1334             free_mesh(&mesh);
1335         }
1336
1337         mesh.vertex_size = d3dxmesh->lpVtbl->GetNumBytesPerVertex(d3dxmesh);
1338         ok(mesh.vertex_size == 60, "Got vertex size %u, expected %u\n", mesh.vertex_size, 60);
1339
1340         d3dxmesh->lpVtbl->Release(d3dxmesh);
1341     }
1342
1343     /* Test a declaration with multiple streams. */
1344     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
1345     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1346
1347     IDirect3DDevice9_Release(device);
1348     IDirect3D9_Release(d3d);
1349     DestroyWindow(wnd);
1350 }
1351
1352 static void D3DXCreateMeshFVFTest(void)
1353 {
1354     HRESULT hr;
1355     HWND wnd;
1356     IDirect3D9 *d3d;
1357     IDirect3DDevice9 *device, *test_device;
1358     D3DPRESENT_PARAMETERS d3dpp;
1359     ID3DXMesh *d3dxmesh;
1360     int i, size;
1361     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1362     DWORD options;
1363     struct mesh mesh;
1364
1365     static const D3DVERTEXELEMENT9 decl[3] = {
1366         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1367         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1368         D3DDECL_END(), };
1369
1370     hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1371     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1372
1373     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, NULL, &d3dxmesh);
1374     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1375
1376     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1377     if (!wnd)
1378     {
1379         skip("Couldn't create application window\n");
1380         return;
1381     }
1382     d3d = Direct3DCreate9(D3D_SDK_VERSION);
1383     if (!d3d)
1384     {
1385         skip("Couldn't create IDirect3D9 object\n");
1386         DestroyWindow(wnd);
1387         return;
1388     }
1389
1390     ZeroMemory(&d3dpp, sizeof(d3dpp));
1391     d3dpp.Windowed = TRUE;
1392     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1393     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1394     if (FAILED(hr))
1395     {
1396         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1397         IDirect3D9_Release(d3d);
1398         DestroyWindow(wnd);
1399         return;
1400     }
1401
1402     hr = D3DXCreateMeshFVF(0, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1403     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1404
1405     hr = D3DXCreateMeshFVF(1, 0, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1406     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1407
1408     hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1409     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1410
1411     if (hr == D3D_OK)
1412     {
1413         d3dxmesh->lpVtbl->Release(d3dxmesh);
1414     }
1415
1416     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1417     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1418
1419     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, NULL);
1420     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1421
1422     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1423     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1424
1425     if (hr == D3D_OK)
1426     {
1427         /* device */
1428         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1429         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1430
1431         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1432         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1433         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1434
1435         if (hr == D3D_OK)
1436         {
1437             IDirect3DDevice9_Release(device);
1438         }
1439
1440         /* declaration */
1441         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1442         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1443
1444         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1445         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1446
1447         if (hr == D3D_OK)
1448         {
1449             size = sizeof(decl) / sizeof(decl[0]);
1450             for (i = 0; i < size - 1; i++)
1451             {
1452                 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1453                 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1454                 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1455                 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1456                 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1457                    test_decl[i].UsageIndex, decl[i].UsageIndex);
1458                 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1459             }
1460             ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1461         }
1462
1463         /* options */
1464         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1465         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1466
1467         /* rest */
1468         if (!new_mesh(&mesh, 3, 1))
1469         {
1470             skip("Couldn't create mesh\n");
1471         }
1472         else
1473         {
1474             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1475             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1476             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1477
1478             compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1479
1480             free_mesh(&mesh);
1481         }
1482
1483         d3dxmesh->lpVtbl->Release(d3dxmesh);
1484     }
1485
1486     IDirect3DDevice9_Release(device);
1487     IDirect3D9_Release(d3d);
1488     DestroyWindow(wnd);
1489 }
1490
1491 #define check_vertex_buffer(mesh, vertices, num_vertices, fvf) \
1492     check_vertex_buffer_(__LINE__, mesh, vertices, num_vertices, fvf)
1493 static void check_vertex_buffer_(int line, ID3DXMesh *mesh, const void *vertices, DWORD num_vertices, DWORD fvf)
1494 {
1495     DWORD mesh_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
1496     DWORD mesh_fvf = mesh->lpVtbl->GetFVF(mesh);
1497     const void *mesh_vertices;
1498     HRESULT hr;
1499
1500     ok_(__FILE__,line)(fvf == mesh_fvf, "expected FVF %x, got %x\n", fvf, mesh_fvf);
1501     ok_(__FILE__,line)(num_vertices == mesh_num_vertices,
1502        "Expected %u vertices, got %u\n", num_vertices, mesh_num_vertices);
1503
1504     hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
1505     ok_(__FILE__,line)(hr == D3D_OK, "LockVertexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1506     if (FAILED(hr))
1507         return;
1508
1509     if (mesh_fvf == fvf) {
1510         DWORD vertex_size = D3DXGetFVFVertexSize(fvf);
1511         int i;
1512         for (i = 0; i < min(num_vertices, mesh_num_vertices); i++)
1513         {
1514             const FLOAT *exp_float = vertices;
1515             const FLOAT *got_float = mesh_vertices;
1516             DWORD texcount;
1517             DWORD pos_dim = 0;
1518             int j;
1519             BOOL last_beta_dword = FALSE;
1520             char prefix[128];
1521
1522             switch (fvf & D3DFVF_POSITION_MASK) {
1523                 case D3DFVF_XYZ: pos_dim = 3; break;
1524                 case D3DFVF_XYZRHW: pos_dim = 4; break;
1525                 case D3DFVF_XYZB1:
1526                 case D3DFVF_XYZB2:
1527                 case D3DFVF_XYZB3:
1528                 case D3DFVF_XYZB4:
1529                 case D3DFVF_XYZB5:
1530                     pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
1531                     if (fvf & (D3DFVF_LASTBETA_UBYTE4 | D3DFVF_LASTBETA_D3DCOLOR))
1532                     {
1533                         pos_dim--;
1534                         last_beta_dword = TRUE;
1535                     }
1536                     break;
1537                 case D3DFVF_XYZW: pos_dim = 4; break;
1538             }
1539             sprintf(prefix, "vertex[%u] position, ", i);
1540             check_floats_(line, prefix, got_float, exp_float, pos_dim);
1541             exp_float += pos_dim;
1542             got_float += pos_dim;
1543
1544             if (last_beta_dword) {
1545                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1546                     "Vertex[%u]: Expected last beta %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1547                 exp_float++;
1548                 got_float++;
1549             }
1550
1551             if (fvf & D3DFVF_NORMAL) {
1552                 sprintf(prefix, "vertex[%u] normal, ", i);
1553                 check_floats_(line, prefix, got_float, exp_float, 3);
1554                 exp_float += 3;
1555                 got_float += 3;
1556             }
1557             if (fvf & D3DFVF_PSIZE) {
1558                 ok_(__FILE__,line)(compare(*exp_float, *got_float),
1559                         "Vertex[%u]: Expected psize %g, got %g\n", i, *exp_float, *got_float);
1560                 exp_float++;
1561                 got_float++;
1562             }
1563             if (fvf & D3DFVF_DIFFUSE) {
1564                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1565                     "Vertex[%u]: Expected diffuse %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1566                 exp_float++;
1567                 got_float++;
1568             }
1569             if (fvf & D3DFVF_SPECULAR) {
1570                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1571                     "Vertex[%u]: Expected specular %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1572                 exp_float++;
1573                 got_float++;
1574             }
1575
1576             texcount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
1577             for (j = 0; j < texcount; j++) {
1578                 DWORD dim = (((fvf >> (16 + 2 * j)) + 1) & 0x03) + 1;
1579                 sprintf(prefix, "vertex[%u] texture, ", i);
1580                 check_floats_(line, prefix, got_float, exp_float, dim);
1581                 exp_float += dim;
1582                 got_float += dim;
1583             }
1584
1585             vertices = (BYTE*)vertices + vertex_size;
1586             mesh_vertices = (BYTE*)mesh_vertices + vertex_size;
1587         }
1588     }
1589
1590     mesh->lpVtbl->UnlockVertexBuffer(mesh);
1591 }
1592
1593 #define check_index_buffer(mesh, indices, num_indices, index_size) \
1594     check_index_buffer_(__LINE__, mesh, indices, num_indices, index_size)
1595 static void check_index_buffer_(int line, ID3DXMesh *mesh, const void *indices, DWORD num_indices, DWORD index_size)
1596 {
1597     DWORD mesh_index_size = (mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT) ? 4 : 2;
1598     DWORD mesh_num_indices = mesh->lpVtbl->GetNumFaces(mesh) * 3;
1599     const void *mesh_indices;
1600     HRESULT hr;
1601     DWORD i;
1602
1603     ok_(__FILE__,line)(index_size == mesh_index_size,
1604         "Expected index size %u, got %u\n", index_size, mesh_index_size);
1605     ok_(__FILE__,line)(num_indices == mesh_num_indices,
1606         "Expected %u indices, got %u\n", num_indices, mesh_num_indices);
1607
1608     hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
1609     ok_(__FILE__,line)(hr == D3D_OK, "LockIndexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1610     if (FAILED(hr))
1611         return;
1612
1613     if (mesh_index_size == index_size) {
1614         for (i = 0; i < min(num_indices, mesh_num_indices); i++)
1615         {
1616             if (index_size == 4)
1617                 ok_(__FILE__,line)(*(DWORD*)indices == *(DWORD*)mesh_indices,
1618                     "Index[%u]: expected %u, got %u\n", i, *(DWORD*)indices, *(DWORD*)mesh_indices);
1619             else
1620                 ok_(__FILE__,line)(*(WORD*)indices == *(WORD*)mesh_indices,
1621                     "Index[%u]: expected %u, got %u\n", i, *(WORD*)indices, *(WORD*)mesh_indices);
1622             indices = (BYTE*)indices + index_size;
1623             mesh_indices = (BYTE*)mesh_indices + index_size;
1624         }
1625     }
1626     mesh->lpVtbl->UnlockIndexBuffer(mesh);
1627 }
1628
1629 #define check_matrix(got, expected) check_matrix_(__LINE__, got, expected)
1630 static void check_matrix_(int line, const D3DXMATRIX *got, const D3DXMATRIX *expected)
1631 {
1632     int i, j;
1633     for (i = 0; i < 4; i++) {
1634         for (j = 0; j < 4; j++) {
1635             ok_(__FILE__,line)(compare(U(*expected).m[i][j], U(*got).m[i][j]),
1636                     "matrix[%u][%u]: expected %g, got %g\n",
1637                     i, j, U(*expected).m[i][j], U(*got).m[i][j]);
1638         }
1639     }
1640 }
1641
1642 static void check_colorvalue_(int line, const char *prefix, const D3DCOLORVALUE got, const D3DCOLORVALUE expected)
1643 {
1644     ok_(__FILE__,line)(expected.r == got.r && expected.g == got.g && expected.b == got.b && expected.a == got.a,
1645             "%sExpected (%g, %g, %g, %g), got (%g, %g, %g, %g)\n", prefix,
1646             expected.r, expected.g, expected.b, expected.a, got.r, got.g, got.b, got.a);
1647 }
1648
1649 #define check_materials(got, got_count, expected, expected_count) \
1650     check_materials_(__LINE__, got, got_count, expected, expected_count)
1651 static void check_materials_(int line, const D3DXMATERIAL *got, DWORD got_count, const D3DXMATERIAL *expected, DWORD expected_count)
1652 {
1653     int i;
1654     ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
1655     if (!expected) {
1656         ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
1657         return;
1658     }
1659     for (i = 0; i < min(expected_count, got_count); i++)
1660     {
1661         if (!expected[i].pTextureFilename)
1662             ok_(__FILE__,line)(got[i].pTextureFilename == NULL,
1663                     "Expected NULL pTextureFilename, got %p\n", got[i].pTextureFilename);
1664         else
1665             ok_(__FILE__,line)(!strcmp(expected[i].pTextureFilename, got[i].pTextureFilename),
1666                     "Expected '%s' for pTextureFilename, got '%s'\n", expected[i].pTextureFilename, got[i].pTextureFilename);
1667         check_colorvalue_(line, "Diffuse: ", got[i].MatD3D.Diffuse, expected[i].MatD3D.Diffuse);
1668         check_colorvalue_(line, "Ambient: ", got[i].MatD3D.Ambient, expected[i].MatD3D.Ambient);
1669         check_colorvalue_(line, "Specular: ", got[i].MatD3D.Specular, expected[i].MatD3D.Specular);
1670         check_colorvalue_(line, "Emissive: ", got[i].MatD3D.Emissive, expected[i].MatD3D.Emissive);
1671         ok_(__FILE__,line)(expected[i].MatD3D.Power == got[i].MatD3D.Power,
1672                 "Power: Expected %g, got %g\n", expected[i].MatD3D.Power, got[i].MatD3D.Power);
1673     }
1674 }
1675
1676 #define check_generated_adjacency(mesh, got, epsilon) check_generated_adjacency_(__LINE__, mesh, got, epsilon)
1677 static void check_generated_adjacency_(int line, ID3DXMesh *mesh, const DWORD *got, FLOAT epsilon)
1678 {
1679     DWORD *expected;
1680     DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
1681     HRESULT hr;
1682
1683     expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
1684     if (!expected) {
1685         skip_(__FILE__, line)("Out of memory\n");
1686         return;
1687     }
1688     hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
1689     ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1690     if (SUCCEEDED(hr))
1691     {
1692         int i;
1693         for (i = 0; i < num_faces; i++)
1694         {
1695             ok_(__FILE__, line)(expected[i * 3] == got[i * 3] &&
1696                     expected[i * 3 + 1] == got[i * 3 + 1] &&
1697                     expected[i * 3 + 2] == got[i * 3 + 2],
1698                     "Face %u adjacencies: Expected (%u, %u, %u), got (%u, %u, %u)\n", i,
1699                     expected[i * 3], expected[i * 3 + 1], expected[i * 3 + 2],
1700                     got[i * 3], got[i * 3 + 1], got[i * 3 + 2]);
1701         }
1702     }
1703     HeapFree(GetProcessHeap(), 0, expected);
1704 }
1705
1706 #define check_generated_effects(materials, num_materials, effects) \
1707     check_generated_effects_(__LINE__, materials, num_materials, effects)
1708 static void check_generated_effects_(int line, const D3DXMATERIAL *materials, DWORD num_materials, const D3DXEFFECTINSTANCE *effects)
1709 {
1710     int i;
1711     static const struct {
1712         const char *name;
1713         DWORD name_size;
1714         DWORD num_bytes;
1715         DWORD value_offset;
1716     } params[] = {
1717 #define EFFECT_TABLE_ENTRY(str, field) \
1718     {str, sizeof(str), sizeof(materials->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
1719         EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
1720         EFFECT_TABLE_ENTRY("Power", Power),
1721         EFFECT_TABLE_ENTRY("Specular", Specular),
1722         EFFECT_TABLE_ENTRY("Emissive", Emissive),
1723         EFFECT_TABLE_ENTRY("Ambient", Ambient),
1724 #undef EFFECT_TABLE_ENTRY
1725     };
1726
1727     if (!num_materials) {
1728         ok_(__FILE__, line)(effects == NULL, "Expected NULL effects, got %p\n", effects);
1729         return;
1730     }
1731     for (i = 0; i < num_materials; i++)
1732     {
1733         int j;
1734         DWORD expected_num_defaults = ARRAY_SIZE(params) + (materials[i].pTextureFilename ? 1 : 0);
1735
1736         ok_(__FILE__,line)(expected_num_defaults == effects[i].NumDefaults,
1737                 "effect[%u] NumDefaults: Expected %u, got %u\n", i,
1738                 expected_num_defaults, effects[i].NumDefaults);
1739         for (j = 0; j < min(ARRAY_SIZE(params), effects[i].NumDefaults); j++)
1740         {
1741             int k;
1742             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1743             ok_(__FILE__,line)(!strcmp(params[j].name, got_param->pParamName),
1744                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1745                params[j].name, got_param->pParamName);
1746             ok_(__FILE__,line)(D3DXEDT_FLOATS == got_param->Type,
1747                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1748                D3DXEDT_FLOATS, got_param->Type);
1749             ok_(__FILE__,line)(params[j].num_bytes == got_param->NumBytes,
1750                "effect[%u].pDefaults[%u].NumBytes: Expected %u, got %u\n", i, j,
1751                params[j].num_bytes, got_param->NumBytes);
1752             for (k = 0; k < min(params[j].num_bytes, got_param->NumBytes) / 4; k++)
1753             {
1754                 FLOAT expected = ((FLOAT*)((BYTE*)&materials[i] + params[j].value_offset))[k];
1755                 FLOAT got = ((FLOAT*)got_param->pValue)[k];
1756                 ok_(__FILE__,line)(compare(expected, got),
1757                    "effect[%u].pDefaults[%u] float value %u: Expected %g, got %g\n", i, j, k, expected, got);
1758             }
1759         }
1760         if (effects[i].NumDefaults > ARRAY_SIZE(params)) {
1761             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1762             static const char *expected_name = "Texture0@Name";
1763
1764             ok_(__FILE__,line)(!strcmp(expected_name, got_param->pParamName),
1765                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1766                expected_name, got_param->pParamName);
1767             ok_(__FILE__,line)(D3DXEDT_STRING == got_param->Type,
1768                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1769                D3DXEDT_STRING, got_param->Type);
1770             if (materials[i].pTextureFilename) {
1771                 ok_(__FILE__,line)(strlen(materials[i].pTextureFilename) + 1 == got_param->NumBytes,
1772                    "effect[%u] texture filename length: Expected %u, got %u\n", i,
1773                    (DWORD)strlen(materials[i].pTextureFilename) + 1, got_param->NumBytes);
1774                 ok_(__FILE__,line)(!strcmp(materials[i].pTextureFilename, got_param->pValue),
1775                    "effect[%u] texture filename: Expected '%s', got '%s'\n", i,
1776                    materials[i].pTextureFilename, (char*)got_param->pValue);
1777             }
1778         }
1779     }
1780 }
1781
1782 static LPSTR strdupA(LPCSTR p)
1783 {
1784     LPSTR ret;
1785     if (!p) return NULL;
1786     ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
1787     if (ret) strcpy(ret, p);
1788     return ret;
1789 }
1790
1791 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
1792 {
1793     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
1794     if (frame) {
1795         HeapFree(GetProcessHeap(), 0, frame->Name);
1796         HeapFree(GetProcessHeap(), 0, frame);
1797     }
1798     return D3D_OK;
1799 }
1800
1801 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface, LPCSTR name, LPD3DXFRAME *new_frame)
1802 {
1803     LPD3DXFRAME frame;
1804
1805     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
1806     frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
1807     if (!frame)
1808         return E_OUTOFMEMORY;
1809     if (name) {
1810         frame->Name = strdupA(name);
1811         if (!frame->Name) {
1812             HeapFree(GetProcessHeap(), 0, frame);
1813             return E_OUTOFMEMORY;
1814         }
1815     }
1816     *new_frame = frame;
1817     return D3D_OK;
1818 }
1819
1820 static HRESULT destroy_mesh_container(LPD3DXMESHCONTAINER mesh_container)
1821 {
1822     int i;
1823
1824     if (!mesh_container)
1825         return D3D_OK;
1826     HeapFree(GetProcessHeap(), 0, mesh_container->Name);
1827     if (U(mesh_container->MeshData).pMesh)
1828         IUnknown_Release(U(mesh_container->MeshData).pMesh);
1829     if (mesh_container->pMaterials) {
1830         for (i = 0; i < mesh_container->NumMaterials; i++)
1831             HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials[i].pTextureFilename);
1832         HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials);
1833     }
1834     if (mesh_container->pEffects) {
1835         for (i = 0; i < mesh_container->NumMaterials; i++) {
1836             HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pEffectFilename);
1837             if (mesh_container->pEffects[i].pDefaults) {
1838                 int j;
1839                 for (j = 0; j < mesh_container->pEffects[i].NumDefaults; j++) {
1840                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pParamName);
1841                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pValue);
1842                 }
1843                 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults);
1844             }
1845         }
1846         HeapFree(GetProcessHeap(), 0, mesh_container->pEffects);
1847     }
1848     HeapFree(GetProcessHeap(), 0, mesh_container->pAdjacency);
1849     if (mesh_container->pSkinInfo)
1850         IUnknown_Release(mesh_container->pSkinInfo);
1851     HeapFree(GetProcessHeap(), 0, mesh_container);
1852     return D3D_OK;
1853 }
1854
1855 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_DestroyMeshContainer(ID3DXAllocateHierarchy *iface, LPD3DXMESHCONTAINER mesh_container)
1856 {
1857     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyMeshContainer(%p, %p)\n", iface, mesh_container);
1858     return destroy_mesh_container(mesh_container);
1859 }
1860
1861 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_CreateMeshContainer(ID3DXAllocateHierarchy *iface,
1862         LPCSTR name, CONST D3DXMESHDATA *mesh_data, CONST D3DXMATERIAL *materials,
1863         CONST D3DXEFFECTINSTANCE *effects, DWORD num_materials, CONST DWORD *adjacency,
1864         LPD3DXSKININFO skin_info, LPD3DXMESHCONTAINER *new_mesh_container)
1865 {
1866     LPD3DXMESHCONTAINER mesh_container = NULL;
1867     int i;
1868
1869     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateMeshContainer(%p, '%s', %u, %p, %p, %p, %d, %p, %p, %p)\n",
1870             iface, name, mesh_data->Type, U(*mesh_data).pMesh, materials, effects,
1871             num_materials, adjacency, skin_info, *new_mesh_container);
1872
1873     mesh_container = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mesh_container));
1874     if (!mesh_container)
1875         return E_OUTOFMEMORY;
1876
1877     if (name) {
1878         mesh_container->Name = strdupA(name);
1879         if (!mesh_container->Name)
1880             goto error;
1881     }
1882
1883     mesh_container->NumMaterials = num_materials;
1884     if (num_materials) {
1885         mesh_container->pMaterials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*materials));
1886         if (!mesh_container->pMaterials)
1887             goto error;
1888
1889         memcpy(mesh_container->pMaterials, materials, num_materials * sizeof(*materials));
1890         for (i = 0; i < num_materials; i++)
1891             mesh_container->pMaterials[i].pTextureFilename = NULL;
1892         for (i = 0; i < num_materials; i++) {
1893             if (materials[i].pTextureFilename) {
1894                 mesh_container->pMaterials[i].pTextureFilename = strdupA(materials[i].pTextureFilename);
1895                 if (!mesh_container->pMaterials[i].pTextureFilename)
1896                     goto error;
1897             }
1898         }
1899
1900         mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
1901         if (!mesh_container->pEffects)
1902             goto error;
1903         for (i = 0; i < num_materials; i++) {
1904             int j;
1905             const D3DXEFFECTINSTANCE *effect_src = &effects[i];
1906             D3DXEFFECTINSTANCE *effect_dest = &mesh_container->pEffects[i];
1907
1908             if (effect_src->pEffectFilename) {
1909                 effect_dest->pEffectFilename = strdupA(effect_src->pEffectFilename);
1910                 if (!effect_dest->pEffectFilename)
1911                     goto error;
1912             }
1913             effect_dest->pDefaults = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1914                     effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
1915             if (!effect_dest->pDefaults)
1916                 goto error;
1917             effect_dest->NumDefaults = effect_src->NumDefaults;
1918             for (j = 0; j < effect_src->NumDefaults; j++) {
1919                 const D3DXEFFECTDEFAULT *default_src = &effect_src->pDefaults[j];
1920                 D3DXEFFECTDEFAULT *default_dest = &effect_dest->pDefaults[j];
1921
1922                 if (default_src->pParamName) {
1923                     default_dest->pParamName = strdupA(default_src->pParamName);
1924                     if (!default_dest->pParamName)
1925                         goto error;
1926                 }
1927                 default_dest->NumBytes = default_src->NumBytes;
1928                 default_dest->Type = default_src->Type;
1929                 default_dest->pValue = HeapAlloc(GetProcessHeap(), 0, default_src->NumBytes);
1930                 memcpy(default_dest->pValue, default_src->pValue, default_src->NumBytes);
1931             }
1932         }
1933     }
1934
1935     ok(adjacency != NULL, "Expected non-NULL adjacency, got NULL\n");
1936     if (adjacency) {
1937         if (mesh_data->Type == D3DXMESHTYPE_MESH || mesh_data->Type == D3DXMESHTYPE_PMESH) {
1938             ID3DXBaseMesh *basemesh = (ID3DXBaseMesh*)U(*mesh_data).pMesh;
1939             DWORD num_faces = basemesh->lpVtbl->GetNumFaces(basemesh);
1940             size_t size = num_faces * sizeof(DWORD) * 3;
1941             mesh_container->pAdjacency = HeapAlloc(GetProcessHeap(), 0, size);
1942             if (!mesh_container->pAdjacency)
1943                 goto error;
1944             memcpy(mesh_container->pAdjacency, adjacency, size);
1945         } else {
1946             ok(mesh_data->Type == D3DXMESHTYPE_PATCHMESH, "Unknown mesh type %u\n", mesh_data->Type);
1947             if (mesh_data->Type == D3DXMESHTYPE_PATCHMESH)
1948                 trace("FIXME: copying adjacency data for patch mesh not implemented\n");
1949         }
1950     }
1951
1952     memcpy(&mesh_container->MeshData, mesh_data, sizeof(*mesh_data));
1953     if (U(*mesh_data).pMesh)
1954         IUnknown_AddRef(U(*mesh_data).pMesh);
1955     if (skin_info) {
1956         mesh_container->pSkinInfo = skin_info;
1957         skin_info->lpVtbl->AddRef(skin_info);
1958     }
1959     *new_mesh_container = mesh_container;
1960
1961     return S_OK;
1962 error:
1963     destroy_mesh_container(mesh_container);
1964     return E_OUTOFMEMORY;
1965 }
1966
1967 static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
1968     ID3DXAllocateHierarchyImpl_CreateFrame,
1969     ID3DXAllocateHierarchyImpl_CreateMeshContainer,
1970     ID3DXAllocateHierarchyImpl_DestroyFrame,
1971     ID3DXAllocateHierarchyImpl_DestroyMeshContainer,
1972 };
1973 static ID3DXAllocateHierarchy alloc_hier = { &ID3DXAllocateHierarchyImpl_Vtbl };
1974
1975 #define test_LoadMeshFromX(device, xfile_str, vertex_array, fvf, index_array, materials_array, check_adjacency) \
1976     test_LoadMeshFromX_(__LINE__, device, xfile_str, sizeof(xfile_str) - 1, vertex_array, ARRAY_SIZE(vertex_array), fvf, \
1977             index_array, ARRAY_SIZE(index_array), sizeof(*index_array), materials_array, ARRAY_SIZE(materials_array), \
1978             check_adjacency);
1979 static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char *xfile_str, size_t xfile_strlen,
1980         const void *vertices, DWORD num_vertices, DWORD fvf, const void *indices, DWORD num_indices, size_t index_size,
1981         const D3DXMATERIAL *expected_materials, DWORD expected_num_materials, BOOL check_adjacency)
1982 {
1983     HRESULT hr;
1984     ID3DXBuffer *materials = NULL;
1985     ID3DXBuffer *effects = NULL;
1986     ID3DXBuffer *adjacency = NULL;
1987     ID3DXMesh *mesh = NULL;
1988     DWORD num_materials = 0;
1989
1990     /* Adjacency is not checked when the X file contains multiple meshes,
1991      * since calling GenerateAdjacency on the merged mesh is not equivalent
1992      * to calling GenerateAdjacency on the individual meshes and then merging
1993      * the adjacency data. */
1994     hr = D3DXLoadMeshFromXInMemory(xfile_str, xfile_strlen, D3DXMESH_MANAGED, device,
1995             check_adjacency ? &adjacency : NULL, &materials, &effects, &num_materials, &mesh);
1996     ok_(__FILE__,line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1997     if (SUCCEEDED(hr)) {
1998         D3DXMATERIAL *materials_ptr = materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL;
1999         D3DXEFFECTINSTANCE *effects_ptr = effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL;
2000         DWORD *adjacency_ptr = check_adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL;
2001
2002         check_vertex_buffer_(line, mesh, vertices, num_vertices, fvf);
2003         check_index_buffer_(line, mesh, indices, num_indices, index_size);
2004         check_materials_(line, materials_ptr, num_materials, expected_materials, expected_num_materials);
2005         check_generated_effects_(line, materials_ptr, num_materials, effects_ptr);
2006         if (check_adjacency)
2007             check_generated_adjacency_(line, mesh, adjacency_ptr, 0.0f);
2008
2009         if (materials) ID3DXBuffer_Release(materials);
2010         if (effects) ID3DXBuffer_Release(effects);
2011         if (adjacency) ID3DXBuffer_Release(adjacency);
2012         IUnknown_Release(mesh);
2013     }
2014 }
2015
2016 static void D3DXLoadMeshTest(void)
2017 {
2018     static const char empty_xfile[] = "xof 0303txt 0032";
2019     /*________________________*/
2020     static const char simple_xfile[] =
2021         "xof 0303txt 0032"
2022         "Mesh {"
2023             "3;"
2024             "0.0; 0.0; 0.0;,"
2025             "0.0; 1.0; 0.0;,"
2026             "1.0; 1.0; 0.0;;"
2027             "1;"
2028             "3; 0, 1, 2;;"
2029         "}";
2030     static const WORD simple_index_buffer[] = {0, 1, 2};
2031     static const D3DXVECTOR3 simple_vertex_buffer[] = {
2032         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}
2033     };
2034     const DWORD simple_fvf = D3DFVF_XYZ;
2035     static const char framed_xfile[] =
2036         "xof 0303txt 0032"
2037         "Frame {"
2038             "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;; }"
2039             "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */
2040               "1.0, 0.0, 0.0, 0.0,"
2041               "0.0, 1.0, 0.0, 0.0,"
2042               "0.0, 0.0, 1.0, 0.0,"
2043               "0.0, 0.0, 2.0, 1.0;;"
2044             "}"
2045             "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;; }"
2046             "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */
2047               "1.0, 0.0, 0.0, 0.0,"
2048               "0.0, 1.0, 0.0, 0.0,"
2049               "0.0, 0.0, 1.0, 0.0,"
2050               "0.0, 0.0, 3.0, 1.0;;"
2051             "}"
2052             "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;; }"
2053         "}";
2054     static const WORD framed_index_buffer[] = { 0, 1, 2 };
2055     static const D3DXVECTOR3 framed_vertex_buffers[3][3] = {
2056         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}},
2057         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}},
2058         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {3.0, 1.0, 0.0}},
2059     };
2060     static const WORD merged_index_buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
2061     /* frame transforms accumulates for D3DXLoadMeshFromX */
2062     static const D3DXVECTOR3 merged_vertex_buffer[] = {
2063         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0},
2064         {0.0, 0.0, 2.0}, {0.0, 1.0, 2.0}, {2.0, 1.0, 2.0},
2065         {0.0, 0.0, 5.0}, {0.0, 1.0, 5.0}, {3.0, 1.0, 5.0},
2066     };
2067     const DWORD framed_fvf = D3DFVF_XYZ;
2068     /*________________________*/
2069     static const char box_xfile[] =
2070         "xof 0303txt 0032"
2071         "Mesh {"
2072             "8;" /* DWORD nVertices; */
2073             /* array Vector vertices[nVertices]; */
2074             "0.0; 0.0; 0.0;,"
2075             "0.0; 0.0; 1.0;,"
2076             "0.0; 1.0; 0.0;,"
2077             "0.0; 1.0; 1.0;,"
2078             "1.0; 0.0; 0.0;,"
2079             "1.0; 0.0; 1.0;,"
2080             "1.0; 1.0; 0.0;,"
2081             "1.0; 1.0; 1.0;;"
2082             "6;" /* DWORD nFaces; */
2083             /* array MeshFace faces[nFaces]; */
2084             "4; 0, 1, 3, 2;," /* (left side) */
2085             "4; 2, 3, 7, 6;," /* (top side) */
2086             "4; 6, 7, 5, 4;," /* (right side) */
2087             "4; 1, 0, 4, 5;," /* (bottom side) */
2088             "4; 1, 5, 7, 3;," /* (back side) */
2089             "4; 0, 2, 6, 4;;" /* (front side) */
2090             "MeshNormals {"
2091               "6;" /* DWORD nNormals; */
2092               /* array Vector normals[nNormals]; */
2093               "-1.0; 0.0; 0.0;,"
2094               "0.0; 1.0; 0.0;,"
2095               "1.0; 0.0; 0.0;,"
2096               "0.0; -1.0; 0.0;,"
2097               "0.0; 0.0; 1.0;,"
2098               "0.0; 0.0; -1.0;;"
2099               "6;" /* DWORD nFaceNormals; */
2100               /* array MeshFace faceNormals[nFaceNormals]; */
2101               "4; 0, 0, 0, 0;,"
2102               "4; 1, 1, 1, 1;,"
2103               "4; 2, 2, 2, 2;,"
2104               "4; 3, 3, 3, 3;,"
2105               "4; 4, 4, 4, 4;,"
2106               "4; 5, 5, 5, 5;;"
2107             "}"
2108             "MeshMaterialList materials {"
2109               "2;" /* DWORD nMaterials; */
2110               "6;" /* DWORD nFaceIndexes; */
2111               /* array DWORD faceIndexes[nFaceIndexes]; */
2112               "0, 0, 0, 1, 1, 1;;"
2113               "Material {"
2114                 /* ColorRGBA faceColor; */
2115                 "0.0; 0.0; 1.0; 1.0;;"
2116                 /* FLOAT power; */
2117                 "0.5;"
2118                 /* ColorRGB specularColor; */
2119                 "1.0; 1.0; 1.0;;"
2120                 /* ColorRGB emissiveColor; */
2121                 "0.0; 0.0; 0.0;;"
2122               "}"
2123               "Material {"
2124                 /* ColorRGBA faceColor; */
2125                 "1.0; 1.0; 1.0; 1.0;;"
2126                 /* FLOAT power; */
2127                 "1.0;"
2128                 /* ColorRGB specularColor; */
2129                 "1.0; 1.0; 1.0;;"
2130                 /* ColorRGB emissiveColor; */
2131                 "0.0; 0.0; 0.0;;"
2132                 "TextureFilename { \"texture.jpg\"; }"
2133               "}"
2134             "}"
2135             "MeshVertexColors {"
2136               "8;" /* DWORD nVertexColors; */
2137               /* array IndexedColor vertexColors[nVertexColors]; */
2138               "0; 0.0; 0.0; 0.0; 0.0;;"
2139               "1; 0.0; 0.0; 1.0; 0.1;;"
2140               "2; 0.0; 1.0; 0.0; 0.2;;"
2141               "3; 0.0; 1.0; 1.0; 0.3;;"
2142               "4; 1.0; 0.0; 0.0; 0.4;;"
2143               "5; 1.0; 0.0; 1.0; 0.5;;"
2144               "6; 1.0; 1.0; 0.0; 0.6;;"
2145               "7; 1.0; 1.0; 1.0; 0.7;;"
2146             "}"
2147             "MeshTextureCoords {"
2148               "8;" /* DWORD nTextureCoords; */
2149               /* array Coords2d textureCoords[nTextureCoords]; */
2150               "0.0; 1.0;,"
2151               "1.0; 1.0;,"
2152               "0.0; 0.0;,"
2153               "1.0; 0.0;,"
2154               "1.0; 1.0;,"
2155               "0.0; 1.0;,"
2156               "1.0; 0.0;,"
2157               "0.0; 0.0;;"
2158             "}"
2159           "}";
2160     static const WORD box_index_buffer[] = {
2161         0, 1, 3,
2162         0, 3, 2,
2163         8, 9, 7,
2164         8, 7, 6,
2165         10, 11, 5,
2166         10, 5, 4,
2167         12, 13, 14,
2168         12, 14, 15,
2169         16, 17, 18,
2170         16, 18, 19,
2171         20, 21, 22,
2172         20, 22, 23,
2173     };
2174     static const struct {
2175         D3DXVECTOR3 position;
2176         D3DXVECTOR3 normal;
2177         D3DCOLOR diffuse;
2178         D3DXVECTOR2 tex_coords;
2179     } box_vertex_buffer[] = {
2180         {{0.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, 0x00000000, {0.0, 1.0}},
2181         {{0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2182         {{0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2183         {{0.0, 1.0, 1.0}, {-1.0, 0.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2184         {{1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2185         {{1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2186         {{1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2187         {{1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2188         {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2189         {{0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2190         {{1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2191         {{1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2192         {{0.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2193         {{0.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x00000000, {0.0, 1.0}},
2194         {{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2195         {{1.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2196         {{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x1a0000ff, {1.0, 1.0}},
2197         {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x80ff00ff, {0.0, 1.0}},
2198         {{1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0xb3ffffff, {0.0, 0.0}},
2199         {{0.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0x4d00ffff, {1.0, 0.0}},
2200         {{0.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x00000000, {0.0, 1.0}},
2201         {{0.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x3300ff00, {0.0, 0.0}},
2202         {{1.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x99ffff00, {1.0, 0.0}},
2203         {{1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x66ff0000, {1.0, 1.0}},
2204     };
2205     static const D3DXMATERIAL box_materials[] = {
2206         {
2207             {
2208                 {0.0, 0.0, 1.0, 1.0}, /* Diffuse */
2209                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2210                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2211                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2212                 0.5, /* Power */
2213             },
2214             NULL, /* pTextureFilename */
2215         },
2216         {
2217             {
2218                 {1.0, 1.0, 1.0, 1.0}, /* Diffuse */
2219                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2220                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2221                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2222                 1.0, /* Power */
2223             },
2224             (char *)"texture.jpg", /* pTextureFilename */
2225         },
2226     };
2227     const DWORD box_fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
2228     /*________________________*/
2229     static const D3DXMATERIAL default_materials[] = {
2230         {
2231             {
2232                 {0.5, 0.5, 0.5, 0.0}, /* Diffuse */
2233                 {0.0, 0.0, 0.0, 0.0}, /* Ambient */
2234                 {0.5, 0.5, 0.5, 0.0}, /* Specular */
2235                 {0.0, 0.0, 0.0, 0.0}, /* Emissive */
2236                 0.0, /* Power */
2237             },
2238             NULL, /* pTextureFilename */
2239         }
2240     };
2241     HRESULT hr;
2242     HWND wnd = NULL;
2243     IDirect3D9 *d3d = NULL;
2244     IDirect3DDevice9 *device = NULL;
2245     D3DPRESENT_PARAMETERS d3dpp;
2246     ID3DXMesh *mesh = NULL;
2247     D3DXFRAME *frame_hier = NULL;
2248     D3DXMATRIX transform;
2249
2250     wnd = CreateWindow("static", "d3dx9_test", WS_POPUP, 0, 0, 1000, 1000, NULL, NULL, NULL, NULL);
2251     if (!wnd)
2252     {
2253         skip("Couldn't create application window\n");
2254         return;
2255     }
2256     d3d = Direct3DCreate9(D3D_SDK_VERSION);
2257     if (!d3d)
2258     {
2259         skip("Couldn't create IDirect3D9 object\n");
2260         goto cleanup;
2261     }
2262
2263     ZeroMemory(&d3dpp, sizeof(d3dpp));
2264     d3dpp.Windowed = TRUE;
2265     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2266     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2267     if (FAILED(hr))
2268     {
2269         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2270         goto cleanup;
2271     }
2272
2273     hr = D3DXLoadMeshHierarchyFromXInMemory(NULL, sizeof(simple_xfile) - 1,
2274             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2275     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2276
2277     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, 0,
2278             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2279     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2280
2281     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2282             D3DXMESH_MANAGED, NULL, &alloc_hier, NULL, &frame_hier, NULL);
2283     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2284
2285     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2286             D3DXMESH_MANAGED, device, NULL, NULL, &frame_hier, NULL);
2287     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2288
2289     hr = D3DXLoadMeshHierarchyFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1,
2290             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2291     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2292
2293     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2294             D3DXMESH_MANAGED, device, &alloc_hier, NULL, NULL, NULL);
2295     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2296
2297     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2298             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2299     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2300     if (SUCCEEDED(hr)) {
2301         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2302
2303         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2304         D3DXMatrixIdentity(&transform);
2305         check_matrix(&frame_hier->TransformationMatrix, &transform);
2306
2307         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2308         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2309            D3DXMESHTYPE_MESH, container->MeshData.Type);
2310         mesh = U(container->MeshData).pMesh;
2311         check_vertex_buffer(mesh, simple_vertex_buffer, ARRAY_SIZE(simple_vertex_buffer), simple_fvf);
2312         check_index_buffer(mesh, simple_index_buffer, ARRAY_SIZE(simple_index_buffer), sizeof(*simple_index_buffer));
2313         check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2314         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2315         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2316         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2317         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2318         frame_hier = NULL;
2319     }
2320
2321     hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1,
2322             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2323     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2324     if (SUCCEEDED(hr)) {
2325         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2326
2327         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2328         D3DXMatrixIdentity(&transform);
2329         check_matrix(&frame_hier->TransformationMatrix, &transform);
2330
2331         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2332         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2333            D3DXMESHTYPE_MESH, container->MeshData.Type);
2334         mesh = U(container->MeshData).pMesh;
2335         check_vertex_buffer(mesh, box_vertex_buffer, ARRAY_SIZE(box_vertex_buffer), box_fvf);
2336         check_index_buffer(mesh, box_index_buffer, ARRAY_SIZE(box_index_buffer), sizeof(*box_index_buffer));
2337         check_materials(container->pMaterials, container->NumMaterials, box_materials, ARRAY_SIZE(box_materials));
2338         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2339         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2340         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2341         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2342         frame_hier = NULL;
2343     }
2344
2345     hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1,
2346             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2347     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2348     if (SUCCEEDED(hr)) {
2349         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2350         int i;
2351
2352         ok(!strcmp(frame_hier->Name, ""), "Expected '', got '%s'\n", frame_hier->Name);
2353         /* last frame transform replaces the first */
2354         D3DXMatrixIdentity(&transform);
2355         U(transform).m[3][2] = 3.0;
2356         check_matrix(&frame_hier->TransformationMatrix, &transform);
2357
2358         for (i = 0; i < 3; i++) {
2359             ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2360             ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2361                D3DXMESHTYPE_MESH, container->MeshData.Type);
2362             mesh = U(container->MeshData).pMesh;
2363             check_vertex_buffer(mesh, framed_vertex_buffers[i], ARRAY_SIZE(framed_vertex_buffers[0]), framed_fvf);
2364             check_index_buffer(mesh, framed_index_buffer, ARRAY_SIZE(framed_index_buffer), sizeof(*framed_index_buffer));
2365             check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2366             check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2367             check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2368             container = container->pNextMeshContainer;
2369         }
2370         ok(container == NULL, "Expected NULL, got %p\n", container);
2371         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2372         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2373         frame_hier = NULL;
2374     }
2375
2376
2377     hr = D3DXLoadMeshFromXInMemory(NULL, 0, D3DXMESH_MANAGED,
2378                                    device, NULL, NULL, NULL, NULL, &mesh);
2379     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2380
2381     hr = D3DXLoadMeshFromXInMemory(NULL, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2382                                    device, NULL, NULL, NULL, NULL, &mesh);
2383     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2384
2385     hr = D3DXLoadMeshFromXInMemory(simple_xfile, 0, D3DXMESH_MANAGED,
2386                                    device, NULL, NULL, NULL, NULL, &mesh);
2387     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2388
2389     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2390                                    device, NULL, NULL, NULL, NULL, NULL);
2391     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2392
2393     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2394                                    NULL, NULL, NULL, NULL, NULL, &mesh);
2395     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2396
2397     hr = D3DXLoadMeshFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1, D3DXMESH_MANAGED,
2398                                    device, NULL, NULL, NULL, NULL, &mesh);
2399     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2400
2401     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2402                                    device, NULL, NULL, NULL, NULL, &mesh);
2403     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2404     if (SUCCEEDED(hr))
2405         IUnknown_Release(mesh);
2406
2407     test_LoadMeshFromX(device, simple_xfile, simple_vertex_buffer, simple_fvf, simple_index_buffer, default_materials, TRUE);
2408     test_LoadMeshFromX(device, box_xfile, box_vertex_buffer, box_fvf, box_index_buffer, box_materials, TRUE);
2409     test_LoadMeshFromX(device, framed_xfile, merged_vertex_buffer, framed_fvf, merged_index_buffer, default_materials, FALSE);
2410
2411 cleanup:
2412     if (device) IDirect3DDevice9_Release(device);
2413     if (d3d) IDirect3D9_Release(d3d);
2414     if (wnd) DestroyWindow(wnd);
2415 }
2416
2417 static void D3DXCreateBoxTest(void)
2418 {
2419     HRESULT hr;
2420     HWND wnd;
2421     WNDCLASS wc={0};
2422     IDirect3D9* d3d;
2423     IDirect3DDevice9* device;
2424     D3DPRESENT_PARAMETERS d3dpp;
2425     ID3DXMesh* box;
2426     ID3DXBuffer* ppBuffer;
2427     DWORD *buffer;
2428     static const DWORD adjacency[36]=
2429         {6, 9, 1, 2, 10, 0,
2430          1, 9, 3, 4, 10, 2,
2431          3, 8, 5, 7, 11, 4,
2432          0, 11, 7, 5, 8, 6,
2433          7, 4, 9, 2, 0, 8,
2434          1, 3, 11, 5, 6, 10};
2435     unsigned int i;
2436
2437     wc.lpfnWndProc = DefWindowProcA;
2438     wc.lpszClassName = "d3dx9_test_wc";
2439     if (!RegisterClass(&wc))
2440     {
2441         skip("RegisterClass failed\n");
2442         return;
2443     }
2444
2445     wnd = CreateWindow("d3dx9_test_wc", "d3dx9_test",
2446                         WS_SYSMENU | WS_POPUP , 0, 0, 640, 480, 0, 0, 0, 0);
2447     ok(wnd != NULL, "Expected to have a window, received NULL\n");
2448     if (!wnd)
2449     {
2450         skip("Couldn't create application window\n");
2451         return;
2452     }
2453
2454     d3d = Direct3DCreate9(D3D_SDK_VERSION);
2455     if (!d3d)
2456     {
2457         skip("Couldn't create IDirect3D9 object\n");
2458         DestroyWindow(wnd);
2459         return;
2460     }
2461
2462     memset(&d3dpp, 0, sizeof(d3dpp));
2463     d3dpp.Windowed = TRUE;
2464     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2465     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2466     if (FAILED(hr))
2467     {
2468         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2469         IDirect3D9_Release(d3d);
2470         DestroyWindow(wnd);
2471         return;
2472     }
2473
2474     hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
2475     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2476
2477     hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
2478     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2479
2480     hr = D3DXCreateBox(device,-2.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,22.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     ppBuffer = NULL;
2490     hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
2491     todo_wine ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2492
2493     if (FAILED(hr))
2494     {
2495         skip("D3DXCreateBox failed\n");
2496         goto end;
2497     }
2498
2499     buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
2500     for(i=0; i<36; i++)
2501         todo_wine ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
2502
2503     box->lpVtbl->Release(box);
2504
2505 end:
2506     IDirect3DDevice9_Release(device);
2507     IDirect3D9_Release(d3d);
2508     if (ppBuffer) ID3DXBuffer_Release(ppBuffer);
2509     DestroyWindow(wnd);
2510 }
2511
2512 struct sincos_table
2513 {
2514     float *sin;
2515     float *cos;
2516 };
2517
2518 static void free_sincos_table(struct sincos_table *sincos_table)
2519 {
2520     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
2521     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2522 }
2523
2524 /* pre compute sine and cosine tables; caller must free */
2525 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
2526 {
2527     float angle;
2528     int i;
2529
2530     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2531     if (!sincos_table->sin)
2532     {
2533         return FALSE;
2534     }
2535     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2536     if (!sincos_table->cos)
2537     {
2538         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2539         return FALSE;
2540     }
2541
2542     angle = angle_start;
2543     for (i = 0; i < n; i++)
2544     {
2545         sincos_table->sin[i] = sin(angle);
2546         sincos_table->cos[i] = cos(angle);
2547         angle += angle_step;
2548     }
2549
2550     return TRUE;
2551 }
2552
2553 static WORD vertex_index(UINT slices, int slice, int stack)
2554 {
2555     return stack*slices+slice+1;
2556 }
2557
2558 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
2559 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
2560 {
2561     float theta_step, theta_start;
2562     struct sincos_table theta;
2563     float phi_step, phi_start;
2564     struct sincos_table phi;
2565     DWORD number_of_vertices, number_of_faces;
2566     DWORD vertex, face;
2567     int slice, stack;
2568
2569     /* theta = angle on xy plane wrt x axis */
2570     theta_step = M_PI / stacks;
2571     theta_start = theta_step;
2572
2573     /* phi = angle on xz plane wrt z axis */
2574     phi_step = -2 * M_PI / slices;
2575     phi_start = M_PI / 2;
2576
2577     if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
2578     {
2579         return FALSE;
2580     }
2581     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
2582     {
2583         free_sincos_table(&theta);
2584         return FALSE;
2585     }
2586
2587     number_of_vertices = 2 + slices * (stacks-1);
2588     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
2589
2590     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2591     {
2592         free_sincos_table(&phi);
2593         free_sincos_table(&theta);
2594         return FALSE;
2595     }
2596
2597     vertex = 0;
2598     face = 0;
2599
2600     mesh->vertices[vertex].normal.x = 0.0f;
2601     mesh->vertices[vertex].normal.y = 0.0f;
2602     mesh->vertices[vertex].normal.z = 1.0f;
2603     mesh->vertices[vertex].position.x = 0.0f;
2604     mesh->vertices[vertex].position.y = 0.0f;
2605     mesh->vertices[vertex].position.z = radius;
2606     vertex++;
2607
2608     for (stack = 0; stack < stacks - 1; stack++)
2609     {
2610         for (slice = 0; slice < slices; slice++)
2611         {
2612             mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
2613             mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
2614             mesh->vertices[vertex].normal.z = theta.cos[stack];
2615             mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
2616             mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
2617             mesh->vertices[vertex].position.z = radius * theta.cos[stack];
2618             vertex++;
2619
2620             if (slice > 0)
2621             {
2622                 if (stack == 0)
2623                 {
2624                     /* top stack is triangle fan */
2625                     mesh->faces[face][0] = 0;
2626                     mesh->faces[face][1] = slice + 1;
2627                     mesh->faces[face][2] = slice;
2628                     face++;
2629                 }
2630                 else
2631                 {
2632                     /* stacks in between top and bottom are quad strips */
2633                     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2634                     mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2635                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2636                     face++;
2637
2638                     mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2639                     mesh->faces[face][1] = vertex_index(slices, slice, stack);
2640                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2641                     face++;
2642                 }
2643             }
2644         }
2645
2646         if (stack == 0)
2647         {
2648             mesh->faces[face][0] = 0;
2649             mesh->faces[face][1] = 1;
2650             mesh->faces[face][2] = slice;
2651             face++;
2652         }
2653         else
2654         {
2655             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2656             mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2657             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2658             face++;
2659
2660             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2661             mesh->faces[face][1] = vertex_index(slices, 0, stack);
2662             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2663             face++;
2664         }
2665     }
2666
2667     mesh->vertices[vertex].position.x = 0.0f;
2668     mesh->vertices[vertex].position.y = 0.0f;
2669     mesh->vertices[vertex].position.z = -radius;
2670     mesh->vertices[vertex].normal.x = 0.0f;
2671     mesh->vertices[vertex].normal.y = 0.0f;
2672     mesh->vertices[vertex].normal.z = -1.0f;
2673
2674     /* bottom stack is triangle fan */
2675     for (slice = 1; slice < slices; slice++)
2676     {
2677         mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2678         mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2679         mesh->faces[face][2] = vertex;
2680         face++;
2681     }
2682
2683     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2684     mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2685     mesh->faces[face][2] = vertex;
2686
2687     free_sincos_table(&phi);
2688     free_sincos_table(&theta);
2689
2690     return TRUE;
2691 }
2692
2693 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
2694 {
2695     HRESULT hr;
2696     ID3DXMesh *sphere;
2697     struct mesh mesh;
2698     char name[256];
2699
2700     hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
2701     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2702     if (hr != D3D_OK)
2703     {
2704         skip("Couldn't create sphere\n");
2705         return;
2706     }
2707
2708     if (!compute_sphere(&mesh, radius, slices, stacks))
2709     {
2710         skip("Couldn't create mesh\n");
2711         sphere->lpVtbl->Release(sphere);
2712         return;
2713     }
2714
2715     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2716
2717     sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
2718     compare_mesh(name, sphere, &mesh);
2719
2720     free_mesh(&mesh);
2721
2722     sphere->lpVtbl->Release(sphere);
2723 }
2724
2725 static void D3DXCreateSphereTest(void)
2726 {
2727     HRESULT hr;
2728     HWND wnd;
2729     IDirect3D9* d3d;
2730     IDirect3DDevice9* device;
2731     D3DPRESENT_PARAMETERS d3dpp;
2732     ID3DXMesh* sphere = NULL;
2733
2734     hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
2735     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2736
2737     hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
2738     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2739
2740     hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
2741     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2742
2743     hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
2744     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2745
2746     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
2747     d3d = Direct3DCreate9(D3D_SDK_VERSION);
2748     if (!wnd)
2749     {
2750         skip("Couldn't create application window\n");
2751         return;
2752     }
2753     if (!d3d)
2754     {
2755         skip("Couldn't create IDirect3D9 object\n");
2756         DestroyWindow(wnd);
2757         return;
2758     }
2759
2760     ZeroMemory(&d3dpp, sizeof(d3dpp));
2761     d3dpp.Windowed = TRUE;
2762     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2763     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2764     if (FAILED(hr))
2765     {
2766         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2767         IDirect3D9_Release(d3d);
2768         DestroyWindow(wnd);
2769         return;
2770     }
2771
2772     hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
2773     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2774
2775     hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
2776     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2777
2778     hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
2779     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2780
2781     hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
2782     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2783
2784     test_sphere(device, 0.0f, 2, 2);
2785     test_sphere(device, 1.0f, 2, 2);
2786     test_sphere(device, 1.0f, 3, 2);
2787     test_sphere(device, 1.0f, 4, 4);
2788     test_sphere(device, 1.0f, 3, 4);
2789     test_sphere(device, 5.0f, 6, 7);
2790     test_sphere(device, 10.0f, 11, 12);
2791
2792     IDirect3DDevice9_Release(device);
2793     IDirect3D9_Release(d3d);
2794     DestroyWindow(wnd);
2795 }
2796
2797 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
2798 {
2799     float theta_step, theta_start;
2800     struct sincos_table theta;
2801     FLOAT delta_radius, radius, radius_step;
2802     FLOAT z, z_step, z_normal;
2803     DWORD number_of_vertices, number_of_faces;
2804     DWORD vertex, face;
2805     int slice, stack;
2806
2807     /* theta = angle on xy plane wrt x axis */
2808     theta_step = -2 * M_PI / slices;
2809     theta_start = M_PI / 2;
2810
2811     if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
2812     {
2813         return FALSE;
2814     }
2815
2816     number_of_vertices = 2 + (slices * (3 + stacks));
2817     number_of_faces = 2 * slices + stacks * (2 * slices);
2818
2819     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2820     {
2821         free_sincos_table(&theta);
2822         return FALSE;
2823     }
2824
2825     vertex = 0;
2826     face = 0;
2827
2828     delta_radius = radius1 - radius2;
2829     radius = radius1;
2830     radius_step = delta_radius / stacks;
2831
2832     z = -length / 2;
2833     z_step = length / stacks;
2834     z_normal = delta_radius / length;
2835     if (isnan(z_normal))
2836     {
2837         z_normal = 0.0f;
2838     }
2839
2840     mesh->vertices[vertex].normal.x = 0.0f;
2841     mesh->vertices[vertex].normal.y = 0.0f;
2842     mesh->vertices[vertex].normal.z = -1.0f;
2843     mesh->vertices[vertex].position.x = 0.0f;
2844     mesh->vertices[vertex].position.y = 0.0f;
2845     mesh->vertices[vertex++].position.z = z;
2846
2847     for (slice = 0; slice < slices; slice++, vertex++)
2848     {
2849         mesh->vertices[vertex].normal.x = 0.0f;
2850         mesh->vertices[vertex].normal.y = 0.0f;
2851         mesh->vertices[vertex].normal.z = -1.0f;
2852         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2853         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2854         mesh->vertices[vertex].position.z = z;
2855
2856         if (slice > 0)
2857         {
2858             mesh->faces[face][0] = 0;
2859             mesh->faces[face][1] = slice;
2860             mesh->faces[face++][2] = slice + 1;
2861         }
2862     }
2863
2864     mesh->faces[face][0] = 0;
2865     mesh->faces[face][1] = slice;
2866     mesh->faces[face++][2] = 1;
2867
2868     for (stack = 1; stack <= stacks+1; stack++)
2869     {
2870         for (slice = 0; slice < slices; slice++, vertex++)
2871         {
2872             mesh->vertices[vertex].normal.x = theta.cos[slice];
2873             mesh->vertices[vertex].normal.y = theta.sin[slice];
2874             mesh->vertices[vertex].normal.z = z_normal;
2875             D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
2876             mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2877             mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2878             mesh->vertices[vertex].position.z = z;
2879
2880             if (stack > 1 && slice > 0)
2881             {
2882                 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2883                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2884                 mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
2885
2886                 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2887                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2888                 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
2889             }
2890         }
2891
2892         if (stack > 1)
2893         {
2894             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2895             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2896             mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
2897
2898             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2899             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2900             mesh->faces[face++][2] = vertex_index(slices, 0, stack);
2901         }
2902
2903         if (stack < stacks + 1)
2904         {
2905             z += z_step;
2906             radius -= radius_step;
2907         }
2908     }
2909
2910     for (slice = 0; slice < slices; slice++, vertex++)
2911     {
2912         mesh->vertices[vertex].normal.x = 0.0f;
2913         mesh->vertices[vertex].normal.y = 0.0f;
2914         mesh->vertices[vertex].normal.z = 1.0f;
2915         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2916         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2917         mesh->vertices[vertex].position.z = z;
2918
2919         if (slice > 0)
2920         {
2921             mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
2922             mesh->faces[face][1] = number_of_vertices - 1;
2923             mesh->faces[face++][2] = vertex_index(slices, slice, stack);
2924         }
2925     }
2926
2927     mesh->vertices[vertex].position.x = 0.0f;
2928     mesh->vertices[vertex].position.y = 0.0f;
2929     mesh->vertices[vertex].position.z = z;
2930     mesh->vertices[vertex].normal.x = 0.0f;
2931     mesh->vertices[vertex].normal.y = 0.0f;
2932     mesh->vertices[vertex].normal.z = 1.0f;
2933
2934     mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
2935     mesh->faces[face][1] = number_of_vertices - 1;
2936     mesh->faces[face][2] = vertex_index(slices, 0, stack);
2937
2938     free_sincos_table(&theta);
2939
2940     return TRUE;
2941 }
2942
2943 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
2944 {
2945     HRESULT hr;
2946     ID3DXMesh *cylinder;
2947     struct mesh mesh;
2948     char name[256];
2949
2950     hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
2951     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2952     if (hr != D3D_OK)
2953     {
2954         skip("Couldn't create cylinder\n");
2955         return;
2956     }
2957
2958     if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
2959     {
2960         skip("Couldn't create mesh\n");
2961         cylinder->lpVtbl->Release(cylinder);
2962         return;
2963     }
2964
2965     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2966
2967     sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
2968     compare_mesh(name, cylinder, &mesh);
2969
2970     free_mesh(&mesh);
2971
2972     cylinder->lpVtbl->Release(cylinder);
2973 }
2974
2975 static void D3DXCreateCylinderTest(void)
2976 {
2977     HRESULT hr;
2978     HWND wnd;
2979     IDirect3D9* d3d;
2980     IDirect3DDevice9* device;
2981     D3DPRESENT_PARAMETERS d3dpp;
2982     ID3DXMesh* cylinder = NULL;
2983
2984     hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
2985     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2986
2987     hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
2988     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2989
2990     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
2991     d3d = Direct3DCreate9(D3D_SDK_VERSION);
2992     if (!wnd)
2993     {
2994         skip("Couldn't create application window\n");
2995         return;
2996     }
2997     if (!d3d)
2998     {
2999         skip("Couldn't create IDirect3D9 object\n");
3000         DestroyWindow(wnd);
3001         return;
3002     }
3003
3004     ZeroMemory(&d3dpp, sizeof(d3dpp));
3005     d3dpp.Windowed = TRUE;
3006     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
3007     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
3008     if (FAILED(hr))
3009     {
3010         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
3011         IDirect3D9_Release(d3d);
3012         DestroyWindow(wnd);
3013         return;
3014     }
3015
3016     hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3017     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3018
3019     hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3020     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3021
3022     if (SUCCEEDED(hr) && cylinder)
3023     {
3024         cylinder->lpVtbl->Release(cylinder);
3025     }
3026
3027     hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
3028     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3029
3030     hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
3031     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3032
3033     if (SUCCEEDED(hr) && cylinder)
3034     {
3035         cylinder->lpVtbl->Release(cylinder);
3036     }
3037
3038     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
3039     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3040
3041     /* Test with length == 0.0f succeeds */
3042     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
3043     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3044
3045     if (SUCCEEDED(hr) && cylinder)
3046     {
3047         cylinder->lpVtbl->Release(cylinder);
3048     }
3049
3050     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
3051     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3052
3053     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
3054     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3055
3056     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
3057     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3058
3059     test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
3060     test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
3061     test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
3062     test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
3063     test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
3064     test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
3065
3066     IDirect3DDevice9_Release(device);
3067     IDirect3D9_Release(d3d);
3068     DestroyWindow(wnd);
3069 }
3070
3071 struct dynamic_array
3072 {
3073     int count, capacity;
3074     void *items;
3075 };
3076
3077 enum pointtype {
3078     POINTTYPE_CURVE = 0,
3079     POINTTYPE_CORNER,
3080     POINTTYPE_CURVE_START,
3081     POINTTYPE_CURVE_END,
3082     POINTTYPE_CURVE_MIDDLE,
3083 };
3084
3085 struct point2d
3086 {
3087     D3DXVECTOR2 pos;
3088     enum pointtype corner;
3089 };
3090
3091 /* is a dynamic_array */
3092 struct outline
3093 {
3094     int count, capacity;
3095     struct point2d *items;
3096 };
3097
3098 /* is a dynamic_array */
3099 struct outline_array
3100 {
3101     int count, capacity;
3102     struct outline *items;
3103 };
3104
3105 struct glyphinfo
3106 {
3107     struct outline_array outlines;
3108     float offset_x;
3109 };
3110
3111 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
3112 {
3113     if (count > array->capacity) {
3114         void *new_buffer;
3115         int new_capacity;
3116         if (array->items && array->capacity) {
3117             new_capacity = max(array->capacity * 2, count);
3118             new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
3119         } else {
3120             new_capacity = max(16, count);
3121             new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
3122         }
3123         if (!new_buffer)
3124             return FALSE;
3125         array->items = new_buffer;
3126         array->capacity = new_capacity;
3127     }
3128     return TRUE;
3129 }
3130
3131 static struct point2d *add_point(struct outline *array)
3132 {
3133     struct point2d *item;
3134
3135     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3136         return NULL;
3137
3138     item = &array->items[array->count++];
3139     ZeroMemory(item, sizeof(*item));
3140     return item;
3141 }
3142
3143 static struct outline *add_outline(struct outline_array *array)
3144 {
3145     struct outline *item;
3146
3147     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3148         return NULL;
3149
3150     item = &array->items[array->count++];
3151     ZeroMemory(item, sizeof(*item));
3152     return item;
3153 }
3154
3155 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
3156 {
3157     D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
3158     while (count--) {
3159         D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
3160         pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
3161         pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
3162         pt++;
3163     }
3164     return ret;
3165 }
3166
3167 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
3168                                  const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
3169                                  float max_deviation)
3170 {
3171     D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
3172     float deviation;
3173
3174     D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
3175     D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
3176     D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
3177
3178     deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
3179     if (deviation < max_deviation) {
3180         struct point2d *pt = add_point(outline);
3181         if (!pt) return E_OUTOFMEMORY;
3182         pt->pos = *p2;
3183         pt->corner = POINTTYPE_CURVE;
3184         /* the end point is omitted because the end line merges into the next segment of
3185          * the split bezier curve, and the end of the split bezier curve is added outside
3186          * this recursive function. */
3187     } else {
3188         HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
3189         if (hr != S_OK) return hr;
3190         hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
3191         if (hr != S_OK) return hr;
3192     }
3193
3194     return S_OK;
3195 }
3196
3197 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
3198 {
3199     /* dot product = cos(theta) */
3200     return D3DXVec2Dot(dir1, dir2) > cos_theta;
3201 }
3202
3203 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
3204 {
3205     return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
3206 }
3207
3208 static BOOL attempt_line_merge(struct outline *outline,
3209                                int pt_index,
3210                                const D3DXVECTOR2 *nextpt,
3211                                BOOL to_curve)
3212 {
3213     D3DXVECTOR2 curdir, lastdir;
3214     struct point2d *prevpt, *pt;
3215     BOOL ret = FALSE;
3216     const float cos_half = cos(D3DXToRadian(0.5f));
3217
3218     pt = &outline->items[pt_index];
3219     pt_index = (pt_index - 1 + outline->count) % outline->count;
3220     prevpt = &outline->items[pt_index];
3221
3222     if (to_curve)
3223         pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
3224
3225     if (outline->count < 2)
3226         return FALSE;
3227
3228     /* remove last point if the next line continues the last line */
3229     unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3230     unit_vec2(&curdir, &pt->pos, nextpt);
3231     if (is_direction_similar(&lastdir, &curdir, cos_half))
3232     {
3233         outline->count--;
3234         if (pt->corner == POINTTYPE_CURVE_END)
3235             prevpt->corner = pt->corner;
3236         if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
3237             prevpt->corner = POINTTYPE_CURVE_MIDDLE;
3238         pt = prevpt;
3239
3240         ret = TRUE;
3241         if (outline->count < 2)
3242             return ret;
3243
3244         pt_index = (pt_index - 1 + outline->count) % outline->count;
3245         prevpt = &outline->items[pt_index];
3246         unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3247         unit_vec2(&curdir, &pt->pos, nextpt);
3248     }
3249     return ret;
3250 }
3251
3252 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
3253                               float max_deviation, float emsquare)
3254 {
3255     const float cos_45 = cos(D3DXToRadian(45.0f));
3256     const float cos_90 = cos(D3DXToRadian(90.0f));
3257     TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
3258
3259     while ((char *)header < (char *)raw_outline + datasize)
3260     {
3261         TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
3262         struct point2d *lastpt, *pt;
3263         D3DXVECTOR2 lastdir;
3264         D3DXVECTOR2 *pt_flt;
3265         int j;
3266         struct outline *outline = add_outline(&glyph->outlines);
3267
3268         if (!outline)
3269             return E_OUTOFMEMORY;
3270
3271         pt = add_point(outline);
3272         if (!pt)
3273             return E_OUTOFMEMORY;
3274         pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
3275         pt->pos = *pt_flt;
3276         pt->corner = POINTTYPE_CORNER;
3277
3278         if (header->dwType != TT_POLYGON_TYPE)
3279             trace("Unknown header type %d\n", header->dwType);
3280
3281         while ((char *)curve < (char *)header + header->cb)
3282         {
3283             D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
3284             BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
3285
3286             if (!curve->cpfx) {
3287                 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3288                 continue;
3289             }
3290
3291             pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
3292
3293             attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
3294
3295             if (to_curve)
3296             {
3297                 HRESULT hr;
3298                 int count = curve->cpfx;
3299                 j = 0;
3300
3301                 while (count > 2)
3302                 {
3303                     D3DXVECTOR2 bezier_end;
3304
3305                     D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
3306                     hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
3307                     if (hr != S_OK)
3308                         return hr;
3309                     bezier_start = bezier_end;
3310                     count--;
3311                     j++;
3312                 }
3313                 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
3314                 if (hr != S_OK)
3315                     return hr;
3316
3317                 pt = add_point(outline);
3318                 if (!pt)
3319                     return E_OUTOFMEMORY;
3320                 j++;
3321                 pt->pos = pt_flt[j];
3322                 pt->corner = POINTTYPE_CURVE_END;
3323             } else {
3324                 for (j = 0; j < curve->cpfx; j++)
3325                 {
3326                     pt = add_point(outline);
3327                     if (!pt)
3328                         return E_OUTOFMEMORY;
3329                     pt->pos = pt_flt[j];
3330                     pt->corner = POINTTYPE_CORNER;
3331                 }
3332             }
3333
3334             curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3335         }
3336
3337         /* remove last point if the next line continues the last line */
3338         if (outline->count >= 3) {
3339             BOOL to_curve;
3340
3341             lastpt = &outline->items[outline->count - 1];
3342             pt = &outline->items[0];
3343             if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
3344                 if (lastpt->corner == POINTTYPE_CURVE_END)
3345                 {
3346                     if (pt->corner == POINTTYPE_CURVE_START)
3347                         pt->corner = POINTTYPE_CURVE_MIDDLE;
3348                     else
3349                         pt->corner = POINTTYPE_CURVE_END;
3350                 }
3351                 outline->count--;
3352                 lastpt = &outline->items[outline->count - 1];
3353             } else {
3354                 /* outline closed with a line from end to start point */
3355                 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
3356             }
3357             lastpt = &outline->items[0];
3358             to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
3359             if (lastpt->corner == POINTTYPE_CURVE_START)
3360                 lastpt->corner = POINTTYPE_CORNER;
3361             pt = &outline->items[1];
3362             if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
3363                 *lastpt = outline->items[outline->count];
3364         }
3365
3366         lastpt = &outline->items[outline->count - 1];
3367         pt = &outline->items[0];
3368         unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
3369         for (j = 0; j < outline->count; j++)
3370         {
3371             D3DXVECTOR2 curdir;
3372
3373             lastpt = pt;
3374             pt = &outline->items[(j + 1) % outline->count];
3375             unit_vec2(&curdir, &lastpt->pos, &pt->pos);
3376
3377             switch (lastpt->corner)
3378             {
3379                 case POINTTYPE_CURVE_START:
3380                 case POINTTYPE_CURVE_END:
3381                     if (!is_direction_similar(&lastdir, &curdir, cos_45))
3382                         lastpt->corner = POINTTYPE_CORNER;
3383                     break;
3384                 case POINTTYPE_CURVE_MIDDLE:
3385                     if (!is_direction_similar(&lastdir, &curdir, cos_90))
3386                         lastpt->corner = POINTTYPE_CORNER;
3387                     else
3388                         lastpt->corner = POINTTYPE_CURVE;
3389                     break;
3390                 default:
3391                     break;
3392             }
3393             lastdir = curdir;
3394         }
3395
3396         header = (TTPOLYGONHEADER *)((char *)header + header->cb);
3397     }
3398     return S_OK;
3399 }
3400
3401 static BOOL compute_text_mesh(struct mesh *mesh, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion, FLOAT otmEMSquare)
3402 {
3403     HRESULT hr = E_FAIL;
3404     DWORD nb_vertices, nb_faces;
3405     DWORD nb_corners, nb_outline_points;
3406     int textlen = 0;
3407     float offset_x;
3408     char *raw_outline = NULL;
3409     struct glyphinfo *glyphs = NULL;
3410     GLYPHMETRICS gm;
3411     int i;
3412     struct vertex *vertex_ptr;
3413     face *face_ptr;
3414
3415     if (deviation == 0.0f)
3416         deviation = 1.0f / otmEMSquare;
3417
3418     textlen = strlen(text);
3419     glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
3420     if (!glyphs) {
3421         hr = E_OUTOFMEMORY;
3422         goto error;
3423     }
3424
3425     offset_x = 0.0f;
3426     for (i = 0; i < textlen; i++)
3427     {
3428         /* get outline points from data returned from GetGlyphOutline */
3429         const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
3430         int datasize;
3431
3432         glyphs[i].offset_x = offset_x;
3433
3434         datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
3435         if (datasize < 0) {
3436             hr = E_FAIL;
3437             goto error;
3438         }
3439         HeapFree(GetProcessHeap(), 0, raw_outline);
3440         raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
3441         if (!glyphs) {
3442             hr = E_OUTOFMEMORY;
3443             goto error;
3444         }
3445         datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
3446
3447         create_outline(&glyphs[i], raw_outline, datasize, deviation, otmEMSquare);
3448
3449         offset_x += gm.gmCellIncX / (float)otmEMSquare;
3450     }
3451
3452     /* corner points need an extra vertex for the different side faces normals */
3453     nb_corners = 0;
3454     nb_outline_points = 0;
3455     for (i = 0; i < textlen; i++)
3456     {
3457         int j;
3458         for (j = 0; j < glyphs[i].outlines.count; j++)
3459         {
3460             int k;
3461             struct outline *outline = &glyphs[i].outlines.items[j];
3462             nb_outline_points += outline->count;
3463             nb_corners++; /* first outline point always repeated as a corner */
3464             for (k = 1; k < outline->count; k++)
3465                 if (outline->items[k].corner)
3466                     nb_corners++;
3467         }
3468     }
3469
3470     nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
3471     nb_faces = nb_outline_points * 2;
3472
3473     if (!new_mesh(mesh, nb_vertices, nb_faces))
3474         goto error;
3475
3476     /* convert 2D vertices and faces into 3D mesh */
3477     vertex_ptr = mesh->vertices;
3478     face_ptr = mesh->faces;
3479     for (i = 0; i < textlen; i++)
3480     {
3481         int j;
3482
3483         /* side vertices and faces */
3484         for (j = 0; j < glyphs[i].outlines.count; j++)
3485         {
3486             struct vertex *outline_vertices = vertex_ptr;
3487             struct outline *outline = &glyphs[i].outlines.items[j];
3488             int k;
3489             struct point2d *prevpt = &outline->items[outline->count - 1];
3490             struct point2d *pt = &outline->items[0];
3491
3492             for (k = 1; k <= outline->count; k++)
3493             {
3494                 struct vertex vtx;
3495                 struct point2d *nextpt = &outline->items[k % outline->count];
3496                 WORD vtx_idx = vertex_ptr - mesh->vertices;
3497                 D3DXVECTOR2 vec;
3498
3499                 if (pt->corner == POINTTYPE_CURVE_START)
3500                     D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
3501                 else if (pt->corner)
3502                     D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3503                 else
3504                     D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
3505                 D3DXVec2Normalize(&vec, &vec);
3506                 vtx.normal.x = -vec.y;
3507                 vtx.normal.y = vec.x;
3508                 vtx.normal.z = 0;
3509
3510                 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
3511                 vtx.position.y = pt->pos.y;
3512                 vtx.position.z = 0;
3513                 *vertex_ptr++ = vtx;
3514
3515                 vtx.position.z = -extrusion;
3516                 *vertex_ptr++ = vtx;
3517
3518                 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
3519                 vtx.position.y = nextpt->pos.y;
3520                 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
3521                     vtx.position.z = -extrusion;
3522                     *vertex_ptr++ = vtx;
3523                     vtx.position.z = 0;
3524                     *vertex_ptr++ = vtx;
3525
3526                     (*face_ptr)[0] = vtx_idx;
3527                     (*face_ptr)[1] = vtx_idx + 2;
3528                     (*face_ptr)[2] = vtx_idx + 1;
3529                     face_ptr++;
3530
3531                     (*face_ptr)[0] = vtx_idx;
3532                     (*face_ptr)[1] = vtx_idx + 3;
3533                     (*face_ptr)[2] = vtx_idx + 2;
3534                     face_ptr++;
3535                 } else {
3536                     if (nextpt->corner) {
3537                         if (nextpt->corner == POINTTYPE_CURVE_END) {
3538                             struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
3539                             D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
3540                         } else {
3541                             D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3542                         }
3543                         D3DXVec2Normalize(&vec, &vec);
3544                         vtx.normal.x = -vec.y;
3545                         vtx.normal.y = vec.x;
3546
3547                         vtx.position.z = 0;
3548                         *vertex_ptr++ = vtx;
3549                         vtx.position.z = -extrusion;
3550                         *vertex_ptr++ = vtx;
3551                     }
3552
3553                     (*face_ptr)[0] = vtx_idx;
3554                     (*face_ptr)[1] = vtx_idx + 3;
3555                     (*face_ptr)[2] = vtx_idx + 1;
3556                     face_ptr++;
3557
3558                     (*face_ptr)[0] = vtx_idx;
3559                     (*face_ptr)[1] = vtx_idx + 2;
3560                     (*face_ptr)[2] = vtx_idx + 3;
3561                     face_ptr++;
3562                 }
3563
3564                 prevpt = pt;
3565                 pt = nextpt;
3566             }
3567             if (!pt->corner) {
3568                 *vertex_ptr++ = *outline_vertices++;
3569                 *vertex_ptr++ = *outline_vertices++;
3570             }
3571         }
3572
3573         /* FIXME: compute expected faces */
3574         /* Add placeholder to separate glyph outlines */
3575         vertex_ptr->position.x = 0;
3576         vertex_ptr->position.y = 0;
3577         vertex_ptr->position.z = 0;
3578         vertex_ptr->normal.x = 0;
3579         vertex_ptr->normal.y = 0;
3580         vertex_ptr->normal.z = 1;
3581         vertex_ptr++;
3582     }
3583
3584     hr = D3D_OK;
3585 error:
3586     if (glyphs) {
3587         for (i = 0; i < textlen; i++)
3588         {
3589             int j;
3590             for (j = 0; j < glyphs[i].outlines.count; j++)
3591                 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items[j].items);
3592             HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items);
3593         }
3594         HeapFree(GetProcessHeap(), 0, glyphs);
3595     }
3596     HeapFree(GetProcessHeap(), 0, raw_outline);
3597
3598     return hr == D3D_OK;
3599 }
3600
3601 static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh, int textlen, float extrusion)
3602 {
3603     HRESULT hr;
3604     DWORD number_of_vertices, number_of_faces;
3605     IDirect3DVertexBuffer9 *vertex_buffer = NULL;
3606     IDirect3DIndexBuffer9 *index_buffer = NULL;
3607     D3DVERTEXBUFFER_DESC vertex_buffer_description;
3608     D3DINDEXBUFFER_DESC index_buffer_description;
3609     struct vertex *vertices = NULL;
3610     face *faces = NULL;
3611     int expected, i;
3612     int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
3613
3614     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
3615     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
3616
3617     /* vertex buffer */
3618     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
3619     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3620     if (hr != D3D_OK)
3621     {
3622         skip("Couldn't get vertex buffers\n");
3623         goto error;
3624     }
3625
3626     hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
3627     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3628
3629     if (hr != D3D_OK)
3630     {
3631         skip("Couldn't get vertex buffer description\n");
3632     }
3633     else
3634     {
3635         ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
3636            name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
3637         ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
3638            name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
3639         ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
3640         ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
3641            name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
3642         ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
3643            name, vertex_buffer_description.FVF, mesh->fvf);
3644         if (mesh->fvf == 0)
3645         {
3646             expected = number_of_vertices * mesh->vertex_size;
3647         }
3648         else
3649         {
3650             expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
3651         }
3652         ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
3653            name, vertex_buffer_description.Size, expected);
3654     }
3655
3656     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
3657     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3658     if (hr != D3D_OK)
3659     {
3660         skip("Couldn't get index buffer\n");
3661         goto error;
3662     }
3663
3664     hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
3665     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3666
3667     if (hr != D3D_OK)
3668     {
3669         skip("Couldn't get index buffer description\n");
3670     }
3671     else
3672     {
3673         ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
3674            name, index_buffer_description.Format, D3DFMT_INDEX16);
3675         ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
3676            name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
3677         ok(index_buffer_description.Usage == 0, "Test %s, result %#x, expected %#x.\n",
3678                 name, index_buffer_description.Usage, 0);
3679         ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
3680            name, index_buffer_description.Pool, D3DPOOL_MANAGED);
3681         expected = number_of_faces * sizeof(WORD) * 3;
3682         ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
3683            name, index_buffer_description.Size, expected);
3684     }
3685
3686     /* specify offset and size to avoid potential overruns */
3687     hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
3688                                      (LPVOID *)&vertices, D3DLOCK_DISCARD);
3689     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3690     if (hr != D3D_OK)
3691     {
3692         skip("Couldn't lock vertex buffer\n");
3693         goto error;
3694     }
3695     hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
3696                                     (LPVOID *)&faces, D3DLOCK_DISCARD);
3697     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3698     if (hr != D3D_OK)
3699     {
3700         skip("Couldn't lock index buffer\n");
3701         goto error;
3702     }
3703
3704     face_idx1 = 0;
3705     vtx_idx2 = 0;
3706     face_idx2 = 0;
3707     vtx_idx1 = 0;
3708     for (i = 0; i < textlen; i++)
3709     {
3710         int nb_outline_vertices1, nb_outline_faces1;
3711         int nb_outline_vertices2, nb_outline_faces2;
3712         int nb_back_vertices, nb_back_faces;
3713         int first_vtx1, first_vtx2;
3714         int first_face1, first_face2;
3715         int j;
3716
3717         first_vtx1 = vtx_idx1;
3718         first_vtx2 = vtx_idx2;
3719         for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
3720             if (vertices[vtx_idx1].normal.z != 0)
3721                 break;
3722         }
3723         for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
3724             if (mesh->vertices[vtx_idx2].normal.z != 0)
3725                 break;
3726         }
3727         nb_outline_vertices1 = vtx_idx1 - first_vtx1;
3728         nb_outline_vertices2 = vtx_idx2 - first_vtx2;
3729         ok(nb_outline_vertices1 == nb_outline_vertices2,
3730            "Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
3731            nb_outline_vertices1, nb_outline_vertices2);
3732
3733         for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
3734         {
3735             vtx_idx1 = first_vtx1 + j;
3736             vtx_idx2 = first_vtx2 + j;
3737             ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
3738                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3739                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
3740                mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
3741             ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
3742                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3743                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3744                mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
3745         }
3746         vtx_idx1 = first_vtx1 + nb_outline_vertices1;
3747         vtx_idx2 = first_vtx2 + nb_outline_vertices2;
3748
3749         first_face1 = face_idx1;
3750         first_face2 = face_idx2;
3751         for (; face_idx1 < number_of_faces; face_idx1++)
3752         {
3753             if (faces[face_idx1][0] >= vtx_idx1 ||
3754                 faces[face_idx1][1] >= vtx_idx1 ||
3755                 faces[face_idx1][2] >= vtx_idx1)
3756                 break;
3757         }
3758         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
3759         {
3760             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
3761                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
3762                 mesh->faces[face_idx2][2] >= vtx_idx2)
3763                 break;
3764         }
3765         nb_outline_faces1 = face_idx1 - first_face1;
3766         nb_outline_faces2 = face_idx2 - first_face2;
3767         ok(nb_outline_faces1 == nb_outline_faces2,
3768            "Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
3769            nb_outline_faces1, nb_outline_faces2);
3770
3771         for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
3772         {
3773             face_idx1 = first_face1 + j;
3774             face_idx2 = first_face2 + j;
3775             ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
3776                faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
3777                faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
3778                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
3779                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
3780                mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
3781                mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
3782                mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
3783         }
3784         face_idx1 = first_face1 + nb_outline_faces1;
3785         face_idx2 = first_face2 + nb_outline_faces2;
3786
3787         /* partial test on back vertices and faces  */
3788         first_vtx1 = vtx_idx1;
3789         for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
3790             struct vertex vtx;
3791
3792             if (vertices[vtx_idx1].normal.z != 1.0f)
3793                 break;
3794
3795             vtx.position.z = 0.0f;
3796             vtx.normal.x = 0.0f;
3797             vtx.normal.y = 0.0f;
3798             vtx.normal.z = 1.0f;
3799             ok(compare(vertices[vtx_idx1].position.z, vtx.position.z),
3800                "Test %s, glyph %d, vertex position.z %d, result %g, expected %g\n", name, i, vtx_idx1,
3801                vertices[vtx_idx1].position.z, vtx.position.z);
3802             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
3803                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3804                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3805                vtx.normal.x, vtx.normal.y, vtx.normal.z);
3806         }
3807         nb_back_vertices = vtx_idx1 - first_vtx1;
3808         first_face1 = face_idx1;
3809         for (; face_idx1 < number_of_faces; face_idx1++)
3810         {
3811             const D3DXVECTOR3 *vtx1, *vtx2, *vtx3;
3812             D3DXVECTOR3 normal;
3813             D3DXVECTOR3 v1 = {0, 0, 0};
3814             D3DXVECTOR3 v2 = {0, 0, 0};
3815             D3DXVECTOR3 forward = {0.0f, 0.0f, 1.0f};
3816
3817             if (faces[face_idx1][0] >= vtx_idx1 ||
3818                 faces[face_idx1][1] >= vtx_idx1 ||
3819                 faces[face_idx1][2] >= vtx_idx1)
3820                 break;
3821
3822             vtx1 = &vertices[faces[face_idx1][0]].position;
3823             vtx2 = &vertices[faces[face_idx1][1]].position;
3824             vtx3 = &vertices[faces[face_idx1][2]].position;
3825
3826             D3DXVec3Subtract(&v1, vtx2, vtx1);
3827             D3DXVec3Subtract(&v2, vtx3, vtx2);
3828             D3DXVec3Cross(&normal, &v1, &v2);
3829             D3DXVec3Normalize(&normal, &normal);
3830             ok(!D3DXVec3Length(&normal) || compare_vec3(normal, forward),
3831                "Test %s, glyph %d, face %d normal, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, face_idx1,
3832                normal.x, normal.y, normal.z, forward.x, forward.y, forward.z);
3833         }
3834         nb_back_faces = face_idx1 - first_face1;
3835
3836         /* compare front and back faces & vertices */
3837         if (extrusion == 0.0f) {
3838             /* Oddly there are only back faces in this case */
3839             nb_back_vertices /= 2;
3840             nb_back_faces /= 2;
3841             face_idx1 -= nb_back_faces;
3842             vtx_idx1 -= nb_back_vertices;
3843         }
3844         for (j = 0; j < nb_back_vertices; j++)
3845         {
3846             struct vertex vtx = vertices[first_vtx1];
3847             vtx.position.z = -extrusion;
3848             vtx.normal.x = 0.0f;
3849             vtx.normal.y = 0.0f;
3850             vtx.normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
3851             ok(compare_vec3(vertices[vtx_idx1].position, vtx.position),
3852                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3853                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
3854                vtx.position.x, vtx.position.y, vtx.position.z);
3855             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
3856                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3857                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3858                vtx.normal.x, vtx.normal.y, vtx.normal.z);
3859             vtx_idx1++;
3860             first_vtx1++;
3861         }
3862         for (j = 0; j < nb_back_faces; j++)
3863         {
3864             int f1, f2;
3865             if (extrusion == 0.0f) {
3866                 f1 = 1;
3867                 f2 = 2;
3868             } else {
3869                 f1 = 2;
3870                 f2 = 1;
3871             }
3872             ok(faces[face_idx1][0] == faces[first_face1][0] + nb_back_vertices &&
3873                faces[face_idx1][1] == faces[first_face1][f1] + nb_back_vertices &&
3874                faces[face_idx1][2] == faces[first_face1][f2] + nb_back_vertices,
3875                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
3876                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
3877                faces[first_face1][0] - nb_back_faces,
3878                faces[first_face1][f1] - nb_back_faces,
3879                faces[first_face1][f2] - nb_back_faces);
3880             first_face1++;
3881             face_idx1++;
3882         }
3883
3884         /* skip to the outline for the next glyph */
3885         for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
3886             if (mesh->vertices[vtx_idx2].normal.z == 0)
3887                 break;
3888         }
3889         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
3890         {
3891             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
3892                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
3893                 mesh->faces[face_idx2][2] >= vtx_idx2) break;
3894         }
3895     }
3896
3897 error:
3898     if (vertices) IDirect3DVertexBuffer9_Unlock(vertex_buffer);
3899     if (faces) IDirect3DIndexBuffer9_Unlock(index_buffer);
3900     if (index_buffer) IDirect3DIndexBuffer9_Release(index_buffer);
3901     if (vertex_buffer) IDirect3DVertexBuffer9_Release(vertex_buffer);
3902 }
3903
3904 static void test_createtext(IDirect3DDevice9 *device, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion)
3905 {
3906     HRESULT hr;
3907     ID3DXMesh *d3dxmesh;
3908     struct mesh mesh;
3909     char name[256];
3910     OUTLINETEXTMETRIC otm;
3911     GLYPHMETRICS gm;
3912     GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
3913     int i;
3914     LOGFONT lf;
3915     HFONT font = NULL, oldfont = NULL;
3916
3917     sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion);
3918
3919     hr = D3DXCreateText(device, hdc, text, deviation, extrusion, &d3dxmesh, NULL, glyphmetrics_float);
3920     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3921     if (hr != D3D_OK)
3922     {
3923         skip("Couldn't create text with D3DXCreateText\n");
3924         return;
3925     }
3926
3927     /* must select a modified font having lfHeight = otm.otmEMSquare before
3928      * calling GetGlyphOutline to get the expected values */
3929     if (!GetObject(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf) ||
3930         !GetOutlineTextMetrics(hdc, sizeof(otm), &otm))
3931     {
3932         d3dxmesh->lpVtbl->Release(d3dxmesh);
3933         skip("Couldn't get text outline\n");
3934         return;
3935     }
3936     lf.lfHeight = otm.otmEMSquare;
3937     lf.lfWidth = 0;
3938     font = CreateFontIndirect(&lf);
3939     if (!font) {
3940         d3dxmesh->lpVtbl->Release(d3dxmesh);
3941         skip("Couldn't create the modified font\n");
3942         return;
3943     }
3944     oldfont = SelectObject(hdc, font);
3945
3946     for (i = 0; i < strlen(text); i++)
3947     {
3948         const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
3949         GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
3950         compare_float(glyphmetrics_float[i].gmfBlackBoxX, gm.gmBlackBoxX / (float)otm.otmEMSquare);
3951         compare_float(glyphmetrics_float[i].gmfBlackBoxY, gm.gmBlackBoxY / (float)otm.otmEMSquare);
3952         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.x, gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare);
3953         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.y, gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare);
3954         compare_float(glyphmetrics_float[i].gmfCellIncX, gm.gmCellIncX / (float)otm.otmEMSquare);
3955         compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
3956     }
3957
3958     ZeroMemory(&mesh, sizeof(mesh));
3959     if (!compute_text_mesh(&mesh, hdc, text, deviation, extrusion, otm.otmEMSquare))
3960     {
3961         skip("Couldn't create mesh\n");
3962         d3dxmesh->lpVtbl->Release(d3dxmesh);
3963         return;
3964     }
3965     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3966
3967     compare_text_outline_mesh(name, d3dxmesh, &mesh, strlen(text), extrusion);
3968
3969     free_mesh(&mesh);
3970
3971     d3dxmesh->lpVtbl->Release(d3dxmesh);
3972     SelectObject(hdc, oldfont);
3973     HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
3974 }
3975
3976 static void D3DXCreateTextTest(void)
3977 {
3978     HRESULT hr;
3979     HWND wnd;
3980     HDC hdc;
3981     IDirect3D9* d3d;
3982     IDirect3DDevice9* device;
3983     D3DPRESENT_PARAMETERS d3dpp;
3984     ID3DXMesh* d3dxmesh = NULL;
3985     HFONT hFont;
3986     OUTLINETEXTMETRIC otm;
3987     int number_of_vertices;
3988     int number_of_faces;
3989
3990     wnd = CreateWindow("static", "d3dx9_test", WS_POPUP, 0, 0, 1000, 1000, NULL, NULL, NULL, NULL);
3991     d3d = Direct3DCreate9(D3D_SDK_VERSION);
3992     if (!wnd)
3993     {
3994         skip("Couldn't create application window\n");
3995         return;
3996     }
3997     if (!d3d)
3998     {
3999         skip("Couldn't create IDirect3D9 object\n");
4000         DestroyWindow(wnd);
4001         return;
4002     }
4003
4004     ZeroMemory(&d3dpp, sizeof(d3dpp));
4005     d3dpp.Windowed = TRUE;
4006     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
4007     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
4008     if (FAILED(hr))
4009     {
4010         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
4011         IDirect3D9_Release(d3d);
4012         DestroyWindow(wnd);
4013         return;
4014     }
4015
4016     hdc = CreateCompatibleDC(NULL);
4017
4018     hFont = CreateFont(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
4019                        OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
4020                        "Arial");
4021     SelectObject(hdc, hFont);
4022     GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
4023
4024     hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, NULL, NULL, NULL);
4025     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4026
4027     /* D3DXCreateTextA page faults from passing NULL text */
4028
4029     hr = D3DXCreateTextW(device, hdc, NULL, 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4030     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4031
4032     hr = D3DXCreateText(device, hdc, "", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4033     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4034
4035     hr = D3DXCreateText(device, hdc, " ", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4036     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4037
4038     hr = D3DXCreateText(NULL, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4039     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4040
4041     hr = D3DXCreateText(device, NULL, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4042     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4043
4044     hr = D3DXCreateText(device, hdc, "wine", -FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4045     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4046
4047     hr = D3DXCreateText(device, hdc, "wine", 0.001f, -FLT_MIN, &d3dxmesh, NULL, NULL);
4048     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4049
4050     /* deviation = 0.0f treated as if deviation = 1.0f / otm.otmEMSquare */
4051     hr = D3DXCreateText(device, hdc, "wine", 1.0f / otm.otmEMSquare, 0.4f, &d3dxmesh, NULL, NULL);
4052     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4053     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
4054     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
4055     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4056
4057     hr = D3DXCreateText(device, hdc, "wine", 0.0f, 0.4f, &d3dxmesh, NULL, NULL);
4058     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4059     ok(number_of_vertices == d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh),
4060        "Got %d vertices, expected %d\n",
4061        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_vertices);
4062     ok(number_of_faces == d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh),
4063        "Got %d faces, expected %d\n",
4064        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_faces);
4065     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4066
4067 #if 0
4068     /* too much detail requested, so will appear to hang */
4069     trace("Waiting for D3DXCreateText to finish with deviation = FLT_MIN ...\n");
4070     hr = D3DXCreateText(device, hdc, "wine", FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4071     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4072     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4073     trace("D3DXCreateText finish with deviation = FLT_MIN\n");
4074 #endif
4075
4076     hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4077     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4078     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4079
4080     test_createtext(device, hdc, "wine", FLT_MAX, 0.4f);
4081     test_createtext(device, hdc, "wine", 0.001f, FLT_MIN);
4082     test_createtext(device, hdc, "wine", 0.001f, 0.0f);
4083     test_createtext(device, hdc, "wine", 0.001f, FLT_MAX);
4084     test_createtext(device, hdc, "wine", 0.0f, 1.0f);
4085
4086     DeleteDC(hdc);
4087
4088     IDirect3DDevice9_Release(device);
4089     IDirect3D9_Release(d3d);
4090     DestroyWindow(wnd);
4091 }
4092
4093 static void test_get_decl_length(void)
4094 {
4095     static const D3DVERTEXELEMENT9 declaration1[] =
4096     {
4097         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4098         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4099         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4100         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4101         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4102         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4103         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4104         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4105         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4106         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4107         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4108         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4109         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4110         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4111         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4112         D3DDECL_END(),
4113     };
4114     static const D3DVERTEXELEMENT9 declaration2[] =
4115     {
4116         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4117         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4118         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4119         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4120         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4121         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4122         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4123         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4124         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4125         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4126         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4127         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4128         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4129         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4130         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4131         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4132         D3DDECL_END(),
4133     };
4134     UINT size;
4135
4136     size = D3DXGetDeclLength(declaration1);
4137     ok(size == 15, "Got size %u, expected 15.\n", size);
4138
4139     size = D3DXGetDeclLength(declaration2);
4140     ok(size == 16, "Got size %u, expected 16.\n", size);
4141 }
4142
4143 static void test_get_decl_vertex_size(void)
4144 {
4145     static const D3DVERTEXELEMENT9 declaration1[] =
4146     {
4147         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4148         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4149         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4150         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4151         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4152         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4153         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4154         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4155         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4156         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4157         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4158         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4159         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4160         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4161         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4162         D3DDECL_END(),
4163     };
4164     static const D3DVERTEXELEMENT9 declaration2[] =
4165     {
4166         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4167         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4168         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4169         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4170         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4171         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4172         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4173         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4174         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4175         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4176         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4177         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4178         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4179         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4180         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4181         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4182         D3DDECL_END(),
4183     };
4184     static const UINT sizes1[] =
4185     {
4186         4,  8,  12, 16,
4187         4,  4,  4,  8,
4188         4,  4,  8,  4,
4189         4,  4,  8,  0,
4190     };
4191     static const UINT sizes2[] =
4192     {
4193         12, 16, 20, 24,
4194         12, 12, 16, 16,
4195     };
4196     unsigned int i;
4197     UINT size;
4198
4199     size = D3DXGetDeclVertexSize(NULL, 0);
4200     ok(size == 0, "Got size %#x, expected 0.\n", size);
4201
4202     for (i = 0; i < 16; ++i)
4203     {
4204         size = D3DXGetDeclVertexSize(declaration1, i);
4205         ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
4206     }
4207
4208     for (i = 0; i < 8; ++i)
4209     {
4210         size = D3DXGetDeclVertexSize(declaration2, i);
4211         ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
4212     }
4213 }
4214
4215 static void D3DXGenerateAdjacencyTest(void)
4216 {
4217     HRESULT hr;
4218     HWND wnd;
4219     IDirect3D9 *d3d;
4220     IDirect3DDevice9 *device;
4221     D3DPRESENT_PARAMETERS d3dpp;
4222     ID3DXMesh *d3dxmesh = NULL;
4223     D3DXVECTOR3 *vertices = NULL;
4224     WORD *indices = NULL;
4225     int i;
4226     struct {
4227         DWORD num_vertices;
4228         D3DXVECTOR3 vertices[6];
4229         DWORD num_faces;
4230         WORD indices[3 * 3];
4231         FLOAT epsilon;
4232         DWORD adjacency[3 * 3];
4233     } test_data[] = {
4234         { /* for epsilon < 0, indices must match for faces to be adjacent */
4235             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}},
4236             2, {0, 1, 2,  0, 2, 3},
4237             -1.0,
4238             {-1, -1, 1,  0, -1, -1},
4239         },
4240         {
4241             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}},
4242             2, {0, 1, 2,  3, 4, 5},
4243             -1.0,
4244             {-1, -1, -1,  -1, -1, -1},
4245         },
4246         { /* for epsilon == 0, indices or vertices must match for faces to be adjacent */
4247             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}},
4248             2, {0, 1, 2,  3, 4, 5},
4249             0.0,
4250             {-1, -1, 1,  0, -1, -1},
4251         },
4252         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4253             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}},
4254             2, {0, 1, 2,  3, 4, 5},
4255             0.25,
4256             {-1, -1, -1,  -1, -1, -1},
4257         },
4258         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4259             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}},
4260             2, {0, 1, 2,  3, 4, 5},
4261             0.250001,
4262             {-1, -1, 1,  0, -1, -1},
4263         },
4264         { /* length between vertices are compared to epsilon, not the individual dimension deltas */
4265             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}},
4266             2, {0, 1, 2,  3, 4, 5},
4267             0.353, /* < sqrt(0.25*0.25 + 0.25*0.25) */
4268             {-1, -1, -1,  -1, -1, -1},
4269         },
4270         {
4271             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}},
4272             2, {0, 1, 2,  3, 4, 5},
4273             0.354, /* > sqrt(0.25*0.25 + 0.25*0.25) */
4274             {-1, -1, 1,  0, -1, -1},
4275         },
4276         { /* adjacent faces must have opposite winding orders at the shared edge */
4277             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}},
4278             2, {0, 1, 2,  0, 3, 2},
4279             0.0,
4280             {-1, -1, -1,  -1, -1, -1},
4281         },
4282     };
4283
4284     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
4285     if (!wnd)
4286     {
4287         skip("Couldn't create application window\n");
4288         return;
4289     }
4290     d3d = Direct3DCreate9(D3D_SDK_VERSION);
4291     if (!d3d)
4292     {
4293         skip("Couldn't create IDirect3D9 object\n");
4294         DestroyWindow(wnd);
4295         return;
4296     }
4297
4298     ZeroMemory(&d3dpp, sizeof(d3dpp));
4299     d3dpp.Windowed = TRUE;
4300     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
4301     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
4302     if (FAILED(hr))
4303     {
4304         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
4305         IDirect3D9_Release(d3d);
4306         DestroyWindow(wnd);
4307         return;
4308     }
4309
4310     for (i = 0; i < ARRAY_SIZE(test_data); i++)
4311     {
4312         DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
4313         int j;
4314
4315         if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4316         d3dxmesh = NULL;
4317
4318         hr = D3DXCreateMeshFVF(test_data[i].num_faces, test_data[i].num_vertices, 0, D3DFVF_XYZ, device, &d3dxmesh);
4319         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4320
4321         hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&vertices);
4322         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4323         if (FAILED(hr)) continue;
4324         CopyMemory(vertices, test_data[i].vertices, test_data[i].num_vertices * sizeof(test_data[0].vertices[0]));
4325         d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
4326
4327         hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&indices);
4328         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4329         if (FAILED(hr)) continue;
4330         CopyMemory(indices, test_data[i].indices, test_data[i].num_faces * 3 * sizeof(test_data[0].indices[0]));
4331         d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
4332
4333         if (i == 0) {
4334             hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, NULL);
4335             ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4336         }
4337
4338         hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, test_data[i].epsilon, adjacency);
4339         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4340         if (FAILED(hr)) continue;
4341
4342         for (j = 0; j < test_data[i].num_faces * 3; j++)
4343             ok(adjacency[j] == test_data[i].adjacency[j],
4344                "Test %d adjacency %d: Got result %u, expected %u\n", i, j,
4345                adjacency[j], test_data[i].adjacency[j]);
4346     }
4347     if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4348 }
4349
4350 static void test_update_semantics(void)
4351 {
4352     HRESULT hr;
4353     struct test_context *test_context = NULL;
4354     ID3DXMesh *mesh = NULL;
4355     D3DVERTEXELEMENT9 declaration0[] =
4356     {
4357          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4358          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4359          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4360          D3DDECL_END()
4361     };
4362     D3DVERTEXELEMENT9 declaration_pos_type_color[] =
4363     {
4364          {0, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4365          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4366          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4367          D3DDECL_END()
4368     };
4369     D3DVERTEXELEMENT9 declaration_smaller[] =
4370     {
4371          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4372          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4373          D3DDECL_END()
4374     };
4375     D3DVERTEXELEMENT9 declaration_larger[] =
4376     {
4377          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4378          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4379          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4380          {0, 40, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4381          D3DDECL_END()
4382     };
4383     D3DVERTEXELEMENT9 declaration_multiple_streams[] =
4384     {
4385          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4386          {1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4387          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4388          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4389
4390          D3DDECL_END()
4391     };
4392     D3DVERTEXELEMENT9 declaration_double_usage[] =
4393     {
4394          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4395          {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4396          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4397          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4398          D3DDECL_END()
4399     };
4400     D3DVERTEXELEMENT9 declaration_undefined_type[] =
4401     {
4402          {0, 0, D3DDECLTYPE_UNUSED+1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4403          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4404          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4405          D3DDECL_END()
4406     };
4407     D3DVERTEXELEMENT9 declaration_not_4_byte_aligned_offset[] =
4408     {
4409          {0, 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4410          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4411          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4412          D3DDECL_END()
4413     };
4414     static const struct
4415     {
4416         D3DXVECTOR3 position0;
4417         D3DXVECTOR3 position1;
4418         D3DXVECTOR3 normal;
4419         DWORD color;
4420     }
4421     vertices[] =
4422     {
4423         { { 0.0f,  1.0f,  0.f}, { 1.0f,  0.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xffff0000 },
4424         { { 1.0f, -1.0f,  0.f}, {-1.0f, -1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff00ff00 },
4425         { {-1.0f, -1.0f,  0.f}, {-1.0f,  1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff0000ff },
4426     };
4427     unsigned int faces[] = {0, 1, 2};
4428     unsigned int attributes[] = {0};
4429     unsigned int num_faces = ARRAY_SIZE(faces) / 3;
4430     unsigned int num_vertices = ARRAY_SIZE(vertices);
4431     int offset = sizeof(D3DXVECTOR3);
4432     DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4433     void *vertex_buffer;
4434     void *index_buffer;
4435     DWORD *attributes_buffer;
4436     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
4437     D3DVERTEXELEMENT9 *decl_ptr;
4438     DWORD exp_vertex_size = sizeof(*vertices);
4439     DWORD vertex_size = 0;
4440     int equal;
4441     int i = 0;
4442     int *decl_mem;
4443     int filler_a = 0xaaaaaaaa;
4444     int filler_b = 0xbbbbbbbb;
4445
4446     test_context = new_test_context();
4447     if (!test_context)
4448     {
4449         skip("Couldn't create a test_context\n");
4450         goto cleanup;
4451     }
4452
4453     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration0,
4454                         test_context->device, &mesh);
4455     if (FAILED(hr))
4456     {
4457         skip("Couldn't create test mesh %#x\n", hr);
4458         goto cleanup;
4459     }
4460
4461     mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
4462     memcpy(vertex_buffer, vertices, sizeof(vertices));
4463     mesh->lpVtbl->UnlockVertexBuffer(mesh);
4464
4465     mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
4466     memcpy(index_buffer, faces, sizeof(faces));
4467     mesh->lpVtbl->UnlockIndexBuffer(mesh);
4468
4469     mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
4470     memcpy(attributes_buffer, attributes, sizeof(attributes));
4471     mesh->lpVtbl->UnlockAttributeBuffer(mesh);
4472
4473     /* Get the declaration and try to change it */
4474     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4475     if (FAILED(hr))
4476     {
4477         skip("Couldn't get vertex declaration %#x\n", hr);
4478         goto cleanup;
4479     }
4480     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4481     ok(equal == 0, "Vertex declarations were not equal\n");
4482
4483     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4484     {
4485         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4486         {
4487             /* Use second vertex position instead of first */
4488             decl_ptr->Offset = offset;
4489         }
4490     }
4491
4492     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4493     ok(hr == D3D_OK, "Test UpdateSematics, got %#x expected %#x\n", hr, D3D_OK);
4494
4495     /* Check that declaration was written by getting it again */
4496     memset(declaration, 0, sizeof(declaration));
4497     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4498     if (FAILED(hr))
4499     {
4500         skip("Couldn't get vertex declaration %#x\n", hr);
4501         goto cleanup;
4502     }
4503
4504     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4505     {
4506         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4507         {
4508             ok(decl_ptr->Offset == offset, "Test UpdateSematics, got offset %d expected %d\n",
4509                decl_ptr->Offset, offset);
4510         }
4511     }
4512
4513     /* Check that GetDeclaration only writes up to the D3DDECL_END() marker and
4514      * not the full MAX_FVF_DECL_SIZE elements.
4515      */
4516     memset(declaration, filler_a, sizeof(declaration));
4517     memcpy(declaration, declaration0, sizeof(declaration0));
4518     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4519     ok(hr == D3D_OK, "Test UpdateSematics, "
4520        "got %#x expected D3D_OK\n", hr);
4521     memset(declaration, filler_b, sizeof(declaration));
4522     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4523     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4524     decl_mem = (int*)declaration;
4525     for (i = sizeof(declaration0)/sizeof(*decl_mem); i < sizeof(declaration)/sizeof(*decl_mem); i++)
4526     {
4527         equal = memcmp(&decl_mem[i], &filler_b, sizeof(filler_b));
4528         ok(equal == 0,
4529            "GetDeclaration wrote past the D3DDECL_END() marker. "
4530            "Got %#x, expected  %#x\n", decl_mem[i], filler_b);
4531         if (equal != 0) break;
4532     }
4533
4534     /* UpdateSemantics does not check for overlapping fields */
4535     memset(declaration, 0, sizeof(declaration));
4536     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4537     if (FAILED(hr))
4538     {
4539         skip("Couldn't get vertex declaration %#x\n", hr);
4540         goto cleanup;
4541     }
4542
4543     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4544     {
4545         if (decl_ptr->Type == D3DDECLTYPE_FLOAT3)
4546         {
4547             decl_ptr->Type = D3DDECLTYPE_FLOAT4;
4548         }
4549     }
4550
4551     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4552     ok(hr == D3D_OK, "Test UpdateSematics for overlapping fields, "
4553        "got %#x expected D3D_OK\n", hr);
4554
4555     /* Set the position type to color instead of float3 */
4556     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_pos_type_color);
4557     ok(hr == D3D_OK, "Test UpdateSematics position type color, "
4558        "got %#x expected D3D_OK\n", hr);
4559
4560     /* The following test cases show that NULL, smaller or larger declarations,
4561      * and declarations with non-zero Stream values are not accepted.
4562      * UpdateSemantics returns D3DERR_INVALIDCALL and the previously set
4563      * declaration will be used by DrawSubset, GetNumBytesPerVertex, and
4564      * GetDeclaration.
4565      */
4566
4567     /* Null declaration (invalid declaration) */
4568     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4569     hr = mesh->lpVtbl->UpdateSemantics(mesh, NULL);
4570     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics null pointer declaration, "
4571        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4572     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4573     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4574        vertex_size, exp_vertex_size);
4575     memset(declaration, 0, sizeof(declaration));
4576     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4577     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4578     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4579     ok(equal == 0, "Vertex declarations were not equal\n");
4580
4581     /* Smaller vertex declaration (invalid declaration) */
4582     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4583     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_smaller);
4584     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics for smaller vertex declaration, "
4585        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4586     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4587     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4588        vertex_size, exp_vertex_size);
4589     memset(declaration, 0, sizeof(declaration));
4590     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4591     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4592     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4593     ok(equal == 0, "Vertex declarations were not equal\n");
4594
4595     /* Larger vertex declaration (invalid declaration) */
4596     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4597     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_larger);
4598     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics for larger vertex declaration, "
4599        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4600     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4601     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4602        vertex_size, exp_vertex_size);
4603     memset(declaration, 0, sizeof(declaration));
4604     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4605     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4606     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4607     ok(equal == 0, "Vertex declarations were not equal\n");
4608
4609     /* Use multiple streams and keep the same vertex size (invalid declaration) */
4610     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4611     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_multiple_streams);
4612     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics using multiple streams, "
4613                  "got %#x expected D3DERR_INVALIDCALL\n", hr);
4614     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4615     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4616        vertex_size, exp_vertex_size);
4617     memset(declaration, 0, sizeof(declaration));
4618     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4619     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4620     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4621     ok(equal == 0, "Vertex declarations were not equal\n");
4622
4623     /* The next following test cases show that some invalid declarations are
4624      * accepted with a D3D_OK. An access violation is thrown on Windows if
4625      * DrawSubset is called. The methods GetNumBytesPerVertex and GetDeclaration
4626      * are not affected, which indicates that the declaration is cached.
4627      */
4628
4629     /* Double usage (invalid declaration) */
4630     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4631     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_double_usage);
4632     ok(hr == D3D_OK, "Test UpdateSematics double usage, "
4633        "got %#x expected D3D_OK\n", hr);
4634     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4635     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4636        vertex_size, exp_vertex_size);
4637     memset(declaration, 0, sizeof(declaration));
4638     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4639     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4640     equal = memcmp(declaration, declaration_double_usage, sizeof(declaration_double_usage));
4641     ok(equal == 0, "Vertex declarations were not equal\n");
4642
4643     /* Set the position to an undefined type (invalid declaration) */
4644     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4645     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_undefined_type);
4646     ok(hr == D3D_OK, "Test UpdateSematics undefined type, "
4647        "got %#x expected D3D_OK\n", hr);
4648     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4649     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4650        vertex_size, exp_vertex_size);
4651     memset(declaration, 0, sizeof(declaration));
4652     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4653     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4654     equal = memcmp(declaration, declaration_undefined_type, sizeof(declaration_undefined_type));
4655     ok(equal == 0, "Vertex declarations were not equal\n");
4656
4657     /* Use a not 4 byte aligned offset (invalid declaration) */
4658     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4659     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_not_4_byte_aligned_offset);
4660     ok(hr == D3D_OK, "Test UpdateSematics not 4 byte aligned offset, "
4661        "got %#x expected D3D_OK\n", hr);
4662     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4663     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4664        vertex_size, exp_vertex_size);
4665     memset(declaration, 0, sizeof(declaration));
4666     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4667     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4668     equal = memcmp(declaration, declaration_not_4_byte_aligned_offset,
4669                    sizeof(declaration_not_4_byte_aligned_offset));
4670     ok(equal == 0, "Vertex declarations were not equal\n");
4671
4672 cleanup:
4673     if (mesh)
4674         mesh->lpVtbl->Release(mesh);
4675
4676     free_test_context(test_context);
4677 }
4678
4679 static void test_create_skin_info(void)
4680 {
4681     HRESULT hr;
4682     ID3DXSkinInfo *skininfo = NULL;
4683     D3DVERTEXELEMENT9 empty_declaration[] = { D3DDECL_END() };
4684     D3DVERTEXELEMENT9 declaration_out[MAX_FVF_DECL_SIZE];
4685     const D3DVERTEXELEMENT9 declaration_with_nonzero_stream[] = {
4686         {1, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
4687         D3DDECL_END()
4688     };
4689
4690     hr = D3DXCreateSkinInfo(0, empty_declaration, 0, &skininfo);
4691     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4692     if (skininfo) IUnknown_Release(skininfo);
4693     skininfo = NULL;
4694
4695     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
4696     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4697
4698     hr = D3DXCreateSkinInfo(1, declaration_with_nonzero_stream, 1, &skininfo);
4699     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4700
4701     hr = D3DXCreateSkinInfoFVF(1, 0, 1, &skininfo);
4702     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4703     if (skininfo) {
4704         DWORD dword_result;
4705         FLOAT flt_result;
4706         LPCSTR string_result;
4707         D3DXMATRIX *transform;
4708         D3DXMATRIX identity_matrix;
4709
4710         /* test initial values */
4711         hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4712         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4713         if (SUCCEEDED(hr))
4714             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
4715
4716         dword_result = skininfo->lpVtbl->GetNumBones(skininfo);
4717         ok(dword_result == 1, "Expected 1, got %u\n", dword_result);
4718
4719         flt_result = skininfo->lpVtbl->GetMinBoneInfluence(skininfo);
4720         ok(flt_result == 0.0f, "Expected 0.0, got %g\n", flt_result);
4721
4722         string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4723         ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
4724
4725         dword_result = skininfo->lpVtbl->GetFVF(skininfo);
4726         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4727
4728         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 0);
4729         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4730
4731         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 1);
4732         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4733
4734         transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, -1);
4735         ok(transform == NULL, "Expected NULL, got %p\n", transform);
4736
4737         {
4738             /* test [GS]etBoneOffsetMatrix */
4739             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 1, &identity_matrix);
4740             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4741
4742             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, NULL);
4743             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4744
4745             D3DXMatrixIdentity(&identity_matrix);
4746             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, &identity_matrix);
4747             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4748
4749             transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, 0);
4750             check_matrix(transform, &identity_matrix);
4751         }
4752
4753         {
4754             /* test [GS]etBoneName */
4755             const char *name_in = "testBoneName";
4756             const char *string_result2;
4757
4758             hr = skininfo->lpVtbl->SetBoneName(skininfo, 1, name_in);
4759             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4760
4761             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, NULL);
4762             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4763
4764             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, name_in);
4765             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4766
4767             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4768             ok(string_result != NULL, "Expected non-NULL string, got %p\n", string_result);
4769             ok(!strcmp(string_result, name_in), "Expected '%s', got '%s'\n", name_in, string_result);
4770
4771             string_result2 = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4772             ok(string_result == string_result2, "Expected %p, got %p\n", string_result, string_result2);
4773
4774             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 1);
4775             ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
4776         }
4777
4778         {
4779             /* test [GS]etBoneInfluence */
4780             DWORD vertices[2];
4781             FLOAT weights[2];
4782             int i;
4783             DWORD num_influences;
4784             DWORD exp_vertices[2];
4785             FLOAT exp_weights[2];
4786
4787             /* vertex and weight arrays untouched when num_influences is 0 */
4788             vertices[0] = 0xdeadbeef;
4789             weights[0] = FLT_MAX;
4790             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4791             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4792             ok(vertices[0] == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", vertices[0]);
4793             ok(weights[0] == FLT_MAX, "expected %g, got %g\n", FLT_MAX, weights[0]);
4794
4795             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 1, vertices, weights);
4796             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4797
4798             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, NULL);
4799             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4800
4801             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, NULL);
4802             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4803
4804             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, weights);
4805             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4806
4807
4808             /* no vertex or weight value checking */
4809             exp_vertices[0] = 0;
4810             exp_vertices[1] = 0x87654321;
4811             exp_weights[0] = 0.5;
4812             exp_weights[1] = 0.0f / 0.0f; /* NAN */
4813             num_influences = 2;
4814
4815             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 1, num_influences, vertices, weights);
4816             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4817
4818             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, weights);
4819             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4820
4821             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, vertices, NULL);
4822             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4823
4824             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, NULL);
4825             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4826
4827             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, exp_vertices, exp_weights);
4828             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4829
4830             memset(vertices, 0, sizeof(vertices));
4831             memset(weights, 0, sizeof(weights));
4832             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4833             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4834             for (i = 0; i < num_influences; i++) {
4835                 ok(exp_vertices[i] == vertices[i],
4836                    "influence[%d]: expected vertex %u, got %u\n", i, exp_vertices[i], vertices[i]);
4837                 ok((isnan(exp_weights[i]) && isnan(weights[i])) || exp_weights[i] == weights[i],
4838                    "influence[%d]: expected weights %g, got %g\n", i, exp_weights[i], weights[i]);
4839             }
4840
4841             /* vertices and weights aren't returned after setting num_influences to 0 */
4842             memset(vertices, 0, sizeof(vertices));
4843             memset(weights, 0, sizeof(weights));
4844             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, 0, vertices, weights);
4845             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4846
4847             vertices[0] = 0xdeadbeef;
4848             weights[0] = FLT_MAX;
4849             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4850             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4851             ok(vertices[0] == 0xdeadbeef, "expected vertex 0xdeadbeef, got %u\n", vertices[0]);
4852             ok(weights[0] == FLT_MAX, "expected weight %g, got %g\n", FLT_MAX, weights[0]);
4853         }
4854
4855         {
4856             /* test [GS]etFVF and [GS]etDeclaration */
4857             D3DVERTEXELEMENT9 declaration_in[MAX_FVF_DECL_SIZE];
4858             DWORD fvf = D3DFVF_XYZ;
4859             DWORD got_fvf;
4860
4861             hr = skininfo->lpVtbl->SetDeclaration(skininfo, NULL);
4862             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4863
4864             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_with_nonzero_stream);
4865             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4866
4867             hr = skininfo->lpVtbl->SetFVF(skininfo, 0);
4868             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4869
4870             hr = D3DXDeclaratorFromFVF(fvf, declaration_in);
4871             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4872             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_in);
4873             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4874             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4875             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
4876             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4877             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4878             compare_elements(declaration_out, declaration_in, __LINE__, 0);
4879
4880             hr = skininfo->lpVtbl->SetDeclaration(skininfo, empty_declaration);
4881             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4882             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4883             ok(got_fvf == 0, "Expected 0, got %#x\n", got_fvf);
4884             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4885             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4886             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
4887
4888             hr = skininfo->lpVtbl->SetFVF(skininfo, fvf);
4889             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4890             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4891             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
4892             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4893             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4894             compare_elements(declaration_out, declaration_in, __LINE__, 0);
4895         }
4896     }
4897     if (skininfo) IUnknown_Release(skininfo);
4898     skininfo = NULL;
4899
4900     hr = D3DXCreateSkinInfoFVF(1, D3DFVF_XYZ, 1, NULL);
4901     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4902
4903     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
4904     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4905 }
4906
4907 static void test_convert_adjacency_to_point_reps(void)
4908 {
4909     HRESULT hr;
4910     struct test_context *test_context = NULL;
4911     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4912     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
4913     const D3DVERTEXELEMENT9 declaration[] =
4914     {
4915         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4916         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4917         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4918         D3DDECL_END()
4919     };
4920     const unsigned int VERTS_PER_FACE = 3;
4921     void *vertex_buffer;
4922     void *index_buffer;
4923     DWORD *attributes_buffer;
4924     int i, j;
4925     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
4926     struct vertex_pnc
4927     {
4928         D3DXVECTOR3 position;
4929         D3DXVECTOR3 normal;
4930         enum color color; /* In case of manual visual inspection */
4931     };
4932     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
4933     /* mesh0 (one face)
4934      *
4935      * 0--1
4936      * | /
4937      * |/
4938      * 2
4939      */
4940     const struct vertex_pnc vertices0[] =
4941     {
4942         {{ 0.0f,  3.0f,  0.f}, up, RED},
4943         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
4944         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
4945     };
4946     const DWORD indices0[] = {0, 1, 2};
4947     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
4948     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
4949     const DWORD adjacency0[] = {-1, -1, -1};
4950     const DWORD exp_point_rep0[] = {0, 1, 2};
4951     /* mesh1 (right)
4952      *
4953      * 0--1 3
4954      * | / /|
4955      * |/ / |
4956      * 2 5--4
4957      */
4958     const struct vertex_pnc vertices1[] =
4959     {
4960         {{ 0.0f,  3.0f,  0.f}, up, RED},
4961         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
4962         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
4963
4964         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
4965         {{ 3.0f,  0.0f,  0.f}, up, RED},
4966         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
4967     };
4968     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
4969     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
4970     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
4971     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
4972     const DWORD exp_point_rep1[] = {0, 1, 2, 1, 4, 2};
4973     /* mesh2 (left)
4974      *
4975      *    3 0--1
4976      *   /| | /
4977      *  / | |/
4978      * 5--4 2
4979      */
4980     const struct vertex_pnc vertices2[] =
4981     {
4982         {{ 0.0f,  3.0f,  0.f}, up, RED},
4983         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
4984         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
4985
4986         {{-1.0f,  3.0f,  0.f}, up, RED},
4987         {{-1.0f,  0.0f,  0.f}, up, GREEN},
4988         {{-3.0f,  0.0f,  0.f}, up, BLUE},
4989     };
4990     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
4991     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
4992     const unsigned int num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
4993     const DWORD adjacency2[] = {-1, -1, 1, 0, -1, -1};
4994     const DWORD exp_point_rep2[] = {0, 1, 2, 0, 2, 5};
4995     /* mesh3 (above)
4996      *
4997      *    3
4998      *   /|
4999      *  / |
5000      * 5--4
5001      * 0--1
5002      * | /
5003      * |/
5004      * 2
5005      */
5006     struct vertex_pnc vertices3[] =
5007     {
5008         {{ 0.0f,  3.0f,  0.f}, up, RED},
5009         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5010         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5011
5012         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5013         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5014         {{ 0.0f,  4.0f,  0.f}, up, RED},
5015     };
5016     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5017     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5018     const unsigned int num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
5019     const DWORD adjacency3[] = {1, -1, -1, -1, 0, -1};
5020     const DWORD exp_point_rep3[] = {0, 1, 2, 3, 1, 0};
5021     /* mesh4 (below, tip against tip)
5022      *
5023      * 0--1
5024      * | /
5025      * |/
5026      * 2
5027      * 3
5028      * |\
5029      * | \
5030      * 5--4
5031      */
5032     struct vertex_pnc vertices4[] =
5033     {
5034         {{ 0.0f,  3.0f,  0.f}, up, RED},
5035         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5036         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5037
5038         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5039         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5040         {{ 0.0f, -7.0f,  0.f}, up, RED},
5041     };
5042     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5043     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5044     const unsigned int num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
5045     const DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
5046     const DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
5047     /* mesh5 (gap in mesh)
5048      *
5049      *    0      3-----4  15
5050      *   / \      \   /  /  \
5051      *  /   \      \ /  /    \
5052      * 2-----1      5 17-----16
5053      * 6-----7      9 12-----13
5054      *  \   /      / \  \    /
5055      *   \ /      /   \  \  /
5056      *    8     10-----11 14
5057      *
5058      */
5059     const struct vertex_pnc vertices5[] =
5060     {
5061         {{ 0.0f,  1.0f,  0.f}, up, RED},
5062         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5063         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5064
5065         {{ 0.1f,  1.0f,  0.f}, up, RED},
5066         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5067         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5068
5069         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5070         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5071         {{ 0.0f, -3.1f,  0.f}, up, RED},
5072
5073         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5074         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5075         {{ 0.1f, -3.1f,  0.f}, up, RED},
5076
5077         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5078         {{ 3.2f, -1.1f,  0.f}, up, RED},
5079         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5080
5081         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5082         {{ 3.2f, -1.0f,  0.f}, up, RED},
5083         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5084     };
5085     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5086     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5087     const unsigned int num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
5088     const DWORD adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5089     const DWORD exp_point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5090     const WORD indices5_16bit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5091     /* mesh6 (indices re-ordering)
5092      *
5093      * 0--1 6 3
5094      * | / /| |\
5095      * |/ / | | \
5096      * 2 8--7 5--4
5097      */
5098     const struct vertex_pnc vertices6[] =
5099     {
5100         {{ 0.0f,  3.0f,  0.f}, up, RED},
5101         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5102         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5103
5104         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5105         {{ 3.0f,  0.0f,  0.f}, up, RED},
5106         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5107
5108         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5109         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5110         {{ 4.0f,  0.0f,  0.f}, up, RED},
5111     };
5112     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5113     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5114     const unsigned int num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
5115     const DWORD adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5116     const DWORD exp_point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5117     /* mesh7 (expands collapsed triangle)
5118      *
5119      * 0--1 3
5120      * | / /|
5121      * |/ / |
5122      * 2 5--4
5123      */
5124     const struct vertex_pnc vertices7[] =
5125     {
5126         {{ 0.0f,  3.0f,  0.f}, up, RED},
5127         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5128         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5129
5130         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5131         {{ 3.0f,  0.0f,  0.f}, up, RED},
5132         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5133     };
5134     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5135     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5136     const unsigned int num_faces7 = ARRAY_SIZE(indices7) / VERTS_PER_FACE;
5137     const DWORD adjacency7[] = {-1, -1, -1, -1, -1, -1};
5138     const DWORD exp_point_rep7[] = {0, 1, 2, 3, 4, 5};
5139     /* mesh8 (indices re-ordering and double replacement)
5140      *
5141      * 0--1 9  6
5142      * | / /|  |\
5143      * |/ / |  | \
5144      * 2 11-10 8--7
5145      *         3--4
5146      *         | /
5147      *         |/
5148      *         5
5149      */
5150     const struct vertex_pnc vertices8[] =
5151     {
5152         {{ 0.0f,  3.0f,  0.f}, up, RED},
5153         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5154         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5155
5156         {{ 4.0,  -4.0,  0.f}, up, RED},
5157         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5158         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5159
5160         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5161         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5162         {{ 4.0f,  0.0f,  0.f}, up, RED},
5163
5164         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5165         {{ 3.0f,  0.0f,  0.f}, up, RED},
5166         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5167     };
5168     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5169     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5170     const unsigned int num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
5171     const DWORD adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5172     const DWORD exp_point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5173     /* mesh9 (right, shared vertices)
5174      *
5175      * 0--1
5176      * | /|
5177      * |/ |
5178      * 2--3
5179      */
5180     const struct vertex_pnc vertices9[] =
5181     {
5182         {{ 0.0f,  3.0f,  0.f}, up, RED},
5183         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5184         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5185
5186         {{ 2.0f,  0.0f,  0.f}, up, RED},
5187     };
5188     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5189     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5190     const unsigned int num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
5191     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
5192     const DWORD exp_point_rep9[] = {0, 1, 2, 3};
5193     /* All mesh data */
5194     ID3DXMesh *mesh = NULL;
5195     ID3DXMesh *mesh_null_check = NULL;
5196     unsigned int attributes[] = {0};
5197     struct
5198     {
5199         const struct vertex_pnc *vertices;
5200         const DWORD *indices;
5201         const DWORD num_vertices;
5202         const DWORD num_faces;
5203         const DWORD *adjacency;
5204         const DWORD *exp_point_reps;
5205         const DWORD options;
5206     }
5207     tc[] =
5208     {
5209         {
5210             vertices0,
5211             indices0,
5212             num_vertices0,
5213             num_faces0,
5214             adjacency0,
5215             exp_point_rep0,
5216             options
5217         },
5218         {
5219             vertices1,
5220             indices1,
5221             num_vertices1,
5222             num_faces1,
5223             adjacency1,
5224             exp_point_rep1,
5225             options
5226         },
5227         {
5228             vertices2,
5229             indices2,
5230             num_vertices2,
5231             num_faces2,
5232             adjacency2,
5233             exp_point_rep2,
5234             options
5235         },
5236         {
5237             vertices3,
5238             indices3,
5239             num_vertices3,
5240             num_faces3,
5241             adjacency3,
5242             exp_point_rep3,
5243             options
5244         },
5245         {
5246             vertices4,
5247             indices4,
5248             num_vertices4,
5249             num_faces4,
5250             adjacency4,
5251             exp_point_rep4,
5252             options
5253         },
5254         {
5255             vertices5,
5256             indices5,
5257             num_vertices5,
5258             num_faces5,
5259             adjacency5,
5260             exp_point_rep5,
5261             options
5262         },
5263         {
5264             vertices6,
5265             indices6,
5266             num_vertices6,
5267             num_faces6,
5268             adjacency6,
5269             exp_point_rep6,
5270             options
5271         },
5272         {
5273             vertices7,
5274             indices7,
5275             num_vertices7,
5276             num_faces7,
5277             adjacency7,
5278             exp_point_rep7,
5279             options
5280         },
5281         {
5282             vertices8,
5283             indices8,
5284             num_vertices8,
5285             num_faces8,
5286             adjacency8,
5287             exp_point_rep8,
5288             options
5289         },
5290         {
5291             vertices9,
5292             indices9,
5293             num_vertices9,
5294             num_faces9,
5295             adjacency9,
5296             exp_point_rep9,
5297             options
5298         },
5299         {
5300             vertices5,
5301             (DWORD*)indices5_16bit,
5302             num_vertices5,
5303             num_faces5,
5304             adjacency5,
5305             exp_point_rep5,
5306             options_16bit
5307         },
5308     };
5309     DWORD *point_reps = NULL;
5310
5311     test_context = new_test_context();
5312     if (!test_context)
5313     {
5314         skip("Couldn't create test context\n");
5315         goto cleanup;
5316     }
5317
5318     for (i = 0; i < ARRAY_SIZE(tc); i++)
5319     {
5320         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options, declaration,
5321                             test_context->device, &mesh);
5322         if (FAILED(hr))
5323         {
5324             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5325             goto cleanup;
5326         }
5327
5328         if (i == 0) /* Save first mesh for later NULL checks */
5329             mesh_null_check = mesh;
5330
5331         point_reps = HeapAlloc(GetProcessHeap(), 0, tc[i].num_vertices * sizeof(*point_reps));
5332         if (!point_reps)
5333         {
5334             skip("Couldn't allocate point reps array.\n");
5335             goto cleanup;
5336         }
5337
5338         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5339         if (FAILED(hr))
5340         {
5341             skip("Couldn't lock vertex buffer.\n");
5342             goto cleanup;
5343         }
5344         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5345         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5346         if (FAILED(hr))
5347         {
5348             skip("Couldn't unlock vertex buffer.\n");
5349             goto cleanup;
5350         }
5351
5352         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5353         if (FAILED(hr))
5354         {
5355             skip("Couldn't lock index buffer.\n");
5356             goto cleanup;
5357         }
5358         if (tc[i].options & D3DXMESH_32BIT)
5359         {
5360             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5361         }
5362         else
5363         {
5364             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5365         }
5366         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5367         if (FAILED(hr)) {
5368             skip("Couldn't unlock index buffer.\n");
5369             goto cleanup;
5370         }
5371
5372         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5373         if (FAILED(hr))
5374         {
5375             skip("Couldn't lock attributes buffer.\n");
5376             goto cleanup;
5377         }
5378         memcpy(attributes_buffer, attributes, sizeof(attributes));
5379         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5380         if (FAILED(hr))
5381         {
5382             skip("Couldn't unlock attributes buffer.\n");
5383             goto cleanup;
5384         }
5385
5386         /* Convert adjacency to point representation */
5387         for (j = 0; j < tc[i].num_vertices; j++) point_reps[j] = -1;
5388         hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacency, point_reps);
5389         ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
5390            "Got %x expected D3D_OK\n", i, hr);
5391
5392         /* Check point representation */
5393         for (j = 0; j < tc[i].num_vertices; j++)
5394         {
5395             ok(point_reps[j] == tc[i].exp_point_reps[j],
5396                "Unexpected point representation at (%d, %d)."
5397                " Got %d expected %d\n",
5398                i, j, point_reps[j], tc[i].exp_point_reps[j]);
5399         }
5400
5401         HeapFree(GetProcessHeap(), 0, point_reps);
5402         point_reps = NULL;
5403
5404         if (i != 0) /* First mesh will be freed during cleanup */
5405             mesh->lpVtbl->Release(mesh);
5406     }
5407
5408     /* NULL checks */
5409     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacency, NULL);
5410     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
5411        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5412     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, NULL);
5413     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. "
5414        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5415
5416 cleanup:
5417     if (mesh_null_check)
5418         mesh_null_check->lpVtbl->Release(mesh_null_check);
5419     HeapFree(GetProcessHeap(), 0, point_reps);
5420     free_test_context(test_context);
5421 }
5422
5423 static void test_convert_point_reps_to_adjacency(void)
5424 {
5425     HRESULT hr;
5426     struct test_context *test_context = NULL;
5427     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5428     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5429     const D3DVERTEXELEMENT9 declaration[] =
5430     {
5431         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5432         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5433         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5434         D3DDECL_END()
5435     };
5436     const unsigned int VERTS_PER_FACE = 3;
5437     void *vertex_buffer;
5438     void *index_buffer;
5439     DWORD *attributes_buffer;
5440     int i, j;
5441     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5442     struct vertex_pnc
5443     {
5444         D3DXVECTOR3 position;
5445         D3DXVECTOR3 normal;
5446         enum color color; /* In case of manual visual inspection */
5447     };
5448     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5449     /* mesh0 (one face)
5450      *
5451      * 0--1
5452      * | /
5453      * |/
5454      * 2
5455      */
5456     const struct vertex_pnc vertices0[] =
5457     {
5458         {{ 0.0f,  3.0f,  0.f}, up, RED},
5459         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5460         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5461     };
5462     const DWORD indices0[] = {0, 1, 2};
5463     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5464     const unsigned int num_faces0 = num_vertices0 / VERTS_PER_FACE;
5465     const DWORD exp_adjacency0[] = {-1, -1, -1};
5466     const DWORD exp_id_adjacency0[] = {-1, -1, -1};
5467     const DWORD point_rep0[] = {0, 1, 2};
5468     /* mesh1 (right)
5469      *
5470      * 0--1 3
5471      * | / /|
5472      * |/ / |
5473      * 2 5--4
5474      */
5475     const struct vertex_pnc vertices1[] =
5476     {
5477         {{ 0.0f,  3.0f,  0.f}, up, RED},
5478         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5479         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5480
5481         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5482         {{ 3.0f,  0.0f,  0.f}, up, RED},
5483         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5484     };
5485     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5486     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5487     const unsigned int num_faces1 = num_vertices1 / VERTS_PER_FACE;
5488     const DWORD exp_adjacency1[] = {-1, 1, -1, -1, -1, 0};
5489     const DWORD exp_id_adjacency1[] = {-1, -1, -1, -1, -1, -1};
5490     const DWORD point_rep1[] = {0, 1, 2, 1, 4, 2};
5491     /* mesh2 (left)
5492      *
5493      *    3 0--1
5494      *   /| | /
5495      *  / | |/
5496      * 5--4 2
5497      */
5498     const struct vertex_pnc vertices2[] =
5499     {
5500         {{ 0.0f,  3.0f,  0.f}, up, RED},
5501         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5502         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5503
5504         {{-1.0f,  3.0f,  0.f}, up, RED},
5505         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5506         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5507     };
5508     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5509     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5510     const unsigned int num_faces2 = num_vertices2 / VERTS_PER_FACE;
5511     const DWORD exp_adjacency2[] = {-1, -1, 1, 0, -1, -1};
5512     const DWORD exp_id_adjacency2[] = {-1, -1, -1, -1, -1, -1};
5513     const DWORD point_rep2[] = {0, 1, 2, 0, 2, 5};
5514     /* mesh3 (above)
5515      *
5516      *    3
5517      *   /|
5518      *  / |
5519      * 5--4
5520      * 0--1
5521      * | /
5522      * |/
5523      * 2
5524      */
5525     struct vertex_pnc vertices3[] =
5526     {
5527         {{ 0.0f,  3.0f,  0.f}, up, RED},
5528         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5529         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5530
5531         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5532         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5533         {{ 0.0f,  4.0f,  0.f}, up, RED},
5534     };
5535     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5536     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5537     const unsigned int num_faces3 = num_vertices3 / VERTS_PER_FACE;
5538     const DWORD exp_adjacency3[] = {1, -1, -1, -1, 0, -1};
5539     const DWORD exp_id_adjacency3[] = {-1, -1, -1, -1, -1, -1};
5540     const DWORD point_rep3[] = {0, 1, 2, 3, 1, 0};
5541     /* mesh4 (below, tip against tip)
5542      *
5543      * 0--1
5544      * | /
5545      * |/
5546      * 2
5547      * 3
5548      * |\
5549      * | \
5550      * 5--4
5551      */
5552     struct vertex_pnc vertices4[] =
5553     {
5554         {{ 0.0f,  3.0f,  0.f}, up, RED},
5555         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5556         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5557
5558         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5559         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5560         {{ 0.0f, -7.0f,  0.f}, up, RED},
5561     };
5562     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5563     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5564     const unsigned int num_faces4 = num_vertices4 / VERTS_PER_FACE;
5565     const DWORD exp_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5566     const DWORD exp_id_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5567     const DWORD point_rep4[] = {0, 1, 2, 3, 4, 5};
5568     /* mesh5 (gap in mesh)
5569      *
5570      *    0      3-----4  15
5571      *   / \      \   /  /  \
5572      *  /   \      \ /  /    \
5573      * 2-----1      5 17-----16
5574      * 6-----7      9 12-----13
5575      *  \   /      / \  \    /
5576      *   \ /      /   \  \  /
5577      *    8     10-----11 14
5578      *
5579      */
5580     const struct vertex_pnc vertices5[] =
5581     {
5582         {{ 0.0f,  1.0f,  0.f}, up, RED},
5583         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5584         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5585
5586         {{ 0.1f,  1.0f,  0.f}, up, RED},
5587         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5588         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5589
5590         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5591         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5592         {{ 0.0f, -3.1f,  0.f}, up, RED},
5593
5594         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5595         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5596         {{ 0.1f, -3.1f,  0.f}, up, RED},
5597
5598         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5599         {{ 3.2f, -1.1f,  0.f}, up, RED},
5600         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5601
5602         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5603         {{ 3.2f, -1.0f,  0.f}, up, RED},
5604         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5605     };
5606     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5607     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5608     const unsigned int num_faces5 = num_vertices5 / VERTS_PER_FACE;
5609     const DWORD exp_adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5610     const DWORD exp_id_adjacency5[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5611     const DWORD point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5612     /* mesh6 (indices re-ordering)
5613      *
5614      * 0--1 6 3
5615      * | / /| |\
5616      * |/ / | | \
5617      * 2 8--7 5--4
5618      */
5619     const struct vertex_pnc vertices6[] =
5620     {
5621         {{ 0.0f,  3.0f,  0.f}, up, RED},
5622         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5623         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5624
5625         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5626         {{ 3.0f,  0.0f,  0.f}, up, RED},
5627         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5628
5629         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5630         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5631         {{ 4.0f,  0.0f,  0.f}, up, RED},
5632     };
5633     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5634     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5635     const unsigned int num_faces6 = num_vertices6 / VERTS_PER_FACE;
5636     const DWORD exp_adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5637     const DWORD exp_id_adjacency6[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1};
5638     const DWORD point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5639     /* mesh7 (expands collapsed triangle)
5640      *
5641      * 0--1 3
5642      * | / /|
5643      * |/ / |
5644      * 2 5--4
5645      */
5646     const struct vertex_pnc vertices7[] =
5647     {
5648         {{ 0.0f,  3.0f,  0.f}, up, RED},
5649         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5650         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5651
5652         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5653         {{ 3.0f,  0.0f,  0.f}, up, RED},
5654         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5655     };
5656     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5657     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5658     const unsigned int num_faces7 = num_vertices7 / VERTS_PER_FACE;
5659     const DWORD exp_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5660     const DWORD exp_id_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5661     const DWORD point_rep7[] = {0, 1, 2, 3, 4, 5};
5662     /* mesh8 (indices re-ordering and double replacement)
5663      *
5664      * 0--1 9  6
5665      * | / /|  |\
5666      * |/ / |  | \
5667      * 2 11-10 8--7
5668      *         3--4
5669      *         | /
5670      *         |/
5671      *         5
5672      */
5673     const struct vertex_pnc vertices8[] =
5674     {
5675         {{ 0.0f,  3.0f,  0.f}, up, RED},
5676         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5677         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5678
5679         {{ 4.0,  -4.0,  0.f}, up, RED},
5680         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5681         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5682
5683         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5684         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5685         {{ 4.0f,  0.0f,  0.f}, up, RED},
5686
5687         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5688         {{ 3.0f,  0.0f,  0.f}, up, RED},
5689         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5690     };
5691     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5692     const WORD indices8_16bit[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5693     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5694     const unsigned int num_faces8 = num_vertices8 / VERTS_PER_FACE;
5695     const DWORD exp_adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5696     const DWORD exp_id_adjacency8[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5697     const DWORD point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5698      /* mesh9 (right, shared vertices)
5699      *
5700      * 0--1
5701      * | /|
5702      * |/ |
5703      * 2--3
5704      */
5705     const struct vertex_pnc vertices9[] =
5706     {
5707         {{ 0.0f,  3.0f,  0.f}, up, RED},
5708         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5709         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5710
5711         {{ 2.0f,  0.0f,  0.f}, up, RED},
5712     };
5713     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5714     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5715     const unsigned int num_faces9 = 2;
5716     const DWORD exp_adjacency9[] = {-1, 1, -1, -1, -1, 0};
5717     const DWORD exp_id_adjacency9[] = {-1, 1, -1, -1, -1, 0};
5718     const DWORD point_rep9[] = {0, 1, 2, 3};
5719     /* All mesh data */
5720     ID3DXMesh *mesh = NULL;
5721     ID3DXMesh *mesh_null_check = NULL;
5722     unsigned int attributes[] = {0};
5723     struct
5724     {
5725         const struct vertex_pnc *vertices;
5726         const DWORD *indices;
5727         const DWORD num_vertices;
5728         const DWORD num_faces;
5729         const DWORD *point_reps;
5730         const DWORD *exp_adjacency;
5731         const DWORD *exp_id_adjacency;
5732         const DWORD options;
5733     }
5734     tc[] =
5735     {
5736         {
5737             vertices0,
5738             indices0,
5739             num_vertices0,
5740             num_faces0,
5741             point_rep0,
5742             exp_adjacency0,
5743             exp_id_adjacency0,
5744             options
5745         },
5746         {
5747             vertices1,
5748             indices1,
5749             num_vertices1,
5750             num_faces1,
5751             point_rep1,
5752             exp_adjacency1,
5753             exp_id_adjacency1,
5754             options
5755         },
5756         {
5757             vertices2,
5758             indices2,
5759             num_vertices2,
5760             num_faces2,
5761             point_rep2,
5762             exp_adjacency2,
5763             exp_id_adjacency2,
5764             options
5765         },
5766         {
5767             vertices3,
5768             indices3,
5769             num_vertices3,
5770             num_faces3,
5771             point_rep3,
5772             exp_adjacency3,
5773             exp_id_adjacency3,
5774             options
5775         },
5776         {
5777             vertices4,
5778             indices4,
5779             num_vertices4,
5780             num_faces4,
5781             point_rep4,
5782             exp_adjacency4,
5783             exp_id_adjacency4,
5784             options
5785         },
5786         {
5787             vertices5,
5788             indices5,
5789             num_vertices5,
5790             num_faces5,
5791             point_rep5,
5792             exp_adjacency5,
5793             exp_id_adjacency5,
5794             options
5795         },
5796         {
5797             vertices6,
5798             indices6,
5799             num_vertices6,
5800             num_faces6,
5801             point_rep6,
5802             exp_adjacency6,
5803             exp_id_adjacency6,
5804             options
5805         },
5806         {
5807             vertices7,
5808             indices7,
5809             num_vertices7,
5810             num_faces7,
5811             point_rep7,
5812             exp_adjacency7,
5813             exp_id_adjacency7,
5814             options
5815         },
5816         {
5817             vertices8,
5818             indices8,
5819             num_vertices8,
5820             num_faces8,
5821             point_rep8,
5822             exp_adjacency8,
5823             exp_id_adjacency8,
5824             options
5825         },
5826         {
5827             vertices9,
5828             indices9,
5829             num_vertices9,
5830             num_faces9,
5831             point_rep9,
5832             exp_adjacency9,
5833             exp_id_adjacency9,
5834             options
5835         },
5836         {
5837             vertices8,
5838             (DWORD*)indices8_16bit,
5839             num_vertices8,
5840             num_faces8,
5841             point_rep8,
5842             exp_adjacency8,
5843             exp_id_adjacency8,
5844             options_16bit
5845         },
5846     };
5847     DWORD *adjacency = NULL;
5848
5849     test_context = new_test_context();
5850     if (!test_context)
5851     {
5852         skip("Couldn't create test context\n");
5853         goto cleanup;
5854     }
5855
5856     for (i = 0; i < ARRAY_SIZE(tc); i++)
5857     {
5858         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
5859                             declaration, test_context->device, &mesh);
5860         if (FAILED(hr))
5861         {
5862             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5863             goto cleanup;
5864         }
5865
5866         if (i == 0) /* Save first mesh for later NULL checks */
5867             mesh_null_check = mesh;
5868
5869         adjacency = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
5870         if (!adjacency)
5871         {
5872             skip("Couldn't allocate adjacency array.\n");
5873             goto cleanup;
5874         }
5875
5876         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5877         if (FAILED(hr))
5878         {
5879             skip("Couldn't lock vertex buffer.\n");
5880             goto cleanup;
5881         }
5882         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5883         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5884         if (FAILED(hr))
5885         {
5886             skip("Couldn't unlock vertex buffer.\n");
5887             goto cleanup;
5888         }
5889         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5890         if (FAILED(hr))
5891         {
5892             skip("Couldn't lock index buffer.\n");
5893             goto cleanup;
5894         }
5895         if (tc[i].options & D3DXMESH_32BIT)
5896         {
5897             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5898         }
5899         else
5900         {
5901             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5902         }
5903         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5904         if (FAILED(hr)) {
5905             skip("Couldn't unlock index buffer.\n");
5906             goto cleanup;
5907         }
5908
5909         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5910         if (FAILED(hr))
5911         {
5912             skip("Couldn't lock attributes buffer.\n");
5913             goto cleanup;
5914         }
5915         memcpy(attributes_buffer, attributes, sizeof(attributes));
5916         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5917         if (FAILED(hr))
5918         {
5919             skip("Couldn't unlock attributes buffer.\n");
5920             goto cleanup;
5921         }
5922
5923         /* Convert point representation to adjacency*/
5924         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
5925
5926         hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
5927         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
5928            "Got %x expected D3D_OK\n", i, hr);
5929         /* Check adjacency */
5930         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
5931         {
5932             ok(adjacency[j] == tc[i].exp_adjacency[j],
5933                "Unexpected adjacency information at (%d, %d)."
5934                " Got %d expected %d\n",
5935                i, j, adjacency[j], tc[i].exp_adjacency[j]);
5936         }
5937
5938         /* NULL point representation is considered identity. */
5939         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
5940         hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
5941         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
5942                      "Got %x expected D3D_OK\n", hr);
5943         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
5944         {
5945             ok(adjacency[j] == tc[i].exp_id_adjacency[j],
5946                "Unexpected adjacency information (id) at (%d, %d)."
5947                " Got %d expected %d\n",
5948                i, j, adjacency[j], tc[i].exp_id_adjacency[j]);
5949         }
5950
5951         HeapFree(GetProcessHeap(), 0, adjacency);
5952         adjacency = NULL;
5953         if (i != 0) /* First mesh will be freed during cleanup */
5954             mesh->lpVtbl->Release(mesh);
5955     }
5956
5957     /* NULL checks */
5958     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
5959     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
5960        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5961     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
5962     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
5963        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5964
5965 cleanup:
5966     if (mesh_null_check)
5967         mesh_null_check->lpVtbl->Release(mesh_null_check);
5968     HeapFree(GetProcessHeap(), 0, adjacency);
5969     free_test_context(test_context);
5970 }
5971
5972 static HRESULT init_test_mesh(const DWORD num_faces, const DWORD num_vertices,
5973                               const DWORD options,
5974                               const D3DVERTEXELEMENT9 *declaration,
5975                               IDirect3DDevice9 *device, ID3DXMesh **mesh_ptr,
5976                               const void *vertices, const DWORD vertex_size,
5977                               const DWORD *indices, const DWORD *attributes)
5978 {
5979     HRESULT hr;
5980     void *vertex_buffer;
5981     void *index_buffer;
5982     DWORD *attributes_buffer;
5983     ID3DXMesh *mesh = NULL;
5984
5985     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration, device, mesh_ptr);
5986     if (FAILED(hr))
5987     {
5988         skip("Couldn't create mesh. Got %x expected D3D_OK\n", hr);
5989         goto cleanup;
5990     }
5991     mesh = *mesh_ptr;
5992
5993     hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5994     if (FAILED(hr))
5995     {
5996         skip("Couldn't lock vertex buffer.\n");
5997         goto cleanup;
5998     }
5999     memcpy(vertex_buffer, vertices, num_vertices * vertex_size);
6000     hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6001     if (FAILED(hr))
6002     {
6003         skip("Couldn't unlock vertex buffer.\n");
6004         goto cleanup;
6005     }
6006
6007     hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6008     if (FAILED(hr))
6009     {
6010         skip("Couldn't lock index buffer.\n");
6011         goto cleanup;
6012     }
6013     if (options & D3DXMESH_32BIT)
6014     {
6015         if (indices)
6016             memcpy(index_buffer, indices, 3 * num_faces * sizeof(DWORD));
6017         else
6018         {
6019             /* Fill index buffer with 0, 1, 2, ...*/
6020             DWORD *indices_32bit = (DWORD*)index_buffer;
6021             UINT i;
6022             for (i = 0; i < 3 * num_faces; i++)
6023                 indices_32bit[i] = i;
6024         }
6025     }
6026     else
6027     {
6028         if (indices)
6029             memcpy(index_buffer, indices, 3 * num_faces * sizeof(WORD));
6030         else
6031         {
6032             /* Fill index buffer with 0, 1, 2, ...*/
6033             WORD *indices_16bit = (WORD*)index_buffer;
6034             UINT i;
6035             for (i = 0; i < 3 * num_faces; i++)
6036                 indices_16bit[i] = i;
6037         }
6038     }
6039     hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6040     if (FAILED(hr)) {
6041         skip("Couldn't unlock index buffer.\n");
6042         goto cleanup;
6043     }
6044
6045     hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6046     if (FAILED(hr))
6047     {
6048         skip("Couldn't lock attributes buffer.\n");
6049         goto cleanup;
6050     }
6051
6052     if (attributes)
6053         memcpy(attributes_buffer, attributes, num_faces * sizeof(*attributes));
6054     else
6055         memset(attributes_buffer, 0, num_faces * sizeof(*attributes));
6056
6057     hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6058     if (FAILED(hr))
6059     {
6060         skip("Couldn't unlock attributes buffer.\n");
6061         goto cleanup;
6062     }
6063
6064     hr = D3D_OK;
6065 cleanup:
6066     return hr;
6067 }
6068
6069 /* Using structs instead of bit-fields in order to avoid compiler issues. */
6070 struct udec3
6071 {
6072     UINT x;
6073     UINT y;
6074     UINT z;
6075     UINT w;
6076 };
6077
6078 struct dec3n
6079 {
6080     INT x;
6081     INT y;
6082     INT z;
6083     INT w;
6084 };
6085
6086 static DWORD init_udec3_dword(UINT x, UINT y, UINT z, UINT w)
6087 {
6088     DWORD d = 0;
6089
6090     d |= x & 0x3ff;
6091     d |= (y << 10) & 0xffc00;
6092     d |= (z << 20) & 0x3ff00000;
6093     d |= (w << 30) & 0xc0000000;
6094
6095     return d;
6096 }
6097
6098 static DWORD init_dec3n_dword(INT x, INT y, INT z, INT w)
6099 {
6100     DWORD d = 0;
6101
6102     d |= x & 0x3ff;
6103     d |= (y << 10) & 0xffc00;
6104     d |= (z << 20) & 0x3ff00000;
6105     d |= (w << 30) & 0xc0000000;
6106
6107     return d;
6108 }
6109
6110 static struct udec3 dword_to_udec3(DWORD d)
6111 {
6112     struct udec3 v;
6113
6114     v.x = d & 0x3ff;
6115     v.y = (d & 0xffc00) >> 10;
6116     v.z = (d & 0x3ff00000) >> 20;
6117     v.w = (d & 0xc0000000) >> 30;
6118
6119     return v;
6120 }
6121
6122 static struct dec3n dword_to_dec3n(DWORD d)
6123 {
6124     struct dec3n v;
6125
6126     v.x = d & 0x3ff;
6127     v.y = (d & 0xffc00) >> 10;
6128     v.z = (d & 0x3ff00000) >> 20;
6129     v.w = (d & 0xc0000000) >> 30;
6130
6131     return v;
6132 }
6133
6134 static void check_vertex_components(int line, int mesh_number, int vertex_number, BYTE *got_ptr, const BYTE *exp_ptr, D3DVERTEXELEMENT9 *declaration)
6135 {
6136     const char *usage_strings[] =
6137     {
6138         "position",
6139         "blend weight",
6140         "blend indices",
6141         "normal",
6142         "point size",
6143         "texture coordinates",
6144         "tangent",
6145         "binormal",
6146         "tessellation factor",
6147         "position transformed",
6148         "color",
6149         "fog",
6150         "depth",
6151         "sample"
6152     };
6153     D3DVERTEXELEMENT9 *decl_ptr;
6154     const float PRECISION = 1e-5f;
6155
6156     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
6157     {
6158         switch (decl_ptr->Type)
6159         {
6160             case D3DDECLTYPE_FLOAT1:
6161             {
6162                 FLOAT *got = (FLOAT*)(got_ptr + decl_ptr->Offset);
6163                 FLOAT *exp = (FLOAT*)(exp_ptr + decl_ptr->Offset);
6164                 FLOAT diff = fabsf(*got - *exp);
6165                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got %f for vertex %d %s, expected %f.\n",
6166                     mesh_number, *got, vertex_number, usage_strings[decl_ptr->Usage], *exp);
6167                 break;
6168             }
6169             case D3DDECLTYPE_FLOAT2:
6170             {
6171                 D3DXVECTOR2 *got = (D3DXVECTOR2*)(got_ptr + decl_ptr->Offset);
6172                 D3DXVECTOR2 *exp = (D3DXVECTOR2*)(exp_ptr + decl_ptr->Offset);
6173                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6174                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f) for vertex %d %s, expected (%f, %f).\n",
6175                     mesh_number, got->x, got->y, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y);
6176                 break;
6177             }
6178             case D3DDECLTYPE_FLOAT3:
6179             {
6180                 D3DXVECTOR3 *got = (D3DXVECTOR3*)(got_ptr + decl_ptr->Offset);
6181                 D3DXVECTOR3 *exp = (D3DXVECTOR3*)(exp_ptr + decl_ptr->Offset);
6182                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6183                 diff = max(diff, fabsf(got->z - exp->z));
6184                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f) for vertex %d %s, expected (%f, %f, %f).\n",
6185                     mesh_number, got->x, got->y, got->z, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y, exp->z);
6186                 break;
6187             }
6188             case D3DDECLTYPE_FLOAT4:
6189             {
6190                 D3DXVECTOR4 *got = (D3DXVECTOR4*)(got_ptr + decl_ptr->Offset);
6191                 D3DXVECTOR4 *exp = (D3DXVECTOR4*)(exp_ptr + decl_ptr->Offset);
6192                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6193                 diff = max(diff, fabsf(got->z - exp->z));
6194                 diff = max(diff, fabsf(got->w - exp->w));
6195                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f, %f) for vertex %d %s, expected (%f, %f, %f, %f).\n",
6196                     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);
6197                 break;
6198             }
6199             case D3DDECLTYPE_D3DCOLOR:
6200             {
6201                 BYTE *got = got_ptr + decl_ptr->Offset;
6202                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6203                 BOOL same_color = got[0] == exp[0] && got[1] == exp[1]
6204                                   && got[2] == exp[2] && got[3] == exp[3];
6205                 const char *color_types[] = {"diffuse", "specular", "undefined color"};
6206                 BYTE usage_index = decl_ptr->UsageIndex;
6207                 if (usage_index > 1) usage_index = 2;
6208                 ok_(__FILE__,line)(same_color, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6209                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, color_types[usage_index], exp[0], exp[1], exp[2], exp[3]);
6210                 break;
6211             }
6212             case D3DDECLTYPE_UBYTE4:
6213             case D3DDECLTYPE_UBYTE4N:
6214             {
6215                 BYTE *got = got_ptr + decl_ptr->Offset;
6216                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6217                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6218                             && got[2] == exp[2] && got[3] == exp[3];
6219                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6220                     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]);
6221                 break;
6222             }
6223             case D3DDECLTYPE_SHORT2:
6224             case D3DDECLTYPE_SHORT2N:
6225             {
6226                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6227                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6228                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6229                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd) for vertex %d %s, expected (%hd, %hd).\n",
6230                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6231                 break;
6232             }
6233             case D3DDECLTYPE_SHORT4:
6234             case D3DDECLTYPE_SHORT4N:
6235             {
6236                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6237                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6238                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6239                             && got[2] == exp[2] && got[3] == exp[3];
6240                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd, %hd, %hd) for vertex %d %s, expected (%hd, %hd, %hd, %hd).\n",
6241                     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]);
6242                 break;
6243             }
6244             case D3DDECLTYPE_USHORT2N:
6245             {
6246                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6247                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6248                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6249                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu) for vertex %d %s, expected (%hu, %hu).\n",
6250                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6251                 break;
6252             }
6253             case D3DDECLTYPE_USHORT4N:
6254             {
6255                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6256                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6257                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6258                             && got[2] == exp[2] && got[3] == exp[3];
6259                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu, %hu, %hu) for vertex %d %s, expected (%hu, %hu, %hu, %hu).\n",
6260                     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]);
6261                 break;
6262             }
6263             case D3DDECLTYPE_UDEC3:
6264             {
6265                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6266                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6267                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6268                 struct udec3 got_udec3 = dword_to_udec3(*got);
6269                 struct udec3 exp_udec3 = dword_to_udec3(*exp);
6270                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6271                     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);
6272
6273                 break;
6274             }
6275             case D3DDECLTYPE_DEC3N:
6276             {
6277                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6278                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6279                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6280                 struct dec3n got_dec3n = dword_to_dec3n(*got);
6281                 struct dec3n exp_dec3n = dword_to_dec3n(*exp);
6282                 ok_(__FILE__,line)(same, "Mesh %d: Got (%d, %d, %d, %d) for vertex %d %s, expected (%d, %d, %d, %d).\n",
6283                     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);
6284                 break;
6285             }
6286             case D3DDECLTYPE_FLOAT16_2:
6287             {
6288                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6289                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6290                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6291                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx) for vertex %d %s, expected (%hx, %hx).\n",
6292                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6293                 break;
6294             }
6295             case D3DDECLTYPE_FLOAT16_4:
6296             {
6297                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6298                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6299                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6300                             && got[2] == exp[2] && got[3] == exp[3];
6301                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx, %hx, %hx) for vertex %d %s, expected (%hx, %hx, %hx, %hx).\n",
6302                     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]);
6303                 break;
6304             }
6305             default:
6306                 break;
6307         }
6308     }
6309 }
6310
6311 static void test_weld_vertices(void)
6312 {
6313     HRESULT hr;
6314     struct test_context *test_context = NULL;
6315     DWORD i;
6316     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
6317     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
6318     BYTE *vertices = NULL;
6319     DWORD *indices = NULL;
6320     WORD *indices_16bit = NULL;
6321     const UINT VERTS_PER_FACE = 3;
6322     const D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
6323     struct vertex_normal
6324     {
6325         D3DXVECTOR3 position;
6326         D3DXVECTOR3 normal;
6327     };
6328     struct vertex_blendweight
6329     {
6330         D3DXVECTOR3 position;
6331         FLOAT blendweight;
6332     };
6333     struct vertex_texcoord
6334     {
6335         D3DXVECTOR3 position;
6336         D3DXVECTOR2 texcoord;
6337     };
6338     struct vertex_color
6339     {
6340         D3DXVECTOR3 position;
6341         DWORD color;
6342     };
6343     struct vertex_color_ubyte4
6344     {
6345         D3DXVECTOR3 position;
6346         BYTE color[4];
6347     };
6348     struct vertex_texcoord_short2
6349     {
6350         D3DXVECTOR3 position;
6351         SHORT texcoord[2];
6352     };
6353     struct vertex_texcoord_ushort2n
6354     {
6355         D3DXVECTOR3 position;
6356         USHORT texcoord[2];
6357     };
6358     struct vertex_normal_short4
6359     {
6360         D3DXVECTOR3 position;
6361         SHORT normal[4];
6362     };
6363     struct vertex_color_float4
6364     {
6365         D3DXVECTOR3 position;
6366         D3DXVECTOR4 color;
6367     };
6368     struct vertex_texcoord_float16_2
6369     {
6370         D3DXVECTOR3 position;
6371         WORD texcoord[2];
6372     };
6373     struct vertex_texcoord_float16_4
6374     {
6375         D3DXVECTOR3 position;
6376         WORD texcoord[4];
6377     };
6378     struct vertex_normal_udec3
6379     {
6380         D3DXVECTOR3 position;
6381         DWORD normal;
6382     };
6383     struct vertex_normal_dec3n
6384     {
6385         D3DXVECTOR3 position;
6386         DWORD normal;
6387     };
6388     UINT vertex_size_normal = sizeof(struct vertex_normal);
6389     UINT vertex_size_blendweight = sizeof(struct vertex_blendweight);
6390     UINT vertex_size_texcoord = sizeof(struct vertex_texcoord);
6391     UINT vertex_size_color = sizeof(struct vertex_color);
6392     UINT vertex_size_color_ubyte4 = sizeof(struct vertex_color_ubyte4);
6393     UINT vertex_size_texcoord_short2 = sizeof(struct vertex_texcoord_short2);
6394     UINT vertex_size_normal_short4 = sizeof(struct vertex_normal_short4);
6395     UINT vertex_size_color_float4 = sizeof(struct vertex_color_float4);
6396     UINT vertex_size_texcoord_float16_2 = sizeof(struct vertex_texcoord_float16_2);
6397     UINT vertex_size_texcoord_float16_4 = sizeof(struct vertex_texcoord_float16_4);
6398     UINT vertex_size_normal_udec3 = sizeof(struct vertex_normal_udec3);
6399     UINT vertex_size_normal_dec3n = sizeof(struct vertex_normal_dec3n);
6400     D3DVERTEXELEMENT9 declaration_normal[] =
6401     {
6402         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6403         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6404         D3DDECL_END()
6405     };
6406     D3DVERTEXELEMENT9 declaration_normal3[] =
6407     {
6408         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 3},
6409         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6410         D3DDECL_END()
6411     };
6412     D3DVERTEXELEMENT9 declaration_blendweight[] =
6413     {
6414         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6415         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
6416         D3DDECL_END()
6417     };
6418     D3DVERTEXELEMENT9 declaration_texcoord[] =
6419     {
6420         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6421         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6422         D3DDECL_END()
6423     };
6424     D3DVERTEXELEMENT9 declaration_color[] =
6425     {
6426         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6427         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6428         D3DDECL_END()
6429     };
6430     D3DVERTEXELEMENT9 declaration_color_ubyte4n[] =
6431     {
6432         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6433         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6434         D3DDECL_END()
6435     };
6436     D3DVERTEXELEMENT9 declaration_color_ubyte4[] =
6437     {
6438         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6439         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6440         D3DDECL_END()
6441     };
6442     D3DVERTEXELEMENT9 declaration_texcoord_short2[] =
6443     {
6444         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6445         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6446         D3DDECL_END()
6447     };
6448     D3DVERTEXELEMENT9 declaration_texcoord_short2n[] =
6449     {
6450         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6451         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6452         D3DDECL_END()
6453     };
6454     D3DVERTEXELEMENT9 declaration_texcoord_ushort2n[] =
6455     {
6456         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6457         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6458         D3DDECL_END()
6459     };
6460     D3DVERTEXELEMENT9 declaration_normal_short4[] =
6461     {
6462         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6463         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6464         D3DDECL_END()
6465     };
6466     D3DVERTEXELEMENT9 declaration_normal_short4n[] =
6467     {
6468         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6469         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6470         D3DDECL_END()
6471     };
6472     D3DVERTEXELEMENT9 declaration_normal_ushort4n[] =
6473     {
6474         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6475         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6476         D3DDECL_END()
6477     };
6478     D3DVERTEXELEMENT9 declaration_texcoord10[] =
6479     {
6480         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6481         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 10},
6482         D3DDECL_END()
6483     };
6484     D3DVERTEXELEMENT9 declaration_color2[] =
6485     {
6486         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6487         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
6488         D3DDECL_END()
6489     };
6490     D3DVERTEXELEMENT9 declaration_color2_float4[] =
6491     {
6492         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6493         {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
6494         D3DDECL_END()
6495     };
6496     D3DVERTEXELEMENT9 declaration_texcoord_float16_2[] =
6497     {
6498         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6499         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6500         D3DDECL_END()
6501     };
6502     D3DVERTEXELEMENT9 declaration_texcoord_float16_4[] =
6503     {
6504         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6505         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6506         D3DDECL_END()
6507     };
6508     D3DVERTEXELEMENT9 declaration_normal_udec3[] =
6509    {
6510         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6511         {0, 12, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6512         D3DDECL_END()
6513     };
6514     D3DVERTEXELEMENT9 declaration_normal_dec3n[] =
6515     {
6516         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6517         {0, 12, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6518         D3DDECL_END()
6519     };
6520     /* Test 0. One face and no welding.
6521      *
6522      * 0--1
6523      * | /
6524      * |/
6525      * 2
6526      */
6527     const struct vertex vertices0[] =
6528     {
6529         {{ 0.0f,  3.0f,  0.f}, up},
6530         {{ 2.0f,  3.0f,  0.f}, up},
6531         {{ 0.0f,  0.0f,  0.f}, up},
6532     };
6533     const DWORD indices0[] = {0, 1, 2};
6534     const DWORD attributes0[] = {0};
6535     const DWORD exp_indices0[] = {0, 1, 2};
6536     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
6537     const UINT num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
6538     const DWORD flags0 = D3DXWELDEPSILONS_WELDALL;
6539     /* epsilons0 is NULL */
6540     const DWORD adjacency0[] = {-1, -1, -1};
6541     const struct vertex exp_vertices0[] =
6542     {
6543         {{ 0.0f,  3.0f,  0.f}, up},
6544         {{ 2.0f,  3.0f,  0.f}, up},
6545         {{ 0.0f,  0.0f,  0.f}, up},
6546     };
6547     const DWORD exp_face_remap0[] = {0};
6548     const DWORD exp_vertex_remap0[] = {0, 1, 2};
6549     const DWORD exp_new_num_vertices0 = ARRAY_SIZE(exp_vertices0);
6550     /* Test 1. Two vertices should be removed without regard to epsilon.
6551      *
6552      * 0--1 3
6553      * | / /|
6554      * |/ / |
6555      * 2 5--4
6556      */
6557     const struct vertex_normal vertices1[] =
6558     {
6559         {{ 0.0f,  3.0f,  0.f}, up},
6560         {{ 2.0f,  3.0f,  0.f}, up},
6561         {{ 0.0f,  0.0f,  0.f}, up},
6562
6563         {{ 3.0f,  3.0f,  0.f}, up},
6564         {{ 3.0f,  0.0f,  0.f}, up},
6565         {{ 1.0f,  0.0f,  0.f}, up},
6566     };
6567     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
6568     const DWORD attributes1[] = {0, 0};
6569     const UINT num_vertices1 = ARRAY_SIZE(vertices1);
6570     const UINT num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
6571     const DWORD flags1 = D3DXWELDEPSILONS_WELDALL;
6572     /* epsilons1 is NULL */
6573     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
6574     const struct vertex_normal exp_vertices1[] =
6575     {
6576         {{ 0.0f,  3.0f,  0.f}, up},
6577         {{ 2.0f,  3.0f,  0.f}, up},
6578         {{ 0.0f,  0.0f,  0.f}, up},
6579
6580         {{ 3.0f,  0.0f,  0.f}, up}
6581     };
6582     const DWORD exp_indices1[] = {0, 1, 2, 1, 3, 2};
6583     const DWORD exp_face_remap1[] = {0, 1};
6584     const DWORD exp_vertex_remap1[] = {0, 1, 2, 4, -1, -1};
6585     const DWORD exp_new_num_vertices1 = ARRAY_SIZE(exp_vertices1);
6586     /* Test 2. Two faces. No vertices should be removed because of normal
6587      * epsilon, but the positions should be replaced. */
6588     const struct vertex_normal vertices2[] =
6589     {
6590         {{ 0.0f,  3.0f,  0.f}, up},
6591         {{ 2.0f,  3.0f,  0.f}, up},
6592         {{ 0.0f,  0.0f,  0.f}, up},
6593
6594         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6595         {{ 3.0f,  0.0f,  0.f}, up},
6596         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6597     };
6598     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
6599     const DWORD attributes2[] = {0, 0};
6600     const UINT num_vertices2 = ARRAY_SIZE(vertices2);
6601     const UINT num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
6602     DWORD flags2 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6603     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};
6604     const DWORD adjacency2[] = {-1, 1, -1, -1, -1, 0};
6605     const struct vertex_normal exp_vertices2[] =
6606     {
6607         {{ 0.0f,  3.0f,  0.f}, up},
6608         {{ 2.0f,  3.0f,  0.f}, up},
6609         {{ 0.0f,  0.0f,  0.f}, up},
6610
6611         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6612         {{ 3.0f,  0.0f,  0.f}, up},
6613         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6614     };
6615     const DWORD exp_indices2[] = {0, 1, 2, 3, 4, 5};
6616     const DWORD exp_face_remap2[] = {0, 1};
6617     const DWORD exp_vertex_remap2[] = {0, 1, 2, 3, 4, 5};
6618     const DWORD exp_new_num_vertices2 = ARRAY_SIZE(exp_vertices2);
6619     /* Test 3. Two faces. One vertex should be removed because of normal epsilon. */
6620     const struct vertex_normal vertices3[] =
6621     {
6622         {{ 0.0f,  3.0f,  0.f}, up},
6623         {{ 2.0f,  3.0f,  0.f}, up},
6624         {{ 0.0f,  0.0f,  0.f}, up},
6625
6626         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6627         {{ 3.0f,  0.0f,  0.f}, up},
6628         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6629     };
6630     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
6631     const DWORD attributes3[] = {0, 0};
6632     const UINT num_vertices3 = ARRAY_SIZE(vertices3);
6633     const UINT num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
6634     DWORD flags3 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6635     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};
6636     const DWORD adjacency3[] = {-1, 1, -1, -1, -1, 0};
6637     const struct vertex_normal exp_vertices3[] =
6638     {
6639         {{ 0.0f,  3.0f,  0.f}, up},
6640         {{ 2.0f,  3.0f,  0.f}, up},
6641         {{ 0.0f,  0.0f,  0.f}, up},
6642
6643         {{ 3.0f,  0.0f,  0.f}, up},
6644         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6645     };
6646     const DWORD exp_indices3[] = {0, 1, 2, 1, 3, 4};
6647     const DWORD exp_face_remap3[] = {0, 1};
6648     const DWORD exp_vertex_remap3[] = {0, 1, 2, 4, 5, -1};
6649     const DWORD exp_new_num_vertices3 = ARRAY_SIZE(exp_vertices3);
6650     /* Test 4  Two faces. Two vertices should be removed. */
6651     const struct vertex_normal vertices4[] =
6652     {
6653         {{ 0.0f,  3.0f,  0.f}, up},
6654         {{ 2.0f,  3.0f,  0.f}, up},
6655         {{ 0.0f,  0.0f,  0.f}, up},
6656
6657         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6658         {{ 3.0f,  0.0f,  0.f}, up},
6659         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6660     };
6661     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
6662     const DWORD attributes4[] = {0, 0};
6663     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
6664     const UINT num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
6665     DWORD flags4 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6666     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};
6667     const DWORD adjacency4[] = {-1, 1, -1, -1, -1, 0};
6668     const struct vertex_normal exp_vertices4[] =
6669     {
6670         {{ 0.0f,  3.0f,  0.f}, up},
6671         {{ 2.0f,  3.0f,  0.f}, up},
6672         {{ 0.0f,  0.0f,  0.f}, up},
6673
6674         {{ 3.0f,  0.0f,  0.f}, up},
6675     };
6676     const DWORD exp_indices4[] = {0, 1, 2, 1, 3, 2};
6677     const DWORD exp_face_remap4[] = {0, 1};
6678     const DWORD exp_vertex_remap4[] = {0, 1, 2, 4, -1, -1};
6679     const DWORD exp_new_num_vertices4 = ARRAY_SIZE(exp_vertices4);
6680     /* Test 5. Odd face ordering.
6681      *
6682      * 0--1 6 3
6683      * | / /| |\
6684      * |/ / | | \
6685      * 2 8--7 5--4
6686      */
6687     const struct vertex_normal vertices5[] =
6688     {
6689         {{ 0.0f,  3.0f,  0.f}, up},
6690         {{ 2.0f,  3.0f,  0.f}, up},
6691         {{ 0.0f,  0.0f,  0.f}, up},
6692
6693         {{ 3.0f,  3.0f,  0.f}, up},
6694         {{ 3.0f,  0.0f,  0.f}, up},
6695         {{ 1.0f,  0.0f,  0.f}, up},
6696
6697         {{ 4.0f,  3.0f,  0.f}, up},
6698         {{ 6.0f,  0.0f,  0.f}, up},
6699         {{ 4.0f,  0.0f,  0.f}, up},
6700     };
6701     const DWORD indices5[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
6702     const DWORD exp_indices5[] = {0, 1, 2, 1, 4, 2, 1, 3, 4};
6703     const DWORD attributes5[] = {0, 0, 0};
6704     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
6705     const UINT num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
6706     DWORD flags5 = D3DXWELDEPSILONS_WELDALL;
6707     const DWORD adjacency5[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
6708     const struct vertex_normal exp_vertices5[] =
6709     {
6710         {{ 0.0f,  3.0f,  0.f}, up},
6711         {{ 2.0f,  3.0f,  0.f}, up},
6712         {{ 0.0f,  0.0f,  0.f}, up},
6713
6714         {{ 3.0f,  0.0f,  0.f}, up},
6715         {{ 1.0f,  0.0f,  0.f}, up},
6716     };
6717     const DWORD exp_face_remap5[] = {0, 1, 2};
6718     const DWORD exp_vertex_remap5[] = {0, 1, 2, 4, 5, -1, -1, -1, -1};
6719     const DWORD exp_new_num_vertices5 = ARRAY_SIZE(exp_vertices5);
6720     /* Test 6. Two faces. Do not remove flag is used, so no vertices should be
6721      * removed. */
6722     const struct vertex_normal vertices6[] =
6723     {
6724         {{ 0.0f,  3.0f,  0.f}, up},
6725         {{ 2.0f,  3.0f,  0.f}, up},
6726         {{ 0.0f,  0.0f,  0.f}, up},
6727
6728         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6729         {{ 3.0f,  0.0f,  0.f}, up},
6730         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6731     };
6732     const DWORD indices6[] = {0, 1, 2, 3, 4, 5};
6733     const DWORD attributes6[] = {0, 0};
6734     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
6735     const UINT num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
6736     DWORD flags6 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTREMOVEVERTICES;
6737     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};
6738     const DWORD adjacency6[] = {-1, 1, -1, -1, -1, 0};
6739     const struct vertex_normal exp_vertices6[] =
6740     {
6741         {{ 0.0f,  3.0f,  0.f}, up},
6742         {{ 2.0f,  3.0f,  0.f}, up},
6743         {{ 0.0f,  0.0f,  0.f}, up},
6744
6745         {{ 2.0f,  3.0f,  0.f}, up},
6746         {{ 3.0f,  0.0f,  0.f}, up},
6747         {{ 0.0f,  0.0f,  0.f}, up},
6748
6749     };
6750     const DWORD exp_indices6[] = {0, 1, 2, 3, 4, 5};
6751     const DWORD exp_face_remap6[] = {0, 1};
6752     const DWORD exp_vertex_remap6[] = {0, 1, 2, 3, 4, 5};
6753     const DWORD exp_new_num_vertices6 = ARRAY_SIZE(exp_vertices6);
6754     /* Test 7. Same as test 6 but with 16 bit indices. */
6755     const WORD indices6_16bit[] = {0, 1, 2, 3, 4, 5};
6756     /* Test 8. No flags. Same result as D3DXWELDEPSILONS_WELDPARTIALMATCHES. */
6757     const struct vertex_normal vertices8[] =
6758     {
6759         {{ 0.0f,  3.0f,  0.f}, up},
6760         {{ 2.0f,  3.0f,  0.f}, up},
6761         {{ 0.0f,  0.0f,  0.f}, up},
6762
6763         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6764         {{ 3.0f,  0.0f,  0.f}, up},
6765         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6766     };
6767     const DWORD indices8[] = {0, 1, 2, 1, 3, 4};
6768     const DWORD attributes8[] = {0, 0};
6769     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
6770     const UINT num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
6771     DWORD flags8 = 0;
6772     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};
6773     const DWORD adjacency8[] = {-1, 1, -1, -1, -1, 0};
6774     const struct vertex_normal exp_vertices8[] =
6775     {
6776         {{ 0.0f,  3.0f,  0.f}, up},
6777         {{ 2.0f,  3.0f,  0.f}, up},
6778         {{ 0.0f,  0.0f,  0.f}, up},
6779
6780         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6781         {{ 3.0f,  0.0f,  0.f}, up},
6782     };
6783     const DWORD exp_indices8[] = {0, 1, 2, 1, 3, 4};
6784     const DWORD exp_face_remap8[] = {0, 1};
6785     const DWORD exp_vertex_remap8[] = {0, 1, 2, 3, 4, -1};
6786     const DWORD exp_new_num_vertices8 = ARRAY_SIZE(exp_vertices8);
6787     /* Test 9. Vertices are removed even though they belong to separate
6788      * attribute groups if D3DXWELDEPSILONS_DONOTSPLIT is set. */
6789     const struct vertex_normal vertices9[] =
6790     {
6791         {{ 0.0f,  3.0f,  0.f}, up},
6792         {{ 2.0f,  3.0f,  0.f}, up},
6793         {{ 0.0f,  0.0f,  0.f}, up},
6794
6795         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6796         {{ 3.0f,  0.0f,  0.f}, up},
6797         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6798     };
6799     const DWORD indices9[] = {0, 1, 2, 3, 4, 5};
6800     const DWORD attributes9[] = {0, 1};
6801     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
6802     const UINT num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
6803     DWORD flags9 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTSPLIT;
6804     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};
6805     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
6806     const struct vertex_normal exp_vertices9[] =
6807     {
6808         {{ 0.0f,  3.0f,  0.f}, up},
6809         {{ 2.0f,  3.0f,  0.f}, up},
6810         {{ 0.0f,  0.0f,  0.f}, up},
6811
6812         {{ 3.0f,  0.0f,  0.f}, up},
6813     };
6814     const DWORD exp_indices9[] = {0, 1, 2, 1, 3, 2};
6815     const DWORD exp_face_remap9[] = {0, 1};
6816     const DWORD exp_vertex_remap9[] = {0, 1, 2, 4, -1, -1};
6817     const DWORD exp_new_num_vertices9 = ARRAY_SIZE(exp_vertices9);
6818     /* Test 10. Weld blendweight (FLOAT1). */
6819     const struct vertex_blendweight vertices10[] =
6820     {
6821         {{ 0.0f,  3.0f,  0.f}, 1.0f},
6822         {{ 2.0f,  3.0f,  0.f}, 1.0f},
6823         {{ 0.0f,  0.0f,  0.f}, 1.0f},
6824
6825         {{ 3.0f,  3.0f,  0.f}, 0.9},
6826         {{ 3.0f,  0.0f,  0.f}, 1.0},
6827         {{ 1.0f,  0.0f,  0.f}, 0.4},
6828     };
6829     const DWORD indices10[] = {0, 1, 2, 3, 4, 5};
6830     const DWORD attributes10[] = {0, 0};
6831     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
6832     const UINT num_faces10 = ARRAY_SIZE(indices10) / VERTS_PER_FACE;
6833     DWORD flags10 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6834     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};
6835     const DWORD adjacency10[] = {-1, 1, -1, -1, -1, 0};
6836     const struct vertex_blendweight exp_vertices10[] =
6837     {
6838         {{ 0.0f,  3.0f,  0.f}, 1.0f},
6839         {{ 2.0f,  3.0f,  0.f}, 1.0f},
6840         {{ 0.0f,  0.0f,  0.f}, 1.0f},
6841
6842         {{ 3.0f,  0.0f,  0.f}, 1.0},
6843         {{ 0.0f,  0.0f,  0.f}, 0.4},
6844     };
6845     const DWORD exp_indices10[] = {0, 1, 2, 1, 3, 4};
6846     const DWORD exp_face_remap10[] = {0, 1};
6847     const DWORD exp_vertex_remap10[] = {0, 1, 2, 4, 5, -1};
6848     const DWORD exp_new_num_vertices10 = ARRAY_SIZE(exp_vertices10);
6849     /* Test 11. Weld texture coordinates. */
6850     const struct vertex_texcoord vertices11[] =
6851     {
6852         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
6853         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
6854         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
6855
6856         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
6857         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
6858         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
6859     };
6860     const DWORD indices11[] = {0, 1, 2, 3, 4, 5};
6861     const DWORD attributes11[] = {0, 0};
6862     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
6863     const UINT num_faces11 = ARRAY_SIZE(indices11) / VERTS_PER_FACE;
6864     DWORD flags11 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6865     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};
6866     const DWORD adjacency11[] = {-1, 1, -1, -1, -1, 0};
6867     const struct vertex_texcoord exp_vertices11[] =
6868     {
6869         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
6870         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
6871         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
6872
6873         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
6874         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
6875     };
6876     const DWORD exp_indices11[] = {0, 1, 2, 1, 3, 4};
6877     const DWORD exp_face_remap11[] = {0, 1};
6878     const DWORD exp_vertex_remap11[] = {0, 1, 2, 4, 5, -1};
6879     const DWORD exp_new_num_vertices11 = ARRAY_SIZE(exp_vertices11);
6880     /* Test 12. Weld with color. */
6881     const struct vertex_color vertices12[] =
6882     {
6883         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6884         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6885         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6886
6887         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
6888         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6889         {{ 1.0f,  0.0f,  0.f}, 0x88888888},
6890     };
6891     const DWORD indices12[] = {0, 1, 2, 3, 4, 5};
6892     const DWORD attributes12[] = {0, 0};
6893     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
6894     const UINT num_faces12 = ARRAY_SIZE(indices12) / VERTS_PER_FACE;
6895     DWORD flags12 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6896     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};
6897     const DWORD adjacency12[] = {-1, 1, -1, -1, -1, 0};
6898     const struct vertex_color exp_vertices12[] =
6899     {
6900         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6901         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6902         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6903
6904         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
6905         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6906     };
6907     const DWORD exp_indices12[] = {0, 1, 2, 3, 4, 2};
6908     const DWORD exp_face_remap12[] = {0, 1};
6909     const DWORD exp_vertex_remap12[] = {0, 1, 2, 3, 4, -1};
6910     const DWORD exp_new_num_vertices12 = ARRAY_SIZE(exp_vertices12);
6911     /* Test 13. Two faces. One vertex should be removed because of normal epsilon.
6912      * This is similar to test 3, but the declaration has been changed to NORMAL3.
6913      */
6914     const struct vertex_normal vertices13[] =
6915     {
6916         {{ 0.0f,  3.0f,  0.f}, up},
6917         {{ 2.0f,  3.0f,  0.f}, up},
6918         {{ 0.0f,  0.0f,  0.f}, up},
6919
6920         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6921         {{ 3.0f,  0.0f,  0.f}, up},
6922         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6923     };
6924     const DWORD indices13[] = {0, 1, 2, 3, 4, 5};
6925     const DWORD attributes13[] = {0, 0};
6926     const UINT num_vertices13 = ARRAY_SIZE(vertices3);
6927     const UINT num_faces13 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
6928     DWORD flags13 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6929     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};
6930     const DWORD adjacency13[] = {-1, 1, -1, -1, -1, 0};
6931     const struct vertex_normal exp_vertices13[] =
6932     {
6933         {{ 0.0f,  3.0f,  0.f}, up},
6934         {{ 2.0f,  3.0f,  0.f}, up},
6935         {{ 0.0f,  0.0f,  0.f}, up},
6936
6937         {{ 3.0f,  0.0f,  0.f}, up},
6938         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6939     };
6940     const DWORD exp_indices13[] = {0, 1, 2, 1, 3, 4};
6941     const DWORD exp_face_remap13[] = {0, 1};
6942     const DWORD exp_vertex_remap13[] = {0, 1, 2, 4, 5, -1};
6943     const DWORD exp_new_num_vertices13 = ARRAY_SIZE(exp_vertices13);
6944     /* Test 14. Another test for welding with color. */
6945     const struct vertex_color vertices14[] =
6946     {
6947         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6948         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6949         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6950
6951         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
6952         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6953         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
6954     };
6955     const DWORD indices14[] = {0, 1, 2, 3, 4, 5};
6956     const DWORD attributes14[] = {0, 0};
6957     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
6958     const UINT num_faces14 = ARRAY_SIZE(indices14) / VERTS_PER_FACE;
6959     DWORD flags14 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6960     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};
6961     const DWORD adjacency14[] = {-1, 1, -1, -1, -1, 0};
6962     const struct vertex_color exp_vertices14[] =
6963     {
6964         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6965         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6966         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6967
6968         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
6969         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6970     };
6971     const DWORD exp_indices14[] = {0, 1, 2, 3, 4, 2};
6972     const DWORD exp_face_remap14[] = {0, 1};
6973     const DWORD exp_vertex_remap14[] = {0, 1, 2, 3, 4, -1};
6974     const DWORD exp_new_num_vertices14 = ARRAY_SIZE(exp_vertices14);
6975     /* Test 15. Weld with color, but as UBYTE4N instead of D3DCOLOR. It shows
6976      * that UBYTE4N and D3DCOLOR are compared the same way.
6977      */
6978     const struct vertex_color_ubyte4 vertices15[] =
6979     {
6980         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
6981         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
6982         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
6983
6984         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
6985         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
6986         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
6987     };
6988     const DWORD indices15[] = {0, 1, 2, 3, 4, 5};
6989     const DWORD attributes15[] = {0, 0};
6990     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
6991     const UINT num_faces15 = ARRAY_SIZE(indices15) / VERTS_PER_FACE;
6992     DWORD flags15 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6993     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};
6994     const DWORD adjacency15[] = {-1, 1, -1, -1, -1, 0};
6995     const struct vertex_color_ubyte4 exp_vertices15[] =
6996     {
6997         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
6998         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
6999         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7000
7001         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7002         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7003     };
7004     const DWORD exp_indices15[] = {0, 1, 2, 3, 4, 2};
7005     const DWORD exp_face_remap15[] = {0, 1};
7006     const DWORD exp_vertex_remap15[] = {0, 1, 2, 3, 4, -1};
7007     const DWORD exp_new_num_vertices15 = ARRAY_SIZE(exp_vertices15);
7008     /* Test 16. Weld with color, but as UBYTE4 instead of D3DCOLOR. It shows
7009      * that UBYTE4 is not normalized and that epsilon is truncated and compared
7010      * directly to each of the four bytes.
7011      */
7012     const struct vertex_color_ubyte4 vertices16[] =
7013     {
7014         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7015         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7016         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7017
7018         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7019         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7020         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7021     };
7022     const DWORD indices16[] = {0, 1, 2, 3, 4, 5};
7023     const DWORD attributes16[] = {0, 0};
7024     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
7025     const UINT num_faces16 = ARRAY_SIZE(indices16) / VERTS_PER_FACE;
7026     DWORD flags16 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7027     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};
7028     const DWORD adjacency16[] = {-1, 1, -1, -1, -1, 0};
7029     const struct vertex_color_ubyte4 exp_vertices16[] =
7030     {
7031         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7032         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7033         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7034
7035         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7036         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7037     };
7038     const DWORD exp_indices16[] = {0, 1, 2, 3, 4, 2};
7039     const DWORD exp_face_remap16[] = {0, 1};
7040     const DWORD exp_vertex_remap16[] = {0, 1, 2, 3, 4, -1};
7041     const DWORD exp_new_num_vertices16 = ARRAY_SIZE(exp_vertices16);
7042     /* Test 17. Weld texture coordinates but as SHORT2 instead of D3DXVECTOR2.*/
7043     const struct vertex_texcoord_short2 vertices17[] =
7044     {
7045         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7046         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7047         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7048
7049         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7050         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7051         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7052     };
7053     const DWORD indices17[] = {0, 1, 2, 3, 4, 5};
7054     const DWORD attributes17[] = {0, 0};
7055     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
7056     const UINT num_faces17 = ARRAY_SIZE(indices17) / VERTS_PER_FACE;
7057     DWORD flags17 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7058     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};
7059     const DWORD adjacency17[] = {-1, 1, -1, -1, -1, 0};
7060     const struct vertex_texcoord_short2 exp_vertices17[] =
7061     {
7062         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7063         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7064         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7065
7066         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7067         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7068     };
7069     const DWORD exp_indices17[] = {0, 1, 2, 3, 4, 2};
7070     const DWORD exp_face_remap17[] = {0, 1};
7071     const DWORD exp_vertex_remap17[] = {0, 1, 2, 3, 4, -1};
7072     const DWORD exp_new_num_vertices17 = ARRAY_SIZE(exp_vertices17);
7073     /* Test 18. Weld texture coordinates but as SHORT2N instead of D3DXVECTOR2. */
7074     const struct vertex_texcoord_short2 vertices18[] =
7075     {
7076         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7077         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7078         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7079
7080         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7081         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7082         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7083     };
7084     const DWORD indices18[] = {0, 1, 2, 3, 4, 5};
7085     const DWORD attributes18[] = {0, 0};
7086     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
7087     const UINT num_faces18 = ARRAY_SIZE(indices18) / VERTS_PER_FACE;
7088     DWORD flags18 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7089     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};
7090     const DWORD adjacency18[] = {-1, 1, -1, -1, -1, 0};
7091     const struct vertex_texcoord_short2 exp_vertices18[] =
7092     {
7093         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7094         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7095         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7096
7097         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7098         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7099     };
7100     const DWORD exp_indices18[] = {0, 1, 2, 3, 4, 2};
7101     const DWORD exp_face_remap18[] = {0, 1};
7102     const DWORD exp_vertex_remap18[] = {0, 1, 2, 3, 4, -1};
7103     const DWORD exp_new_num_vertices18 = ARRAY_SIZE(exp_vertices18);
7104     /* Test 19.  Weld texture coordinates but as USHORT2N instead of D3DXVECTOR2. */
7105     const struct vertex_texcoord_ushort2n vertices19[] =
7106     {
7107         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7108         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7109         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7110
7111         {{ 3.0f,  3.0f,  0.f}, {65535, 65535}},
7112         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7113         {{ 1.0f,  0.0f,  0.f}, {65534, 65534}},
7114     };
7115     const DWORD indices19[] = {0, 1, 2, 3, 4, 5};
7116     const DWORD attributes19[] = {0, 0};
7117     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
7118     const UINT num_faces19 = ARRAY_SIZE(indices19) / VERTS_PER_FACE;
7119     DWORD flags19 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7120     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};
7121     const DWORD adjacency19[] = {-1, 1, -1, -1, -1, 0};
7122     const struct vertex_texcoord_ushort2n exp_vertices19[] =
7123     {
7124         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7125         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7126         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7127
7128         {{ 2.0f,  3.0f,  0.f}, {65535, 65535}},
7129         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7130     };
7131     const DWORD exp_indices19[] = {0, 1, 2, 3, 4, 2};
7132     const DWORD exp_face_remap19[] = {0, 1};
7133     const DWORD exp_vertex_remap19[] = {0, 1, 2, 3, 4, -1};
7134     const DWORD exp_new_num_vertices19 = ARRAY_SIZE(exp_vertices19);
7135     /* Test 20.  Weld normal as SHORT4 instead of D3DXVECTOR3. */
7136     const struct vertex_normal_short4 vertices20[] =
7137     {
7138         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7139         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7140         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7141
7142         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7143         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7144         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7145     };
7146     const DWORD indices20[] = {0, 1, 2, 3, 4, 5};
7147     const DWORD attributes20[] = {0, 0};
7148     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
7149     const UINT num_faces20 = ARRAY_SIZE(indices20) / VERTS_PER_FACE;
7150     DWORD flags20 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7151     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};
7152     const DWORD adjacency20[] = {-1, 1, -1, -1, -1, 0};
7153     const struct vertex_normal_short4 exp_vertices20[] =
7154     {
7155         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7156         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7157         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7158
7159         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7160         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7161     };
7162     const DWORD exp_indices20[] = {0, 1, 2, 3, 4, 2};
7163     const DWORD exp_face_remap20[] = {0, 1};
7164     const DWORD exp_vertex_remap20[] = {0, 1, 2, 3, 4, -1};
7165     const DWORD exp_new_num_vertices20 = ARRAY_SIZE(exp_vertices20);
7166     /* Test 21.  Weld normal as SHORT4N instead of D3DXVECTOR3. */
7167     const struct vertex_normal_short4 vertices21[] =
7168     {
7169         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7170         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7171         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7172
7173         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7174         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7175         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7176     };
7177     const DWORD indices21[] = {0, 1, 2, 3, 4, 5};
7178     const DWORD attributes21[] = {0, 0};
7179     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
7180     const UINT num_faces21 = ARRAY_SIZE(indices21) / VERTS_PER_FACE;
7181     DWORD flags21 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7182     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};
7183     const DWORD adjacency21[] = {-1, 1, -1, -1, -1, 0};
7184     const struct vertex_normal_short4 exp_vertices21[] =
7185     {
7186         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7187         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7188         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7189
7190         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7191         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7192     };
7193     const DWORD exp_indices21[] = {0, 1, 2, 3, 4, 2};
7194     const DWORD exp_face_remap21[] = {0, 1};
7195     const DWORD exp_vertex_remap21[] = {0, 1, 2, 3, 4, -1};
7196     const DWORD exp_new_num_vertices21 = ARRAY_SIZE(exp_vertices21);
7197     /* Test 22.  Weld normal as USHORT4N instead of D3DXVECTOR3. */
7198     const struct vertex_normal_short4 vertices22[] =
7199     {
7200         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7201         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7202         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7203
7204         {{ 3.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7205         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7206         {{ 1.0f,  0.0f,  0.f}, {65534, 65534, 65534, 65534}},
7207     };
7208     const DWORD indices22[] = {0, 1, 2, 3, 4, 5};
7209     const DWORD attributes22[] = {0, 0};
7210     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
7211     const UINT num_faces22 = ARRAY_SIZE(indices22) / VERTS_PER_FACE;
7212     DWORD flags22 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7213     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};
7214     const DWORD adjacency22[] = {-1, 1, -1, -1, -1, 0};
7215     const struct vertex_normal_short4 exp_vertices22[] =
7216     {
7217         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7218         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7219         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7220
7221         {{ 2.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7222         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7223     };
7224     const DWORD exp_indices22[] = {0, 1, 2, 3, 4, 2};
7225     const DWORD exp_face_remap22[] = {0, 1};
7226     const DWORD exp_vertex_remap22[] = {0, 1, 2, 3, 4, -1};
7227     const DWORD exp_new_num_vertices22 = ARRAY_SIZE(exp_vertices22);
7228     /* Test 23. Weld texture coordinates as FLOAT16_2. Similar to test 11, but
7229      * with texture coordinates converted to float16 in hex. */
7230     const struct vertex_texcoord_float16_2 vertices23[] =
7231     {
7232         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7233         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7234         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7235
7236         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
7237         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7238         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7239     };
7240     const DWORD indices23[] = {0, 1, 2, 3, 4, 5};
7241     const DWORD attributes23[] = {0, 0};
7242     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
7243     const UINT num_faces23 = ARRAY_SIZE(indices23) / VERTS_PER_FACE;
7244     DWORD flags23 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7245     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};
7246     const DWORD adjacency23[] = {-1, 1, -1, -1, -1, 0};
7247     const struct vertex_texcoord_float16_2 exp_vertices23[] =
7248     {
7249         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7250         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7251         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7252
7253         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7254         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7255     };
7256     const DWORD exp_indices23[] = {0, 1, 2, 1, 3, 4};
7257     const DWORD exp_face_remap23[] = {0, 1};
7258     const DWORD exp_vertex_remap23[] = {0, 1, 2, 4, 5, -1};
7259     const DWORD exp_new_num_vertices23 = ARRAY_SIZE(exp_vertices23);
7260     /* Test 24. Weld texture coordinates as FLOAT16_4. Similar to test 24. */
7261     const struct vertex_texcoord_float16_4 vertices24[] =
7262     {
7263         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7264         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7265         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7266
7267         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0x3266, 0x34cd}},
7268         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7269         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7270     };
7271     const DWORD indices24[] = {0, 1, 2, 3, 4, 5};
7272     const DWORD attributes24[] = {0, 0};
7273     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
7274     const UINT num_faces24 = ARRAY_SIZE(indices24) / VERTS_PER_FACE;
7275     DWORD flags24 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7276     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};
7277     const DWORD adjacency24[] = {-1, 1, -1, -1, -1, 0};
7278     const struct vertex_texcoord_float16_4 exp_vertices24[] =
7279     {
7280         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7281         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7282         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7283
7284         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7285         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7286     };
7287     const DWORD exp_indices24[] = {0, 1, 2, 1, 3, 4};
7288     const DWORD exp_face_remap24[] = {0, 1};
7289     const DWORD exp_vertex_remap24[] = {0, 1, 2, 4, 5, -1};
7290     const DWORD exp_new_num_vertices24 = ARRAY_SIZE(exp_vertices24);
7291     /* Test 25. Weld texture coordinates with usage index 10 (TEXCOORD10). The
7292      * usage index is capped at 7, so the epsilon for TEXCOORD7 is used instead.
7293      */
7294     const struct vertex_texcoord vertices25[] =
7295     {
7296         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7297         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7298         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7299
7300         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7301         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7302         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7303     };
7304     const DWORD indices25[] = {0, 1, 2, 3, 4, 5};
7305     const DWORD attributes25[] = {0, 0};
7306     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
7307     const UINT num_faces25 = ARRAY_SIZE(indices25) / VERTS_PER_FACE;
7308     DWORD flags25 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7309     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};
7310     const DWORD adjacency25[] = {-1, 1, -1, -1, -1, 0};
7311     const struct vertex_texcoord exp_vertices25[] =
7312     {
7313         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7314         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7315         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7316
7317         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7318         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7319     };
7320     const DWORD exp_indices25[] = {0, 1, 2, 1, 3, 4};
7321     const DWORD exp_face_remap25[] = {0, 1};
7322     const DWORD exp_vertex_remap25[] = {0, 1, 2, 4, 5, -1};
7323     const DWORD exp_new_num_vertices25 = ARRAY_SIZE(exp_vertices25);
7324     /* Test 26. Weld color with usage index larger than 1. Shows that none of
7325      * the epsilon values are used. */
7326     const struct vertex_color vertices26[] =
7327     {
7328         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7329         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7330         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7331
7332         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7333         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7334         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7335     };
7336     const DWORD indices26[] = {0, 1, 2, 3, 4, 5};
7337     const DWORD attributes26[] = {0, 0};
7338     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
7339     const UINT num_faces26 = ARRAY_SIZE(indices26) / VERTS_PER_FACE;
7340     DWORD flags26 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7341     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};
7342     const DWORD adjacency26[] = {-1, 1, -1, -1, -1, 0};
7343     const struct vertex_color exp_vertices26[] =
7344     {
7345         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7346         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7347         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7348
7349         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7350         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7351         {{ 0.0f,  0.0f,  0.f}, 0x01010101},
7352     };
7353     const DWORD exp_indices26[] = {0, 1, 2, 3, 4, 5};
7354     const DWORD exp_face_remap26[] = {0, 1};
7355     const DWORD exp_vertex_remap26[] = {0, 1, 2, 3, 4, 5};
7356     const DWORD exp_new_num_vertices26 = ARRAY_SIZE(exp_vertices26);
7357     /* Test 27. Weld color with usage index larger than 1. Check that the
7358      * default epsilon of 1e-6f is used. */
7359     D3DXVECTOR4 zero_float4 = {0.0f, 0.0f, 0.0f, 0.0f};
7360     D3DXVECTOR4 almost_zero_float4 = {0.0f + FLT_EPSILON, 0.0f + FLT_EPSILON, 0.0f + FLT_EPSILON, 0.0f + FLT_EPSILON};
7361     const struct vertex_color_float4 vertices27[] =
7362     {
7363         {{ 0.0f,  3.0f,  0.f}, zero_float4},
7364         {{ 2.0f,  3.0f,  0.f}, zero_float4},
7365         {{ 0.0f,  0.0f,  0.f}, zero_float4},
7366
7367         {{ 3.0f,  3.0f,  0.f}, almost_zero_float4},
7368         {{ 3.0f,  0.0f,  0.f}, zero_float4},
7369         {{ 1.0f,  0.0f,  0.f}, almost_zero_float4},
7370     };
7371     const DWORD indices27[] = {0, 1, 2, 3, 4, 5};
7372     const DWORD attributes27[] = {0, 0};
7373     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
7374     const UINT num_faces27 = ARRAY_SIZE(indices27) / VERTS_PER_FACE;
7375     DWORD flags27 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7376     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};
7377     const DWORD adjacency27[] = {-1, 1, -1, -1, -1, 0};
7378     const struct vertex_color_float4 exp_vertices27[] =
7379     {
7380         {{ 0.0f,  3.0f,  0.f}, zero_float4},
7381         {{ 2.0f,  3.0f,  0.f}, zero_float4},
7382         {{ 0.0f,  0.0f,  0.f}, zero_float4},
7383
7384         {{ 3.0f,  0.0f,  0.f}, zero_float4},
7385     };
7386     const DWORD exp_indices27[] = {0, 1, 2, 1, 3, 2};
7387     const DWORD exp_face_remap27[] = {0, 1};
7388     const DWORD exp_vertex_remap27[] = {0, 1, 2, 4, -1, -1};
7389     const DWORD exp_new_num_vertices27 = ARRAY_SIZE(exp_vertices27);
7390     /* Test 28. Weld one normal with UDEC3. */
7391     const DWORD dword_udec3_zero = init_udec3_dword(0, 0, 0, 1);
7392     const DWORD dword_udec3_1023 = init_udec3_dword(1023, 1023, 1023, 1);
7393     const DWORD dword_udec3_1022 = init_udec3_dword(1022, 1022, 1022, 1);
7394     const struct vertex_normal_udec3 vertices28[] =
7395     {
7396         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7397         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7398         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7399
7400         {{ 3.0f,  3.0f,  0.f}, dword_udec3_1023},
7401         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7402         {{ 1.0f,  0.0f,  0.f}, dword_udec3_1022},
7403     };
7404     const DWORD indices28[] = {0, 1, 2, 3, 4, 5};
7405     const DWORD attributes28[] = {0, 0};
7406     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
7407     const UINT num_faces28 = ARRAY_SIZE(indices28) / VERTS_PER_FACE;
7408     DWORD flags28 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7409     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};
7410     const DWORD adjacency28[] = {-1, 1, -1, -1, -1, 0};
7411     const struct vertex_normal_udec3 exp_vertices28[] =
7412     {
7413         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7414         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7415         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7416
7417         {{ 2.0f,  3.0f,  0.f}, dword_udec3_1023},
7418         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7419     };
7420     const DWORD exp_indices28[] = {0, 1, 2, 3, 4, 2};
7421     const DWORD exp_face_remap28[] = {0, 1};
7422     const DWORD exp_vertex_remap28[] = {0, 1, 2, 3, 4, -1};
7423     const DWORD exp_new_num_vertices28 = ARRAY_SIZE(exp_vertices28);
7424     /* Test 29. Weld one normal with DEC3N. */
7425     const DWORD dword_dec3n_zero = init_dec3n_dword(0, 0, 0, 1);
7426     const DWORD dword_dec3n_511 = init_dec3n_dword(511, 511, 511, 1);
7427     const DWORD dword_dec3n_510 = init_dec3n_dword(510, 510, 510, 1);
7428     const struct vertex_normal_dec3n vertices29[] =
7429     {
7430         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7431         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7432         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7433
7434         {{ 3.0f,  3.0f,  0.f}, dword_dec3n_511},
7435         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7436         {{ 1.0f,  0.0f,  0.f}, dword_dec3n_510},
7437     };
7438     const DWORD indices29[] = {0, 1, 2, 3, 4, 5};
7439     const DWORD attributes29[] = {0, 0};
7440     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
7441     const UINT num_faces29 = ARRAY_SIZE(indices29) / VERTS_PER_FACE;
7442     DWORD flags29 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7443     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};
7444     const DWORD adjacency29[] = {-1, 1, -1, -1, -1, 0};
7445     const struct vertex_normal_dec3n exp_vertices29[] =
7446     {
7447         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7448         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7449         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7450
7451         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_511},
7452         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7453     };
7454     const DWORD exp_indices29[] = {0, 1, 2, 3, 4, 2};
7455     const DWORD exp_face_remap29[] = {0, 1};
7456     const DWORD exp_vertex_remap29[] = {0, 1, 2, 3, 4, -1};
7457     const DWORD exp_new_num_vertices29 = ARRAY_SIZE(exp_vertices29);
7458     /* All mesh data */
7459     DWORD *adjacency_out = NULL;
7460     DWORD *face_remap = NULL;
7461     ID3DXMesh *mesh = NULL;
7462     ID3DXBuffer *vertex_remap = NULL;
7463     struct
7464     {
7465         const BYTE *vertices;
7466         const DWORD *indices;
7467         const DWORD *attributes;
7468         const DWORD num_vertices;
7469         const DWORD num_faces;
7470         const DWORD options;
7471         D3DVERTEXELEMENT9 *declaration;
7472         const UINT vertex_size;
7473         const DWORD flags;
7474         const D3DXWELDEPSILONS *epsilons;
7475         const DWORD *adjacency;
7476         const BYTE *exp_vertices;
7477         const DWORD *exp_indices;
7478         const DWORD *exp_face_remap;
7479         const DWORD *exp_vertex_remap;
7480         const DWORD exp_new_num_vertices;
7481     }
7482     tc[] =
7483     {
7484         {
7485             (BYTE*)vertices0,
7486             indices0,
7487             attributes0,
7488             num_vertices0,
7489             num_faces0,
7490             options,
7491             declaration_normal,
7492             vertex_size_normal,
7493             flags0,
7494             NULL,
7495             adjacency0,
7496             (BYTE*)exp_vertices0,
7497             exp_indices0,
7498             exp_face_remap0,
7499             exp_vertex_remap0,
7500             exp_new_num_vertices0
7501         },
7502         {
7503             (BYTE*)vertices1,
7504             indices1,
7505             attributes1,
7506             num_vertices1,
7507             num_faces1,
7508             options,
7509             declaration_normal,
7510             vertex_size_normal,
7511             flags1,
7512             NULL,
7513             adjacency1,
7514             (BYTE*)exp_vertices1,
7515             exp_indices1,
7516             exp_face_remap1,
7517             exp_vertex_remap1,
7518             exp_new_num_vertices1
7519         },
7520         {
7521             (BYTE*)vertices2,
7522             indices2,
7523             attributes2,
7524             num_vertices2,
7525             num_faces2,
7526             options,
7527             declaration_normal,
7528             vertex_size_normal,
7529             flags2,
7530             &epsilons2,
7531             adjacency2,
7532             (BYTE*)exp_vertices2,
7533             exp_indices2,
7534             exp_face_remap2,
7535             exp_vertex_remap2,
7536             exp_new_num_vertices2
7537         },
7538         {
7539             (BYTE*)vertices3,
7540             indices3,
7541             attributes3,
7542             num_vertices3,
7543             num_faces3,
7544             options,
7545             declaration_normal,
7546             vertex_size_normal,
7547             flags3,
7548             &epsilons3,
7549             adjacency3,
7550             (BYTE*)exp_vertices3,
7551             exp_indices3,
7552             exp_face_remap3,
7553             exp_vertex_remap3,
7554             exp_new_num_vertices3
7555         },
7556         {
7557             (BYTE*)vertices4,
7558             indices4,
7559             attributes4,
7560             num_vertices4,
7561             num_faces4,
7562             options,
7563             declaration_normal,
7564             vertex_size_normal,
7565             flags4,
7566             &epsilons4,
7567             adjacency4,
7568             (BYTE*)exp_vertices4,
7569             exp_indices4,
7570             exp_face_remap4,
7571             exp_vertex_remap4,
7572             exp_new_num_vertices4
7573         },
7574         /* Unusual ordering. */
7575         {
7576             (BYTE*)vertices5,
7577             indices5,
7578             attributes5,
7579             num_vertices5,
7580             num_faces5,
7581             options,
7582             declaration_normal,
7583             vertex_size_normal,
7584             flags5,
7585             NULL,
7586             adjacency5,
7587             (BYTE*)exp_vertices5,
7588             exp_indices5,
7589             exp_face_remap5,
7590             exp_vertex_remap5,
7591             exp_new_num_vertices5
7592         },
7593         {
7594             (BYTE*)vertices6,
7595             indices6,
7596             attributes6,
7597             num_vertices6,
7598             num_faces6,
7599             options,
7600             declaration_normal,
7601             vertex_size_normal,
7602             flags6,
7603             &epsilons6,
7604             adjacency6,
7605             (BYTE*)exp_vertices6,
7606             exp_indices6,
7607             exp_face_remap6,
7608             exp_vertex_remap6,
7609             exp_new_num_vertices6
7610         },
7611         {
7612             (BYTE*)vertices6,
7613             (DWORD*)indices6_16bit,
7614             attributes6,
7615             num_vertices6,
7616             num_faces6,
7617             options_16bit,
7618             declaration_normal,
7619             vertex_size_normal,
7620             flags6,
7621             &epsilons6,
7622             adjacency6,
7623             (BYTE*)exp_vertices6,
7624             exp_indices6,
7625             exp_face_remap6,
7626             exp_vertex_remap6,
7627             exp_new_num_vertices6
7628         },
7629         {
7630             (BYTE*)vertices8,
7631             indices8,
7632             attributes8,
7633             num_vertices8,
7634             num_faces8,
7635             options,
7636             declaration_normal,
7637             vertex_size_normal,
7638             flags8,
7639             &epsilons8,
7640             adjacency8,
7641             (BYTE*)exp_vertices8,
7642             exp_indices8,
7643             exp_face_remap8,
7644             exp_vertex_remap8,
7645             exp_new_num_vertices8
7646         },
7647         {
7648             (BYTE*)vertices9,
7649             indices9,
7650             attributes9,
7651             num_vertices9,
7652             num_faces9,
7653             options,
7654             declaration_normal,
7655             vertex_size_normal,
7656             flags9,
7657             &epsilons9,
7658             adjacency9,
7659             (BYTE*)exp_vertices9,
7660             exp_indices9,
7661             exp_face_remap9,
7662             exp_vertex_remap9,
7663             exp_new_num_vertices9
7664         },
7665         {
7666             (BYTE*)vertices10,
7667             indices10,
7668             attributes10,
7669             num_vertices10,
7670             num_faces10,
7671             options,
7672             declaration_blendweight,
7673             vertex_size_blendweight,
7674             flags10,
7675             &epsilons10,
7676             adjacency10,
7677             (BYTE*)exp_vertices10,
7678             exp_indices10,
7679             exp_face_remap10,
7680             exp_vertex_remap10,
7681             exp_new_num_vertices10
7682         },
7683         {
7684             (BYTE*)vertices11,
7685             indices11,
7686             attributes11,
7687             num_vertices11,
7688             num_faces11,
7689             options,
7690             declaration_texcoord,
7691             vertex_size_texcoord,
7692             flags11,
7693             &epsilons11,
7694             adjacency11,
7695             (BYTE*)exp_vertices11,
7696             exp_indices11,
7697             exp_face_remap11,
7698             exp_vertex_remap11,
7699             exp_new_num_vertices11
7700         },
7701         {
7702             (BYTE*)vertices12,
7703             indices12,
7704             attributes12,
7705             num_vertices12,
7706             num_faces12,
7707             options,
7708             declaration_color,
7709             vertex_size_color,
7710             flags12,
7711             &epsilons12,
7712             adjacency12,
7713             (BYTE*)exp_vertices12,
7714             exp_indices12,
7715             exp_face_remap12,
7716             exp_vertex_remap12,
7717             exp_new_num_vertices12
7718         },
7719         {
7720             (BYTE*)vertices13,
7721             indices13,
7722             attributes13,
7723             num_vertices13,
7724             num_faces13,
7725             options,
7726             declaration_normal3,
7727             vertex_size_normal,
7728             flags13,
7729             &epsilons13,
7730             adjacency13,
7731             (BYTE*)exp_vertices13,
7732             exp_indices13,
7733             exp_face_remap13,
7734             exp_vertex_remap13,
7735             exp_new_num_vertices13
7736         },
7737         {
7738             (BYTE*)vertices14,
7739             indices14,
7740             attributes14,
7741             num_vertices14,
7742             num_faces14,
7743             options,
7744             declaration_color,
7745             vertex_size_color,
7746             flags14,
7747             &epsilons14,
7748             adjacency14,
7749             (BYTE*)exp_vertices14,
7750             exp_indices14,
7751             exp_face_remap14,
7752             exp_vertex_remap14,
7753             exp_new_num_vertices14
7754         },
7755         {
7756             (BYTE*)vertices15,
7757             indices15,
7758             attributes15,
7759             num_vertices15,
7760             num_faces15,
7761             options,
7762             declaration_color_ubyte4n,
7763             vertex_size_color_ubyte4, /* UBYTE4 same size as UBYTE4N */
7764             flags15,
7765             &epsilons15,
7766             adjacency15,
7767             (BYTE*)exp_vertices15,
7768             exp_indices15,
7769             exp_face_remap15,
7770             exp_vertex_remap15,
7771             exp_new_num_vertices15
7772         },
7773         {
7774             (BYTE*)vertices16,
7775             indices16,
7776             attributes16,
7777             num_vertices16,
7778             num_faces16,
7779             options,
7780             declaration_color_ubyte4,
7781             vertex_size_color_ubyte4,
7782             flags16,
7783             &epsilons16,
7784             adjacency16,
7785             (BYTE*)exp_vertices16,
7786             exp_indices16,
7787             exp_face_remap16,
7788             exp_vertex_remap16,
7789             exp_new_num_vertices16
7790         },
7791         {
7792             (BYTE*)vertices17,
7793             indices17,
7794             attributes17,
7795             num_vertices17,
7796             num_faces17,
7797             options,
7798             declaration_texcoord_short2,
7799             vertex_size_texcoord_short2,
7800             flags17,
7801             &epsilons17,
7802             adjacency17,
7803             (BYTE*)exp_vertices17,
7804             exp_indices17,
7805             exp_face_remap17,
7806             exp_vertex_remap17,
7807             exp_new_num_vertices17
7808         },
7809         {
7810             (BYTE*)vertices18,
7811             indices18,
7812             attributes18,
7813             num_vertices18,
7814             num_faces18,
7815             options,
7816             declaration_texcoord_short2n,
7817             vertex_size_texcoord_short2, /* SHORT2 same size as SHORT2N */
7818             flags18,
7819             &epsilons18,
7820             adjacency18,
7821             (BYTE*)exp_vertices18,
7822             exp_indices18,
7823             exp_face_remap18,
7824             exp_vertex_remap18,
7825             exp_new_num_vertices18
7826         },
7827         {
7828             (BYTE*)vertices19,
7829             indices19,
7830             attributes19,
7831             num_vertices19,
7832             num_faces19,
7833             options,
7834             declaration_texcoord_ushort2n,
7835             vertex_size_texcoord_short2, /* SHORT2 same size as USHORT2N */
7836             flags19,
7837             &epsilons19,
7838             adjacency19,
7839             (BYTE*)exp_vertices19,
7840             exp_indices19,
7841             exp_face_remap19,
7842             exp_vertex_remap19,
7843             exp_new_num_vertices19
7844         },
7845         {
7846             (BYTE*)vertices20,
7847             indices20,
7848             attributes20,
7849             num_vertices20,
7850             num_faces20,
7851             options,
7852             declaration_normal_short4,
7853             vertex_size_normal_short4,
7854             flags20,
7855             &epsilons20,
7856             adjacency20,
7857             (BYTE*)exp_vertices20,
7858             exp_indices20,
7859             exp_face_remap20,
7860             exp_vertex_remap20,
7861             exp_new_num_vertices20
7862         },
7863         {
7864             (BYTE*)vertices21,
7865             indices21,
7866             attributes21,
7867             num_vertices21,
7868             num_faces21,
7869             options,
7870             declaration_normal_short4n,
7871             vertex_size_normal_short4, /* SHORT4 same size as SHORT4N */
7872             flags21,
7873             &epsilons21,
7874             adjacency21,
7875             (BYTE*)exp_vertices21,
7876             exp_indices21,
7877             exp_face_remap21,
7878             exp_vertex_remap21,
7879             exp_new_num_vertices21
7880         },
7881         {
7882             (BYTE*)vertices22,
7883             indices22,
7884             attributes22,
7885             num_vertices22,
7886             num_faces22,
7887             options,
7888             declaration_normal_ushort4n,
7889             vertex_size_normal_short4, /* SHORT4 same size as USHORT4N */
7890             flags22,
7891             &epsilons22,
7892             adjacency22,
7893             (BYTE*)exp_vertices22,
7894             exp_indices22,
7895             exp_face_remap22,
7896             exp_vertex_remap22,
7897             exp_new_num_vertices22
7898         },
7899         {
7900             (BYTE*)vertices23,
7901             indices23,
7902             attributes23,
7903             num_vertices23,
7904             num_faces23,
7905             options,
7906             declaration_texcoord_float16_2,
7907             vertex_size_texcoord_float16_2,
7908             flags23,
7909             &epsilons23,
7910             adjacency23,
7911             (BYTE*)exp_vertices23,
7912             exp_indices23,
7913             exp_face_remap23,
7914             exp_vertex_remap23,
7915             exp_new_num_vertices23
7916         },
7917         {
7918             (BYTE*)vertices24,
7919             indices24,
7920             attributes24,
7921             num_vertices24,
7922             num_faces24,
7923             options,
7924             declaration_texcoord_float16_4,
7925             vertex_size_texcoord_float16_4,
7926             flags24,
7927             &epsilons24,
7928             adjacency24,
7929             (BYTE*)exp_vertices24,
7930             exp_indices24,
7931             exp_face_remap24,
7932             exp_vertex_remap24,
7933             exp_new_num_vertices24
7934         },
7935         {
7936             (BYTE*)vertices25,
7937             indices25,
7938             attributes25,
7939             num_vertices25,
7940             num_faces25,
7941             options,
7942             declaration_texcoord10,
7943             vertex_size_texcoord,
7944             flags25,
7945             &epsilons25,
7946             adjacency25,
7947             (BYTE*)exp_vertices25,
7948             exp_indices25,
7949             exp_face_remap25,
7950             exp_vertex_remap25,
7951             exp_new_num_vertices25
7952         },
7953         {
7954             (BYTE*)vertices26,
7955             indices26,
7956             attributes26,
7957             num_vertices26,
7958             num_faces26,
7959             options,
7960             declaration_color2,
7961             vertex_size_color,
7962             flags26,
7963             &epsilons26,
7964             adjacency26,
7965             (BYTE*)exp_vertices26,
7966             exp_indices26,
7967             exp_face_remap26,
7968             exp_vertex_remap26,
7969             exp_new_num_vertices26
7970         },
7971         {
7972             (BYTE*)vertices27,
7973             indices27,
7974             attributes27,
7975             num_vertices27,
7976             num_faces27,
7977             options,
7978             declaration_color2_float4,
7979             vertex_size_color_float4,
7980             flags27,
7981             &epsilons27,
7982             adjacency27,
7983             (BYTE*)exp_vertices27,
7984             exp_indices27,
7985             exp_face_remap27,
7986             exp_vertex_remap27,
7987             exp_new_num_vertices27
7988         },
7989         {
7990             (BYTE*)vertices28,
7991             indices28,
7992             attributes28,
7993             num_vertices28,
7994             num_faces28,
7995             options,
7996             declaration_normal_udec3,
7997             vertex_size_normal_udec3,
7998             flags28,
7999             &epsilons28,
8000             adjacency28,
8001             (BYTE*)exp_vertices28,
8002             exp_indices28,
8003             exp_face_remap28,
8004             exp_vertex_remap28,
8005             exp_new_num_vertices28
8006         },
8007         {
8008             (BYTE*)vertices29,
8009             indices29,
8010             attributes29,
8011             num_vertices29,
8012             num_faces29,
8013             options,
8014             declaration_normal_dec3n,
8015             vertex_size_normal_dec3n,
8016             flags29,
8017             &epsilons29,
8018             adjacency29,
8019             (BYTE*)exp_vertices29,
8020             exp_indices29,
8021             exp_face_remap29,
8022             exp_vertex_remap29,
8023             exp_new_num_vertices29
8024         }
8025     };
8026
8027     test_context = new_test_context();
8028     if (!test_context)
8029     {
8030         skip("Couldn't create test context\n");
8031         goto cleanup;
8032     }
8033
8034     for (i = 0; i < ARRAY_SIZE(tc); i++)
8035     {
8036         DWORD j;
8037         DWORD *vertex_remap_ptr;
8038         DWORD new_num_vertices;
8039
8040         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
8041                             tc[i].declaration, test_context->device, &mesh,
8042                             tc[i].vertices, tc[i].vertex_size,
8043                             tc[i].indices, tc[i].attributes);
8044         if (FAILED(hr))
8045         {
8046             skip("Couldn't initialize test mesh %d.\n", i);
8047             goto cleanup;
8048         }
8049
8050         /* Allocate out parameters */
8051         adjacency_out = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency_out));
8052         if (!adjacency_out)
8053         {
8054             skip("Couldn't allocate adjacency_out array.\n");
8055             goto cleanup;
8056         }
8057         face_remap = HeapAlloc(GetProcessHeap(), 0, tc[i].num_faces * sizeof(*face_remap));
8058         if (!adjacency_out)
8059         {
8060             skip("Couldn't allocate face_remap array.\n");
8061             goto cleanup;
8062         }
8063
8064         hr = D3DXWeldVertices(mesh, tc[i].flags, tc[i].epsilons, tc[i].adjacency,
8065                               adjacency_out, face_remap, &vertex_remap);
8066         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
8067         /* Check number of vertices*/
8068         new_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
8069         ok(new_num_vertices == tc[i].exp_new_num_vertices,
8070            "Mesh %d: new_num_vertices == %d, expected %d.\n",
8071            i, new_num_vertices, tc[i].exp_new_num_vertices);
8072         /* Check index buffer */
8073         if (tc[i].options & D3DXMESH_32BIT)
8074         {
8075             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices);
8076             if (FAILED(hr))
8077             {
8078                 skip("Couldn't lock index buffer.\n");
8079                 goto cleanup;
8080             }
8081             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8082             {
8083                 ok(indices[j] == tc[i].exp_indices[j],
8084                    "Mesh %d: indices[%d] == %d, expected %d\n",
8085                    i, j, indices[j], tc[i].exp_indices[j]);
8086             }
8087         }
8088         else
8089         {
8090             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices_16bit);
8091             if (FAILED(hr))
8092             {
8093                 skip("Couldn't lock index buffer.\n");
8094                 goto cleanup;
8095             }
8096             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8097             {
8098                 ok(indices_16bit[j] == tc[i].exp_indices[j],
8099                    "Mesh %d: indices_16bit[%d] == %d, expected %d\n",
8100                    i, j, indices_16bit[j], tc[i].exp_indices[j]);
8101             }
8102         }
8103         mesh->lpVtbl->UnlockIndexBuffer(mesh);
8104         indices = NULL;
8105         indices_16bit = NULL;
8106         /* Check adjacency_out */
8107         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8108         {
8109             ok(adjacency_out[j] == tc[i].adjacency[j],
8110                "Mesh %d: adjacency_out[%d] == %d, expected %d\n",
8111                i, j, adjacency_out[j], tc[i].adjacency[j]);
8112         }
8113         /* Check face_remap */
8114         for (j = 0; j < tc[i].num_faces; j++)
8115         {
8116             ok(face_remap[j] == tc[i].exp_face_remap[j],
8117                "Mesh %d: face_remap[%d] == %d, expected %d\n",
8118                i, j, face_remap[j], tc[i].exp_face_remap[j]);
8119         }
8120         /* Check vertex_remap */
8121         vertex_remap_ptr = vertex_remap->lpVtbl->GetBufferPointer(vertex_remap);
8122         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8123         {
8124             ok(vertex_remap_ptr[j] == tc[i].exp_vertex_remap[j],
8125                "Mesh %d: vertex_remap_ptr[%d] == %d, expected %d\n",
8126                i, j, vertex_remap_ptr[j], tc[i].exp_vertex_remap[j]);
8127         }
8128         /* Check vertex buffer */
8129         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void*)&vertices);
8130         if (FAILED(hr))
8131         {
8132             skip("Couldn't lock vertex buffer.\n");
8133             goto cleanup;
8134         }
8135         /* Check contents of re-ordered vertex buffer */
8136         for (j = 0; j < tc[i].exp_new_num_vertices; j++)
8137         {
8138             int index = tc[i].vertex_size*j;
8139             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].declaration);
8140         }
8141         mesh->lpVtbl->UnlockVertexBuffer(mesh);
8142         vertices = NULL;
8143
8144         /* Free mesh and output data */
8145         HeapFree(GetProcessHeap(), 0, adjacency_out);
8146         adjacency_out = NULL;
8147         HeapFree(GetProcessHeap(), 0, face_remap);
8148         face_remap = NULL;
8149         vertex_remap->lpVtbl->Release(vertex_remap);
8150         vertex_remap = NULL;
8151         mesh->lpVtbl->Release(mesh);
8152         mesh = NULL;
8153     }
8154
8155 cleanup:
8156     HeapFree(GetProcessHeap(), 0, adjacency_out);
8157     HeapFree(GetProcessHeap(), 0, face_remap);
8158     if (indices) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8159     if (indices_16bit) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8160     if (mesh) mesh->lpVtbl->Release(mesh);
8161     if (vertex_remap) vertex_remap->lpVtbl->Release(vertex_remap);
8162     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
8163     free_test_context(test_context);
8164 }
8165
8166 static void test_clone_mesh(void)
8167 {
8168     HRESULT hr;
8169     struct test_context *test_context = NULL;
8170     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
8171     D3DVERTEXELEMENT9 declaration_pn[] =
8172     {
8173         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8174         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8175         D3DDECL_END()
8176     };
8177     D3DVERTEXELEMENT9 declaration_pntc[] =
8178     {
8179         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8180         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8181         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8182         D3DDECL_END()
8183     };
8184     D3DVERTEXELEMENT9 declaration_ptcn[] =
8185     {
8186         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8187         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8188         {0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8189         D3DDECL_END()
8190     };
8191     D3DVERTEXELEMENT9 declaration_ptc[] =
8192     {
8193         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8194         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8195         D3DDECL_END()
8196     };
8197     D3DVERTEXELEMENT9 declaration_ptc_float16_2[] =
8198     {
8199         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8200         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8201         D3DDECL_END()
8202     };
8203     D3DVERTEXELEMENT9 declaration_ptc_float16_4[] =
8204     {
8205         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8206         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8207         D3DDECL_END()
8208     };
8209     D3DVERTEXELEMENT9 declaration_ptc_float1[] =
8210     {
8211         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8212         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8213         D3DDECL_END()
8214     };
8215     D3DVERTEXELEMENT9 declaration_ptc_float3[] =
8216     {
8217         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8218         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8219         D3DDECL_END()
8220     };
8221     D3DVERTEXELEMENT9 declaration_ptc_float4[] =
8222     {
8223         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8224         {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8225         D3DDECL_END()
8226     };
8227     D3DVERTEXELEMENT9 declaration_ptc_d3dcolor[] =
8228     {
8229         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8230         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8231         D3DDECL_END()
8232     };
8233     D3DVERTEXELEMENT9 declaration_ptc_ubyte4[] =
8234     {
8235         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8236         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8237         D3DDECL_END()
8238     };
8239     D3DVERTEXELEMENT9 declaration_ptc_ubyte4n[] =
8240     {
8241         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8242         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8243         D3DDECL_END()
8244     };
8245     D3DVERTEXELEMENT9 declaration_ptc_short2[] =
8246     {
8247         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8248         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8249         D3DDECL_END()
8250     };
8251     D3DVERTEXELEMENT9 declaration_ptc_short4[] =
8252     {
8253         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8254         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8255         D3DDECL_END()
8256     };
8257     D3DVERTEXELEMENT9 declaration_ptc_short2n[] =
8258     {
8259         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8260         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8261         D3DDECL_END()
8262     };
8263     D3DVERTEXELEMENT9 declaration_ptc_short4n[] =
8264     {
8265         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8266         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8267         D3DDECL_END()
8268     };
8269     D3DVERTEXELEMENT9 declaration_ptc_ushort2n[] =
8270     {
8271         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8272         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8273         D3DDECL_END()
8274     };
8275     D3DVERTEXELEMENT9 declaration_ptc_ushort4n[] =
8276     {
8277         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8278         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8279         D3DDECL_END()
8280     };
8281     D3DVERTEXELEMENT9 declaration_ptc_float16_2_partialu[] =
8282     {
8283         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8284         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_PARTIALU, D3DDECLUSAGE_TEXCOORD, 0},
8285         D3DDECL_END()
8286     };
8287     D3DVERTEXELEMENT9 declaration_pntc1[] =
8288     {
8289         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8290         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8291         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
8292         D3DDECL_END()
8293     };
8294     const unsigned int VERTS_PER_FACE = 3;
8295     BYTE *vertices = NULL;
8296     INT i;
8297     struct vertex_pn
8298     {
8299         D3DXVECTOR3 position;
8300         D3DXVECTOR3 normal;
8301     };
8302     struct vertex_pntc
8303     {
8304         D3DXVECTOR3 position;
8305         D3DXVECTOR3 normal;
8306         D3DXVECTOR2 texcoords;
8307     };
8308     struct vertex_ptcn
8309     {
8310         D3DXVECTOR3 position;
8311         D3DXVECTOR2 texcoords;
8312         D3DXVECTOR3 normal;
8313     };
8314     struct vertex_ptc
8315     {
8316         D3DXVECTOR3 position;
8317         D3DXVECTOR2 texcoords;
8318     };
8319     struct vertex_ptc_float16_2
8320     {
8321         D3DXVECTOR3 position;
8322         WORD texcoords[2]; /* float16_2 */
8323     };
8324     struct vertex_ptc_float16_4
8325     {
8326         D3DXVECTOR3 position;
8327         WORD texcoords[4]; /* float16_4 */
8328     };
8329     struct vertex_ptc_float1
8330     {
8331         D3DXVECTOR3 position;
8332         FLOAT texcoords;
8333     };
8334     struct vertex_ptc_float3
8335     {
8336         D3DXVECTOR3 position;
8337         FLOAT texcoords[3];
8338     };
8339     struct vertex_ptc_float4
8340     {
8341         D3DXVECTOR3 position;
8342         FLOAT texcoords[4];
8343     };
8344     struct vertex_ptc_d3dcolor
8345     {
8346         D3DXVECTOR3 position;
8347         BYTE texcoords[4];
8348     };
8349     struct vertex_ptc_ubyte4
8350     {
8351         D3DXVECTOR3 position;
8352         BYTE texcoords[4];
8353     };
8354     struct vertex_ptc_ubyte4n
8355     {
8356         D3DXVECTOR3 position;
8357         BYTE texcoords[4];
8358     };
8359     struct vertex_ptc_short2
8360     {
8361         D3DXVECTOR3 position;
8362         SHORT texcoords[2];
8363     };
8364     struct vertex_ptc_short4
8365     {
8366         D3DXVECTOR3 position;
8367         SHORT texcoords[4];
8368     };
8369     struct vertex_ptc_ushort2n
8370     {
8371         D3DXVECTOR3 position;
8372         USHORT texcoords[2];
8373     };
8374     struct vertex_ptc_ushort4n
8375     {
8376         D3DXVECTOR3 position;
8377         USHORT texcoords[4];
8378     };
8379     struct vertex_ptc_udec3
8380     {
8381         D3DXVECTOR3 position;
8382         DWORD texcoords;
8383     };
8384     struct vertex_ptc_dec3n
8385     {
8386         D3DXVECTOR3 position;
8387         DWORD texcoords;
8388     };
8389     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
8390     D3DXVECTOR2 zero_vec2 = {0.0f, 0.0f};
8391     /* Test 0. Check that a mesh can be cloned if the new declaration is the
8392      * same as the one used to create the mesh.
8393      *
8394      * 0--1 3
8395      * | / /|
8396      * |/ / |
8397      * 2 5--4
8398      */
8399     const struct vertex_pn vertices0[] =
8400     {
8401         {{ 0.0f,  3.0f,  0.f}, up},
8402         {{ 2.0f,  3.0f,  0.f}, up},
8403         {{ 0.0f,  0.0f,  0.f}, up},
8404
8405         {{ 3.0f,  3.0f,  0.f}, up},
8406         {{ 3.0f,  0.0f,  0.f}, up},
8407         {{ 1.0f,  0.0f,  0.f}, up},
8408     };
8409     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
8410     const UINT num_faces0 = ARRAY_SIZE(vertices0) / VERTS_PER_FACE;
8411     const UINT vertex_size0 = sizeof(*vertices0);
8412     /* Test 1. Check that 16-bit indices are handled. */
8413     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
8414     /* Test 2. Check that the size of each vertex is increased and the data
8415      * moved if the new declaration adds an element after the original elements.
8416      */
8417     const struct vertex_pntc exp_vertices2[] =
8418     {
8419         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8420         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8421         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8422
8423         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8424         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8425         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8426     };
8427     const UINT exp_vertex_size2 = sizeof(*exp_vertices2);
8428     /* Test 3. Check that the size of each vertex is increased and the data
8429      * moved if the new declaration adds an element between the original
8430      * elements.
8431      */
8432     const struct vertex_ptcn exp_vertices3[] =
8433     {
8434         {{ 0.0f,  3.0f,  0.f}, zero_vec2, up},
8435         {{ 2.0f,  3.0f,  0.f}, zero_vec2, up},
8436         {{ 0.0f,  0.0f,  0.f}, zero_vec2, up},
8437
8438         {{ 3.0f,  3.0f,  0.f}, zero_vec2, up},
8439         {{ 3.0f,  0.0f,  0.f}, zero_vec2, up},
8440         {{ 1.0f,  0.0f,  0.f}, zero_vec2, up},
8441     };
8442     const UINT exp_vertex_size3 = sizeof(*exp_vertices3);
8443     /* Test 4. Test that data types can be converted, e.g. FLOAT2 to FLOAT16_2. */
8444     const struct vertex_ptc vertices4[] =
8445     {
8446         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8447         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8448         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8449
8450         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8451         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8452         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8453     };
8454     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
8455     const UINT num_faces4 = ARRAY_SIZE(vertices4) / VERTS_PER_FACE;
8456     const UINT vertex_size4 = sizeof(*vertices4);
8457     const struct vertex_ptc_float16_2 exp_vertices4[] =
8458     {
8459         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8460         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
8461         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
8462
8463         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
8464         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8465         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
8466     };
8467     const UINT exp_vertex_size4 = sizeof(*exp_vertices4);
8468     /* Test 5. Convert FLOAT2 to FLOAT16_4. */
8469     const struct vertex_ptc vertices5[] =
8470     {
8471         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8472         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8473         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8474
8475         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8476         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8477         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8478     };
8479     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
8480     const UINT num_faces5 = ARRAY_SIZE(vertices5) / VERTS_PER_FACE;
8481     const UINT vertex_size5 = sizeof(*vertices5);
8482     const struct vertex_ptc_float16_4 exp_vertices5[] =
8483     {
8484         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8485         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0, 0x3c00}}, /* {0.5f, 0.7f, 0.0f, 1.0f} */
8486         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0, 0x3c00}}, /* {-0.2f, -0.3f, 0.0f, 1.0f} */
8487
8488         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0, 0x3c00}}, /* {0.2f, 0.3f, 0.0f, 1.0f} */
8489         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8490         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0, 0x3c00}}, /* {0.1f, 0.2f, 0.0f, 1.0f} */
8491     };
8492     const UINT exp_vertex_size5 = sizeof(*exp_vertices5);
8493     /* Test 6. Convert FLOAT2 to FLOAT1. */
8494     const struct vertex_ptc vertices6[] =
8495     {
8496         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8497         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8498         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8499
8500         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8501         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8502         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8503     };
8504     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
8505     const UINT num_faces6 = ARRAY_SIZE(vertices6) / VERTS_PER_FACE;
8506     const UINT vertex_size6 = sizeof(*vertices6);
8507     const struct vertex_ptc_float1 exp_vertices6[] =
8508     {
8509         {{ 0.0f,  3.0f,  0.f},  1.0f},
8510         {{ 2.0f,  3.0f,  0.f},  0.5f},
8511         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8512
8513         {{ 3.0f,  3.0f,  0.f},  0.2f},
8514         {{ 3.0f,  0.0f,  0.f},  1.0f},
8515         {{ 1.0f,  0.0f,  0.f},  0.1f},
8516     };
8517     const UINT exp_vertex_size6 = sizeof(*exp_vertices6);
8518     /* Test 7. Convert FLOAT2 to FLOAT3. */
8519     const struct vertex_ptc vertices7[] =
8520     {
8521         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8522         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8523         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8524
8525         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8526         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8527         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8528     };
8529     const UINT num_vertices7 = ARRAY_SIZE(vertices7);
8530     const UINT num_faces7 = ARRAY_SIZE(vertices7) / VERTS_PER_FACE;
8531     const UINT vertex_size7 = sizeof(*vertices7);
8532     const struct vertex_ptc_float3 exp_vertices7[] =
8533     {
8534         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8535         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f}},
8536         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f}},
8537
8538         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f}},
8539         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8540         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f}},
8541     };
8542     const UINT exp_vertex_size7 = sizeof(*exp_vertices7);
8543     /* Test 8. Convert FLOAT2 to FLOAT4. */
8544     const struct vertex_ptc vertices8[] =
8545     {
8546         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8547         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8548         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8549
8550         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8551         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8552         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8553     };
8554     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
8555     const UINT num_faces8 = ARRAY_SIZE(vertices8) / VERTS_PER_FACE;
8556     const UINT vertex_size8 = sizeof(*vertices8);
8557     const struct vertex_ptc_float4 exp_vertices8[] =
8558     {
8559         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
8560         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f, 1.0f}},
8561         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f, 1.0f}},
8562
8563         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f, 1.0f}},
8564         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
8565         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f, 1.0f}},
8566     };
8567     const UINT exp_vertex_size8 = sizeof(*exp_vertices8);
8568     /* Test 9. Convert FLOAT2 to D3DCOLOR. */
8569     const struct vertex_ptc vertices9[] =
8570     {
8571         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8572         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8573         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.6f}},
8574
8575         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8576         {{ 3.0f,  0.0f,  0.f}, { 2.0f, 256.0f}},
8577         {{ 1.0f,  0.0f,  0.f}, { 0.11f,  0.2f}},
8578     };
8579     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
8580     const UINT num_faces9 = ARRAY_SIZE(vertices9) / VERTS_PER_FACE;
8581     const UINT vertex_size9 = sizeof(*vertices9);
8582     const struct vertex_ptc_d3dcolor exp_vertices9[] =
8583     {
8584         {{ 0.0f,  3.0f,  0.f}, {0, 255, 255, 255}},
8585         {{ 2.0f,  3.0f,  0.f}, {0, 179, 128, 255}},
8586         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
8587
8588         {{ 3.0f,  3.0f,  0.f}, {0, 77, 51, 255}},
8589         {{ 3.0f,  0.0f,  0.f}, {0, 255, 255, 255}},
8590         {{ 1.0f,  0.0f,  0.f}, {0, 51, 28, 255}},
8591     };
8592     const UINT exp_vertex_size9 = sizeof(*exp_vertices9);
8593     /* Test 10. Convert FLOAT2 to UBYTE4. */
8594     const struct vertex_ptc vertices10[] =
8595     {
8596         {{ 0.0f,  3.0f,  0.f}, { 0.0f,  1.0f}},
8597         {{ 2.0f,  3.0f,  0.f}, { 2.0f,  3.0f}},
8598         {{ 0.0f,  0.0f,  0.f}, { 254.0f,  255.0f}},
8599
8600         {{ 3.0f,  3.0f,  0.f}, { 256.0f, 257.0f}},
8601         {{ 3.0f,  0.0f,  0.f}, { 1.4f, 1.5f}},
8602         {{ 1.0f,  0.0f,  0.f}, {-4.0f, -5.0f}},
8603     };
8604     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
8605     const UINT num_faces10 = ARRAY_SIZE(vertices10) / VERTS_PER_FACE;
8606     const UINT vertex_size10 = sizeof(*vertices10);
8607     const struct vertex_ptc_ubyte4 exp_vertices10[] =
8608     {
8609         {{ 0.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8610         {{ 2.0f,  3.0f,  0.f}, {2, 3, 0, 1}},
8611         {{ 0.0f,  0.0f,  0.f}, {254, 255, 0, 1}},
8612
8613         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8614         {{ 3.0f,  0.0f,  0.f}, {1, 2, 0, 1}},
8615         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
8616     };
8617     const UINT exp_vertex_size10 = sizeof(*exp_vertices10);
8618     /* Test 11. Convert FLOAT2 to SHORT2. */
8619     const struct vertex_ptc vertices11[] =
8620     {
8621         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
8622         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
8623         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
8624
8625         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8626         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
8627         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
8628
8629         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
8630         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
8631         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
8632     };
8633     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
8634     const UINT num_faces11 = ARRAY_SIZE(vertices11) / VERTS_PER_FACE;
8635     const UINT vertex_size11 = sizeof(*vertices11);
8636     const struct vertex_ptc_short2 exp_vertices11[] =
8637     {
8638         {{ 0.0f,  3.0f,  0.f}, {1, 0}},
8639         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
8640         {{ 0.0f,  0.0f,  0.f}, {0, -4}},
8641
8642         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1}},
8643         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN}},
8644         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
8645
8646         {{ 4.0f,  3.0f,  0.f}, {-2, 1}},
8647         {{ 6.0f,  0.0f,  0.f}, {32765, -32767}},
8648         {{ 4.0f,  0.0f,  0.f}, {-4, 1}},
8649     };
8650     const UINT exp_vertex_size11 = sizeof(*exp_vertices11);
8651     /* Test 12. Convert FLOAT2 to SHORT4. */
8652     const struct vertex_ptc vertices12[] =
8653     {
8654         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
8655         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
8656         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
8657
8658         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8659         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
8660         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
8661
8662         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
8663         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
8664         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
8665     };
8666     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
8667     const UINT num_faces12 = ARRAY_SIZE(vertices12) / VERTS_PER_FACE;
8668     const UINT vertex_size12 = sizeof(*vertices12);
8669     const struct vertex_ptc_short4 exp_vertices12[] =
8670     {
8671         {{ 0.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
8672         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8673         {{ 0.0f,  0.0f,  0.f}, {0, -4, 0, 1}},
8674
8675         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1, 0, 1}},
8676         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN, 0, 1}},
8677         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, 0, 1}},
8678
8679         {{ 4.0f,  3.0f,  0.f}, {-2, 1, 0, 1}},
8680         {{ 6.0f,  0.0f,  0.f}, {32765, -32767, 0, 1}},
8681         {{ 4.0f,  0.0f,  0.f}, {-4, 1, 0, 1}},
8682     };
8683     const UINT exp_vertex_size12 = sizeof(*exp_vertices12);
8684     /* Test 13. Convert FLOAT2 to UBYTE4N. */
8685     const struct vertex_ptc vertices13[] =
8686     {
8687         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  2.0f}},
8688         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8689         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.5f}},
8690
8691         {{ 3.0f,  3.0f,  0.f}, {-0.6f,  -1.0f}},
8692         {{ 3.0f,  0.0f,  0.f}, {UCHAR_MAX,  UCHAR_MAX + 1}},
8693         {{ 1.0f,  0.0f,  0.f}, {2 * UCHAR_MAX, -UCHAR_MAX}},
8694     };
8695     const UINT num_vertices13 = ARRAY_SIZE(vertices13);
8696     const UINT num_faces13 = ARRAY_SIZE(vertices13) / VERTS_PER_FACE;
8697     const UINT vertex_size13 = sizeof(*vertices13);
8698     const struct vertex_ptc_ubyte4n exp_vertices13[] =
8699     {
8700         {{ 0.0f,  3.0f,  0.f}, {255, 255, 0, 255}},
8701         {{ 2.0f,  3.0f,  0.f}, {128, 179, 0, 255}},
8702         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
8703
8704         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, 255}},
8705         {{ 3.0f,  0.0f,  0.f}, {255, 255, 0, 255}},
8706         {{ 1.0f,  0.0f,  0.f}, {255, 0, 0, 255}},
8707     };
8708     const UINT exp_vertex_size13 = sizeof(*exp_vertices13);
8709     /* Test 14. Convert FLOAT2 to SHORT2N. */
8710     const struct vertex_ptc vertices14[] =
8711     {
8712         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8713         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8714         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8715
8716         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8717         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
8718         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8719     };
8720     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
8721     const UINT num_faces14 = ARRAY_SIZE(vertices14) / VERTS_PER_FACE;
8722     const UINT vertex_size14 = sizeof(*vertices14);
8723     const struct vertex_ptc_short2 exp_vertices14[] =
8724     {
8725         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX}},
8726         {{ 2.0f,  3.0f,  0.f}, {13107, 16384}},
8727         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2}},
8728
8729         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383}},
8730         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3}},
8731         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2}},
8732     };
8733     const UINT exp_vertex_size14 = sizeof(*exp_vertices14);
8734     /* Test 15. Convert FLOAT2 to SHORT4N. */
8735     const struct vertex_ptc vertices15[] =
8736     {
8737         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8738         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8739         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8740
8741         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8742         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
8743         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8744     };
8745     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
8746     const UINT num_faces15 = ARRAY_SIZE(vertices15) / VERTS_PER_FACE;
8747     const UINT vertex_size15 = sizeof(*vertices15);
8748     const struct vertex_ptc_short4 exp_vertices15[] =
8749     {
8750         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX, 0, SHRT_MAX}},
8751         {{ 2.0f,  3.0f,  0.f}, {13107, 16384, 0, SHRT_MAX}},
8752         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2, 0, SHRT_MAX}},
8753
8754         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383, 0, SHRT_MAX}},
8755         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3, 0, SHRT_MAX}},
8756         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2, 0, SHRT_MAX}},
8757     };
8758     const UINT exp_vertex_size15 = sizeof(*exp_vertices15);
8759     /* Test 16. Convert FLOAT2 to USHORT2N. */
8760     const struct vertex_ptc vertices16[] =
8761     {
8762         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8763         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8764         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8765
8766         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8767         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
8768         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
8769     };
8770     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
8771     const UINT num_faces16 = ARRAY_SIZE(vertices16) / VERTS_PER_FACE;
8772     const UINT vertex_size16 = sizeof(*vertices16);
8773     const struct vertex_ptc_ushort2n exp_vertices16[] =
8774     {
8775         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX}},
8776         {{ 2.0f,  3.0f,  0.f}, {26214, 32768}},
8777         {{ 0.0f,  0.0f,  0.f}, {39321, 0}},
8778
8779         {{ 3.0f,  3.0f,  0.f}, {0, 0}},
8780         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1}},
8781         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0}},
8782     };
8783     const UINT exp_vertex_size16 = sizeof(*exp_vertices16);
8784     /* Test 17. Convert FLOAT2 to USHORT4N. */
8785     const struct vertex_ptc vertices17[] =
8786     {
8787         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8788         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8789         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8790
8791         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8792         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
8793         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
8794     };
8795     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
8796     const UINT num_faces17 = ARRAY_SIZE(vertices17) / VERTS_PER_FACE;
8797     const UINT vertex_size17 = sizeof(*vertices17);
8798     const struct vertex_ptc_ushort4n exp_vertices17[] =
8799     {
8800         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX, 0, USHRT_MAX}},
8801         {{ 2.0f,  3.0f,  0.f}, {26214, 32768, 0, USHRT_MAX}},
8802         {{ 0.0f,  0.0f,  0.f}, {39321, 0, 0, USHRT_MAX}},
8803
8804         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, USHRT_MAX}},
8805         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1, 0, USHRT_MAX}},
8806         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0, 0, USHRT_MAX}},
8807     };
8808     const UINT exp_vertex_size17 = sizeof(*exp_vertices17);
8809     /* Test 18. Test that the method field is compared by converting a FLOAT2 to
8810      * FLOAT16_2. where the method field has been change from
8811      * D3DDECLMETHOD_DEFAULT to D3DDECLMETHOD_PARTIALU. */
8812     const struct vertex_ptc vertices18[] =
8813     {
8814         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8815         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8816         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8817
8818         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8819         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8820         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8821     };
8822     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
8823     const UINT num_faces18 = ARRAY_SIZE(vertices18) / VERTS_PER_FACE;
8824     const UINT vertex_size18 = sizeof(*vertices18);
8825     const struct vertex_ptc_float16_2 exp_vertices18[] =
8826     {
8827         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8828         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
8829         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
8830
8831         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
8832         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8833         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
8834     };
8835     const UINT exp_vertex_size18 = sizeof(*exp_vertices18);
8836     /* Test 19. Test that data is lost if usage index changes, e.g. TEXCOORD0
8837      * TEXCOORD1. */
8838     const struct vertex_pntc vertices19[] =
8839     {
8840         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
8841         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
8842         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
8843
8844         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
8845         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
8846         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
8847     };
8848     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
8849     const UINT num_faces19 = ARRAY_SIZE(vertices19) / VERTS_PER_FACE;
8850     const UINT vertex_size19 = sizeof(*vertices19);
8851     const struct vertex_pntc exp_vertices19[] =
8852     {
8853         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8854         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8855         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8856
8857         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8858         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8859         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8860     };
8861     const UINT exp_vertex_size19 = sizeof(*exp_vertices19);
8862     /* Test 20. Another test that data is lost if usage index changes, e.g.
8863      * TEXCOORD1 to TEXCOORD0. */
8864     const struct vertex_pntc vertices20[] =
8865     {
8866         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
8867         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
8868         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
8869
8870         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
8871         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
8872         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
8873     };
8874     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
8875     const UINT num_faces20 = ARRAY_SIZE(vertices20) / VERTS_PER_FACE;
8876     const UINT vertex_size20 = sizeof(*vertices20);
8877     const struct vertex_pntc exp_vertices20[] =
8878     {
8879         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8880         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8881         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8882
8883         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8884         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8885         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8886     };
8887     const UINT exp_vertex_size20 = sizeof(*exp_vertices20);
8888     /* Test 21. Convert FLOAT1 to FLOAT2. */
8889     const struct vertex_ptc_float1 vertices21[] =
8890     {
8891         {{ 0.0f,  3.0f,  0.f},  1.0f},
8892         {{ 2.0f,  3.0f,  0.f},  0.5f},
8893         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8894
8895         {{ 3.0f,  3.0f,  0.f},  0.2f},
8896         {{ 3.0f,  0.0f,  0.f},  1.0f},
8897         {{ 1.0f,  0.0f,  0.f},  0.1f},
8898     };
8899     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
8900     const UINT num_faces21 = ARRAY_SIZE(vertices21) / VERTS_PER_FACE;
8901     const UINT vertex_size21 = sizeof(*vertices21);
8902     const struct vertex_ptc exp_vertices21[] =
8903     {
8904         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f}},
8905         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f}},
8906         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f}},
8907
8908         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f}},
8909         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f}},
8910         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f}},
8911     };
8912     const UINT exp_vertex_size21 = sizeof(*exp_vertices21);
8913     /* Test 22. Convert FLOAT1 to FLOAT3. */
8914     const struct vertex_ptc_float1 vertices22[] =
8915     {
8916         {{ 0.0f,  3.0f,  0.f},  1.0f},
8917         {{ 2.0f,  3.0f,  0.f},  0.5f},
8918         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8919
8920         {{ 3.0f,  3.0f,  0.f},  0.2f},
8921         {{ 3.0f,  0.0f,  0.f},  1.0f},
8922         {{ 1.0f,  0.0f,  0.f},  0.1f},
8923     };
8924     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
8925     const UINT num_faces22 = ARRAY_SIZE(vertices22) / VERTS_PER_FACE;
8926     const UINT vertex_size22 = sizeof(*vertices22);
8927     const struct vertex_ptc_float3 exp_vertices22[] =
8928     {
8929         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
8930         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f}},
8931         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f}},
8932
8933         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f}},
8934         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
8935         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f}},
8936     };
8937     const UINT exp_vertex_size22 = sizeof(*exp_vertices22);
8938     /* Test 23. Convert FLOAT1 to FLOAT4. */
8939     const struct vertex_ptc_float1 vertices23[] =
8940     {
8941         {{ 0.0f,  3.0f,  0.f},  1.0f},
8942         {{ 2.0f,  3.0f,  0.f},  0.5f},
8943         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8944
8945         {{ 3.0f,  3.0f,  0.f},  0.2f},
8946         {{ 3.0f,  0.0f,  0.f},  1.0f},
8947         {{ 1.0f,  0.0f,  0.f},  0.1f},
8948     };
8949     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
8950     const UINT num_faces23 = ARRAY_SIZE(vertices23) / VERTS_PER_FACE;
8951     const UINT vertex_size23 = sizeof(*vertices23);
8952     const struct vertex_ptc_float4 exp_vertices23[] =
8953     {
8954         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
8955         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f, 1.0f}},
8956         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f, 1.0f}},
8957
8958         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f, 1.0f}},
8959         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
8960         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f, 1.0f}},
8961     };
8962     const UINT exp_vertex_size23 = sizeof(*exp_vertices23);
8963     /* Test 24. Convert FLOAT1 to D3DCOLOR. */
8964     const struct vertex_ptc_float1 vertices24[] =
8965     {
8966         {{ 0.0f,  3.0f,  0.f},  1.0f},
8967         {{ 2.0f,  3.0f,  0.f},  0.5f},
8968         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8969
8970         {{ 3.0f,  3.0f,  0.f},  0.2f},
8971         {{ 3.0f,  0.0f,  0.f},  1.0f},
8972         {{ 1.0f,  0.0f,  0.f},  0.11f},
8973     };
8974     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
8975     const UINT num_faces24 = ARRAY_SIZE(vertices24) / VERTS_PER_FACE;
8976     const UINT vertex_size24 = sizeof(*vertices24);
8977     const struct vertex_ptc_d3dcolor exp_vertices24[] =
8978     {
8979         {{ 0.0f,  3.0f,  0.f}, {0, 0, 255, 255}},
8980         {{ 2.0f,  3.0f,  0.f}, {0, 0, 128, 255}},
8981         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
8982
8983         {{ 3.0f,  3.0f,  0.f}, {0, 0, 51, 255}},
8984         {{ 3.0f,  0.0f,  0.f}, {0, 0, 255, 255}},
8985         {{ 1.0f,  0.0f,  0.f}, {0, 0, 28, 255}},
8986     };
8987     const UINT exp_vertex_size24 = sizeof(*exp_vertices24);
8988     /* Test 25. Convert FLOAT1 to ubyte4. */
8989     const struct vertex_ptc_float1 vertices25[] =
8990     {
8991         {{ 0.0f,  3.0f,  0.f}, 0.0f},
8992         {{ 2.0f,  3.0f,  0.f}, 1.4f},
8993         {{ 0.0f,  0.0f,  0.f}, 1.5f},
8994
8995         {{ 3.0f,  3.0f,  0.f}, 255.0f},
8996         {{ 3.0f,  0.0f,  0.f}, 256.0f},
8997         {{ 1.0f,  0.0f,  0.f}, -1.0f},
8998     };
8999     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
9000     const UINT num_faces25 = ARRAY_SIZE(vertices25) / VERTS_PER_FACE;
9001     const UINT vertex_size25 = sizeof(*vertices25);
9002     const struct vertex_ptc_ubyte4 exp_vertices25[] =
9003     {
9004         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 1}},
9005         {{ 2.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
9006         {{ 0.0f,  0.0f,  0.f}, {2, 0, 0, 1}},
9007
9008         {{ 3.0f,  3.0f,  0.f}, {255, 0, 0, 1}},
9009         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9010         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9011     };
9012     const UINT exp_vertex_size25 = sizeof(*exp_vertices25);
9013     /* Test 26. Convert FLOAT4 to D3DCOLOR. */
9014     const struct vertex_ptc_float4 vertices26[] =
9015     {
9016         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.5f}},
9017         {{ 2.0f,  3.0f,  0.f}, {-0.4f, -0.5f, -1.0f, -2.0f}},
9018         {{ 0.0f,  0.0f,  0.f}, {254.0f, 255.0f, 256.0f, 257.0f}},
9019
9020         {{ 3.0f,  3.0f,  0.f}, {0.1f, 0.2f, 0.3f, 0.4f}},
9021         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.6f, 0.7f, 0.8f}},
9022         {{ 1.0f,  0.0f,  0.f}, {0.9f, 0.99f, 0.995f, 0.999f}},
9023     };
9024     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
9025     const UINT num_faces26 = ARRAY_SIZE(vertices26) / VERTS_PER_FACE;
9026     const UINT vertex_size26 = sizeof(*vertices26);
9027     const struct vertex_ptc_d3dcolor exp_vertices26[] =
9028     {
9029         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9030         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9031         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9032
9033         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9034         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9035         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9036     };
9037     const UINT exp_vertex_size26 = sizeof(*exp_vertices26);
9038     /* Test 27. Convert D3DCOLOR to FLOAT4. */
9039     const struct vertex_ptc_d3dcolor vertices27[] =
9040     {
9041         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9042         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9043         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9044
9045         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9046         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9047         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9048     };
9049     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
9050     const UINT num_faces27 = ARRAY_SIZE(vertices27) / VERTS_PER_FACE;
9051     const UINT vertex_size27 = sizeof(*vertices27);
9052     const struct vertex_ptc_float4 exp_vertices27[] =
9053     {
9054         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.501961f}},
9055         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9056         {{ 0.0f,  0.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9057
9058         {{ 3.0f,  3.0f,  0.f}, {0.101961f, 0.2f, 0.301961f, 0.4f}},
9059         {{ 3.0f,  0.0f,  0.f}, {0.501961f, 0.6f, 0.701961f, 0.8f}},
9060         {{ 1.0f,  0.0f,  0.f}, {0.901961f, 0.988235f, 0.996078f, 1.0f}},
9061     };
9062     const UINT exp_vertex_size27 = sizeof(*exp_vertices27);
9063     /* Test 28. Convert UBYTE4 to FLOAT4. */
9064     const struct vertex_ptc_ubyte4 vertices28[] =
9065     {
9066         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9067         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9068         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9069
9070         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9071         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9072         {{ 1.0f,  0.0f,  0.f}, {50, 60, 127, 255}},
9073     };
9074     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
9075     const UINT num_faces28 = ARRAY_SIZE(vertices28) / VERTS_PER_FACE;
9076     const UINT vertex_size28 = sizeof(*vertices28);
9077     const struct vertex_ptc_float4 exp_vertices28[] =
9078     {
9079         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9080         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9081         {{ 0.0f,  0.0f,  0.f}, {1.0f,  0.0f, 1.0f, 0.0f}},
9082
9083         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9084         {{ 3.0f,  0.0f,  0.f}, {10.0f, 20.0f, 30.0f, 40.0f}},
9085         {{ 1.0f,  0.0f,  0.f}, {50.0f, 60.0f, 127.0f, 255.0f}},
9086     };
9087     const UINT exp_vertex_size28 = sizeof(*exp_vertices28);
9088     /* Test 29. Convert SHORT2 to FLOAT4. */
9089     const struct vertex_ptc_short2 vertices29[] =
9090     {
9091         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9092         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9093         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9094
9095         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9096         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX}},
9097         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9098     };
9099     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
9100     const UINT num_faces29 = ARRAY_SIZE(vertices29) / VERTS_PER_FACE;
9101     const UINT vertex_size29 = sizeof(*vertices29);
9102     const struct vertex_ptc_float4 exp_vertices29[] =
9103     {
9104         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9105         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9106         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 0.0f, 1.0f}},
9107
9108         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9109         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 0.0f, 1.0f}},
9110         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, 0.0f, 1.0f}},
9111     };
9112     const UINT exp_vertex_size29 = sizeof(*exp_vertices29);
9113     /* Test 29. Convert SHORT4 to FLOAT4. */
9114     const struct vertex_ptc_short4 vertices30[] =
9115     {
9116         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9117         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9118         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9119
9120         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9121         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1, 0}},
9122         {{ 1.0f,  0.0f,  0.f}, {-42, 42, SHRT_MAX, SHRT_MIN}},
9123     };
9124     const UINT num_vertices30 = ARRAY_SIZE(vertices30);
9125     const UINT num_faces30 = ARRAY_SIZE(vertices30) / VERTS_PER_FACE;
9126     const UINT vertex_size30 = sizeof(*vertices30);
9127     const struct vertex_ptc_float4 exp_vertices30[] =
9128     {
9129         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9130         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9131         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9132
9133         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9134         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1.0f, 0.0f}},
9135         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, SHRT_MAX, SHRT_MIN}},
9136     };
9137     const UINT exp_vertex_size30 = sizeof(*exp_vertices30);
9138     /* Test 31. Convert UBYTE4N to FLOAT4. */
9139     const struct vertex_ptc_ubyte4n vertices31[] =
9140     {
9141         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9142         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9143         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9144
9145         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9146         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9147         {{ 1.0f,  0.0f,  0.f}, {50, 60, 70, UCHAR_MAX}},
9148     };
9149     const UINT num_vertices31 = ARRAY_SIZE(vertices31);
9150     const UINT num_faces31 = ARRAY_SIZE(vertices31) / VERTS_PER_FACE;
9151     const UINT vertex_size31 = sizeof(*vertices31);
9152     const struct vertex_ptc_float4 exp_vertices31[] =
9153     {
9154         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9155         {{ 2.0f,  3.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX}},
9156         {{ 0.0f,  0.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX, 0.0f}},
9157
9158         {{ 3.0f,  3.0f,  0.f}, {0.0f, (FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX}},
9159         {{ 3.0f,  0.0f,  0.f}, {(FLOAT)10/UCHAR_MAX, (FLOAT)20/UCHAR_MAX, (FLOAT)30/UCHAR_MAX, (FLOAT)40/UCHAR_MAX}},
9160         {{ 1.0f,  0.0f,  0.f}, {(FLOAT)50/UCHAR_MAX, (FLOAT)60/UCHAR_MAX, (FLOAT)70/UCHAR_MAX, 1.0f}},
9161     };
9162     const UINT exp_vertex_size31 = sizeof(*exp_vertices31);
9163     /* Test 32. Convert SHORT2N to FLOAT4. */
9164     const struct vertex_ptc_short2 vertices32[] =
9165     {
9166         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9167         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9168         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9169
9170         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9171         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
9172         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9173     };
9174     const UINT num_vertices32 = ARRAY_SIZE(vertices32);
9175     const UINT num_faces32 = ARRAY_SIZE(vertices32) / VERTS_PER_FACE;
9176     const UINT vertex_size32 = sizeof(*vertices32);
9177     const struct vertex_ptc_float4 exp_vertices32[] =
9178     {
9179         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9180         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9181         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 0.0f, 1.0f}},
9182
9183         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9184         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, 0.0f, 1.0f}},
9185         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 0.0f, 1.0f}},
9186     };
9187     const UINT exp_vertex_size32 = sizeof(*exp_vertices32);
9188     /* Test 33. Convert SHORT4N to FLOAT4. */
9189     const struct vertex_ptc_short4 vertices33[] =
9190     {
9191         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9192         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9193         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9194
9195         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9196         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, SHRT_MIN + 1, SHRT_MAX}},
9197         {{ 1.0f,  0.0f,  0.f}, {-42, 42, 1, 1}},
9198     };
9199     const UINT num_vertices33 = ARRAY_SIZE(vertices33);
9200     const UINT num_faces33 = ARRAY_SIZE(vertices33) / VERTS_PER_FACE;
9201     const UINT vertex_size33 = sizeof(*vertices33);
9202     const struct vertex_ptc_float4 exp_vertices33[] =
9203     {
9204         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9205         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX}},
9206         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX, 0.0f}},
9207
9208         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9209         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, -1.0f, 1.0f}},
9210         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9211     };
9212     const UINT exp_vertex_size33 = sizeof(*exp_vertices33);
9213     /* Test 34. Convert FLOAT16_2 to FLOAT4. */
9214     const struct vertex_ptc_float16_2 vertices34[] =
9215     {
9216         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9217         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9218         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9219
9220         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9221         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9222         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9223     };
9224     const UINT num_vertices34 = ARRAY_SIZE(vertices34);
9225     const UINT num_faces34 = ARRAY_SIZE(vertices34) / VERTS_PER_FACE;
9226     const UINT vertex_size34 = sizeof(*vertices34);
9227     const struct vertex_ptc_float4 exp_vertices34[] =
9228     {
9229         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9230         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.700195f, 0.0f, 1.0f}},
9231         {{ 0.0f,  0.0f,  0.f}, {-0.199951f, -0.300049f, 0.0f, 1.0f}},
9232
9233         {{ 3.0f,  3.0f,  0.f}, {0.199951f, 0.300049f, 0.0f, 1.0f}},
9234         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9235         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.0f, 1.0f}},
9236     };
9237     const UINT exp_vertex_size34 = sizeof(*exp_vertices34);
9238     /* Test 35. Convert FLOAT16_4 to FLOAT4. */
9239     const struct vertex_ptc_float16_4 vertices35[] =
9240     {
9241         {{ 0.0f,  3.0f,  0.f}, {0x0000, 0x0000, 0x0000, 0x0000}},
9242         {{ 2.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
9243         {{ 0.0f,  0.0f,  0.f}, {0x3c00, 0x0000, 0x3c00, 0x0000}},
9244
9245         {{ 3.0f,  3.0f,  0.f}, {0x0000, 0x3c00, 0x0000, 0x3c00}},
9246         {{ 3.0f,  0.0f,  0.f}, {0x3800, 0x399a, 0xb266, 0xb4cd}},
9247         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
9248     };
9249     const UINT num_vertices35 = ARRAY_SIZE(vertices35);
9250     const UINT num_faces35 = ARRAY_SIZE(vertices35) / VERTS_PER_FACE;
9251     const UINT vertex_size35 = sizeof(*vertices35);
9252     const struct vertex_ptc_float4 exp_vertices35[] =
9253     {
9254         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9255         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9256         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9257
9258         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9259         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.700195f, -0.199951f, -0.300049f}},
9260         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.099976f, 0.199951f}},
9261     };
9262     const UINT exp_vertex_size35 = sizeof(*exp_vertices35);
9263     /* Test 36. Check that vertex buffer sharing is ok. */
9264     const struct vertex_pn vertices36[] =
9265     {
9266         {{ 0.0f,  3.0f,  0.f}, up},
9267         {{ 2.0f,  3.0f,  0.f}, up},
9268         {{ 0.0f,  0.0f,  0.f}, up},
9269     };
9270     const UINT num_vertices36 = ARRAY_SIZE(vertices36);
9271     const UINT num_faces36 = ARRAY_SIZE(vertices36) / VERTS_PER_FACE;
9272     const UINT vertex_size36 = sizeof(*vertices36);
9273     const DWORD clone_options36 = options | D3DXMESH_VB_SHARE;
9274     /* Common mesh data */
9275     ID3DXMesh *mesh = NULL;
9276     ID3DXMesh *mesh_clone = NULL;
9277     struct
9278     {
9279         const BYTE *vertices;
9280         const DWORD *indices;
9281         const DWORD *attributes;
9282         const UINT num_vertices;
9283         const UINT num_faces;
9284         const UINT vertex_size;
9285         const DWORD create_options;
9286         const DWORD clone_options;
9287         D3DVERTEXELEMENT9 *declaration;
9288         D3DVERTEXELEMENT9 *new_declaration;
9289         const BYTE *exp_vertices;
9290         const UINT exp_vertex_size;
9291     }
9292     tc[] =
9293     {
9294         {
9295             (BYTE*)vertices0,
9296             NULL,
9297             NULL,
9298             num_vertices0,
9299             num_faces0,
9300             vertex_size0,
9301             options,
9302             options,
9303             declaration_pn,
9304             declaration_pn,
9305             (BYTE*)vertices0,
9306             vertex_size0
9307         },
9308         {
9309             (BYTE*)vertices0,
9310             NULL,
9311             NULL,
9312             num_vertices0,
9313             num_faces0,
9314             vertex_size0,
9315             options_16bit,
9316             options_16bit,
9317             declaration_pn,
9318             declaration_pn,
9319             (BYTE*)vertices0,
9320             vertex_size0
9321         },
9322         {
9323             (BYTE*)vertices0,
9324             NULL,
9325             NULL,
9326             num_vertices0,
9327             num_faces0,
9328             vertex_size0,
9329             options,
9330             options,
9331             declaration_pn,
9332             declaration_pntc,
9333             (BYTE*)exp_vertices2,
9334             exp_vertex_size2
9335         },
9336         {
9337             (BYTE*)vertices0,
9338             NULL,
9339             NULL,
9340             num_vertices0,
9341             num_faces0,
9342             vertex_size0,
9343             options,
9344             options,
9345             declaration_pn,
9346             declaration_ptcn,
9347             (BYTE*)exp_vertices3,
9348             exp_vertex_size3
9349         },
9350         {
9351             (BYTE*)vertices4,
9352             NULL,
9353             NULL,
9354             num_vertices4,
9355             num_faces4,
9356             vertex_size4,
9357             options,
9358             options,
9359             declaration_ptc,
9360             declaration_ptc_float16_2,
9361             (BYTE*)exp_vertices4,
9362             exp_vertex_size4
9363         },
9364         {
9365             (BYTE*)vertices5,
9366             NULL,
9367             NULL,
9368             num_vertices5,
9369             num_faces5,
9370             vertex_size5,
9371             options,
9372             options,
9373             declaration_ptc,
9374             declaration_ptc_float16_4,
9375             (BYTE*)exp_vertices5,
9376             exp_vertex_size5
9377         },
9378         {
9379             (BYTE*)vertices6,
9380             NULL,
9381             NULL,
9382             num_vertices6,
9383             num_faces6,
9384             vertex_size6,
9385             options,
9386             options,
9387             declaration_ptc,
9388             declaration_ptc_float1,
9389             (BYTE*)exp_vertices6,
9390             exp_vertex_size6
9391         },
9392         {
9393             (BYTE*)vertices7,
9394             NULL,
9395             NULL,
9396             num_vertices7,
9397             num_faces7,
9398             vertex_size7,
9399             options,
9400             options,
9401             declaration_ptc,
9402             declaration_ptc_float3,
9403             (BYTE*)exp_vertices7,
9404             exp_vertex_size7
9405         },
9406         {
9407             (BYTE*)vertices8,
9408             NULL,
9409             NULL,
9410             num_vertices8,
9411             num_faces8,
9412             vertex_size8,
9413             options,
9414             options,
9415             declaration_ptc,
9416             declaration_ptc_float4,
9417             (BYTE*)exp_vertices8,
9418             exp_vertex_size8
9419         },
9420         {
9421             (BYTE*)vertices9,
9422             NULL,
9423             NULL,
9424             num_vertices9,
9425             num_faces9,
9426             vertex_size9,
9427             options,
9428             options,
9429             declaration_ptc,
9430             declaration_ptc_d3dcolor,
9431             (BYTE*)exp_vertices9,
9432             exp_vertex_size9
9433         },
9434         {
9435             (BYTE*)vertices10,
9436             NULL,
9437             NULL,
9438             num_vertices10,
9439             num_faces10,
9440             vertex_size10,
9441             options,
9442             options,
9443             declaration_ptc,
9444             declaration_ptc_ubyte4,
9445             (BYTE*)exp_vertices10,
9446             exp_vertex_size10
9447         },
9448         {
9449             (BYTE*)vertices11,
9450             NULL,
9451             NULL,
9452             num_vertices11,
9453             num_faces11,
9454             vertex_size11,
9455             options,
9456             options,
9457             declaration_ptc,
9458             declaration_ptc_short2,
9459             (BYTE*)exp_vertices11,
9460             exp_vertex_size11
9461         },
9462         {
9463             (BYTE*)vertices12,
9464             NULL,
9465             NULL,
9466             num_vertices12,
9467             num_faces12,
9468             vertex_size12,
9469             options,
9470             options,
9471             declaration_ptc,
9472             declaration_ptc_short4,
9473             (BYTE*)exp_vertices12,
9474             exp_vertex_size12
9475         },
9476         {
9477             (BYTE*)vertices13,
9478             NULL,
9479             NULL,
9480             num_vertices13,
9481             num_faces13,
9482             vertex_size13,
9483             options,
9484             options,
9485             declaration_ptc,
9486             declaration_ptc_ubyte4n,
9487             (BYTE*)exp_vertices13,
9488             exp_vertex_size13
9489         },
9490         {
9491             (BYTE*)vertices14,
9492             NULL,
9493             NULL,
9494             num_vertices14,
9495             num_faces14,
9496             vertex_size14,
9497             options,
9498             options,
9499             declaration_ptc,
9500             declaration_ptc_short2n,
9501             (BYTE*)exp_vertices14,
9502             exp_vertex_size14
9503         },
9504         {
9505             (BYTE*)vertices15,
9506             NULL,
9507             NULL,
9508             num_vertices15,
9509             num_faces15,
9510             vertex_size15,
9511             options,
9512             options,
9513             declaration_ptc,
9514             declaration_ptc_short4n,
9515             (BYTE*)exp_vertices15,
9516             exp_vertex_size15
9517         },
9518         {
9519             (BYTE*)vertices16,
9520             NULL,
9521             NULL,
9522             num_vertices16,
9523             num_faces16,
9524             vertex_size16,
9525             options,
9526             options,
9527             declaration_ptc,
9528             declaration_ptc_ushort2n,
9529             (BYTE*)exp_vertices16,
9530             exp_vertex_size16
9531         },
9532         {
9533             (BYTE*)vertices17,
9534             NULL,
9535             NULL,
9536             num_vertices17,
9537             num_faces17,
9538             vertex_size17,
9539             options,
9540             options,
9541             declaration_ptc,
9542             declaration_ptc_ushort4n,
9543             (BYTE*)exp_vertices17,
9544             exp_vertex_size17
9545         },
9546         {
9547             (BYTE*)vertices18,
9548             NULL,
9549             NULL,
9550             num_vertices18,
9551             num_faces18,
9552             vertex_size18,
9553             options,
9554             options,
9555             declaration_ptc,
9556             declaration_ptc_float16_2_partialu,
9557             (BYTE*)exp_vertices18,
9558             exp_vertex_size18
9559         },
9560         {
9561             (BYTE*)vertices19,
9562             NULL,
9563             NULL,
9564             num_vertices19,
9565             num_faces19,
9566             vertex_size19,
9567             options,
9568             options,
9569             declaration_pntc,
9570             declaration_pntc1,
9571             (BYTE*)exp_vertices19,
9572             exp_vertex_size19
9573         },
9574         {
9575             (BYTE*)vertices20,
9576             NULL,
9577             NULL,
9578             num_vertices20,
9579             num_faces20,
9580             vertex_size20,
9581             options,
9582             options,
9583             declaration_pntc1,
9584             declaration_pntc,
9585             (BYTE*)exp_vertices20,
9586             exp_vertex_size20
9587         },
9588         {
9589             (BYTE*)vertices21,
9590             NULL,
9591             NULL,
9592             num_vertices21,
9593             num_faces21,
9594             vertex_size21,
9595             options,
9596             options,
9597             declaration_ptc_float1,
9598             declaration_ptc,
9599             (BYTE*)exp_vertices21,
9600             exp_vertex_size21
9601         },
9602         {
9603             (BYTE*)vertices22,
9604             NULL,
9605             NULL,
9606             num_vertices22,
9607             num_faces22,
9608             vertex_size22,
9609             options,
9610             options,
9611             declaration_ptc_float1,
9612             declaration_ptc_float3,
9613             (BYTE*)exp_vertices22,
9614             exp_vertex_size22
9615         },
9616         {
9617             (BYTE*)vertices23,
9618             NULL,
9619             NULL,
9620             num_vertices23,
9621             num_faces23,
9622             vertex_size23,
9623             options,
9624             options,
9625             declaration_ptc_float1,
9626             declaration_ptc_float4,
9627             (BYTE*)exp_vertices23,
9628             exp_vertex_size23
9629         },
9630         {
9631             (BYTE*)vertices24,
9632             NULL,
9633             NULL,
9634             num_vertices24,
9635             num_faces24,
9636             vertex_size24,
9637             options,
9638             options,
9639             declaration_ptc_float1,
9640             declaration_ptc_d3dcolor,
9641             (BYTE*)exp_vertices24,
9642             exp_vertex_size24
9643         },
9644         {
9645             (BYTE*)vertices25,
9646             NULL,
9647             NULL,
9648             num_vertices25,
9649             num_faces25,
9650             vertex_size25,
9651             options,
9652             options,
9653             declaration_ptc_float1,
9654             declaration_ptc_ubyte4,
9655             (BYTE*)exp_vertices25,
9656             exp_vertex_size25
9657         },
9658         {
9659             (BYTE*)vertices26,
9660             NULL,
9661             NULL,
9662             num_vertices26,
9663             num_faces26,
9664             vertex_size26,
9665             options,
9666             options,
9667             declaration_ptc_float4,
9668             declaration_ptc_d3dcolor,
9669             (BYTE*)exp_vertices26,
9670             exp_vertex_size26
9671         },
9672         {
9673             (BYTE*)vertices27,
9674             NULL,
9675             NULL,
9676             num_vertices27,
9677             num_faces27,
9678             vertex_size27,
9679             options,
9680             options,
9681             declaration_ptc_d3dcolor,
9682             declaration_ptc_float4,
9683             (BYTE*)exp_vertices27,
9684             exp_vertex_size27
9685         },
9686         {
9687             (BYTE*)vertices28,
9688             NULL,
9689             NULL,
9690             num_vertices28,
9691             num_faces28,
9692             vertex_size28,
9693             options,
9694             options,
9695             declaration_ptc_ubyte4,
9696             declaration_ptc_float4,
9697             (BYTE*)exp_vertices28,
9698             exp_vertex_size28
9699         },
9700         {
9701             (BYTE*)vertices29,
9702             NULL,
9703             NULL,
9704             num_vertices29,
9705             num_faces29,
9706             vertex_size29,
9707             options,
9708             options,
9709             declaration_ptc_short2,
9710             declaration_ptc_float4,
9711             (BYTE*)exp_vertices29,
9712             exp_vertex_size29
9713         },
9714         {
9715             (BYTE*)vertices30,
9716             NULL,
9717             NULL,
9718             num_vertices30,
9719             num_faces30,
9720             vertex_size30,
9721             options,
9722             options,
9723             declaration_ptc_short4,
9724             declaration_ptc_float4,
9725             (BYTE*)exp_vertices30,
9726             exp_vertex_size30
9727         },
9728         {
9729             (BYTE*)vertices31,
9730             NULL,
9731             NULL,
9732             num_vertices31,
9733             num_faces31,
9734             vertex_size31,
9735             options,
9736             options,
9737             declaration_ptc_ubyte4n,
9738             declaration_ptc_float4,
9739             (BYTE*)exp_vertices31,
9740             exp_vertex_size31
9741         },
9742         {
9743             (BYTE*)vertices32,
9744             NULL,
9745             NULL,
9746             num_vertices32,
9747             num_faces32,
9748             vertex_size32,
9749             options,
9750             options,
9751             declaration_ptc_short2n,
9752             declaration_ptc_float4,
9753             (BYTE*)exp_vertices32,
9754             exp_vertex_size32
9755         },
9756         {
9757             (BYTE*)vertices33,
9758             NULL,
9759             NULL,
9760             num_vertices33,
9761             num_faces33,
9762             vertex_size33,
9763             options,
9764             options,
9765             declaration_ptc_short4n,
9766             declaration_ptc_float4,
9767             (BYTE*)exp_vertices33,
9768             exp_vertex_size33
9769         },
9770         {
9771             (BYTE*)vertices34,
9772             NULL,
9773             NULL,
9774             num_vertices34,
9775             num_faces34,
9776             vertex_size34,
9777             options,
9778             options,
9779             declaration_ptc_float16_2,
9780             declaration_ptc_float4,
9781             (BYTE*)exp_vertices34,
9782             exp_vertex_size34
9783         },
9784         {
9785             (BYTE*)vertices35,
9786             NULL,
9787             NULL,
9788             num_vertices35,
9789             num_faces35,
9790             vertex_size35,
9791             options,
9792             options,
9793             declaration_ptc_float16_4,
9794             declaration_ptc_float4,
9795             (BYTE*)exp_vertices35,
9796             exp_vertex_size35
9797         },
9798         {
9799             (BYTE*)vertices36,
9800             NULL,
9801             NULL,
9802             num_vertices36,
9803             num_faces36,
9804             vertex_size36,
9805             options,
9806             clone_options36,
9807             declaration_pn,
9808             declaration_pn,
9809             (BYTE*)vertices36,
9810             vertex_size36
9811         },
9812     };
9813
9814     test_context = new_test_context();
9815     if (!test_context)
9816     {
9817         skip("Couldn't create test context\n");
9818         goto cleanup;
9819     }
9820
9821     for (i = 0; i < ARRAY_SIZE(tc); i++)
9822     {
9823         UINT j;
9824         D3DVERTEXELEMENT9 new_declaration[MAX_FVF_DECL_SIZE];
9825         UINT exp_new_decl_length, new_decl_length;
9826         UINT exp_new_decl_size, new_decl_size;
9827
9828         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
9829                               tc[i].create_options,
9830                               tc[i].declaration,
9831                               test_context->device, &mesh,
9832                               tc[i].vertices, tc[i].vertex_size,
9833                               tc[i].indices, tc[i].attributes);
9834         if (FAILED(hr))
9835         {
9836             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
9837             goto cleanup;
9838         }
9839
9840         hr = mesh->lpVtbl->CloneMesh(mesh, tc[i].clone_options, tc[i].new_declaration,
9841                                      test_context->device, &mesh_clone);
9842         ok(hr == D3D_OK, "CloneMesh test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
9843
9844         hr = mesh_clone->lpVtbl->GetDeclaration(mesh_clone, new_declaration);
9845         ok(hr == D3D_OK, "GetDeclaration test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
9846         /* Check declaration elements */
9847         for (j = 0; tc[i].new_declaration[j].Stream != 0xFF; j++)
9848         {
9849             ok(memcmp(&tc[i].new_declaration[j], &new_declaration[j], sizeof(*new_declaration)) == 0,
9850                "Test case %d failed. Declaration element %d did not match.\n", i, j);
9851         }
9852
9853         /* Check declaration length */
9854         exp_new_decl_length = D3DXGetDeclLength(tc[i].new_declaration);
9855         new_decl_length = D3DXGetDeclLength(new_declaration);
9856         ok(new_decl_length == exp_new_decl_length,
9857            "Test case %d failed. Got new declaration length %d, expected %d\n",
9858            i, new_decl_length, exp_new_decl_length);
9859
9860         /* Check declaration size */
9861         exp_new_decl_size = D3DXGetDeclVertexSize(tc[i].new_declaration, 0);
9862         new_decl_size = D3DXGetDeclVertexSize(new_declaration, 0);
9863         ok(new_decl_size == exp_new_decl_size,
9864            "Test case %d failed. Got new declaration size %d, expected %d\n",
9865            i, new_decl_size, exp_new_decl_size);
9866
9867         /* Check vertex data in cloned mesh */
9868         hr = mesh_clone->lpVtbl->LockVertexBuffer(mesh_clone, 0, (void**)&vertices);
9869         if (FAILED(hr))
9870         {
9871             skip("Couldn't lock cloned vertex buffer.\n");
9872             goto cleanup;
9873         }
9874         for (j = 0; j < tc[i].num_vertices; j++)
9875         {
9876             UINT index = tc[i].exp_vertex_size * j;
9877             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].new_declaration);
9878         }
9879         hr = mesh_clone->lpVtbl->UnlockVertexBuffer(mesh_clone);
9880         if (FAILED(hr))
9881         {
9882             skip("Couldn't unlock vertex buffer.\n");
9883             goto cleanup;
9884         }
9885         vertices = NULL;
9886         mesh->lpVtbl->Release(mesh);
9887         mesh = NULL;
9888         mesh_clone->lpVtbl->Release(mesh_clone);
9889         mesh_clone = NULL;
9890     }
9891
9892     /* The following test shows that it is not possible to share a vertex buffer
9893      * with D3DXMESH_VB_SHARE and change the vertex declaration at the same
9894      * time. It reuses the test data from test 2.
9895      */
9896     hr = init_test_mesh(tc[2].num_faces, tc[2].num_vertices,
9897                         tc[2].create_options,
9898                         tc[2].declaration,
9899                         test_context->device, &mesh,
9900                         tc[2].vertices, tc[2].vertex_size,
9901                         tc[2].indices, tc[2].attributes);
9902     if (FAILED(hr))
9903     {
9904         skip("Couldn't initialize test mesh for D3DXMESH_VB_SHARE case."
9905              " Got %x expected D3D_OK\n", hr);
9906         goto cleanup;
9907     }
9908
9909     hr = mesh->lpVtbl->CloneMesh(mesh, tc[2].create_options | D3DXMESH_VB_SHARE,
9910                                  tc[2].new_declaration, test_context->device,
9911                                  &mesh_clone);
9912     ok(hr == D3DERR_INVALIDCALL, "CloneMesh D3DXMESH_VB_SHARE with new"
9913        " declaration. Got %x, expected D3DERR_INVALIDCALL\n",
9914        hr);
9915     mesh->lpVtbl->Release(mesh);
9916     mesh = NULL;
9917     mesh_clone = NULL;
9918
9919 cleanup:
9920     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
9921     if (mesh) mesh->lpVtbl->Release(mesh);
9922     if (mesh_clone) mesh_clone->lpVtbl->Release(mesh_clone);
9923     free_test_context(test_context);
9924 }
9925
9926 static void test_valid_mesh(void)
9927 {
9928     HRESULT hr;
9929     struct test_context *test_context = NULL;
9930     UINT i;
9931     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
9932     const D3DVERTEXELEMENT9 declaration[] =
9933     {
9934         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
9935         D3DDECL_END()
9936     };
9937     const unsigned int VERTS_PER_FACE = 3;
9938     /* mesh0 (one face)
9939      *
9940      * 0--1
9941      * | /
9942      * |/
9943      * 2
9944      */
9945     const D3DXVECTOR3 vertices0[] =
9946     {
9947         { 0.0f,  3.0f,  0.f},
9948         { 2.0f,  3.0f,  0.f},
9949         { 0.0f,  0.0f,  0.f},
9950     };
9951     const DWORD indices0[] = {0, 1, 2};
9952     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
9953     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
9954     const DWORD adjacency0[] = {-1, -1, -1};
9955     const HRESULT exp_hr0 = D3D_OK;
9956     /* mesh1 (Simple bow-tie)
9957      *
9958      * 0--1 1--3
9959      * | /   \ |
9960      * |/     \|
9961      * 2       4
9962      */
9963     const D3DXVECTOR3 vertices1[] =
9964     {
9965         { 0.0f,  3.0f,  0.f},
9966         { 2.0f,  3.0f,  0.f},
9967         { 0.0f,  0.0f,  0.f},
9968
9969         { 4.0f,  3.0f,  0.f},
9970         { 4.0f,  0.0f,  0.f},
9971     };
9972     const DWORD indices1[] = {0, 1, 2, 1, 3, 4};
9973     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
9974     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
9975     const DWORD adjacency1[] = {-1, -1, -1, -1, -1, -1};
9976     const HRESULT exp_hr1 = D3DXERR_INVALIDMESH;
9977     /* Common mesh data */
9978     ID3DXMesh *mesh = NULL;
9979     UINT vertex_size = sizeof(D3DXVECTOR3);
9980     ID3DXBuffer *errors_and_warnings = NULL;
9981     struct
9982     {
9983         const D3DXVECTOR3 *vertices;
9984         const DWORD *indices;
9985         const UINT num_vertices;
9986         const UINT num_faces;
9987         const DWORD *adjacency;
9988         const HRESULT exp_hr;
9989     }
9990     tc[] =
9991     {
9992         {
9993             vertices0,
9994             indices0,
9995             num_vertices0,
9996             num_faces0,
9997             adjacency0,
9998             exp_hr0,
9999         },
10000         {
10001             vertices1,
10002             indices1,
10003             num_vertices1,
10004             num_faces1,
10005             adjacency1,
10006             exp_hr1,
10007         },
10008     };
10009
10010     test_context = new_test_context();
10011     if (!test_context)
10012     {
10013         skip("Couldn't create test context\n");
10014         goto cleanup;
10015     }
10016
10017     for (i = 0; i < ARRAY_SIZE(tc); i++)
10018     {
10019         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10020                             options, declaration,
10021                             test_context->device, &mesh,
10022                             tc[i].vertices, vertex_size,
10023                             tc[i].indices, NULL);
10024         if (FAILED(hr))
10025         {
10026             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10027             goto cleanup;
10028         }
10029
10030         hr = D3DXValidMesh(mesh, tc[i].adjacency, &errors_and_warnings);
10031         todo_wine ok(hr == tc[i].exp_hr, "D3DXValidMesh test case %d failed. "
10032                      "Got %x\n, expected %x\n", i, hr, tc[i].exp_hr);
10033
10034         /* Note errors_and_warnings is deliberately not checked because that
10035          * would require copying wast amounts of the text output. */
10036         if (errors_and_warnings)
10037         {
10038             ID3DXBuffer_Release(errors_and_warnings);
10039             errors_and_warnings = NULL;
10040         }
10041         mesh->lpVtbl->Release(mesh);
10042         mesh = NULL;
10043     }
10044
10045 cleanup:
10046     if (mesh) mesh->lpVtbl->Release(mesh);
10047     free_test_context(test_context);
10048 }
10049
10050 START_TEST(mesh)
10051 {
10052     D3DXBoundProbeTest();
10053     D3DXComputeBoundingBoxTest();
10054     D3DXComputeBoundingSphereTest();
10055     D3DXGetFVFVertexSizeTest();
10056     D3DXIntersectTriTest();
10057     D3DXCreateMeshTest();
10058     D3DXCreateMeshFVFTest();
10059     D3DXLoadMeshTest();
10060     D3DXCreateBoxTest();
10061     D3DXCreateSphereTest();
10062     D3DXCreateCylinderTest();
10063     D3DXCreateTextTest();
10064     test_get_decl_length();
10065     test_get_decl_vertex_size();
10066     test_fvf_decl_conversion();
10067     D3DXGenerateAdjacencyTest();
10068     test_update_semantics();
10069     test_create_skin_info();
10070     test_convert_adjacency_to_point_reps();
10071     test_convert_point_reps_to_adjacency();
10072     test_weld_vertices();
10073     test_clone_mesh();
10074     test_valid_mesh();
10075 }