Release 1.4-rc5.
[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 = D3DXCreateBuffer(36 * sizeof(DWORD), &ppBuffer);
2475     ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2476     if (FAILED(hr)) goto end;
2477
2478     hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
2479     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2480
2481     hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
2482     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2483
2484     hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
2485     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2486
2487     hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
2488     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2489
2490     hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
2491     todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2492
2493     hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
2494     todo_wine ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2495
2496     if (FAILED(hr))
2497     {
2498         skip("D3DXCreateBox failed\n");
2499         goto end;
2500     }
2501
2502     buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
2503     for(i=0; i<36; i++)
2504         todo_wine ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
2505
2506     box->lpVtbl->Release(box);
2507
2508 end:
2509     IDirect3DDevice9_Release(device);
2510     IDirect3D9_Release(d3d);
2511     ID3DXBuffer_Release(ppBuffer);
2512     DestroyWindow(wnd);
2513 }
2514
2515 struct sincos_table
2516 {
2517     float *sin;
2518     float *cos;
2519 };
2520
2521 static void free_sincos_table(struct sincos_table *sincos_table)
2522 {
2523     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
2524     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2525 }
2526
2527 /* pre compute sine and cosine tables; caller must free */
2528 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
2529 {
2530     float angle;
2531     int i;
2532
2533     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2534     if (!sincos_table->sin)
2535     {
2536         return FALSE;
2537     }
2538     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2539     if (!sincos_table->cos)
2540     {
2541         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2542         return FALSE;
2543     }
2544
2545     angle = angle_start;
2546     for (i = 0; i < n; i++)
2547     {
2548         sincos_table->sin[i] = sin(angle);
2549         sincos_table->cos[i] = cos(angle);
2550         angle += angle_step;
2551     }
2552
2553     return TRUE;
2554 }
2555
2556 static WORD vertex_index(UINT slices, int slice, int stack)
2557 {
2558     return stack*slices+slice+1;
2559 }
2560
2561 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
2562 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
2563 {
2564     float theta_step, theta_start;
2565     struct sincos_table theta;
2566     float phi_step, phi_start;
2567     struct sincos_table phi;
2568     DWORD number_of_vertices, number_of_faces;
2569     DWORD vertex, face;
2570     int slice, stack;
2571
2572     /* theta = angle on xy plane wrt x axis */
2573     theta_step = M_PI / stacks;
2574     theta_start = theta_step;
2575
2576     /* phi = angle on xz plane wrt z axis */
2577     phi_step = -2 * M_PI / slices;
2578     phi_start = M_PI / 2;
2579
2580     if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
2581     {
2582         return FALSE;
2583     }
2584     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
2585     {
2586         free_sincos_table(&theta);
2587         return FALSE;
2588     }
2589
2590     number_of_vertices = 2 + slices * (stacks-1);
2591     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
2592
2593     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2594     {
2595         free_sincos_table(&phi);
2596         free_sincos_table(&theta);
2597         return FALSE;
2598     }
2599
2600     vertex = 0;
2601     face = 0;
2602
2603     mesh->vertices[vertex].normal.x = 0.0f;
2604     mesh->vertices[vertex].normal.y = 0.0f;
2605     mesh->vertices[vertex].normal.z = 1.0f;
2606     mesh->vertices[vertex].position.x = 0.0f;
2607     mesh->vertices[vertex].position.y = 0.0f;
2608     mesh->vertices[vertex].position.z = radius;
2609     vertex++;
2610
2611     for (stack = 0; stack < stacks - 1; stack++)
2612     {
2613         for (slice = 0; slice < slices; slice++)
2614         {
2615             mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
2616             mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
2617             mesh->vertices[vertex].normal.z = theta.cos[stack];
2618             mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
2619             mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
2620             mesh->vertices[vertex].position.z = radius * theta.cos[stack];
2621             vertex++;
2622
2623             if (slice > 0)
2624             {
2625                 if (stack == 0)
2626                 {
2627                     /* top stack is triangle fan */
2628                     mesh->faces[face][0] = 0;
2629                     mesh->faces[face][1] = slice + 1;
2630                     mesh->faces[face][2] = slice;
2631                     face++;
2632                 }
2633                 else
2634                 {
2635                     /* stacks in between top and bottom are quad strips */
2636                     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2637                     mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2638                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2639                     face++;
2640
2641                     mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2642                     mesh->faces[face][1] = vertex_index(slices, slice, stack);
2643                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2644                     face++;
2645                 }
2646             }
2647         }
2648
2649         if (stack == 0)
2650         {
2651             mesh->faces[face][0] = 0;
2652             mesh->faces[face][1] = 1;
2653             mesh->faces[face][2] = slice;
2654             face++;
2655         }
2656         else
2657         {
2658             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2659             mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2660             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2661             face++;
2662
2663             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2664             mesh->faces[face][1] = vertex_index(slices, 0, stack);
2665             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2666             face++;
2667         }
2668     }
2669
2670     mesh->vertices[vertex].position.x = 0.0f;
2671     mesh->vertices[vertex].position.y = 0.0f;
2672     mesh->vertices[vertex].position.z = -radius;
2673     mesh->vertices[vertex].normal.x = 0.0f;
2674     mesh->vertices[vertex].normal.y = 0.0f;
2675     mesh->vertices[vertex].normal.z = -1.0f;
2676
2677     /* bottom stack is triangle fan */
2678     for (slice = 1; slice < slices; slice++)
2679     {
2680         mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2681         mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2682         mesh->faces[face][2] = vertex;
2683         face++;
2684     }
2685
2686     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2687     mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2688     mesh->faces[face][2] = vertex;
2689
2690     free_sincos_table(&phi);
2691     free_sincos_table(&theta);
2692
2693     return TRUE;
2694 }
2695
2696 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
2697 {
2698     HRESULT hr;
2699     ID3DXMesh *sphere;
2700     struct mesh mesh;
2701     char name[256];
2702
2703     hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
2704     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2705     if (hr != D3D_OK)
2706     {
2707         skip("Couldn't create sphere\n");
2708         return;
2709     }
2710
2711     if (!compute_sphere(&mesh, radius, slices, stacks))
2712     {
2713         skip("Couldn't create mesh\n");
2714         sphere->lpVtbl->Release(sphere);
2715         return;
2716     }
2717
2718     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2719
2720     sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
2721     compare_mesh(name, sphere, &mesh);
2722
2723     free_mesh(&mesh);
2724
2725     sphere->lpVtbl->Release(sphere);
2726 }
2727
2728 static void D3DXCreateSphereTest(void)
2729 {
2730     HRESULT hr;
2731     HWND wnd;
2732     IDirect3D9* d3d;
2733     IDirect3DDevice9* device;
2734     D3DPRESENT_PARAMETERS d3dpp;
2735     ID3DXMesh* sphere = NULL;
2736
2737     hr = D3DXCreateSphere(NULL, 0.0f, 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.1f, 0, 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, 1, 0, NULL, NULL);
2744     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2745
2746     hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
2747     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2748
2749     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
2750     d3d = Direct3DCreate9(D3D_SDK_VERSION);
2751     if (!wnd)
2752     {
2753         skip("Couldn't create application window\n");
2754         return;
2755     }
2756     if (!d3d)
2757     {
2758         skip("Couldn't create IDirect3D9 object\n");
2759         DestroyWindow(wnd);
2760         return;
2761     }
2762
2763     ZeroMemory(&d3dpp, sizeof(d3dpp));
2764     d3dpp.Windowed = TRUE;
2765     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2766     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2767     if (FAILED(hr))
2768     {
2769         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2770         IDirect3D9_Release(d3d);
2771         DestroyWindow(wnd);
2772         return;
2773     }
2774
2775     hr = D3DXCreateSphere(device, 1.0f, 1, 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, 2, 1, &sphere, NULL);
2779     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2780
2781     hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
2782     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2783
2784     hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
2785     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2786
2787     test_sphere(device, 0.0f, 2, 2);
2788     test_sphere(device, 1.0f, 2, 2);
2789     test_sphere(device, 1.0f, 3, 2);
2790     test_sphere(device, 1.0f, 4, 4);
2791     test_sphere(device, 1.0f, 3, 4);
2792     test_sphere(device, 5.0f, 6, 7);
2793     test_sphere(device, 10.0f, 11, 12);
2794
2795     IDirect3DDevice9_Release(device);
2796     IDirect3D9_Release(d3d);
2797     DestroyWindow(wnd);
2798 }
2799
2800 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
2801 {
2802     float theta_step, theta_start;
2803     struct sincos_table theta;
2804     FLOAT delta_radius, radius, radius_step;
2805     FLOAT z, z_step, z_normal;
2806     DWORD number_of_vertices, number_of_faces;
2807     DWORD vertex, face;
2808     int slice, stack;
2809
2810     /* theta = angle on xy plane wrt x axis */
2811     theta_step = -2 * M_PI / slices;
2812     theta_start = M_PI / 2;
2813
2814     if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
2815     {
2816         return FALSE;
2817     }
2818
2819     number_of_vertices = 2 + (slices * (3 + stacks));
2820     number_of_faces = 2 * slices + stacks * (2 * slices);
2821
2822     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2823     {
2824         free_sincos_table(&theta);
2825         return FALSE;
2826     }
2827
2828     vertex = 0;
2829     face = 0;
2830
2831     delta_radius = radius1 - radius2;
2832     radius = radius1;
2833     radius_step = delta_radius / stacks;
2834
2835     z = -length / 2;
2836     z_step = length / stacks;
2837     z_normal = delta_radius / length;
2838     if (isnan(z_normal))
2839     {
2840         z_normal = 0.0f;
2841     }
2842
2843     mesh->vertices[vertex].normal.x = 0.0f;
2844     mesh->vertices[vertex].normal.y = 0.0f;
2845     mesh->vertices[vertex].normal.z = -1.0f;
2846     mesh->vertices[vertex].position.x = 0.0f;
2847     mesh->vertices[vertex].position.y = 0.0f;
2848     mesh->vertices[vertex++].position.z = z;
2849
2850     for (slice = 0; slice < slices; slice++, vertex++)
2851     {
2852         mesh->vertices[vertex].normal.x = 0.0f;
2853         mesh->vertices[vertex].normal.y = 0.0f;
2854         mesh->vertices[vertex].normal.z = -1.0f;
2855         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2856         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2857         mesh->vertices[vertex].position.z = z;
2858
2859         if (slice > 0)
2860         {
2861             mesh->faces[face][0] = 0;
2862             mesh->faces[face][1] = slice;
2863             mesh->faces[face++][2] = slice + 1;
2864         }
2865     }
2866
2867     mesh->faces[face][0] = 0;
2868     mesh->faces[face][1] = slice;
2869     mesh->faces[face++][2] = 1;
2870
2871     for (stack = 1; stack <= stacks+1; stack++)
2872     {
2873         for (slice = 0; slice < slices; slice++, vertex++)
2874         {
2875             mesh->vertices[vertex].normal.x = theta.cos[slice];
2876             mesh->vertices[vertex].normal.y = theta.sin[slice];
2877             mesh->vertices[vertex].normal.z = z_normal;
2878             D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
2879             mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2880             mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2881             mesh->vertices[vertex].position.z = z;
2882
2883             if (stack > 1 && slice > 0)
2884             {
2885                 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2886                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2887                 mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
2888
2889                 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2890                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2891                 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
2892             }
2893         }
2894
2895         if (stack > 1)
2896         {
2897             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2898             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2899             mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
2900
2901             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2902             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2903             mesh->faces[face++][2] = vertex_index(slices, 0, stack);
2904         }
2905
2906         if (stack < stacks + 1)
2907         {
2908             z += z_step;
2909             radius -= radius_step;
2910         }
2911     }
2912
2913     for (slice = 0; slice < slices; slice++, vertex++)
2914     {
2915         mesh->vertices[vertex].normal.x = 0.0f;
2916         mesh->vertices[vertex].normal.y = 0.0f;
2917         mesh->vertices[vertex].normal.z = 1.0f;
2918         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2919         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2920         mesh->vertices[vertex].position.z = z;
2921
2922         if (slice > 0)
2923         {
2924             mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
2925             mesh->faces[face][1] = number_of_vertices - 1;
2926             mesh->faces[face++][2] = vertex_index(slices, slice, stack);
2927         }
2928     }
2929
2930     mesh->vertices[vertex].position.x = 0.0f;
2931     mesh->vertices[vertex].position.y = 0.0f;
2932     mesh->vertices[vertex].position.z = z;
2933     mesh->vertices[vertex].normal.x = 0.0f;
2934     mesh->vertices[vertex].normal.y = 0.0f;
2935     mesh->vertices[vertex].normal.z = 1.0f;
2936
2937     mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
2938     mesh->faces[face][1] = number_of_vertices - 1;
2939     mesh->faces[face][2] = vertex_index(slices, 0, stack);
2940
2941     free_sincos_table(&theta);
2942
2943     return TRUE;
2944 }
2945
2946 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
2947 {
2948     HRESULT hr;
2949     ID3DXMesh *cylinder;
2950     struct mesh mesh;
2951     char name[256];
2952
2953     hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
2954     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2955     if (hr != D3D_OK)
2956     {
2957         skip("Couldn't create cylinder\n");
2958         return;
2959     }
2960
2961     if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
2962     {
2963         skip("Couldn't create mesh\n");
2964         cylinder->lpVtbl->Release(cylinder);
2965         return;
2966     }
2967
2968     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2969
2970     sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
2971     compare_mesh(name, cylinder, &mesh);
2972
2973     free_mesh(&mesh);
2974
2975     cylinder->lpVtbl->Release(cylinder);
2976 }
2977
2978 static void D3DXCreateCylinderTest(void)
2979 {
2980     HRESULT hr;
2981     HWND wnd;
2982     IDirect3D9* d3d;
2983     IDirect3DDevice9* device;
2984     D3DPRESENT_PARAMETERS d3dpp;
2985     ID3DXMesh* cylinder = NULL;
2986
2987     hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
2988     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2989
2990     hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
2991     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2992
2993     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
2994     d3d = Direct3DCreate9(D3D_SDK_VERSION);
2995     if (!wnd)
2996     {
2997         skip("Couldn't create application window\n");
2998         return;
2999     }
3000     if (!d3d)
3001     {
3002         skip("Couldn't create IDirect3D9 object\n");
3003         DestroyWindow(wnd);
3004         return;
3005     }
3006
3007     ZeroMemory(&d3dpp, sizeof(d3dpp));
3008     d3dpp.Windowed = TRUE;
3009     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
3010     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
3011     if (FAILED(hr))
3012     {
3013         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
3014         IDirect3D9_Release(d3d);
3015         DestroyWindow(wnd);
3016         return;
3017     }
3018
3019     hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3020     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3021
3022     hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3023     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3024
3025     if (SUCCEEDED(hr) && cylinder)
3026     {
3027         cylinder->lpVtbl->Release(cylinder);
3028     }
3029
3030     hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
3031     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3032
3033     hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
3034     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3035
3036     if (SUCCEEDED(hr) && cylinder)
3037     {
3038         cylinder->lpVtbl->Release(cylinder);
3039     }
3040
3041     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
3042     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3043
3044     /* Test with length == 0.0f succeeds */
3045     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
3046     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3047
3048     if (SUCCEEDED(hr) && cylinder)
3049     {
3050         cylinder->lpVtbl->Release(cylinder);
3051     }
3052
3053     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &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, 0, &cylinder, NULL);
3057     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3058
3059     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
3060     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3061
3062     test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
3063     test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
3064     test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
3065     test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
3066     test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
3067     test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
3068
3069     IDirect3DDevice9_Release(device);
3070     IDirect3D9_Release(d3d);
3071     DestroyWindow(wnd);
3072 }
3073
3074 struct dynamic_array
3075 {
3076     int count, capacity;
3077     void *items;
3078 };
3079
3080 enum pointtype {
3081     POINTTYPE_CURVE = 0,
3082     POINTTYPE_CORNER,
3083     POINTTYPE_CURVE_START,
3084     POINTTYPE_CURVE_END,
3085     POINTTYPE_CURVE_MIDDLE,
3086 };
3087
3088 struct point2d
3089 {
3090     D3DXVECTOR2 pos;
3091     enum pointtype corner;
3092 };
3093
3094 /* is a dynamic_array */
3095 struct outline
3096 {
3097     int count, capacity;
3098     struct point2d *items;
3099 };
3100
3101 /* is a dynamic_array */
3102 struct outline_array
3103 {
3104     int count, capacity;
3105     struct outline *items;
3106 };
3107
3108 struct glyphinfo
3109 {
3110     struct outline_array outlines;
3111     float offset_x;
3112 };
3113
3114 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
3115 {
3116     if (count > array->capacity) {
3117         void *new_buffer;
3118         int new_capacity;
3119         if (array->items && array->capacity) {
3120             new_capacity = max(array->capacity * 2, count);
3121             new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
3122         } else {
3123             new_capacity = max(16, count);
3124             new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
3125         }
3126         if (!new_buffer)
3127             return FALSE;
3128         array->items = new_buffer;
3129         array->capacity = new_capacity;
3130     }
3131     return TRUE;
3132 }
3133
3134 static struct point2d *add_point(struct outline *array)
3135 {
3136     struct point2d *item;
3137
3138     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3139         return NULL;
3140
3141     item = &array->items[array->count++];
3142     ZeroMemory(item, sizeof(*item));
3143     return item;
3144 }
3145
3146 static struct outline *add_outline(struct outline_array *array)
3147 {
3148     struct outline *item;
3149
3150     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3151         return NULL;
3152
3153     item = &array->items[array->count++];
3154     ZeroMemory(item, sizeof(*item));
3155     return item;
3156 }
3157
3158 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
3159 {
3160     D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
3161     while (count--) {
3162         D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
3163         pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
3164         pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
3165         pt++;
3166     }
3167     return ret;
3168 }
3169
3170 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
3171                                  const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
3172                                  float max_deviation)
3173 {
3174     D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
3175     float deviation;
3176
3177     D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
3178     D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
3179     D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
3180
3181     deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
3182     if (deviation < max_deviation) {
3183         struct point2d *pt = add_point(outline);
3184         if (!pt) return E_OUTOFMEMORY;
3185         pt->pos = *p2;
3186         pt->corner = POINTTYPE_CURVE;
3187         /* the end point is omitted because the end line merges into the next segment of
3188          * the split bezier curve, and the end of the split bezier curve is added outside
3189          * this recursive function. */
3190     } else {
3191         HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
3192         if (hr != S_OK) return hr;
3193         hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
3194         if (hr != S_OK) return hr;
3195     }
3196
3197     return S_OK;
3198 }
3199
3200 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
3201 {
3202     /* dot product = cos(theta) */
3203     return D3DXVec2Dot(dir1, dir2) > cos_theta;
3204 }
3205
3206 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
3207 {
3208     return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
3209 }
3210
3211 static BOOL attempt_line_merge(struct outline *outline,
3212                                int pt_index,
3213                                const D3DXVECTOR2 *nextpt,
3214                                BOOL to_curve)
3215 {
3216     D3DXVECTOR2 curdir, lastdir;
3217     struct point2d *prevpt, *pt;
3218     BOOL ret = FALSE;
3219     const float cos_half = cos(D3DXToRadian(0.5f));
3220
3221     pt = &outline->items[pt_index];
3222     pt_index = (pt_index - 1 + outline->count) % outline->count;
3223     prevpt = &outline->items[pt_index];
3224
3225     if (to_curve)
3226         pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
3227
3228     if (outline->count < 2)
3229         return FALSE;
3230
3231     /* remove last point if the next line continues the last line */
3232     unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3233     unit_vec2(&curdir, &pt->pos, nextpt);
3234     if (is_direction_similar(&lastdir, &curdir, cos_half))
3235     {
3236         outline->count--;
3237         if (pt->corner == POINTTYPE_CURVE_END)
3238             prevpt->corner = pt->corner;
3239         if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
3240             prevpt->corner = POINTTYPE_CURVE_MIDDLE;
3241         pt = prevpt;
3242
3243         ret = TRUE;
3244         if (outline->count < 2)
3245             return ret;
3246
3247         pt_index = (pt_index - 1 + outline->count) % outline->count;
3248         prevpt = &outline->items[pt_index];
3249         unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3250         unit_vec2(&curdir, &pt->pos, nextpt);
3251     }
3252     return ret;
3253 }
3254
3255 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
3256                               float max_deviation, float emsquare)
3257 {
3258     const float cos_45 = cos(D3DXToRadian(45.0f));
3259     const float cos_90 = cos(D3DXToRadian(90.0f));
3260     TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
3261
3262     while ((char *)header < (char *)raw_outline + datasize)
3263     {
3264         TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
3265         struct point2d *lastpt, *pt;
3266         D3DXVECTOR2 lastdir;
3267         D3DXVECTOR2 *pt_flt;
3268         int j;
3269         struct outline *outline = add_outline(&glyph->outlines);
3270
3271         if (!outline)
3272             return E_OUTOFMEMORY;
3273
3274         pt = add_point(outline);
3275         if (!pt)
3276             return E_OUTOFMEMORY;
3277         pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
3278         pt->pos = *pt_flt;
3279         pt->corner = POINTTYPE_CORNER;
3280
3281         if (header->dwType != TT_POLYGON_TYPE)
3282             trace("Unknown header type %d\n", header->dwType);
3283
3284         while ((char *)curve < (char *)header + header->cb)
3285         {
3286             D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
3287             BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
3288
3289             if (!curve->cpfx) {
3290                 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3291                 continue;
3292             }
3293
3294             pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
3295
3296             attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
3297
3298             if (to_curve)
3299             {
3300                 HRESULT hr;
3301                 int count = curve->cpfx;
3302                 j = 0;
3303
3304                 while (count > 2)
3305                 {
3306                     D3DXVECTOR2 bezier_end;
3307
3308                     D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
3309                     hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
3310                     if (hr != S_OK)
3311                         return hr;
3312                     bezier_start = bezier_end;
3313                     count--;
3314                     j++;
3315                 }
3316                 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
3317                 if (hr != S_OK)
3318                     return hr;
3319
3320                 pt = add_point(outline);
3321                 if (!pt)
3322                     return E_OUTOFMEMORY;
3323                 j++;
3324                 pt->pos = pt_flt[j];
3325                 pt->corner = POINTTYPE_CURVE_END;
3326             } else {
3327                 for (j = 0; j < curve->cpfx; j++)
3328                 {
3329                     pt = add_point(outline);
3330                     if (!pt)
3331                         return E_OUTOFMEMORY;
3332                     pt->pos = pt_flt[j];
3333                     pt->corner = POINTTYPE_CORNER;
3334                 }
3335             }
3336
3337             curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3338         }
3339
3340         /* remove last point if the next line continues the last line */
3341         if (outline->count >= 3) {
3342             BOOL to_curve;
3343
3344             lastpt = &outline->items[outline->count - 1];
3345             pt = &outline->items[0];
3346             if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
3347                 if (lastpt->corner == POINTTYPE_CURVE_END)
3348                 {
3349                     if (pt->corner == POINTTYPE_CURVE_START)
3350                         pt->corner = POINTTYPE_CURVE_MIDDLE;
3351                     else
3352                         pt->corner = POINTTYPE_CURVE_END;
3353                 }
3354                 outline->count--;
3355                 lastpt = &outline->items[outline->count - 1];
3356             } else {
3357                 /* outline closed with a line from end to start point */
3358                 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
3359             }
3360             lastpt = &outline->items[0];
3361             to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
3362             if (lastpt->corner == POINTTYPE_CURVE_START)
3363                 lastpt->corner = POINTTYPE_CORNER;
3364             pt = &outline->items[1];
3365             if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
3366                 *lastpt = outline->items[outline->count];
3367         }
3368
3369         lastpt = &outline->items[outline->count - 1];
3370         pt = &outline->items[0];
3371         unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
3372         for (j = 0; j < outline->count; j++)
3373         {
3374             D3DXVECTOR2 curdir;
3375
3376             lastpt = pt;
3377             pt = &outline->items[(j + 1) % outline->count];
3378             unit_vec2(&curdir, &lastpt->pos, &pt->pos);
3379
3380             switch (lastpt->corner)
3381             {
3382                 case POINTTYPE_CURVE_START:
3383                 case POINTTYPE_CURVE_END:
3384                     if (!is_direction_similar(&lastdir, &curdir, cos_45))
3385                         lastpt->corner = POINTTYPE_CORNER;
3386                     break;
3387                 case POINTTYPE_CURVE_MIDDLE:
3388                     if (!is_direction_similar(&lastdir, &curdir, cos_90))
3389                         lastpt->corner = POINTTYPE_CORNER;
3390                     else
3391                         lastpt->corner = POINTTYPE_CURVE;
3392                     break;
3393                 default:
3394                     break;
3395             }
3396             lastdir = curdir;
3397         }
3398
3399         header = (TTPOLYGONHEADER *)((char *)header + header->cb);
3400     }
3401     return S_OK;
3402 }
3403
3404 static BOOL compute_text_mesh(struct mesh *mesh, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion, FLOAT otmEMSquare)
3405 {
3406     HRESULT hr = E_FAIL;
3407     DWORD nb_vertices, nb_faces;
3408     DWORD nb_corners, nb_outline_points;
3409     int textlen = 0;
3410     float offset_x;
3411     char *raw_outline = NULL;
3412     struct glyphinfo *glyphs = NULL;
3413     GLYPHMETRICS gm;
3414     int i;
3415     struct vertex *vertex_ptr;
3416     face *face_ptr;
3417
3418     if (deviation == 0.0f)
3419         deviation = 1.0f / otmEMSquare;
3420
3421     textlen = strlen(text);
3422     glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
3423     if (!glyphs) {
3424         hr = E_OUTOFMEMORY;
3425         goto error;
3426     }
3427
3428     offset_x = 0.0f;
3429     for (i = 0; i < textlen; i++)
3430     {
3431         /* get outline points from data returned from GetGlyphOutline */
3432         const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
3433         int datasize;
3434
3435         glyphs[i].offset_x = offset_x;
3436
3437         datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
3438         if (datasize < 0) {
3439             hr = E_FAIL;
3440             goto error;
3441         }
3442         HeapFree(GetProcessHeap(), 0, raw_outline);
3443         raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
3444         if (!glyphs) {
3445             hr = E_OUTOFMEMORY;
3446             goto error;
3447         }
3448         datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
3449
3450         create_outline(&glyphs[i], raw_outline, datasize, deviation, otmEMSquare);
3451
3452         offset_x += gm.gmCellIncX / (float)otmEMSquare;
3453     }
3454
3455     /* corner points need an extra vertex for the different side faces normals */
3456     nb_corners = 0;
3457     nb_outline_points = 0;
3458     for (i = 0; i < textlen; i++)
3459     {
3460         int j;
3461         for (j = 0; j < glyphs[i].outlines.count; j++)
3462         {
3463             int k;
3464             struct outline *outline = &glyphs[i].outlines.items[j];
3465             nb_outline_points += outline->count;
3466             nb_corners++; /* first outline point always repeated as a corner */
3467             for (k = 1; k < outline->count; k++)
3468                 if (outline->items[k].corner)
3469                     nb_corners++;
3470         }
3471     }
3472
3473     nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
3474     nb_faces = nb_outline_points * 2;
3475
3476     if (!new_mesh(mesh, nb_vertices, nb_faces))
3477         goto error;
3478
3479     /* convert 2D vertices and faces into 3D mesh */
3480     vertex_ptr = mesh->vertices;
3481     face_ptr = mesh->faces;
3482     for (i = 0; i < textlen; i++)
3483     {
3484         int j;
3485
3486         /* side vertices and faces */
3487         for (j = 0; j < glyphs[i].outlines.count; j++)
3488         {
3489             struct vertex *outline_vertices = vertex_ptr;
3490             struct outline *outline = &glyphs[i].outlines.items[j];
3491             int k;
3492             struct point2d *prevpt = &outline->items[outline->count - 1];
3493             struct point2d *pt = &outline->items[0];
3494
3495             for (k = 1; k <= outline->count; k++)
3496             {
3497                 struct vertex vtx;
3498                 struct point2d *nextpt = &outline->items[k % outline->count];
3499                 WORD vtx_idx = vertex_ptr - mesh->vertices;
3500                 D3DXVECTOR2 vec;
3501
3502                 if (pt->corner == POINTTYPE_CURVE_START)
3503                     D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
3504                 else if (pt->corner)
3505                     D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3506                 else
3507                     D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
3508                 D3DXVec2Normalize(&vec, &vec);
3509                 vtx.normal.x = -vec.y;
3510                 vtx.normal.y = vec.x;
3511                 vtx.normal.z = 0;
3512
3513                 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
3514                 vtx.position.y = pt->pos.y;
3515                 vtx.position.z = 0;
3516                 *vertex_ptr++ = vtx;
3517
3518                 vtx.position.z = -extrusion;
3519                 *vertex_ptr++ = vtx;
3520
3521                 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
3522                 vtx.position.y = nextpt->pos.y;
3523                 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
3524                     vtx.position.z = -extrusion;
3525                     *vertex_ptr++ = vtx;
3526                     vtx.position.z = 0;
3527                     *vertex_ptr++ = vtx;
3528
3529                     (*face_ptr)[0] = vtx_idx;
3530                     (*face_ptr)[1] = vtx_idx + 2;
3531                     (*face_ptr)[2] = vtx_idx + 1;
3532                     face_ptr++;
3533
3534                     (*face_ptr)[0] = vtx_idx;
3535                     (*face_ptr)[1] = vtx_idx + 3;
3536                     (*face_ptr)[2] = vtx_idx + 2;
3537                     face_ptr++;
3538                 } else {
3539                     if (nextpt->corner) {
3540                         if (nextpt->corner == POINTTYPE_CURVE_END) {
3541                             struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
3542                             D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
3543                         } else {
3544                             D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3545                         }
3546                         D3DXVec2Normalize(&vec, &vec);
3547                         vtx.normal.x = -vec.y;
3548                         vtx.normal.y = vec.x;
3549
3550                         vtx.position.z = 0;
3551                         *vertex_ptr++ = vtx;
3552                         vtx.position.z = -extrusion;
3553                         *vertex_ptr++ = vtx;
3554                     }
3555
3556                     (*face_ptr)[0] = vtx_idx;
3557                     (*face_ptr)[1] = vtx_idx + 3;
3558                     (*face_ptr)[2] = vtx_idx + 1;
3559                     face_ptr++;
3560
3561                     (*face_ptr)[0] = vtx_idx;
3562                     (*face_ptr)[1] = vtx_idx + 2;
3563                     (*face_ptr)[2] = vtx_idx + 3;
3564                     face_ptr++;
3565                 }
3566
3567                 prevpt = pt;
3568                 pt = nextpt;
3569             }
3570             if (!pt->corner) {
3571                 *vertex_ptr++ = *outline_vertices++;
3572                 *vertex_ptr++ = *outline_vertices++;
3573             }
3574         }
3575
3576         /* FIXME: compute expected faces */
3577         /* Add placeholder to separate glyph outlines */
3578         vertex_ptr->position.x = 0;
3579         vertex_ptr->position.y = 0;
3580         vertex_ptr->position.z = 0;
3581         vertex_ptr->normal.x = 0;
3582         vertex_ptr->normal.y = 0;
3583         vertex_ptr->normal.z = 1;
3584         vertex_ptr++;
3585     }
3586
3587     hr = D3D_OK;
3588 error:
3589     if (glyphs) {
3590         for (i = 0; i < textlen; i++)
3591         {
3592             int j;
3593             for (j = 0; j < glyphs[i].outlines.count; j++)
3594                 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items[j].items);
3595             HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items);
3596         }
3597         HeapFree(GetProcessHeap(), 0, glyphs);
3598     }
3599     HeapFree(GetProcessHeap(), 0, raw_outline);
3600
3601     return hr == D3D_OK;
3602 }
3603
3604 static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh, int textlen, float extrusion)
3605 {
3606     HRESULT hr;
3607     DWORD number_of_vertices, number_of_faces;
3608     IDirect3DVertexBuffer9 *vertex_buffer = NULL;
3609     IDirect3DIndexBuffer9 *index_buffer = NULL;
3610     D3DVERTEXBUFFER_DESC vertex_buffer_description;
3611     D3DINDEXBUFFER_DESC index_buffer_description;
3612     struct vertex *vertices = NULL;
3613     face *faces = NULL;
3614     int expected, i;
3615     int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
3616
3617     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
3618     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
3619
3620     /* vertex buffer */
3621     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
3622     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3623     if (hr != D3D_OK)
3624     {
3625         skip("Couldn't get vertex buffers\n");
3626         goto error;
3627     }
3628
3629     hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
3630     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3631
3632     if (hr != D3D_OK)
3633     {
3634         skip("Couldn't get vertex buffer description\n");
3635     }
3636     else
3637     {
3638         ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
3639            name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
3640         ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
3641            name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
3642         ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
3643         ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
3644            name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
3645         ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
3646            name, vertex_buffer_description.FVF, mesh->fvf);
3647         if (mesh->fvf == 0)
3648         {
3649             expected = number_of_vertices * mesh->vertex_size;
3650         }
3651         else
3652         {
3653             expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
3654         }
3655         ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
3656            name, vertex_buffer_description.Size, expected);
3657     }
3658
3659     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
3660     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3661     if (hr != D3D_OK)
3662     {
3663         skip("Couldn't get index buffer\n");
3664         goto error;
3665     }
3666
3667     hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
3668     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3669
3670     if (hr != D3D_OK)
3671     {
3672         skip("Couldn't get index buffer description\n");
3673     }
3674     else
3675     {
3676         ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
3677            name, index_buffer_description.Format, D3DFMT_INDEX16);
3678         ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
3679            name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
3680         ok(index_buffer_description.Usage == 0, "Test %s, result %#x, expected %#x.\n",
3681                 name, index_buffer_description.Usage, 0);
3682         ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
3683            name, index_buffer_description.Pool, D3DPOOL_MANAGED);
3684         expected = number_of_faces * sizeof(WORD) * 3;
3685         ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
3686            name, index_buffer_description.Size, expected);
3687     }
3688
3689     /* specify offset and size to avoid potential overruns */
3690     hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
3691                                      (LPVOID *)&vertices, D3DLOCK_DISCARD);
3692     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3693     if (hr != D3D_OK)
3694     {
3695         skip("Couldn't lock vertex buffer\n");
3696         goto error;
3697     }
3698     hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
3699                                     (LPVOID *)&faces, D3DLOCK_DISCARD);
3700     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3701     if (hr != D3D_OK)
3702     {
3703         skip("Couldn't lock index buffer\n");
3704         goto error;
3705     }
3706
3707     face_idx1 = 0;
3708     vtx_idx2 = 0;
3709     face_idx2 = 0;
3710     vtx_idx1 = 0;
3711     for (i = 0; i < textlen; i++)
3712     {
3713         int nb_outline_vertices1, nb_outline_faces1;
3714         int nb_outline_vertices2, nb_outline_faces2;
3715         int nb_back_vertices, nb_back_faces;
3716         int first_vtx1, first_vtx2;
3717         int first_face1, first_face2;
3718         int j;
3719
3720         first_vtx1 = vtx_idx1;
3721         first_vtx2 = vtx_idx2;
3722         for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
3723             if (vertices[vtx_idx1].normal.z != 0)
3724                 break;
3725         }
3726         for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
3727             if (mesh->vertices[vtx_idx2].normal.z != 0)
3728                 break;
3729         }
3730         nb_outline_vertices1 = vtx_idx1 - first_vtx1;
3731         nb_outline_vertices2 = vtx_idx2 - first_vtx2;
3732         ok(nb_outline_vertices1 == nb_outline_vertices2,
3733            "Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
3734            nb_outline_vertices1, nb_outline_vertices2);
3735
3736         for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
3737         {
3738             vtx_idx1 = first_vtx1 + j;
3739             vtx_idx2 = first_vtx2 + j;
3740             ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
3741                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3742                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
3743                mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
3744             ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
3745                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3746                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3747                mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
3748         }
3749         vtx_idx1 = first_vtx1 + nb_outline_vertices1;
3750         vtx_idx2 = first_vtx2 + nb_outline_vertices2;
3751
3752         first_face1 = face_idx1;
3753         first_face2 = face_idx2;
3754         for (; face_idx1 < number_of_faces; face_idx1++)
3755         {
3756             if (faces[face_idx1][0] >= vtx_idx1 ||
3757                 faces[face_idx1][1] >= vtx_idx1 ||
3758                 faces[face_idx1][2] >= vtx_idx1)
3759                 break;
3760         }
3761         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
3762         {
3763             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
3764                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
3765                 mesh->faces[face_idx2][2] >= vtx_idx2)
3766                 break;
3767         }
3768         nb_outline_faces1 = face_idx1 - first_face1;
3769         nb_outline_faces2 = face_idx2 - first_face2;
3770         ok(nb_outline_faces1 == nb_outline_faces2,
3771            "Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
3772            nb_outline_faces1, nb_outline_faces2);
3773
3774         for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
3775         {
3776             face_idx1 = first_face1 + j;
3777             face_idx2 = first_face2 + j;
3778             ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
3779                faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
3780                faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
3781                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
3782                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
3783                mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
3784                mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
3785                mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
3786         }
3787         face_idx1 = first_face1 + nb_outline_faces1;
3788         face_idx2 = first_face2 + nb_outline_faces2;
3789
3790         /* partial test on back vertices and faces  */
3791         first_vtx1 = vtx_idx1;
3792         for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
3793             struct vertex vtx;
3794
3795             if (vertices[vtx_idx1].normal.z != 1.0f)
3796                 break;
3797
3798             vtx.position.z = 0.0f;
3799             vtx.normal.x = 0.0f;
3800             vtx.normal.y = 0.0f;
3801             vtx.normal.z = 1.0f;
3802             ok(compare(vertices[vtx_idx1].position.z, vtx.position.z),
3803                "Test %s, glyph %d, vertex position.z %d, result %g, expected %g\n", name, i, vtx_idx1,
3804                vertices[vtx_idx1].position.z, vtx.position.z);
3805             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
3806                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3807                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3808                vtx.normal.x, vtx.normal.y, vtx.normal.z);
3809         }
3810         nb_back_vertices = vtx_idx1 - first_vtx1;
3811         first_face1 = face_idx1;
3812         for (; face_idx1 < number_of_faces; face_idx1++)
3813         {
3814             const D3DXVECTOR3 *vtx1, *vtx2, *vtx3;
3815             D3DXVECTOR3 normal;
3816             D3DXVECTOR3 v1 = {0, 0, 0};
3817             D3DXVECTOR3 v2 = {0, 0, 0};
3818             D3DXVECTOR3 forward = {0.0f, 0.0f, 1.0f};
3819
3820             if (faces[face_idx1][0] >= vtx_idx1 ||
3821                 faces[face_idx1][1] >= vtx_idx1 ||
3822                 faces[face_idx1][2] >= vtx_idx1)
3823                 break;
3824
3825             vtx1 = &vertices[faces[face_idx1][0]].position;
3826             vtx2 = &vertices[faces[face_idx1][1]].position;
3827             vtx3 = &vertices[faces[face_idx1][2]].position;
3828
3829             D3DXVec3Subtract(&v1, vtx2, vtx1);
3830             D3DXVec3Subtract(&v2, vtx3, vtx2);
3831             D3DXVec3Cross(&normal, &v1, &v2);
3832             D3DXVec3Normalize(&normal, &normal);
3833             ok(!D3DXVec3Length(&normal) || compare_vec3(normal, forward),
3834                "Test %s, glyph %d, face %d normal, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, face_idx1,
3835                normal.x, normal.y, normal.z, forward.x, forward.y, forward.z);
3836         }
3837         nb_back_faces = face_idx1 - first_face1;
3838
3839         /* compare front and back faces & vertices */
3840         if (extrusion == 0.0f) {
3841             /* Oddly there are only back faces in this case */
3842             nb_back_vertices /= 2;
3843             nb_back_faces /= 2;
3844             face_idx1 -= nb_back_faces;
3845             vtx_idx1 -= nb_back_vertices;
3846         }
3847         for (j = 0; j < nb_back_vertices; j++)
3848         {
3849             struct vertex vtx = vertices[first_vtx1];
3850             vtx.position.z = -extrusion;
3851             vtx.normal.x = 0.0f;
3852             vtx.normal.y = 0.0f;
3853             vtx.normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
3854             ok(compare_vec3(vertices[vtx_idx1].position, vtx.position),
3855                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3856                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
3857                vtx.position.x, vtx.position.y, vtx.position.z);
3858             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
3859                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3860                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3861                vtx.normal.x, vtx.normal.y, vtx.normal.z);
3862             vtx_idx1++;
3863             first_vtx1++;
3864         }
3865         for (j = 0; j < nb_back_faces; j++)
3866         {
3867             int f1, f2;
3868             if (extrusion == 0.0f) {
3869                 f1 = 1;
3870                 f2 = 2;
3871             } else {
3872                 f1 = 2;
3873                 f2 = 1;
3874             }
3875             ok(faces[face_idx1][0] == faces[first_face1][0] + nb_back_vertices &&
3876                faces[face_idx1][1] == faces[first_face1][f1] + nb_back_vertices &&
3877                faces[face_idx1][2] == faces[first_face1][f2] + nb_back_vertices,
3878                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
3879                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
3880                faces[first_face1][0] - nb_back_faces,
3881                faces[first_face1][f1] - nb_back_faces,
3882                faces[first_face1][f2] - nb_back_faces);
3883             first_face1++;
3884             face_idx1++;
3885         }
3886
3887         /* skip to the outline for the next glyph */
3888         for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
3889             if (mesh->vertices[vtx_idx2].normal.z == 0)
3890                 break;
3891         }
3892         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
3893         {
3894             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
3895                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
3896                 mesh->faces[face_idx2][2] >= vtx_idx2) break;
3897         }
3898     }
3899
3900 error:
3901     if (vertices) IDirect3DVertexBuffer9_Unlock(vertex_buffer);
3902     if (faces) IDirect3DIndexBuffer9_Unlock(index_buffer);
3903     if (index_buffer) IDirect3DIndexBuffer9_Release(index_buffer);
3904     if (vertex_buffer) IDirect3DVertexBuffer9_Release(vertex_buffer);
3905 }
3906
3907 static void test_createtext(IDirect3DDevice9 *device, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion)
3908 {
3909     HRESULT hr;
3910     ID3DXMesh *d3dxmesh;
3911     struct mesh mesh;
3912     char name[256];
3913     OUTLINETEXTMETRIC otm;
3914     GLYPHMETRICS gm;
3915     GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
3916     int i;
3917     LOGFONT lf;
3918     HFONT font = NULL, oldfont = NULL;
3919
3920     sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion);
3921
3922     hr = D3DXCreateText(device, hdc, text, deviation, extrusion, &d3dxmesh, NULL, glyphmetrics_float);
3923     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3924     if (hr != D3D_OK)
3925     {
3926         skip("Couldn't create text with D3DXCreateText\n");
3927         return;
3928     }
3929
3930     /* must select a modified font having lfHeight = otm.otmEMSquare before
3931      * calling GetGlyphOutline to get the expected values */
3932     if (!GetObject(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf) ||
3933         !GetOutlineTextMetrics(hdc, sizeof(otm), &otm))
3934     {
3935         d3dxmesh->lpVtbl->Release(d3dxmesh);
3936         skip("Couldn't get text outline\n");
3937         return;
3938     }
3939     lf.lfHeight = otm.otmEMSquare;
3940     lf.lfWidth = 0;
3941     font = CreateFontIndirect(&lf);
3942     if (!font) {
3943         d3dxmesh->lpVtbl->Release(d3dxmesh);
3944         skip("Couldn't create the modified font\n");
3945         return;
3946     }
3947     oldfont = SelectObject(hdc, font);
3948
3949     for (i = 0; i < strlen(text); i++)
3950     {
3951         const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
3952         GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
3953         compare_float(glyphmetrics_float[i].gmfBlackBoxX, gm.gmBlackBoxX / (float)otm.otmEMSquare);
3954         compare_float(glyphmetrics_float[i].gmfBlackBoxY, gm.gmBlackBoxY / (float)otm.otmEMSquare);
3955         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.x, gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare);
3956         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.y, gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare);
3957         compare_float(glyphmetrics_float[i].gmfCellIncX, gm.gmCellIncX / (float)otm.otmEMSquare);
3958         compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
3959     }
3960
3961     ZeroMemory(&mesh, sizeof(mesh));
3962     if (!compute_text_mesh(&mesh, hdc, text, deviation, extrusion, otm.otmEMSquare))
3963     {
3964         skip("Couldn't create mesh\n");
3965         d3dxmesh->lpVtbl->Release(d3dxmesh);
3966         return;
3967     }
3968     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3969
3970     compare_text_outline_mesh(name, d3dxmesh, &mesh, strlen(text), extrusion);
3971
3972     free_mesh(&mesh);
3973
3974     d3dxmesh->lpVtbl->Release(d3dxmesh);
3975     SelectObject(hdc, oldfont);
3976     HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
3977 }
3978
3979 static void D3DXCreateTextTest(void)
3980 {
3981     HRESULT hr;
3982     HWND wnd;
3983     HDC hdc;
3984     IDirect3D9* d3d;
3985     IDirect3DDevice9* device;
3986     D3DPRESENT_PARAMETERS d3dpp;
3987     ID3DXMesh* d3dxmesh = NULL;
3988     HFONT hFont;
3989     OUTLINETEXTMETRIC otm;
3990     int number_of_vertices;
3991     int number_of_faces;
3992
3993     wnd = CreateWindow("static", "d3dx9_test", WS_POPUP, 0, 0, 1000, 1000, NULL, NULL, NULL, NULL);
3994     d3d = Direct3DCreate9(D3D_SDK_VERSION);
3995     if (!wnd)
3996     {
3997         skip("Couldn't create application window\n");
3998         return;
3999     }
4000     if (!d3d)
4001     {
4002         skip("Couldn't create IDirect3D9 object\n");
4003         DestroyWindow(wnd);
4004         return;
4005     }
4006
4007     ZeroMemory(&d3dpp, sizeof(d3dpp));
4008     d3dpp.Windowed = TRUE;
4009     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
4010     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
4011     if (FAILED(hr))
4012     {
4013         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
4014         IDirect3D9_Release(d3d);
4015         DestroyWindow(wnd);
4016         return;
4017     }
4018
4019     hdc = CreateCompatibleDC(NULL);
4020
4021     hFont = CreateFont(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
4022                        OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
4023                        "Arial");
4024     SelectObject(hdc, hFont);
4025     GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
4026
4027     hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, NULL, NULL, NULL);
4028     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4029
4030     /* D3DXCreateTextA page faults from passing NULL text */
4031
4032     hr = D3DXCreateTextW(device, hdc, NULL, 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(device, hdc, " ", 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(NULL, hdc, "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, NULL, "wine", 0.001f, 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", -FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4048     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4049
4050     hr = D3DXCreateText(device, hdc, "wine", 0.001f, -FLT_MIN, &d3dxmesh, NULL, NULL);
4051     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4052
4053     /* deviation = 0.0f treated as if deviation = 1.0f / otm.otmEMSquare */
4054     hr = D3DXCreateText(device, hdc, "wine", 1.0f / otm.otmEMSquare, 0.4f, &d3dxmesh, NULL, NULL);
4055     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4056     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
4057     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
4058     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4059
4060     hr = D3DXCreateText(device, hdc, "wine", 0.0f, 0.4f, &d3dxmesh, NULL, NULL);
4061     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4062     ok(number_of_vertices == d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh),
4063        "Got %d vertices, expected %d\n",
4064        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_vertices);
4065     ok(number_of_faces == d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh),
4066        "Got %d faces, expected %d\n",
4067        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_faces);
4068     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4069
4070 #if 0
4071     /* too much detail requested, so will appear to hang */
4072     trace("Waiting for D3DXCreateText to finish with deviation = FLT_MIN ...\n");
4073     hr = D3DXCreateText(device, hdc, "wine", FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4074     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4075     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4076     trace("D3DXCreateText finish with deviation = FLT_MIN\n");
4077 #endif
4078
4079     hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4080     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4081     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4082
4083     test_createtext(device, hdc, "wine", FLT_MAX, 0.4f);
4084     test_createtext(device, hdc, "wine", 0.001f, FLT_MIN);
4085     test_createtext(device, hdc, "wine", 0.001f, 0.0f);
4086     test_createtext(device, hdc, "wine", 0.001f, FLT_MAX);
4087     test_createtext(device, hdc, "wine", 0.0f, 1.0f);
4088
4089     DeleteDC(hdc);
4090
4091     IDirect3DDevice9_Release(device);
4092     IDirect3D9_Release(d3d);
4093     DestroyWindow(wnd);
4094 }
4095
4096 static void test_get_decl_length(void)
4097 {
4098     static const D3DVERTEXELEMENT9 declaration1[] =
4099     {
4100         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4101         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4102         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4103         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4104         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4105         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4106         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4107         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4108         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4109         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4110         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4111         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4112         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4113         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4114         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4115         D3DDECL_END(),
4116     };
4117     static const D3DVERTEXELEMENT9 declaration2[] =
4118     {
4119         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4120         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4121         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4122         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4123         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4124         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4125         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4126         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4127         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4128         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4129         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4130         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4131         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4132         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4133         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4134         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4135         D3DDECL_END(),
4136     };
4137     UINT size;
4138
4139     size = D3DXGetDeclLength(declaration1);
4140     ok(size == 15, "Got size %u, expected 15.\n", size);
4141
4142     size = D3DXGetDeclLength(declaration2);
4143     ok(size == 16, "Got size %u, expected 16.\n", size);
4144 }
4145
4146 static void test_get_decl_vertex_size(void)
4147 {
4148     static const D3DVERTEXELEMENT9 declaration1[] =
4149     {
4150         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4151         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4152         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4153         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4154         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4155         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4156         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4157         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4158         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4159         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4160         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4161         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4162         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4163         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4164         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4165         D3DDECL_END(),
4166     };
4167     static const D3DVERTEXELEMENT9 declaration2[] =
4168     {
4169         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4170         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4171         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4172         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4173         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4174         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4175         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4176         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4177         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4178         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4179         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4180         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4181         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4182         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4183         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4184         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4185         D3DDECL_END(),
4186     };
4187     static const UINT sizes1[] =
4188     {
4189         4,  8,  12, 16,
4190         4,  4,  4,  8,
4191         4,  4,  8,  4,
4192         4,  4,  8,  0,
4193     };
4194     static const UINT sizes2[] =
4195     {
4196         12, 16, 20, 24,
4197         12, 12, 16, 16,
4198     };
4199     unsigned int i;
4200     UINT size;
4201
4202     size = D3DXGetDeclVertexSize(NULL, 0);
4203     ok(size == 0, "Got size %#x, expected 0.\n", size);
4204
4205     for (i = 0; i < 16; ++i)
4206     {
4207         size = D3DXGetDeclVertexSize(declaration1, i);
4208         ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
4209     }
4210
4211     for (i = 0; i < 8; ++i)
4212     {
4213         size = D3DXGetDeclVertexSize(declaration2, i);
4214         ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
4215     }
4216 }
4217
4218 static void D3DXGenerateAdjacencyTest(void)
4219 {
4220     HRESULT hr;
4221     HWND wnd;
4222     IDirect3D9 *d3d;
4223     IDirect3DDevice9 *device;
4224     D3DPRESENT_PARAMETERS d3dpp;
4225     ID3DXMesh *d3dxmesh = NULL;
4226     D3DXVECTOR3 *vertices = NULL;
4227     WORD *indices = NULL;
4228     int i;
4229     struct {
4230         DWORD num_vertices;
4231         D3DXVECTOR3 vertices[6];
4232         DWORD num_faces;
4233         WORD indices[3 * 3];
4234         FLOAT epsilon;
4235         DWORD adjacency[3 * 3];
4236     } test_data[] = {
4237         { /* for epsilon < 0, indices must match for faces to be adjacent */
4238             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}},
4239             2, {0, 1, 2,  0, 2, 3},
4240             -1.0,
4241             {-1, -1, 1,  0, -1, -1},
4242         },
4243         {
4244             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}},
4245             2, {0, 1, 2,  3, 4, 5},
4246             -1.0,
4247             {-1, -1, -1,  -1, -1, -1},
4248         },
4249         { /* for epsilon == 0, indices or vertices must match for faces to be adjacent */
4250             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}},
4251             2, {0, 1, 2,  3, 4, 5},
4252             0.0,
4253             {-1, -1, 1,  0, -1, -1},
4254         },
4255         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4256             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}},
4257             2, {0, 1, 2,  3, 4, 5},
4258             0.25,
4259             {-1, -1, -1,  -1, -1, -1},
4260         },
4261         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4262             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}},
4263             2, {0, 1, 2,  3, 4, 5},
4264             0.250001,
4265             {-1, -1, 1,  0, -1, -1},
4266         },
4267         { /* length between vertices are compared to epsilon, not the individual dimension deltas */
4268             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}},
4269             2, {0, 1, 2,  3, 4, 5},
4270             0.353, /* < sqrt(0.25*0.25 + 0.25*0.25) */
4271             {-1, -1, -1,  -1, -1, -1},
4272         },
4273         {
4274             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}},
4275             2, {0, 1, 2,  3, 4, 5},
4276             0.354, /* > sqrt(0.25*0.25 + 0.25*0.25) */
4277             {-1, -1, 1,  0, -1, -1},
4278         },
4279         { /* adjacent faces must have opposite winding orders at the shared edge */
4280             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}},
4281             2, {0, 1, 2,  0, 3, 2},
4282             0.0,
4283             {-1, -1, -1,  -1, -1, -1},
4284         },
4285     };
4286
4287     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
4288     if (!wnd)
4289     {
4290         skip("Couldn't create application window\n");
4291         return;
4292     }
4293     d3d = Direct3DCreate9(D3D_SDK_VERSION);
4294     if (!d3d)
4295     {
4296         skip("Couldn't create IDirect3D9 object\n");
4297         DestroyWindow(wnd);
4298         return;
4299     }
4300
4301     ZeroMemory(&d3dpp, sizeof(d3dpp));
4302     d3dpp.Windowed = TRUE;
4303     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
4304     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
4305     if (FAILED(hr))
4306     {
4307         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
4308         IDirect3D9_Release(d3d);
4309         DestroyWindow(wnd);
4310         return;
4311     }
4312
4313     for (i = 0; i < ARRAY_SIZE(test_data); i++)
4314     {
4315         DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
4316         int j;
4317
4318         if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4319         d3dxmesh = NULL;
4320
4321         hr = D3DXCreateMeshFVF(test_data[i].num_faces, test_data[i].num_vertices, 0, D3DFVF_XYZ, device, &d3dxmesh);
4322         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4323
4324         hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&vertices);
4325         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4326         if (FAILED(hr)) continue;
4327         CopyMemory(vertices, test_data[i].vertices, test_data[i].num_vertices * sizeof(test_data[0].vertices[0]));
4328         d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
4329
4330         hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&indices);
4331         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4332         if (FAILED(hr)) continue;
4333         CopyMemory(indices, test_data[i].indices, test_data[i].num_faces * 3 * sizeof(test_data[0].indices[0]));
4334         d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
4335
4336         if (i == 0) {
4337             hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, NULL);
4338             ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4339         }
4340
4341         hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, test_data[i].epsilon, adjacency);
4342         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4343         if (FAILED(hr)) continue;
4344
4345         for (j = 0; j < test_data[i].num_faces * 3; j++)
4346             ok(adjacency[j] == test_data[i].adjacency[j],
4347                "Test %d adjacency %d: Got result %u, expected %u\n", i, j,
4348                adjacency[j], test_data[i].adjacency[j]);
4349     }
4350     if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4351 }
4352
4353 static void test_update_semantics(void)
4354 {
4355     HRESULT hr;
4356     struct test_context *test_context = NULL;
4357     ID3DXMesh *mesh = NULL;
4358     D3DVERTEXELEMENT9 declaration0[] =
4359     {
4360          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4361          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4362          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4363          D3DDECL_END()
4364     };
4365     D3DVERTEXELEMENT9 declaration_pos_type_color[] =
4366     {
4367          {0, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4368          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4369          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4370          D3DDECL_END()
4371     };
4372     D3DVERTEXELEMENT9 declaration_smaller[] =
4373     {
4374          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4375          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4376          D3DDECL_END()
4377     };
4378     D3DVERTEXELEMENT9 declaration_larger[] =
4379     {
4380          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4381          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4382          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4383          {0, 40, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4384          D3DDECL_END()
4385     };
4386     D3DVERTEXELEMENT9 declaration_multiple_streams[] =
4387     {
4388          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4389          {1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4390          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4391          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4392
4393          D3DDECL_END()
4394     };
4395     D3DVERTEXELEMENT9 declaration_double_usage[] =
4396     {
4397          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4398          {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4399          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4400          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4401          D3DDECL_END()
4402     };
4403     D3DVERTEXELEMENT9 declaration_undefined_type[] =
4404     {
4405          {0, 0, D3DDECLTYPE_UNUSED+1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4406          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4407          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4408          D3DDECL_END()
4409     };
4410     D3DVERTEXELEMENT9 declaration_not_4_byte_aligned_offset[] =
4411     {
4412          {0, 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4413          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4414          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4415          D3DDECL_END()
4416     };
4417     static const struct
4418     {
4419         D3DXVECTOR3 position0;
4420         D3DXVECTOR3 position1;
4421         D3DXVECTOR3 normal;
4422         DWORD color;
4423     }
4424     vertices[] =
4425     {
4426         { { 0.0f,  1.0f,  0.f}, { 1.0f,  0.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xffff0000 },
4427         { { 1.0f, -1.0f,  0.f}, {-1.0f, -1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff00ff00 },
4428         { {-1.0f, -1.0f,  0.f}, {-1.0f,  1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff0000ff },
4429     };
4430     unsigned int faces[] = {0, 1, 2};
4431     unsigned int attributes[] = {0};
4432     unsigned int num_faces = ARRAY_SIZE(faces) / 3;
4433     unsigned int num_vertices = ARRAY_SIZE(vertices);
4434     int offset = sizeof(D3DXVECTOR3);
4435     DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4436     void *vertex_buffer;
4437     void *index_buffer;
4438     DWORD *attributes_buffer;
4439     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
4440     D3DVERTEXELEMENT9 *decl_ptr;
4441     DWORD exp_vertex_size = sizeof(*vertices);
4442     DWORD vertex_size = 0;
4443     int equal;
4444     int i = 0;
4445     int *decl_mem;
4446     int filler_a = 0xaaaaaaaa;
4447     int filler_b = 0xbbbbbbbb;
4448
4449     test_context = new_test_context();
4450     if (!test_context)
4451     {
4452         skip("Couldn't create a test_context\n");
4453         goto cleanup;
4454     }
4455
4456     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration0,
4457                         test_context->device, &mesh);
4458     if (FAILED(hr))
4459     {
4460         skip("Couldn't create test mesh %#x\n", hr);
4461         goto cleanup;
4462     }
4463
4464     mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
4465     memcpy(vertex_buffer, vertices, sizeof(vertices));
4466     mesh->lpVtbl->UnlockVertexBuffer(mesh);
4467
4468     mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
4469     memcpy(index_buffer, faces, sizeof(faces));
4470     mesh->lpVtbl->UnlockIndexBuffer(mesh);
4471
4472     mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
4473     memcpy(attributes_buffer, attributes, sizeof(attributes));
4474     mesh->lpVtbl->UnlockAttributeBuffer(mesh);
4475
4476     /* Get the declaration and try to change it */
4477     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4478     if (FAILED(hr))
4479     {
4480         skip("Couldn't get vertex declaration %#x\n", hr);
4481         goto cleanup;
4482     }
4483     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4484     ok(equal == 0, "Vertex declarations were not equal\n");
4485
4486     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4487     {
4488         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4489         {
4490             /* Use second vertex position instead of first */
4491             decl_ptr->Offset = offset;
4492         }
4493     }
4494
4495     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4496     ok(hr == D3D_OK, "Test UpdateSematics, got %#x expected %#x\n", hr, D3D_OK);
4497
4498     /* Check that declaration was written by getting it again */
4499     memset(declaration, 0, sizeof(declaration));
4500     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4501     if (FAILED(hr))
4502     {
4503         skip("Couldn't get vertex declaration %#x\n", hr);
4504         goto cleanup;
4505     }
4506
4507     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4508     {
4509         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4510         {
4511             ok(decl_ptr->Offset == offset, "Test UpdateSematics, got offset %d expected %d\n",
4512                decl_ptr->Offset, offset);
4513         }
4514     }
4515
4516     /* Check that GetDeclaration only writes up to the D3DDECL_END() marker and
4517      * not the full MAX_FVF_DECL_SIZE elements.
4518      */
4519     memset(declaration, filler_a, sizeof(declaration));
4520     memcpy(declaration, declaration0, sizeof(declaration0));
4521     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4522     ok(hr == D3D_OK, "Test UpdateSematics, "
4523        "got %#x expected D3D_OK\n", hr);
4524     memset(declaration, filler_b, sizeof(declaration));
4525     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4526     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4527     decl_mem = (int*)declaration;
4528     for (i = sizeof(declaration0)/sizeof(*decl_mem); i < sizeof(declaration)/sizeof(*decl_mem); i++)
4529     {
4530         equal = memcmp(&decl_mem[i], &filler_b, sizeof(filler_b));
4531         ok(equal == 0,
4532            "GetDeclaration wrote past the D3DDECL_END() marker. "
4533            "Got %#x, expected  %#x\n", decl_mem[i], filler_b);
4534         if (equal != 0) break;
4535     }
4536
4537     /* UpdateSemantics does not check for overlapping fields */
4538     memset(declaration, 0, sizeof(declaration));
4539     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4540     if (FAILED(hr))
4541     {
4542         skip("Couldn't get vertex declaration %#x\n", hr);
4543         goto cleanup;
4544     }
4545
4546     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4547     {
4548         if (decl_ptr->Type == D3DDECLTYPE_FLOAT3)
4549         {
4550             decl_ptr->Type = D3DDECLTYPE_FLOAT4;
4551         }
4552     }
4553
4554     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4555     ok(hr == D3D_OK, "Test UpdateSematics for overlapping fields, "
4556        "got %#x expected D3D_OK\n", hr);
4557
4558     /* Set the position type to color instead of float3 */
4559     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_pos_type_color);
4560     ok(hr == D3D_OK, "Test UpdateSematics position type color, "
4561        "got %#x expected D3D_OK\n", hr);
4562
4563     /* The following test cases show that NULL, smaller or larger declarations,
4564      * and declarations with non-zero Stream values are not accepted.
4565      * UpdateSemantics returns D3DERR_INVALIDCALL and the previously set
4566      * declaration will be used by DrawSubset, GetNumBytesPerVertex, and
4567      * GetDeclaration.
4568      */
4569
4570     /* Null declaration (invalid declaration) */
4571     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4572     hr = mesh->lpVtbl->UpdateSemantics(mesh, NULL);
4573     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics null pointer declaration, "
4574        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4575     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4576     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4577        vertex_size, exp_vertex_size);
4578     memset(declaration, 0, sizeof(declaration));
4579     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4580     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4581     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4582     ok(equal == 0, "Vertex declarations were not equal\n");
4583
4584     /* Smaller vertex declaration (invalid declaration) */
4585     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4586     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_smaller);
4587     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics for smaller vertex declaration, "
4588        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4589     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4590     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4591        vertex_size, exp_vertex_size);
4592     memset(declaration, 0, sizeof(declaration));
4593     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4594     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4595     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4596     ok(equal == 0, "Vertex declarations were not equal\n");
4597
4598     /* Larger vertex declaration (invalid declaration) */
4599     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4600     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_larger);
4601     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics for larger vertex declaration, "
4602        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4603     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4604     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4605        vertex_size, exp_vertex_size);
4606     memset(declaration, 0, sizeof(declaration));
4607     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4608     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4609     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4610     ok(equal == 0, "Vertex declarations were not equal\n");
4611
4612     /* Use multiple streams and keep the same vertex size (invalid declaration) */
4613     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4614     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_multiple_streams);
4615     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics using multiple streams, "
4616                  "got %#x expected D3DERR_INVALIDCALL\n", hr);
4617     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4618     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4619        vertex_size, exp_vertex_size);
4620     memset(declaration, 0, sizeof(declaration));
4621     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4622     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4623     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4624     ok(equal == 0, "Vertex declarations were not equal\n");
4625
4626     /* The next following test cases show that some invalid declarations are
4627      * accepted with a D3D_OK. An access violation is thrown on Windows if
4628      * DrawSubset is called. The methods GetNumBytesPerVertex and GetDeclaration
4629      * are not affected, which indicates that the declaration is cached.
4630      */
4631
4632     /* Double usage (invalid declaration) */
4633     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4634     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_double_usage);
4635     ok(hr == D3D_OK, "Test UpdateSematics double usage, "
4636        "got %#x expected D3D_OK\n", hr);
4637     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4638     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4639        vertex_size, exp_vertex_size);
4640     memset(declaration, 0, sizeof(declaration));
4641     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4642     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4643     equal = memcmp(declaration, declaration_double_usage, sizeof(declaration_double_usage));
4644     ok(equal == 0, "Vertex declarations were not equal\n");
4645
4646     /* Set the position to an undefined type (invalid declaration) */
4647     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4648     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_undefined_type);
4649     ok(hr == D3D_OK, "Test UpdateSematics undefined type, "
4650        "got %#x expected D3D_OK\n", hr);
4651     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4652     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4653        vertex_size, exp_vertex_size);
4654     memset(declaration, 0, sizeof(declaration));
4655     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4656     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4657     equal = memcmp(declaration, declaration_undefined_type, sizeof(declaration_undefined_type));
4658     ok(equal == 0, "Vertex declarations were not equal\n");
4659
4660     /* Use a not 4 byte aligned offset (invalid declaration) */
4661     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4662     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_not_4_byte_aligned_offset);
4663     ok(hr == D3D_OK, "Test UpdateSematics not 4 byte aligned offset, "
4664        "got %#x expected D3D_OK\n", hr);
4665     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4666     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4667        vertex_size, exp_vertex_size);
4668     memset(declaration, 0, sizeof(declaration));
4669     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4670     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4671     equal = memcmp(declaration, declaration_not_4_byte_aligned_offset,
4672                    sizeof(declaration_not_4_byte_aligned_offset));
4673     ok(equal == 0, "Vertex declarations were not equal\n");
4674
4675 cleanup:
4676     if (mesh)
4677         mesh->lpVtbl->Release(mesh);
4678
4679     free_test_context(test_context);
4680 }
4681
4682 static void test_create_skin_info(void)
4683 {
4684     HRESULT hr;
4685     ID3DXSkinInfo *skininfo = NULL;
4686     D3DVERTEXELEMENT9 empty_declaration[] = { D3DDECL_END() };
4687     D3DVERTEXELEMENT9 declaration_out[MAX_FVF_DECL_SIZE];
4688     const D3DVERTEXELEMENT9 declaration_with_nonzero_stream[] = {
4689         {1, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
4690         D3DDECL_END()
4691     };
4692
4693     hr = D3DXCreateSkinInfo(0, empty_declaration, 0, &skininfo);
4694     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4695     if (skininfo) IUnknown_Release(skininfo);
4696     skininfo = NULL;
4697
4698     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
4699     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4700
4701     hr = D3DXCreateSkinInfo(1, declaration_with_nonzero_stream, 1, &skininfo);
4702     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4703
4704     hr = D3DXCreateSkinInfoFVF(1, 0, 1, &skininfo);
4705     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4706     if (skininfo) {
4707         DWORD dword_result;
4708         FLOAT flt_result;
4709         LPCSTR string_result;
4710         D3DXMATRIX *transform;
4711         D3DXMATRIX identity_matrix;
4712
4713         /* test initial values */
4714         hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4715         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4716         if (SUCCEEDED(hr))
4717             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
4718
4719         dword_result = skininfo->lpVtbl->GetNumBones(skininfo);
4720         ok(dword_result == 1, "Expected 1, got %u\n", dword_result);
4721
4722         flt_result = skininfo->lpVtbl->GetMinBoneInfluence(skininfo);
4723         ok(flt_result == 0.0f, "Expected 0.0, got %g\n", flt_result);
4724
4725         string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4726         ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
4727
4728         dword_result = skininfo->lpVtbl->GetFVF(skininfo);
4729         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4730
4731         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 0);
4732         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4733
4734         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 1);
4735         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4736
4737         transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, -1);
4738         ok(transform == NULL, "Expected NULL, got %p\n", transform);
4739
4740         {
4741             /* test [GS]etBoneOffsetMatrix */
4742             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 1, &identity_matrix);
4743             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4744
4745             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, NULL);
4746             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4747
4748             D3DXMatrixIdentity(&identity_matrix);
4749             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, &identity_matrix);
4750             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4751
4752             transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, 0);
4753             check_matrix(transform, &identity_matrix);
4754         }
4755
4756         {
4757             /* test [GS]etBoneName */
4758             const char *name_in = "testBoneName";
4759             const char *string_result2;
4760
4761             hr = skininfo->lpVtbl->SetBoneName(skininfo, 1, name_in);
4762             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4763
4764             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, NULL);
4765             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4766
4767             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, name_in);
4768             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4769
4770             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4771             ok(string_result != NULL, "Expected non-NULL string, got %p\n", string_result);
4772             ok(!strcmp(string_result, name_in), "Expected '%s', got '%s'\n", name_in, string_result);
4773
4774             string_result2 = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4775             ok(string_result == string_result2, "Expected %p, got %p\n", string_result, string_result2);
4776
4777             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 1);
4778             ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
4779         }
4780
4781         {
4782             /* test [GS]etBoneInfluence */
4783             DWORD vertices[2];
4784             FLOAT weights[2];
4785             int i;
4786             DWORD num_influences;
4787             DWORD exp_vertices[2];
4788             FLOAT exp_weights[2];
4789
4790             /* vertex and weight arrays untouched when num_influences is 0 */
4791             vertices[0] = 0xdeadbeef;
4792             weights[0] = FLT_MAX;
4793             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4794             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4795             ok(vertices[0] == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", vertices[0]);
4796             ok(weights[0] == FLT_MAX, "expected %g, got %g\n", FLT_MAX, weights[0]);
4797
4798             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 1, vertices, weights);
4799             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4800
4801             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, NULL);
4802             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4803
4804             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, NULL);
4805             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4806
4807             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, weights);
4808             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4809
4810
4811             /* no vertex or weight value checking */
4812             exp_vertices[0] = 0;
4813             exp_vertices[1] = 0x87654321;
4814             exp_weights[0] = 0.5;
4815             exp_weights[1] = 0.0f / 0.0f; /* NAN */
4816             num_influences = 2;
4817
4818             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 1, num_influences, vertices, weights);
4819             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4820
4821             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, weights);
4822             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4823
4824             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, vertices, NULL);
4825             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4826
4827             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, NULL);
4828             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4829
4830             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, exp_vertices, exp_weights);
4831             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4832
4833             memset(vertices, 0, sizeof(vertices));
4834             memset(weights, 0, sizeof(weights));
4835             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4836             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4837             for (i = 0; i < num_influences; i++) {
4838                 ok(exp_vertices[i] == vertices[i],
4839                    "influence[%d]: expected vertex %u, got %u\n", i, exp_vertices[i], vertices[i]);
4840                 ok((isnan(exp_weights[i]) && isnan(weights[i])) || exp_weights[i] == weights[i],
4841                    "influence[%d]: expected weights %g, got %g\n", i, exp_weights[i], weights[i]);
4842             }
4843
4844             /* vertices and weights aren't returned after setting num_influences to 0 */
4845             memset(vertices, 0, sizeof(vertices));
4846             memset(weights, 0, sizeof(weights));
4847             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, 0, vertices, weights);
4848             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4849
4850             vertices[0] = 0xdeadbeef;
4851             weights[0] = FLT_MAX;
4852             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4853             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4854             ok(vertices[0] == 0xdeadbeef, "expected vertex 0xdeadbeef, got %u\n", vertices[0]);
4855             ok(weights[0] == FLT_MAX, "expected weight %g, got %g\n", FLT_MAX, weights[0]);
4856         }
4857
4858         {
4859             /* test [GS]etFVF and [GS]etDeclaration */
4860             D3DVERTEXELEMENT9 declaration_in[MAX_FVF_DECL_SIZE];
4861             DWORD fvf = D3DFVF_XYZ;
4862             DWORD got_fvf;
4863
4864             hr = skininfo->lpVtbl->SetDeclaration(skininfo, NULL);
4865             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4866
4867             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_with_nonzero_stream);
4868             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4869
4870             hr = skininfo->lpVtbl->SetFVF(skininfo, 0);
4871             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4872
4873             hr = D3DXDeclaratorFromFVF(fvf, declaration_in);
4874             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4875             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_in);
4876             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4877             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4878             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
4879             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4880             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4881             compare_elements(declaration_out, declaration_in, __LINE__, 0);
4882
4883             hr = skininfo->lpVtbl->SetDeclaration(skininfo, empty_declaration);
4884             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4885             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4886             ok(got_fvf == 0, "Expected 0, got %#x\n", got_fvf);
4887             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4888             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4889             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
4890
4891             hr = skininfo->lpVtbl->SetFVF(skininfo, fvf);
4892             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4893             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4894             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
4895             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4896             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4897             compare_elements(declaration_out, declaration_in, __LINE__, 0);
4898         }
4899     }
4900     if (skininfo) IUnknown_Release(skininfo);
4901     skininfo = NULL;
4902
4903     hr = D3DXCreateSkinInfoFVF(1, D3DFVF_XYZ, 1, NULL);
4904     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4905
4906     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
4907     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4908 }
4909
4910 static void test_convert_adjacency_to_point_reps(void)
4911 {
4912     HRESULT hr;
4913     struct test_context *test_context = NULL;
4914     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4915     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
4916     const D3DVERTEXELEMENT9 declaration[] =
4917     {
4918         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4919         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4920         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4921         D3DDECL_END()
4922     };
4923     const unsigned int VERTS_PER_FACE = 3;
4924     void *vertex_buffer;
4925     void *index_buffer;
4926     DWORD *attributes_buffer;
4927     int i, j;
4928     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
4929     struct vertex_pnc
4930     {
4931         D3DXVECTOR3 position;
4932         D3DXVECTOR3 normal;
4933         enum color color; /* In case of manual visual inspection */
4934     };
4935     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
4936     /* mesh0 (one face)
4937      *
4938      * 0--1
4939      * | /
4940      * |/
4941      * 2
4942      */
4943     const struct vertex_pnc vertices0[] =
4944     {
4945         {{ 0.0f,  3.0f,  0.f}, up, RED},
4946         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
4947         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
4948     };
4949     const DWORD indices0[] = {0, 1, 2};
4950     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
4951     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
4952     const DWORD adjacency0[] = {-1, -1, -1};
4953     const DWORD exp_point_rep0[] = {0, 1, 2};
4954     /* mesh1 (right)
4955      *
4956      * 0--1 3
4957      * | / /|
4958      * |/ / |
4959      * 2 5--4
4960      */
4961     const struct vertex_pnc vertices1[] =
4962     {
4963         {{ 0.0f,  3.0f,  0.f}, up, RED},
4964         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
4965         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
4966
4967         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
4968         {{ 3.0f,  0.0f,  0.f}, up, RED},
4969         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
4970     };
4971     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
4972     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
4973     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
4974     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
4975     const DWORD exp_point_rep1[] = {0, 1, 2, 1, 4, 2};
4976     /* mesh2 (left)
4977      *
4978      *    3 0--1
4979      *   /| | /
4980      *  / | |/
4981      * 5--4 2
4982      */
4983     const struct vertex_pnc vertices2[] =
4984     {
4985         {{ 0.0f,  3.0f,  0.f}, up, RED},
4986         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
4987         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
4988
4989         {{-1.0f,  3.0f,  0.f}, up, RED},
4990         {{-1.0f,  0.0f,  0.f}, up, GREEN},
4991         {{-3.0f,  0.0f,  0.f}, up, BLUE},
4992     };
4993     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
4994     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
4995     const unsigned int num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
4996     const DWORD adjacency2[] = {-1, -1, 1, 0, -1, -1};
4997     const DWORD exp_point_rep2[] = {0, 1, 2, 0, 2, 5};
4998     /* mesh3 (above)
4999      *
5000      *    3
5001      *   /|
5002      *  / |
5003      * 5--4
5004      * 0--1
5005      * | /
5006      * |/
5007      * 2
5008      */
5009     struct vertex_pnc vertices3[] =
5010     {
5011         {{ 0.0f,  3.0f,  0.f}, up, RED},
5012         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5013         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5014
5015         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5016         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5017         {{ 0.0f,  4.0f,  0.f}, up, RED},
5018     };
5019     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5020     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5021     const unsigned int num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
5022     const DWORD adjacency3[] = {1, -1, -1, -1, 0, -1};
5023     const DWORD exp_point_rep3[] = {0, 1, 2, 3, 1, 0};
5024     /* mesh4 (below, tip against tip)
5025      *
5026      * 0--1
5027      * | /
5028      * |/
5029      * 2
5030      * 3
5031      * |\
5032      * | \
5033      * 5--4
5034      */
5035     struct vertex_pnc vertices4[] =
5036     {
5037         {{ 0.0f,  3.0f,  0.f}, up, RED},
5038         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5039         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5040
5041         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5042         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5043         {{ 0.0f, -7.0f,  0.f}, up, RED},
5044     };
5045     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5046     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5047     const unsigned int num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
5048     const DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
5049     const DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
5050     /* mesh5 (gap in mesh)
5051      *
5052      *    0      3-----4  15
5053      *   / \      \   /  /  \
5054      *  /   \      \ /  /    \
5055      * 2-----1      5 17-----16
5056      * 6-----7      9 12-----13
5057      *  \   /      / \  \    /
5058      *   \ /      /   \  \  /
5059      *    8     10-----11 14
5060      *
5061      */
5062     const struct vertex_pnc vertices5[] =
5063     {
5064         {{ 0.0f,  1.0f,  0.f}, up, RED},
5065         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5066         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5067
5068         {{ 0.1f,  1.0f,  0.f}, up, RED},
5069         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5070         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5071
5072         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5073         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5074         {{ 0.0f, -3.1f,  0.f}, up, RED},
5075
5076         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5077         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5078         {{ 0.1f, -3.1f,  0.f}, up, RED},
5079
5080         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5081         {{ 3.2f, -1.1f,  0.f}, up, RED},
5082         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5083
5084         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5085         {{ 3.2f, -1.0f,  0.f}, up, RED},
5086         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5087     };
5088     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5089     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5090     const unsigned int num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
5091     const DWORD adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5092     const DWORD exp_point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5093     const WORD indices5_16bit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5094     /* mesh6 (indices re-ordering)
5095      *
5096      * 0--1 6 3
5097      * | / /| |\
5098      * |/ / | | \
5099      * 2 8--7 5--4
5100      */
5101     const struct vertex_pnc vertices6[] =
5102     {
5103         {{ 0.0f,  3.0f,  0.f}, up, RED},
5104         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5105         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5106
5107         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5108         {{ 3.0f,  0.0f,  0.f}, up, RED},
5109         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5110
5111         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5112         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5113         {{ 4.0f,  0.0f,  0.f}, up, RED},
5114     };
5115     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5116     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5117     const unsigned int num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
5118     const DWORD adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5119     const DWORD exp_point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5120     /* mesh7 (expands collapsed triangle)
5121      *
5122      * 0--1 3
5123      * | / /|
5124      * |/ / |
5125      * 2 5--4
5126      */
5127     const struct vertex_pnc vertices7[] =
5128     {
5129         {{ 0.0f,  3.0f,  0.f}, up, RED},
5130         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5131         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5132
5133         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5134         {{ 3.0f,  0.0f,  0.f}, up, RED},
5135         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5136     };
5137     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5138     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5139     const unsigned int num_faces7 = ARRAY_SIZE(indices7) / VERTS_PER_FACE;
5140     const DWORD adjacency7[] = {-1, -1, -1, -1, -1, -1};
5141     const DWORD exp_point_rep7[] = {0, 1, 2, 3, 4, 5};
5142     /* mesh8 (indices re-ordering and double replacement)
5143      *
5144      * 0--1 9  6
5145      * | / /|  |\
5146      * |/ / |  | \
5147      * 2 11-10 8--7
5148      *         3--4
5149      *         | /
5150      *         |/
5151      *         5
5152      */
5153     const struct vertex_pnc vertices8[] =
5154     {
5155         {{ 0.0f,  3.0f,  0.f}, up, RED},
5156         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5157         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5158
5159         {{ 4.0,  -4.0,  0.f}, up, RED},
5160         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5161         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5162
5163         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5164         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5165         {{ 4.0f,  0.0f,  0.f}, up, RED},
5166
5167         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5168         {{ 3.0f,  0.0f,  0.f}, up, RED},
5169         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5170     };
5171     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5172     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5173     const unsigned int num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
5174     const DWORD adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5175     const DWORD exp_point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5176     /* mesh9 (right, shared vertices)
5177      *
5178      * 0--1
5179      * | /|
5180      * |/ |
5181      * 2--3
5182      */
5183     const struct vertex_pnc vertices9[] =
5184     {
5185         {{ 0.0f,  3.0f,  0.f}, up, RED},
5186         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5187         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5188
5189         {{ 2.0f,  0.0f,  0.f}, up, RED},
5190     };
5191     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5192     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5193     const unsigned int num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
5194     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
5195     const DWORD exp_point_rep9[] = {0, 1, 2, 3};
5196     /* All mesh data */
5197     ID3DXMesh *mesh = NULL;
5198     ID3DXMesh *mesh_null_check = NULL;
5199     unsigned int attributes[] = {0};
5200     struct
5201     {
5202         const struct vertex_pnc *vertices;
5203         const DWORD *indices;
5204         const DWORD num_vertices;
5205         const DWORD num_faces;
5206         const DWORD *adjacency;
5207         const DWORD *exp_point_reps;
5208         const DWORD options;
5209     }
5210     tc[] =
5211     {
5212         {
5213             vertices0,
5214             indices0,
5215             num_vertices0,
5216             num_faces0,
5217             adjacency0,
5218             exp_point_rep0,
5219             options
5220         },
5221         {
5222             vertices1,
5223             indices1,
5224             num_vertices1,
5225             num_faces1,
5226             adjacency1,
5227             exp_point_rep1,
5228             options
5229         },
5230         {
5231             vertices2,
5232             indices2,
5233             num_vertices2,
5234             num_faces2,
5235             adjacency2,
5236             exp_point_rep2,
5237             options
5238         },
5239         {
5240             vertices3,
5241             indices3,
5242             num_vertices3,
5243             num_faces3,
5244             adjacency3,
5245             exp_point_rep3,
5246             options
5247         },
5248         {
5249             vertices4,
5250             indices4,
5251             num_vertices4,
5252             num_faces4,
5253             adjacency4,
5254             exp_point_rep4,
5255             options
5256         },
5257         {
5258             vertices5,
5259             indices5,
5260             num_vertices5,
5261             num_faces5,
5262             adjacency5,
5263             exp_point_rep5,
5264             options
5265         },
5266         {
5267             vertices6,
5268             indices6,
5269             num_vertices6,
5270             num_faces6,
5271             adjacency6,
5272             exp_point_rep6,
5273             options
5274         },
5275         {
5276             vertices7,
5277             indices7,
5278             num_vertices7,
5279             num_faces7,
5280             adjacency7,
5281             exp_point_rep7,
5282             options
5283         },
5284         {
5285             vertices8,
5286             indices8,
5287             num_vertices8,
5288             num_faces8,
5289             adjacency8,
5290             exp_point_rep8,
5291             options
5292         },
5293         {
5294             vertices9,
5295             indices9,
5296             num_vertices9,
5297             num_faces9,
5298             adjacency9,
5299             exp_point_rep9,
5300             options
5301         },
5302         {
5303             vertices5,
5304             (DWORD*)indices5_16bit,
5305             num_vertices5,
5306             num_faces5,
5307             adjacency5,
5308             exp_point_rep5,
5309             options_16bit
5310         },
5311     };
5312     DWORD *point_reps = NULL;
5313
5314     test_context = new_test_context();
5315     if (!test_context)
5316     {
5317         skip("Couldn't create test context\n");
5318         goto cleanup;
5319     }
5320
5321     for (i = 0; i < ARRAY_SIZE(tc); i++)
5322     {
5323         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options, declaration,
5324                             test_context->device, &mesh);
5325         if (FAILED(hr))
5326         {
5327             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5328             goto cleanup;
5329         }
5330
5331         if (i == 0) /* Save first mesh for later NULL checks */
5332             mesh_null_check = mesh;
5333
5334         point_reps = HeapAlloc(GetProcessHeap(), 0, tc[i].num_vertices * sizeof(*point_reps));
5335         if (!point_reps)
5336         {
5337             skip("Couldn't allocate point reps array.\n");
5338             goto cleanup;
5339         }
5340
5341         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5342         if (FAILED(hr))
5343         {
5344             skip("Couldn't lock vertex buffer.\n");
5345             goto cleanup;
5346         }
5347         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5348         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5349         if (FAILED(hr))
5350         {
5351             skip("Couldn't unlock vertex buffer.\n");
5352             goto cleanup;
5353         }
5354
5355         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5356         if (FAILED(hr))
5357         {
5358             skip("Couldn't lock index buffer.\n");
5359             goto cleanup;
5360         }
5361         if (tc[i].options & D3DXMESH_32BIT)
5362         {
5363             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5364         }
5365         else
5366         {
5367             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5368         }
5369         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5370         if (FAILED(hr)) {
5371             skip("Couldn't unlock index buffer.\n");
5372             goto cleanup;
5373         }
5374
5375         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5376         if (FAILED(hr))
5377         {
5378             skip("Couldn't lock attributes buffer.\n");
5379             goto cleanup;
5380         }
5381         memcpy(attributes_buffer, attributes, sizeof(attributes));
5382         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5383         if (FAILED(hr))
5384         {
5385             skip("Couldn't unlock attributes buffer.\n");
5386             goto cleanup;
5387         }
5388
5389         /* Convert adjacency to point representation */
5390         for (j = 0; j < tc[i].num_vertices; j++) point_reps[j] = -1;
5391         hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacency, point_reps);
5392         ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
5393            "Got %x expected D3D_OK\n", i, hr);
5394
5395         /* Check point representation */
5396         for (j = 0; j < tc[i].num_vertices; j++)
5397         {
5398             ok(point_reps[j] == tc[i].exp_point_reps[j],
5399                "Unexpected point representation at (%d, %d)."
5400                " Got %d expected %d\n",
5401                i, j, point_reps[j], tc[i].exp_point_reps[j]);
5402         }
5403
5404         HeapFree(GetProcessHeap(), 0, point_reps);
5405         point_reps = NULL;
5406
5407         if (i != 0) /* First mesh will be freed during cleanup */
5408             mesh->lpVtbl->Release(mesh);
5409     }
5410
5411     /* NULL checks */
5412     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacency, NULL);
5413     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
5414        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5415     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, NULL);
5416     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. "
5417        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5418
5419 cleanup:
5420     if (mesh_null_check)
5421         mesh_null_check->lpVtbl->Release(mesh_null_check);
5422     HeapFree(GetProcessHeap(), 0, point_reps);
5423     free_test_context(test_context);
5424 }
5425
5426 static void test_convert_point_reps_to_adjacency(void)
5427 {
5428     HRESULT hr;
5429     struct test_context *test_context = NULL;
5430     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5431     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5432     const D3DVERTEXELEMENT9 declaration[] =
5433     {
5434         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5435         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5436         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5437         D3DDECL_END()
5438     };
5439     const unsigned int VERTS_PER_FACE = 3;
5440     void *vertex_buffer;
5441     void *index_buffer;
5442     DWORD *attributes_buffer;
5443     int i, j;
5444     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5445     struct vertex_pnc
5446     {
5447         D3DXVECTOR3 position;
5448         D3DXVECTOR3 normal;
5449         enum color color; /* In case of manual visual inspection */
5450     };
5451     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5452     /* mesh0 (one face)
5453      *
5454      * 0--1
5455      * | /
5456      * |/
5457      * 2
5458      */
5459     const struct vertex_pnc vertices0[] =
5460     {
5461         {{ 0.0f,  3.0f,  0.f}, up, RED},
5462         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5463         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5464     };
5465     const DWORD indices0[] = {0, 1, 2};
5466     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5467     const unsigned int num_faces0 = num_vertices0 / VERTS_PER_FACE;
5468     const DWORD exp_adjacency0[] = {-1, -1, -1};
5469     const DWORD exp_id_adjacency0[] = {-1, -1, -1};
5470     const DWORD point_rep0[] = {0, 1, 2};
5471     /* mesh1 (right)
5472      *
5473      * 0--1 3
5474      * | / /|
5475      * |/ / |
5476      * 2 5--4
5477      */
5478     const struct vertex_pnc vertices1[] =
5479     {
5480         {{ 0.0f,  3.0f,  0.f}, up, RED},
5481         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5482         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5483
5484         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5485         {{ 3.0f,  0.0f,  0.f}, up, RED},
5486         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5487     };
5488     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5489     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5490     const unsigned int num_faces1 = num_vertices1 / VERTS_PER_FACE;
5491     const DWORD exp_adjacency1[] = {-1, 1, -1, -1, -1, 0};
5492     const DWORD exp_id_adjacency1[] = {-1, -1, -1, -1, -1, -1};
5493     const DWORD point_rep1[] = {0, 1, 2, 1, 4, 2};
5494     /* mesh2 (left)
5495      *
5496      *    3 0--1
5497      *   /| | /
5498      *  / | |/
5499      * 5--4 2
5500      */
5501     const struct vertex_pnc vertices2[] =
5502     {
5503         {{ 0.0f,  3.0f,  0.f}, up, RED},
5504         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5505         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5506
5507         {{-1.0f,  3.0f,  0.f}, up, RED},
5508         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5509         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5510     };
5511     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5512     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5513     const unsigned int num_faces2 = num_vertices2 / VERTS_PER_FACE;
5514     const DWORD exp_adjacency2[] = {-1, -1, 1, 0, -1, -1};
5515     const DWORD exp_id_adjacency2[] = {-1, -1, -1, -1, -1, -1};
5516     const DWORD point_rep2[] = {0, 1, 2, 0, 2, 5};
5517     /* mesh3 (above)
5518      *
5519      *    3
5520      *   /|
5521      *  / |
5522      * 5--4
5523      * 0--1
5524      * | /
5525      * |/
5526      * 2
5527      */
5528     struct vertex_pnc vertices3[] =
5529     {
5530         {{ 0.0f,  3.0f,  0.f}, up, RED},
5531         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5532         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5533
5534         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5535         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5536         {{ 0.0f,  4.0f,  0.f}, up, RED},
5537     };
5538     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5539     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5540     const unsigned int num_faces3 = num_vertices3 / VERTS_PER_FACE;
5541     const DWORD exp_adjacency3[] = {1, -1, -1, -1, 0, -1};
5542     const DWORD exp_id_adjacency3[] = {-1, -1, -1, -1, -1, -1};
5543     const DWORD point_rep3[] = {0, 1, 2, 3, 1, 0};
5544     /* mesh4 (below, tip against tip)
5545      *
5546      * 0--1
5547      * | /
5548      * |/
5549      * 2
5550      * 3
5551      * |\
5552      * | \
5553      * 5--4
5554      */
5555     struct vertex_pnc vertices4[] =
5556     {
5557         {{ 0.0f,  3.0f,  0.f}, up, RED},
5558         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5559         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5560
5561         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5562         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5563         {{ 0.0f, -7.0f,  0.f}, up, RED},
5564     };
5565     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5566     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5567     const unsigned int num_faces4 = num_vertices4 / VERTS_PER_FACE;
5568     const DWORD exp_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5569     const DWORD exp_id_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5570     const DWORD point_rep4[] = {0, 1, 2, 3, 4, 5};
5571     /* mesh5 (gap in mesh)
5572      *
5573      *    0      3-----4  15
5574      *   / \      \   /  /  \
5575      *  /   \      \ /  /    \
5576      * 2-----1      5 17-----16
5577      * 6-----7      9 12-----13
5578      *  \   /      / \  \    /
5579      *   \ /      /   \  \  /
5580      *    8     10-----11 14
5581      *
5582      */
5583     const struct vertex_pnc vertices5[] =
5584     {
5585         {{ 0.0f,  1.0f,  0.f}, up, RED},
5586         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5587         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5588
5589         {{ 0.1f,  1.0f,  0.f}, up, RED},
5590         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5591         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5592
5593         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5594         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5595         {{ 0.0f, -3.1f,  0.f}, up, RED},
5596
5597         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5598         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5599         {{ 0.1f, -3.1f,  0.f}, up, RED},
5600
5601         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5602         {{ 3.2f, -1.1f,  0.f}, up, RED},
5603         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5604
5605         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5606         {{ 3.2f, -1.0f,  0.f}, up, RED},
5607         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5608     };
5609     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5610     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5611     const unsigned int num_faces5 = num_vertices5 / VERTS_PER_FACE;
5612     const DWORD exp_adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5613     const DWORD exp_id_adjacency5[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5614     const DWORD point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5615     /* mesh6 (indices re-ordering)
5616      *
5617      * 0--1 6 3
5618      * | / /| |\
5619      * |/ / | | \
5620      * 2 8--7 5--4
5621      */
5622     const struct vertex_pnc vertices6[] =
5623     {
5624         {{ 0.0f,  3.0f,  0.f}, up, RED},
5625         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5626         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5627
5628         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5629         {{ 3.0f,  0.0f,  0.f}, up, RED},
5630         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5631
5632         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5633         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5634         {{ 4.0f,  0.0f,  0.f}, up, RED},
5635     };
5636     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5637     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5638     const unsigned int num_faces6 = num_vertices6 / VERTS_PER_FACE;
5639     const DWORD exp_adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5640     const DWORD exp_id_adjacency6[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1};
5641     const DWORD point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5642     /* mesh7 (expands collapsed triangle)
5643      *
5644      * 0--1 3
5645      * | / /|
5646      * |/ / |
5647      * 2 5--4
5648      */
5649     const struct vertex_pnc vertices7[] =
5650     {
5651         {{ 0.0f,  3.0f,  0.f}, up, RED},
5652         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5653         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5654
5655         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5656         {{ 3.0f,  0.0f,  0.f}, up, RED},
5657         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5658     };
5659     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5660     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5661     const unsigned int num_faces7 = num_vertices7 / VERTS_PER_FACE;
5662     const DWORD exp_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5663     const DWORD exp_id_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5664     const DWORD point_rep7[] = {0, 1, 2, 3, 4, 5};
5665     /* mesh8 (indices re-ordering and double replacement)
5666      *
5667      * 0--1 9  6
5668      * | / /|  |\
5669      * |/ / |  | \
5670      * 2 11-10 8--7
5671      *         3--4
5672      *         | /
5673      *         |/
5674      *         5
5675      */
5676     const struct vertex_pnc vertices8[] =
5677     {
5678         {{ 0.0f,  3.0f,  0.f}, up, RED},
5679         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5680         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5681
5682         {{ 4.0,  -4.0,  0.f}, up, RED},
5683         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5684         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5685
5686         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5687         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5688         {{ 4.0f,  0.0f,  0.f}, up, RED},
5689
5690         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5691         {{ 3.0f,  0.0f,  0.f}, up, RED},
5692         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5693     };
5694     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5695     const WORD indices8_16bit[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5696     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5697     const unsigned int num_faces8 = num_vertices8 / VERTS_PER_FACE;
5698     const DWORD exp_adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5699     const DWORD exp_id_adjacency8[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5700     const DWORD point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5701      /* mesh9 (right, shared vertices)
5702      *
5703      * 0--1
5704      * | /|
5705      * |/ |
5706      * 2--3
5707      */
5708     const struct vertex_pnc vertices9[] =
5709     {
5710         {{ 0.0f,  3.0f,  0.f}, up, RED},
5711         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5712         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5713
5714         {{ 2.0f,  0.0f,  0.f}, up, RED},
5715     };
5716     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5717     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5718     const unsigned int num_faces9 = 2;
5719     const DWORD exp_adjacency9[] = {-1, 1, -1, -1, -1, 0};
5720     const DWORD exp_id_adjacency9[] = {-1, 1, -1, -1, -1, 0};
5721     const DWORD point_rep9[] = {0, 1, 2, 3};
5722     /* All mesh data */
5723     ID3DXMesh *mesh = NULL;
5724     ID3DXMesh *mesh_null_check = NULL;
5725     unsigned int attributes[] = {0};
5726     struct
5727     {
5728         const struct vertex_pnc *vertices;
5729         const DWORD *indices;
5730         const DWORD num_vertices;
5731         const DWORD num_faces;
5732         const DWORD *point_reps;
5733         const DWORD *exp_adjacency;
5734         const DWORD *exp_id_adjacency;
5735         const DWORD options;
5736     }
5737     tc[] =
5738     {
5739         {
5740             vertices0,
5741             indices0,
5742             num_vertices0,
5743             num_faces0,
5744             point_rep0,
5745             exp_adjacency0,
5746             exp_id_adjacency0,
5747             options
5748         },
5749         {
5750             vertices1,
5751             indices1,
5752             num_vertices1,
5753             num_faces1,
5754             point_rep1,
5755             exp_adjacency1,
5756             exp_id_adjacency1,
5757             options
5758         },
5759         {
5760             vertices2,
5761             indices2,
5762             num_vertices2,
5763             num_faces2,
5764             point_rep2,
5765             exp_adjacency2,
5766             exp_id_adjacency2,
5767             options
5768         },
5769         {
5770             vertices3,
5771             indices3,
5772             num_vertices3,
5773             num_faces3,
5774             point_rep3,
5775             exp_adjacency3,
5776             exp_id_adjacency3,
5777             options
5778         },
5779         {
5780             vertices4,
5781             indices4,
5782             num_vertices4,
5783             num_faces4,
5784             point_rep4,
5785             exp_adjacency4,
5786             exp_id_adjacency4,
5787             options
5788         },
5789         {
5790             vertices5,
5791             indices5,
5792             num_vertices5,
5793             num_faces5,
5794             point_rep5,
5795             exp_adjacency5,
5796             exp_id_adjacency5,
5797             options
5798         },
5799         {
5800             vertices6,
5801             indices6,
5802             num_vertices6,
5803             num_faces6,
5804             point_rep6,
5805             exp_adjacency6,
5806             exp_id_adjacency6,
5807             options
5808         },
5809         {
5810             vertices7,
5811             indices7,
5812             num_vertices7,
5813             num_faces7,
5814             point_rep7,
5815             exp_adjacency7,
5816             exp_id_adjacency7,
5817             options
5818         },
5819         {
5820             vertices8,
5821             indices8,
5822             num_vertices8,
5823             num_faces8,
5824             point_rep8,
5825             exp_adjacency8,
5826             exp_id_adjacency8,
5827             options
5828         },
5829         {
5830             vertices9,
5831             indices9,
5832             num_vertices9,
5833             num_faces9,
5834             point_rep9,
5835             exp_adjacency9,
5836             exp_id_adjacency9,
5837             options
5838         },
5839         {
5840             vertices8,
5841             (DWORD*)indices8_16bit,
5842             num_vertices8,
5843             num_faces8,
5844             point_rep8,
5845             exp_adjacency8,
5846             exp_id_adjacency8,
5847             options_16bit
5848         },
5849     };
5850     DWORD *adjacency = NULL;
5851
5852     test_context = new_test_context();
5853     if (!test_context)
5854     {
5855         skip("Couldn't create test context\n");
5856         goto cleanup;
5857     }
5858
5859     for (i = 0; i < ARRAY_SIZE(tc); i++)
5860     {
5861         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
5862                             declaration, test_context->device, &mesh);
5863         if (FAILED(hr))
5864         {
5865             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5866             goto cleanup;
5867         }
5868
5869         if (i == 0) /* Save first mesh for later NULL checks */
5870             mesh_null_check = mesh;
5871
5872         adjacency = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
5873         if (!adjacency)
5874         {
5875             skip("Couldn't allocate adjacency array.\n");
5876             goto cleanup;
5877         }
5878
5879         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5880         if (FAILED(hr))
5881         {
5882             skip("Couldn't lock vertex buffer.\n");
5883             goto cleanup;
5884         }
5885         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5886         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5887         if (FAILED(hr))
5888         {
5889             skip("Couldn't unlock vertex buffer.\n");
5890             goto cleanup;
5891         }
5892         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5893         if (FAILED(hr))
5894         {
5895             skip("Couldn't lock index buffer.\n");
5896             goto cleanup;
5897         }
5898         if (tc[i].options & D3DXMESH_32BIT)
5899         {
5900             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5901         }
5902         else
5903         {
5904             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5905         }
5906         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5907         if (FAILED(hr)) {
5908             skip("Couldn't unlock index buffer.\n");
5909             goto cleanup;
5910         }
5911
5912         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5913         if (FAILED(hr))
5914         {
5915             skip("Couldn't lock attributes buffer.\n");
5916             goto cleanup;
5917         }
5918         memcpy(attributes_buffer, attributes, sizeof(attributes));
5919         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5920         if (FAILED(hr))
5921         {
5922             skip("Couldn't unlock attributes buffer.\n");
5923             goto cleanup;
5924         }
5925
5926         /* Convert point representation to adjacency*/
5927         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
5928
5929         hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
5930         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
5931            "Got %x expected D3D_OK\n", i, hr);
5932         /* Check adjacency */
5933         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
5934         {
5935             ok(adjacency[j] == tc[i].exp_adjacency[j],
5936                "Unexpected adjacency information at (%d, %d)."
5937                " Got %d expected %d\n",
5938                i, j, adjacency[j], tc[i].exp_adjacency[j]);
5939         }
5940
5941         /* NULL point representation is considered identity. */
5942         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
5943         hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
5944         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
5945                      "Got %x expected D3D_OK\n", hr);
5946         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
5947         {
5948             ok(adjacency[j] == tc[i].exp_id_adjacency[j],
5949                "Unexpected adjacency information (id) at (%d, %d)."
5950                " Got %d expected %d\n",
5951                i, j, adjacency[j], tc[i].exp_id_adjacency[j]);
5952         }
5953
5954         HeapFree(GetProcessHeap(), 0, adjacency);
5955         adjacency = NULL;
5956         if (i != 0) /* First mesh will be freed during cleanup */
5957             mesh->lpVtbl->Release(mesh);
5958     }
5959
5960     /* NULL checks */
5961     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
5962     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
5963        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5964     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
5965     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
5966        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5967
5968 cleanup:
5969     if (mesh_null_check)
5970         mesh_null_check->lpVtbl->Release(mesh_null_check);
5971     HeapFree(GetProcessHeap(), 0, adjacency);
5972     free_test_context(test_context);
5973 }
5974
5975 static HRESULT init_test_mesh(const DWORD num_faces, const DWORD num_vertices,
5976                               const DWORD options,
5977                               const D3DVERTEXELEMENT9 *declaration,
5978                               IDirect3DDevice9 *device, ID3DXMesh **mesh_ptr,
5979                               const void *vertices, const DWORD vertex_size,
5980                               const DWORD *indices, const DWORD *attributes)
5981 {
5982     HRESULT hr;
5983     void *vertex_buffer;
5984     void *index_buffer;
5985     DWORD *attributes_buffer;
5986     ID3DXMesh *mesh = NULL;
5987
5988     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration, device, mesh_ptr);
5989     if (FAILED(hr))
5990     {
5991         skip("Couldn't create mesh. Got %x expected D3D_OK\n", hr);
5992         goto cleanup;
5993     }
5994     mesh = *mesh_ptr;
5995
5996     hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5997     if (FAILED(hr))
5998     {
5999         skip("Couldn't lock vertex buffer.\n");
6000         goto cleanup;
6001     }
6002     memcpy(vertex_buffer, vertices, num_vertices * vertex_size);
6003     hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6004     if (FAILED(hr))
6005     {
6006         skip("Couldn't unlock vertex buffer.\n");
6007         goto cleanup;
6008     }
6009
6010     hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6011     if (FAILED(hr))
6012     {
6013         skip("Couldn't lock index buffer.\n");
6014         goto cleanup;
6015     }
6016     if (options & D3DXMESH_32BIT)
6017     {
6018         if (indices)
6019             memcpy(index_buffer, indices, 3 * num_faces * sizeof(DWORD));
6020         else
6021         {
6022             /* Fill index buffer with 0, 1, 2, ...*/
6023             DWORD *indices_32bit = (DWORD*)index_buffer;
6024             UINT i;
6025             for (i = 0; i < 3 * num_faces; i++)
6026                 indices_32bit[i] = i;
6027         }
6028     }
6029     else
6030     {
6031         if (indices)
6032             memcpy(index_buffer, indices, 3 * num_faces * sizeof(WORD));
6033         else
6034         {
6035             /* Fill index buffer with 0, 1, 2, ...*/
6036             WORD *indices_16bit = (WORD*)index_buffer;
6037             UINT i;
6038             for (i = 0; i < 3 * num_faces; i++)
6039                 indices_16bit[i] = i;
6040         }
6041     }
6042     hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6043     if (FAILED(hr)) {
6044         skip("Couldn't unlock index buffer.\n");
6045         goto cleanup;
6046     }
6047
6048     hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6049     if (FAILED(hr))
6050     {
6051         skip("Couldn't lock attributes buffer.\n");
6052         goto cleanup;
6053     }
6054
6055     if (attributes)
6056         memcpy(attributes_buffer, attributes, num_faces * sizeof(*attributes));
6057     else
6058         memset(attributes_buffer, 0, num_faces * sizeof(*attributes));
6059
6060     hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6061     if (FAILED(hr))
6062     {
6063         skip("Couldn't unlock attributes buffer.\n");
6064         goto cleanup;
6065     }
6066
6067     hr = D3D_OK;
6068 cleanup:
6069     return hr;
6070 }
6071
6072 /* Using structs instead of bit-fields in order to avoid compiler issues. */
6073 struct udec3
6074 {
6075     UINT x;
6076     UINT y;
6077     UINT z;
6078     UINT w;
6079 };
6080
6081 struct dec3n
6082 {
6083     INT x;
6084     INT y;
6085     INT z;
6086     INT w;
6087 };
6088
6089 static DWORD init_udec3_dword(UINT x, UINT y, UINT z, UINT w)
6090 {
6091     DWORD d = 0;
6092
6093     d |= x & 0x3ff;
6094     d |= (y << 10) & 0xffc00;
6095     d |= (z << 20) & 0x3ff00000;
6096     d |= (w << 30) & 0xc0000000;
6097
6098     return d;
6099 }
6100
6101 static DWORD init_dec3n_dword(INT x, INT y, INT z, INT w)
6102 {
6103     DWORD d = 0;
6104
6105     d |= x & 0x3ff;
6106     d |= (y << 10) & 0xffc00;
6107     d |= (z << 20) & 0x3ff00000;
6108     d |= (w << 30) & 0xc0000000;
6109
6110     return d;
6111 }
6112
6113 static struct udec3 dword_to_udec3(DWORD d)
6114 {
6115     struct udec3 v;
6116
6117     v.x = d & 0x3ff;
6118     v.y = (d & 0xffc00) >> 10;
6119     v.z = (d & 0x3ff00000) >> 20;
6120     v.w = (d & 0xc0000000) >> 30;
6121
6122     return v;
6123 }
6124
6125 static struct dec3n dword_to_dec3n(DWORD d)
6126 {
6127     struct dec3n v;
6128
6129     v.x = d & 0x3ff;
6130     v.y = (d & 0xffc00) >> 10;
6131     v.z = (d & 0x3ff00000) >> 20;
6132     v.w = (d & 0xc0000000) >> 30;
6133
6134     return v;
6135 }
6136
6137 static void check_vertex_components(int line, int mesh_number, int vertex_number, BYTE *got_ptr, const BYTE *exp_ptr, D3DVERTEXELEMENT9 *declaration)
6138 {
6139     const char *usage_strings[] =
6140     {
6141         "position",
6142         "blend weight",
6143         "blend indices",
6144         "normal",
6145         "point size",
6146         "texture coordinates",
6147         "tangent",
6148         "binormal",
6149         "tessellation factor",
6150         "position transformed",
6151         "color",
6152         "fog",
6153         "depth",
6154         "sample"
6155     };
6156     D3DVERTEXELEMENT9 *decl_ptr;
6157     const float PRECISION = 1e-5f;
6158
6159     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
6160     {
6161         switch (decl_ptr->Type)
6162         {
6163             case D3DDECLTYPE_FLOAT1:
6164             {
6165                 FLOAT *got = (FLOAT*)(got_ptr + decl_ptr->Offset);
6166                 FLOAT *exp = (FLOAT*)(exp_ptr + decl_ptr->Offset);
6167                 FLOAT diff = fabsf(*got - *exp);
6168                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got %f for vertex %d %s, expected %f.\n",
6169                     mesh_number, *got, vertex_number, usage_strings[decl_ptr->Usage], *exp);
6170                 break;
6171             }
6172             case D3DDECLTYPE_FLOAT2:
6173             {
6174                 D3DXVECTOR2 *got = (D3DXVECTOR2*)(got_ptr + decl_ptr->Offset);
6175                 D3DXVECTOR2 *exp = (D3DXVECTOR2*)(exp_ptr + decl_ptr->Offset);
6176                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6177                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f) for vertex %d %s, expected (%f, %f).\n",
6178                     mesh_number, got->x, got->y, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y);
6179                 break;
6180             }
6181             case D3DDECLTYPE_FLOAT3:
6182             {
6183                 D3DXVECTOR3 *got = (D3DXVECTOR3*)(got_ptr + decl_ptr->Offset);
6184                 D3DXVECTOR3 *exp = (D3DXVECTOR3*)(exp_ptr + decl_ptr->Offset);
6185                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6186                 diff = max(diff, fabsf(got->z - exp->z));
6187                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f) for vertex %d %s, expected (%f, %f, %f).\n",
6188                     mesh_number, got->x, got->y, got->z, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y, exp->z);
6189                 break;
6190             }
6191             case D3DDECLTYPE_FLOAT4:
6192             {
6193                 D3DXVECTOR4 *got = (D3DXVECTOR4*)(got_ptr + decl_ptr->Offset);
6194                 D3DXVECTOR4 *exp = (D3DXVECTOR4*)(exp_ptr + decl_ptr->Offset);
6195                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6196                 diff = max(diff, fabsf(got->z - exp->z));
6197                 diff = max(diff, fabsf(got->w - exp->w));
6198                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f, %f) for vertex %d %s, expected (%f, %f, %f, %f).\n",
6199                     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);
6200                 break;
6201             }
6202             case D3DDECLTYPE_D3DCOLOR:
6203             {
6204                 BYTE *got = got_ptr + decl_ptr->Offset;
6205                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6206                 BOOL same_color = got[0] == exp[0] && got[1] == exp[1]
6207                                   && got[2] == exp[2] && got[3] == exp[3];
6208                 const char *color_types[] = {"diffuse", "specular", "undefined color"};
6209                 BYTE usage_index = decl_ptr->UsageIndex;
6210                 if (usage_index > 1) usage_index = 2;
6211                 ok_(__FILE__,line)(same_color, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6212                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, color_types[usage_index], exp[0], exp[1], exp[2], exp[3]);
6213                 break;
6214             }
6215             case D3DDECLTYPE_UBYTE4:
6216             case D3DDECLTYPE_UBYTE4N:
6217             {
6218                 BYTE *got = got_ptr + decl_ptr->Offset;
6219                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6220                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6221                             && got[2] == exp[2] && got[3] == exp[3];
6222                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6223                     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]);
6224                 break;
6225             }
6226             case D3DDECLTYPE_SHORT2:
6227             case D3DDECLTYPE_SHORT2N:
6228             {
6229                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6230                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6231                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6232                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd) for vertex %d %s, expected (%hd, %hd).\n",
6233                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6234                 break;
6235             }
6236             case D3DDECLTYPE_SHORT4:
6237             case D3DDECLTYPE_SHORT4N:
6238             {
6239                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6240                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6241                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6242                             && got[2] == exp[2] && got[3] == exp[3];
6243                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd, %hd, %hd) for vertex %d %s, expected (%hd, %hd, %hd, %hd).\n",
6244                     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]);
6245                 break;
6246             }
6247             case D3DDECLTYPE_USHORT2N:
6248             {
6249                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6250                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6251                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6252                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu) for vertex %d %s, expected (%hu, %hu).\n",
6253                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6254                 break;
6255             }
6256             case D3DDECLTYPE_USHORT4N:
6257             {
6258                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6259                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6260                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6261                             && got[2] == exp[2] && got[3] == exp[3];
6262                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu, %hu, %hu) for vertex %d %s, expected (%hu, %hu, %hu, %hu).\n",
6263                     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]);
6264                 break;
6265             }
6266             case D3DDECLTYPE_UDEC3:
6267             {
6268                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6269                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6270                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6271                 struct udec3 got_udec3 = dword_to_udec3(*got);
6272                 struct udec3 exp_udec3 = dword_to_udec3(*exp);
6273                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6274                     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);
6275
6276                 break;
6277             }
6278             case D3DDECLTYPE_DEC3N:
6279             {
6280                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6281                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6282                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6283                 struct dec3n got_dec3n = dword_to_dec3n(*got);
6284                 struct dec3n exp_dec3n = dword_to_dec3n(*exp);
6285                 ok_(__FILE__,line)(same, "Mesh %d: Got (%d, %d, %d, %d) for vertex %d %s, expected (%d, %d, %d, %d).\n",
6286                     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);
6287                 break;
6288             }
6289             case D3DDECLTYPE_FLOAT16_2:
6290             {
6291                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6292                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6293                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6294                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx) for vertex %d %s, expected (%hx, %hx).\n",
6295                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6296                 break;
6297             }
6298             case D3DDECLTYPE_FLOAT16_4:
6299             {
6300                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6301                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6302                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6303                             && got[2] == exp[2] && got[3] == exp[3];
6304                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx, %hx, %hx) for vertex %d %s, expected (%hx, %hx, %hx, %hx).\n",
6305                     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]);
6306                 break;
6307             }
6308             default:
6309                 break;
6310         }
6311     }
6312 }
6313
6314 static void test_weld_vertices(void)
6315 {
6316     HRESULT hr;
6317     struct test_context *test_context = NULL;
6318     DWORD i;
6319     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
6320     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
6321     BYTE *vertices = NULL;
6322     DWORD *indices = NULL;
6323     WORD *indices_16bit = NULL;
6324     const UINT VERTS_PER_FACE = 3;
6325     const D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
6326     struct vertex_normal
6327     {
6328         D3DXVECTOR3 position;
6329         D3DXVECTOR3 normal;
6330     };
6331     struct vertex_blendweight
6332     {
6333         D3DXVECTOR3 position;
6334         FLOAT blendweight;
6335     };
6336     struct vertex_texcoord
6337     {
6338         D3DXVECTOR3 position;
6339         D3DXVECTOR2 texcoord;
6340     };
6341     struct vertex_color
6342     {
6343         D3DXVECTOR3 position;
6344         DWORD color;
6345     };
6346     struct vertex_color_ubyte4
6347     {
6348         D3DXVECTOR3 position;
6349         BYTE color[4];
6350     };
6351     struct vertex_texcoord_short2
6352     {
6353         D3DXVECTOR3 position;
6354         SHORT texcoord[2];
6355     };
6356     struct vertex_texcoord_ushort2n
6357     {
6358         D3DXVECTOR3 position;
6359         USHORT texcoord[2];
6360     };
6361     struct vertex_normal_short4
6362     {
6363         D3DXVECTOR3 position;
6364         SHORT normal[4];
6365     };
6366     struct vertex_color_float4
6367     {
6368         D3DXVECTOR3 position;
6369         D3DXVECTOR4 color;
6370     };
6371     struct vertex_texcoord_float16_2
6372     {
6373         D3DXVECTOR3 position;
6374         WORD texcoord[2];
6375     };
6376     struct vertex_texcoord_float16_4
6377     {
6378         D3DXVECTOR3 position;
6379         WORD texcoord[4];
6380     };
6381     struct vertex_normal_udec3
6382     {
6383         D3DXVECTOR3 position;
6384         DWORD normal;
6385     };
6386     struct vertex_normal_dec3n
6387     {
6388         D3DXVECTOR3 position;
6389         DWORD normal;
6390     };
6391     UINT vertex_size_normal = sizeof(struct vertex_normal);
6392     UINT vertex_size_blendweight = sizeof(struct vertex_blendweight);
6393     UINT vertex_size_texcoord = sizeof(struct vertex_texcoord);
6394     UINT vertex_size_color = sizeof(struct vertex_color);
6395     UINT vertex_size_color_ubyte4 = sizeof(struct vertex_color_ubyte4);
6396     UINT vertex_size_texcoord_short2 = sizeof(struct vertex_texcoord_short2);
6397     UINT vertex_size_normal_short4 = sizeof(struct vertex_normal_short4);
6398     UINT vertex_size_color_float4 = sizeof(struct vertex_color_float4);
6399     UINT vertex_size_texcoord_float16_2 = sizeof(struct vertex_texcoord_float16_2);
6400     UINT vertex_size_texcoord_float16_4 = sizeof(struct vertex_texcoord_float16_4);
6401     UINT vertex_size_normal_udec3 = sizeof(struct vertex_normal_udec3);
6402     UINT vertex_size_normal_dec3n = sizeof(struct vertex_normal_dec3n);
6403     D3DVERTEXELEMENT9 declaration_normal[] =
6404     {
6405         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6406         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6407         D3DDECL_END()
6408     };
6409     D3DVERTEXELEMENT9 declaration_normal3[] =
6410     {
6411         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 3},
6412         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6413         D3DDECL_END()
6414     };
6415     D3DVERTEXELEMENT9 declaration_blendweight[] =
6416     {
6417         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6418         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
6419         D3DDECL_END()
6420     };
6421     D3DVERTEXELEMENT9 declaration_texcoord[] =
6422     {
6423         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6424         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6425         D3DDECL_END()
6426     };
6427     D3DVERTEXELEMENT9 declaration_color[] =
6428     {
6429         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6430         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6431         D3DDECL_END()
6432     };
6433     D3DVERTEXELEMENT9 declaration_color_ubyte4n[] =
6434     {
6435         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6436         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6437         D3DDECL_END()
6438     };
6439     D3DVERTEXELEMENT9 declaration_color_ubyte4[] =
6440     {
6441         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6442         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6443         D3DDECL_END()
6444     };
6445     D3DVERTEXELEMENT9 declaration_texcoord_short2[] =
6446     {
6447         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6448         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6449         D3DDECL_END()
6450     };
6451     D3DVERTEXELEMENT9 declaration_texcoord_short2n[] =
6452     {
6453         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6454         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6455         D3DDECL_END()
6456     };
6457     D3DVERTEXELEMENT9 declaration_texcoord_ushort2n[] =
6458     {
6459         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6460         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6461         D3DDECL_END()
6462     };
6463     D3DVERTEXELEMENT9 declaration_normal_short4[] =
6464     {
6465         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6466         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6467         D3DDECL_END()
6468     };
6469     D3DVERTEXELEMENT9 declaration_normal_short4n[] =
6470     {
6471         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6472         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6473         D3DDECL_END()
6474     };
6475     D3DVERTEXELEMENT9 declaration_normal_ushort4n[] =
6476     {
6477         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6478         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6479         D3DDECL_END()
6480     };
6481     D3DVERTEXELEMENT9 declaration_texcoord10[] =
6482     {
6483         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6484         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 10},
6485         D3DDECL_END()
6486     };
6487     D3DVERTEXELEMENT9 declaration_color2[] =
6488     {
6489         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6490         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
6491         D3DDECL_END()
6492     };
6493     D3DVERTEXELEMENT9 declaration_color2_float4[] =
6494     {
6495         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6496         {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
6497         D3DDECL_END()
6498     };
6499     D3DVERTEXELEMENT9 declaration_texcoord_float16_2[] =
6500     {
6501         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6502         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6503         D3DDECL_END()
6504     };
6505     D3DVERTEXELEMENT9 declaration_texcoord_float16_4[] =
6506     {
6507         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6508         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6509         D3DDECL_END()
6510     };
6511     D3DVERTEXELEMENT9 declaration_normal_udec3[] =
6512    {
6513         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6514         {0, 12, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6515         D3DDECL_END()
6516     };
6517     D3DVERTEXELEMENT9 declaration_normal_dec3n[] =
6518     {
6519         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6520         {0, 12, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6521         D3DDECL_END()
6522     };
6523     /* Test 0. One face and no welding.
6524      *
6525      * 0--1
6526      * | /
6527      * |/
6528      * 2
6529      */
6530     const struct vertex vertices0[] =
6531     {
6532         {{ 0.0f,  3.0f,  0.f}, up},
6533         {{ 2.0f,  3.0f,  0.f}, up},
6534         {{ 0.0f,  0.0f,  0.f}, up},
6535     };
6536     const DWORD indices0[] = {0, 1, 2};
6537     const DWORD attributes0[] = {0};
6538     const DWORD exp_indices0[] = {0, 1, 2};
6539     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
6540     const UINT num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
6541     const DWORD flags0 = D3DXWELDEPSILONS_WELDALL;
6542     /* epsilons0 is NULL */
6543     const DWORD adjacency0[] = {-1, -1, -1};
6544     const struct vertex exp_vertices0[] =
6545     {
6546         {{ 0.0f,  3.0f,  0.f}, up},
6547         {{ 2.0f,  3.0f,  0.f}, up},
6548         {{ 0.0f,  0.0f,  0.f}, up},
6549     };
6550     const DWORD exp_face_remap0[] = {0};
6551     const DWORD exp_vertex_remap0[] = {0, 1, 2};
6552     const DWORD exp_new_num_vertices0 = ARRAY_SIZE(exp_vertices0);
6553     /* Test 1. Two vertices should be removed without regard to epsilon.
6554      *
6555      * 0--1 3
6556      * | / /|
6557      * |/ / |
6558      * 2 5--4
6559      */
6560     const struct vertex_normal vertices1[] =
6561     {
6562         {{ 0.0f,  3.0f,  0.f}, up},
6563         {{ 2.0f,  3.0f,  0.f}, up},
6564         {{ 0.0f,  0.0f,  0.f}, up},
6565
6566         {{ 3.0f,  3.0f,  0.f}, up},
6567         {{ 3.0f,  0.0f,  0.f}, up},
6568         {{ 1.0f,  0.0f,  0.f}, up},
6569     };
6570     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
6571     const DWORD attributes1[] = {0, 0};
6572     const UINT num_vertices1 = ARRAY_SIZE(vertices1);
6573     const UINT num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
6574     const DWORD flags1 = D3DXWELDEPSILONS_WELDALL;
6575     /* epsilons1 is NULL */
6576     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
6577     const struct vertex_normal exp_vertices1[] =
6578     {
6579         {{ 0.0f,  3.0f,  0.f}, up},
6580         {{ 2.0f,  3.0f,  0.f}, up},
6581         {{ 0.0f,  0.0f,  0.f}, up},
6582
6583         {{ 3.0f,  0.0f,  0.f}, up}
6584     };
6585     const DWORD exp_indices1[] = {0, 1, 2, 1, 3, 2};
6586     const DWORD exp_face_remap1[] = {0, 1};
6587     const DWORD exp_vertex_remap1[] = {0, 1, 2, 4, -1, -1};
6588     const DWORD exp_new_num_vertices1 = ARRAY_SIZE(exp_vertices1);
6589     /* Test 2. Two faces. No vertices should be removed because of normal
6590      * epsilon, but the positions should be replaced. */
6591     const struct vertex_normal vertices2[] =
6592     {
6593         {{ 0.0f,  3.0f,  0.f}, up},
6594         {{ 2.0f,  3.0f,  0.f}, up},
6595         {{ 0.0f,  0.0f,  0.f}, up},
6596
6597         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6598         {{ 3.0f,  0.0f,  0.f}, up},
6599         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6600     };
6601     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
6602     const DWORD attributes2[] = {0, 0};
6603     const UINT num_vertices2 = ARRAY_SIZE(vertices2);
6604     const UINT num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
6605     DWORD flags2 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6606     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};
6607     const DWORD adjacency2[] = {-1, 1, -1, -1, -1, 0};
6608     const struct vertex_normal exp_vertices2[] =
6609     {
6610         {{ 0.0f,  3.0f,  0.f}, up},
6611         {{ 2.0f,  3.0f,  0.f}, up},
6612         {{ 0.0f,  0.0f,  0.f}, up},
6613
6614         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6615         {{ 3.0f,  0.0f,  0.f}, up},
6616         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6617     };
6618     const DWORD exp_indices2[] = {0, 1, 2, 3, 4, 5};
6619     const DWORD exp_face_remap2[] = {0, 1};
6620     const DWORD exp_vertex_remap2[] = {0, 1, 2, 3, 4, 5};
6621     const DWORD exp_new_num_vertices2 = ARRAY_SIZE(exp_vertices2);
6622     /* Test 3. Two faces. One vertex should be removed because of normal epsilon. */
6623     const struct vertex_normal vertices3[] =
6624     {
6625         {{ 0.0f,  3.0f,  0.f}, up},
6626         {{ 2.0f,  3.0f,  0.f}, up},
6627         {{ 0.0f,  0.0f,  0.f}, up},
6628
6629         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6630         {{ 3.0f,  0.0f,  0.f}, up},
6631         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6632     };
6633     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
6634     const DWORD attributes3[] = {0, 0};
6635     const UINT num_vertices3 = ARRAY_SIZE(vertices3);
6636     const UINT num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
6637     DWORD flags3 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6638     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};
6639     const DWORD adjacency3[] = {-1, 1, -1, -1, -1, 0};
6640     const struct vertex_normal exp_vertices3[] =
6641     {
6642         {{ 0.0f,  3.0f,  0.f}, up},
6643         {{ 2.0f,  3.0f,  0.f}, up},
6644         {{ 0.0f,  0.0f,  0.f}, up},
6645
6646         {{ 3.0f,  0.0f,  0.f}, up},
6647         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6648     };
6649     const DWORD exp_indices3[] = {0, 1, 2, 1, 3, 4};
6650     const DWORD exp_face_remap3[] = {0, 1};
6651     const DWORD exp_vertex_remap3[] = {0, 1, 2, 4, 5, -1};
6652     const DWORD exp_new_num_vertices3 = ARRAY_SIZE(exp_vertices3);
6653     /* Test 4  Two faces. Two vertices should be removed. */
6654     const struct vertex_normal vertices4[] =
6655     {
6656         {{ 0.0f,  3.0f,  0.f}, up},
6657         {{ 2.0f,  3.0f,  0.f}, up},
6658         {{ 0.0f,  0.0f,  0.f}, up},
6659
6660         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6661         {{ 3.0f,  0.0f,  0.f}, up},
6662         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6663     };
6664     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
6665     const DWORD attributes4[] = {0, 0};
6666     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
6667     const UINT num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
6668     DWORD flags4 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6669     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};
6670     const DWORD adjacency4[] = {-1, 1, -1, -1, -1, 0};
6671     const struct vertex_normal exp_vertices4[] =
6672     {
6673         {{ 0.0f,  3.0f,  0.f}, up},
6674         {{ 2.0f,  3.0f,  0.f}, up},
6675         {{ 0.0f,  0.0f,  0.f}, up},
6676
6677         {{ 3.0f,  0.0f,  0.f}, up},
6678     };
6679     const DWORD exp_indices4[] = {0, 1, 2, 1, 3, 2};
6680     const DWORD exp_face_remap4[] = {0, 1};
6681     const DWORD exp_vertex_remap4[] = {0, 1, 2, 4, -1, -1};
6682     const DWORD exp_new_num_vertices4 = ARRAY_SIZE(exp_vertices4);
6683     /* Test 5. Odd face ordering.
6684      *
6685      * 0--1 6 3
6686      * | / /| |\
6687      * |/ / | | \
6688      * 2 8--7 5--4
6689      */
6690     const struct vertex_normal vertices5[] =
6691     {
6692         {{ 0.0f,  3.0f,  0.f}, up},
6693         {{ 2.0f,  3.0f,  0.f}, up},
6694         {{ 0.0f,  0.0f,  0.f}, up},
6695
6696         {{ 3.0f,  3.0f,  0.f}, up},
6697         {{ 3.0f,  0.0f,  0.f}, up},
6698         {{ 1.0f,  0.0f,  0.f}, up},
6699
6700         {{ 4.0f,  3.0f,  0.f}, up},
6701         {{ 6.0f,  0.0f,  0.f}, up},
6702         {{ 4.0f,  0.0f,  0.f}, up},
6703     };
6704     const DWORD indices5[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
6705     const DWORD exp_indices5[] = {0, 1, 2, 1, 4, 2, 1, 3, 4};
6706     const DWORD attributes5[] = {0, 0, 0};
6707     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
6708     const UINT num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
6709     DWORD flags5 = D3DXWELDEPSILONS_WELDALL;
6710     const DWORD adjacency5[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
6711     const struct vertex_normal exp_vertices5[] =
6712     {
6713         {{ 0.0f,  3.0f,  0.f}, up},
6714         {{ 2.0f,  3.0f,  0.f}, up},
6715         {{ 0.0f,  0.0f,  0.f}, up},
6716
6717         {{ 3.0f,  0.0f,  0.f}, up},
6718         {{ 1.0f,  0.0f,  0.f}, up},
6719     };
6720     const DWORD exp_face_remap5[] = {0, 1, 2};
6721     const DWORD exp_vertex_remap5[] = {0, 1, 2, 4, 5, -1, -1, -1, -1};
6722     const DWORD exp_new_num_vertices5 = ARRAY_SIZE(exp_vertices5);
6723     /* Test 6. Two faces. Do not remove flag is used, so no vertices should be
6724      * removed. */
6725     const struct vertex_normal vertices6[] =
6726     {
6727         {{ 0.0f,  3.0f,  0.f}, up},
6728         {{ 2.0f,  3.0f,  0.f}, up},
6729         {{ 0.0f,  0.0f,  0.f}, up},
6730
6731         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6732         {{ 3.0f,  0.0f,  0.f}, up},
6733         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6734     };
6735     const DWORD indices6[] = {0, 1, 2, 3, 4, 5};
6736     const DWORD attributes6[] = {0, 0};
6737     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
6738     const UINT num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
6739     DWORD flags6 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTREMOVEVERTICES;
6740     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};
6741     const DWORD adjacency6[] = {-1, 1, -1, -1, -1, 0};
6742     const struct vertex_normal exp_vertices6[] =
6743     {
6744         {{ 0.0f,  3.0f,  0.f}, up},
6745         {{ 2.0f,  3.0f,  0.f}, up},
6746         {{ 0.0f,  0.0f,  0.f}, up},
6747
6748         {{ 2.0f,  3.0f,  0.f}, up},
6749         {{ 3.0f,  0.0f,  0.f}, up},
6750         {{ 0.0f,  0.0f,  0.f}, up},
6751
6752     };
6753     const DWORD exp_indices6[] = {0, 1, 2, 3, 4, 5};
6754     const DWORD exp_face_remap6[] = {0, 1};
6755     const DWORD exp_vertex_remap6[] = {0, 1, 2, 3, 4, 5};
6756     const DWORD exp_new_num_vertices6 = ARRAY_SIZE(exp_vertices6);
6757     /* Test 7. Same as test 6 but with 16 bit indices. */
6758     const WORD indices6_16bit[] = {0, 1, 2, 3, 4, 5};
6759     /* Test 8. No flags. Same result as D3DXWELDEPSILONS_WELDPARTIALMATCHES. */
6760     const struct vertex_normal vertices8[] =
6761     {
6762         {{ 0.0f,  3.0f,  0.f}, up},
6763         {{ 2.0f,  3.0f,  0.f}, up},
6764         {{ 0.0f,  0.0f,  0.f}, up},
6765
6766         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6767         {{ 3.0f,  0.0f,  0.f}, up},
6768         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6769     };
6770     const DWORD indices8[] = {0, 1, 2, 1, 3, 4};
6771     const DWORD attributes8[] = {0, 0};
6772     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
6773     const UINT num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
6774     DWORD flags8 = 0;
6775     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};
6776     const DWORD adjacency8[] = {-1, 1, -1, -1, -1, 0};
6777     const struct vertex_normal exp_vertices8[] =
6778     {
6779         {{ 0.0f,  3.0f,  0.f}, up},
6780         {{ 2.0f,  3.0f,  0.f}, up},
6781         {{ 0.0f,  0.0f,  0.f}, up},
6782
6783         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6784         {{ 3.0f,  0.0f,  0.f}, up},
6785     };
6786     const DWORD exp_indices8[] = {0, 1, 2, 1, 3, 4};
6787     const DWORD exp_face_remap8[] = {0, 1};
6788     const DWORD exp_vertex_remap8[] = {0, 1, 2, 3, 4, -1};
6789     const DWORD exp_new_num_vertices8 = ARRAY_SIZE(exp_vertices8);
6790     /* Test 9. Vertices are removed even though they belong to separate
6791      * attribute groups if D3DXWELDEPSILONS_DONOTSPLIT is set. */
6792     const struct vertex_normal vertices9[] =
6793     {
6794         {{ 0.0f,  3.0f,  0.f}, up},
6795         {{ 2.0f,  3.0f,  0.f}, up},
6796         {{ 0.0f,  0.0f,  0.f}, up},
6797
6798         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6799         {{ 3.0f,  0.0f,  0.f}, up},
6800         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6801     };
6802     const DWORD indices9[] = {0, 1, 2, 3, 4, 5};
6803     const DWORD attributes9[] = {0, 1};
6804     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
6805     const UINT num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
6806     DWORD flags9 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTSPLIT;
6807     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};
6808     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
6809     const struct vertex_normal exp_vertices9[] =
6810     {
6811         {{ 0.0f,  3.0f,  0.f}, up},
6812         {{ 2.0f,  3.0f,  0.f}, up},
6813         {{ 0.0f,  0.0f,  0.f}, up},
6814
6815         {{ 3.0f,  0.0f,  0.f}, up},
6816     };
6817     const DWORD exp_indices9[] = {0, 1, 2, 1, 3, 2};
6818     const DWORD exp_face_remap9[] = {0, 1};
6819     const DWORD exp_vertex_remap9[] = {0, 1, 2, 4, -1, -1};
6820     const DWORD exp_new_num_vertices9 = ARRAY_SIZE(exp_vertices9);
6821     /* Test 10. Weld blendweight (FLOAT1). */
6822     const struct vertex_blendweight vertices10[] =
6823     {
6824         {{ 0.0f,  3.0f,  0.f}, 1.0f},
6825         {{ 2.0f,  3.0f,  0.f}, 1.0f},
6826         {{ 0.0f,  0.0f,  0.f}, 1.0f},
6827
6828         {{ 3.0f,  3.0f,  0.f}, 0.9},
6829         {{ 3.0f,  0.0f,  0.f}, 1.0},
6830         {{ 1.0f,  0.0f,  0.f}, 0.4},
6831     };
6832     const DWORD indices10[] = {0, 1, 2, 3, 4, 5};
6833     const DWORD attributes10[] = {0, 0};
6834     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
6835     const UINT num_faces10 = ARRAY_SIZE(indices10) / VERTS_PER_FACE;
6836     DWORD flags10 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6837     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};
6838     const DWORD adjacency10[] = {-1, 1, -1, -1, -1, 0};
6839     const struct vertex_blendweight exp_vertices10[] =
6840     {
6841         {{ 0.0f,  3.0f,  0.f}, 1.0f},
6842         {{ 2.0f,  3.0f,  0.f}, 1.0f},
6843         {{ 0.0f,  0.0f,  0.f}, 1.0f},
6844
6845         {{ 3.0f,  0.0f,  0.f}, 1.0},
6846         {{ 0.0f,  0.0f,  0.f}, 0.4},
6847     };
6848     const DWORD exp_indices10[] = {0, 1, 2, 1, 3, 4};
6849     const DWORD exp_face_remap10[] = {0, 1};
6850     const DWORD exp_vertex_remap10[] = {0, 1, 2, 4, 5, -1};
6851     const DWORD exp_new_num_vertices10 = ARRAY_SIZE(exp_vertices10);
6852     /* Test 11. Weld texture coordinates. */
6853     const struct vertex_texcoord vertices11[] =
6854     {
6855         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
6856         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
6857         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
6858
6859         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
6860         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
6861         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
6862     };
6863     const DWORD indices11[] = {0, 1, 2, 3, 4, 5};
6864     const DWORD attributes11[] = {0, 0};
6865     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
6866     const UINT num_faces11 = ARRAY_SIZE(indices11) / VERTS_PER_FACE;
6867     DWORD flags11 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6868     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};
6869     const DWORD adjacency11[] = {-1, 1, -1, -1, -1, 0};
6870     const struct vertex_texcoord exp_vertices11[] =
6871     {
6872         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
6873         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
6874         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
6875
6876         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
6877         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
6878     };
6879     const DWORD exp_indices11[] = {0, 1, 2, 1, 3, 4};
6880     const DWORD exp_face_remap11[] = {0, 1};
6881     const DWORD exp_vertex_remap11[] = {0, 1, 2, 4, 5, -1};
6882     const DWORD exp_new_num_vertices11 = ARRAY_SIZE(exp_vertices11);
6883     /* Test 12. Weld with color. */
6884     const struct vertex_color vertices12[] =
6885     {
6886         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6887         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6888         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6889
6890         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
6891         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6892         {{ 1.0f,  0.0f,  0.f}, 0x88888888},
6893     };
6894     const DWORD indices12[] = {0, 1, 2, 3, 4, 5};
6895     const DWORD attributes12[] = {0, 0};
6896     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
6897     const UINT num_faces12 = ARRAY_SIZE(indices12) / VERTS_PER_FACE;
6898     DWORD flags12 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6899     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};
6900     const DWORD adjacency12[] = {-1, 1, -1, -1, -1, 0};
6901     const struct vertex_color exp_vertices12[] =
6902     {
6903         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6904         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6905         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6906
6907         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
6908         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6909     };
6910     const DWORD exp_indices12[] = {0, 1, 2, 3, 4, 2};
6911     const DWORD exp_face_remap12[] = {0, 1};
6912     const DWORD exp_vertex_remap12[] = {0, 1, 2, 3, 4, -1};
6913     const DWORD exp_new_num_vertices12 = ARRAY_SIZE(exp_vertices12);
6914     /* Test 13. Two faces. One vertex should be removed because of normal epsilon.
6915      * This is similar to test 3, but the declaration has been changed to NORMAL3.
6916      */
6917     const struct vertex_normal vertices13[] =
6918     {
6919         {{ 0.0f,  3.0f,  0.f}, up},
6920         {{ 2.0f,  3.0f,  0.f}, up},
6921         {{ 0.0f,  0.0f,  0.f}, up},
6922
6923         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
6924         {{ 3.0f,  0.0f,  0.f}, up},
6925         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6926     };
6927     const DWORD indices13[] = {0, 1, 2, 3, 4, 5};
6928     const DWORD attributes13[] = {0, 0};
6929     const UINT num_vertices13 = ARRAY_SIZE(vertices3);
6930     const UINT num_faces13 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
6931     DWORD flags13 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6932     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};
6933     const DWORD adjacency13[] = {-1, 1, -1, -1, -1, 0};
6934     const struct vertex_normal exp_vertices13[] =
6935     {
6936         {{ 0.0f,  3.0f,  0.f}, up},
6937         {{ 2.0f,  3.0f,  0.f}, up},
6938         {{ 0.0f,  0.0f,  0.f}, up},
6939
6940         {{ 3.0f,  0.0f,  0.f}, up},
6941         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
6942     };
6943     const DWORD exp_indices13[] = {0, 1, 2, 1, 3, 4};
6944     const DWORD exp_face_remap13[] = {0, 1};
6945     const DWORD exp_vertex_remap13[] = {0, 1, 2, 4, 5, -1};
6946     const DWORD exp_new_num_vertices13 = ARRAY_SIZE(exp_vertices13);
6947     /* Test 14. Another test for welding with color. */
6948     const struct vertex_color vertices14[] =
6949     {
6950         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6951         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6952         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6953
6954         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
6955         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6956         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
6957     };
6958     const DWORD indices14[] = {0, 1, 2, 3, 4, 5};
6959     const DWORD attributes14[] = {0, 0};
6960     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
6961     const UINT num_faces14 = ARRAY_SIZE(indices14) / VERTS_PER_FACE;
6962     DWORD flags14 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6963     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};
6964     const DWORD adjacency14[] = {-1, 1, -1, -1, -1, 0};
6965     const struct vertex_color exp_vertices14[] =
6966     {
6967         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6968         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
6969         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6970
6971         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
6972         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
6973     };
6974     const DWORD exp_indices14[] = {0, 1, 2, 3, 4, 2};
6975     const DWORD exp_face_remap14[] = {0, 1};
6976     const DWORD exp_vertex_remap14[] = {0, 1, 2, 3, 4, -1};
6977     const DWORD exp_new_num_vertices14 = ARRAY_SIZE(exp_vertices14);
6978     /* Test 15. Weld with color, but as UBYTE4N instead of D3DCOLOR. It shows
6979      * that UBYTE4N and D3DCOLOR are compared the same way.
6980      */
6981     const struct vertex_color_ubyte4 vertices15[] =
6982     {
6983         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
6984         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
6985         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
6986
6987         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
6988         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
6989         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
6990     };
6991     const DWORD indices15[] = {0, 1, 2, 3, 4, 5};
6992     const DWORD attributes15[] = {0, 0};
6993     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
6994     const UINT num_faces15 = ARRAY_SIZE(indices15) / VERTS_PER_FACE;
6995     DWORD flags15 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
6996     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};
6997     const DWORD adjacency15[] = {-1, 1, -1, -1, -1, 0};
6998     const struct vertex_color_ubyte4 exp_vertices15[] =
6999     {
7000         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7001         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7002         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7003
7004         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7005         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7006     };
7007     const DWORD exp_indices15[] = {0, 1, 2, 3, 4, 2};
7008     const DWORD exp_face_remap15[] = {0, 1};
7009     const DWORD exp_vertex_remap15[] = {0, 1, 2, 3, 4, -1};
7010     const DWORD exp_new_num_vertices15 = ARRAY_SIZE(exp_vertices15);
7011     /* Test 16. Weld with color, but as UBYTE4 instead of D3DCOLOR. It shows
7012      * that UBYTE4 is not normalized and that epsilon is truncated and compared
7013      * directly to each of the four bytes.
7014      */
7015     const struct vertex_color_ubyte4 vertices16[] =
7016     {
7017         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7018         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7019         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7020
7021         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7022         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7023         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7024     };
7025     const DWORD indices16[] = {0, 1, 2, 3, 4, 5};
7026     const DWORD attributes16[] = {0, 0};
7027     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
7028     const UINT num_faces16 = ARRAY_SIZE(indices16) / VERTS_PER_FACE;
7029     DWORD flags16 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7030     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};
7031     const DWORD adjacency16[] = {-1, 1, -1, -1, -1, 0};
7032     const struct vertex_color_ubyte4 exp_vertices16[] =
7033     {
7034         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7035         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7036         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7037
7038         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7039         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7040     };
7041     const DWORD exp_indices16[] = {0, 1, 2, 3, 4, 2};
7042     const DWORD exp_face_remap16[] = {0, 1};
7043     const DWORD exp_vertex_remap16[] = {0, 1, 2, 3, 4, -1};
7044     const DWORD exp_new_num_vertices16 = ARRAY_SIZE(exp_vertices16);
7045     /* Test 17. Weld texture coordinates but as SHORT2 instead of D3DXVECTOR2.*/
7046     const struct vertex_texcoord_short2 vertices17[] =
7047     {
7048         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7049         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7050         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7051
7052         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7053         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7054         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7055     };
7056     const DWORD indices17[] = {0, 1, 2, 3, 4, 5};
7057     const DWORD attributes17[] = {0, 0};
7058     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
7059     const UINT num_faces17 = ARRAY_SIZE(indices17) / VERTS_PER_FACE;
7060     DWORD flags17 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7061     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};
7062     const DWORD adjacency17[] = {-1, 1, -1, -1, -1, 0};
7063     const struct vertex_texcoord_short2 exp_vertices17[] =
7064     {
7065         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7066         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7067         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7068
7069         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7070         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7071     };
7072     const DWORD exp_indices17[] = {0, 1, 2, 3, 4, 2};
7073     const DWORD exp_face_remap17[] = {0, 1};
7074     const DWORD exp_vertex_remap17[] = {0, 1, 2, 3, 4, -1};
7075     const DWORD exp_new_num_vertices17 = ARRAY_SIZE(exp_vertices17);
7076     /* Test 18. Weld texture coordinates but as SHORT2N instead of D3DXVECTOR2. */
7077     const struct vertex_texcoord_short2 vertices18[] =
7078     {
7079         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7080         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7081         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7082
7083         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7084         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7085         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7086     };
7087     const DWORD indices18[] = {0, 1, 2, 3, 4, 5};
7088     const DWORD attributes18[] = {0, 0};
7089     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
7090     const UINT num_faces18 = ARRAY_SIZE(indices18) / VERTS_PER_FACE;
7091     DWORD flags18 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7092     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};
7093     const DWORD adjacency18[] = {-1, 1, -1, -1, -1, 0};
7094     const struct vertex_texcoord_short2 exp_vertices18[] =
7095     {
7096         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7097         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7098         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7099
7100         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7101         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7102     };
7103     const DWORD exp_indices18[] = {0, 1, 2, 3, 4, 2};
7104     const DWORD exp_face_remap18[] = {0, 1};
7105     const DWORD exp_vertex_remap18[] = {0, 1, 2, 3, 4, -1};
7106     const DWORD exp_new_num_vertices18 = ARRAY_SIZE(exp_vertices18);
7107     /* Test 19.  Weld texture coordinates but as USHORT2N instead of D3DXVECTOR2. */
7108     const struct vertex_texcoord_ushort2n vertices19[] =
7109     {
7110         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7111         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7112         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7113
7114         {{ 3.0f,  3.0f,  0.f}, {65535, 65535}},
7115         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7116         {{ 1.0f,  0.0f,  0.f}, {65534, 65534}},
7117     };
7118     const DWORD indices19[] = {0, 1, 2, 3, 4, 5};
7119     const DWORD attributes19[] = {0, 0};
7120     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
7121     const UINT num_faces19 = ARRAY_SIZE(indices19) / VERTS_PER_FACE;
7122     DWORD flags19 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7123     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};
7124     const DWORD adjacency19[] = {-1, 1, -1, -1, -1, 0};
7125     const struct vertex_texcoord_ushort2n exp_vertices19[] =
7126     {
7127         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7128         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7129         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7130
7131         {{ 2.0f,  3.0f,  0.f}, {65535, 65535}},
7132         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7133     };
7134     const DWORD exp_indices19[] = {0, 1, 2, 3, 4, 2};
7135     const DWORD exp_face_remap19[] = {0, 1};
7136     const DWORD exp_vertex_remap19[] = {0, 1, 2, 3, 4, -1};
7137     const DWORD exp_new_num_vertices19 = ARRAY_SIZE(exp_vertices19);
7138     /* Test 20.  Weld normal as SHORT4 instead of D3DXVECTOR3. */
7139     const struct vertex_normal_short4 vertices20[] =
7140     {
7141         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7142         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7143         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7144
7145         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7146         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7147         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7148     };
7149     const DWORD indices20[] = {0, 1, 2, 3, 4, 5};
7150     const DWORD attributes20[] = {0, 0};
7151     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
7152     const UINT num_faces20 = ARRAY_SIZE(indices20) / VERTS_PER_FACE;
7153     DWORD flags20 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7154     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};
7155     const DWORD adjacency20[] = {-1, 1, -1, -1, -1, 0};
7156     const struct vertex_normal_short4 exp_vertices20[] =
7157     {
7158         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7159         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7160         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7161
7162         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7163         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7164     };
7165     const DWORD exp_indices20[] = {0, 1, 2, 3, 4, 2};
7166     const DWORD exp_face_remap20[] = {0, 1};
7167     const DWORD exp_vertex_remap20[] = {0, 1, 2, 3, 4, -1};
7168     const DWORD exp_new_num_vertices20 = ARRAY_SIZE(exp_vertices20);
7169     /* Test 21.  Weld normal as SHORT4N instead of D3DXVECTOR3. */
7170     const struct vertex_normal_short4 vertices21[] =
7171     {
7172         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7173         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7174         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7175
7176         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7177         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7178         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7179     };
7180     const DWORD indices21[] = {0, 1, 2, 3, 4, 5};
7181     const DWORD attributes21[] = {0, 0};
7182     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
7183     const UINT num_faces21 = ARRAY_SIZE(indices21) / VERTS_PER_FACE;
7184     DWORD flags21 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7185     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};
7186     const DWORD adjacency21[] = {-1, 1, -1, -1, -1, 0};
7187     const struct vertex_normal_short4 exp_vertices21[] =
7188     {
7189         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7190         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7191         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7192
7193         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7194         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7195     };
7196     const DWORD exp_indices21[] = {0, 1, 2, 3, 4, 2};
7197     const DWORD exp_face_remap21[] = {0, 1};
7198     const DWORD exp_vertex_remap21[] = {0, 1, 2, 3, 4, -1};
7199     const DWORD exp_new_num_vertices21 = ARRAY_SIZE(exp_vertices21);
7200     /* Test 22.  Weld normal as USHORT4N instead of D3DXVECTOR3. */
7201     const struct vertex_normal_short4 vertices22[] =
7202     {
7203         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7204         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7205         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7206
7207         {{ 3.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7208         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7209         {{ 1.0f,  0.0f,  0.f}, {65534, 65534, 65534, 65534}},
7210     };
7211     const DWORD indices22[] = {0, 1, 2, 3, 4, 5};
7212     const DWORD attributes22[] = {0, 0};
7213     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
7214     const UINT num_faces22 = ARRAY_SIZE(indices22) / VERTS_PER_FACE;
7215     DWORD flags22 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7216     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};
7217     const DWORD adjacency22[] = {-1, 1, -1, -1, -1, 0};
7218     const struct vertex_normal_short4 exp_vertices22[] =
7219     {
7220         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7221         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7222         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7223
7224         {{ 2.0f,  3.0f,  0.f}, {65535, 65535, 65535, 65535}},
7225         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7226     };
7227     const DWORD exp_indices22[] = {0, 1, 2, 3, 4, 2};
7228     const DWORD exp_face_remap22[] = {0, 1};
7229     const DWORD exp_vertex_remap22[] = {0, 1, 2, 3, 4, -1};
7230     const DWORD exp_new_num_vertices22 = ARRAY_SIZE(exp_vertices22);
7231     /* Test 23. Weld texture coordinates as FLOAT16_2. Similar to test 11, but
7232      * with texture coordinates converted to float16 in hex. */
7233     const struct vertex_texcoord_float16_2 vertices23[] =
7234     {
7235         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7236         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7237         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7238
7239         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
7240         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7241         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7242     };
7243     const DWORD indices23[] = {0, 1, 2, 3, 4, 5};
7244     const DWORD attributes23[] = {0, 0};
7245     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
7246     const UINT num_faces23 = ARRAY_SIZE(indices23) / VERTS_PER_FACE;
7247     DWORD flags23 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7248     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};
7249     const DWORD adjacency23[] = {-1, 1, -1, -1, -1, 0};
7250     const struct vertex_texcoord_float16_2 exp_vertices23[] =
7251     {
7252         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7253         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7254         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7255
7256         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7257         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7258     };
7259     const DWORD exp_indices23[] = {0, 1, 2, 1, 3, 4};
7260     const DWORD exp_face_remap23[] = {0, 1};
7261     const DWORD exp_vertex_remap23[] = {0, 1, 2, 4, 5, -1};
7262     const DWORD exp_new_num_vertices23 = ARRAY_SIZE(exp_vertices23);
7263     /* Test 24. Weld texture coordinates as FLOAT16_4. Similar to test 24. */
7264     const struct vertex_texcoord_float16_4 vertices24[] =
7265     {
7266         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7267         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7268         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7269
7270         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0x3266, 0x34cd}},
7271         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7272         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7273     };
7274     const DWORD indices24[] = {0, 1, 2, 3, 4, 5};
7275     const DWORD attributes24[] = {0, 0};
7276     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
7277     const UINT num_faces24 = ARRAY_SIZE(indices24) / VERTS_PER_FACE;
7278     DWORD flags24 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7279     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};
7280     const DWORD adjacency24[] = {-1, 1, -1, -1, -1, 0};
7281     const struct vertex_texcoord_float16_4 exp_vertices24[] =
7282     {
7283         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7284         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7285         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7286
7287         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7288         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7289     };
7290     const DWORD exp_indices24[] = {0, 1, 2, 1, 3, 4};
7291     const DWORD exp_face_remap24[] = {0, 1};
7292     const DWORD exp_vertex_remap24[] = {0, 1, 2, 4, 5, -1};
7293     const DWORD exp_new_num_vertices24 = ARRAY_SIZE(exp_vertices24);
7294     /* Test 25. Weld texture coordinates with usage index 10 (TEXCOORD10). The
7295      * usage index is capped at 7, so the epsilon for TEXCOORD7 is used instead.
7296      */
7297     const struct vertex_texcoord vertices25[] =
7298     {
7299         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7300         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7301         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7302
7303         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7304         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7305         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7306     };
7307     const DWORD indices25[] = {0, 1, 2, 3, 4, 5};
7308     const DWORD attributes25[] = {0, 0};
7309     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
7310     const UINT num_faces25 = ARRAY_SIZE(indices25) / VERTS_PER_FACE;
7311     DWORD flags25 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7312     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};
7313     const DWORD adjacency25[] = {-1, 1, -1, -1, -1, 0};
7314     const struct vertex_texcoord exp_vertices25[] =
7315     {
7316         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7317         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7318         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7319
7320         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7321         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7322     };
7323     const DWORD exp_indices25[] = {0, 1, 2, 1, 3, 4};
7324     const DWORD exp_face_remap25[] = {0, 1};
7325     const DWORD exp_vertex_remap25[] = {0, 1, 2, 4, 5, -1};
7326     const DWORD exp_new_num_vertices25 = ARRAY_SIZE(exp_vertices25);
7327     /* Test 26. Weld color with usage index larger than 1. Shows that none of
7328      * the epsilon values are used. */
7329     const struct vertex_color vertices26[] =
7330     {
7331         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7332         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7333         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7334
7335         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7336         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7337         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7338     };
7339     const DWORD indices26[] = {0, 1, 2, 3, 4, 5};
7340     const DWORD attributes26[] = {0, 0};
7341     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
7342     const UINT num_faces26 = ARRAY_SIZE(indices26) / VERTS_PER_FACE;
7343     DWORD flags26 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7344     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};
7345     const DWORD adjacency26[] = {-1, 1, -1, -1, -1, 0};
7346     const struct vertex_color exp_vertices26[] =
7347     {
7348         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7349         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7350         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7351
7352         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7353         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7354         {{ 0.0f,  0.0f,  0.f}, 0x01010101},
7355     };
7356     const DWORD exp_indices26[] = {0, 1, 2, 3, 4, 5};
7357     const DWORD exp_face_remap26[] = {0, 1};
7358     const DWORD exp_vertex_remap26[] = {0, 1, 2, 3, 4, 5};
7359     const DWORD exp_new_num_vertices26 = ARRAY_SIZE(exp_vertices26);
7360     /* Test 27. Weld color with usage index larger than 1. Check that the
7361      * default epsilon of 1e-6f is used. */
7362     D3DXVECTOR4 zero_float4 = {0.0f, 0.0f, 0.0f, 0.0f};
7363     D3DXVECTOR4 almost_zero_float4 = {0.0f + FLT_EPSILON, 0.0f + FLT_EPSILON, 0.0f + FLT_EPSILON, 0.0f + FLT_EPSILON};
7364     const struct vertex_color_float4 vertices27[] =
7365     {
7366         {{ 0.0f,  3.0f,  0.f}, zero_float4},
7367         {{ 2.0f,  3.0f,  0.f}, zero_float4},
7368         {{ 0.0f,  0.0f,  0.f}, zero_float4},
7369
7370         {{ 3.0f,  3.0f,  0.f}, almost_zero_float4},
7371         {{ 3.0f,  0.0f,  0.f}, zero_float4},
7372         {{ 1.0f,  0.0f,  0.f}, almost_zero_float4},
7373     };
7374     const DWORD indices27[] = {0, 1, 2, 3, 4, 5};
7375     const DWORD attributes27[] = {0, 0};
7376     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
7377     const UINT num_faces27 = ARRAY_SIZE(indices27) / VERTS_PER_FACE;
7378     DWORD flags27 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7379     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};
7380     const DWORD adjacency27[] = {-1, 1, -1, -1, -1, 0};
7381     const struct vertex_color_float4 exp_vertices27[] =
7382     {
7383         {{ 0.0f,  3.0f,  0.f}, zero_float4},
7384         {{ 2.0f,  3.0f,  0.f}, zero_float4},
7385         {{ 0.0f,  0.0f,  0.f}, zero_float4},
7386
7387         {{ 3.0f,  0.0f,  0.f}, zero_float4},
7388     };
7389     const DWORD exp_indices27[] = {0, 1, 2, 1, 3, 2};
7390     const DWORD exp_face_remap27[] = {0, 1};
7391     const DWORD exp_vertex_remap27[] = {0, 1, 2, 4, -1, -1};
7392     const DWORD exp_new_num_vertices27 = ARRAY_SIZE(exp_vertices27);
7393     /* Test 28. Weld one normal with UDEC3. */
7394     const DWORD dword_udec3_zero = init_udec3_dword(0, 0, 0, 1);
7395     const DWORD dword_udec3_1023 = init_udec3_dword(1023, 1023, 1023, 1);
7396     const DWORD dword_udec3_1022 = init_udec3_dword(1022, 1022, 1022, 1);
7397     const struct vertex_normal_udec3 vertices28[] =
7398     {
7399         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7400         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7401         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7402
7403         {{ 3.0f,  3.0f,  0.f}, dword_udec3_1023},
7404         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7405         {{ 1.0f,  0.0f,  0.f}, dword_udec3_1022},
7406     };
7407     const DWORD indices28[] = {0, 1, 2, 3, 4, 5};
7408     const DWORD attributes28[] = {0, 0};
7409     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
7410     const UINT num_faces28 = ARRAY_SIZE(indices28) / VERTS_PER_FACE;
7411     DWORD flags28 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7412     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};
7413     const DWORD adjacency28[] = {-1, 1, -1, -1, -1, 0};
7414     const struct vertex_normal_udec3 exp_vertices28[] =
7415     {
7416         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7417         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7418         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7419
7420         {{ 2.0f,  3.0f,  0.f}, dword_udec3_1023},
7421         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7422     };
7423     const DWORD exp_indices28[] = {0, 1, 2, 3, 4, 2};
7424     const DWORD exp_face_remap28[] = {0, 1};
7425     const DWORD exp_vertex_remap28[] = {0, 1, 2, 3, 4, -1};
7426     const DWORD exp_new_num_vertices28 = ARRAY_SIZE(exp_vertices28);
7427     /* Test 29. Weld one normal with DEC3N. */
7428     const DWORD dword_dec3n_zero = init_dec3n_dword(0, 0, 0, 1);
7429     const DWORD dword_dec3n_511 = init_dec3n_dword(511, 511, 511, 1);
7430     const DWORD dword_dec3n_510 = init_dec3n_dword(510, 510, 510, 1);
7431     const struct vertex_normal_dec3n vertices29[] =
7432     {
7433         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7434         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7435         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7436
7437         {{ 3.0f,  3.0f,  0.f}, dword_dec3n_511},
7438         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7439         {{ 1.0f,  0.0f,  0.f}, dword_dec3n_510},
7440     };
7441     const DWORD indices29[] = {0, 1, 2, 3, 4, 5};
7442     const DWORD attributes29[] = {0, 0};
7443     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
7444     const UINT num_faces29 = ARRAY_SIZE(indices29) / VERTS_PER_FACE;
7445     DWORD flags29 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7446     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};
7447     const DWORD adjacency29[] = {-1, 1, -1, -1, -1, 0};
7448     const struct vertex_normal_dec3n exp_vertices29[] =
7449     {
7450         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7451         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7452         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7453
7454         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_511},
7455         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7456     };
7457     const DWORD exp_indices29[] = {0, 1, 2, 3, 4, 2};
7458     const DWORD exp_face_remap29[] = {0, 1};
7459     const DWORD exp_vertex_remap29[] = {0, 1, 2, 3, 4, -1};
7460     const DWORD exp_new_num_vertices29 = ARRAY_SIZE(exp_vertices29);
7461     /* All mesh data */
7462     DWORD *adjacency_out = NULL;
7463     DWORD *face_remap = NULL;
7464     ID3DXMesh *mesh = NULL;
7465     ID3DXBuffer *vertex_remap = NULL;
7466     struct
7467     {
7468         const BYTE *vertices;
7469         const DWORD *indices;
7470         const DWORD *attributes;
7471         const DWORD num_vertices;
7472         const DWORD num_faces;
7473         const DWORD options;
7474         D3DVERTEXELEMENT9 *declaration;
7475         const UINT vertex_size;
7476         const DWORD flags;
7477         const D3DXWELDEPSILONS *epsilons;
7478         const DWORD *adjacency;
7479         const BYTE *exp_vertices;
7480         const DWORD *exp_indices;
7481         const DWORD *exp_face_remap;
7482         const DWORD *exp_vertex_remap;
7483         const DWORD exp_new_num_vertices;
7484     }
7485     tc[] =
7486     {
7487         {
7488             (BYTE*)vertices0,
7489             indices0,
7490             attributes0,
7491             num_vertices0,
7492             num_faces0,
7493             options,
7494             declaration_normal,
7495             vertex_size_normal,
7496             flags0,
7497             NULL,
7498             adjacency0,
7499             (BYTE*)exp_vertices0,
7500             exp_indices0,
7501             exp_face_remap0,
7502             exp_vertex_remap0,
7503             exp_new_num_vertices0
7504         },
7505         {
7506             (BYTE*)vertices1,
7507             indices1,
7508             attributes1,
7509             num_vertices1,
7510             num_faces1,
7511             options,
7512             declaration_normal,
7513             vertex_size_normal,
7514             flags1,
7515             NULL,
7516             adjacency1,
7517             (BYTE*)exp_vertices1,
7518             exp_indices1,
7519             exp_face_remap1,
7520             exp_vertex_remap1,
7521             exp_new_num_vertices1
7522         },
7523         {
7524             (BYTE*)vertices2,
7525             indices2,
7526             attributes2,
7527             num_vertices2,
7528             num_faces2,
7529             options,
7530             declaration_normal,
7531             vertex_size_normal,
7532             flags2,
7533             &epsilons2,
7534             adjacency2,
7535             (BYTE*)exp_vertices2,
7536             exp_indices2,
7537             exp_face_remap2,
7538             exp_vertex_remap2,
7539             exp_new_num_vertices2
7540         },
7541         {
7542             (BYTE*)vertices3,
7543             indices3,
7544             attributes3,
7545             num_vertices3,
7546             num_faces3,
7547             options,
7548             declaration_normal,
7549             vertex_size_normal,
7550             flags3,
7551             &epsilons3,
7552             adjacency3,
7553             (BYTE*)exp_vertices3,
7554             exp_indices3,
7555             exp_face_remap3,
7556             exp_vertex_remap3,
7557             exp_new_num_vertices3
7558         },
7559         {
7560             (BYTE*)vertices4,
7561             indices4,
7562             attributes4,
7563             num_vertices4,
7564             num_faces4,
7565             options,
7566             declaration_normal,
7567             vertex_size_normal,
7568             flags4,
7569             &epsilons4,
7570             adjacency4,
7571             (BYTE*)exp_vertices4,
7572             exp_indices4,
7573             exp_face_remap4,
7574             exp_vertex_remap4,
7575             exp_new_num_vertices4
7576         },
7577         /* Unusual ordering. */
7578         {
7579             (BYTE*)vertices5,
7580             indices5,
7581             attributes5,
7582             num_vertices5,
7583             num_faces5,
7584             options,
7585             declaration_normal,
7586             vertex_size_normal,
7587             flags5,
7588             NULL,
7589             adjacency5,
7590             (BYTE*)exp_vertices5,
7591             exp_indices5,
7592             exp_face_remap5,
7593             exp_vertex_remap5,
7594             exp_new_num_vertices5
7595         },
7596         {
7597             (BYTE*)vertices6,
7598             indices6,
7599             attributes6,
7600             num_vertices6,
7601             num_faces6,
7602             options,
7603             declaration_normal,
7604             vertex_size_normal,
7605             flags6,
7606             &epsilons6,
7607             adjacency6,
7608             (BYTE*)exp_vertices6,
7609             exp_indices6,
7610             exp_face_remap6,
7611             exp_vertex_remap6,
7612             exp_new_num_vertices6
7613         },
7614         {
7615             (BYTE*)vertices6,
7616             (DWORD*)indices6_16bit,
7617             attributes6,
7618             num_vertices6,
7619             num_faces6,
7620             options_16bit,
7621             declaration_normal,
7622             vertex_size_normal,
7623             flags6,
7624             &epsilons6,
7625             adjacency6,
7626             (BYTE*)exp_vertices6,
7627             exp_indices6,
7628             exp_face_remap6,
7629             exp_vertex_remap6,
7630             exp_new_num_vertices6
7631         },
7632         {
7633             (BYTE*)vertices8,
7634             indices8,
7635             attributes8,
7636             num_vertices8,
7637             num_faces8,
7638             options,
7639             declaration_normal,
7640             vertex_size_normal,
7641             flags8,
7642             &epsilons8,
7643             adjacency8,
7644             (BYTE*)exp_vertices8,
7645             exp_indices8,
7646             exp_face_remap8,
7647             exp_vertex_remap8,
7648             exp_new_num_vertices8
7649         },
7650         {
7651             (BYTE*)vertices9,
7652             indices9,
7653             attributes9,
7654             num_vertices9,
7655             num_faces9,
7656             options,
7657             declaration_normal,
7658             vertex_size_normal,
7659             flags9,
7660             &epsilons9,
7661             adjacency9,
7662             (BYTE*)exp_vertices9,
7663             exp_indices9,
7664             exp_face_remap9,
7665             exp_vertex_remap9,
7666             exp_new_num_vertices9
7667         },
7668         {
7669             (BYTE*)vertices10,
7670             indices10,
7671             attributes10,
7672             num_vertices10,
7673             num_faces10,
7674             options,
7675             declaration_blendweight,
7676             vertex_size_blendweight,
7677             flags10,
7678             &epsilons10,
7679             adjacency10,
7680             (BYTE*)exp_vertices10,
7681             exp_indices10,
7682             exp_face_remap10,
7683             exp_vertex_remap10,
7684             exp_new_num_vertices10
7685         },
7686         {
7687             (BYTE*)vertices11,
7688             indices11,
7689             attributes11,
7690             num_vertices11,
7691             num_faces11,
7692             options,
7693             declaration_texcoord,
7694             vertex_size_texcoord,
7695             flags11,
7696             &epsilons11,
7697             adjacency11,
7698             (BYTE*)exp_vertices11,
7699             exp_indices11,
7700             exp_face_remap11,
7701             exp_vertex_remap11,
7702             exp_new_num_vertices11
7703         },
7704         {
7705             (BYTE*)vertices12,
7706             indices12,
7707             attributes12,
7708             num_vertices12,
7709             num_faces12,
7710             options,
7711             declaration_color,
7712             vertex_size_color,
7713             flags12,
7714             &epsilons12,
7715             adjacency12,
7716             (BYTE*)exp_vertices12,
7717             exp_indices12,
7718             exp_face_remap12,
7719             exp_vertex_remap12,
7720             exp_new_num_vertices12
7721         },
7722         {
7723             (BYTE*)vertices13,
7724             indices13,
7725             attributes13,
7726             num_vertices13,
7727             num_faces13,
7728             options,
7729             declaration_normal3,
7730             vertex_size_normal,
7731             flags13,
7732             &epsilons13,
7733             adjacency13,
7734             (BYTE*)exp_vertices13,
7735             exp_indices13,
7736             exp_face_remap13,
7737             exp_vertex_remap13,
7738             exp_new_num_vertices13
7739         },
7740         {
7741             (BYTE*)vertices14,
7742             indices14,
7743             attributes14,
7744             num_vertices14,
7745             num_faces14,
7746             options,
7747             declaration_color,
7748             vertex_size_color,
7749             flags14,
7750             &epsilons14,
7751             adjacency14,
7752             (BYTE*)exp_vertices14,
7753             exp_indices14,
7754             exp_face_remap14,
7755             exp_vertex_remap14,
7756             exp_new_num_vertices14
7757         },
7758         {
7759             (BYTE*)vertices15,
7760             indices15,
7761             attributes15,
7762             num_vertices15,
7763             num_faces15,
7764             options,
7765             declaration_color_ubyte4n,
7766             vertex_size_color_ubyte4, /* UBYTE4 same size as UBYTE4N */
7767             flags15,
7768             &epsilons15,
7769             adjacency15,
7770             (BYTE*)exp_vertices15,
7771             exp_indices15,
7772             exp_face_remap15,
7773             exp_vertex_remap15,
7774             exp_new_num_vertices15
7775         },
7776         {
7777             (BYTE*)vertices16,
7778             indices16,
7779             attributes16,
7780             num_vertices16,
7781             num_faces16,
7782             options,
7783             declaration_color_ubyte4,
7784             vertex_size_color_ubyte4,
7785             flags16,
7786             &epsilons16,
7787             adjacency16,
7788             (BYTE*)exp_vertices16,
7789             exp_indices16,
7790             exp_face_remap16,
7791             exp_vertex_remap16,
7792             exp_new_num_vertices16
7793         },
7794         {
7795             (BYTE*)vertices17,
7796             indices17,
7797             attributes17,
7798             num_vertices17,
7799             num_faces17,
7800             options,
7801             declaration_texcoord_short2,
7802             vertex_size_texcoord_short2,
7803             flags17,
7804             &epsilons17,
7805             adjacency17,
7806             (BYTE*)exp_vertices17,
7807             exp_indices17,
7808             exp_face_remap17,
7809             exp_vertex_remap17,
7810             exp_new_num_vertices17
7811         },
7812         {
7813             (BYTE*)vertices18,
7814             indices18,
7815             attributes18,
7816             num_vertices18,
7817             num_faces18,
7818             options,
7819             declaration_texcoord_short2n,
7820             vertex_size_texcoord_short2, /* SHORT2 same size as SHORT2N */
7821             flags18,
7822             &epsilons18,
7823             adjacency18,
7824             (BYTE*)exp_vertices18,
7825             exp_indices18,
7826             exp_face_remap18,
7827             exp_vertex_remap18,
7828             exp_new_num_vertices18
7829         },
7830         {
7831             (BYTE*)vertices19,
7832             indices19,
7833             attributes19,
7834             num_vertices19,
7835             num_faces19,
7836             options,
7837             declaration_texcoord_ushort2n,
7838             vertex_size_texcoord_short2, /* SHORT2 same size as USHORT2N */
7839             flags19,
7840             &epsilons19,
7841             adjacency19,
7842             (BYTE*)exp_vertices19,
7843             exp_indices19,
7844             exp_face_remap19,
7845             exp_vertex_remap19,
7846             exp_new_num_vertices19
7847         },
7848         {
7849             (BYTE*)vertices20,
7850             indices20,
7851             attributes20,
7852             num_vertices20,
7853             num_faces20,
7854             options,
7855             declaration_normal_short4,
7856             vertex_size_normal_short4,
7857             flags20,
7858             &epsilons20,
7859             adjacency20,
7860             (BYTE*)exp_vertices20,
7861             exp_indices20,
7862             exp_face_remap20,
7863             exp_vertex_remap20,
7864             exp_new_num_vertices20
7865         },
7866         {
7867             (BYTE*)vertices21,
7868             indices21,
7869             attributes21,
7870             num_vertices21,
7871             num_faces21,
7872             options,
7873             declaration_normal_short4n,
7874             vertex_size_normal_short4, /* SHORT4 same size as SHORT4N */
7875             flags21,
7876             &epsilons21,
7877             adjacency21,
7878             (BYTE*)exp_vertices21,
7879             exp_indices21,
7880             exp_face_remap21,
7881             exp_vertex_remap21,
7882             exp_new_num_vertices21
7883         },
7884         {
7885             (BYTE*)vertices22,
7886             indices22,
7887             attributes22,
7888             num_vertices22,
7889             num_faces22,
7890             options,
7891             declaration_normal_ushort4n,
7892             vertex_size_normal_short4, /* SHORT4 same size as USHORT4N */
7893             flags22,
7894             &epsilons22,
7895             adjacency22,
7896             (BYTE*)exp_vertices22,
7897             exp_indices22,
7898             exp_face_remap22,
7899             exp_vertex_remap22,
7900             exp_new_num_vertices22
7901         },
7902         {
7903             (BYTE*)vertices23,
7904             indices23,
7905             attributes23,
7906             num_vertices23,
7907             num_faces23,
7908             options,
7909             declaration_texcoord_float16_2,
7910             vertex_size_texcoord_float16_2,
7911             flags23,
7912             &epsilons23,
7913             adjacency23,
7914             (BYTE*)exp_vertices23,
7915             exp_indices23,
7916             exp_face_remap23,
7917             exp_vertex_remap23,
7918             exp_new_num_vertices23
7919         },
7920         {
7921             (BYTE*)vertices24,
7922             indices24,
7923             attributes24,
7924             num_vertices24,
7925             num_faces24,
7926             options,
7927             declaration_texcoord_float16_4,
7928             vertex_size_texcoord_float16_4,
7929             flags24,
7930             &epsilons24,
7931             adjacency24,
7932             (BYTE*)exp_vertices24,
7933             exp_indices24,
7934             exp_face_remap24,
7935             exp_vertex_remap24,
7936             exp_new_num_vertices24
7937         },
7938         {
7939             (BYTE*)vertices25,
7940             indices25,
7941             attributes25,
7942             num_vertices25,
7943             num_faces25,
7944             options,
7945             declaration_texcoord10,
7946             vertex_size_texcoord,
7947             flags25,
7948             &epsilons25,
7949             adjacency25,
7950             (BYTE*)exp_vertices25,
7951             exp_indices25,
7952             exp_face_remap25,
7953             exp_vertex_remap25,
7954             exp_new_num_vertices25
7955         },
7956         {
7957             (BYTE*)vertices26,
7958             indices26,
7959             attributes26,
7960             num_vertices26,
7961             num_faces26,
7962             options,
7963             declaration_color2,
7964             vertex_size_color,
7965             flags26,
7966             &epsilons26,
7967             adjacency26,
7968             (BYTE*)exp_vertices26,
7969             exp_indices26,
7970             exp_face_remap26,
7971             exp_vertex_remap26,
7972             exp_new_num_vertices26
7973         },
7974         {
7975             (BYTE*)vertices27,
7976             indices27,
7977             attributes27,
7978             num_vertices27,
7979             num_faces27,
7980             options,
7981             declaration_color2_float4,
7982             vertex_size_color_float4,
7983             flags27,
7984             &epsilons27,
7985             adjacency27,
7986             (BYTE*)exp_vertices27,
7987             exp_indices27,
7988             exp_face_remap27,
7989             exp_vertex_remap27,
7990             exp_new_num_vertices27
7991         },
7992         {
7993             (BYTE*)vertices28,
7994             indices28,
7995             attributes28,
7996             num_vertices28,
7997             num_faces28,
7998             options,
7999             declaration_normal_udec3,
8000             vertex_size_normal_udec3,
8001             flags28,
8002             &epsilons28,
8003             adjacency28,
8004             (BYTE*)exp_vertices28,
8005             exp_indices28,
8006             exp_face_remap28,
8007             exp_vertex_remap28,
8008             exp_new_num_vertices28
8009         },
8010         {
8011             (BYTE*)vertices29,
8012             indices29,
8013             attributes29,
8014             num_vertices29,
8015             num_faces29,
8016             options,
8017             declaration_normal_dec3n,
8018             vertex_size_normal_dec3n,
8019             flags29,
8020             &epsilons29,
8021             adjacency29,
8022             (BYTE*)exp_vertices29,
8023             exp_indices29,
8024             exp_face_remap29,
8025             exp_vertex_remap29,
8026             exp_new_num_vertices29
8027         }
8028     };
8029
8030     test_context = new_test_context();
8031     if (!test_context)
8032     {
8033         skip("Couldn't create test context\n");
8034         goto cleanup;
8035     }
8036
8037     for (i = 0; i < ARRAY_SIZE(tc); i++)
8038     {
8039         DWORD j;
8040         DWORD *vertex_remap_ptr;
8041         DWORD new_num_vertices;
8042
8043         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
8044                             tc[i].declaration, test_context->device, &mesh,
8045                             tc[i].vertices, tc[i].vertex_size,
8046                             tc[i].indices, tc[i].attributes);
8047         if (FAILED(hr))
8048         {
8049             skip("Couldn't initialize test mesh %d.\n", i);
8050             goto cleanup;
8051         }
8052
8053         /* Allocate out parameters */
8054         adjacency_out = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency_out));
8055         if (!adjacency_out)
8056         {
8057             skip("Couldn't allocate adjacency_out array.\n");
8058             goto cleanup;
8059         }
8060         face_remap = HeapAlloc(GetProcessHeap(), 0, tc[i].num_faces * sizeof(*face_remap));
8061         if (!adjacency_out)
8062         {
8063             skip("Couldn't allocate face_remap array.\n");
8064             goto cleanup;
8065         }
8066         hr = D3DXCreateBuffer(tc[i].num_vertices * sizeof(DWORD), &vertex_remap);
8067         if (FAILED(hr))
8068         {
8069             skip("Couldn't create vertex_remap buffer.\n");
8070             goto cleanup;
8071         }
8072
8073         hr = D3DXWeldVertices(mesh, tc[i].flags, tc[i].epsilons, tc[i].adjacency,
8074                               adjacency_out, face_remap, &vertex_remap);
8075         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
8076         /* Check number of vertices*/
8077         new_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
8078         ok(new_num_vertices == tc[i].exp_new_num_vertices,
8079            "Mesh %d: new_num_vertices == %d, expected %d.\n",
8080            i, new_num_vertices, tc[i].exp_new_num_vertices);
8081         /* Check index buffer */
8082         if (tc[i].options & D3DXMESH_32BIT)
8083         {
8084             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices);
8085             if (FAILED(hr))
8086             {
8087                 skip("Couldn't lock index buffer.\n");
8088                 goto cleanup;
8089             }
8090             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8091             {
8092                 ok(indices[j] == tc[i].exp_indices[j],
8093                    "Mesh %d: indices[%d] == %d, expected %d\n",
8094                    i, j, indices[j], tc[i].exp_indices[j]);
8095             }
8096         }
8097         else
8098         {
8099             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices_16bit);
8100             if (FAILED(hr))
8101             {
8102                 skip("Couldn't lock index buffer.\n");
8103                 goto cleanup;
8104             }
8105             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8106             {
8107                 ok(indices_16bit[j] == tc[i].exp_indices[j],
8108                    "Mesh %d: indices_16bit[%d] == %d, expected %d\n",
8109                    i, j, indices_16bit[j], tc[i].exp_indices[j]);
8110             }
8111         }
8112         mesh->lpVtbl->UnlockIndexBuffer(mesh);
8113         indices = NULL;
8114         indices_16bit = NULL;
8115         /* Check adjacency_out */
8116         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8117         {
8118             ok(adjacency_out[j] == tc[i].adjacency[j],
8119                "Mesh %d: adjacency_out[%d] == %d, expected %d\n",
8120                i, j, adjacency_out[j], tc[i].adjacency[j]);
8121         }
8122         /* Check face_remap */
8123         for (j = 0; j < tc[i].num_faces; j++)
8124         {
8125             ok(face_remap[j] == tc[i].exp_face_remap[j],
8126                "Mesh %d: face_remap[%d] == %d, expected %d\n",
8127                i, j, face_remap[j], tc[i].exp_face_remap[j]);
8128         }
8129         /* Check vertex_remap */
8130         vertex_remap_ptr = vertex_remap->lpVtbl->GetBufferPointer(vertex_remap);
8131         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8132         {
8133             ok(vertex_remap_ptr[j] == tc[i].exp_vertex_remap[j],
8134                "Mesh %d: vertex_remap_ptr[%d] == %d, expected %d\n",
8135                i, j, vertex_remap_ptr[j], tc[i].exp_vertex_remap[j]);
8136         }
8137         /* Check vertex buffer */
8138         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void*)&vertices);
8139         if (FAILED(hr))
8140         {
8141             skip("Couldn't lock vertex buffer.\n");
8142             goto cleanup;
8143         }
8144         /* Check contents of re-ordered vertex buffer */
8145         for (j = 0; j < tc[i].exp_new_num_vertices; j++)
8146         {
8147             int index = tc[i].vertex_size*j;
8148             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].declaration);
8149         }
8150         mesh->lpVtbl->UnlockVertexBuffer(mesh);
8151         vertices = NULL;
8152
8153         /* Free mesh and output data */
8154         HeapFree(GetProcessHeap(), 0, adjacency_out);
8155         adjacency_out = NULL;
8156         HeapFree(GetProcessHeap(), 0, face_remap);
8157         face_remap = NULL;
8158         vertex_remap->lpVtbl->Release(vertex_remap);
8159         vertex_remap = NULL;
8160         mesh->lpVtbl->Release(mesh);
8161         mesh = NULL;
8162     }
8163
8164 cleanup:
8165     HeapFree(GetProcessHeap(), 0, adjacency_out);
8166     HeapFree(GetProcessHeap(), 0, face_remap);
8167     if (indices) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8168     if (indices_16bit) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8169     if (mesh) mesh->lpVtbl->Release(mesh);
8170     if (vertex_remap) vertex_remap->lpVtbl->Release(vertex_remap);
8171     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
8172     free_test_context(test_context);
8173 }
8174
8175 static void test_clone_mesh(void)
8176 {
8177     HRESULT hr;
8178     struct test_context *test_context = NULL;
8179     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
8180     D3DVERTEXELEMENT9 declaration_pn[] =
8181     {
8182         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8183         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8184         D3DDECL_END()
8185     };
8186     D3DVERTEXELEMENT9 declaration_pntc[] =
8187     {
8188         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8189         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8190         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8191         D3DDECL_END()
8192     };
8193     D3DVERTEXELEMENT9 declaration_ptcn[] =
8194     {
8195         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8196         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8197         {0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8198         D3DDECL_END()
8199     };
8200     D3DVERTEXELEMENT9 declaration_ptc[] =
8201     {
8202         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8203         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8204         D3DDECL_END()
8205     };
8206     D3DVERTEXELEMENT9 declaration_ptc_float16_2[] =
8207     {
8208         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8209         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8210         D3DDECL_END()
8211     };
8212     D3DVERTEXELEMENT9 declaration_ptc_float16_4[] =
8213     {
8214         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8215         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8216         D3DDECL_END()
8217     };
8218     D3DVERTEXELEMENT9 declaration_ptc_float1[] =
8219     {
8220         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8221         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8222         D3DDECL_END()
8223     };
8224     D3DVERTEXELEMENT9 declaration_ptc_float3[] =
8225     {
8226         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8227         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8228         D3DDECL_END()
8229     };
8230     D3DVERTEXELEMENT9 declaration_ptc_float4[] =
8231     {
8232         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8233         {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8234         D3DDECL_END()
8235     };
8236     D3DVERTEXELEMENT9 declaration_ptc_d3dcolor[] =
8237     {
8238         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8239         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8240         D3DDECL_END()
8241     };
8242     D3DVERTEXELEMENT9 declaration_ptc_ubyte4[] =
8243     {
8244         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8245         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8246         D3DDECL_END()
8247     };
8248     D3DVERTEXELEMENT9 declaration_ptc_ubyte4n[] =
8249     {
8250         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8251         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8252         D3DDECL_END()
8253     };
8254     D3DVERTEXELEMENT9 declaration_ptc_short2[] =
8255     {
8256         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8257         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8258         D3DDECL_END()
8259     };
8260     D3DVERTEXELEMENT9 declaration_ptc_short4[] =
8261     {
8262         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8263         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8264         D3DDECL_END()
8265     };
8266     D3DVERTEXELEMENT9 declaration_ptc_short2n[] =
8267     {
8268         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8269         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8270         D3DDECL_END()
8271     };
8272     D3DVERTEXELEMENT9 declaration_ptc_short4n[] =
8273     {
8274         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8275         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8276         D3DDECL_END()
8277     };
8278     D3DVERTEXELEMENT9 declaration_ptc_ushort2n[] =
8279     {
8280         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8281         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8282         D3DDECL_END()
8283     };
8284     D3DVERTEXELEMENT9 declaration_ptc_ushort4n[] =
8285     {
8286         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8287         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8288         D3DDECL_END()
8289     };
8290     D3DVERTEXELEMENT9 declaration_ptc_float16_2_partialu[] =
8291     {
8292         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8293         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_PARTIALU, D3DDECLUSAGE_TEXCOORD, 0},
8294         D3DDECL_END()
8295     };
8296     D3DVERTEXELEMENT9 declaration_pntc1[] =
8297     {
8298         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8299         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8300         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
8301         D3DDECL_END()
8302     };
8303     const unsigned int VERTS_PER_FACE = 3;
8304     BYTE *vertices = NULL;
8305     INT i;
8306     struct vertex_pn
8307     {
8308         D3DXVECTOR3 position;
8309         D3DXVECTOR3 normal;
8310     };
8311     struct vertex_pntc
8312     {
8313         D3DXVECTOR3 position;
8314         D3DXVECTOR3 normal;
8315         D3DXVECTOR2 texcoords;
8316     };
8317     struct vertex_ptcn
8318     {
8319         D3DXVECTOR3 position;
8320         D3DXVECTOR2 texcoords;
8321         D3DXVECTOR3 normal;
8322     };
8323     struct vertex_ptc
8324     {
8325         D3DXVECTOR3 position;
8326         D3DXVECTOR2 texcoords;
8327     };
8328     struct vertex_ptc_float16_2
8329     {
8330         D3DXVECTOR3 position;
8331         WORD texcoords[2]; /* float16_2 */
8332     };
8333     struct vertex_ptc_float16_4
8334     {
8335         D3DXVECTOR3 position;
8336         WORD texcoords[4]; /* float16_4 */
8337     };
8338     struct vertex_ptc_float1
8339     {
8340         D3DXVECTOR3 position;
8341         FLOAT texcoords;
8342     };
8343     struct vertex_ptc_float3
8344     {
8345         D3DXVECTOR3 position;
8346         FLOAT texcoords[3];
8347     };
8348     struct vertex_ptc_float4
8349     {
8350         D3DXVECTOR3 position;
8351         FLOAT texcoords[4];
8352     };
8353     struct vertex_ptc_d3dcolor
8354     {
8355         D3DXVECTOR3 position;
8356         BYTE texcoords[4];
8357     };
8358     struct vertex_ptc_ubyte4
8359     {
8360         D3DXVECTOR3 position;
8361         BYTE texcoords[4];
8362     };
8363     struct vertex_ptc_ubyte4n
8364     {
8365         D3DXVECTOR3 position;
8366         BYTE texcoords[4];
8367     };
8368     struct vertex_ptc_short2
8369     {
8370         D3DXVECTOR3 position;
8371         SHORT texcoords[2];
8372     };
8373     struct vertex_ptc_short4
8374     {
8375         D3DXVECTOR3 position;
8376         SHORT texcoords[4];
8377     };
8378     struct vertex_ptc_ushort2n
8379     {
8380         D3DXVECTOR3 position;
8381         USHORT texcoords[2];
8382     };
8383     struct vertex_ptc_ushort4n
8384     {
8385         D3DXVECTOR3 position;
8386         USHORT texcoords[4];
8387     };
8388     struct vertex_ptc_udec3
8389     {
8390         D3DXVECTOR3 position;
8391         DWORD texcoords;
8392     };
8393     struct vertex_ptc_dec3n
8394     {
8395         D3DXVECTOR3 position;
8396         DWORD texcoords;
8397     };
8398     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
8399     D3DXVECTOR2 zero_vec2 = {0.0f, 0.0f};
8400     /* Test 0. Check that a mesh can be cloned if the new declaration is the
8401      * same as the one used to create the mesh.
8402      *
8403      * 0--1 3
8404      * | / /|
8405      * |/ / |
8406      * 2 5--4
8407      */
8408     const struct vertex_pn vertices0[] =
8409     {
8410         {{ 0.0f,  3.0f,  0.f}, up},
8411         {{ 2.0f,  3.0f,  0.f}, up},
8412         {{ 0.0f,  0.0f,  0.f}, up},
8413
8414         {{ 3.0f,  3.0f,  0.f}, up},
8415         {{ 3.0f,  0.0f,  0.f}, up},
8416         {{ 1.0f,  0.0f,  0.f}, up},
8417     };
8418     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
8419     const UINT num_faces0 = ARRAY_SIZE(vertices0) / VERTS_PER_FACE;
8420     const UINT vertex_size0 = sizeof(*vertices0);
8421     /* Test 1. Check that 16-bit indices are handled. */
8422     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
8423     /* Test 2. Check that the size of each vertex is increased and the data
8424      * moved if the new declaration adds an element after the original elements.
8425      */
8426     const struct vertex_pntc exp_vertices2[] =
8427     {
8428         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8429         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8430         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8431
8432         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8433         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8434         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8435     };
8436     const UINT exp_vertex_size2 = sizeof(*exp_vertices2);
8437     /* Test 3. Check that the size of each vertex is increased and the data
8438      * moved if the new declaration adds an element between the original
8439      * elements.
8440      */
8441     const struct vertex_ptcn exp_vertices3[] =
8442     {
8443         {{ 0.0f,  3.0f,  0.f}, zero_vec2, up},
8444         {{ 2.0f,  3.0f,  0.f}, zero_vec2, up},
8445         {{ 0.0f,  0.0f,  0.f}, zero_vec2, up},
8446
8447         {{ 3.0f,  3.0f,  0.f}, zero_vec2, up},
8448         {{ 3.0f,  0.0f,  0.f}, zero_vec2, up},
8449         {{ 1.0f,  0.0f,  0.f}, zero_vec2, up},
8450     };
8451     const UINT exp_vertex_size3 = sizeof(*exp_vertices3);
8452     /* Test 4. Test that data types can be converted, e.g. FLOAT2 to FLOAT16_2. */
8453     const struct vertex_ptc vertices4[] =
8454     {
8455         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8456         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8457         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8458
8459         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8460         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8461         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8462     };
8463     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
8464     const UINT num_faces4 = ARRAY_SIZE(vertices4) / VERTS_PER_FACE;
8465     const UINT vertex_size4 = sizeof(*vertices4);
8466     const struct vertex_ptc_float16_2 exp_vertices4[] =
8467     {
8468         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8469         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
8470         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
8471
8472         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
8473         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8474         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
8475     };
8476     const UINT exp_vertex_size4 = sizeof(*exp_vertices4);
8477     /* Test 5. Convert FLOAT2 to FLOAT16_4. */
8478     const struct vertex_ptc vertices5[] =
8479     {
8480         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8481         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8482         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8483
8484         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8485         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8486         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8487     };
8488     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
8489     const UINT num_faces5 = ARRAY_SIZE(vertices5) / VERTS_PER_FACE;
8490     const UINT vertex_size5 = sizeof(*vertices5);
8491     const struct vertex_ptc_float16_4 exp_vertices5[] =
8492     {
8493         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8494         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0, 0x3c00}}, /* {0.5f, 0.7f, 0.0f, 1.0f} */
8495         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0, 0x3c00}}, /* {-0.2f, -0.3f, 0.0f, 1.0f} */
8496
8497         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0, 0x3c00}}, /* {0.2f, 0.3f, 0.0f, 1.0f} */
8498         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8499         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0, 0x3c00}}, /* {0.1f, 0.2f, 0.0f, 1.0f} */
8500     };
8501     const UINT exp_vertex_size5 = sizeof(*exp_vertices5);
8502     /* Test 6. Convert FLOAT2 to FLOAT1. */
8503     const struct vertex_ptc vertices6[] =
8504     {
8505         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8506         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8507         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8508
8509         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8510         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8511         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8512     };
8513     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
8514     const UINT num_faces6 = ARRAY_SIZE(vertices6) / VERTS_PER_FACE;
8515     const UINT vertex_size6 = sizeof(*vertices6);
8516     const struct vertex_ptc_float1 exp_vertices6[] =
8517     {
8518         {{ 0.0f,  3.0f,  0.f},  1.0f},
8519         {{ 2.0f,  3.0f,  0.f},  0.5f},
8520         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8521
8522         {{ 3.0f,  3.0f,  0.f},  0.2f},
8523         {{ 3.0f,  0.0f,  0.f},  1.0f},
8524         {{ 1.0f,  0.0f,  0.f},  0.1f},
8525     };
8526     const UINT exp_vertex_size6 = sizeof(*exp_vertices6);
8527     /* Test 7. Convert FLOAT2 to FLOAT3. */
8528     const struct vertex_ptc vertices7[] =
8529     {
8530         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8531         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8532         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8533
8534         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8535         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8536         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8537     };
8538     const UINT num_vertices7 = ARRAY_SIZE(vertices7);
8539     const UINT num_faces7 = ARRAY_SIZE(vertices7) / VERTS_PER_FACE;
8540     const UINT vertex_size7 = sizeof(*vertices7);
8541     const struct vertex_ptc_float3 exp_vertices7[] =
8542     {
8543         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8544         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f}},
8545         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f}},
8546
8547         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f}},
8548         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
8549         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f}},
8550     };
8551     const UINT exp_vertex_size7 = sizeof(*exp_vertices7);
8552     /* Test 8. Convert FLOAT2 to FLOAT4. */
8553     const struct vertex_ptc vertices8[] =
8554     {
8555         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8556         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8557         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8558
8559         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8560         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8561         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8562     };
8563     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
8564     const UINT num_faces8 = ARRAY_SIZE(vertices8) / VERTS_PER_FACE;
8565     const UINT vertex_size8 = sizeof(*vertices8);
8566     const struct vertex_ptc_float4 exp_vertices8[] =
8567     {
8568         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
8569         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f, 1.0f}},
8570         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f, 1.0f}},
8571
8572         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f, 1.0f}},
8573         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
8574         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f, 1.0f}},
8575     };
8576     const UINT exp_vertex_size8 = sizeof(*exp_vertices8);
8577     /* Test 9. Convert FLOAT2 to D3DCOLOR. */
8578     const struct vertex_ptc vertices9[] =
8579     {
8580         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8581         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8582         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.6f}},
8583
8584         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8585         {{ 3.0f,  0.0f,  0.f}, { 2.0f, 256.0f}},
8586         {{ 1.0f,  0.0f,  0.f}, { 0.11f,  0.2f}},
8587     };
8588     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
8589     const UINT num_faces9 = ARRAY_SIZE(vertices9) / VERTS_PER_FACE;
8590     const UINT vertex_size9 = sizeof(*vertices9);
8591     const struct vertex_ptc_d3dcolor exp_vertices9[] =
8592     {
8593         {{ 0.0f,  3.0f,  0.f}, {0, 255, 255, 255}},
8594         {{ 2.0f,  3.0f,  0.f}, {0, 179, 128, 255}},
8595         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
8596
8597         {{ 3.0f,  3.0f,  0.f}, {0, 77, 51, 255}},
8598         {{ 3.0f,  0.0f,  0.f}, {0, 255, 255, 255}},
8599         {{ 1.0f,  0.0f,  0.f}, {0, 51, 28, 255}},
8600     };
8601     const UINT exp_vertex_size9 = sizeof(*exp_vertices9);
8602     /* Test 10. Convert FLOAT2 to UBYTE4. */
8603     const struct vertex_ptc vertices10[] =
8604     {
8605         {{ 0.0f,  3.0f,  0.f}, { 0.0f,  1.0f}},
8606         {{ 2.0f,  3.0f,  0.f}, { 2.0f,  3.0f}},
8607         {{ 0.0f,  0.0f,  0.f}, { 254.0f,  255.0f}},
8608
8609         {{ 3.0f,  3.0f,  0.f}, { 256.0f, 257.0f}},
8610         {{ 3.0f,  0.0f,  0.f}, { 1.4f, 1.5f}},
8611         {{ 1.0f,  0.0f,  0.f}, {-4.0f, -5.0f}},
8612     };
8613     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
8614     const UINT num_faces10 = ARRAY_SIZE(vertices10) / VERTS_PER_FACE;
8615     const UINT vertex_size10 = sizeof(*vertices10);
8616     const struct vertex_ptc_ubyte4 exp_vertices10[] =
8617     {
8618         {{ 0.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8619         {{ 2.0f,  3.0f,  0.f}, {2, 3, 0, 1}},
8620         {{ 0.0f,  0.0f,  0.f}, {254, 255, 0, 1}},
8621
8622         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8623         {{ 3.0f,  0.0f,  0.f}, {1, 2, 0, 1}},
8624         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
8625     };
8626     const UINT exp_vertex_size10 = sizeof(*exp_vertices10);
8627     /* Test 11. Convert FLOAT2 to SHORT2. */
8628     const struct vertex_ptc vertices11[] =
8629     {
8630         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
8631         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
8632         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
8633
8634         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8635         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
8636         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
8637
8638         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
8639         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
8640         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
8641     };
8642     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
8643     const UINT num_faces11 = ARRAY_SIZE(vertices11) / VERTS_PER_FACE;
8644     const UINT vertex_size11 = sizeof(*vertices11);
8645     const struct vertex_ptc_short2 exp_vertices11[] =
8646     {
8647         {{ 0.0f,  3.0f,  0.f}, {1, 0}},
8648         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
8649         {{ 0.0f,  0.0f,  0.f}, {0, -4}},
8650
8651         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1}},
8652         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN}},
8653         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
8654
8655         {{ 4.0f,  3.0f,  0.f}, {-2, 1}},
8656         {{ 6.0f,  0.0f,  0.f}, {32765, -32767}},
8657         {{ 4.0f,  0.0f,  0.f}, {-4, 1}},
8658     };
8659     const UINT exp_vertex_size11 = sizeof(*exp_vertices11);
8660     /* Test 12. Convert FLOAT2 to SHORT4. */
8661     const struct vertex_ptc vertices12[] =
8662     {
8663         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
8664         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
8665         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
8666
8667         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8668         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
8669         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
8670
8671         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
8672         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
8673         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
8674     };
8675     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
8676     const UINT num_faces12 = ARRAY_SIZE(vertices12) / VERTS_PER_FACE;
8677     const UINT vertex_size12 = sizeof(*vertices12);
8678     const struct vertex_ptc_short4 exp_vertices12[] =
8679     {
8680         {{ 0.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
8681         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
8682         {{ 0.0f,  0.0f,  0.f}, {0, -4, 0, 1}},
8683
8684         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1, 0, 1}},
8685         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN, 0, 1}},
8686         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, 0, 1}},
8687
8688         {{ 4.0f,  3.0f,  0.f}, {-2, 1, 0, 1}},
8689         {{ 6.0f,  0.0f,  0.f}, {32765, -32767, 0, 1}},
8690         {{ 4.0f,  0.0f,  0.f}, {-4, 1, 0, 1}},
8691     };
8692     const UINT exp_vertex_size12 = sizeof(*exp_vertices12);
8693     /* Test 13. Convert FLOAT2 to UBYTE4N. */
8694     const struct vertex_ptc vertices13[] =
8695     {
8696         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  2.0f}},
8697         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8698         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.5f}},
8699
8700         {{ 3.0f,  3.0f,  0.f}, {-0.6f,  -1.0f}},
8701         {{ 3.0f,  0.0f,  0.f}, {UCHAR_MAX,  UCHAR_MAX + 1}},
8702         {{ 1.0f,  0.0f,  0.f}, {2 * UCHAR_MAX, -UCHAR_MAX}},
8703     };
8704     const UINT num_vertices13 = ARRAY_SIZE(vertices13);
8705     const UINT num_faces13 = ARRAY_SIZE(vertices13) / VERTS_PER_FACE;
8706     const UINT vertex_size13 = sizeof(*vertices13);
8707     const struct vertex_ptc_ubyte4n exp_vertices13[] =
8708     {
8709         {{ 0.0f,  3.0f,  0.f}, {255, 255, 0, 255}},
8710         {{ 2.0f,  3.0f,  0.f}, {128, 179, 0, 255}},
8711         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
8712
8713         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, 255}},
8714         {{ 3.0f,  0.0f,  0.f}, {255, 255, 0, 255}},
8715         {{ 1.0f,  0.0f,  0.f}, {255, 0, 0, 255}},
8716     };
8717     const UINT exp_vertex_size13 = sizeof(*exp_vertices13);
8718     /* Test 14. Convert FLOAT2 to SHORT2N. */
8719     const struct vertex_ptc vertices14[] =
8720     {
8721         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8722         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8723         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8724
8725         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8726         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
8727         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8728     };
8729     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
8730     const UINT num_faces14 = ARRAY_SIZE(vertices14) / VERTS_PER_FACE;
8731     const UINT vertex_size14 = sizeof(*vertices14);
8732     const struct vertex_ptc_short2 exp_vertices14[] =
8733     {
8734         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX}},
8735         {{ 2.0f,  3.0f,  0.f}, {13107, 16384}},
8736         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2}},
8737
8738         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383}},
8739         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3}},
8740         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2}},
8741     };
8742     const UINT exp_vertex_size14 = sizeof(*exp_vertices14);
8743     /* Test 15. Convert FLOAT2 to SHORT4N. */
8744     const struct vertex_ptc vertices15[] =
8745     {
8746         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8747         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8748         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8749
8750         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8751         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
8752         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
8753     };
8754     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
8755     const UINT num_faces15 = ARRAY_SIZE(vertices15) / VERTS_PER_FACE;
8756     const UINT vertex_size15 = sizeof(*vertices15);
8757     const struct vertex_ptc_short4 exp_vertices15[] =
8758     {
8759         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX, 0, SHRT_MAX}},
8760         {{ 2.0f,  3.0f,  0.f}, {13107, 16384, 0, SHRT_MAX}},
8761         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2, 0, SHRT_MAX}},
8762
8763         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383, 0, SHRT_MAX}},
8764         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3, 0, SHRT_MAX}},
8765         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2, 0, SHRT_MAX}},
8766     };
8767     const UINT exp_vertex_size15 = sizeof(*exp_vertices15);
8768     /* Test 16. Convert FLOAT2 to USHORT2N. */
8769     const struct vertex_ptc vertices16[] =
8770     {
8771         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8772         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8773         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8774
8775         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8776         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
8777         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
8778     };
8779     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
8780     const UINT num_faces16 = ARRAY_SIZE(vertices16) / VERTS_PER_FACE;
8781     const UINT vertex_size16 = sizeof(*vertices16);
8782     const struct vertex_ptc_ushort2n exp_vertices16[] =
8783     {
8784         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX}},
8785         {{ 2.0f,  3.0f,  0.f}, {26214, 32768}},
8786         {{ 0.0f,  0.0f,  0.f}, {39321, 0}},
8787
8788         {{ 3.0f,  3.0f,  0.f}, {0, 0}},
8789         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1}},
8790         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0}},
8791     };
8792     const UINT exp_vertex_size16 = sizeof(*exp_vertices16);
8793     /* Test 17. Convert FLOAT2 to USHORT4N. */
8794     const struct vertex_ptc vertices17[] =
8795     {
8796         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
8797         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
8798         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
8799
8800         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
8801         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
8802         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
8803     };
8804     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
8805     const UINT num_faces17 = ARRAY_SIZE(vertices17) / VERTS_PER_FACE;
8806     const UINT vertex_size17 = sizeof(*vertices17);
8807     const struct vertex_ptc_ushort4n exp_vertices17[] =
8808     {
8809         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX, 0, USHRT_MAX}},
8810         {{ 2.0f,  3.0f,  0.f}, {26214, 32768, 0, USHRT_MAX}},
8811         {{ 0.0f,  0.0f,  0.f}, {39321, 0, 0, USHRT_MAX}},
8812
8813         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, USHRT_MAX}},
8814         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1, 0, USHRT_MAX}},
8815         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0, 0, USHRT_MAX}},
8816     };
8817     const UINT exp_vertex_size17 = sizeof(*exp_vertices17);
8818     /* Test 18. Test that the method field is compared by converting a FLOAT2 to
8819      * FLOAT16_2. where the method field has been change from
8820      * D3DDECLMETHOD_DEFAULT to D3DDECLMETHOD_PARTIALU. */
8821     const struct vertex_ptc vertices18[] =
8822     {
8823         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8824         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8825         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8826
8827         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8828         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8829         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8830     };
8831     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
8832     const UINT num_faces18 = ARRAY_SIZE(vertices18) / VERTS_PER_FACE;
8833     const UINT vertex_size18 = sizeof(*vertices18);
8834     const struct vertex_ptc_float16_2 exp_vertices18[] =
8835     {
8836         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8837         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
8838         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
8839
8840         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
8841         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8842         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
8843     };
8844     const UINT exp_vertex_size18 = sizeof(*exp_vertices18);
8845     /* Test 19. Test that data is lost if usage index changes, e.g. TEXCOORD0
8846      * TEXCOORD1. */
8847     const struct vertex_pntc vertices19[] =
8848     {
8849         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
8850         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
8851         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
8852
8853         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
8854         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
8855         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
8856     };
8857     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
8858     const UINT num_faces19 = ARRAY_SIZE(vertices19) / VERTS_PER_FACE;
8859     const UINT vertex_size19 = sizeof(*vertices19);
8860     const struct vertex_pntc exp_vertices19[] =
8861     {
8862         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8863         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8864         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8865
8866         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8867         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8868         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8869     };
8870     const UINT exp_vertex_size19 = sizeof(*exp_vertices19);
8871     /* Test 20. Another test that data is lost if usage index changes, e.g.
8872      * TEXCOORD1 to TEXCOORD0. */
8873     const struct vertex_pntc vertices20[] =
8874     {
8875         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
8876         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
8877         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
8878
8879         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
8880         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
8881         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
8882     };
8883     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
8884     const UINT num_faces20 = ARRAY_SIZE(vertices20) / VERTS_PER_FACE;
8885     const UINT vertex_size20 = sizeof(*vertices20);
8886     const struct vertex_pntc exp_vertices20[] =
8887     {
8888         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8889         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8890         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8891
8892         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8893         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8894         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8895     };
8896     const UINT exp_vertex_size20 = sizeof(*exp_vertices20);
8897     /* Test 21. Convert FLOAT1 to FLOAT2. */
8898     const struct vertex_ptc_float1 vertices21[] =
8899     {
8900         {{ 0.0f,  3.0f,  0.f},  1.0f},
8901         {{ 2.0f,  3.0f,  0.f},  0.5f},
8902         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8903
8904         {{ 3.0f,  3.0f,  0.f},  0.2f},
8905         {{ 3.0f,  0.0f,  0.f},  1.0f},
8906         {{ 1.0f,  0.0f,  0.f},  0.1f},
8907     };
8908     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
8909     const UINT num_faces21 = ARRAY_SIZE(vertices21) / VERTS_PER_FACE;
8910     const UINT vertex_size21 = sizeof(*vertices21);
8911     const struct vertex_ptc exp_vertices21[] =
8912     {
8913         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f}},
8914         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f}},
8915         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f}},
8916
8917         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f}},
8918         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f}},
8919         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f}},
8920     };
8921     const UINT exp_vertex_size21 = sizeof(*exp_vertices21);
8922     /* Test 22. Convert FLOAT1 to FLOAT3. */
8923     const struct vertex_ptc_float1 vertices22[] =
8924     {
8925         {{ 0.0f,  3.0f,  0.f},  1.0f},
8926         {{ 2.0f,  3.0f,  0.f},  0.5f},
8927         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8928
8929         {{ 3.0f,  3.0f,  0.f},  0.2f},
8930         {{ 3.0f,  0.0f,  0.f},  1.0f},
8931         {{ 1.0f,  0.0f,  0.f},  0.1f},
8932     };
8933     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
8934     const UINT num_faces22 = ARRAY_SIZE(vertices22) / VERTS_PER_FACE;
8935     const UINT vertex_size22 = sizeof(*vertices22);
8936     const struct vertex_ptc_float3 exp_vertices22[] =
8937     {
8938         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
8939         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f}},
8940         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f}},
8941
8942         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f}},
8943         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
8944         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f}},
8945     };
8946     const UINT exp_vertex_size22 = sizeof(*exp_vertices22);
8947     /* Test 23. Convert FLOAT1 to FLOAT4. */
8948     const struct vertex_ptc_float1 vertices23[] =
8949     {
8950         {{ 0.0f,  3.0f,  0.f},  1.0f},
8951         {{ 2.0f,  3.0f,  0.f},  0.5f},
8952         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8953
8954         {{ 3.0f,  3.0f,  0.f},  0.2f},
8955         {{ 3.0f,  0.0f,  0.f},  1.0f},
8956         {{ 1.0f,  0.0f,  0.f},  0.1f},
8957     };
8958     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
8959     const UINT num_faces23 = ARRAY_SIZE(vertices23) / VERTS_PER_FACE;
8960     const UINT vertex_size23 = sizeof(*vertices23);
8961     const struct vertex_ptc_float4 exp_vertices23[] =
8962     {
8963         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
8964         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f, 1.0f}},
8965         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f, 1.0f}},
8966
8967         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f, 1.0f}},
8968         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
8969         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f, 1.0f}},
8970     };
8971     const UINT exp_vertex_size23 = sizeof(*exp_vertices23);
8972     /* Test 24. Convert FLOAT1 to D3DCOLOR. */
8973     const struct vertex_ptc_float1 vertices24[] =
8974     {
8975         {{ 0.0f,  3.0f,  0.f},  1.0f},
8976         {{ 2.0f,  3.0f,  0.f},  0.5f},
8977         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8978
8979         {{ 3.0f,  3.0f,  0.f},  0.2f},
8980         {{ 3.0f,  0.0f,  0.f},  1.0f},
8981         {{ 1.0f,  0.0f,  0.f},  0.11f},
8982     };
8983     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
8984     const UINT num_faces24 = ARRAY_SIZE(vertices24) / VERTS_PER_FACE;
8985     const UINT vertex_size24 = sizeof(*vertices24);
8986     const struct vertex_ptc_d3dcolor exp_vertices24[] =
8987     {
8988         {{ 0.0f,  3.0f,  0.f}, {0, 0, 255, 255}},
8989         {{ 2.0f,  3.0f,  0.f}, {0, 0, 128, 255}},
8990         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
8991
8992         {{ 3.0f,  3.0f,  0.f}, {0, 0, 51, 255}},
8993         {{ 3.0f,  0.0f,  0.f}, {0, 0, 255, 255}},
8994         {{ 1.0f,  0.0f,  0.f}, {0, 0, 28, 255}},
8995     };
8996     const UINT exp_vertex_size24 = sizeof(*exp_vertices24);
8997     /* Test 25. Convert FLOAT1 to ubyte4. */
8998     const struct vertex_ptc_float1 vertices25[] =
8999     {
9000         {{ 0.0f,  3.0f,  0.f}, 0.0f},
9001         {{ 2.0f,  3.0f,  0.f}, 1.4f},
9002         {{ 0.0f,  0.0f,  0.f}, 1.5f},
9003
9004         {{ 3.0f,  3.0f,  0.f}, 255.0f},
9005         {{ 3.0f,  0.0f,  0.f}, 256.0f},
9006         {{ 1.0f,  0.0f,  0.f}, -1.0f},
9007     };
9008     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
9009     const UINT num_faces25 = ARRAY_SIZE(vertices25) / VERTS_PER_FACE;
9010     const UINT vertex_size25 = sizeof(*vertices25);
9011     const struct vertex_ptc_ubyte4 exp_vertices25[] =
9012     {
9013         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 1}},
9014         {{ 2.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
9015         {{ 0.0f,  0.0f,  0.f}, {2, 0, 0, 1}},
9016
9017         {{ 3.0f,  3.0f,  0.f}, {255, 0, 0, 1}},
9018         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9019         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9020     };
9021     const UINT exp_vertex_size25 = sizeof(*exp_vertices25);
9022     /* Test 26. Convert FLOAT4 to D3DCOLOR. */
9023     const struct vertex_ptc_float4 vertices26[] =
9024     {
9025         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.5f}},
9026         {{ 2.0f,  3.0f,  0.f}, {-0.4f, -0.5f, -1.0f, -2.0f}},
9027         {{ 0.0f,  0.0f,  0.f}, {254.0f, 255.0f, 256.0f, 257.0f}},
9028
9029         {{ 3.0f,  3.0f,  0.f}, {0.1f, 0.2f, 0.3f, 0.4f}},
9030         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.6f, 0.7f, 0.8f}},
9031         {{ 1.0f,  0.0f,  0.f}, {0.9f, 0.99f, 0.995f, 0.999f}},
9032     };
9033     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
9034     const UINT num_faces26 = ARRAY_SIZE(vertices26) / VERTS_PER_FACE;
9035     const UINT vertex_size26 = sizeof(*vertices26);
9036     const struct vertex_ptc_d3dcolor exp_vertices26[] =
9037     {
9038         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9039         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9040         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9041
9042         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9043         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9044         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9045     };
9046     const UINT exp_vertex_size26 = sizeof(*exp_vertices26);
9047     /* Test 27. Convert D3DCOLOR to FLOAT4. */
9048     const struct vertex_ptc_d3dcolor vertices27[] =
9049     {
9050         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9051         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9052         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9053
9054         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9055         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9056         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9057     };
9058     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
9059     const UINT num_faces27 = ARRAY_SIZE(vertices27) / VERTS_PER_FACE;
9060     const UINT vertex_size27 = sizeof(*vertices27);
9061     const struct vertex_ptc_float4 exp_vertices27[] =
9062     {
9063         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.501961f}},
9064         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9065         {{ 0.0f,  0.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9066
9067         {{ 3.0f,  3.0f,  0.f}, {0.101961f, 0.2f, 0.301961f, 0.4f}},
9068         {{ 3.0f,  0.0f,  0.f}, {0.501961f, 0.6f, 0.701961f, 0.8f}},
9069         {{ 1.0f,  0.0f,  0.f}, {0.901961f, 0.988235f, 0.996078f, 1.0f}},
9070     };
9071     const UINT exp_vertex_size27 = sizeof(*exp_vertices27);
9072     /* Test 28. Convert UBYTE4 to FLOAT4. */
9073     const struct vertex_ptc_ubyte4 vertices28[] =
9074     {
9075         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9076         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9077         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9078
9079         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9080         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9081         {{ 1.0f,  0.0f,  0.f}, {50, 60, 127, 255}},
9082     };
9083     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
9084     const UINT num_faces28 = ARRAY_SIZE(vertices28) / VERTS_PER_FACE;
9085     const UINT vertex_size28 = sizeof(*vertices28);
9086     const struct vertex_ptc_float4 exp_vertices28[] =
9087     {
9088         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9089         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9090         {{ 0.0f,  0.0f,  0.f}, {1.0f,  0.0f, 1.0f, 0.0f}},
9091
9092         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9093         {{ 3.0f,  0.0f,  0.f}, {10.0f, 20.0f, 30.0f, 40.0f}},
9094         {{ 1.0f,  0.0f,  0.f}, {50.0f, 60.0f, 127.0f, 255.0f}},
9095     };
9096     const UINT exp_vertex_size28 = sizeof(*exp_vertices28);
9097     /* Test 29. Convert SHORT2 to FLOAT4. */
9098     const struct vertex_ptc_short2 vertices29[] =
9099     {
9100         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9101         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9102         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9103
9104         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9105         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX}},
9106         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9107     };
9108     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
9109     const UINT num_faces29 = ARRAY_SIZE(vertices29) / VERTS_PER_FACE;
9110     const UINT vertex_size29 = sizeof(*vertices29);
9111     const struct vertex_ptc_float4 exp_vertices29[] =
9112     {
9113         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9114         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9115         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 0.0f, 1.0f}},
9116
9117         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9118         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 0.0f, 1.0f}},
9119         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, 0.0f, 1.0f}},
9120     };
9121     const UINT exp_vertex_size29 = sizeof(*exp_vertices29);
9122     /* Test 29. Convert SHORT4 to FLOAT4. */
9123     const struct vertex_ptc_short4 vertices30[] =
9124     {
9125         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9126         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9127         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9128
9129         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9130         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1, 0}},
9131         {{ 1.0f,  0.0f,  0.f}, {-42, 42, SHRT_MAX, SHRT_MIN}},
9132     };
9133     const UINT num_vertices30 = ARRAY_SIZE(vertices30);
9134     const UINT num_faces30 = ARRAY_SIZE(vertices30) / VERTS_PER_FACE;
9135     const UINT vertex_size30 = sizeof(*vertices30);
9136     const struct vertex_ptc_float4 exp_vertices30[] =
9137     {
9138         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9139         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9140         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9141
9142         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9143         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1.0f, 0.0f}},
9144         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, SHRT_MAX, SHRT_MIN}},
9145     };
9146     const UINT exp_vertex_size30 = sizeof(*exp_vertices30);
9147     /* Test 31. Convert UBYTE4N to FLOAT4. */
9148     const struct vertex_ptc_ubyte4n vertices31[] =
9149     {
9150         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9151         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9152         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9153
9154         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9155         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9156         {{ 1.0f,  0.0f,  0.f}, {50, 60, 70, UCHAR_MAX}},
9157     };
9158     const UINT num_vertices31 = ARRAY_SIZE(vertices31);
9159     const UINT num_faces31 = ARRAY_SIZE(vertices31) / VERTS_PER_FACE;
9160     const UINT vertex_size31 = sizeof(*vertices31);
9161     const struct vertex_ptc_float4 exp_vertices31[] =
9162     {
9163         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9164         {{ 2.0f,  3.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX}},
9165         {{ 0.0f,  0.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX, 0.0f}},
9166
9167         {{ 3.0f,  3.0f,  0.f}, {0.0f, (FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX}},
9168         {{ 3.0f,  0.0f,  0.f}, {(FLOAT)10/UCHAR_MAX, (FLOAT)20/UCHAR_MAX, (FLOAT)30/UCHAR_MAX, (FLOAT)40/UCHAR_MAX}},
9169         {{ 1.0f,  0.0f,  0.f}, {(FLOAT)50/UCHAR_MAX, (FLOAT)60/UCHAR_MAX, (FLOAT)70/UCHAR_MAX, 1.0f}},
9170     };
9171     const UINT exp_vertex_size31 = sizeof(*exp_vertices31);
9172     /* Test 32. Convert SHORT2N to FLOAT4. */
9173     const struct vertex_ptc_short2 vertices32[] =
9174     {
9175         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9176         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9177         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9178
9179         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9180         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
9181         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9182     };
9183     const UINT num_vertices32 = ARRAY_SIZE(vertices32);
9184     const UINT num_faces32 = ARRAY_SIZE(vertices32) / VERTS_PER_FACE;
9185     const UINT vertex_size32 = sizeof(*vertices32);
9186     const struct vertex_ptc_float4 exp_vertices32[] =
9187     {
9188         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9189         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9190         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 0.0f, 1.0f}},
9191
9192         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9193         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, 0.0f, 1.0f}},
9194         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 0.0f, 1.0f}},
9195     };
9196     const UINT exp_vertex_size32 = sizeof(*exp_vertices32);
9197     /* Test 33. Convert SHORT4N to FLOAT4. */
9198     const struct vertex_ptc_short4 vertices33[] =
9199     {
9200         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9201         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9202         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9203
9204         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9205         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, SHRT_MIN + 1, SHRT_MAX}},
9206         {{ 1.0f,  0.0f,  0.f}, {-42, 42, 1, 1}},
9207     };
9208     const UINT num_vertices33 = ARRAY_SIZE(vertices33);
9209     const UINT num_faces33 = ARRAY_SIZE(vertices33) / VERTS_PER_FACE;
9210     const UINT vertex_size33 = sizeof(*vertices33);
9211     const struct vertex_ptc_float4 exp_vertices33[] =
9212     {
9213         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9214         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX}},
9215         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX, 0.0f}},
9216
9217         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9218         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, -1.0f, 1.0f}},
9219         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9220     };
9221     const UINT exp_vertex_size33 = sizeof(*exp_vertices33);
9222     /* Test 34. Convert FLOAT16_2 to FLOAT4. */
9223     const struct vertex_ptc_float16_2 vertices34[] =
9224     {
9225         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9226         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9227         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9228
9229         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9230         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9231         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9232     };
9233     const UINT num_vertices34 = ARRAY_SIZE(vertices34);
9234     const UINT num_faces34 = ARRAY_SIZE(vertices34) / VERTS_PER_FACE;
9235     const UINT vertex_size34 = sizeof(*vertices34);
9236     const struct vertex_ptc_float4 exp_vertices34[] =
9237     {
9238         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9239         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.700195f, 0.0f, 1.0f}},
9240         {{ 0.0f,  0.0f,  0.f}, {-0.199951f, -0.300049f, 0.0f, 1.0f}},
9241
9242         {{ 3.0f,  3.0f,  0.f}, {0.199951f, 0.300049f, 0.0f, 1.0f}},
9243         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9244         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.0f, 1.0f}},
9245     };
9246     const UINT exp_vertex_size34 = sizeof(*exp_vertices34);
9247     /* Test 35. Convert FLOAT16_4 to FLOAT4. */
9248     const struct vertex_ptc_float16_4 vertices35[] =
9249     {
9250         {{ 0.0f,  3.0f,  0.f}, {0x0000, 0x0000, 0x0000, 0x0000}},
9251         {{ 2.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
9252         {{ 0.0f,  0.0f,  0.f}, {0x3c00, 0x0000, 0x3c00, 0x0000}},
9253
9254         {{ 3.0f,  3.0f,  0.f}, {0x0000, 0x3c00, 0x0000, 0x3c00}},
9255         {{ 3.0f,  0.0f,  0.f}, {0x3800, 0x399a, 0xb266, 0xb4cd}},
9256         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
9257     };
9258     const UINT num_vertices35 = ARRAY_SIZE(vertices35);
9259     const UINT num_faces35 = ARRAY_SIZE(vertices35) / VERTS_PER_FACE;
9260     const UINT vertex_size35 = sizeof(*vertices35);
9261     const struct vertex_ptc_float4 exp_vertices35[] =
9262     {
9263         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9264         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9265         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9266
9267         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9268         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.700195f, -0.199951f, -0.300049f}},
9269         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.099976f, 0.199951f}},
9270     };
9271     const UINT exp_vertex_size35 = sizeof(*exp_vertices35);
9272     /* Test 36. Check that vertex buffer sharing is ok. */
9273     const struct vertex_pn vertices36[] =
9274     {
9275         {{ 0.0f,  3.0f,  0.f}, up},
9276         {{ 2.0f,  3.0f,  0.f}, up},
9277         {{ 0.0f,  0.0f,  0.f}, up},
9278     };
9279     const UINT num_vertices36 = ARRAY_SIZE(vertices36);
9280     const UINT num_faces36 = ARRAY_SIZE(vertices36) / VERTS_PER_FACE;
9281     const UINT vertex_size36 = sizeof(*vertices36);
9282     const DWORD clone_options36 = options | D3DXMESH_VB_SHARE;
9283     /* Common mesh data */
9284     ID3DXMesh *mesh = NULL;
9285     ID3DXMesh *mesh_clone = NULL;
9286     struct
9287     {
9288         const BYTE *vertices;
9289         const DWORD *indices;
9290         const DWORD *attributes;
9291         const UINT num_vertices;
9292         const UINT num_faces;
9293         const UINT vertex_size;
9294         const DWORD create_options;
9295         const DWORD clone_options;
9296         D3DVERTEXELEMENT9 *declaration;
9297         D3DVERTEXELEMENT9 *new_declaration;
9298         const BYTE *exp_vertices;
9299         const UINT exp_vertex_size;
9300     }
9301     tc[] =
9302     {
9303         {
9304             (BYTE*)vertices0,
9305             NULL,
9306             NULL,
9307             num_vertices0,
9308             num_faces0,
9309             vertex_size0,
9310             options,
9311             options,
9312             declaration_pn,
9313             declaration_pn,
9314             (BYTE*)vertices0,
9315             vertex_size0
9316         },
9317         {
9318             (BYTE*)vertices0,
9319             NULL,
9320             NULL,
9321             num_vertices0,
9322             num_faces0,
9323             vertex_size0,
9324             options_16bit,
9325             options_16bit,
9326             declaration_pn,
9327             declaration_pn,
9328             (BYTE*)vertices0,
9329             vertex_size0
9330         },
9331         {
9332             (BYTE*)vertices0,
9333             NULL,
9334             NULL,
9335             num_vertices0,
9336             num_faces0,
9337             vertex_size0,
9338             options,
9339             options,
9340             declaration_pn,
9341             declaration_pntc,
9342             (BYTE*)exp_vertices2,
9343             exp_vertex_size2
9344         },
9345         {
9346             (BYTE*)vertices0,
9347             NULL,
9348             NULL,
9349             num_vertices0,
9350             num_faces0,
9351             vertex_size0,
9352             options,
9353             options,
9354             declaration_pn,
9355             declaration_ptcn,
9356             (BYTE*)exp_vertices3,
9357             exp_vertex_size3
9358         },
9359         {
9360             (BYTE*)vertices4,
9361             NULL,
9362             NULL,
9363             num_vertices4,
9364             num_faces4,
9365             vertex_size4,
9366             options,
9367             options,
9368             declaration_ptc,
9369             declaration_ptc_float16_2,
9370             (BYTE*)exp_vertices4,
9371             exp_vertex_size4
9372         },
9373         {
9374             (BYTE*)vertices5,
9375             NULL,
9376             NULL,
9377             num_vertices5,
9378             num_faces5,
9379             vertex_size5,
9380             options,
9381             options,
9382             declaration_ptc,
9383             declaration_ptc_float16_4,
9384             (BYTE*)exp_vertices5,
9385             exp_vertex_size5
9386         },
9387         {
9388             (BYTE*)vertices6,
9389             NULL,
9390             NULL,
9391             num_vertices6,
9392             num_faces6,
9393             vertex_size6,
9394             options,
9395             options,
9396             declaration_ptc,
9397             declaration_ptc_float1,
9398             (BYTE*)exp_vertices6,
9399             exp_vertex_size6
9400         },
9401         {
9402             (BYTE*)vertices7,
9403             NULL,
9404             NULL,
9405             num_vertices7,
9406             num_faces7,
9407             vertex_size7,
9408             options,
9409             options,
9410             declaration_ptc,
9411             declaration_ptc_float3,
9412             (BYTE*)exp_vertices7,
9413             exp_vertex_size7
9414         },
9415         {
9416             (BYTE*)vertices8,
9417             NULL,
9418             NULL,
9419             num_vertices8,
9420             num_faces8,
9421             vertex_size8,
9422             options,
9423             options,
9424             declaration_ptc,
9425             declaration_ptc_float4,
9426             (BYTE*)exp_vertices8,
9427             exp_vertex_size8
9428         },
9429         {
9430             (BYTE*)vertices9,
9431             NULL,
9432             NULL,
9433             num_vertices9,
9434             num_faces9,
9435             vertex_size9,
9436             options,
9437             options,
9438             declaration_ptc,
9439             declaration_ptc_d3dcolor,
9440             (BYTE*)exp_vertices9,
9441             exp_vertex_size9
9442         },
9443         {
9444             (BYTE*)vertices10,
9445             NULL,
9446             NULL,
9447             num_vertices10,
9448             num_faces10,
9449             vertex_size10,
9450             options,
9451             options,
9452             declaration_ptc,
9453             declaration_ptc_ubyte4,
9454             (BYTE*)exp_vertices10,
9455             exp_vertex_size10
9456         },
9457         {
9458             (BYTE*)vertices11,
9459             NULL,
9460             NULL,
9461             num_vertices11,
9462             num_faces11,
9463             vertex_size11,
9464             options,
9465             options,
9466             declaration_ptc,
9467             declaration_ptc_short2,
9468             (BYTE*)exp_vertices11,
9469             exp_vertex_size11
9470         },
9471         {
9472             (BYTE*)vertices12,
9473             NULL,
9474             NULL,
9475             num_vertices12,
9476             num_faces12,
9477             vertex_size12,
9478             options,
9479             options,
9480             declaration_ptc,
9481             declaration_ptc_short4,
9482             (BYTE*)exp_vertices12,
9483             exp_vertex_size12
9484         },
9485         {
9486             (BYTE*)vertices13,
9487             NULL,
9488             NULL,
9489             num_vertices13,
9490             num_faces13,
9491             vertex_size13,
9492             options,
9493             options,
9494             declaration_ptc,
9495             declaration_ptc_ubyte4n,
9496             (BYTE*)exp_vertices13,
9497             exp_vertex_size13
9498         },
9499         {
9500             (BYTE*)vertices14,
9501             NULL,
9502             NULL,
9503             num_vertices14,
9504             num_faces14,
9505             vertex_size14,
9506             options,
9507             options,
9508             declaration_ptc,
9509             declaration_ptc_short2n,
9510             (BYTE*)exp_vertices14,
9511             exp_vertex_size14
9512         },
9513         {
9514             (BYTE*)vertices15,
9515             NULL,
9516             NULL,
9517             num_vertices15,
9518             num_faces15,
9519             vertex_size15,
9520             options,
9521             options,
9522             declaration_ptc,
9523             declaration_ptc_short4n,
9524             (BYTE*)exp_vertices15,
9525             exp_vertex_size15
9526         },
9527         {
9528             (BYTE*)vertices16,
9529             NULL,
9530             NULL,
9531             num_vertices16,
9532             num_faces16,
9533             vertex_size16,
9534             options,
9535             options,
9536             declaration_ptc,
9537             declaration_ptc_ushort2n,
9538             (BYTE*)exp_vertices16,
9539             exp_vertex_size16
9540         },
9541         {
9542             (BYTE*)vertices17,
9543             NULL,
9544             NULL,
9545             num_vertices17,
9546             num_faces17,
9547             vertex_size17,
9548             options,
9549             options,
9550             declaration_ptc,
9551             declaration_ptc_ushort4n,
9552             (BYTE*)exp_vertices17,
9553             exp_vertex_size17
9554         },
9555         {
9556             (BYTE*)vertices18,
9557             NULL,
9558             NULL,
9559             num_vertices18,
9560             num_faces18,
9561             vertex_size18,
9562             options,
9563             options,
9564             declaration_ptc,
9565             declaration_ptc_float16_2_partialu,
9566             (BYTE*)exp_vertices18,
9567             exp_vertex_size18
9568         },
9569         {
9570             (BYTE*)vertices19,
9571             NULL,
9572             NULL,
9573             num_vertices19,
9574             num_faces19,
9575             vertex_size19,
9576             options,
9577             options,
9578             declaration_pntc,
9579             declaration_pntc1,
9580             (BYTE*)exp_vertices19,
9581             exp_vertex_size19
9582         },
9583         {
9584             (BYTE*)vertices20,
9585             NULL,
9586             NULL,
9587             num_vertices20,
9588             num_faces20,
9589             vertex_size20,
9590             options,
9591             options,
9592             declaration_pntc1,
9593             declaration_pntc,
9594             (BYTE*)exp_vertices20,
9595             exp_vertex_size20
9596         },
9597         {
9598             (BYTE*)vertices21,
9599             NULL,
9600             NULL,
9601             num_vertices21,
9602             num_faces21,
9603             vertex_size21,
9604             options,
9605             options,
9606             declaration_ptc_float1,
9607             declaration_ptc,
9608             (BYTE*)exp_vertices21,
9609             exp_vertex_size21
9610         },
9611         {
9612             (BYTE*)vertices22,
9613             NULL,
9614             NULL,
9615             num_vertices22,
9616             num_faces22,
9617             vertex_size22,
9618             options,
9619             options,
9620             declaration_ptc_float1,
9621             declaration_ptc_float3,
9622             (BYTE*)exp_vertices22,
9623             exp_vertex_size22
9624         },
9625         {
9626             (BYTE*)vertices23,
9627             NULL,
9628             NULL,
9629             num_vertices23,
9630             num_faces23,
9631             vertex_size23,
9632             options,
9633             options,
9634             declaration_ptc_float1,
9635             declaration_ptc_float4,
9636             (BYTE*)exp_vertices23,
9637             exp_vertex_size23
9638         },
9639         {
9640             (BYTE*)vertices24,
9641             NULL,
9642             NULL,
9643             num_vertices24,
9644             num_faces24,
9645             vertex_size24,
9646             options,
9647             options,
9648             declaration_ptc_float1,
9649             declaration_ptc_d3dcolor,
9650             (BYTE*)exp_vertices24,
9651             exp_vertex_size24
9652         },
9653         {
9654             (BYTE*)vertices25,
9655             NULL,
9656             NULL,
9657             num_vertices25,
9658             num_faces25,
9659             vertex_size25,
9660             options,
9661             options,
9662             declaration_ptc_float1,
9663             declaration_ptc_ubyte4,
9664             (BYTE*)exp_vertices25,
9665             exp_vertex_size25
9666         },
9667         {
9668             (BYTE*)vertices26,
9669             NULL,
9670             NULL,
9671             num_vertices26,
9672             num_faces26,
9673             vertex_size26,
9674             options,
9675             options,
9676             declaration_ptc_float4,
9677             declaration_ptc_d3dcolor,
9678             (BYTE*)exp_vertices26,
9679             exp_vertex_size26
9680         },
9681         {
9682             (BYTE*)vertices27,
9683             NULL,
9684             NULL,
9685             num_vertices27,
9686             num_faces27,
9687             vertex_size27,
9688             options,
9689             options,
9690             declaration_ptc_d3dcolor,
9691             declaration_ptc_float4,
9692             (BYTE*)exp_vertices27,
9693             exp_vertex_size27
9694         },
9695         {
9696             (BYTE*)vertices28,
9697             NULL,
9698             NULL,
9699             num_vertices28,
9700             num_faces28,
9701             vertex_size28,
9702             options,
9703             options,
9704             declaration_ptc_ubyte4,
9705             declaration_ptc_float4,
9706             (BYTE*)exp_vertices28,
9707             exp_vertex_size28
9708         },
9709         {
9710             (BYTE*)vertices29,
9711             NULL,
9712             NULL,
9713             num_vertices29,
9714             num_faces29,
9715             vertex_size29,
9716             options,
9717             options,
9718             declaration_ptc_short2,
9719             declaration_ptc_float4,
9720             (BYTE*)exp_vertices29,
9721             exp_vertex_size29
9722         },
9723         {
9724             (BYTE*)vertices30,
9725             NULL,
9726             NULL,
9727             num_vertices30,
9728             num_faces30,
9729             vertex_size30,
9730             options,
9731             options,
9732             declaration_ptc_short4,
9733             declaration_ptc_float4,
9734             (BYTE*)exp_vertices30,
9735             exp_vertex_size30
9736         },
9737         {
9738             (BYTE*)vertices31,
9739             NULL,
9740             NULL,
9741             num_vertices31,
9742             num_faces31,
9743             vertex_size31,
9744             options,
9745             options,
9746             declaration_ptc_ubyte4n,
9747             declaration_ptc_float4,
9748             (BYTE*)exp_vertices31,
9749             exp_vertex_size31
9750         },
9751         {
9752             (BYTE*)vertices32,
9753             NULL,
9754             NULL,
9755             num_vertices32,
9756             num_faces32,
9757             vertex_size32,
9758             options,
9759             options,
9760             declaration_ptc_short2n,
9761             declaration_ptc_float4,
9762             (BYTE*)exp_vertices32,
9763             exp_vertex_size32
9764         },
9765         {
9766             (BYTE*)vertices33,
9767             NULL,
9768             NULL,
9769             num_vertices33,
9770             num_faces33,
9771             vertex_size33,
9772             options,
9773             options,
9774             declaration_ptc_short4n,
9775             declaration_ptc_float4,
9776             (BYTE*)exp_vertices33,
9777             exp_vertex_size33
9778         },
9779         {
9780             (BYTE*)vertices34,
9781             NULL,
9782             NULL,
9783             num_vertices34,
9784             num_faces34,
9785             vertex_size34,
9786             options,
9787             options,
9788             declaration_ptc_float16_2,
9789             declaration_ptc_float4,
9790             (BYTE*)exp_vertices34,
9791             exp_vertex_size34
9792         },
9793         {
9794             (BYTE*)vertices35,
9795             NULL,
9796             NULL,
9797             num_vertices35,
9798             num_faces35,
9799             vertex_size35,
9800             options,
9801             options,
9802             declaration_ptc_float16_4,
9803             declaration_ptc_float4,
9804             (BYTE*)exp_vertices35,
9805             exp_vertex_size35
9806         },
9807         {
9808             (BYTE*)vertices36,
9809             NULL,
9810             NULL,
9811             num_vertices36,
9812             num_faces36,
9813             vertex_size36,
9814             options,
9815             clone_options36,
9816             declaration_pn,
9817             declaration_pn,
9818             (BYTE*)vertices36,
9819             vertex_size36
9820         },
9821     };
9822
9823     test_context = new_test_context();
9824     if (!test_context)
9825     {
9826         skip("Couldn't create test context\n");
9827         goto cleanup;
9828     }
9829
9830     for (i = 0; i < ARRAY_SIZE(tc); i++)
9831     {
9832         UINT j;
9833         D3DVERTEXELEMENT9 new_declaration[MAX_FVF_DECL_SIZE];
9834         UINT exp_new_decl_length, new_decl_length;
9835         UINT exp_new_decl_size, new_decl_size;
9836
9837         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
9838                               tc[i].create_options,
9839                               tc[i].declaration,
9840                               test_context->device, &mesh,
9841                               tc[i].vertices, tc[i].vertex_size,
9842                               tc[i].indices, tc[i].attributes);
9843         if (FAILED(hr))
9844         {
9845             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
9846             goto cleanup;
9847         }
9848
9849         hr = mesh->lpVtbl->CloneMesh(mesh, tc[i].clone_options, tc[i].new_declaration,
9850                                      test_context->device, &mesh_clone);
9851         ok(hr == D3D_OK, "CloneMesh test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
9852
9853         hr = mesh_clone->lpVtbl->GetDeclaration(mesh_clone, new_declaration);
9854         ok(hr == D3D_OK, "GetDeclaration test case %d failed. Got %x\n, expected D3D_OK\n", i, hr);
9855         /* Check declaration elements */
9856         for (j = 0; tc[i].new_declaration[j].Stream != 0xFF; j++)
9857         {
9858             ok(memcmp(&tc[i].new_declaration[j], &new_declaration[j], sizeof(*new_declaration)) == 0,
9859                "Test case %d failed. Declaration element %d did not match.\n", i, j);
9860         }
9861
9862         /* Check declaration length */
9863         exp_new_decl_length = D3DXGetDeclLength(tc[i].new_declaration);
9864         new_decl_length = D3DXGetDeclLength(new_declaration);
9865         ok(new_decl_length == exp_new_decl_length,
9866            "Test case %d failed. Got new declaration length %d, expected %d\n",
9867            i, new_decl_length, exp_new_decl_length);
9868
9869         /* Check declaration size */
9870         exp_new_decl_size = D3DXGetDeclVertexSize(tc[i].new_declaration, 0);
9871         new_decl_size = D3DXGetDeclVertexSize(new_declaration, 0);
9872         ok(new_decl_size == exp_new_decl_size,
9873            "Test case %d failed. Got new declaration size %d, expected %d\n",
9874            i, new_decl_size, exp_new_decl_size);
9875
9876         /* Check vertex data in cloned mesh */
9877         hr = mesh_clone->lpVtbl->LockVertexBuffer(mesh_clone, 0, (void**)&vertices);
9878         if (FAILED(hr))
9879         {
9880             skip("Couldn't lock cloned vertex buffer.\n");
9881             goto cleanup;
9882         }
9883         for (j = 0; j < tc[i].num_vertices; j++)
9884         {
9885             UINT index = tc[i].exp_vertex_size * j;
9886             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].new_declaration);
9887         }
9888         hr = mesh_clone->lpVtbl->UnlockVertexBuffer(mesh_clone);
9889         if (FAILED(hr))
9890         {
9891             skip("Couldn't unlock vertex buffer.\n");
9892             goto cleanup;
9893         }
9894         vertices = NULL;
9895         mesh->lpVtbl->Release(mesh);
9896         mesh = NULL;
9897         mesh_clone->lpVtbl->Release(mesh_clone);
9898         mesh_clone = NULL;
9899     }
9900
9901     /* The following test shows that it is not possible to share a vertex buffer
9902      * with D3DXMESH_VB_SHARE and change the vertex declaration at the same
9903      * time. It reuses the test data from test 2.
9904      */
9905     hr = init_test_mesh(tc[2].num_faces, tc[2].num_vertices,
9906                         tc[2].create_options,
9907                         tc[2].declaration,
9908                         test_context->device, &mesh,
9909                         tc[2].vertices, tc[2].vertex_size,
9910                         tc[2].indices, tc[2].attributes);
9911     if (FAILED(hr))
9912     {
9913         skip("Couldn't initialize test mesh for D3DXMESH_VB_SHARE case."
9914              " Got %x expected D3D_OK\n", hr);
9915         goto cleanup;
9916     }
9917
9918     hr = mesh->lpVtbl->CloneMesh(mesh, tc[2].create_options | D3DXMESH_VB_SHARE,
9919                                  tc[2].new_declaration, test_context->device,
9920                                  &mesh_clone);
9921     ok(hr == D3DERR_INVALIDCALL, "CloneMesh D3DXMESH_VB_SHARE with new"
9922        " declaration. Got %x, expected D3DERR_INVALIDCALL\n",
9923        hr);
9924     mesh->lpVtbl->Release(mesh);
9925     mesh = NULL;
9926     mesh_clone = NULL;
9927
9928 cleanup:
9929     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
9930     if (mesh) mesh->lpVtbl->Release(mesh);
9931     if (mesh_clone) mesh_clone->lpVtbl->Release(mesh_clone);
9932     free_test_context(test_context);
9933 }
9934
9935 static void test_valid_mesh(void)
9936 {
9937     HRESULT hr;
9938     struct test_context *test_context = NULL;
9939     UINT i;
9940     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
9941     const D3DVERTEXELEMENT9 declaration[] =
9942     {
9943         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
9944         D3DDECL_END()
9945     };
9946     const unsigned int VERTS_PER_FACE = 3;
9947     /* mesh0 (one face)
9948      *
9949      * 0--1
9950      * | /
9951      * |/
9952      * 2
9953      */
9954     const D3DXVECTOR3 vertices0[] =
9955     {
9956         { 0.0f,  3.0f,  0.f},
9957         { 2.0f,  3.0f,  0.f},
9958         { 0.0f,  0.0f,  0.f},
9959     };
9960     const DWORD indices0[] = {0, 1, 2};
9961     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
9962     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
9963     const DWORD adjacency0[] = {-1, -1, -1};
9964     const HRESULT exp_hr0 = D3D_OK;
9965     /* mesh1 (Simple bow-tie)
9966      *
9967      * 0--1 1--3
9968      * | /   \ |
9969      * |/     \|
9970      * 2       4
9971      */
9972     const D3DXVECTOR3 vertices1[] =
9973     {
9974         { 0.0f,  3.0f,  0.f},
9975         { 2.0f,  3.0f,  0.f},
9976         { 0.0f,  0.0f,  0.f},
9977
9978         { 4.0f,  3.0f,  0.f},
9979         { 4.0f,  0.0f,  0.f},
9980     };
9981     const DWORD indices1[] = {0, 1, 2, 1, 3, 4};
9982     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
9983     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
9984     const DWORD adjacency1[] = {-1, -1, -1, -1, -1, -1};
9985     const HRESULT exp_hr1 = D3DXERR_INVALIDMESH;
9986     /* Common mesh data */
9987     ID3DXMesh *mesh = NULL;
9988     UINT vertex_size = sizeof(D3DXVECTOR3);
9989     ID3DXBuffer *errors_and_warnings = NULL;
9990     struct
9991     {
9992         const D3DXVECTOR3 *vertices;
9993         const DWORD *indices;
9994         const UINT num_vertices;
9995         const UINT num_faces;
9996         const DWORD *adjacency;
9997         const HRESULT exp_hr;
9998     }
9999     tc[] =
10000     {
10001         {
10002             vertices0,
10003             indices0,
10004             num_vertices0,
10005             num_faces0,
10006             adjacency0,
10007             exp_hr0,
10008         },
10009         {
10010             vertices1,
10011             indices1,
10012             num_vertices1,
10013             num_faces1,
10014             adjacency1,
10015             exp_hr1,
10016         },
10017     };
10018
10019     test_context = new_test_context();
10020     if (!test_context)
10021     {
10022         skip("Couldn't create test context\n");
10023         goto cleanup;
10024     }
10025
10026     for (i = 0; i < ARRAY_SIZE(tc); i++)
10027     {
10028         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10029                             options, declaration,
10030                             test_context->device, &mesh,
10031                             tc[i].vertices, vertex_size,
10032                             tc[i].indices, NULL);
10033         if (FAILED(hr))
10034         {
10035             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10036             goto cleanup;
10037         }
10038
10039         hr = D3DXValidMesh(mesh, tc[i].adjacency, &errors_and_warnings);
10040         todo_wine ok(hr == tc[i].exp_hr, "D3DXValidMesh test case %d failed. "
10041                      "Got %x\n, expected %x\n", i, hr, tc[i].exp_hr);
10042
10043         /* Note errors_and_warnings is deliberately not checked because that
10044          * would require copying wast amounts of the text output. */
10045         if (errors_and_warnings)
10046         {
10047             ID3DXBuffer_Release(errors_and_warnings);
10048             errors_and_warnings = NULL;
10049         }
10050         mesh->lpVtbl->Release(mesh);
10051         mesh = NULL;
10052     }
10053
10054 cleanup:
10055     if (mesh) mesh->lpVtbl->Release(mesh);
10056     free_test_context(test_context);
10057 }
10058
10059 START_TEST(mesh)
10060 {
10061     D3DXBoundProbeTest();
10062     D3DXComputeBoundingBoxTest();
10063     D3DXComputeBoundingSphereTest();
10064     D3DXGetFVFVertexSizeTest();
10065     D3DXIntersectTriTest();
10066     D3DXCreateMeshTest();
10067     D3DXCreateMeshFVFTest();
10068     D3DXLoadMeshTest();
10069     D3DXCreateBoxTest();
10070     D3DXCreateSphereTest();
10071     D3DXCreateCylinderTest();
10072     D3DXCreateTextTest();
10073     test_get_decl_length();
10074     test_get_decl_vertex_size();
10075     test_fvf_decl_conversion();
10076     D3DXGenerateAdjacencyTest();
10077     test_update_semantics();
10078     test_create_skin_info();
10079     test_convert_adjacency_to_point_reps();
10080     test_convert_point_reps_to_adjacency();
10081     test_weld_vertices();
10082     test_clone_mesh();
10083     test_valid_mesh();
10084 }