1 /*
2  * Copyright 2008 David Adam
3  * Copyright 2008 Luis Busquets
4  * Copyright 2009 Henri Verbeet for CodeWeavers
5  * Copyright 2011 Michael Mc Donnell
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #define COBJMACROS
23 #include <stdio.h>
24 #include <float.h>
25 #include <limits.h>
26 #include "wine/test.h"
27 #include "d3dx9.h"
28 #include "initguid.h"
29 #include "rmxftmpl.h"
30 #include "rmxfguid.h"
31 
32 #ifndef NAN
33 /* From wine/port.h */
__port_nan(void)34 static inline float __port_nan(void)
35 {
36     static const unsigned __nan_bytes = 0x7fc00000;
37     return *(const float *)&__nan_bytes;
38 }
39 #define NAN __port_nan()
40 #endif
41 
42 /* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose
43  * function call traces of ID3DXAllocateHierarchy callbacks. */
44 #define TRACECALLBACK if(winetest_debug > 1) trace
45 
46 #define admitted_error 0.0001f
47 
48 #define compare_vertex_sizes(type, exp) \
49     got=D3DXGetFVFVertexSize(type); \
50     ok(got==exp, "Expected: %d, Got: %d\n", exp, got);
51 
52 #define compare_float(got, exp) \
53     do { \
54         float _got = (got); \
55         float _exp = (exp); \
56         ok(_got == _exp, "Expected: %g, Got: %g\n", _exp, _got); \
57     } while (0)
58 
compare(FLOAT u,FLOAT v)59 static BOOL compare(FLOAT u, FLOAT v)
60 {
61     return (fabs(u-v) < admitted_error);
62 }
63 
compare_vec3(D3DXVECTOR3 u,D3DXVECTOR3 v)64 static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v)
65 {
66     return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
67 }
68 
compare_vec4(D3DXVECTOR4 u,D3DXVECTOR4 v)69 static BOOL compare_vec4(D3DXVECTOR4 u, D3DXVECTOR4 v)
70 {
71     return compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) && compare(u.w, v.w);
72 }
73 
74 #define check_floats(got, exp, dim) check_floats_(__LINE__, "", got, exp, dim)
check_floats_(int line,const char * prefix,const float * got,const float * exp,int dim)75 static void check_floats_(int line, const char *prefix, const float *got, const float *exp, int dim)
76 {
77     int i;
78     char exp_buffer[256] = "";
79     char got_buffer[256] = "";
80     char *exp_buffer_ptr = exp_buffer;
81     char *got_buffer_ptr = got_buffer;
82     BOOL equal = TRUE;
83 
84     for (i = 0; i < dim; i++) {
85         if (i) {
86             exp_buffer_ptr += sprintf(exp_buffer_ptr, ", ");
87             got_buffer_ptr += sprintf(got_buffer_ptr, ", ");
88         }
89         equal = equal && compare(*exp, *got);
90         exp_buffer_ptr += sprintf(exp_buffer_ptr, "%g", *exp);
91         got_buffer_ptr += sprintf(got_buffer_ptr, "%g", *got);
92         exp++; got++;
93     }
94     ok_(__FILE__,line)(equal, "%sExpected (%s), got (%s)", prefix, exp_buffer, got_buffer);
95 }
96 
97 struct vertex
98 {
99     D3DXVECTOR3 position;
100     D3DXVECTOR3 normal;
101 };
102 
103 typedef WORD face[3];
104 
compare_face(face a,face b)105 static BOOL compare_face(face a, face b)
106 {
107     return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
108 }
109 
110 struct test_context
111 {
112     HWND hwnd;
113     IDirect3D9 *d3d;
114     IDirect3DDevice9 *device;
115 };
116 
117 /* Initializes a test context struct. Use it to initialize DirectX.
118  *
119  * Returns NULL if an error occurred.
120  */
new_test_context(void)121 static struct test_context *new_test_context(void)
122 {
123     HRESULT hr;
124     HWND hwnd = NULL;
125     IDirect3D9 *d3d = NULL;
126     IDirect3DDevice9 *device = NULL;
127     D3DPRESENT_PARAMETERS d3dpp = {0};
128     struct test_context *test_context;
129 
130     if (!(hwnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
131             640, 480, NULL, NULL, NULL, NULL)))
132     {
133         skip("Couldn't create application window\n");
134         goto error;
135     }
136 
137     d3d = Direct3DCreate9(D3D_SDK_VERSION);
138     if (!d3d)
139     {
140         skip("Couldn't create IDirect3D9 object\n");
141         goto error;
142     }
143 
144     memset(&d3dpp, 0, sizeof(d3dpp));
145     d3dpp.Windowed = TRUE;
146     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
147     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
148                                  D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
149     if (FAILED(hr))
150     {
151         skip("Couldn't create IDirect3DDevice9 object %#x\n", hr);
152         goto error;
153     }
154 
155     test_context = HeapAlloc(GetProcessHeap(), 0, sizeof(*test_context));
156     if (!test_context)
157     {
158         skip("Couldn't allocate memory for test_context\n");
159         goto error;
160     }
161     test_context->hwnd = hwnd;
162     test_context->d3d = d3d;
163     test_context->device = device;
164 
165     return test_context;
166 
167 error:
168     if (device)
169         IDirect3DDevice9_Release(device);
170 
171     if (d3d)
172         IDirect3D9_Release(d3d);
173 
174     if (hwnd)
175         DestroyWindow(hwnd);
176 
177     return NULL;
178 }
179 
free_test_context(struct test_context * test_context)180 static void free_test_context(struct test_context *test_context)
181 {
182     if (!test_context)
183         return;
184 
185     if (test_context->device)
186         IDirect3DDevice9_Release(test_context->device);
187 
188     if (test_context->d3d)
189         IDirect3D9_Release(test_context->d3d);
190 
191     if (test_context->hwnd)
192         DestroyWindow(test_context->hwnd);
193 
194     HeapFree(GetProcessHeap(), 0, test_context);
195 }
196 
197 struct mesh
198 {
199     DWORD number_of_vertices;
200     struct vertex *vertices;
201 
202     DWORD number_of_faces;
203     face *faces;
204 
205     DWORD fvf;
206     UINT vertex_size;
207 };
208 
free_mesh(struct mesh * mesh)209 static void free_mesh(struct mesh *mesh)
210 {
211     HeapFree(GetProcessHeap(), 0, mesh->faces);
212     HeapFree(GetProcessHeap(), 0, mesh->vertices);
213 }
214 
new_mesh(struct mesh * mesh,DWORD number_of_vertices,DWORD number_of_faces)215 static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
216 {
217     mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
218     if (!mesh->vertices)
219     {
220         return FALSE;
221     }
222     mesh->number_of_vertices = number_of_vertices;
223 
224     mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
225     if (!mesh->faces)
226     {
227         HeapFree(GetProcessHeap(), 0, mesh->vertices);
228         return FALSE;
229     }
230     mesh->number_of_faces = number_of_faces;
231 
232     return TRUE;
233 }
234 
compare_mesh(const char * name,ID3DXMesh * d3dxmesh,struct mesh * mesh)235 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
236 {
237     HRESULT hr;
238     DWORD number_of_vertices, number_of_faces;
239     IDirect3DVertexBuffer9 *vertex_buffer;
240     IDirect3DIndexBuffer9 *index_buffer;
241     D3DVERTEXBUFFER_DESC vertex_buffer_description;
242     D3DINDEXBUFFER_DESC index_buffer_description;
243     struct vertex *vertices;
244     face *faces;
245     int expected, i;
246 
247     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
248     ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
249        name, number_of_vertices, mesh->number_of_vertices);
250 
251     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
252     ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
253        name, number_of_faces, mesh->number_of_faces);
254 
255     /* vertex buffer */
256     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
257     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
258 
259     if (hr != D3D_OK)
260     {
261         skip("Couldn't get vertex buffer\n");
262     }
263     else
264     {
265         hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
266         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
267 
268         if (hr != D3D_OK)
269         {
270             skip("Couldn't get vertex buffer description\n");
271         }
272         else
273         {
274             ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
275                name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
276             ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
277                name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
278             ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
279             ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
280                name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
281             ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
282                name, vertex_buffer_description.FVF, mesh->fvf);
283             if (mesh->fvf == 0)
284             {
285                 expected = number_of_vertices * mesh->vertex_size;
286             }
287             else
288             {
289                 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
290             }
291             ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
292                name, vertex_buffer_description.Size, expected);
293         }
294 
295         /* specify offset and size to avoid potential overruns */
296         hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
297                 (void **)&vertices, D3DLOCK_DISCARD);
298         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
299 
300         if (hr != D3D_OK)
301         {
302             skip("Couldn't lock vertex buffer\n");
303         }
304         else
305         {
306             for (i = 0; i < number_of_vertices; i++)
307             {
308                 ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
309                    "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
310                    vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
311                    mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
312                 ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
313                    "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
314                    vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
315                    mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
316             }
317 
318             IDirect3DVertexBuffer9_Unlock(vertex_buffer);
319         }
320 
321         IDirect3DVertexBuffer9_Release(vertex_buffer);
322     }
323 
324     /* index buffer */
325     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
326     ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
327 
328     if (!index_buffer)
329     {
330         skip("Couldn't get index buffer\n");
331     }
332     else
333     {
334         hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
335         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
336 
337         if (hr != D3D_OK)
338         {
339             skip("Couldn't get index buffer description\n");
340         }
341         else
342         {
343             ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
344                name, index_buffer_description.Format, D3DFMT_INDEX16);
345             ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
346                name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
347             ok(index_buffer_description.Usage == 0, "Test %s, result %#x, expected %#x.\n",
348                     name, index_buffer_description.Usage, 0);
349             ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
350                name, index_buffer_description.Pool, D3DPOOL_MANAGED);
351             expected = number_of_faces * sizeof(WORD) * 3;
352             ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
353                name, index_buffer_description.Size, expected);
354         }
355 
356         /* specify offset and size to avoid potential overruns */
357         hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
358                 (void **)&faces, D3DLOCK_DISCARD);
359         ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
360 
361         if (hr != D3D_OK)
362         {
363             skip("Couldn't lock index buffer\n");
364         }
365         else
366         {
367             for (i = 0; i < number_of_faces; i++)
368             {
369                 ok(compare_face(faces[i], mesh->faces[i]),
370                    "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
371                    faces[i][0], faces[i][1], faces[i][2],
372                    mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
373             }
374 
375             IDirect3DIndexBuffer9_Unlock(index_buffer);
376         }
377 
378         IDirect3DIndexBuffer9_Release(index_buffer);
379     }
380 }
381 
D3DXBoundProbeTest(void)382 static void D3DXBoundProbeTest(void)
383 {
384     BOOL result;
385     D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
386     FLOAT radius;
387 
388 /*____________Test the Box case___________________________*/
389     bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
390     top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
391 
392     raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
393     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
394     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
395     ok(result == TRUE, "expected TRUE, received FALSE\n");
396 
397     raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
398     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
399     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
400     ok(result == FALSE, "expected FALSE, received TRUE\n");
401 
402     rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
403     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
404     ok(result == TRUE, "expected TRUE, received FALSE\n");
405 
406     bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
407     top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
408     rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
409     raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
410     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
411     ok(result == FALSE, "expected FALSE, received TRUE\n");
412 
413     bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
414     top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
415 
416     raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
417     rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
418     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
419     ok(result == TRUE, "expected TRUE, received FALSE\n");
420 
421     bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
422     top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
423 
424     raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
425     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
426     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
427     ok(result == FALSE, "expected FALSE, received TRUE\n");
428 
429     raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
430     rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
431     result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
432     ok(result == TRUE, "expected TRUE, received FALSE\n");
433 
434 /*____________Test the Sphere case________________________*/
435     radius = sqrt(77.0f);
436     center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
437     raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
438     rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
439     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
440     ok(result == TRUE, "Got unexpected result %#x.\n", result);
441 
442     rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
443     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
444     ok(result == FALSE, "Got unexpected result %#x.\n", result);
445 
446     raydirection.x = -2.0f; raydirection.y = 4.0f; raydirection.z = -2.0f;
447     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
448     ok(result == TRUE, "Got unexpected result %#x.\n", result);
449 
450     rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
451     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
452     ok(result == FALSE, "Got unexpected result %#x.\n", result);
453 
454     raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
455     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
456     ok(result == FALSE, "Got unexpected result %#x.\n", result);
457 
458     radius = 1.0f;
459     rayposition.x = 2.0f; rayposition.y = 2.0f; rayposition.z = 3.0f;
460     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
461     ok(result == FALSE, "Got unexpected result %#x.\n", result);
462 
463     raydirection.x = 0.0f; raydirection.y = 0.0f; raydirection.z = 1.0f;
464     result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
465     ok(result == TRUE, "Got unexpected result %#x.\n", result);
466 
467     if (0)
468     {
469         /* All these crash on native. */
470         D3DXSphereBoundProbe(&center, radius, &rayposition, NULL);
471         D3DXSphereBoundProbe(&center, radius, NULL, &raydirection);
472         D3DXSphereBoundProbe(NULL, radius, &rayposition, &raydirection);
473     }
474 }
475 
D3DXComputeBoundingBoxTest(void)476 static void D3DXComputeBoundingBoxTest(void)
477 {
478     D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
479     HRESULT hr;
480 
481     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
482     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
483     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
484     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
485     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
486 
487     exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
488     exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
489 
490     hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
491 
492     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
493     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);
494     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);
495 
496 /*________________________*/
497 
498     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
499     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
500     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
501     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
502     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
503 
504     exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
505     exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
506 
507     hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
508 
509     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
510     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);
511     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);
512 
513 /*________________________*/
514 
515     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
516     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
517     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
518     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
519     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
520 
521     exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
522     exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
523 
524     hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
525 
526     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
527     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);
528     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);
529 
530 /*________________________*/
531     hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
532     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
533 
534 /*________________________*/
535     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
536     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
537 
538 /*________________________*/
539     hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
540     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
541 }
542 
D3DXComputeBoundingSphereTest(void)543 static void D3DXComputeBoundingSphereTest(void)
544 {
545     D3DXVECTOR3 exp_cen, got_cen, vertex[5];
546     FLOAT exp_rad, got_rad;
547     HRESULT hr;
548 
549     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
550     vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
551     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
552     vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
553     vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
554 
555     exp_rad = 6.928203f;
556     exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
557 
558     hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
559 
560     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
561     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
562     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);
563 
564 /*________________________*/
565 
566     vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
567     vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
568     vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
569     vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
570     vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
571 
572     exp_rad = 13.707883f;
573     exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
574 
575     hr = D3DXComputeBoundingSphere(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
576 
577     ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
578     ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
579     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);
580 
581 /*________________________*/
582     hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
583     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
584 
585 /*________________________*/
586     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
587     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
588 
589 /*________________________*/
590     hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
591     ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
592 }
593 
print_elements(const D3DVERTEXELEMENT9 * elements)594 static void print_elements(const D3DVERTEXELEMENT9 *elements)
595 {
596     D3DVERTEXELEMENT9 last = D3DDECL_END();
597     const D3DVERTEXELEMENT9 *ptr = elements;
598     int count = 0;
599 
600     while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
601     {
602         trace(
603             "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
604              count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
605         ptr++;
606         count++;
607     }
608 }
609 
compare_elements(const D3DVERTEXELEMENT9 * elements,const D3DVERTEXELEMENT9 * expected_elements,unsigned int line,unsigned int test_id)610 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
611         unsigned int line, unsigned int test_id)
612 {
613     D3DVERTEXELEMENT9 last = D3DDECL_END();
614     unsigned int i;
615 
616     for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
617     {
618         int end1 = memcmp(&elements[i], &last, sizeof(last));
619         int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
620         int status;
621 
622         if (!end1 && !end2) break;
623 
624         status = !end1 ^ !end2;
625         ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
626                 line, test_id, end1 ? "shorter" : "longer");
627         if (status)
628         {
629             print_elements(elements);
630             break;
631         }
632 
633         status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
634         ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
635         if (status)
636         {
637             print_elements(elements);
638             break;
639         }
640     }
641 }
642 
test_fvf_to_decl(DWORD test_fvf,const D3DVERTEXELEMENT9 expected_elements[],HRESULT expected_hr,unsigned int line,unsigned int test_id)643 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
644         HRESULT expected_hr, unsigned int line, unsigned int test_id)
645 {
646     HRESULT hr;
647     D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
648 
649     hr = D3DXDeclaratorFromFVF(test_fvf, decl);
650     ok(hr == expected_hr,
651             "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
652             line, test_id, hr, expected_hr);
653     if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
654 }
655 
test_decl_to_fvf(const D3DVERTEXELEMENT9 * decl,DWORD expected_fvf,HRESULT expected_hr,unsigned int line,unsigned int test_id)656 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
657         HRESULT expected_hr, unsigned int line, unsigned int test_id)
658 {
659     HRESULT hr;
660     DWORD result_fvf = 0xdeadbeef;
661 
662     hr = D3DXFVFFromDeclarator(decl, &result_fvf);
663     ok(hr == expected_hr,
664        "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
665        line, test_id, hr, expected_hr);
666     if (SUCCEEDED(hr))
667     {
668         ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
669                 line, test_id, result_fvf, expected_fvf);
670     }
671 }
672 
test_fvf_decl_conversion(void)673 static void test_fvf_decl_conversion(void)
674 {
675     static const struct
676     {
677         D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
678         DWORD fvf;
679     }
680     test_data[] =
681     {
682         {{
683             D3DDECL_END(),
684         }, 0},
685         {{
686             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
687             D3DDECL_END(),
688         }, D3DFVF_XYZ},
689         {{
690             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
691             D3DDECL_END(),
692         }, D3DFVF_XYZRHW},
693         {{
694             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
695             D3DDECL_END(),
696         }, D3DFVF_XYZRHW},
697         {{
698             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
699             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
700             D3DDECL_END(),
701         }, D3DFVF_XYZB1},
702         {{
703             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
704             {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
705             D3DDECL_END(),
706         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
707         {{
708             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
709             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
710             D3DDECL_END(),
711         }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
712         {{
713             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
714             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
715             D3DDECL_END(),
716         }, D3DFVF_XYZB2},
717         {{
718             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
719             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
720             {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
721             D3DDECL_END(),
722         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
723         {{
724             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
725             {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
726             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
727             D3DDECL_END(),
728         }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
729         {{
730             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
731             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
732             D3DDECL_END(),
733         }, D3DFVF_XYZB3},
734         {{
735             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
736             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
737             {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
738             D3DDECL_END(),
739         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
740         {{
741             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
742             {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
743             {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
744             D3DDECL_END(),
745         }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
746         {{
747             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
748             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
749             D3DDECL_END(),
750         }, D3DFVF_XYZB4},
751         {{
752             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
753             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
754             {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
755             D3DDECL_END(),
756         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
757         {{
758             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
759             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
760             {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
761             D3DDECL_END(),
762         }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
763         {{
764             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
765             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
766             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
767             D3DDECL_END(),
768         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
769         {{
770             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
771             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
772             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
773             D3DDECL_END(),
774         }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
775         {{
776             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
777             D3DDECL_END(),
778         }, D3DFVF_NORMAL},
779         {{
780             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
781             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
782             D3DDECL_END(),
783         }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
784         {{
785             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
786             D3DDECL_END(),
787         }, D3DFVF_PSIZE},
788         {{
789             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
790             D3DDECL_END(),
791         }, D3DFVF_DIFFUSE},
792         {{
793             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
794             D3DDECL_END(),
795         }, D3DFVF_SPECULAR},
796         /* Make sure textures of different sizes work. */
797         {{
798             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
799             D3DDECL_END(),
800         }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
801         {{
802             {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
803             D3DDECL_END(),
804         }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
805         {{
806             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
807             D3DDECL_END(),
808         }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
809         {{
810             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
811             D3DDECL_END(),
812         }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
813         /* Make sure the TEXCOORD index works correctly - try several textures. */
814         {{
815             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
816             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
817             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
818             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
819             D3DDECL_END(),
820         }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
821                 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
822         /* Now try some combination tests. */
823         {{
824             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
825             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
826             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
827             {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
828             {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
829             {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
830             D3DDECL_END(),
831         }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
832                 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
833         {{
834             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
835             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
836             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
837             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
838             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
839             {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
840             D3DDECL_END(),
841         }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
842                 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
843     };
844     unsigned int i;
845 
846     for (i = 0; i < ARRAY_SIZE(test_data); ++i)
847     {
848         test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
849         test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
850     }
851 
852     /* Usage indices for position and normal are apparently ignored. */
853     {
854         const D3DVERTEXELEMENT9 decl[] =
855         {
856             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
857             D3DDECL_END(),
858         };
859         test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
860     }
861     {
862         const D3DVERTEXELEMENT9 decl[] =
863         {
864             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
865             D3DDECL_END(),
866         };
867         test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
868     }
869     /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
870      * there are no blend matrices. */
871     {
872         const D3DVERTEXELEMENT9 decl[] =
873         {
874             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
875             D3DDECL_END(),
876         };
877         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
878     }
879     {
880         const D3DVERTEXELEMENT9 decl[] =
881         {
882             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
883             D3DDECL_END(),
884         };
885         test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
886     }
887     /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
888     {
889         const D3DVERTEXELEMENT9 decl[] =
890         {
891             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
892             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
893             {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
894             D3DDECL_END(),
895         };
896         test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
897                 decl, D3D_OK, __LINE__, 0);
898     }
899     /* These are supposed to fail, both ways. */
900     {
901         const D3DVERTEXELEMENT9 decl[] =
902         {
903             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
904             D3DDECL_END(),
905         };
906         test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
907         test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
908     }
909     {
910         const D3DVERTEXELEMENT9 decl[] =
911         {
912             {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
913             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
914             D3DDECL_END(),
915         };
916         test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
917         test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
918     }
919     {
920         const D3DVERTEXELEMENT9 decl[] =
921         {
922             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
923             {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
924             {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
925             D3DDECL_END(),
926         };
927         test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
928         test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
929     }
930     /* Test a declaration that can't be converted to an FVF. */
931     {
932         const D3DVERTEXELEMENT9 decl[] =
933         {
934             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
935             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
936             {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
937             {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
938             {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
939             /* 8 bytes padding */
940             {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
941             D3DDECL_END(),
942         };
943         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
944     }
945     /* Elements must be ordered by offset. */
946     {
947         const D3DVERTEXELEMENT9 decl[] =
948         {
949             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
950             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
951             D3DDECL_END(),
952         };
953         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
954     }
955     /* Basic tests for element order. */
956     {
957         const D3DVERTEXELEMENT9 decl[] =
958         {
959             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
960             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
961             {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
962             D3DDECL_END(),
963         };
964         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
965     }
966     {
967         const D3DVERTEXELEMENT9 decl[] =
968         {
969             {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
970             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
971             D3DDECL_END(),
972         };
973         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
974     }
975     {
976         const D3DVERTEXELEMENT9 decl[] =
977         {
978             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
979             {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
980             D3DDECL_END(),
981         };
982         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
983     }
984     /* Textures must be ordered by texcoords. */
985     {
986         const D3DVERTEXELEMENT9 decl[] =
987         {
988             {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
989             {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
990             {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
991             {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
992             D3DDECL_END(),
993         };
994         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
995     }
996     /* Duplicate elements are not allowed. */
997     {
998         const D3DVERTEXELEMENT9 decl[] =
999         {
1000             {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
1001             {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
1002             {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
1003             D3DDECL_END(),
1004         };
1005         test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
1006     }
1007     /* Invalid FVFs cannot be converted to a declarator. */
1008     test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
1009 }
1010 
D3DXGetFVFVertexSizeTest(void)1011 static void D3DXGetFVFVertexSizeTest(void)
1012 {
1013     UINT got;
1014 
1015     compare_vertex_sizes (D3DFVF_XYZ, 12);
1016 
1017     compare_vertex_sizes (D3DFVF_XYZB3, 24);
1018 
1019     compare_vertex_sizes (D3DFVF_XYZB5, 32);
1020 
1021     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
1022 
1023     compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
1024 
1025     compare_vertex_sizes (
1026         D3DFVF_XYZ |
1027         D3DFVF_TEX1 |
1028         D3DFVF_TEXCOORDSIZE1(0), 16);
1029     compare_vertex_sizes (
1030         D3DFVF_XYZ |
1031         D3DFVF_TEX2 |
1032         D3DFVF_TEXCOORDSIZE1(0) |
1033         D3DFVF_TEXCOORDSIZE1(1), 20);
1034 
1035     compare_vertex_sizes (
1036         D3DFVF_XYZ |
1037         D3DFVF_TEX1 |
1038         D3DFVF_TEXCOORDSIZE2(0), 20);
1039 
1040     compare_vertex_sizes (
1041         D3DFVF_XYZ |
1042         D3DFVF_TEX2 |
1043         D3DFVF_TEXCOORDSIZE2(0) |
1044         D3DFVF_TEXCOORDSIZE2(1), 28);
1045 
1046     compare_vertex_sizes (
1047         D3DFVF_XYZ |
1048         D3DFVF_TEX6 |
1049         D3DFVF_TEXCOORDSIZE2(0) |
1050         D3DFVF_TEXCOORDSIZE2(1) |
1051         D3DFVF_TEXCOORDSIZE2(2) |
1052         D3DFVF_TEXCOORDSIZE2(3) |
1053         D3DFVF_TEXCOORDSIZE2(4) |
1054         D3DFVF_TEXCOORDSIZE2(5), 60);
1055 
1056     compare_vertex_sizes (
1057         D3DFVF_XYZ |
1058         D3DFVF_TEX8 |
1059         D3DFVF_TEXCOORDSIZE2(0) |
1060         D3DFVF_TEXCOORDSIZE2(1) |
1061         D3DFVF_TEXCOORDSIZE2(2) |
1062         D3DFVF_TEXCOORDSIZE2(3) |
1063         D3DFVF_TEXCOORDSIZE2(4) |
1064         D3DFVF_TEXCOORDSIZE2(5) |
1065         D3DFVF_TEXCOORDSIZE2(6) |
1066         D3DFVF_TEXCOORDSIZE2(7), 76);
1067 
1068     compare_vertex_sizes (
1069         D3DFVF_XYZ |
1070         D3DFVF_TEX1 |
1071         D3DFVF_TEXCOORDSIZE3(0), 24);
1072 
1073     compare_vertex_sizes (
1074         D3DFVF_XYZ |
1075         D3DFVF_TEX4 |
1076         D3DFVF_TEXCOORDSIZE3(0) |
1077         D3DFVF_TEXCOORDSIZE3(1) |
1078         D3DFVF_TEXCOORDSIZE3(2) |
1079         D3DFVF_TEXCOORDSIZE3(3), 60);
1080 
1081     compare_vertex_sizes (
1082         D3DFVF_XYZ |
1083         D3DFVF_TEX1 |
1084         D3DFVF_TEXCOORDSIZE4(0), 28);
1085 
1086     compare_vertex_sizes (
1087         D3DFVF_XYZ |
1088         D3DFVF_TEX2 |
1089         D3DFVF_TEXCOORDSIZE4(0) |
1090         D3DFVF_TEXCOORDSIZE4(1), 44);
1091 
1092     compare_vertex_sizes (
1093         D3DFVF_XYZ |
1094         D3DFVF_TEX3 |
1095         D3DFVF_TEXCOORDSIZE4(0) |
1096         D3DFVF_TEXCOORDSIZE4(1) |
1097         D3DFVF_TEXCOORDSIZE4(2), 60);
1098 
1099     compare_vertex_sizes (
1100         D3DFVF_XYZB5 |
1101         D3DFVF_NORMAL |
1102         D3DFVF_DIFFUSE |
1103         D3DFVF_SPECULAR |
1104         D3DFVF_TEX8 |
1105         D3DFVF_TEXCOORDSIZE4(0) |
1106         D3DFVF_TEXCOORDSIZE4(1) |
1107         D3DFVF_TEXCOORDSIZE4(2) |
1108         D3DFVF_TEXCOORDSIZE4(3) |
1109         D3DFVF_TEXCOORDSIZE4(4) |
1110         D3DFVF_TEXCOORDSIZE4(5) |
1111         D3DFVF_TEXCOORDSIZE4(6) |
1112         D3DFVF_TEXCOORDSIZE4(7), 180);
1113 }
1114 
D3DXIntersectTriTest(void)1115 static void D3DXIntersectTriTest(void)
1116 {
1117     BOOL exp_res, got_res;
1118     D3DXVECTOR3 position, ray, vertex[3];
1119     FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
1120 
1121     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1122     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1123     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1124 
1125     position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
1126 
1127     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1128 
1129     exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
1130 
1131     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1132     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1133     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1134     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1135     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1136 
1137     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1138     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1139 
1140     vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1141     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1142     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 0.0f;
1143 
1144     got_u = got_v = got_dist = 0.0f;
1145     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1146     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1147     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1148     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1149     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1150 
1151     vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1152     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = -0.5f;
1153     vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = -1.0f;
1154     exp_u = 0.375f;
1155     exp_v = 0.5625f;
1156     exp_dist = 7.9375f;
1157     got_u = got_v = got_dist = 0.0f;
1158     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1159     ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1160     ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1161     ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1162     ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1163 
1164 
1165 /*Only positive ray is taken in account*/
1166 
1167     vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1168     vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1169     vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1170 
1171     position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
1172 
1173     ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1174 
1175     exp_res = FALSE;
1176 
1177     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1178     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1179 
1180     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1181     ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1182 
1183 /*Intersection between ray and triangle in a same plane is considered as empty*/
1184 
1185     vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1186     vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1187     vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
1188 
1189     position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
1190 
1191     ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
1192 
1193     exp_res = FALSE;
1194 
1195     got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1196     ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1197 
1198     got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1199     ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1200 }
1201 
D3DXCreateMeshTest(void)1202 static void D3DXCreateMeshTest(void)
1203 {
1204     HRESULT hr;
1205     IDirect3DDevice9 *device, *test_device;
1206     ID3DXMesh *d3dxmesh;
1207     int i, size;
1208     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1209     DWORD options;
1210     struct mesh mesh;
1211     struct test_context *test_context;
1212 
1213     static const D3DVERTEXELEMENT9 decl1[] =
1214     {
1215         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1216         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1217         D3DDECL_END(),
1218     };
1219 
1220     static const D3DVERTEXELEMENT9 decl2[] =
1221     {
1222         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1223         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1224         {0, 24, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
1225         {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
1226         {0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
1227         /* 8 bytes padding */
1228         {0, 44, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
1229         D3DDECL_END(),
1230     };
1231 
1232     static const D3DVERTEXELEMENT9 decl3[] =
1233     {
1234         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1235         {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1236         D3DDECL_END(),
1237     };
1238 
1239     hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1240     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1241 
1242     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1243     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1244 
1245     test_context = new_test_context();
1246     if (!test_context)
1247     {
1248         skip("Couldn't create test context\n");
1249         return;
1250     }
1251     device = test_context->device;
1252 
1253     hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1254     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1255 
1256     hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1257     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1258 
1259     hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
1260     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1261 
1262     if (hr == D3D_OK)
1263     {
1264         d3dxmesh->lpVtbl->Release(d3dxmesh);
1265     }
1266 
1267     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1268     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1269 
1270     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
1271     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1272 
1273     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1274     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1275 
1276     if (hr == D3D_OK)
1277     {
1278         /* device */
1279         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1280         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1281 
1282         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1283         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1284         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1285 
1286         if (hr == D3D_OK)
1287         {
1288             IDirect3DDevice9_Release(device);
1289         }
1290 
1291         /* declaration */
1292         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1293         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1294 
1295         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1296         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1297 
1298         if (hr == D3D_OK)
1299         {
1300             size = ARRAY_SIZE(decl1);
1301             for (i = 0; i < size - 1; i++)
1302             {
1303                 ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1304                 ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1305                 ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1306                 ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1307                 ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1308                 ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1309             }
1310             ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1311         }
1312 
1313         /* options */
1314         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1315         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1316 
1317         /* rest */
1318         if (!new_mesh(&mesh, 3, 1))
1319         {
1320             skip("Couldn't create mesh\n");
1321         }
1322         else
1323         {
1324             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1325             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1326             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1327 
1328             compare_mesh("createmesh1", d3dxmesh, &mesh);
1329 
1330             free_mesh(&mesh);
1331         }
1332 
1333         d3dxmesh->lpVtbl->Release(d3dxmesh);
1334     }
1335 
1336     /* Test a declaration that can't be converted to an FVF. */
1337     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1338     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1339 
1340     if (hr == D3D_OK)
1341     {
1342         /* device */
1343         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1344         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1345 
1346         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1347         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1348         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1349 
1350         if (hr == D3D_OK)
1351         {
1352             IDirect3DDevice9_Release(device);
1353         }
1354 
1355         /* declaration */
1356         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1357         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1358 
1359         if (hr == D3D_OK)
1360         {
1361             size = ARRAY_SIZE(decl2);
1362             for (i = 0; i < size - 1; i++)
1363             {
1364                 ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1365                 ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1366                 ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1367                 ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1368                 ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1369                 ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1370             }
1371             ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1372         }
1373 
1374         /* options */
1375         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1376         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1377 
1378         /* rest */
1379         if (!new_mesh(&mesh, 3, 1))
1380         {
1381             skip("Couldn't create mesh\n");
1382         }
1383         else
1384         {
1385             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1386             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1387             mesh.fvf = 0;
1388             mesh.vertex_size = 60;
1389 
1390             compare_mesh("createmesh2", d3dxmesh, &mesh);
1391 
1392             free_mesh(&mesh);
1393         }
1394 
1395         mesh.vertex_size = d3dxmesh->lpVtbl->GetNumBytesPerVertex(d3dxmesh);
1396         ok(mesh.vertex_size == 60, "Got vertex size %u, expected %u\n", mesh.vertex_size, 60);
1397 
1398         d3dxmesh->lpVtbl->Release(d3dxmesh);
1399     }
1400 
1401     /* Test a declaration with multiple streams. */
1402     hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
1403     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1404 
1405     free_test_context(test_context);
1406 }
1407 
D3DXCreateMeshFVFTest(void)1408 static void D3DXCreateMeshFVFTest(void)
1409 {
1410     HRESULT hr;
1411     IDirect3DDevice9 *device, *test_device;
1412     ID3DXMesh *d3dxmesh;
1413     int i, size;
1414     D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1415     DWORD options;
1416     struct mesh mesh;
1417     struct test_context *test_context;
1418 
1419     static const D3DVERTEXELEMENT9 decl[] =
1420     {
1421         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1422         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1423         D3DDECL_END(),
1424     };
1425 
1426     hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1427     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1428 
1429     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, NULL, &d3dxmesh);
1430     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1431 
1432     test_context = new_test_context();
1433     if (!test_context)
1434     {
1435         skip("Couldn't create test context\n");
1436         return;
1437     }
1438     device = test_context->device;
1439 
1440     hr = D3DXCreateMeshFVF(0, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1441     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1442 
1443     hr = D3DXCreateMeshFVF(1, 0, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1444     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1445 
1446     hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1447     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1448 
1449     if (hr == D3D_OK)
1450     {
1451         d3dxmesh->lpVtbl->Release(d3dxmesh);
1452     }
1453 
1454     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1455     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1456 
1457     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, NULL);
1458     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1459 
1460     hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1461     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1462 
1463     if (hr == D3D_OK)
1464     {
1465         /* device */
1466         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1467         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1468 
1469         hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1470         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1471         ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1472 
1473         if (hr == D3D_OK)
1474         {
1475             IDirect3DDevice9_Release(device);
1476         }
1477 
1478         /* declaration */
1479         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1480         ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1481 
1482         hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1483         ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1484 
1485         if (hr == D3D_OK)
1486         {
1487             size = ARRAY_SIZE(decl);
1488             for (i = 0; i < size - 1; i++)
1489             {
1490                 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1491                 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1492                 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1493                 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1494                 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1495                    test_decl[i].UsageIndex, decl[i].UsageIndex);
1496                 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1497             }
1498             ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1499         }
1500 
1501         /* options */
1502         options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1503         ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1504 
1505         /* rest */
1506         if (!new_mesh(&mesh, 3, 1))
1507         {
1508             skip("Couldn't create mesh\n");
1509         }
1510         else
1511         {
1512             memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1513             memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1514             mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1515 
1516             compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1517 
1518             free_mesh(&mesh);
1519         }
1520 
1521         d3dxmesh->lpVtbl->Release(d3dxmesh);
1522     }
1523 
1524     free_test_context(test_context);
1525 }
1526 
1527 #define check_vertex_buffer(mesh, vertices, num_vertices, fvf) \
1528     check_vertex_buffer_(__LINE__, mesh, vertices, num_vertices, fvf)
check_vertex_buffer_(int line,ID3DXMesh * mesh,const void * vertices,DWORD num_vertices,DWORD fvf)1529 static void check_vertex_buffer_(int line, ID3DXMesh *mesh, const void *vertices, DWORD num_vertices, DWORD fvf)
1530 {
1531     DWORD mesh_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
1532     DWORD mesh_fvf = mesh->lpVtbl->GetFVF(mesh);
1533     const void *mesh_vertices;
1534     HRESULT hr;
1535 
1536     ok_(__FILE__,line)(fvf == mesh_fvf, "expected FVF %x, got %x\n", fvf, mesh_fvf);
1537     ok_(__FILE__,line)(num_vertices == mesh_num_vertices,
1538        "Expected %u vertices, got %u\n", num_vertices, mesh_num_vertices);
1539 
1540     hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
1541     ok_(__FILE__,line)(hr == D3D_OK, "LockVertexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1542     if (FAILED(hr))
1543         return;
1544 
1545     if (mesh_fvf == fvf) {
1546         DWORD vertex_size = D3DXGetFVFVertexSize(fvf), i;
1547 
1548         for (i = 0; i < min(num_vertices, mesh_num_vertices); i++)
1549         {
1550             const FLOAT *exp_float = vertices;
1551             const FLOAT *got_float = mesh_vertices;
1552             DWORD texcount;
1553             DWORD pos_dim = 0;
1554             int j;
1555             BOOL last_beta_dword = FALSE;
1556             char prefix[128];
1557 
1558             switch (fvf & D3DFVF_POSITION_MASK) {
1559                 case D3DFVF_XYZ: pos_dim = 3; break;
1560                 case D3DFVF_XYZRHW: pos_dim = 4; break;
1561                 case D3DFVF_XYZB1:
1562                 case D3DFVF_XYZB2:
1563                 case D3DFVF_XYZB3:
1564                 case D3DFVF_XYZB4:
1565                 case D3DFVF_XYZB5:
1566                     pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
1567                     if (fvf & (D3DFVF_LASTBETA_UBYTE4 | D3DFVF_LASTBETA_D3DCOLOR))
1568                     {
1569                         pos_dim--;
1570                         last_beta_dword = TRUE;
1571                     }
1572                     break;
1573                 case D3DFVF_XYZW: pos_dim = 4; break;
1574             }
1575             sprintf(prefix, "vertex[%u] position, ", i);
1576             check_floats_(line, prefix, got_float, exp_float, pos_dim);
1577             exp_float += pos_dim;
1578             got_float += pos_dim;
1579 
1580             if (last_beta_dword) {
1581                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1582                     "Vertex[%u]: Expected last beta %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1583                 exp_float++;
1584                 got_float++;
1585             }
1586 
1587             if (fvf & D3DFVF_NORMAL) {
1588                 sprintf(prefix, "vertex[%u] normal, ", i);
1589                 check_floats_(line, prefix, got_float, exp_float, 3);
1590                 exp_float += 3;
1591                 got_float += 3;
1592             }
1593             if (fvf & D3DFVF_PSIZE) {
1594                 ok_(__FILE__,line)(compare(*exp_float, *got_float),
1595                         "Vertex[%u]: Expected psize %g, got %g\n", i, *exp_float, *got_float);
1596                 exp_float++;
1597                 got_float++;
1598             }
1599             if (fvf & D3DFVF_DIFFUSE) {
1600                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1601                     "Vertex[%u]: Expected diffuse %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1602                 exp_float++;
1603                 got_float++;
1604             }
1605             if (fvf & D3DFVF_SPECULAR) {
1606                 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1607                     "Vertex[%u]: Expected specular %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1608                 exp_float++;
1609                 got_float++;
1610             }
1611 
1612             texcount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
1613             for (j = 0; j < texcount; j++) {
1614                 DWORD dim = (((fvf >> (16 + 2 * j)) + 1) & 0x03) + 1;
1615                 sprintf(prefix, "vertex[%u] texture, ", i);
1616                 check_floats_(line, prefix, got_float, exp_float, dim);
1617                 exp_float += dim;
1618                 got_float += dim;
1619             }
1620 
1621             vertices = (BYTE*)vertices + vertex_size;
1622             mesh_vertices = (BYTE*)mesh_vertices + vertex_size;
1623         }
1624     }
1625 
1626     mesh->lpVtbl->UnlockVertexBuffer(mesh);
1627 }
1628 
1629 #define check_index_buffer(mesh, indices, num_indices, index_size) \
1630     check_index_buffer_(__LINE__, mesh, indices, num_indices, index_size)
check_index_buffer_(int line,ID3DXMesh * mesh,const void * indices,DWORD num_indices,DWORD index_size)1631 static void check_index_buffer_(int line, ID3DXMesh *mesh, const void *indices, DWORD num_indices, DWORD index_size)
1632 {
1633     DWORD mesh_index_size = (mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT) ? 4 : 2;
1634     DWORD mesh_num_indices = mesh->lpVtbl->GetNumFaces(mesh) * 3;
1635     const void *mesh_indices;
1636     HRESULT hr;
1637     DWORD i;
1638 
1639     ok_(__FILE__,line)(index_size == mesh_index_size,
1640         "Expected index size %u, got %u\n", index_size, mesh_index_size);
1641     ok_(__FILE__,line)(num_indices == mesh_num_indices,
1642         "Expected %u indices, got %u\n", num_indices, mesh_num_indices);
1643 
1644     hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
1645     ok_(__FILE__,line)(hr == D3D_OK, "LockIndexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1646     if (FAILED(hr))
1647         return;
1648 
1649     if (mesh_index_size == index_size) {
1650         for (i = 0; i < min(num_indices, mesh_num_indices); i++)
1651         {
1652             if (index_size == 4)
1653                 ok_(__FILE__,line)(*(DWORD*)indices == *(DWORD*)mesh_indices,
1654                     "Index[%u]: expected %u, got %u\n", i, *(DWORD*)indices, *(DWORD*)mesh_indices);
1655             else
1656                 ok_(__FILE__,line)(*(WORD*)indices == *(WORD*)mesh_indices,
1657                     "Index[%u]: expected %u, got %u\n", i, *(WORD*)indices, *(WORD*)mesh_indices);
1658             indices = (BYTE*)indices + index_size;
1659             mesh_indices = (BYTE*)mesh_indices + index_size;
1660         }
1661     }
1662     mesh->lpVtbl->UnlockIndexBuffer(mesh);
1663 }
1664 
1665 #define check_matrix(got, expected) check_matrix_(__LINE__, got, expected)
check_matrix_(int line,const D3DXMATRIX * got,const D3DXMATRIX * expected)1666 static void check_matrix_(int line, const D3DXMATRIX *got, const D3DXMATRIX *expected)
1667 {
1668     int i, j;
1669     for (i = 0; i < 4; i++) {
1670         for (j = 0; j < 4; j++) {
1671             ok_(__FILE__,line)(compare(U(*expected).m[i][j], U(*got).m[i][j]),
1672                     "matrix[%u][%u]: expected %g, got %g\n",
1673                     i, j, U(*expected).m[i][j], U(*got).m[i][j]);
1674         }
1675     }
1676 }
1677 
check_colorvalue_(int line,const char * prefix,const D3DCOLORVALUE got,const D3DCOLORVALUE expected)1678 static void check_colorvalue_(int line, const char *prefix, const D3DCOLORVALUE got, const D3DCOLORVALUE expected)
1679 {
1680     ok_(__FILE__,line)(expected.r == got.r && expected.g == got.g && expected.b == got.b && expected.a == got.a,
1681             "%sExpected (%g, %g, %g, %g), got (%g, %g, %g, %g)\n", prefix,
1682             expected.r, expected.g, expected.b, expected.a, got.r, got.g, got.b, got.a);
1683 }
1684 
1685 #define check_materials(got, got_count, expected, expected_count) \
1686     check_materials_(__LINE__, got, got_count, expected, expected_count)
check_materials_(int line,const D3DXMATERIAL * got,DWORD got_count,const D3DXMATERIAL * expected,DWORD expected_count)1687 static void check_materials_(int line, const D3DXMATERIAL *got, DWORD got_count, const D3DXMATERIAL *expected, DWORD expected_count)
1688 {
1689     int i;
1690     ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
1691     if (!expected) {
1692         ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
1693         return;
1694     }
1695     for (i = 0; i < min(expected_count, got_count); i++)
1696     {
1697         if (!expected[i].pTextureFilename)
1698             ok_(__FILE__,line)(got[i].pTextureFilename == NULL,
1699                     "Expected NULL pTextureFilename, got %p\n", got[i].pTextureFilename);
1700         else
1701             ok_(__FILE__,line)(!strcmp(expected[i].pTextureFilename, got[i].pTextureFilename),
1702                     "Expected '%s' for pTextureFilename, got '%s'\n", expected[i].pTextureFilename, got[i].pTextureFilename);
1703         check_colorvalue_(line, "Diffuse: ", got[i].MatD3D.Diffuse, expected[i].MatD3D.Diffuse);
1704         check_colorvalue_(line, "Ambient: ", got[i].MatD3D.Ambient, expected[i].MatD3D.Ambient);
1705         check_colorvalue_(line, "Specular: ", got[i].MatD3D.Specular, expected[i].MatD3D.Specular);
1706         check_colorvalue_(line, "Emissive: ", got[i].MatD3D.Emissive, expected[i].MatD3D.Emissive);
1707         ok_(__FILE__,line)(expected[i].MatD3D.Power == got[i].MatD3D.Power,
1708                 "Power: Expected %g, got %g\n", expected[i].MatD3D.Power, got[i].MatD3D.Power);
1709     }
1710 }
1711 
1712 #define check_generated_adjacency(mesh, got, epsilon) check_generated_adjacency_(__LINE__, mesh, got, epsilon)
check_generated_adjacency_(int line,ID3DXMesh * mesh,const DWORD * got,FLOAT epsilon)1713 static void check_generated_adjacency_(int line, ID3DXMesh *mesh, const DWORD *got, FLOAT epsilon)
1714 {
1715     DWORD *expected;
1716     DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
1717     HRESULT hr;
1718 
1719     expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
1720     if (!expected) {
1721         skip_(__FILE__, line)("Out of memory\n");
1722         return;
1723     }
1724     hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
1725     ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1726     if (SUCCEEDED(hr))
1727     {
1728         int i;
1729         for (i = 0; i < num_faces; i++)
1730         {
1731             ok_(__FILE__, line)(expected[i * 3] == got[i * 3] &&
1732                     expected[i * 3 + 1] == got[i * 3 + 1] &&
1733                     expected[i * 3 + 2] == got[i * 3 + 2],
1734                     "Face %u adjacencies: Expected (%u, %u, %u), got (%u, %u, %u)\n", i,
1735                     expected[i * 3], expected[i * 3 + 1], expected[i * 3 + 2],
1736                     got[i * 3], got[i * 3 + 1], got[i * 3 + 2]);
1737         }
1738     }
1739     HeapFree(GetProcessHeap(), 0, expected);
1740 }
1741 
1742 #define check_generated_effects(materials, num_materials, effects) \
1743     check_generated_effects_(__LINE__, materials, num_materials, effects)
check_generated_effects_(int line,const D3DXMATERIAL * materials,DWORD num_materials,const D3DXEFFECTINSTANCE * effects)1744 static void check_generated_effects_(int line, const D3DXMATERIAL *materials, DWORD num_materials, const D3DXEFFECTINSTANCE *effects)
1745 {
1746     int i;
1747     static const struct {
1748         const char *name;
1749         DWORD name_size;
1750         DWORD num_bytes;
1751         DWORD value_offset;
1752     } params[] = {
1753 #define EFFECT_TABLE_ENTRY(str, field) \
1754     {str, sizeof(str), sizeof(materials->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
1755         EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
1756         EFFECT_TABLE_ENTRY("Power", Power),
1757         EFFECT_TABLE_ENTRY("Specular", Specular),
1758         EFFECT_TABLE_ENTRY("Emissive", Emissive),
1759         EFFECT_TABLE_ENTRY("Ambient", Ambient),
1760 #undef EFFECT_TABLE_ENTRY
1761     };
1762 
1763     if (!num_materials) {
1764         ok_(__FILE__, line)(effects == NULL, "Expected NULL effects, got %p\n", effects);
1765         return;
1766     }
1767     for (i = 0; i < num_materials; i++)
1768     {
1769         int j;
1770         DWORD expected_num_defaults = ARRAY_SIZE(params) + (materials[i].pTextureFilename ? 1 : 0);
1771 
1772         ok_(__FILE__,line)(expected_num_defaults == effects[i].NumDefaults,
1773                 "effect[%u] NumDefaults: Expected %u, got %u\n", i,
1774                 expected_num_defaults, effects[i].NumDefaults);
1775         for (j = 0; j < min(ARRAY_SIZE(params), effects[i].NumDefaults); j++)
1776         {
1777             int k;
1778             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1779             ok_(__FILE__,line)(!strcmp(params[j].name, got_param->pParamName),
1780                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1781                params[j].name, got_param->pParamName);
1782             ok_(__FILE__,line)(D3DXEDT_FLOATS == got_param->Type,
1783                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1784                D3DXEDT_FLOATS, got_param->Type);
1785             ok_(__FILE__,line)(params[j].num_bytes == got_param->NumBytes,
1786                "effect[%u].pDefaults[%u].NumBytes: Expected %u, got %u\n", i, j,
1787                params[j].num_bytes, got_param->NumBytes);
1788             for (k = 0; k < min(params[j].num_bytes, got_param->NumBytes) / 4; k++)
1789             {
1790                 FLOAT expected = ((FLOAT*)((BYTE*)&materials[i] + params[j].value_offset))[k];
1791                 FLOAT got = ((FLOAT*)got_param->pValue)[k];
1792                 ok_(__FILE__,line)(compare(expected, got),
1793                    "effect[%u].pDefaults[%u] float value %u: Expected %g, got %g\n", i, j, k, expected, got);
1794             }
1795         }
1796         if (effects[i].NumDefaults > ARRAY_SIZE(params)) {
1797             D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1798             static const char *expected_name = "Texture0@Name";
1799 
1800             ok_(__FILE__,line)(!strcmp(expected_name, got_param->pParamName),
1801                "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1802                expected_name, got_param->pParamName);
1803             ok_(__FILE__,line)(D3DXEDT_STRING == got_param->Type,
1804                "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1805                D3DXEDT_STRING, got_param->Type);
1806             if (materials[i].pTextureFilename) {
1807                 ok_(__FILE__,line)(strlen(materials[i].pTextureFilename) + 1 == got_param->NumBytes,
1808                    "effect[%u] texture filename length: Expected %u, got %u\n", i,
1809                    (DWORD)strlen(materials[i].pTextureFilename) + 1, got_param->NumBytes);
1810                 ok_(__FILE__,line)(!strcmp(materials[i].pTextureFilename, got_param->pValue),
1811                    "effect[%u] texture filename: Expected '%s', got '%s'\n", i,
1812                    materials[i].pTextureFilename, (char*)got_param->pValue);
1813             }
1814         }
1815     }
1816 }
1817 
strdupA(const char * p)1818 static char *strdupA(const char *p)
1819 {
1820     char *ret;
1821     if (!p) return NULL;
1822     ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
1823     if (ret) strcpy(ret, p);
1824     return ret;
1825 }
1826 
ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy * iface,LPD3DXFRAME frame)1827 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
1828 {
1829     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
1830     if (frame) {
1831         HeapFree(GetProcessHeap(), 0, frame->Name);
1832         HeapFree(GetProcessHeap(), 0, frame);
1833     }
1834     return D3D_OK;
1835 }
1836 
ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy * iface,const char * name,D3DXFRAME ** new_frame)1837 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface,
1838         const char *name, D3DXFRAME **new_frame)
1839 {
1840     D3DXFRAME *frame;
1841 
1842     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
1843     frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
1844     if (!frame)
1845         return E_OUTOFMEMORY;
1846     if (name) {
1847         frame->Name = strdupA(name);
1848         if (!frame->Name) {
1849             HeapFree(GetProcessHeap(), 0, frame);
1850             return E_OUTOFMEMORY;
1851         }
1852     }
1853     *new_frame = frame;
1854     return D3D_OK;
1855 }
1856 
destroy_mesh_container(LPD3DXMESHCONTAINER mesh_container)1857 static HRESULT destroy_mesh_container(LPD3DXMESHCONTAINER mesh_container)
1858 {
1859     int i;
1860 
1861     if (!mesh_container)
1862         return D3D_OK;
1863     HeapFree(GetProcessHeap(), 0, mesh_container->Name);
1864     if (U(mesh_container->MeshData).pMesh)
1865         IUnknown_Release(U(mesh_container->MeshData).pMesh);
1866     if (mesh_container->pMaterials) {
1867         for (i = 0; i < mesh_container->NumMaterials; i++)
1868             HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials[i].pTextureFilename);
1869         HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials);
1870     }
1871     if (mesh_container->pEffects) {
1872         for (i = 0; i < mesh_container->NumMaterials; i++) {
1873             HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pEffectFilename);
1874             if (mesh_container->pEffects[i].pDefaults) {
1875                 int j;
1876                 for (j = 0; j < mesh_container->pEffects[i].NumDefaults; j++) {
1877                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pParamName);
1878                     HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pValue);
1879                 }
1880                 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults);
1881             }
1882         }
1883         HeapFree(GetProcessHeap(), 0, mesh_container->pEffects);
1884     }
1885     HeapFree(GetProcessHeap(), 0, mesh_container->pAdjacency);
1886     if (mesh_container->pSkinInfo)
1887         IUnknown_Release(mesh_container->pSkinInfo);
1888     HeapFree(GetProcessHeap(), 0, mesh_container);
1889     return D3D_OK;
1890 }
1891 
ID3DXAllocateHierarchyImpl_DestroyMeshContainer(ID3DXAllocateHierarchy * iface,LPD3DXMESHCONTAINER mesh_container)1892 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyMeshContainer(ID3DXAllocateHierarchy *iface, LPD3DXMESHCONTAINER mesh_container)
1893 {
1894     TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyMeshContainer(%p, %p)\n", iface, mesh_container);
1895     return destroy_mesh_container(mesh_container);
1896 }
1897 
ID3DXAllocateHierarchyImpl_CreateMeshContainer(ID3DXAllocateHierarchy * iface,const char * name,const D3DXMESHDATA * mesh_data,const D3DXMATERIAL * materials,const D3DXEFFECTINSTANCE * effects,DWORD num_materials,const DWORD * adjacency,ID3DXSkinInfo * skin_info,D3DXMESHCONTAINER ** new_mesh_container)1898 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateMeshContainer(ID3DXAllocateHierarchy *iface,
1899         const char *name, const D3DXMESHDATA *mesh_data, const D3DXMATERIAL *materials,
1900         const D3DXEFFECTINSTANCE *effects, DWORD num_materials, const DWORD *adjacency,
1901         ID3DXSkinInfo *skin_info, D3DXMESHCONTAINER **new_mesh_container)
1902 {
1903     LPD3DXMESHCONTAINER mesh_container = NULL;
1904     int i;
1905 
1906     TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateMeshContainer(%p, '%s', %u, %p, %p, %p, %d, %p, %p, %p)\n",
1907             iface, name, mesh_data->Type, U(*mesh_data).pMesh, materials, effects,
1908             num_materials, adjacency, skin_info, *new_mesh_container);
1909 
1910     mesh_container = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mesh_container));
1911     if (!mesh_container)
1912         return E_OUTOFMEMORY;
1913 
1914     if (name) {
1915         mesh_container->Name = strdupA(name);
1916         if (!mesh_container->Name)
1917             goto error;
1918     }
1919 
1920     mesh_container->NumMaterials = num_materials;
1921     if (num_materials) {
1922         mesh_container->pMaterials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*materials));
1923         if (!mesh_container->pMaterials)
1924             goto error;
1925 
1926         memcpy(mesh_container->pMaterials, materials, num_materials * sizeof(*materials));
1927         for (i = 0; i < num_materials; i++)
1928             mesh_container->pMaterials[i].pTextureFilename = NULL;
1929         for (i = 0; i < num_materials; i++) {
1930             if (materials[i].pTextureFilename) {
1931                 mesh_container->pMaterials[i].pTextureFilename = strdupA(materials[i].pTextureFilename);
1932                 if (!mesh_container->pMaterials[i].pTextureFilename)
1933                     goto error;
1934             }
1935         }
1936 
1937         mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
1938         if (!mesh_container->pEffects)
1939             goto error;
1940         for (i = 0; i < num_materials; i++) {
1941             int j;
1942             const D3DXEFFECTINSTANCE *effect_src = &effects[i];
1943             D3DXEFFECTINSTANCE *effect_dest = &mesh_container->pEffects[i];
1944 
1945             if (effect_src->pEffectFilename) {
1946                 effect_dest->pEffectFilename = strdupA(effect_src->pEffectFilename);
1947                 if (!effect_dest->pEffectFilename)
1948                     goto error;
1949             }
1950             effect_dest->pDefaults = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1951                     effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
1952             if (!effect_dest->pDefaults)
1953                 goto error;
1954             effect_dest->NumDefaults = effect_src->NumDefaults;
1955             for (j = 0; j < effect_src->NumDefaults; j++) {
1956                 const D3DXEFFECTDEFAULT *default_src = &effect_src->pDefaults[j];
1957                 D3DXEFFECTDEFAULT *default_dest = &effect_dest->pDefaults[j];
1958 
1959                 if (default_src->pParamName) {
1960                     default_dest->pParamName = strdupA(default_src->pParamName);
1961                     if (!default_dest->pParamName)
1962                         goto error;
1963                 }
1964                 default_dest->NumBytes = default_src->NumBytes;
1965                 default_dest->Type = default_src->Type;
1966                 default_dest->pValue = HeapAlloc(GetProcessHeap(), 0, default_src->NumBytes);
1967                 memcpy(default_dest->pValue, default_src->pValue, default_src->NumBytes);
1968             }
1969         }
1970     }
1971 
1972     ok(adjacency != NULL, "Expected non-NULL adjacency, got NULL\n");
1973     if (adjacency) {
1974         if (mesh_data->Type == D3DXMESHTYPE_MESH || mesh_data->Type == D3DXMESHTYPE_PMESH) {
1975             ID3DXBaseMesh *basemesh = (ID3DXBaseMesh*)U(*mesh_data).pMesh;
1976             DWORD num_faces = basemesh->lpVtbl->GetNumFaces(basemesh);
1977             size_t size = num_faces * sizeof(DWORD) * 3;
1978             mesh_container->pAdjacency = HeapAlloc(GetProcessHeap(), 0, size);
1979             if (!mesh_container->pAdjacency)
1980                 goto error;
1981             memcpy(mesh_container->pAdjacency, adjacency, size);
1982         } else {
1983             ok(mesh_data->Type == D3DXMESHTYPE_PATCHMESH, "Unknown mesh type %u\n", mesh_data->Type);
1984             if (mesh_data->Type == D3DXMESHTYPE_PATCHMESH)
1985                 trace("FIXME: copying adjacency data for patch mesh not implemented\n");
1986         }
1987     }
1988 
1989     memcpy(&mesh_container->MeshData, mesh_data, sizeof(*mesh_data));
1990     if (U(*mesh_data).pMesh)
1991         IUnknown_AddRef(U(*mesh_data).pMesh);
1992     if (skin_info) {
1993         mesh_container->pSkinInfo = skin_info;
1994         skin_info->lpVtbl->AddRef(skin_info);
1995     }
1996     *new_mesh_container = mesh_container;
1997 
1998     return S_OK;
1999 error:
2000     destroy_mesh_container(mesh_container);
2001     return E_OUTOFMEMORY;
2002 }
2003 
2004 static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
2005     ID3DXAllocateHierarchyImpl_CreateFrame,
2006     ID3DXAllocateHierarchyImpl_CreateMeshContainer,
2007     ID3DXAllocateHierarchyImpl_DestroyFrame,
2008     ID3DXAllocateHierarchyImpl_DestroyMeshContainer,
2009 };
2010 static ID3DXAllocateHierarchy alloc_hier = { &ID3DXAllocateHierarchyImpl_Vtbl };
2011 
2012 #define test_LoadMeshFromX(device, xfile_str, vertex_array, fvf, index_array, materials_array, check_adjacency) \
2013     test_LoadMeshFromX_(__LINE__, device, xfile_str, sizeof(xfile_str) - 1, vertex_array, ARRAY_SIZE(vertex_array), fvf, \
2014             index_array, ARRAY_SIZE(index_array), sizeof(*index_array), materials_array, ARRAY_SIZE(materials_array), \
2015             check_adjacency);
test_LoadMeshFromX_(int line,IDirect3DDevice9 * device,const char * xfile_str,size_t xfile_strlen,const void * vertices,DWORD num_vertices,DWORD fvf,const void * indices,DWORD num_indices,size_t index_size,const D3DXMATERIAL * expected_materials,DWORD expected_num_materials,BOOL check_adjacency)2016 static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char *xfile_str, size_t xfile_strlen,
2017         const void *vertices, DWORD num_vertices, DWORD fvf, const void *indices, DWORD num_indices, size_t index_size,
2018         const D3DXMATERIAL *expected_materials, DWORD expected_num_materials, BOOL check_adjacency)
2019 {
2020     HRESULT hr;
2021     ID3DXBuffer *materials = NULL;
2022     ID3DXBuffer *effects = NULL;
2023     ID3DXBuffer *adjacency = NULL;
2024     ID3DXMesh *mesh = NULL;
2025     DWORD num_materials = 0;
2026 
2027     /* Adjacency is not checked when the X file contains multiple meshes,
2028      * since calling GenerateAdjacency on the merged mesh is not equivalent
2029      * to calling GenerateAdjacency on the individual meshes and then merging
2030      * the adjacency data. */
2031     hr = D3DXLoadMeshFromXInMemory(xfile_str, xfile_strlen, D3DXMESH_MANAGED, device,
2032             check_adjacency ? &adjacency : NULL, &materials, &effects, &num_materials, &mesh);
2033     ok_(__FILE__,line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2034     if (SUCCEEDED(hr)) {
2035         D3DXMATERIAL *materials_ptr = materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL;
2036         D3DXEFFECTINSTANCE *effects_ptr = effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL;
2037         DWORD *adjacency_ptr = check_adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL;
2038 
2039         check_vertex_buffer_(line, mesh, vertices, num_vertices, fvf);
2040         check_index_buffer_(line, mesh, indices, num_indices, index_size);
2041         check_materials_(line, materials_ptr, num_materials, expected_materials, expected_num_materials);
2042         check_generated_effects_(line, materials_ptr, num_materials, effects_ptr);
2043         if (check_adjacency)
2044             check_generated_adjacency_(line, mesh, adjacency_ptr, 0.0f);
2045 
2046         if (materials) ID3DXBuffer_Release(materials);
2047         if (effects) ID3DXBuffer_Release(effects);
2048         if (adjacency) ID3DXBuffer_Release(adjacency);
2049         IUnknown_Release(mesh);
2050     }
2051 }
2052 
D3DXLoadMeshTest(void)2053 static void D3DXLoadMeshTest(void)
2054 {
2055     static const char empty_xfile[] = "xof 0303txt 0032";
2056     /*________________________*/
2057     static const char simple_xfile[] =
2058         "xof 0303txt 0032"
2059         "Mesh {"
2060             "3;"
2061             "0.0; 0.0; 0.0;,"
2062             "0.0; 1.0; 0.0;,"
2063             "1.0; 1.0; 0.0;;"
2064             "1;"
2065             "3; 0, 1, 2;;"
2066         "}";
2067     static const WORD simple_index_buffer[] = {0, 1, 2};
2068     static const D3DXVECTOR3 simple_vertex_buffer[] = {
2069         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}
2070     };
2071     const DWORD simple_fvf = D3DFVF_XYZ;
2072     static const char framed_xfile[] =
2073         "xof 0303txt 0032"
2074         "Frame {"
2075             "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;; }"
2076             "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */
2077               "1.0, 0.0, 0.0, 0.0,"
2078               "0.0, 1.0, 0.0, 0.0,"
2079               "0.0, 0.0, 1.0, 0.0,"
2080               "0.0, 0.0, 2.0, 1.0;;"
2081             "}"
2082             "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;; }"
2083             "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */
2084               "1.0, 0.0, 0.0, 0.0,"
2085               "0.0, 1.0, 0.0, 0.0,"
2086               "0.0, 0.0, 1.0, 0.0,"
2087               "0.0, 0.0, 3.0, 1.0;;"
2088             "}"
2089             "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;; }"
2090         "}";
2091     static const WORD framed_index_buffer[] = { 0, 1, 2 };
2092     static const D3DXVECTOR3 framed_vertex_buffers[3][3] = {
2093         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}},
2094         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}},
2095         {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {3.0, 1.0, 0.0}},
2096     };
2097     static const WORD merged_index_buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
2098     /* frame transforms accumulates for D3DXLoadMeshFromX */
2099     static const D3DXVECTOR3 merged_vertex_buffer[] = {
2100         {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0},
2101         {0.0, 0.0, 2.0}, {0.0, 1.0, 2.0}, {2.0, 1.0, 2.0},
2102         {0.0, 0.0, 5.0}, {0.0, 1.0, 5.0}, {3.0, 1.0, 5.0},
2103     };
2104     const DWORD framed_fvf = D3DFVF_XYZ;
2105     /*________________________*/
2106     static const char box_xfile[] =
2107         "xof 0303txt 0032"
2108         "Mesh {"
2109             "8;" /* DWORD nVertices; */
2110             /* array Vector vertices[nVertices]; */
2111             "0.0; 0.0; 0.0;,"
2112             "0.0; 0.0; 1.0;,"
2113             "0.0; 1.0; 0.0;,"
2114             "0.0; 1.0; 1.0;,"
2115             "1.0; 0.0; 0.0;,"
2116             "1.0; 0.0; 1.0;,"
2117             "1.0; 1.0; 0.0;,"
2118             "1.0; 1.0; 1.0;;"
2119             "6;" /* DWORD nFaces; */
2120             /* array MeshFace faces[nFaces]; */
2121             "4; 0, 1, 3, 2;," /* (left side) */
2122             "4; 2, 3, 7, 6;," /* (top side) */
2123             "4; 6, 7, 5, 4;," /* (right side) */
2124             "4; 1, 0, 4, 5;," /* (bottom side) */
2125             "4; 1, 5, 7, 3;," /* (back side) */
2126             "4; 0, 2, 6, 4;;" /* (front side) */
2127             "MeshNormals {"
2128               "6;" /* DWORD nNormals; */
2129               /* array Vector normals[nNormals]; */
2130               "-1.0; 0.0; 0.0;,"
2131               "0.0; 1.0; 0.0;,"
2132               "1.0; 0.0; 0.0;,"
2133               "0.0; -1.0; 0.0;,"
2134               "0.0; 0.0; 1.0;,"
2135               "0.0; 0.0; -1.0;;"
2136               "6;" /* DWORD nFaceNormals; */
2137               /* array MeshFace faceNormals[nFaceNormals]; */
2138               "4; 0, 0, 0, 0;,"
2139               "4; 1, 1, 1, 1;,"
2140               "4; 2, 2, 2, 2;,"
2141               "4; 3, 3, 3, 3;,"
2142               "4; 4, 4, 4, 4;,"
2143               "4; 5, 5, 5, 5;;"
2144             "}"
2145             "MeshMaterialList materials {"
2146               "2;" /* DWORD nMaterials; */
2147               "6;" /* DWORD nFaceIndexes; */
2148               /* array DWORD faceIndexes[nFaceIndexes]; */
2149               "0, 0, 0, 1, 1, 1;;"
2150               "Material {"
2151                 /* ColorRGBA faceColor; */
2152                 "0.0; 0.0; 1.0; 1.0;;"
2153                 /* FLOAT power; */
2154                 "0.5;"
2155                 /* ColorRGB specularColor; */
2156                 "1.0; 1.0; 1.0;;"
2157                 /* ColorRGB emissiveColor; */
2158                 "0.0; 0.0; 0.0;;"
2159               "}"
2160               "Material {"
2161                 /* ColorRGBA faceColor; */
2162                 "1.0; 1.0; 1.0; 1.0;;"
2163                 /* FLOAT power; */
2164                 "1.0;"
2165                 /* ColorRGB specularColor; */
2166                 "1.0; 1.0; 1.0;;"
2167                 /* ColorRGB emissiveColor; */
2168                 "0.0; 0.0; 0.0;;"
2169                 "TextureFilename { \"texture.jpg\"; }"
2170               "}"
2171             "}"
2172             "MeshVertexColors {"
2173               "8;" /* DWORD nVertexColors; */
2174               /* array IndexedColor vertexColors[nVertexColors]; */
2175               "0; 0.0; 0.0; 0.0; 0.0;;"
2176               "1; 0.0; 0.0; 1.0; 0.1;;"
2177               "2; 0.0; 1.0; 0.0; 0.2;;"
2178               "3; 0.0; 1.0; 1.0; 0.3;;"
2179               "4; 1.0; 0.0; 0.0; 0.4;;"
2180               "5; 1.0; 0.0; 1.0; 0.5;;"
2181               "6; 1.0; 1.0; 0.0; 0.6;;"
2182               "7; 1.0; 1.0; 1.0; 0.7;;"
2183             "}"
2184             "MeshTextureCoords {"
2185               "8;" /* DWORD nTextureCoords; */
2186               /* array Coords2d textureCoords[nTextureCoords]; */
2187               "0.0; 1.0;,"
2188               "1.0; 1.0;,"
2189               "0.0; 0.0;,"
2190               "1.0; 0.0;,"
2191               "1.0; 1.0;,"
2192               "0.0; 1.0;,"
2193               "1.0; 0.0;,"
2194               "0.0; 0.0;;"
2195             "}"
2196           "}";
2197     static const WORD box_index_buffer[] = {
2198         0, 1, 3,
2199         0, 3, 2,
2200         8, 9, 7,
2201         8, 7, 6,
2202         10, 11, 5,
2203         10, 5, 4,
2204         12, 13, 14,
2205         12, 14, 15,
2206         16, 17, 18,
2207         16, 18, 19,
2208         20, 21, 22,
2209         20, 22, 23,
2210     };
2211     static const struct {
2212         D3DXVECTOR3 position;
2213         D3DXVECTOR3 normal;
2214         D3DCOLOR diffuse;
2215         D3DXVECTOR2 tex_coords;
2216     } box_vertex_buffer[] = {
2217         {{0.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, 0x00000000, {0.0, 1.0}},
2218         {{0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2219         {{0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2220         {{0.0, 1.0, 1.0}, {-1.0, 0.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2221         {{1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2222         {{1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2223         {{1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2224         {{1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2225         {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2226         {{0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2227         {{1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2228         {{1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2229         {{0.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2230         {{0.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x00000000, {0.0, 1.0}},
2231         {{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2232         {{1.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2233         {{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x1a0000ff, {1.0, 1.0}},
2234         {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x80ff00ff, {0.0, 1.0}},
2235         {{1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0xb3ffffff, {0.0, 0.0}},
2236         {{0.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0x4d00ffff, {1.0, 0.0}},
2237         {{0.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x00000000, {0.0, 1.0}},
2238         {{0.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x3300ff00, {0.0, 0.0}},
2239         {{1.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x99ffff00, {1.0, 0.0}},
2240         {{1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x66ff0000, {1.0, 1.0}},
2241     };
2242     static const D3DXMATERIAL box_materials[] = {
2243         {
2244             {
2245                 {0.0, 0.0, 1.0, 1.0}, /* Diffuse */
2246                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2247                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2248                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2249                 0.5, /* Power */
2250             },
2251             NULL, /* pTextureFilename */
2252         },
2253         {
2254             {
2255                 {1.0, 1.0, 1.0, 1.0}, /* Diffuse */
2256                 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2257                 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2258                 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2259                 1.0, /* Power */
2260             },
2261             (char *)"texture.jpg", /* pTextureFilename */
2262         },
2263     };
2264     static const char box_anim_xfile[] =
2265         "xof 0303txt 0032"
2266         "Mesh CubeMesh {"
2267         "8;" /* DWORD nVertices; */
2268         /* array Vector vertices[nVertices]; */
2269         "0.0; 0.0; 0.0;,"
2270         "0.0; 0.0; 1.0;,"
2271         "0.0; 1.0; 0.0;,"
2272         "0.0; 1.0; 1.0;,"
2273         "1.0; 0.0; 0.0;,"
2274         "1.0; 0.0; 1.0;,"
2275         "1.0; 1.0; 0.0;,"
2276         "1.0; 1.0; 1.0;;"
2277         "6;" /* DWORD nFaces; */
2278         /* array MeshFace faces[nFaces]; */
2279         "4; 0, 1, 3, 2;," /* left side */
2280         "4; 2, 3, 7, 6;," /* top side */
2281         "4; 6, 7, 5, 4;," /* right side */
2282         "4; 1, 0, 4, 5;," /* bottom side */
2283         "4; 1, 5, 7, 3;," /* back side */
2284         "4; 0, 2, 6, 4;;" /* front side */
2285         "MeshNormals {"
2286         "6;" /* DWORD nNormals; */
2287         /* array Vector normals[nNormals]; */
2288         "-1.0; 0.0; 0.0;,"
2289         "0.0; 1.0; 0.0;,"
2290         "1.0; 0.0; 0.0;,"
2291         "0.0; -1.0; 0.0;,"
2292         "0.0; 0.0; 1.0;,"
2293         "0.0; 0.0; -1.0;;"
2294         "6;" /* DWORD nFaceNormals; */
2295         /* array MeshFace faceNormals[nFaceNormals]; */
2296         "4; 0, 0, 0, 0;,"
2297         "4; 1, 1, 1, 1;,"
2298         "4; 2, 2, 2, 2;,"
2299         "4; 3, 3, 3, 3;,"
2300         "4; 4, 4, 4, 4;,"
2301         "4; 5, 5, 5, 5;;"
2302         "}"
2303         "MeshMaterialList materials {"
2304         "2;" /* DWORD nMaterials; */
2305         "6;" /* DWORD nFaceIndexes; */
2306         /* array DWORD faceIndexes[nFaceIndexes]; */
2307         "0, 0, 0, 1, 1, 1;;"
2308         "Material {"
2309         /* ColorRGBA faceColor; */
2310         "0.0; 0.0; 1.0; 1.0;;"
2311         /* FLOAT power; */
2312         "0.5;"
2313         /* ColorRGB specularColor; */
2314         "1.0; 1.0; 1.0;;"
2315         /* ColorRGB emissiveColor; */
2316         "0.0; 0.0; 0.0;;"
2317         "}"
2318         "Material {"
2319         /* ColorRGBA faceColor; */
2320         "1.0; 1.0; 1.0; 1.0;;"
2321         /* FLOAT power; */
2322         "1.0;"
2323         /* ColorRGB specularColor; */
2324         "1.0; 1.0; 1.0;;"
2325         /* ColorRGB emissiveColor; */
2326         "0.0; 0.0; 0.0;;"
2327         "TextureFilename { \"texture.jpg\"; }"
2328         "}"
2329         "}"
2330         "MeshVertexColors {"
2331         "8;" /* DWORD nVertexColors; */
2332         /* array IndexedColor vertexColors[nVertexColors]; */
2333         "0; 0.0; 0.0; 0.0; 0.0;;"
2334         "1; 0.0; 0.0; 1.0; 0.1;;"
2335         "2; 0.0; 1.0; 0.0; 0.2;;"
2336         "3; 0.0; 1.0; 1.0; 0.3;;"
2337         "4; 1.0; 0.0; 0.0; 0.4;;"
2338         "5; 1.0; 0.0; 1.0; 0.5;;"
2339         "6; 1.0; 1.0; 0.0; 0.6;;"
2340         "7; 1.0; 1.0; 1.0; 0.7;;"
2341         "}"
2342         "MeshTextureCoords {"
2343         "8;" /* DWORD nTextureCoords; */
2344         /* array Coords2d textureCoords[nTextureCoords]; */
2345         "0.0; 1.0;,"
2346         "1.0; 1.0;,"
2347         "0.0; 0.0;,"
2348         "1.0; 0.0;,"
2349         "1.0; 1.0;,"
2350         "0.0; 1.0;,"
2351         "1.0; 0.0;,"
2352         "0.0; 0.0;;"
2353         "}"
2354         "}"
2355         "Frame CubeFrame {"
2356         "FrameTransformMatrix {"
2357         /* Matrix4x4 frameMatrix; */
2358         "1.0, 0.0, 0.0, 0.0,"
2359         "0.0, 1.0, 0.0, 0.0,"
2360         "0.0, 0.0, 1.0, 0.0,"
2361         "0.0, 0.0, 0.0, 1.0;;"
2362         "}"
2363         "{CubeMesh}"
2364         "}"
2365         "AnimationSet AnimationSet0 {"
2366         "Animation Animation0 {"
2367         "{CubeFrame}"
2368         "AnimationKey {"
2369         "2;" /* DWORD keyType; */
2370         "9;" /* DWORD nKeys; */
2371         /* array TimedFloatKeys keys[nKeys]; */
2372         "10; 3; -100.0, 0.0, 0.0;;,"
2373         "20; 3; -75.0,  0.0, 0.0;;,"
2374         "30; 3; -50.0,  0.0, 0.0;;,"
2375         "40; 3; -25.5,  0.0, 0.0;;,"
2376         "50; 3; 0.0,    0.0, 0.0;;,"
2377         "60; 3; 25.5,   0.0, 0.0;;,"
2378         "70; 3; 50.0,   0.0, 0.0;;,"
2379         "80; 3; 75.5,   0.0, 0.0;;,"
2380         "90; 3; 100.0,  0.0, 0.0;;;"
2381         "}"
2382         "}"
2383         "}";
2384 
2385     const DWORD box_fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
2386     /*________________________*/
2387     static const D3DXMATERIAL default_materials[] = {
2388         {
2389             {
2390                 {0.5, 0.5, 0.5, 0.0}, /* Diffuse */
2391                 {0.0, 0.0, 0.0, 0.0}, /* Ambient */
2392                 {0.5, 0.5, 0.5, 0.0}, /* Specular */
2393                 {0.0, 0.0, 0.0, 0.0}, /* Emissive */
2394                 0.0, /* Power */
2395             },
2396             NULL, /* pTextureFilename */
2397         }
2398     };
2399     HRESULT hr;
2400     IDirect3DDevice9 *device = NULL;
2401     ID3DXMesh *mesh = NULL;
2402     D3DXFRAME *frame_hier = NULL;
2403     D3DXMATRIX transform;
2404     struct test_context *test_context;
2405     ID3DXAnimationController *controller;
2406 
2407     if (!(test_context = new_test_context()))
2408     {
2409         skip("Couldn't create test context\n");
2410         return;
2411     }
2412     device = test_context->device;
2413 
2414     hr = D3DXLoadMeshHierarchyFromXInMemory(NULL, sizeof(simple_xfile) - 1,
2415             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2416     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2417 
2418     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, 0,
2419             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2420     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2421 
2422     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2423             D3DXMESH_MANAGED, NULL, &alloc_hier, NULL, &frame_hier, NULL);
2424     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2425 
2426     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2427             D3DXMESH_MANAGED, device, NULL, NULL, &frame_hier, NULL);
2428     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2429 
2430     hr = D3DXLoadMeshHierarchyFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1,
2431             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2432     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2433 
2434     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2435             D3DXMESH_MANAGED, device, &alloc_hier, NULL, NULL, NULL);
2436     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2437 
2438     hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2439             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2440     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2441     if (SUCCEEDED(hr)) {
2442         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2443 
2444         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2445         D3DXMatrixIdentity(&transform);
2446         check_matrix(&frame_hier->TransformationMatrix, &transform);
2447 
2448         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2449         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2450            D3DXMESHTYPE_MESH, container->MeshData.Type);
2451         mesh = U(container->MeshData).pMesh;
2452         check_vertex_buffer(mesh, simple_vertex_buffer, ARRAY_SIZE(simple_vertex_buffer), simple_fvf);
2453         check_index_buffer(mesh, simple_index_buffer, ARRAY_SIZE(simple_index_buffer), sizeof(*simple_index_buffer));
2454         check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2455         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2456         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2457         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2458         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2459         frame_hier = NULL;
2460     }
2461 
2462     controller = (ID3DXAnimationController *)0xdeadbeef;
2463     hr = D3DXLoadMeshHierarchyFromXInMemory(box_anim_xfile, sizeof(box_anim_xfile) - 1,
2464             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2465     todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2466     if (SUCCEEDED(hr))
2467     {
2468         ok(controller != NULL, "Animation Controller NULL.\n");
2469 
2470         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2471         ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2472         if (controller)
2473             controller->lpVtbl->Release(controller);
2474 
2475         frame_hier = NULL;
2476     }
2477 
2478     controller = (ID3DXAnimationController *)0xdeadbeef;
2479     hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1,
2480             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2481     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2482     if (SUCCEEDED(hr))
2483     {
2484         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2485 
2486         ok(!controller, "Animation Controller returned.\n");
2487         ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2488         D3DXMatrixIdentity(&transform);
2489         check_matrix(&frame_hier->TransformationMatrix, &transform);
2490 
2491         ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2492         ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2493            D3DXMESHTYPE_MESH, container->MeshData.Type);
2494         mesh = U(container->MeshData).pMesh;
2495         check_vertex_buffer(mesh, box_vertex_buffer, ARRAY_SIZE(box_vertex_buffer), box_fvf);
2496         check_index_buffer(mesh, box_index_buffer, ARRAY_SIZE(box_index_buffer), sizeof(*box_index_buffer));
2497         check_materials(container->pMaterials, container->NumMaterials, box_materials, ARRAY_SIZE(box_materials));
2498         check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2499         check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2500         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2501         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2502         frame_hier = NULL;
2503     }
2504 
2505     hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1,
2506             D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2507     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2508     if (SUCCEEDED(hr)) {
2509         D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2510         int i;
2511 
2512         ok(!strcmp(frame_hier->Name, ""), "Expected '', got '%s'\n", frame_hier->Name);
2513         /* last frame transform replaces the first */
2514         D3DXMatrixIdentity(&transform);
2515         U(transform).m[3][2] = 3.0;
2516         check_matrix(&frame_hier->TransformationMatrix, &transform);
2517 
2518         for (i = 0; i < 3; i++) {
2519             ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2520             ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2521                D3DXMESHTYPE_MESH, container->MeshData.Type);
2522             mesh = U(container->MeshData).pMesh;
2523             check_vertex_buffer(mesh, framed_vertex_buffers[i], ARRAY_SIZE(framed_vertex_buffers[0]), framed_fvf);
2524             check_index_buffer(mesh, framed_index_buffer, ARRAY_SIZE(framed_index_buffer), sizeof(*framed_index_buffer));
2525             check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2526             check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2527             check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2528             container = container->pNextMeshContainer;
2529         }
2530         ok(container == NULL, "Expected NULL, got %p\n", container);
2531         hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2532         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2533         frame_hier = NULL;
2534     }
2535 
2536 
2537     hr = D3DXLoadMeshFromXInMemory(NULL, 0, D3DXMESH_MANAGED,
2538                                    device, NULL, NULL, NULL, NULL, &mesh);
2539     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2540 
2541     hr = D3DXLoadMeshFromXInMemory(NULL, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2542                                    device, NULL, NULL, NULL, NULL, &mesh);
2543     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2544 
2545     hr = D3DXLoadMeshFromXInMemory(simple_xfile, 0, D3DXMESH_MANAGED,
2546                                    device, NULL, NULL, NULL, NULL, &mesh);
2547     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2548 
2549     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2550                                    device, NULL, NULL, NULL, NULL, NULL);
2551     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2552 
2553     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2554                                    NULL, NULL, NULL, NULL, NULL, &mesh);
2555     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2556 
2557     hr = D3DXLoadMeshFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1, D3DXMESH_MANAGED,
2558                                    device, NULL, NULL, NULL, NULL, &mesh);
2559     ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2560 
2561     hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2562                                    device, NULL, NULL, NULL, NULL, &mesh);
2563     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2564     if (SUCCEEDED(hr))
2565         IUnknown_Release(mesh);
2566 
2567     test_LoadMeshFromX(device, simple_xfile, simple_vertex_buffer, simple_fvf, simple_index_buffer, default_materials, TRUE);
2568     test_LoadMeshFromX(device, box_xfile, box_vertex_buffer, box_fvf, box_index_buffer, box_materials, TRUE);
2569     test_LoadMeshFromX(device, framed_xfile, merged_vertex_buffer, framed_fvf, merged_index_buffer, default_materials, FALSE);
2570 
2571     free_test_context(test_context);
2572 }
2573 
compute_box(struct mesh * mesh,float width,float height,float depth)2574 static BOOL compute_box(struct mesh *mesh, float width, float height, float depth)
2575 {
2576     unsigned int i, face;
2577     static const D3DXVECTOR3 unit_box[] =
2578     {
2579         {-1.0f, -1.0f, -1.0f}, {-1.0f, -1.0f,  1.0f}, {-1.0f,  1.0f,  1.0f}, {-1.0f,  1.0f, -1.0f},
2580         {-1.0f,  1.0f, -1.0f}, {-1.0f,  1.0f,  1.0f}, { 1.0f,  1.0f,  1.0f}, { 1.0f,  1.0f, -1.0f},
2581         { 1.0f,  1.0f, -1.0f}, { 1.0f,  1.0f,  1.0f}, { 1.0f, -1.0f,  1.0f}, { 1.0f, -1.0f, -1.0f},
2582         {-1.0f, -1.0f,  1.0f}, {-1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f,  1.0f},
2583         {-1.0f, -1.0f,  1.0f}, { 1.0f, -1.0f,  1.0f}, { 1.0f,  1.0f,  1.0f}, {-1.0f,  1.0f,  1.0f},
2584         {-1.0f, -1.0f, -1.0f}, {-1.0f,  1.0f, -1.0f}, { 1.0f,  1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}
2585     };
2586     static const D3DXVECTOR3 normals[] =
2587     {
2588         {-1.0f,  0.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f,  0.0f},
2589         { 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, -1.0f}
2590     };
2591 
2592     if (!new_mesh(mesh, 24, 12))
2593     {
2594         return FALSE;
2595     }
2596 
2597     width /= 2.0f;
2598     height /= 2.0f;
2599     depth /= 2.0f;
2600 
2601     for (i = 0; i < 24; i++)
2602     {
2603         mesh->vertices[i].position.x = width * unit_box[i].x;
2604         mesh->vertices[i].position.y = height * unit_box[i].y;
2605         mesh->vertices[i].position.z = depth * unit_box[i].z;
2606         mesh->vertices[i].normal.x = normals[i / 4].x;
2607         mesh->vertices[i].normal.y = normals[i / 4].y;
2608         mesh->vertices[i].normal.z = normals[i / 4].z;
2609     }
2610 
2611     face = 0;
2612     for (i = 0; i < 12; i++)
2613     {
2614         mesh->faces[i][0] = face++;
2615         mesh->faces[i][1] = face++;
2616         mesh->faces[i][2] = (i % 2) ? face - 4 : face;
2617     }
2618 
2619     return TRUE;
2620 }
2621 
test_box(IDirect3DDevice9 * device,float width,float height,float depth)2622 static void test_box(IDirect3DDevice9 *device, float width, float height, float depth)
2623 {
2624     HRESULT hr;
2625     ID3DXMesh *box;
2626     struct mesh mesh;
2627     char name[256];
2628 
2629     hr = D3DXCreateBox(device, width, height, depth, &box, NULL);
2630     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2631     if (hr != D3D_OK)
2632     {
2633         skip("Couldn't create box\n");
2634         return;
2635     }
2636 
2637     if (!compute_box(&mesh, width, height, depth))
2638     {
2639         skip("Couldn't create mesh\n");
2640         box->lpVtbl->Release(box);
2641         return;
2642     }
2643 
2644     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2645 
2646     sprintf(name, "box (%g, %g, %g)", width, height, depth);
2647     compare_mesh(name, box, &mesh);
2648 
2649     free_mesh(&mesh);
2650 
2651     box->lpVtbl->Release(box);
2652 }
D3DXCreateBoxTest(void)2653 static void D3DXCreateBoxTest(void)
2654 {
2655     HRESULT hr;
2656     IDirect3DDevice9* device;
2657     ID3DXMesh* box;
2658     ID3DXBuffer* ppBuffer;
2659     DWORD *buffer;
2660     static const DWORD adjacency[36]=
2661         {6, 9, 1, 2, 10, 0,
2662          1, 9, 3, 4, 10, 2,
2663          3, 8, 5, 7, 11, 4,
2664          0, 11, 7, 5, 8, 6,
2665          7, 4, 9, 2, 0, 8,
2666          1, 3, 11, 5, 6, 10};
2667     unsigned int i;
2668     struct test_context *test_context;
2669 
2670     if (!(test_context = new_test_context()))
2671     {
2672         skip("Couldn't create test context\n");
2673         return;
2674     }
2675     device = test_context->device;
2676 
2677     hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
2678     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2679 
2680     hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
2681     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2682 
2683     hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
2684     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2685 
2686     hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
2687     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2688 
2689     hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
2690     ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2691 
2692     ppBuffer = NULL;
2693     hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
2694     ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2695 
2696     buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
2697     for(i=0; i<36; i++)
2698         ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
2699 
2700     box->lpVtbl->Release(box);
2701     ID3DXBuffer_Release(ppBuffer);
2702 
2703     test_box(device, 10.9f, 20.0f, 4.9f);
2704 
2705     free_test_context(test_context);
2706 }
2707 
compute_polygon(struct mesh * mesh,float length,unsigned int sides)2708 static BOOL compute_polygon(struct mesh *mesh, float length, unsigned int sides)
2709 {
2710     unsigned int i;
2711     float angle, scale;
2712 
2713     if (!new_mesh(mesh, sides + 1, sides))
2714         return FALSE;
2715 
2716     angle = D3DX_PI / sides;
2717     scale = 0.5f * length / sinf(angle);
2718     angle *= 2.0f;
2719 
2720     mesh->vertices[0].position.x = 0.0f;
2721     mesh->vertices[0].position.y = 0.0f;
2722     mesh->vertices[0].position.z = 0.0f;
2723     mesh->vertices[0].normal.x = 0.0f;
2724     mesh->vertices[0].normal.y = 0.0f;
2725     mesh->vertices[0].normal.z = 1.0f;
2726 
2727     for (i = 0; i < sides; ++i)
2728     {
2729         mesh->vertices[i + 1].position.x = cosf(angle * i) * scale;
2730         mesh->vertices[i + 1].position.y = sinf(angle * i) * scale;
2731         mesh->vertices[i + 1].position.z = 0.0f;
2732         mesh->vertices[i + 1].normal.x = 0.0f;
2733         mesh->vertices[i + 1].normal.y = 0.0f;
2734         mesh->vertices[i + 1].normal.z = 1.0f;
2735 
2736         mesh->faces[i][0] = 0;
2737         mesh->faces[i][1] = i + 1;
2738         mesh->faces[i][2] = i + 2;
2739     }
2740 
2741     mesh->faces[sides - 1][2] = 1;
2742 
2743     return TRUE;
2744 }
2745 
test_polygon(IDirect3DDevice9 * device,float length,unsigned int sides)2746 static void test_polygon(IDirect3DDevice9 *device, float length, unsigned int sides)
2747 {
2748     HRESULT hr;
2749     ID3DXMesh *polygon;
2750     struct mesh mesh;
2751     char name[64];
2752 
2753     hr = D3DXCreatePolygon(device, length, sides, &polygon, NULL);
2754     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2755     if (hr != D3D_OK)
2756     {
2757         skip("Couldn't create polygon\n");
2758         return;
2759     }
2760 
2761     if (!compute_polygon(&mesh, length, sides))
2762     {
2763         skip("Couldn't create mesh\n");
2764         polygon->lpVtbl->Release(polygon);
2765         return;
2766     }
2767 
2768     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2769 
2770     sprintf(name, "polygon (%g, %u)", length, sides);
2771     compare_mesh(name, polygon, &mesh);
2772 
2773     free_mesh(&mesh);
2774 
2775     polygon->lpVtbl->Release(polygon);
2776 }
2777 
D3DXCreatePolygonTest(void)2778 static void D3DXCreatePolygonTest(void)
2779 {
2780     HRESULT hr;
2781     IDirect3DDevice9 *device;
2782     ID3DXMesh *polygon;
2783     ID3DXBuffer *adjacency;
2784     DWORD (*buffer)[3], buffer_size;
2785     unsigned int i;
2786     struct test_context *test_context;
2787 
2788     if (!(test_context = new_test_context()))
2789     {
2790         skip("Couldn't create test context\n");
2791         return;
2792     }
2793     device = test_context->device;
2794 
2795     hr = D3DXCreatePolygon(device, 2.0f, 11, NULL, &adjacency);
2796     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2797 
2798     hr = D3DXCreatePolygon(NULL, 2.0f, 11, &polygon, &adjacency);
2799     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2800 
2801     hr = D3DXCreatePolygon(device, -2.0f, 11, &polygon, &adjacency);
2802     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2803 
2804     polygon = (void *)0xdeadbeef;
2805     adjacency = (void *)0xdeadbeef;
2806     hr = D3DXCreatePolygon(device, 2.0f, 0, &polygon, &adjacency);
2807     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2808     ok(polygon == (void *)0xdeadbeef, "Polygon was changed to %p\n", polygon);
2809     ok(adjacency == (void *)0xdeadbeef, "Adjacency was changed to %p\n", adjacency);
2810 
2811     hr = D3DXCreatePolygon(device, 2.0f, 2, &polygon, &adjacency);
2812     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2813 
2814     adjacency = NULL;
2815     hr = D3DXCreatePolygon(device, 3.0f, 11, &polygon, &adjacency);
2816     ok(hr == D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2817 
2818     buffer_size = ID3DXBuffer_GetBufferSize(adjacency);
2819     ok(buffer_size == 33 * sizeof(DWORD), "Wrong adjacency buffer size %u\n", buffer_size);
2820 
2821     buffer = ID3DXBuffer_GetBufferPointer(adjacency);
2822     for (i = 0; i < 11; ++i)
2823     {
2824         ok(buffer[i][0] == (i + 10) % 11, "Wrong adjacency[%d][0] = %u\n", i, buffer[i][0]);
2825         ok(buffer[i][1] == ~0U, "Wrong adjacency[%d][1] = %u\n", i, buffer[i][1]);
2826         ok(buffer[i][2] == (i + 1) % 11, "Wrong adjacency[%d][2] = %u\n", i, buffer[i][2]);
2827     }
2828 
2829     polygon->lpVtbl->Release(polygon);
2830     ID3DXBuffer_Release(adjacency);
2831 
2832     test_polygon(device, 2.0f, 3);
2833     test_polygon(device, 10.0f, 3);
2834     test_polygon(device, 10.0f, 5);
2835     test_polygon(device, 10.0f, 10);
2836     test_polygon(device, 20.0f, 10);
2837     test_polygon(device, 20.0f, 32000);
2838 
2839     free_test_context(test_context);
2840 }
2841 
2842 struct sincos_table
2843 {
2844     float *sin;
2845     float *cos;
2846 };
2847 
free_sincos_table(struct sincos_table * sincos_table)2848 static void free_sincos_table(struct sincos_table *sincos_table)
2849 {
2850     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
2851     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2852 }
2853 
2854 /* pre compute sine and cosine tables; caller must free */
compute_sincos_table(struct sincos_table * sincos_table,float angle_start,float angle_step,int n)2855 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
2856 {
2857     float angle;
2858     int i;
2859 
2860     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2861     if (!sincos_table->sin)
2862     {
2863         return FALSE;
2864     }
2865     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2866     if (!sincos_table->cos)
2867     {
2868         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2869         return FALSE;
2870     }
2871 
2872     angle = angle_start;
2873     for (i = 0; i < n; i++)
2874     {
2875         sincos_table->sin[i] = sin(angle);
2876         sincos_table->cos[i] = cos(angle);
2877         angle += angle_step;
2878     }
2879 
2880     return TRUE;
2881 }
2882 
vertex_index(UINT slices,int slice,int stack)2883 static WORD vertex_index(UINT slices, int slice, int stack)
2884 {
2885     return stack*slices+slice+1;
2886 }
2887 
2888 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
compute_sphere(struct mesh * mesh,FLOAT radius,UINT slices,UINT stacks)2889 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
2890 {
2891     float theta_step, theta_start;
2892     struct sincos_table theta;
2893     float phi_step, phi_start;
2894     struct sincos_table phi;
2895     DWORD number_of_vertices, number_of_faces;
2896     DWORD vertex, face;
2897     int slice, stack;
2898 
2899     /* theta = angle on xy plane wrt x axis */
2900     theta_step = D3DX_PI / stacks;
2901     theta_start = theta_step;
2902 
2903     /* phi = angle on xz plane wrt z axis */
2904     phi_step = -2 * D3DX_PI / slices;
2905     phi_start = D3DX_PI / 2;
2906 
2907     if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
2908     {
2909         return FALSE;
2910     }
2911     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
2912     {
2913         free_sincos_table(&theta);
2914         return FALSE;
2915     }
2916 
2917     number_of_vertices = 2 + slices * (stacks-1);
2918     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
2919 
2920     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2921     {
2922         free_sincos_table(&phi);
2923         free_sincos_table(&theta);
2924         return FALSE;
2925     }
2926 
2927     vertex = 0;
2928     face = 0;
2929 
2930     mesh->vertices[vertex].normal.x = 0.0f;
2931     mesh->vertices[vertex].normal.y = 0.0f;
2932     mesh->vertices[vertex].normal.z = 1.0f;
2933     mesh->vertices[vertex].position.x = 0.0f;
2934     mesh->vertices[vertex].position.y = 0.0f;
2935     mesh->vertices[vertex].position.z = radius;
2936     vertex++;
2937 
2938     for (stack = 0; stack < stacks - 1; stack++)
2939     {
2940         for (slice = 0; slice < slices; slice++)
2941         {
2942             mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
2943             mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
2944             mesh->vertices[vertex].normal.z = theta.cos[stack];
2945             mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
2946             mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
2947             mesh->vertices[vertex].position.z = radius * theta.cos[stack];
2948             vertex++;
2949 
2950             if (slice > 0)
2951             {
2952                 if (stack == 0)
2953                 {
2954                     /* top stack is triangle fan */
2955                     mesh->faces[face][0] = 0;
2956                     mesh->faces[face][1] = slice + 1;
2957                     mesh->faces[face][2] = slice;
2958                     face++;
2959                 }
2960                 else
2961                 {
2962                     /* stacks in between top and bottom are quad strips */
2963                     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2964                     mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2965                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2966                     face++;
2967 
2968                     mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2969                     mesh->faces[face][1] = vertex_index(slices, slice, stack);
2970                     mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2971                     face++;
2972                 }
2973             }
2974         }
2975 
2976         if (stack == 0)
2977         {
2978             mesh->faces[face][0] = 0;
2979             mesh->faces[face][1] = 1;
2980             mesh->faces[face][2] = slice;
2981             face++;
2982         }
2983         else
2984         {
2985             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2986             mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2987             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2988             face++;
2989 
2990             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2991             mesh->faces[face][1] = vertex_index(slices, 0, stack);
2992             mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2993             face++;
2994         }
2995     }
2996 
2997     mesh->vertices[vertex].position.x = 0.0f;
2998     mesh->vertices[vertex].position.y = 0.0f;
2999     mesh->vertices[vertex].position.z = -radius;
3000     mesh->vertices[vertex].normal.x = 0.0f;
3001     mesh->vertices[vertex].normal.y = 0.0f;
3002     mesh->vertices[vertex].normal.z = -1.0f;
3003 
3004     /* bottom stack is triangle fan */
3005     for (slice = 1; slice < slices; slice++)
3006     {
3007         mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3008         mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
3009         mesh->faces[face][2] = vertex;
3010         face++;
3011     }
3012 
3013     mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3014     mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
3015     mesh->faces[face][2] = vertex;
3016 
3017     free_sincos_table(&phi);
3018     free_sincos_table(&theta);
3019 
3020     return TRUE;
3021 }
3022 
test_sphere(IDirect3DDevice9 * device,FLOAT radius,UINT slices,UINT stacks)3023 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
3024 {
3025     HRESULT hr;
3026     ID3DXMesh *sphere;
3027     struct mesh mesh;
3028     char name[256];
3029 
3030     hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
3031     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3032     if (hr != D3D_OK)
3033     {
3034         skip("Couldn't create sphere\n");
3035         return;
3036     }
3037 
3038     if (!compute_sphere(&mesh, radius, slices, stacks))
3039     {
3040         skip("Couldn't create mesh\n");
3041         sphere->lpVtbl->Release(sphere);
3042         return;
3043     }
3044 
3045     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3046 
3047     sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
3048     compare_mesh(name, sphere, &mesh);
3049 
3050     free_mesh(&mesh);
3051 
3052     sphere->lpVtbl->Release(sphere);
3053 }
3054 
D3DXCreateSphereTest(void)3055 static void D3DXCreateSphereTest(void)
3056 {
3057     HRESULT hr;
3058     IDirect3DDevice9* device;
3059     ID3DXMesh* sphere = NULL;
3060     struct test_context *test_context;
3061 
3062     hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
3063     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3064 
3065     hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
3066     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3067 
3068     hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
3069     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3070 
3071     hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
3072     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3073 
3074     if (!(test_context = new_test_context()))
3075     {
3076         skip("Couldn't create test context\n");
3077         return;
3078     }
3079     device = test_context->device;
3080 
3081     hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
3082     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3083 
3084     hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
3085     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3086 
3087     hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
3088     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3089 
3090     hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
3091     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3092 
3093     test_sphere(device, 0.0f, 2, 2);
3094     test_sphere(device, 1.0f, 2, 2);
3095     test_sphere(device, 1.0f, 3, 2);
3096     test_sphere(device, 1.0f, 4, 4);
3097     test_sphere(device, 1.0f, 3, 4);
3098     test_sphere(device, 5.0f, 6, 7);
3099     test_sphere(device, 10.0f, 11, 12);
3100 
3101     free_test_context(test_context);
3102 }
3103 
compute_cylinder(struct mesh * mesh,FLOAT radius1,FLOAT radius2,FLOAT length,UINT slices,UINT stacks)3104 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3105 {
3106     float theta_step, theta_start;
3107     struct sincos_table theta;
3108     FLOAT delta_radius, radius, radius_step;
3109     FLOAT z, z_step, z_normal;
3110     DWORD number_of_vertices, number_of_faces;
3111     DWORD vertex, face;
3112     int slice, stack;
3113 
3114     /* theta = angle on xy plane wrt x axis */
3115     theta_step = -2 * D3DX_PI / slices;
3116     theta_start = D3DX_PI / 2;
3117 
3118     if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
3119     {
3120         return FALSE;
3121     }
3122 
3123     number_of_vertices = 2 + (slices * (3 + stacks));
3124     number_of_faces = 2 * slices + stacks * (2 * slices);
3125 
3126     if (!new_mesh(mesh, number_of_vertices, number_of_faces))
3127     {
3128         free_sincos_table(&theta);
3129         return FALSE;
3130     }
3131 
3132     vertex = 0;
3133     face = 0;
3134 
3135     delta_radius = radius1 - radius2;
3136     radius = radius1;
3137     radius_step = delta_radius / stacks;
3138 
3139     z = -length / 2;
3140     z_step = length / stacks;
3141     z_normal = delta_radius / length;
3142     if (isnan(z_normal))
3143     {
3144         z_normal = 0.0f;
3145     }
3146 
3147     mesh->vertices[vertex].normal.x = 0.0f;
3148     mesh->vertices[vertex].normal.y = 0.0f;
3149     mesh->vertices[vertex].normal.z = -1.0f;
3150     mesh->vertices[vertex].position.x = 0.0f;
3151     mesh->vertices[vertex].position.y = 0.0f;
3152     mesh->vertices[vertex++].position.z = z;
3153 
3154     for (slice = 0; slice < slices; slice++, vertex++)
3155     {
3156         mesh->vertices[vertex].normal.x = 0.0f;
3157         mesh->vertices[vertex].normal.y = 0.0f;
3158         mesh->vertices[vertex].normal.z = -1.0f;
3159         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3160         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3161         mesh->vertices[vertex].position.z = z;
3162 
3163         if (slice > 0)
3164         {
3165             mesh->faces[face][0] = 0;
3166             mesh->faces[face][1] = slice;
3167             mesh->faces[face++][2] = slice + 1;
3168         }
3169     }
3170 
3171     mesh->faces[face][0] = 0;
3172     mesh->faces[face][1] = slice;
3173     mesh->faces[face++][2] = 1;
3174 
3175     for (stack = 1; stack <= stacks+1; stack++)
3176     {
3177         for (slice = 0; slice < slices; slice++, vertex++)
3178         {
3179             mesh->vertices[vertex].normal.x = theta.cos[slice];
3180             mesh->vertices[vertex].normal.y = theta.sin[slice];
3181             mesh->vertices[vertex].normal.z = z_normal;
3182             D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
3183             mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3184             mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3185             mesh->vertices[vertex].position.z = z;
3186 
3187             if (stack > 1 && slice > 0)
3188             {
3189                 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3190                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3191                 mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
3192 
3193                 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
3194                 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3195                 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3196             }
3197         }
3198 
3199         if (stack > 1)
3200         {
3201             mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3202             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3203             mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
3204 
3205             mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
3206             mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3207             mesh->faces[face++][2] = vertex_index(slices, 0, stack);
3208         }
3209 
3210         if (stack < stacks + 1)
3211         {
3212             z += z_step;
3213             radius -= radius_step;
3214         }
3215     }
3216 
3217     for (slice = 0; slice < slices; slice++, vertex++)
3218     {
3219         mesh->vertices[vertex].normal.x = 0.0f;
3220         mesh->vertices[vertex].normal.y = 0.0f;
3221         mesh->vertices[vertex].normal.z = 1.0f;
3222         mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3223         mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3224         mesh->vertices[vertex].position.z = z;
3225 
3226         if (slice > 0)
3227         {
3228             mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3229             mesh->faces[face][1] = number_of_vertices - 1;
3230             mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3231         }
3232     }
3233 
3234     mesh->vertices[vertex].position.x = 0.0f;
3235     mesh->vertices[vertex].position.y = 0.0f;
3236     mesh->vertices[vertex].position.z = z;
3237     mesh->vertices[vertex].normal.x = 0.0f;
3238     mesh->vertices[vertex].normal.y = 0.0f;
3239     mesh->vertices[vertex].normal.z = 1.0f;
3240 
3241     mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3242     mesh->faces[face][1] = number_of_vertices - 1;
3243     mesh->faces[face][2] = vertex_index(slices, 0, stack);
3244 
3245     free_sincos_table(&theta);
3246 
3247     return TRUE;
3248 }
3249 
test_cylinder(IDirect3DDevice9 * device,FLOAT radius1,FLOAT radius2,FLOAT length,UINT slices,UINT stacks)3250 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3251 {
3252     HRESULT hr;
3253     ID3DXMesh *cylinder;
3254     struct mesh mesh;
3255     char name[256];
3256 
3257     hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
3258     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3259     if (hr != D3D_OK)
3260     {
3261         skip("Couldn't create cylinder\n");
3262         return;
3263     }
3264 
3265     if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
3266     {
3267         skip("Couldn't create mesh\n");
3268         cylinder->lpVtbl->Release(cylinder);
3269         return;
3270     }
3271 
3272     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3273 
3274     sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
3275     compare_mesh(name, cylinder, &mesh);
3276 
3277     free_mesh(&mesh);
3278 
3279     cylinder->lpVtbl->Release(cylinder);
3280 }
3281 
D3DXCreateCylinderTest(void)3282 static void D3DXCreateCylinderTest(void)
3283 {
3284     HRESULT hr;
3285     IDirect3DDevice9* device;
3286     ID3DXMesh* cylinder = NULL;
3287     struct test_context *test_context;
3288 
3289     hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
3290     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3291 
3292     hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3293     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3294 
3295     if (!(test_context = new_test_context()))
3296     {
3297         skip("Couldn't create test context\n");
3298         return;
3299     }
3300     device = test_context->device;
3301 
3302     hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3303     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3304 
3305     hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3306     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3307 
3308     if (SUCCEEDED(hr) && cylinder)
3309     {
3310         cylinder->lpVtbl->Release(cylinder);
3311     }
3312 
3313     hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
3314     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3315 
3316     hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
3317     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3318 
3319     if (SUCCEEDED(hr) && cylinder)
3320     {
3321         cylinder->lpVtbl->Release(cylinder);
3322     }
3323 
3324     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
3325     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3326 
3327     /* Test with length == 0.0f succeeds */
3328     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
3329     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3330 
3331     if (SUCCEEDED(hr) && cylinder)
3332     {
3333         cylinder->lpVtbl->Release(cylinder);
3334     }
3335 
3336     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
3337     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3338 
3339     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
3340     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3341 
3342     hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
3343     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3344 
3345     test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
3346     test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
3347     test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
3348     test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
3349     test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
3350     test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
3351 
3352     free_test_context(test_context);
3353 }
3354 
compute_torus(struct mesh * mesh,float innerradius,float outerradius,UINT sides,UINT rings)3355 static BOOL compute_torus(struct mesh *mesh, float innerradius, float outerradius, UINT sides, UINT rings)
3356 {
3357     float phi, phi_step, sin_phi, cos_phi;
3358     float theta, theta_step, sin_theta, cos_theta;
3359     unsigned int numvert, numfaces, i, j;
3360 
3361     numvert = sides * rings;
3362     numfaces = numvert * 2;
3363 
3364     if (!new_mesh(mesh, numvert, numfaces))
3365         return FALSE;
3366 
3367     phi_step = D3DX_PI / sides * 2.0f;
3368     theta_step = D3DX_PI / rings * -2.0f;
3369 
3370     theta = 0.0f;
3371 
3372     for (i = 0; i < rings; ++i)
3373     {
3374         phi = 0.0f;
3375 
3376         cos_theta = cosf(theta);
3377         sin_theta = sinf(theta);
3378 
3379         for (j = 0; j < sides; ++j)
3380         {
3381             sin_phi = sinf(phi);
3382             cos_phi = cosf(phi);
3383 
3384             mesh->vertices[i * sides + j].position.x = (innerradius * cos_phi + outerradius) * cos_theta;
3385             mesh->vertices[i * sides + j].position.y = (innerradius * cos_phi + outerradius) * sin_theta;
3386             mesh->vertices[i * sides + j].position.z = innerradius * sin_phi;
3387             mesh->vertices[i * sides + j].normal.x = cos_phi * cos_theta;
3388             mesh->vertices[i * sides + j].normal.y = cos_phi * sin_theta;
3389             mesh->vertices[i * sides + j].normal.z = sin_phi;
3390 
3391             phi += phi_step;
3392         }
3393 
3394         theta += theta_step;
3395     }
3396 
3397     for (i = 0; i < numfaces - sides * 2; ++i)
3398     {
3399         mesh->faces[i][0] = i % 2 ? i / 2 + sides : i / 2;
3400         mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3401         mesh->faces[i][2] = (i + 1) % (sides * 2) ? (i + 1) / 2 + sides : (i + 1) / 2;
3402     }
3403 
3404     for (j = 0; i < numfaces; ++i, ++j)
3405     {
3406         mesh->faces[i][0] = i % 2 ? j / 2 : i / 2;
3407         mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3408         mesh->faces[i][2] = i == numfaces - 1 ? 0 : (j + 1) / 2;
3409     }
3410 
3411     return TRUE;
3412 }
3413 
test_torus(IDirect3DDevice9 * device,float innerradius,float outerradius,UINT sides,UINT rings)3414 static void test_torus(IDirect3DDevice9 *device, float innerradius, float outerradius, UINT sides, UINT rings)
3415 {
3416     HRESULT hr;
3417     ID3DXMesh *torus;
3418     struct mesh mesh;
3419     char name[256];
3420 
3421     hr = D3DXCreateTorus(device, innerradius, outerradius, sides, rings, &torus, NULL);
3422     ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK)\n", hr);
3423     if (hr != D3D_OK)
3424     {
3425         skip("Couldn't create torus\n");
3426         return;
3427     }
3428 
3429     if (!compute_torus(&mesh, innerradius, outerradius, sides, rings))
3430     {
3431         skip("Couldn't create mesh\n");
3432         torus->lpVtbl->Release(torus);
3433         return;
3434     }
3435 
3436     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3437 
3438     sprintf(name, "torus (%g, %g, %u, %u)", innerradius, outerradius, sides, rings);
3439     compare_mesh(name, torus, &mesh);
3440 
3441     free_mesh(&mesh);
3442 
3443     torus->lpVtbl->Release(torus);
3444 }
3445 
D3DXCreateTorusTest(void)3446 static void D3DXCreateTorusTest(void)
3447 {
3448     HRESULT hr;
3449     IDirect3DDevice9* device;
3450     ID3DXMesh* torus = NULL;
3451     struct test_context *test_context;
3452 
3453     if (!(test_context = new_test_context()))
3454     {
3455         skip("Couldn't create test context\n");
3456         return;
3457     }
3458     device = test_context->device;
3459 
3460     hr = D3DXCreateTorus(NULL, 0.0f, 0.0f, 3, 3, &torus, NULL);
3461     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3462 
3463     hr = D3DXCreateTorus(device, -1.0f, 0.0f, 3, 3, &torus, NULL);
3464     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3465 
3466     hr = D3DXCreateTorus(device, 0.0f, -1.0f, 3, 3, &torus, NULL);
3467     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3468 
3469     hr = D3DXCreateTorus(device, 0.0f, 0.0f, 2, 3, &torus, NULL);
3470     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3471 
3472     hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 2, &torus, NULL);
3473     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3474 
3475     hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 3, NULL, NULL);
3476     ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3477 
3478     test_torus(device, 0.0f, 0.0f, 3, 3);
3479     test_torus(device, 1.0f, 1.0f, 3, 3);
3480     test_torus(device, 1.0f, 1.0f, 32, 64);
3481     test_torus(device, 0.0f, 1.0f, 5, 5);
3482     test_torus(device, 1.0f, 0.0f, 5, 5);
3483     test_torus(device, 5.0f, 0.2f, 8, 8);
3484     test_torus(device, 0.2f, 1.0f, 60, 3);
3485     test_torus(device, 0.2f, 1.0f, 8, 70);
3486 
3487     free_test_context(test_context);
3488 }
3489 
3490 struct dynamic_array
3491 {
3492     int count, capacity;
3493     void *items;
3494 };
3495 
3496 enum pointtype {
3497     POINTTYPE_CURVE = 0,
3498     POINTTYPE_CORNER,
3499     POINTTYPE_CURVE_START,
3500     POINTTYPE_CURVE_END,
3501     POINTTYPE_CURVE_MIDDLE,
3502 };
3503 
3504 struct point2d
3505 {
3506     D3DXVECTOR2 pos;
3507     enum pointtype corner;
3508 };
3509 
3510 /* is a dynamic_array */
3511 struct outline
3512 {
3513     int count, capacity;
3514     struct point2d *items;
3515 };
3516 
3517 /* is a dynamic_array */
3518 struct outline_array
3519 {
3520     int count, capacity;
3521     struct outline *items;
3522 };
3523 
3524 struct glyphinfo
3525 {
3526     struct outline_array outlines;
3527     float offset_x;
3528 };
3529 
reserve(struct dynamic_array * array,int count,int itemsize)3530 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
3531 {
3532     if (count > array->capacity) {
3533         void *new_buffer;
3534         int new_capacity;
3535         if (array->items && array->capacity) {
3536             new_capacity = max(array->capacity * 2, count);
3537             new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
3538         } else {
3539             new_capacity = max(16, count);
3540             new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
3541         }
3542         if (!new_buffer)
3543             return FALSE;
3544         array->items = new_buffer;
3545         array->capacity = new_capacity;
3546     }
3547     return TRUE;
3548 }
3549 
add_point(struct outline * array)3550 static struct point2d *add_point(struct outline *array)
3551 {
3552     struct point2d *item;
3553 
3554     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3555         return NULL;
3556 
3557     item = &array->items[array->count++];
3558     ZeroMemory(item, sizeof(*item));
3559     return item;
3560 }
3561 
add_outline(struct outline_array * array)3562 static struct outline *add_outline(struct outline_array *array)
3563 {
3564     struct outline *item;
3565 
3566     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3567         return NULL;
3568 
3569     item = &array->items[array->count++];
3570     ZeroMemory(item, sizeof(*item));
3571     return item;
3572 }
3573 
convert_fixed_to_float(POINTFX * pt,int count,float emsquare)3574 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
3575 {
3576     D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
3577     while (count--) {
3578         D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
3579         pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
3580         pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
3581         pt++;
3582     }
3583     return ret;
3584 }
3585 
add_bezier_points(struct outline * outline,const D3DXVECTOR2 * p1,const D3DXVECTOR2 * p2,const D3DXVECTOR2 * p3,float max_deviation)3586 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
3587                                  const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
3588                                  float max_deviation)
3589 {
3590     D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
3591     float deviation;
3592 
3593     D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
3594     D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
3595     D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
3596 
3597     deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
3598     if (deviation < max_deviation) {
3599         struct point2d *pt = add_point(outline);
3600         if (!pt) return E_OUTOFMEMORY;
3601         pt->pos = *p2;
3602         pt->corner = POINTTYPE_CURVE;
3603         /* the end point is omitted because the end line merges into the next segment of
3604          * the split bezier curve, and the end of the split bezier curve is added outside
3605          * this recursive function. */
3606     } else {
3607         HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
3608         if (hr != S_OK) return hr;
3609         hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
3610         if (hr != S_OK) return hr;
3611     }
3612 
3613     return S_OK;
3614 }
3615 
is_direction_similar(D3DXVECTOR2 * dir1,D3DXVECTOR2 * dir2,float cos_theta)3616 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
3617 {
3618     /* dot product = cos(theta) */
3619     return D3DXVec2Dot(dir1, dir2) > cos_theta;
3620 }
3621 
unit_vec2(D3DXVECTOR2 * dir,const D3DXVECTOR2 * pt1,const D3DXVECTOR2 * pt2)3622 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
3623 {
3624     return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
3625 }
3626 
attempt_line_merge(struct outline * outline,int pt_index,const D3DXVECTOR2 * nextpt,BOOL to_curve)3627 static BOOL attempt_line_merge(struct outline *outline,
3628                                int pt_index,
3629                                const D3DXVECTOR2 *nextpt,
3630                                BOOL to_curve)
3631 {
3632     D3DXVECTOR2 curdir, lastdir;
3633     struct point2d *prevpt, *pt;
3634     BOOL ret = FALSE;
3635     const float cos_half = cos(D3DXToRadian(0.5f));
3636 
3637     pt = &outline->items[pt_index];
3638     pt_index = (pt_index - 1 + outline->count) % outline->count;
3639     prevpt = &outline->items[pt_index];
3640 
3641     if (to_curve)
3642         pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
3643 
3644     if (outline->count < 2)
3645         return FALSE;
3646 
3647     /* remove last point if the next line continues the last line */
3648     unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3649     unit_vec2(&curdir, &pt->pos, nextpt);
3650     if (is_direction_similar(&lastdir, &curdir, cos_half))
3651     {
3652         outline->count--;
3653         if (pt->corner == POINTTYPE_CURVE_END)
3654             prevpt->corner = pt->corner;
3655         if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
3656             prevpt->corner = POINTTYPE_CURVE_MIDDLE;
3657         pt = prevpt;
3658 
3659         ret = TRUE;
3660         if (outline->count < 2)
3661             return ret;
3662 
3663         pt_index = (pt_index - 1 + outline->count) % outline->count;
3664         prevpt = &outline->items[pt_index];
3665         unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3666         unit_vec2(&curdir, &pt->pos, nextpt);
3667     }
3668     return ret;
3669 }
3670 
create_outline(struct glyphinfo * glyph,void * raw_outline,int datasize,float max_deviation,float emsquare)3671 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
3672                               float max_deviation, float emsquare)
3673 {
3674     const float cos_45 = cos(D3DXToRadian(45.0f));
3675     const float cos_90 = cos(D3DXToRadian(90.0f));
3676     TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
3677 
3678     while ((char *)header < (char *)raw_outline + datasize)
3679     {
3680         TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
3681         struct point2d *lastpt, *pt;
3682         D3DXVECTOR2 lastdir;
3683         D3DXVECTOR2 *pt_flt;
3684         int j;
3685         struct outline *outline = add_outline(&glyph->outlines);
3686 
3687         if (!outline)
3688             return E_OUTOFMEMORY;
3689 
3690         pt = add_point(outline);
3691         if (!pt)
3692             return E_OUTOFMEMORY;
3693         pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
3694         pt->pos = *pt_flt;
3695         pt->corner = POINTTYPE_CORNER;
3696 
3697         if (header->dwType != TT_POLYGON_TYPE)
3698             trace("Unknown header type %d\n", header->dwType);
3699 
3700         while ((char *)curve < (char *)header + header->cb)
3701         {
3702             D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
3703             BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
3704 
3705             if (!curve->cpfx) {
3706                 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3707                 continue;
3708             }
3709 
3710             pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
3711 
3712             attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
3713 
3714             if (to_curve)
3715             {
3716                 HRESULT hr;
3717                 int count = curve->cpfx;
3718                 j = 0;
3719 
3720                 while (count > 2)
3721                 {
3722                     D3DXVECTOR2 bezier_end;
3723 
3724                     D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
3725                     hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
3726                     if (hr != S_OK)
3727                         return hr;
3728                     bezier_start = bezier_end;
3729                     count--;
3730                     j++;
3731                 }
3732                 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
3733                 if (hr != S_OK)
3734                     return hr;
3735 
3736                 pt = add_point(outline);
3737                 if (!pt)
3738                     return E_OUTOFMEMORY;
3739                 j++;
3740                 pt->pos = pt_flt[j];
3741                 pt->corner = POINTTYPE_CURVE_END;
3742             } else {
3743                 for (j = 0; j < curve->cpfx; j++)
3744                 {
3745                     pt = add_point(outline);
3746                     if (!pt)
3747                         return E_OUTOFMEMORY;
3748                     pt->pos = pt_flt[j];
3749                     pt->corner = POINTTYPE_CORNER;
3750                 }
3751             }
3752 
3753             curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3754         }
3755 
3756         /* remove last point if the next line continues the last line */
3757         if (outline->count >= 3) {
3758             BOOL to_curve;
3759 
3760             lastpt = &outline->items[outline->count - 1];
3761             pt = &outline->items[0];
3762             if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
3763                 if (lastpt->corner == POINTTYPE_CURVE_END)
3764                 {
3765                     if (pt->corner == POINTTYPE_CURVE_START)
3766                         pt->corner = POINTTYPE_CURVE_MIDDLE;
3767                     else
3768                         pt->corner = POINTTYPE_CURVE_END;
3769                 }
3770                 outline->count--;
3771             } else {
3772                 /* outline closed with a line from end to start point */
3773                 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
3774             }
3775             lastpt = &outline->items[0];
3776             to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
3777             if (lastpt->corner == POINTTYPE_CURVE_START)
3778                 lastpt->corner = POINTTYPE_CORNER;
3779             pt = &outline->items[1];
3780             if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
3781                 *lastpt = outline->items[outline->count];
3782         }
3783 
3784         lastpt = &outline->items[outline->count - 1];
3785         pt = &outline->items[0];
3786         unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
3787         for (j = 0; j < outline->count; j++)
3788         {
3789             D3DXVECTOR2 curdir;
3790 
3791             lastpt = pt;
3792             pt = &outline->items[(j + 1) % outline->count];
3793             unit_vec2(&curdir, &lastpt->pos, &pt->pos);
3794 
3795             switch (lastpt->corner)
3796             {
3797                 case POINTTYPE_CURVE_START:
3798                 case POINTTYPE_CURVE_END:
3799                     if (!is_direction_similar(&lastdir, &curdir, cos_45))
3800                         lastpt->corner = POINTTYPE_CORNER;
3801                     break;
3802                 case POINTTYPE_CURVE_MIDDLE:
3803                     if (!is_direction_similar(&lastdir, &curdir, cos_90))
3804                         lastpt->corner = POINTTYPE_CORNER;
3805                     else
3806                         lastpt->corner = POINTTYPE_CURVE;
3807                     break;
3808                 default:
3809                     break;
3810             }
3811             lastdir = curdir;
3812         }
3813 
3814         header = (TTPOLYGONHEADER *)((char *)header + header->cb);
3815     }
3816     return S_OK;
3817 }
3818 
free_outline(struct outline * outline)3819 static void free_outline(struct outline *outline)
3820 {
3821     HeapFree(GetProcessHeap(), 0, outline->items);
3822 }
3823 
free_glyphinfo(struct glyphinfo * glyph)3824 static void free_glyphinfo(struct glyphinfo *glyph)
3825 {
3826     unsigned int i;
3827 
3828     for (i = 0; i < glyph->outlines.count; ++i)
3829         free_outline(&glyph->outlines.items[i]);
3830     HeapFree(GetProcessHeap(), 0, glyph->outlines.items);
3831 }
3832 
compute_text_mesh(struct mesh * mesh,const char * text,float deviation,float extrusion,float otmEMSquare,const struct glyphinfo * glyphs)3833 static void compute_text_mesh(struct mesh *mesh, const char *text,
3834         float deviation, float extrusion, float otmEMSquare, const struct glyphinfo *glyphs)
3835 {
3836     DWORD nb_vertices, nb_faces;
3837     DWORD nb_corners, nb_outline_points;
3838     int textlen = 0;
3839     int i;
3840     struct vertex *vertex_ptr;
3841     face *face_ptr;
3842 
3843     textlen = strlen(text);
3844 
3845     /* corner points need an extra vertex for the different side faces normals */
3846     nb_corners = 0;
3847     nb_outline_points = 0;
3848     for (i = 0; i < textlen; i++)
3849     {
3850         int j;
3851         for (j = 0; j < glyphs[i].outlines.count; j++)
3852         {
3853             int k;
3854             struct outline *outline = &glyphs[i].outlines.items[j];
3855             nb_outline_points += outline->count;
3856             nb_corners++; /* first outline point always repeated as a corner */
3857             for (k = 1; k < outline->count; k++)
3858                 if (outline->items[k].corner)
3859                     nb_corners++;
3860         }
3861     }
3862 
3863     nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
3864     nb_faces = nb_outline_points * 2;
3865 
3866     ok(new_mesh(mesh, nb_vertices, nb_faces), "Failed to create reference text mesh.\n");
3867 
3868     /* convert 2D vertices and faces into 3D mesh */
3869     vertex_ptr = mesh->vertices;
3870     face_ptr = mesh->faces;
3871     for (i = 0; i < textlen; i++)
3872     {
3873         int j;
3874 
3875         /* side vertices and faces */
3876         for (j = 0; j < glyphs[i].outlines.count; j++)
3877         {
3878             struct vertex *outline_vertices = vertex_ptr;
3879             struct outline *outline = &glyphs[i].outlines.items[j];
3880             int k;
3881             struct point2d *prevpt = &outline->items[outline->count - 1];
3882             struct point2d *pt = &outline->items[0];
3883 
3884             for (k = 1; k <= outline->count; k++)
3885             {
3886                 struct vertex vtx;
3887                 struct point2d *nextpt = &outline->items[k % outline->count];
3888                 WORD vtx_idx = vertex_ptr - mesh->vertices;
3889                 D3DXVECTOR2 vec;
3890 
3891                 if (pt->corner == POINTTYPE_CURVE_START)
3892                     D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
3893                 else if (pt->corner)
3894                     D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3895                 else
3896                     D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
3897                 D3DXVec2Normalize(&vec, &vec);
3898                 vtx.normal.x = -vec.y;
3899                 vtx.normal.y = vec.x;
3900                 vtx.normal.z = 0;
3901 
3902                 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
3903                 vtx.position.y = pt->pos.y;
3904                 vtx.position.z = 0;
3905                 *vertex_ptr++ = vtx;
3906 
3907                 vtx.position.z = -extrusion;
3908                 *vertex_ptr++ = vtx;
3909 
3910                 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
3911                 vtx.position.y = nextpt->pos.y;
3912                 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
3913                     vtx.position.z = -extrusion;
3914                     *vertex_ptr++ = vtx;
3915                     vtx.position.z = 0;
3916                     *vertex_ptr++ = vtx;
3917 
3918                     (*face_ptr)[0] = vtx_idx;
3919                     (*face_ptr)[1] = vtx_idx + 2;
3920                     (*face_ptr)[2] = vtx_idx + 1;
3921                     face_ptr++;
3922 
3923                     (*face_ptr)[0] = vtx_idx;
3924                     (*face_ptr)[1] = vtx_idx + 3;
3925                     (*face_ptr)[2] = vtx_idx + 2;
3926                     face_ptr++;
3927                 } else {
3928                     if (nextpt->corner) {
3929                         if (nextpt->corner == POINTTYPE_CURVE_END) {
3930                             struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
3931                             D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
3932                         } else {
3933                             D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3934                         }
3935                         D3DXVec2Normalize(&vec, &vec);
3936                         vtx.normal.x = -vec.y;
3937                         vtx.normal.y = vec.x;
3938 
3939                         vtx.position.z = 0;
3940                         *vertex_ptr++ = vtx;
3941                         vtx.position.z = -extrusion;
3942                         *vertex_ptr++ = vtx;
3943                     }
3944 
3945                     (*face_ptr)[0] = vtx_idx;
3946                     (*face_ptr)[1] = vtx_idx + 3;
3947                     (*face_ptr)[2] = vtx_idx + 1;
3948                     face_ptr++;
3949 
3950                     (*face_ptr)[0] = vtx_idx;
3951                     (*face_ptr)[1] = vtx_idx + 2;
3952                     (*face_ptr)[2] = vtx_idx + 3;
3953                     face_ptr++;
3954                 }
3955 
3956                 prevpt = pt;
3957                 pt = nextpt;
3958             }
3959             if (!pt->corner) {
3960                 *vertex_ptr++ = *outline_vertices++;
3961                 *vertex_ptr++ = *outline_vertices++;
3962             }
3963         }
3964 
3965         /* FIXME: compute expected faces */
3966         /* Add placeholder to separate glyph outlines */
3967         vertex_ptr->position.x = 0;
3968         vertex_ptr->position.y = 0;
3969         vertex_ptr->position.z = 0;
3970         vertex_ptr->normal.x = 0;
3971         vertex_ptr->normal.y = 0;
3972         vertex_ptr->normal.z = 1;
3973         vertex_ptr++;
3974     }
3975 }
3976 
compare_text_outline_mesh(const char * name,ID3DXMesh * d3dxmesh,struct mesh * mesh,size_t textlen,float extrusion,const struct glyphinfo * glyphs)3977 static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh,
3978         size_t textlen, float extrusion, const struct glyphinfo *glyphs)
3979 {
3980     HRESULT hr;
3981     DWORD number_of_vertices, number_of_faces;
3982     IDirect3DVertexBuffer9 *vertex_buffer = NULL;
3983     IDirect3DIndexBuffer9 *index_buffer = NULL;
3984     D3DVERTEXBUFFER_DESC vertex_buffer_description;
3985     D3DINDEXBUFFER_DESC index_buffer_description;
3986     struct vertex *vertices = NULL;
3987     face *faces = NULL;
3988     int expected, i;
3989     int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
3990 
3991     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
3992     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
3993 
3994     hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
3995     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
3996     hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
3997     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
3998     ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, unexpected format %u.\n",
3999             name, vertex_buffer_description.Format);
4000     ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, unexpected resource type %u.\n",
4001             name, vertex_buffer_description.Type);
4002     ok(!vertex_buffer_description.Usage, "Test %s, unexpected usage %#x.\n", name, vertex_buffer_description.Usage);
4003     ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, unexpected pool %u.\n",
4004             name, vertex_buffer_description.Pool);
4005     ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, unexpected FVF %#x (expected %#x).\n",
4006             name, vertex_buffer_description.FVF, mesh->fvf);
4007     if (!mesh->fvf)
4008         expected = number_of_vertices * mesh->vertex_size;
4009     else
4010         expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
4011     ok(vertex_buffer_description.Size == expected, "Test %s, unexpected size %u (expected %u).\n",
4012             name, vertex_buffer_description.Size, expected);
4013 
4014     hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
4015     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4016     hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
4017     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4018     ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, unexpected format %u.\n",
4019             name, index_buffer_description.Format);
4020     ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, unexpected resource type %u.\n",
4021             name, index_buffer_description.Type);
4022     ok(!index_buffer_description.Usage, "Test %s, unexpected usage %#x.\n",
4023             name, index_buffer_description.Usage);
4024     ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, unexpected pool %u.\n",
4025             name, index_buffer_description.Pool);
4026     expected = number_of_faces * sizeof(WORD) * 3;
4027     ok(index_buffer_description.Size == expected, "Test %s, unexpected size %u.\n",
4028             name, index_buffer_description.Size);
4029 
4030     hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
4031             (void **)&vertices, D3DLOCK_DISCARD);
4032     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4033     hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
4034             (void **)&faces, D3DLOCK_DISCARD);
4035     ok(hr == D3D_OK, "Test %s, unexpected hr %#x.\n", name, hr);
4036     face_idx1 = 0;
4037     vtx_idx2 = 0;
4038     face_idx2 = 0;
4039     vtx_idx1 = 0;
4040     for (i = 0; i < textlen; i++)
4041     {
4042         int nb_outline_vertices1, nb_outline_faces1;
4043         int nb_outline_vertices2, nb_outline_faces2;
4044         int nb_back_vertices, nb_back_faces;
4045         int first_vtx1, first_vtx2;
4046         int first_face1, first_face2;
4047         int j;
4048 
4049         first_vtx1 = vtx_idx1;
4050         first_vtx2 = vtx_idx2;
4051         /* Glyphs without outlines do not generate any vertices. */
4052         if (glyphs[i].outlines.count > 0)
4053         {
4054             for (; vtx_idx1 < number_of_vertices; vtx_idx1++)
4055             {
4056                 if (vertices[vtx_idx1].normal.z != 0)
4057                     break;
4058             }
4059 
4060             for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++)
4061             {
4062                 if (mesh->vertices[vtx_idx2].normal.z != 0)
4063                     break;
4064             }
4065         }
4066         nb_outline_vertices1 = vtx_idx1 - first_vtx1;
4067         nb_outline_vertices2 = vtx_idx2 - first_vtx2;
4068         ok(nb_outline_vertices1 == nb_outline_vertices2,
4069            "Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
4070            nb_outline_vertices1, nb_outline_vertices2);
4071 
4072         for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
4073         {
4074             vtx_idx1 = first_vtx1 + j;
4075             vtx_idx2 = first_vtx2 + j;
4076             ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
4077                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4078                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
4079                mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
4080             ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
4081                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4082                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4083                mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
4084         }
4085         vtx_idx1 = first_vtx1 + nb_outline_vertices1;
4086         vtx_idx2 = first_vtx2 + nb_outline_vertices2;
4087 
4088         first_face1 = face_idx1;
4089         first_face2 = face_idx2;
4090         for (; face_idx1 < number_of_faces; face_idx1++)
4091         {
4092             if (faces[face_idx1][0] >= vtx_idx1 ||
4093                 faces[face_idx1][1] >= vtx_idx1 ||
4094                 faces[face_idx1][2] >= vtx_idx1)
4095                 break;
4096         }
4097         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
4098         {
4099             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
4100                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
4101                 mesh->faces[face_idx2][2] >= vtx_idx2)
4102                 break;
4103         }
4104         nb_outline_faces1 = face_idx1 - first_face1;
4105         nb_outline_faces2 = face_idx2 - first_face2;
4106         ok(nb_outline_faces1 == nb_outline_faces2,
4107            "Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
4108            nb_outline_faces1, nb_outline_faces2);
4109 
4110         for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
4111         {
4112             face_idx1 = first_face1 + j;
4113             face_idx2 = first_face2 + j;
4114             ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
4115                faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
4116                faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
4117                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
4118                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
4119                mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
4120                mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
4121                mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
4122         }
4123         face_idx1 = first_face1 + nb_outline_faces1;
4124         face_idx2 = first_face2 + nb_outline_faces2;
4125 
4126         /* partial test on back vertices and faces  */
4127         first_vtx1 = vtx_idx1;
4128         for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
4129             struct vertex vtx;
4130 
4131             if (vertices[vtx_idx1].normal.z != 1.0f)
4132                 break;
4133 
4134             vtx.position.z = 0.0f;
4135             vtx.normal.x = 0.0f;
4136             vtx.normal.y = 0.0f;
4137             vtx.normal.z = 1.0f;
4138             ok(compare(vertices[vtx_idx1].position.z, vtx.position.z),
4139                "Test %s, glyph %d, vertex position.z %d, result %g, expected %g\n", name, i, vtx_idx1,
4140                vertices[vtx_idx1].position.z, vtx.position.z);
4141             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
4142                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4143                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4144                vtx.normal.x, vtx.normal.y, vtx.normal.z);
4145         }
4146         nb_back_vertices = vtx_idx1 - first_vtx1;
4147         first_face1 = face_idx1;
4148         for (; face_idx1 < number_of_faces; face_idx1++)
4149         {
4150             const D3DXVECTOR3 *vtx1, *vtx2, *vtx3;
4151             D3DXVECTOR3 normal;
4152             D3DXVECTOR3 v1 = {0, 0, 0};
4153             D3DXVECTOR3 v2 = {0, 0, 0};
4154             D3DXVECTOR3 forward = {0.0f, 0.0f, 1.0f};
4155 
4156             if (faces[face_idx1][0] >= vtx_idx1 ||
4157                 faces[face_idx1][1] >= vtx_idx1 ||
4158                 faces[face_idx1][2] >= vtx_idx1)
4159                 break;
4160 
4161             vtx1 = &vertices[faces[face_idx1][0]].position;
4162             vtx2 = &vertices[faces[face_idx1][1]].position;
4163             vtx3 = &vertices[faces[face_idx1][2]].position;
4164 
4165             D3DXVec3Subtract(&v1, vtx2, vtx1);
4166             D3DXVec3Subtract(&v2, vtx3, vtx2);
4167             D3DXVec3Cross(&normal, &v1, &v2);
4168             D3DXVec3Normalize(&normal, &normal);
4169             ok(!D3DXVec3Length(&normal) || compare_vec3(normal, forward),
4170                "Test %s, glyph %d, face %d normal, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, face_idx1,
4171                normal.x, normal.y, normal.z, forward.x, forward.y, forward.z);
4172         }
4173         nb_back_faces = face_idx1 - first_face1;
4174 
4175         /* compare front and back faces & vertices */
4176         if (extrusion == 0.0f) {
4177             /* Oddly there are only back faces in this case */
4178             nb_back_vertices /= 2;
4179             nb_back_faces /= 2;
4180             face_idx1 -= nb_back_faces;
4181             vtx_idx1 -= nb_back_vertices;
4182         }
4183         for (j = 0; j < nb_back_vertices; j++)
4184         {
4185             struct vertex vtx = vertices[first_vtx1];
4186             vtx.position.z = -extrusion;
4187             vtx.normal.x = 0.0f;
4188             vtx.normal.y = 0.0f;
4189             vtx.normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
4190             ok(compare_vec3(vertices[vtx_idx1].position, vtx.position),
4191                "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4192                vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
4193                vtx.position.x, vtx.position.y, vtx.position.z);
4194             ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
4195                "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
4196                vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
4197                vtx.normal.x, vtx.normal.y, vtx.normal.z);
4198             vtx_idx1++;
4199             first_vtx1++;
4200         }
4201         for (j = 0; j < nb_back_faces; j++)
4202         {
4203             int f1, f2;
4204             if (extrusion == 0.0f) {
4205                 f1 = 1;
4206                 f2 = 2;
4207             } else {
4208                 f1 = 2;
4209                 f2 = 1;
4210             }
4211             ok(faces[face_idx1][0] == faces[first_face1][0] + nb_back_vertices &&
4212                faces[face_idx1][1] == faces[first_face1][f1] + nb_back_vertices &&
4213                faces[face_idx1][2] == faces[first_face1][f2] + nb_back_vertices,
4214                "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
4215                faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
4216                faces[first_face1][0] - nb_back_faces,
4217                faces[first_face1][f1] - nb_back_faces,
4218                faces[first_face1][f2] - nb_back_faces);
4219             first_face1++;
4220             face_idx1++;
4221         }
4222 
4223         /* skip to the outline for the next glyph */
4224         for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
4225             if (mesh->vertices[vtx_idx2].normal.z == 0)
4226                 break;
4227         }
4228         for (; face_idx2 < mesh->number_of_faces; face_idx2++)
4229         {
4230             if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
4231                 mesh->faces[face_idx2][1] >= vtx_idx2 ||
4232                 mesh->faces[face_idx2][2] >= vtx_idx2) break;
4233         }
4234     }
4235 
4236     IDirect3DIndexBuffer9_Unlock(index_buffer);
4237     IDirect3DVertexBuffer9_Unlock(vertex_buffer);
4238     IDirect3DIndexBuffer9_Release(index_buffer);
4239     IDirect3DVertexBuffer9_Release(vertex_buffer);
4240 }
4241 
test_createtext(IDirect3DDevice9 * device,HDC hdc,const char * text,float deviation,float extrusion)4242 static void test_createtext(IDirect3DDevice9 *device, HDC hdc, const char *text, float deviation, float extrusion)
4243 {
4244     static const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
4245     HRESULT hr;
4246     ID3DXMesh *d3dxmesh = NULL;
4247     struct mesh mesh = {0};
4248     char name[256];
4249     OUTLINETEXTMETRICA otm;
4250     GLYPHMETRICS gm;
4251     struct glyphinfo *glyphs;
4252     GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
4253     int i;
4254     LOGFONTA lf;
4255     float offset_x;
4256     size_t textlen;
4257     HFONT font = NULL, oldfont = NULL;
4258     char *raw_outline;
4259 
4260     sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion);
4261 
4262     hr = D3DXCreateTextA(device, hdc, text, deviation, extrusion, &d3dxmesh, NULL, glyphmetrics_float);
4263     ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
4264 
4265     /* must select a modified font having lfHeight = otm.otmEMSquare before
4266      * calling GetGlyphOutline to get the expected values */
4267     ok(GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf), "Failed to get current DC font.\n");
4268     ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "Failed to get DC font outline.\n");
4269     lf.lfHeight = otm.otmEMSquare;
4270     lf.lfWidth = 0;
4271     ok(!!(font = CreateFontIndirectA(&lf)), "Failed to create font.\n");
4272 
4273     textlen = strlen(text);
4274     glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
4275     oldfont = SelectObject(hdc, font);
4276 
4277     for (i = 0; i < textlen; i++)
4278     {
4279         GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
4280         compare_float(glyphmetrics_float[i].gmfBlackBoxX, gm.gmBlackBoxX / (float)otm.otmEMSquare);
4281         compare_float(glyphmetrics_float[i].gmfBlackBoxY, gm.gmBlackBoxY / (float)otm.otmEMSquare);
4282         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.x, gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare);
4283         compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.y, gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare);
4284         compare_float(glyphmetrics_float[i].gmfCellIncX, gm.gmCellIncX / (float)otm.otmEMSquare);
4285         compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
4286     }
4287 
4288     if (deviation == 0.0f)
4289         deviation = 1.0f / otm.otmEMSquare;
4290 
4291     offset_x = 0.0f;
4292     for (i = 0; i < textlen; i++)
4293     {
4294         DWORD datasize;
4295 
4296         glyphs[i].offset_x = offset_x;
4297 
4298         datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
4299         ok(datasize != GDI_ERROR, "Failed to retrieve GDI glyph outline size.\n");
4300         raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
4301         datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
4302         ok(datasize != GDI_ERROR, "Failed to retrieve GDI glyph outline.\n");
4303         create_outline(&glyphs[i], raw_outline, datasize, deviation, otm.otmEMSquare);
4304         HeapFree(GetProcessHeap(), 0, raw_outline);
4305 
4306         offset_x += gm.gmCellIncX / (float)otm.otmEMSquare;
4307     }
4308 
4309     SelectObject(hdc, oldfont);
4310 
4311     compute_text_mesh(&mesh, text, deviation, extrusion, otm.otmEMSquare, glyphs);
4312     mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
4313 
4314     compare_text_outline_mesh(name, d3dxmesh, &mesh, textlen, extrusion, glyphs);
4315 
4316     free_mesh(&mesh);
4317     d3dxmesh->lpVtbl->Release(d3dxmesh);
4318     DeleteObject(font);
4319     HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
4320 
4321     for (i = 0; i < textlen; i++)
4322         free_glyphinfo(&glyphs[i]);
4323     HeapFree(GetProcessHeap(), 0, glyphs);
4324 }
4325 
D3DXCreateTextTest(void)4326 static void D3DXCreateTextTest(void)
4327 {
4328     HRESULT hr;
4329     HDC hdc;
4330     IDirect3DDevice9* device;
4331     ID3DXMesh* d3dxmesh = NULL;
4332     HFONT hFont;
4333     OUTLINETEXTMETRICA otm;
4334     int number_of_vertices;
4335     int number_of_faces;
4336     struct test_context *test_context;
4337 
4338     if (!(test_context = new_test_context()))
4339     {
4340         skip("Couldn't create test context\n");
4341         return;
4342     }
4343     device = test_context->device;
4344 
4345     hdc = CreateCompatibleDC(NULL);
4346 
4347     hFont = CreateFontA(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
4348             CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
4349     SelectObject(hdc, hFont);
4350     GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
4351 
4352     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, 0.4f, NULL, NULL, NULL);
4353     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4354 
4355     /* D3DXCreateTextA page faults from passing NULL text */
4356 
4357     hr = D3DXCreateTextW(device, hdc, NULL, 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4358     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4359 
4360     hr = D3DXCreateTextA(device, hdc, "", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4361     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4362 
4363     hr = D3DXCreateTextA(device, hdc, " ", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4364     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4365 
4366     hr = D3DXCreateTextA(NULL, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4367     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4368 
4369     hr = D3DXCreateTextA(device, NULL, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4370     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4371 
4372     hr = D3DXCreateTextA(device, hdc, "wine", -FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4373     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4374 
4375     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, -FLT_MIN, &d3dxmesh, NULL, NULL);
4376     ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4377 
4378     /* deviation = 0.0f treated as if deviation = 1.0f / otm.otmEMSquare */
4379     hr = D3DXCreateTextA(device, hdc, "wine", 1.0f / otm.otmEMSquare, 0.4f, &d3dxmesh, NULL, NULL);
4380     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4381     number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
4382     number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
4383     d3dxmesh->lpVtbl->Release(d3dxmesh);
4384 
4385     hr = D3DXCreateTextA(device, hdc, "wine", 0.0f, 0.4f, &d3dxmesh, NULL, NULL);
4386     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4387     ok(number_of_vertices == d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh),
4388        "Got %d vertices, expected %d\n",
4389        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_vertices);
4390     ok(number_of_faces == d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh),
4391        "Got %d faces, expected %d\n",
4392        d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_faces);
4393     d3dxmesh->lpVtbl->Release(d3dxmesh);
4394 
4395 if (0)
4396 {
4397     /* too much detail requested, so will appear to hang */
4398     trace("Waiting for D3DXCreateText to finish with deviation = FLT_MIN ...\n");
4399     hr = D3DXCreateTextA(device, hdc, "wine", FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4400     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4401     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4402     trace("D3DXCreateText finish with deviation = FLT_MIN\n");
4403 }
4404 
4405     hr = D3DXCreateTextA(device, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4406     ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4407     if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4408 
4409     test_createtext(device, hdc, "wine", FLT_MAX, 0.4f);
4410     test_createtext(device, hdc, "wine", 0.001f, FLT_MIN);
4411     test_createtext(device, hdc, "wine", 0.001f, 0.0f);
4412     test_createtext(device, hdc, "wine", 0.001f, FLT_MAX);
4413     test_createtext(device, hdc, "wine", 0.0f, 1.0f);
4414     test_createtext(device, hdc, " wine", 1.0f, 0.0f);
4415     test_createtext(device, hdc, "wine ", 1.0f, 0.0f);
4416     test_createtext(device, hdc, "wi ne", 1.0f, 0.0f);
4417 
4418     DeleteDC(hdc);
4419     DeleteObject(hFont);
4420 
4421     free_test_context(test_context);
4422 }
4423 
test_get_decl_length(void)4424 static void test_get_decl_length(void)
4425 {
4426     static const D3DVERTEXELEMENT9 declaration1[] =
4427     {
4428         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4429         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4430         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4431         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4432         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4433         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4434         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4435         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4436         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4437         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4438         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4439         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4440         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4441         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4442         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4443         D3DDECL_END(),
4444     };
4445     static const D3DVERTEXELEMENT9 declaration2[] =
4446     {
4447         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4448         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4449         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4450         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4451         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4452         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4453         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4454         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4455         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4456         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4457         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4458         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4459         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4460         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4461         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4462         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4463         D3DDECL_END(),
4464     };
4465     UINT size;
4466 
4467     size = D3DXGetDeclLength(declaration1);
4468     ok(size == 15, "Got size %u, expected 15.\n", size);
4469 
4470     size = D3DXGetDeclLength(declaration2);
4471     ok(size == 16, "Got size %u, expected 16.\n", size);
4472 }
4473 
test_get_decl_vertex_size(void)4474 static void test_get_decl_vertex_size(void)
4475 {
4476     static const D3DVERTEXELEMENT9 declaration1[] =
4477     {
4478         {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4479         {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4480         {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4481         {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4482         {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4483         {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4484         {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4485         {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4486         {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4487         {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4488         {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4489         {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4490         {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4491         {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4492         {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4493         D3DDECL_END(),
4494     };
4495     static const D3DVERTEXELEMENT9 declaration2[] =
4496     {
4497         {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4498         {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4499         {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4500         {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4501         {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4502         {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4503         {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4504         {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4505         {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4506         {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4507         {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4508         {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4509         {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4510         {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4511         {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4512         {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4513         D3DDECL_END(),
4514     };
4515     static const UINT sizes1[] =
4516     {
4517         4,  8,  12, 16,
4518         4,  4,  4,  8,
4519         4,  4,  8,  4,
4520         4,  4,  8,  0,
4521     };
4522     static const UINT sizes2[] =
4523     {
4524         12, 16, 20, 24,
4525         12, 12, 16, 16,
4526     };
4527     unsigned int i;
4528     UINT size;
4529 
4530     size = D3DXGetDeclVertexSize(NULL, 0);
4531     ok(size == 0, "Got size %#x, expected 0.\n", size);
4532 
4533     for (i = 0; i < 16; ++i)
4534     {
4535         size = D3DXGetDeclVertexSize(declaration1, i);
4536         ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
4537     }
4538 
4539     for (i = 0; i < 8; ++i)
4540     {
4541         size = D3DXGetDeclVertexSize(declaration2, i);
4542         ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
4543     }
4544 }
4545 
D3DXGenerateAdjacencyTest(void)4546 static void D3DXGenerateAdjacencyTest(void)
4547 {
4548     HRESULT hr;
4549     IDirect3DDevice9 *device;
4550     ID3DXMesh *d3dxmesh = NULL;
4551     D3DXVECTOR3 *vertices = NULL;
4552     WORD *indices = NULL;
4553     int i;
4554     struct {
4555         DWORD num_vertices;
4556         D3DXVECTOR3 vertices[6];
4557         DWORD num_faces;
4558         WORD indices[3 * 3];
4559         FLOAT epsilon;
4560         DWORD adjacency[3 * 3];
4561     } test_data[] = {
4562         { /* for epsilon < 0, indices must match for faces to be adjacent */
4563             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}},
4564             2, {0, 1, 2,  0, 2, 3},
4565             -1.0,
4566             {-1, -1, 1,  0, -1, -1},
4567         },
4568         {
4569             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}},
4570             2, {0, 1, 2,  3, 4, 5},
4571             -1.0,
4572             {-1, -1, -1,  -1, -1, -1},
4573         },
4574         { /* for epsilon == 0, indices or vertices must match for faces to be adjacent */
4575             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}},
4576             2, {0, 1, 2,  3, 4, 5},
4577             0.0,
4578             {-1, -1, 1,  0, -1, -1},
4579         },
4580         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4581             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}},
4582             2, {0, 1, 2,  3, 4, 5},
4583             0.25,
4584             {-1, -1, -1,  -1, -1, -1},
4585         },
4586         { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4587             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}},
4588             2, {0, 1, 2,  3, 4, 5},
4589             0.250001,
4590             {-1, -1, 1,  0, -1, -1},
4591         },
4592         { /* length between vertices are compared to epsilon, not the individual dimension deltas */
4593             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}},
4594             2, {0, 1, 2,  3, 4, 5},
4595             0.353, /* < sqrt(0.25*0.25 + 0.25*0.25) */
4596             {-1, -1, -1,  -1, -1, -1},
4597         },
4598         {
4599             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}},
4600             2, {0, 1, 2,  3, 4, 5},
4601             0.354, /* > sqrt(0.25*0.25 + 0.25*0.25) */
4602             {-1, -1, 1,  0, -1, -1},
4603         },
4604         { /* adjacent faces must have opposite winding orders at the shared edge */
4605             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}},
4606             2, {0, 1, 2,  0, 3, 2},
4607             0.0,
4608             {-1, -1, -1,  -1, -1, -1},
4609         },
4610     };
4611     struct test_context *test_context;
4612 
4613     if (!(test_context = new_test_context()))
4614     {
4615         skip("Couldn't create test context\n");
4616         return;
4617     }
4618     device = test_context->device;
4619 
4620     for (i = 0; i < ARRAY_SIZE(test_data); i++)
4621     {
4622         DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
4623         int j;
4624 
4625         if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4626         d3dxmesh = NULL;
4627 
4628         hr = D3DXCreateMeshFVF(test_data[i].num_faces, test_data[i].num_vertices, 0, D3DFVF_XYZ, device, &d3dxmesh);
4629         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4630 
4631         hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&vertices);
4632         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4633         if (FAILED(hr)) continue;
4634         CopyMemory(vertices, test_data[i].vertices, test_data[i].num_vertices * sizeof(test_data[0].vertices[0]));
4635         d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
4636 
4637         hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&indices);
4638         ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4639         if (FAILED(hr)) continue;
4640         CopyMemory(indices, test_data[i].indices, test_data[i].num_faces * 3 * sizeof(test_data[0].indices[0]));
4641         d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
4642 
4643         if (i == 0) {
4644             hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, NULL);
4645             ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4646         }
4647 
4648         hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, test_data[i].epsilon, adjacency);
4649         ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4650         if (FAILED(hr)) continue;
4651 
4652         for (j = 0; j < test_data[i].num_faces * 3; j++)
4653             ok(adjacency[j] == test_data[i].adjacency[j],
4654                "Test %d adjacency %d: Got result %u, expected %u\n", i, j,
4655                adjacency[j], test_data[i].adjacency[j]);
4656     }
4657     if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4658 
4659     free_test_context(test_context);
4660 }
4661 
test_update_semantics(void)4662 static void test_update_semantics(void)
4663 {
4664     HRESULT hr;
4665     struct test_context *test_context = NULL;
4666     ID3DXMesh *mesh = NULL;
4667     D3DVERTEXELEMENT9 declaration0[] =
4668     {
4669          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4670          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4671          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4672          D3DDECL_END()
4673     };
4674     D3DVERTEXELEMENT9 declaration_pos_type_color[] =
4675     {
4676          {0, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4677          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4678          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4679          D3DDECL_END()
4680     };
4681     D3DVERTEXELEMENT9 declaration_smaller[] =
4682     {
4683          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4684          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4685          D3DDECL_END()
4686     };
4687     D3DVERTEXELEMENT9 declaration_larger[] =
4688     {
4689          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4690          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4691          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4692          {0, 40, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4693          D3DDECL_END()
4694     };
4695     D3DVERTEXELEMENT9 declaration_multiple_streams[] =
4696     {
4697          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4698          {1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4699          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4700          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4701 
4702          D3DDECL_END()
4703     };
4704     D3DVERTEXELEMENT9 declaration_double_usage[] =
4705     {
4706          {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4707          {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4708          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4709          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4710          D3DDECL_END()
4711     };
4712     D3DVERTEXELEMENT9 declaration_undefined_type[] =
4713     {
4714          {0, 0, D3DDECLTYPE_UNUSED+1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4715          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4716          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4717          D3DDECL_END()
4718     };
4719     D3DVERTEXELEMENT9 declaration_not_4_byte_aligned_offset[] =
4720     {
4721          {0, 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4722          {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4723          {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4724          D3DDECL_END()
4725     };
4726     static const struct
4727     {
4728         D3DXVECTOR3 position0;
4729         D3DXVECTOR3 position1;
4730         D3DXVECTOR3 normal;
4731         DWORD color;
4732     }
4733     vertices[] =
4734     {
4735         { { 0.0f,  1.0f,  0.f}, { 1.0f,  0.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xffff0000 },
4736         { { 1.0f, -1.0f,  0.f}, {-1.0f, -1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff00ff00 },
4737         { {-1.0f, -1.0f,  0.f}, {-1.0f,  1.0f,  0.f}, {0.0f, 0.0f, 1.0f}, 0xff0000ff },
4738     };
4739     unsigned int faces[] = {0, 1, 2};
4740     unsigned int attributes[] = {0};
4741     unsigned int num_faces = ARRAY_SIZE(faces) / 3;
4742     unsigned int num_vertices = ARRAY_SIZE(vertices);
4743     int offset = sizeof(D3DXVECTOR3);
4744     DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4745     void *vertex_buffer;
4746     void *index_buffer;
4747     DWORD *attributes_buffer;
4748     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
4749     D3DVERTEXELEMENT9 *decl_ptr;
4750     DWORD exp_vertex_size = sizeof(*vertices);
4751     DWORD vertex_size = 0;
4752     int equal;
4753     int i = 0;
4754     int *decl_mem;
4755     int filler_a = 0xaaaaaaaa;
4756     int filler_b = 0xbbbbbbbb;
4757 
4758     test_context = new_test_context();
4759     if (!test_context)
4760     {
4761         skip("Couldn't create a test_context\n");
4762         goto cleanup;
4763     }
4764 
4765     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration0,
4766                         test_context->device, &mesh);
4767     if (FAILED(hr))
4768     {
4769         skip("Couldn't create test mesh %#x\n", hr);
4770         goto cleanup;
4771     }
4772 
4773     mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
4774     memcpy(vertex_buffer, vertices, sizeof(vertices));
4775     mesh->lpVtbl->UnlockVertexBuffer(mesh);
4776 
4777     mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
4778     memcpy(index_buffer, faces, sizeof(faces));
4779     mesh->lpVtbl->UnlockIndexBuffer(mesh);
4780 
4781     mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
4782     memcpy(attributes_buffer, attributes, sizeof(attributes));
4783     mesh->lpVtbl->UnlockAttributeBuffer(mesh);
4784 
4785     /* Get the declaration and try to change it */
4786     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4787     if (FAILED(hr))
4788     {
4789         skip("Couldn't get vertex declaration %#x\n", hr);
4790         goto cleanup;
4791     }
4792     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4793     ok(equal == 0, "Vertex declarations were not equal\n");
4794 
4795     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4796     {
4797         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4798         {
4799             /* Use second vertex position instead of first */
4800             decl_ptr->Offset = offset;
4801         }
4802     }
4803 
4804     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4805     ok(hr == D3D_OK, "Test UpdateSemantics, got %#x expected %#x\n", hr, D3D_OK);
4806 
4807     /* Check that declaration was written by getting it again */
4808     memset(declaration, 0, sizeof(declaration));
4809     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4810     if (FAILED(hr))
4811     {
4812         skip("Couldn't get vertex declaration %#x\n", hr);
4813         goto cleanup;
4814     }
4815 
4816     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4817     {
4818         if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4819         {
4820             ok(decl_ptr->Offset == offset, "Test UpdateSemantics, got offset %d expected %d\n",
4821                decl_ptr->Offset, offset);
4822         }
4823     }
4824 
4825     /* Check that GetDeclaration only writes up to the D3DDECL_END() marker and
4826      * not the full MAX_FVF_DECL_SIZE elements.
4827      */
4828     memset(declaration, filler_a, sizeof(declaration));
4829     memcpy(declaration, declaration0, sizeof(declaration0));
4830     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4831     ok(hr == D3D_OK, "Test UpdateSemantics, "
4832        "got %#x expected D3D_OK\n", hr);
4833     memset(declaration, filler_b, sizeof(declaration));
4834     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4835     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4836     decl_mem = (int*)declaration;
4837     for (i = sizeof(declaration0)/sizeof(*decl_mem); i < sizeof(declaration)/sizeof(*decl_mem); i++)
4838     {
4839         equal = memcmp(&decl_mem[i], &filler_b, sizeof(filler_b));
4840         ok(equal == 0,
4841            "GetDeclaration wrote past the D3DDECL_END() marker. "
4842            "Got %#x, expected  %#x\n", decl_mem[i], filler_b);
4843         if (equal != 0) break;
4844     }
4845 
4846     /* UpdateSemantics does not check for overlapping fields */
4847     memset(declaration, 0, sizeof(declaration));
4848     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4849     if (FAILED(hr))
4850     {
4851         skip("Couldn't get vertex declaration %#x\n", hr);
4852         goto cleanup;
4853     }
4854 
4855     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4856     {
4857         if (decl_ptr->Type == D3DDECLTYPE_FLOAT3)
4858         {
4859             decl_ptr->Type = D3DDECLTYPE_FLOAT4;
4860         }
4861     }
4862 
4863     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4864     ok(hr == D3D_OK, "Test UpdateSemantics for overlapping fields, "
4865        "got %#x expected D3D_OK\n", hr);
4866 
4867     /* Set the position type to color instead of float3 */
4868     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_pos_type_color);
4869     ok(hr == D3D_OK, "Test UpdateSemantics position type color, "
4870        "got %#x expected D3D_OK\n", hr);
4871 
4872     /* The following test cases show that NULL, smaller or larger declarations,
4873      * and declarations with non-zero Stream values are not accepted.
4874      * UpdateSemantics returns D3DERR_INVALIDCALL and the previously set
4875      * declaration will be used by DrawSubset, GetNumBytesPerVertex, and
4876      * GetDeclaration.
4877      */
4878 
4879     /* Null declaration (invalid declaration) */
4880     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4881     hr = mesh->lpVtbl->UpdateSemantics(mesh, NULL);
4882     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics null pointer declaration, "
4883        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4884     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4885     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4886        vertex_size, exp_vertex_size);
4887     memset(declaration, 0, sizeof(declaration));
4888     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4889     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4890     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4891     ok(equal == 0, "Vertex declarations were not equal\n");
4892 
4893     /* Smaller vertex declaration (invalid declaration) */
4894     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4895     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_smaller);
4896     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics for smaller vertex declaration, "
4897        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4898     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4899     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4900        vertex_size, exp_vertex_size);
4901     memset(declaration, 0, sizeof(declaration));
4902     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4903     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4904     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4905     ok(equal == 0, "Vertex declarations were not equal\n");
4906 
4907     /* Larger vertex declaration (invalid declaration) */
4908     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4909     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_larger);
4910     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics for larger vertex declaration, "
4911        "got %#x expected D3DERR_INVALIDCALL\n", hr);
4912     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4913     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4914        vertex_size, exp_vertex_size);
4915     memset(declaration, 0, sizeof(declaration));
4916     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4917     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4918     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4919     ok(equal == 0, "Vertex declarations were not equal\n");
4920 
4921     /* Use multiple streams and keep the same vertex size (invalid declaration) */
4922     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4923     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_multiple_streams);
4924     ok(hr == D3DERR_INVALIDCALL, "Test UpdateSemantics using multiple streams, "
4925                  "got %#x expected D3DERR_INVALIDCALL\n", hr);
4926     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4927     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4928        vertex_size, exp_vertex_size);
4929     memset(declaration, 0, sizeof(declaration));
4930     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4931     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4932     equal = memcmp(declaration, declaration0, sizeof(declaration0));
4933     ok(equal == 0, "Vertex declarations were not equal\n");
4934 
4935     /* The next following test cases show that some invalid declarations are
4936      * accepted with a D3D_OK. An access violation is thrown on Windows if
4937      * DrawSubset is called. The methods GetNumBytesPerVertex and GetDeclaration
4938      * are not affected, which indicates that the declaration is cached.
4939      */
4940 
4941     /* Double usage (invalid declaration) */
4942     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4943     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_double_usage);
4944     ok(hr == D3D_OK, "Test UpdateSemantics double usage, "
4945        "got %#x expected D3D_OK\n", hr);
4946     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4947     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4948        vertex_size, exp_vertex_size);
4949     memset(declaration, 0, sizeof(declaration));
4950     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4951     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4952     equal = memcmp(declaration, declaration_double_usage, sizeof(declaration_double_usage));
4953     ok(equal == 0, "Vertex declarations were not equal\n");
4954 
4955     /* Set the position to an undefined type (invalid declaration) */
4956     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4957     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_undefined_type);
4958     ok(hr == D3D_OK, "Test UpdateSemantics undefined type, "
4959        "got %#x expected D3D_OK\n", hr);
4960     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4961     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4962        vertex_size, exp_vertex_size);
4963     memset(declaration, 0, sizeof(declaration));
4964     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4965     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4966     equal = memcmp(declaration, declaration_undefined_type, sizeof(declaration_undefined_type));
4967     ok(equal == 0, "Vertex declarations were not equal\n");
4968 
4969     /* Use a not 4 byte aligned offset (invalid declaration) */
4970     mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4971     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_not_4_byte_aligned_offset);
4972     ok(hr == D3D_OK, "Test UpdateSemantics not 4 byte aligned offset, "
4973        "got %#x expected D3D_OK\n", hr);
4974     vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4975     ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4976        vertex_size, exp_vertex_size);
4977     memset(declaration, 0, sizeof(declaration));
4978     hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4979     ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4980     equal = memcmp(declaration, declaration_not_4_byte_aligned_offset,
4981                    sizeof(declaration_not_4_byte_aligned_offset));
4982     ok(equal == 0, "Vertex declarations were not equal\n");
4983 
4984 cleanup:
4985     if (mesh)
4986         mesh->lpVtbl->Release(mesh);
4987 
4988     free_test_context(test_context);
4989 }
4990 
test_create_skin_info(void)4991 static void test_create_skin_info(void)
4992 {
4993     D3DVERTEXELEMENT9 empty_declaration[] = { D3DDECL_END() };
4994     D3DVERTEXELEMENT9 declaration_out[MAX_FVF_DECL_SIZE];
4995     const D3DVERTEXELEMENT9 declaration_with_nonzero_stream[] = {
4996         {1, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
4997         D3DDECL_END()
4998     };
4999     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
5000     DWORD exp_vertices[2], vertices[2];
5001     float exp_weights[2], weights[2];
5002     const char *exp_string, *string;
5003     ID3DXSkinInfo *skininfo = NULL;
5004     DWORD exp_fvf, fvf;
5005     unsigned int i;
5006     HRESULT hr;
5007 
5008     hr = D3DXCreateSkinInfo(0, empty_declaration, 0, &skininfo);
5009     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5010     if (skininfo) IUnknown_Release(skininfo);
5011     skininfo = NULL;
5012 
5013     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
5014     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5015 
5016     hr = D3DXCreateSkinInfo(1, declaration_with_nonzero_stream, 1, &skininfo);
5017     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5018 
5019     hr = D3DXCreateSkinInfoFVF(1, 0, 1, &skininfo);
5020     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5021     if (skininfo)
5022     {
5023         ID3DXSkinInfo *clone = NULL;
5024         DWORD dword_result;
5025         float flt_result;
5026         const char *string_result;
5027         D3DXMATRIX *transform;
5028         D3DXMATRIX identity_matrix;
5029 
5030         /* test initial values */
5031         hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5032         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5033         if (SUCCEEDED(hr))
5034             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
5035 
5036         dword_result = skininfo->lpVtbl->GetNumBones(skininfo);
5037         ok(dword_result == 1, "Expected 1, got %u\n", dword_result);
5038 
5039         flt_result = skininfo->lpVtbl->GetMinBoneInfluence(skininfo);
5040         ok(flt_result == 0.0f, "Expected 0.0, got %g\n", flt_result);
5041 
5042         string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5043         ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
5044 
5045         dword_result = skininfo->lpVtbl->GetFVF(skininfo);
5046         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5047 
5048         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 0);
5049         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5050 
5051         dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 1);
5052         ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
5053 
5054         transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, -1);
5055         ok(transform == NULL, "Expected NULL, got %p\n", transform);
5056 
5057         hr = skininfo->lpVtbl->Clone(skininfo, &clone);
5058         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5059         IUnknown_Release(clone);
5060 
5061         {
5062             /* test [GS]etBoneOffsetMatrix */
5063             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 1, &identity_matrix);
5064             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5065 
5066             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, NULL);
5067             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5068 
5069             D3DXMatrixIdentity(&identity_matrix);
5070             hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, &identity_matrix);
5071             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5072 
5073             transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, 0);
5074             check_matrix(transform, &identity_matrix);
5075         }
5076 
5077         {
5078             /* test [GS]etBoneName */
5079             const char *name_in = "testBoneName";
5080             const char *string_result2;
5081 
5082             hr = skininfo->lpVtbl->SetBoneName(skininfo, 1, name_in);
5083             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5084 
5085             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, NULL);
5086             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5087 
5088             hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, name_in);
5089             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5090 
5091             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5092             ok(string_result != NULL, "Expected non-NULL string, got %p\n", string_result);
5093             ok(!strcmp(string_result, name_in), "Expected '%s', got '%s'\n", name_in, string_result);
5094 
5095             string_result2 = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5096             ok(string_result == string_result2, "Expected %p, got %p\n", string_result, string_result2);
5097 
5098             string_result = skininfo->lpVtbl->GetBoneName(skininfo, 1);
5099             ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
5100         }
5101 
5102         {
5103             /* test [GS]etBoneInfluence */
5104             DWORD num_influences;
5105 
5106             /* vertex and weight arrays untouched when num_influences is 0 */
5107             vertices[0] = 0xdeadbeef;
5108             weights[0] = FLT_MAX;
5109             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5110             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5111             ok(vertices[0] == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", vertices[0]);
5112             ok(weights[0] == FLT_MAX, "expected %g, got %g\n", FLT_MAX, weights[0]);
5113 
5114             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 1, vertices, weights);
5115             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5116 
5117             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, NULL);
5118             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5119 
5120             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, NULL);
5121             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5122 
5123             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, weights);
5124             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5125 
5126 
5127             /* no vertex or weight value checking */
5128             exp_vertices[0] = 0;
5129             exp_vertices[1] = 0x87654321;
5130             exp_weights[0] = 0.5;
5131             exp_weights[1] = NAN;
5132             num_influences = 2;
5133 
5134             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 1, num_influences, vertices, weights);
5135             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5136 
5137             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, weights);
5138             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5139 
5140             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, vertices, NULL);
5141             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5142 
5143             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, NULL);
5144             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5145 
5146             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, exp_vertices, exp_weights);
5147             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5148 
5149             memset(vertices, 0, sizeof(vertices));
5150             memset(weights, 0, sizeof(weights));
5151             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5152             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5153             for (i = 0; i < num_influences; i++) {
5154                 ok(exp_vertices[i] == vertices[i],
5155                    "influence[%d]: expected vertex %u, got %u\n", i, exp_vertices[i], vertices[i]);
5156                 ok((isnan(exp_weights[i]) && isnan(weights[i])) || exp_weights[i] == weights[i],
5157                    "influence[%d]: expected weights %g, got %g\n", i, exp_weights[i], weights[i]);
5158             }
5159 
5160             /* vertices and weights aren't returned after setting num_influences to 0 */
5161             memset(vertices, 0, sizeof(vertices));
5162             memset(weights, 0, sizeof(weights));
5163             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, 0, vertices, weights);
5164             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5165 
5166             vertices[0] = 0xdeadbeef;
5167             weights[0] = FLT_MAX;
5168             hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
5169             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5170             ok(vertices[0] == 0xdeadbeef, "expected vertex 0xdeadbeef, got %u\n", vertices[0]);
5171             ok(weights[0] == FLT_MAX, "expected weight %g, got %g\n", FLT_MAX, weights[0]);
5172 
5173             hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, exp_vertices, exp_weights);
5174             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5175         }
5176 
5177         {
5178             /* test [GS]etFVF and [GS]etDeclaration */
5179             D3DVERTEXELEMENT9 declaration_in[MAX_FVF_DECL_SIZE];
5180             DWORD got_fvf;
5181 
5182             fvf = D3DFVF_XYZ;
5183             hr = skininfo->lpVtbl->SetDeclaration(skininfo, NULL);
5184             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5185 
5186             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_with_nonzero_stream);
5187             ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5188 
5189             hr = skininfo->lpVtbl->SetFVF(skininfo, 0);
5190             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5191 
5192             hr = D3DXDeclaratorFromFVF(fvf, declaration_in);
5193             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5194             hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_in);
5195             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5196             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5197             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
5198             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5199             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5200             compare_elements(declaration_out, declaration_in, __LINE__, 0);
5201 
5202             hr = skininfo->lpVtbl->SetDeclaration(skininfo, empty_declaration);
5203             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5204             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5205             ok(got_fvf == 0, "Expected 0, got %#x\n", got_fvf);
5206             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5207             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5208             compare_elements(declaration_out, empty_declaration, __LINE__, 0);
5209 
5210             hr = skininfo->lpVtbl->SetFVF(skininfo, fvf);
5211             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5212             got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
5213             ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
5214             hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
5215             ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5216             compare_elements(declaration_out, declaration_in, __LINE__, 0);
5217         }
5218 
5219         /* Test Clone() */
5220         hr = skininfo->lpVtbl->Clone(skininfo, NULL);
5221         ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#x.\n", hr);
5222 
5223         clone = NULL;
5224         hr = skininfo->lpVtbl->Clone(skininfo, &clone);
5225         ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
5226 
5227         hr = clone->lpVtbl->GetDeclaration(clone, declaration);
5228         ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
5229         compare_elements(declaration, declaration_out, __LINE__, 0);
5230 
5231         hr = D3DXFVFFromDeclarator(declaration_out, &exp_fvf);
5232         ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
5233         fvf = clone->lpVtbl->GetFVF(clone);
5234         ok(fvf == exp_fvf, "Got unexpected fvf %#x.\n", fvf);
5235 
5236         exp_string = skininfo->lpVtbl->GetBoneName(skininfo, 0);
5237         string = clone->lpVtbl->GetBoneName(clone, 0);
5238         ok(!strcmp(string, exp_string), "Got unexpected bone 0 name %s.\n", debugstr_a(string));
5239 
5240         transform = clone->lpVtbl->GetBoneOffsetMatrix(clone, 0);
5241         check_matrix(transform, &identity_matrix);
5242 
5243         hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, exp_vertices, exp_weights);
5244         ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
5245         hr = clone->lpVtbl->GetBoneInfluence(clone, 0, vertices, weights);
5246         ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
5247 
5248         for (i = 0; i < ARRAY_SIZE(vertices); ++i)
5249         {
5250             ok(vertices[i] == exp_vertices[i], "influence[%u]: got unexpected vertex %u, expected %u.\n",
5251                     i, vertices[i], exp_vertices[i]);
5252             ok(((DWORD *)weights)[i] == ((DWORD *)exp_weights)[i],
5253                     "influence[%u]: got unexpected weight %.8e, expected %.8e.\n", i, weights[i], exp_weights[i]);
5254         }
5255 
5256         IUnknown_Release(clone);
5257     }
5258     if (skininfo) IUnknown_Release(skininfo);
5259     skininfo = NULL;
5260 
5261     hr = D3DXCreateSkinInfoFVF(1, D3DFVF_XYZ, 1, NULL);
5262     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5263 
5264     hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
5265     ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
5266 }
5267 
test_update_skinned_mesh(void)5268 static void test_update_skinned_mesh(void)
5269 {
5270     static DWORD bone0_vertices[2] = { 1, 3 };
5271     static FLOAT bone0_weights[2] = { 1.0f, 0.5f };
5272     static DWORD bone1_vertices[2] = { 2, 3 };
5273     static FLOAT bone1_weights[2] = { 1.0f, 0.5f };
5274     static D3DMATRIX bones_matrix[2] =
5275     { { { {
5276                1.0f,  0.0f,  0.0f,  0.0f,
5277                0.0f,  1.0f,  0.0f,  0.0f,
5278                0.0f,  0.0f,  1.0f,  0.0f,
5279                2.0f,  2.0f,  4.0f,  1.0f
5280       } } },
5281       { { {
5282                1.0f,  0.0f,  0.0f,  0.0f,
5283                0.0f,  1.0f,  0.0f,  0.0f,
5284                0.0f,  0.0f,  1.0f,  0.0f,
5285               -4.0f, -4.0f,  4.0f,  1.0f
5286       } } } };
5287     static D3DVECTOR vertices_src[] = {{  1.0f,  1.0f,  1.0f },
5288                                        {  1.0f,  0.0f,  0.0f },
5289                                        {  1.0f,  1.0f, -1.0f },
5290                                        {  0.0f,  1.0f,  0.0f },
5291                                        { -1.0f, -1.0f,  1.0f },
5292                                        {  0.0f,  0.0f,  1.0f },
5293                                        { -1.0f, -1.0f, -1.0f },
5294                                        { -1.0f,  0.0f,  0.0f },
5295                                       };
5296     static D3DVECTOR vertices_ref[] = {{  0.0f,  0.0f,  0.0f },
5297                                        {  0.0f,  0.0f,  0.0f },
5298                                        {  3.0f,  3.0f,  3.0f },
5299                                        {  0.0f,  1.0f,  0.0f },
5300                                        { -5.0f, -5.0f,  5.0f },
5301                                        {  0.0f,  0.0f,  1.0f },
5302                                        { -2.0f, -2.0f,  3.0f },
5303                                        { -1.0f,  0.0f,  0.0f },
5304                                       };
5305     D3DVECTOR vertices_dest[8];
5306     HRESULT hr;
5307     ID3DXSkinInfo *skin_info;
5308     D3DXMATRIX matrix;
5309     int i;
5310 
5311     D3DXMatrixIdentity(&matrix);
5312     for (i = 0; i < 8; i++)
5313     {
5314         vertices_dest[i].x = 10000.0f;
5315         vertices_dest[i].y = 10000.0f;
5316         vertices_dest[i].z = 10000.0f;
5317     }
5318 
5319     hr = D3DXCreateSkinInfoFVF(4, D3DFVF_XYZ | D3DFVF_NORMAL, 2, &skin_info);
5320     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5321 
5322     skin_info->lpVtbl->SetBoneInfluence(skin_info, 0, 2, bone0_vertices, bone0_weights);
5323     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5324     skin_info->lpVtbl->SetBoneOffsetMatrix(skin_info, 0, &matrix);
5325     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5326     skin_info->lpVtbl->SetBoneInfluence(skin_info, 1, 2, bone1_vertices, bone1_weights);
5327     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5328     skin_info->lpVtbl->SetBoneOffsetMatrix(skin_info, 1, &matrix);
5329     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5330     skin_info->lpVtbl->UpdateSkinnedMesh(skin_info, bones_matrix, NULL, vertices_src, vertices_dest);
5331     ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
5332     for (i = 0; i < 4; i++)
5333     {
5334         ok(compare(vertices_dest[i*2].x, vertices_ref[i*2].x), "Vertex[%d].position.x: got %g, expected %g\n",
5335            i, vertices_dest[i*2].x, vertices_ref[i*2].x);
5336         ok(compare(vertices_dest[i*2].y, vertices_ref[i*2].y), "Vertex[%d].position.y: got %g, expected %g\n",
5337            i, vertices_dest[i*2].y, vertices_ref[i*2].y);
5338         ok(compare(vertices_dest[i*2].z, vertices_ref[i*2].z), "Vertex[%d].position.z: got %g, expected %g\n",
5339            i, vertices_dest[i*2].z, vertices_ref[i*2].z);
5340         ok(compare(vertices_dest[i*2+1].x, vertices_ref[i*2+1].x), "Vertex[%d].normal.x: got %g, expected %g\n",
5341            i, vertices_dest[i*2+1].x, vertices_ref[i*2+1].x);
5342         ok(compare(vertices_dest[i*2+1].y, vertices_ref[i*2+1].y), "Vertex[%d].normal.y: got %g, expected %g\n",
5343            i, vertices_dest[i*2+1].y, vertices_ref[i*2+1].y);
5344         ok(compare(vertices_dest[i*2+1].z, vertices_ref[i*2+1].z), "Vertex[%d].normal.z: got %g, expected %g\n",
5345            i, vertices_dest[i*2+1].z, vertices_ref[i*2+1].z);
5346     }
5347     skin_info->lpVtbl->Release(skin_info);
5348 }
5349 
test_convert_adjacency_to_point_reps(void)5350 static void test_convert_adjacency_to_point_reps(void)
5351 {
5352     HRESULT hr;
5353     struct test_context *test_context = NULL;
5354     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5355     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5356     const D3DVERTEXELEMENT9 declaration[] =
5357     {
5358         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5359         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5360         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5361         D3DDECL_END()
5362     };
5363     const unsigned int VERTS_PER_FACE = 3;
5364     void *vertex_buffer;
5365     void *index_buffer;
5366     DWORD *attributes_buffer;
5367     int i, j;
5368     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5369     struct vertex_pnc
5370     {
5371         D3DXVECTOR3 position;
5372         D3DXVECTOR3 normal;
5373         enum color color; /* In case of manual visual inspection */
5374     };
5375 #ifndef __REACTOS__
5376     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5377 #else
5378 #define up {0.0f, 0.0f, 1.0f}
5379 #endif
5380     /* mesh0 (one face)
5381      *
5382      * 0--1
5383      * | /
5384      * |/
5385      * 2
5386      */
5387     const struct vertex_pnc vertices0[] =
5388     {
5389         {{ 0.0f,  3.0f,  0.f}, up, RED},
5390         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5391         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5392     };
5393     const DWORD indices0[] = {0, 1, 2};
5394     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5395     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
5396     const DWORD adjacency0[] = {-1, -1, -1};
5397     const DWORD exp_point_rep0[] = {0, 1, 2};
5398     /* mesh1 (right)
5399      *
5400      * 0--1 3
5401      * | / /|
5402      * |/ / |
5403      * 2 5--4
5404      */
5405     const struct vertex_pnc vertices1[] =
5406     {
5407         {{ 0.0f,  3.0f,  0.f}, up, RED},
5408         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5409         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5410 
5411         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5412         {{ 3.0f,  0.0f,  0.f}, up, RED},
5413         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5414     };
5415     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5416     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5417     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
5418     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
5419     const DWORD exp_point_rep1[] = {0, 1, 2, 1, 4, 2};
5420     /* mesh2 (left)
5421      *
5422      *    3 0--1
5423      *   /| | /
5424      *  / | |/
5425      * 5--4 2
5426      */
5427     const struct vertex_pnc vertices2[] =
5428     {
5429         {{ 0.0f,  3.0f,  0.f}, up, RED},
5430         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5431         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5432 
5433         {{-1.0f,  3.0f,  0.f}, up, RED},
5434         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5435         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5436     };
5437     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5438     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5439     const unsigned int num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
5440     const DWORD adjacency2[] = {-1, -1, 1, 0, -1, -1};
5441     const DWORD exp_point_rep2[] = {0, 1, 2, 0, 2, 5};
5442     /* mesh3 (above)
5443      *
5444      *    3
5445      *   /|
5446      *  / |
5447      * 5--4
5448      * 0--1
5449      * | /
5450      * |/
5451      * 2
5452      */
5453     struct vertex_pnc vertices3[] =
5454     {
5455         {{ 0.0f,  3.0f,  0.f}, up, RED},
5456         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5457         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5458 
5459         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5460         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5461         {{ 0.0f,  4.0f,  0.f}, up, RED},
5462     };
5463     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5464     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5465     const unsigned int num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
5466     const DWORD adjacency3[] = {1, -1, -1, -1, 0, -1};
5467     const DWORD exp_point_rep3[] = {0, 1, 2, 3, 1, 0};
5468     /* mesh4 (below, tip against tip)
5469      *
5470      * 0--1
5471      * | /
5472      * |/
5473      * 2
5474      * 3
5475      * |\
5476      * | \
5477      * 5--4
5478      */
5479     struct vertex_pnc vertices4[] =
5480     {
5481         {{ 0.0f,  3.0f,  0.f}, up, RED},
5482         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5483         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5484 
5485         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
5486         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
5487         {{ 0.0f, -7.0f,  0.f}, up, RED},
5488     };
5489     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5490     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5491     const unsigned int num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
5492     const DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
5493     const DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
5494     /* mesh5 (gap in mesh)
5495      *
5496      *    0      3-----4  15
5497      *   / \      \   /  /  \
5498      *  /   \      \ /  /    \
5499      * 2-----1      5 17-----16
5500      * 6-----7      9 12-----13
5501      *  \   /      / \  \    /
5502      *   \ /      /   \  \  /
5503      *    8     10-----11 14
5504      *
5505      */
5506     const struct vertex_pnc vertices5[] =
5507     {
5508         {{ 0.0f,  1.0f,  0.f}, up, RED},
5509         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
5510         {{-1.0f, -1.0f,  0.f}, up, BLUE},
5511 
5512         {{ 0.1f,  1.0f,  0.f}, up, RED},
5513         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
5514         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
5515 
5516         {{-1.0f, -1.1f,  0.f}, up, BLUE},
5517         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
5518         {{ 0.0f, -3.1f,  0.f}, up, RED},
5519 
5520         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
5521         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
5522         {{ 0.1f, -3.1f,  0.f}, up, RED},
5523 
5524         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
5525         {{ 3.2f, -1.1f,  0.f}, up, RED},
5526         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
5527 
5528         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
5529         {{ 3.2f, -1.0f,  0.f}, up, RED},
5530         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
5531     };
5532     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5533     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5534     const unsigned int num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
5535     const DWORD adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5536     const DWORD exp_point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5537     const WORD indices5_16bit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5538     /* mesh6 (indices re-ordering)
5539      *
5540      * 0--1 6 3
5541      * | / /| |\
5542      * |/ / | | \
5543      * 2 8--7 5--4
5544      */
5545     const struct vertex_pnc vertices6[] =
5546     {
5547         {{ 0.0f,  3.0f,  0.f}, up, RED},
5548         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5549         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5550 
5551         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5552         {{ 3.0f,  0.0f,  0.f}, up, RED},
5553         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5554 
5555         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5556         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5557         {{ 4.0f,  0.0f,  0.f}, up, RED},
5558     };
5559     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5560     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5561     const unsigned int num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
5562     const DWORD adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5563     const DWORD exp_point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5564     /* mesh7 (expands collapsed triangle)
5565      *
5566      * 0--1 3
5567      * | / /|
5568      * |/ / |
5569      * 2 5--4
5570      */
5571     const struct vertex_pnc vertices7[] =
5572     {
5573         {{ 0.0f,  3.0f,  0.f}, up, RED},
5574         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5575         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5576 
5577         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5578         {{ 3.0f,  0.0f,  0.f}, up, RED},
5579         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5580     };
5581     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5582     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5583     const unsigned int num_faces7 = ARRAY_SIZE(indices7) / VERTS_PER_FACE;
5584     const DWORD adjacency7[] = {-1, -1, -1, -1, -1, -1};
5585     const DWORD exp_point_rep7[] = {0, 1, 2, 3, 4, 5};
5586     /* mesh8 (indices re-ordering and double replacement)
5587      *
5588      * 0--1 9  6
5589      * | / /|  |\
5590      * |/ / |  | \
5591      * 2 11-10 8--7
5592      *         3--4
5593      *         | /
5594      *         |/
5595      *         5
5596      */
5597     const struct vertex_pnc vertices8[] =
5598     {
5599         {{ 0.0f,  3.0f,  0.f}, up, RED},
5600         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5601         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5602 
5603         {{ 4.0,  -4.0,  0.f}, up, RED},
5604         {{ 6.0,  -4.0,  0.f}, up, BLUE},
5605         {{ 4.0,  -7.0,  0.f}, up, GREEN},
5606 
5607         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
5608         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
5609         {{ 4.0f,  0.0f,  0.f}, up, RED},
5610 
5611         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5612         {{ 3.0f,  0.0f,  0.f}, up, RED},
5613         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5614     };
5615     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5616     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5617     const unsigned int num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
5618     const DWORD adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5619     const DWORD exp_point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5620     /* mesh9 (right, shared vertices)
5621      *
5622      * 0--1
5623      * | /|
5624      * |/ |
5625      * 2--3
5626      */
5627     const struct vertex_pnc vertices9[] =
5628     {
5629         {{ 0.0f,  3.0f,  0.f}, up, RED},
5630         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5631         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5632 
5633         {{ 2.0f,  0.0f,  0.f}, up, RED},
5634     };
5635     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5636     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5637     const unsigned int num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
5638     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
5639     const DWORD exp_point_rep9[] = {0, 1, 2, 3};
5640     /* All mesh data */
5641     ID3DXMesh *mesh = NULL;
5642     ID3DXMesh *mesh_null_check = NULL;
5643     unsigned int attributes[] = {0};
5644     struct
5645     {
5646         const struct vertex_pnc *vertices;
5647         const DWORD *indices;
5648         const DWORD num_vertices;
5649         const DWORD num_faces;
5650         const DWORD *adjacency;
5651         const DWORD *exp_point_reps;
5652         const DWORD options;
5653     }
5654     tc[] =
5655     {
5656         {
5657             vertices0,
5658             indices0,
5659             num_vertices0,
5660             num_faces0,
5661             adjacency0,
5662             exp_point_rep0,
5663             options
5664         },
5665         {
5666             vertices1,
5667             indices1,
5668             num_vertices1,
5669             num_faces1,
5670             adjacency1,
5671             exp_point_rep1,
5672             options
5673         },
5674         {
5675             vertices2,
5676             indices2,
5677             num_vertices2,
5678             num_faces2,
5679             adjacency2,
5680             exp_point_rep2,
5681             options
5682         },
5683         {
5684             vertices3,
5685             indices3,
5686             num_vertices3,
5687             num_faces3,
5688             adjacency3,
5689             exp_point_rep3,
5690             options
5691         },
5692         {
5693             vertices4,
5694             indices4,
5695             num_vertices4,
5696             num_faces4,
5697             adjacency4,
5698             exp_point_rep4,
5699             options
5700         },
5701         {
5702             vertices5,
5703             indices5,
5704             num_vertices5,
5705             num_faces5,
5706             adjacency5,
5707             exp_point_rep5,
5708             options
5709         },
5710         {
5711             vertices6,
5712             indices6,
5713             num_vertices6,
5714             num_faces6,
5715             adjacency6,
5716             exp_point_rep6,
5717             options
5718         },
5719         {
5720             vertices7,
5721             indices7,
5722             num_vertices7,
5723             num_faces7,
5724             adjacency7,
5725             exp_point_rep7,
5726             options
5727         },
5728         {
5729             vertices8,
5730             indices8,
5731             num_vertices8,
5732             num_faces8,
5733             adjacency8,
5734             exp_point_rep8,
5735             options
5736         },
5737         {
5738             vertices9,
5739             indices9,
5740             num_vertices9,
5741             num_faces9,
5742             adjacency9,
5743             exp_point_rep9,
5744             options
5745         },
5746         {
5747             vertices5,
5748             (DWORD*)indices5_16bit,
5749             num_vertices5,
5750             num_faces5,
5751             adjacency5,
5752             exp_point_rep5,
5753             options_16bit
5754         },
5755     };
5756     DWORD *point_reps = NULL;
5757 
5758     test_context = new_test_context();
5759     if (!test_context)
5760     {
5761         skip("Couldn't create test context\n");
5762         goto cleanup;
5763     }
5764 
5765     for (i = 0; i < ARRAY_SIZE(tc); i++)
5766     {
5767         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options, declaration,
5768                             test_context->device, &mesh);
5769         if (FAILED(hr))
5770         {
5771             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5772             goto cleanup;
5773         }
5774 
5775         if (i == 0) /* Save first mesh for later NULL checks */
5776             mesh_null_check = mesh;
5777 
5778         point_reps = HeapAlloc(GetProcessHeap(), 0, tc[i].num_vertices * sizeof(*point_reps));
5779         if (!point_reps)
5780         {
5781             skip("Couldn't allocate point reps array.\n");
5782             goto cleanup;
5783         }
5784 
5785         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5786         if (FAILED(hr))
5787         {
5788             skip("Couldn't lock vertex buffer.\n");
5789             goto cleanup;
5790         }
5791         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5792         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5793         if (FAILED(hr))
5794         {
5795             skip("Couldn't unlock vertex buffer.\n");
5796             goto cleanup;
5797         }
5798 
5799         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5800         if (FAILED(hr))
5801         {
5802             skip("Couldn't lock index buffer.\n");
5803             goto cleanup;
5804         }
5805         if (tc[i].options & D3DXMESH_32BIT)
5806         {
5807             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5808         }
5809         else
5810         {
5811             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5812         }
5813         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5814         if (FAILED(hr)) {
5815             skip("Couldn't unlock index buffer.\n");
5816             goto cleanup;
5817         }
5818 
5819         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5820         if (FAILED(hr))
5821         {
5822             skip("Couldn't lock attributes buffer.\n");
5823             goto cleanup;
5824         }
5825         memcpy(attributes_buffer, attributes, sizeof(attributes));
5826         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5827         if (FAILED(hr))
5828         {
5829             skip("Couldn't unlock attributes buffer.\n");
5830             goto cleanup;
5831         }
5832 
5833         /* Convert adjacency to point representation */
5834         for (j = 0; j < tc[i].num_vertices; j++) point_reps[j] = -1;
5835         hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacency, point_reps);
5836         ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
5837            "Got %x expected D3D_OK\n", i, hr);
5838 
5839         /* Check point representation */
5840         for (j = 0; j < tc[i].num_vertices; j++)
5841         {
5842             ok(point_reps[j] == tc[i].exp_point_reps[j],
5843                "Unexpected point representation at (%d, %d)."
5844                " Got %d expected %d\n",
5845                i, j, point_reps[j], tc[i].exp_point_reps[j]);
5846         }
5847 
5848         HeapFree(GetProcessHeap(), 0, point_reps);
5849         point_reps = NULL;
5850 
5851         if (i != 0) /* First mesh will be freed during cleanup */
5852             mesh->lpVtbl->Release(mesh);
5853     }
5854 
5855     /* NULL checks */
5856     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacency, NULL);
5857     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
5858        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5859     hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, NULL);
5860     ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. "
5861        "Got %x expected D3DERR_INVALIDCALL\n", hr);
5862 
5863 cleanup:
5864     if (mesh_null_check)
5865         mesh_null_check->lpVtbl->Release(mesh_null_check);
5866     HeapFree(GetProcessHeap(), 0, point_reps);
5867     free_test_context(test_context);
5868 #ifdef __REACTOS__
5869 #undef up
5870 #endif
5871 }
5872 
test_convert_point_reps_to_adjacency(void)5873 static void test_convert_point_reps_to_adjacency(void)
5874 {
5875     HRESULT hr;
5876     struct test_context *test_context = NULL;
5877     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5878     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5879     const D3DVERTEXELEMENT9 declaration[] =
5880     {
5881         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5882         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5883         {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5884         D3DDECL_END()
5885     };
5886     const unsigned int VERTS_PER_FACE = 3;
5887     void *vertex_buffer;
5888     void *index_buffer;
5889     DWORD *attributes_buffer;
5890     int i, j;
5891     enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5892     struct vertex_pnc
5893     {
5894         D3DXVECTOR3 position;
5895         D3DXVECTOR3 normal;
5896         enum color color; /* In case of manual visual inspection */
5897     };
5898 #ifndef __REACTOS__
5899     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5900 #else
5901 #define up {0.0f, 0.0f, 1.0f}
5902 #endif
5903 
5904     /* mesh0 (one face)
5905      *
5906      * 0--1
5907      * | /
5908      * |/
5909      * 2
5910      */
5911     const struct vertex_pnc vertices0[] =
5912     {
5913         {{ 0.0f,  3.0f,  0.f}, up, RED},
5914         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5915         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5916     };
5917     const DWORD indices0[] = {0, 1, 2};
5918     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5919     const unsigned int num_faces0 = num_vertices0 / VERTS_PER_FACE;
5920     const DWORD exp_adjacency0[] = {-1, -1, -1};
5921     const DWORD exp_id_adjacency0[] = {-1, -1, -1};
5922     const DWORD point_rep0[] = {0, 1, 2};
5923     /* mesh1 (right)
5924      *
5925      * 0--1 3
5926      * | / /|
5927      * |/ / |
5928      * 2 5--4
5929      */
5930     const struct vertex_pnc vertices1[] =
5931     {
5932         {{ 0.0f,  3.0f,  0.f}, up, RED},
5933         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5934         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5935 
5936         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
5937         {{ 3.0f,  0.0f,  0.f}, up, RED},
5938         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
5939     };
5940     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5941     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5942     const unsigned int num_faces1 = num_vertices1 / VERTS_PER_FACE;
5943     const DWORD exp_adjacency1[] = {-1, 1, -1, -1, -1, 0};
5944     const DWORD exp_id_adjacency1[] = {-1, -1, -1, -1, -1, -1};
5945     const DWORD point_rep1[] = {0, 1, 2, 1, 4, 2};
5946     /* mesh2 (left)
5947      *
5948      *    3 0--1
5949      *   /| | /
5950      *  / | |/
5951      * 5--4 2
5952      */
5953     const struct vertex_pnc vertices2[] =
5954     {
5955         {{ 0.0f,  3.0f,  0.f}, up, RED},
5956         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5957         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5958 
5959         {{-1.0f,  3.0f,  0.f}, up, RED},
5960         {{-1.0f,  0.0f,  0.f}, up, GREEN},
5961         {{-3.0f,  0.0f,  0.f}, up, BLUE},
5962     };
5963     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5964     const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5965     const unsigned int num_faces2 = num_vertices2 / VERTS_PER_FACE;
5966     const DWORD exp_adjacency2[] = {-1, -1, 1, 0, -1, -1};
5967     const DWORD exp_id_adjacency2[] = {-1, -1, -1, -1, -1, -1};
5968     const DWORD point_rep2[] = {0, 1, 2, 0, 2, 5};
5969     /* mesh3 (above)
5970      *
5971      *    3
5972      *   /|
5973      *  / |
5974      * 5--4
5975      * 0--1
5976      * | /
5977      * |/
5978      * 2
5979      */
5980     struct vertex_pnc vertices3[] =
5981     {
5982         {{ 0.0f,  3.0f,  0.f}, up, RED},
5983         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
5984         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
5985 
5986         {{ 2.0f,  7.0f,  0.f}, up, BLUE},
5987         {{ 2.0f,  4.0f,  0.f}, up, GREEN},
5988         {{ 0.0f,  4.0f,  0.f}, up, RED},
5989     };
5990     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5991     const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5992     const unsigned int num_faces3 = num_vertices3 / VERTS_PER_FACE;
5993     const DWORD exp_adjacency3[] = {1, -1, -1, -1, 0, -1};
5994     const DWORD exp_id_adjacency3[] = {-1, -1, -1, -1, -1, -1};
5995     const DWORD point_rep3[] = {0, 1, 2, 3, 1, 0};
5996     /* mesh4 (below, tip against tip)
5997      *
5998      * 0--1
5999      * | /
6000      * |/
6001      * 2
6002      * 3
6003      * |\
6004      * | \
6005      * 5--4
6006      */
6007     struct vertex_pnc vertices4[] =
6008     {
6009         {{ 0.0f,  3.0f,  0.f}, up, RED},
6010         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6011         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6012 
6013         {{ 0.0f, -4.0f,  0.f}, up, BLUE},
6014         {{ 2.0f, -7.0f,  0.f}, up, GREEN},
6015         {{ 0.0f, -7.0f,  0.f}, up, RED},
6016     };
6017     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
6018     const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
6019     const unsigned int num_faces4 = num_vertices4 / VERTS_PER_FACE;
6020     const DWORD exp_adjacency4[] = {-1, -1, -1, -1, -1, -1};
6021     const DWORD exp_id_adjacency4[] = {-1, -1, -1, -1, -1, -1};
6022     const DWORD point_rep4[] = {0, 1, 2, 3, 4, 5};
6023     /* mesh5 (gap in mesh)
6024      *
6025      *    0      3-----4  15
6026      *   / \      \   /  /  \
6027      *  /   \      \ /  /    \
6028      * 2-----1      5 17-----16
6029      * 6-----7      9 12-----13
6030      *  \   /      / \  \    /
6031      *   \ /      /   \  \  /
6032      *    8     10-----11 14
6033      *
6034      */
6035     const struct vertex_pnc vertices5[] =
6036     {
6037         {{ 0.0f,  1.0f,  0.f}, up, RED},
6038         {{ 1.0f, -1.0f,  0.f}, up, GREEN},
6039         {{-1.0f, -1.0f,  0.f}, up, BLUE},
6040 
6041         {{ 0.1f,  1.0f,  0.f}, up, RED},
6042         {{ 2.1f,  1.0f,  0.f}, up, BLUE},
6043         {{ 1.1f, -1.0f,  0.f}, up, GREEN},
6044 
6045         {{-1.0f, -1.1f,  0.f}, up, BLUE},
6046         {{ 1.0f, -1.1f,  0.f}, up, GREEN},
6047         {{ 0.0f, -3.1f,  0.f}, up, RED},
6048 
6049         {{ 1.1f, -1.1f,  0.f}, up, GREEN},
6050         {{ 2.1f, -3.1f,  0.f}, up, BLUE},
6051         {{ 0.1f, -3.1f,  0.f}, up, RED},
6052 
6053         {{ 1.2f, -1.1f,  0.f}, up, GREEN},
6054         {{ 3.2f, -1.1f,  0.f}, up, RED},
6055         {{ 2.2f, -3.1f,  0.f}, up, BLUE},
6056 
6057         {{ 2.2f,  1.0f,  0.f}, up, BLUE},
6058         {{ 3.2f, -1.0f,  0.f}, up, RED},
6059         {{ 1.2f, -1.0f,  0.f}, up, GREEN},
6060     };
6061     const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
6062     const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
6063     const unsigned int num_faces5 = num_vertices5 / VERTS_PER_FACE;
6064     const DWORD exp_adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
6065     const DWORD exp_id_adjacency5[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
6066     const DWORD point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
6067     /* mesh6 (indices re-ordering)
6068      *
6069      * 0--1 6 3
6070      * | / /| |\
6071      * |/ / | | \
6072      * 2 8--7 5--4
6073      */
6074     const struct vertex_pnc vertices6[] =
6075     {
6076         {{ 0.0f,  3.0f,  0.f}, up, RED},
6077         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6078         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6079 
6080         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
6081         {{ 3.0f,  0.0f,  0.f}, up, RED},
6082         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
6083 
6084         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
6085         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
6086         {{ 4.0f,  0.0f,  0.f}, up, RED},
6087     };
6088     const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
6089     const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
6090     const unsigned int num_faces6 = num_vertices6 / VERTS_PER_FACE;
6091     const DWORD exp_adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
6092     const DWORD exp_id_adjacency6[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1};
6093     const DWORD point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
6094     /* mesh7 (expands collapsed triangle)
6095      *
6096      * 0--1 3
6097      * | / /|
6098      * |/ / |
6099      * 2 5--4
6100      */
6101     const struct vertex_pnc vertices7[] =
6102     {
6103         {{ 0.0f,  3.0f,  0.f}, up, RED},
6104         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6105         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6106 
6107         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
6108         {{ 3.0f,  0.0f,  0.f}, up, RED},
6109         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
6110     };
6111     const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
6112     const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
6113     const unsigned int num_faces7 = num_vertices7 / VERTS_PER_FACE;
6114     const DWORD exp_adjacency7[] = {-1, -1, -1, -1, -1, -1};
6115     const DWORD exp_id_adjacency7[] = {-1, -1, -1, -1, -1, -1};
6116     const DWORD point_rep7[] = {0, 1, 2, 3, 4, 5};
6117     /* mesh8 (indices re-ordering and double replacement)
6118      *
6119      * 0--1 9  6
6120      * | / /|  |\
6121      * |/ / |  | \
6122      * 2 11-10 8--7
6123      *         3--4
6124      *         | /
6125      *         |/
6126      *         5
6127      */
6128     const struct vertex_pnc vertices8[] =
6129     {
6130         {{ 0.0f,  3.0f,  0.f}, up, RED},
6131         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6132         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6133 
6134         {{ 4.0,  -4.0,  0.f}, up, RED},
6135         {{ 6.0,  -4.0,  0.f}, up, BLUE},
6136         {{ 4.0,  -7.0,  0.f}, up, GREEN},
6137 
6138         {{ 4.0f,  3.0f,  0.f}, up, GREEN},
6139         {{ 6.0f,  0.0f,  0.f}, up, BLUE},
6140         {{ 4.0f,  0.0f,  0.f}, up, RED},
6141 
6142         {{ 3.0f,  3.0f,  0.f}, up, GREEN},
6143         {{ 3.0f,  0.0f,  0.f}, up, RED},
6144         {{ 1.0f,  0.0f,  0.f}, up, BLUE},
6145     };
6146     const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
6147     const WORD indices8_16bit[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
6148     const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
6149     const unsigned int num_faces8 = num_vertices8 / VERTS_PER_FACE;
6150     const DWORD exp_adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
6151     const DWORD exp_id_adjacency8[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
6152     const DWORD point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
6153      /* mesh9 (right, shared vertices)
6154      *
6155      * 0--1
6156      * | /|
6157      * |/ |
6158      * 2--3
6159      */
6160     const struct vertex_pnc vertices9[] =
6161     {
6162         {{ 0.0f,  3.0f,  0.f}, up, RED},
6163         {{ 2.0f,  3.0f,  0.f}, up, GREEN},
6164         {{ 0.0f,  0.0f,  0.f}, up, BLUE},
6165 
6166         {{ 2.0f,  0.0f,  0.f}, up, RED},
6167     };
6168     const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
6169     const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
6170     const unsigned int num_faces9 = 2;
6171     const DWORD exp_adjacency9[] = {-1, 1, -1, -1, -1, 0};
6172     const DWORD exp_id_adjacency9[] = {-1, 1, -1, -1, -1, 0};
6173     const DWORD point_rep9[] = {0, 1, 2, 3};
6174     /* All mesh data */
6175     ID3DXMesh *mesh = NULL;
6176     ID3DXMesh *mesh_null_check = NULL;
6177     unsigned int attributes[] = {0};
6178     struct
6179     {
6180         const struct vertex_pnc *vertices;
6181         const DWORD *indices;
6182         const DWORD num_vertices;
6183         const DWORD num_faces;
6184         const DWORD *point_reps;
6185         const DWORD *exp_adjacency;
6186         const DWORD *exp_id_adjacency;
6187         const DWORD options;
6188     }
6189     tc[] =
6190     {
6191         {
6192             vertices0,
6193             indices0,
6194             num_vertices0,
6195             num_faces0,
6196             point_rep0,
6197             exp_adjacency0,
6198             exp_id_adjacency0,
6199             options
6200         },
6201         {
6202             vertices1,
6203             indices1,
6204             num_vertices1,
6205             num_faces1,
6206             point_rep1,
6207             exp_adjacency1,
6208             exp_id_adjacency1,
6209             options
6210         },
6211         {
6212             vertices2,
6213             indices2,
6214             num_vertices2,
6215             num_faces2,
6216             point_rep2,
6217             exp_adjacency2,
6218             exp_id_adjacency2,
6219             options
6220         },
6221         {
6222             vertices3,
6223             indices3,
6224             num_vertices3,
6225             num_faces3,
6226             point_rep3,
6227             exp_adjacency3,
6228             exp_id_adjacency3,
6229             options
6230         },
6231         {
6232             vertices4,
6233             indices4,
6234             num_vertices4,
6235             num_faces4,
6236             point_rep4,
6237             exp_adjacency4,
6238             exp_id_adjacency4,
6239             options
6240         },
6241         {
6242             vertices5,
6243             indices5,
6244             num_vertices5,
6245             num_faces5,
6246             point_rep5,
6247             exp_adjacency5,
6248             exp_id_adjacency5,
6249             options
6250         },
6251         {
6252             vertices6,
6253             indices6,
6254             num_vertices6,
6255             num_faces6,
6256             point_rep6,
6257             exp_adjacency6,
6258             exp_id_adjacency6,
6259             options
6260         },
6261         {
6262             vertices7,
6263             indices7,
6264             num_vertices7,
6265             num_faces7,
6266             point_rep7,
6267             exp_adjacency7,
6268             exp_id_adjacency7,
6269             options
6270         },
6271         {
6272             vertices8,
6273             indices8,
6274             num_vertices8,
6275             num_faces8,
6276             point_rep8,
6277             exp_adjacency8,
6278             exp_id_adjacency8,
6279             options
6280         },
6281         {
6282             vertices9,
6283             indices9,
6284             num_vertices9,
6285             num_faces9,
6286             point_rep9,
6287             exp_adjacency9,
6288             exp_id_adjacency9,
6289             options
6290         },
6291         {
6292             vertices8,
6293             (DWORD*)indices8_16bit,
6294             num_vertices8,
6295             num_faces8,
6296             point_rep8,
6297             exp_adjacency8,
6298             exp_id_adjacency8,
6299             options_16bit
6300         },
6301     };
6302     DWORD *adjacency = NULL;
6303 #ifdef __REACTOS__
6304 #undef up
6305 #endif
6306 
6307     test_context = new_test_context();
6308     if (!test_context)
6309     {
6310         skip("Couldn't create test context\n");
6311         goto cleanup;
6312     }
6313 
6314     for (i = 0; i < ARRAY_SIZE(tc); i++)
6315     {
6316         hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
6317                             declaration, test_context->device, &mesh);
6318         if (FAILED(hr))
6319         {
6320             skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
6321             goto cleanup;
6322         }
6323 
6324         if (i == 0) /* Save first mesh for later NULL checks */
6325             mesh_null_check = mesh;
6326 
6327         adjacency = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
6328         if (!adjacency)
6329         {
6330             skip("Couldn't allocate adjacency array.\n");
6331             goto cleanup;
6332         }
6333 
6334         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
6335         if (FAILED(hr))
6336         {
6337             skip("Couldn't lock vertex buffer.\n");
6338             goto cleanup;
6339         }
6340         memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
6341         hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6342         if (FAILED(hr))
6343         {
6344             skip("Couldn't unlock vertex buffer.\n");
6345             goto cleanup;
6346         }
6347         hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6348         if (FAILED(hr))
6349         {
6350             skip("Couldn't lock index buffer.\n");
6351             goto cleanup;
6352         }
6353         if (tc[i].options & D3DXMESH_32BIT)
6354         {
6355             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
6356         }
6357         else
6358         {
6359             memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
6360         }
6361         hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6362         if (FAILED(hr)) {
6363             skip("Couldn't unlock index buffer.\n");
6364             goto cleanup;
6365         }
6366 
6367         hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6368         if (FAILED(hr))
6369         {
6370             skip("Couldn't lock attributes buffer.\n");
6371             goto cleanup;
6372         }
6373         memcpy(attributes_buffer, attributes, sizeof(attributes));
6374         hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6375         if (FAILED(hr))
6376         {
6377             skip("Couldn't unlock attributes buffer.\n");
6378             goto cleanup;
6379         }
6380 
6381         /* Convert point representation to adjacency*/
6382         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
6383 
6384         hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
6385         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
6386            "Got %x expected D3D_OK\n", i, hr);
6387         /* Check adjacency */
6388         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
6389         {
6390             ok(adjacency[j] == tc[i].exp_adjacency[j],
6391                "Unexpected adjacency information at (%d, %d)."
6392                " Got %d expected %d\n",
6393                i, j, adjacency[j], tc[i].exp_adjacency[j]);
6394         }
6395 
6396         /* NULL point representation is considered identity. */
6397         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++) adjacency[j] = -2;
6398         hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
6399         ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
6400                      "Got %x expected D3D_OK\n", hr);
6401         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
6402         {
6403             ok(adjacency[j] == tc[i].exp_id_adjacency[j],
6404                "Unexpected adjacency information (id) at (%d, %d)."
6405                " Got %d expected %d\n",
6406                i, j, adjacency[j], tc[i].exp_id_adjacency[j]);
6407         }
6408 
6409         HeapFree(GetProcessHeap(), 0, adjacency);
6410         adjacency = NULL;
6411         if (i != 0) /* First mesh will be freed during cleanup */
6412             mesh->lpVtbl->Release(mesh);
6413     }
6414 
6415     /* NULL checks */
6416     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
6417     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
6418        "Got %x expected D3DERR_INVALIDCALL\n", hr);
6419     hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
6420     ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
6421        "Got %x expected D3DERR_INVALIDCALL\n", hr);
6422 
6423 cleanup:
6424     if (mesh_null_check)
6425         mesh_null_check->lpVtbl->Release(mesh_null_check);
6426     HeapFree(GetProcessHeap(), 0, adjacency);
6427     free_test_context(test_context);
6428 }
6429 
init_test_mesh(const DWORD num_faces,const DWORD num_vertices,const DWORD options,const D3DVERTEXELEMENT9 * declaration,IDirect3DDevice9 * device,ID3DXMesh ** mesh_ptr,const void * vertices,const DWORD vertex_size,const DWORD * indices,const DWORD * attributes)6430 static HRESULT init_test_mesh(const DWORD num_faces, const DWORD num_vertices,
6431                               const DWORD options,
6432                               const D3DVERTEXELEMENT9 *declaration,
6433                               IDirect3DDevice9 *device, ID3DXMesh **mesh_ptr,
6434                               const void *vertices, const DWORD vertex_size,
6435                               const DWORD *indices, const DWORD *attributes)
6436 {
6437     HRESULT hr;
6438     void *vertex_buffer;
6439     void *index_buffer;
6440     DWORD *attributes_buffer;
6441     ID3DXMesh *mesh = NULL;
6442 
6443     hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration, device, mesh_ptr);
6444     if (FAILED(hr))
6445     {
6446         skip("Couldn't create mesh. Got %x expected D3D_OK\n", hr);
6447         goto cleanup;
6448     }
6449     mesh = *mesh_ptr;
6450 
6451     hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
6452     if (FAILED(hr))
6453     {
6454         skip("Couldn't lock vertex buffer.\n");
6455         goto cleanup;
6456     }
6457     memcpy(vertex_buffer, vertices, num_vertices * vertex_size);
6458     hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
6459     if (FAILED(hr))
6460     {
6461         skip("Couldn't unlock vertex buffer.\n");
6462         goto cleanup;
6463     }
6464 
6465     hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
6466     if (FAILED(hr))
6467     {
6468         skip("Couldn't lock index buffer.\n");
6469         goto cleanup;
6470     }
6471     if (options & D3DXMESH_32BIT)
6472     {
6473         if (indices)
6474             memcpy(index_buffer, indices, 3 * num_faces * sizeof(DWORD));
6475         else
6476         {
6477             /* Fill index buffer with 0, 1, 2, ...*/
6478             DWORD *indices_32bit = (DWORD*)index_buffer;
6479             UINT i;
6480             for (i = 0; i < 3 * num_faces; i++)
6481                 indices_32bit[i] = i;
6482         }
6483     }
6484     else
6485     {
6486         if (indices)
6487             memcpy(index_buffer, indices, 3 * num_faces * sizeof(WORD));
6488         else
6489         {
6490             /* Fill index buffer with 0, 1, 2, ...*/
6491             WORD *indices_16bit = (WORD*)index_buffer;
6492             UINT i;
6493             for (i = 0; i < 3 * num_faces; i++)
6494                 indices_16bit[i] = i;
6495         }
6496     }
6497     hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
6498     if (FAILED(hr)) {
6499         skip("Couldn't unlock index buffer.\n");
6500         goto cleanup;
6501     }
6502 
6503     hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
6504     if (FAILED(hr))
6505     {
6506         skip("Couldn't lock attributes buffer.\n");
6507         goto cleanup;
6508     }
6509 
6510     if (attributes)
6511         memcpy(attributes_buffer, attributes, num_faces * sizeof(*attributes));
6512     else
6513         memset(attributes_buffer, 0, num_faces * sizeof(*attributes));
6514 
6515     hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
6516     if (FAILED(hr))
6517     {
6518         skip("Couldn't unlock attributes buffer.\n");
6519         goto cleanup;
6520     }
6521 
6522     hr = D3D_OK;
6523 cleanup:
6524     return hr;
6525 }
6526 
6527 /* Using structs instead of bit-fields in order to avoid compiler issues. */
6528 struct udec3
6529 {
6530     UINT x;
6531     UINT y;
6532     UINT z;
6533     UINT w;
6534 };
6535 
6536 struct dec3n
6537 {
6538     INT x;
6539     INT y;
6540     INT z;
6541     INT w;
6542 };
6543 
init_udec3_dword(UINT x,UINT y,UINT z,UINT w)6544 static DWORD init_udec3_dword(UINT x, UINT y, UINT z, UINT w)
6545 {
6546     DWORD d = 0;
6547 
6548     d |= x & 0x3ff;
6549     d |= (y << 10) & 0xffc00;
6550     d |= (z << 20) & 0x3ff00000;
6551     d |= (w << 30) & 0xc0000000;
6552 
6553     return d;
6554 }
6555 
init_dec3n_dword(INT x,INT y,INT z,INT w)6556 static DWORD init_dec3n_dword(INT x, INT y, INT z, INT w)
6557 {
6558     DWORD d = 0;
6559 
6560     d |= x & 0x3ff;
6561     d |= (y << 10) & 0xffc00;
6562     d |= (z << 20) & 0x3ff00000;
6563     d |= (w << 30) & 0xc0000000;
6564 
6565     return d;
6566 }
6567 
dword_to_udec3(DWORD d)6568 static struct udec3 dword_to_udec3(DWORD d)
6569 {
6570     struct udec3 v;
6571 
6572     v.x = d & 0x3ff;
6573     v.y = (d & 0xffc00) >> 10;
6574     v.z = (d & 0x3ff00000) >> 20;
6575     v.w = (d & 0xc0000000) >> 30;
6576 
6577     return v;
6578 }
6579 
dword_to_dec3n(DWORD d)6580 static struct dec3n dword_to_dec3n(DWORD d)
6581 {
6582     struct dec3n v;
6583 
6584     v.x = d & 0x3ff;
6585     v.y = (d & 0xffc00) >> 10;
6586     v.z = (d & 0x3ff00000) >> 20;
6587     v.w = (d & 0xc0000000) >> 30;
6588 
6589     return v;
6590 }
6591 
check_vertex_components(int line,int mesh_number,int vertex_number,BYTE * got_ptr,const BYTE * exp_ptr,D3DVERTEXELEMENT9 * declaration)6592 static void check_vertex_components(int line, int mesh_number, int vertex_number, BYTE *got_ptr, const BYTE *exp_ptr, D3DVERTEXELEMENT9 *declaration)
6593 {
6594     const char *usage_strings[] =
6595     {
6596         "position",
6597         "blend weight",
6598         "blend indices",
6599         "normal",
6600         "point size",
6601         "texture coordinates",
6602         "tangent",
6603         "binormal",
6604         "tessellation factor",
6605         "position transformed",
6606         "color",
6607         "fog",
6608         "depth",
6609         "sample"
6610     };
6611     D3DVERTEXELEMENT9 *decl_ptr;
6612     const float PRECISION = 1e-5f;
6613 
6614     for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
6615     {
6616         switch (decl_ptr->Type)
6617         {
6618             case D3DDECLTYPE_FLOAT1:
6619             {
6620                 FLOAT *got = (FLOAT*)(got_ptr + decl_ptr->Offset);
6621                 FLOAT *exp = (FLOAT*)(exp_ptr + decl_ptr->Offset);
6622                 FLOAT diff = fabsf(*got - *exp);
6623                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got %f for vertex %d %s, expected %f.\n",
6624                     mesh_number, *got, vertex_number, usage_strings[decl_ptr->Usage], *exp);
6625                 break;
6626             }
6627             case D3DDECLTYPE_FLOAT2:
6628             {
6629                 D3DXVECTOR2 *got = (D3DXVECTOR2*)(got_ptr + decl_ptr->Offset);
6630                 D3DXVECTOR2 *exp = (D3DXVECTOR2*)(exp_ptr + decl_ptr->Offset);
6631                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6632                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f) for vertex %d %s, expected (%f, %f).\n",
6633                     mesh_number, got->x, got->y, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y);
6634                 break;
6635             }
6636             case D3DDECLTYPE_FLOAT3:
6637             {
6638                 D3DXVECTOR3 *got = (D3DXVECTOR3*)(got_ptr + decl_ptr->Offset);
6639                 D3DXVECTOR3 *exp = (D3DXVECTOR3*)(exp_ptr + decl_ptr->Offset);
6640                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6641                 diff = max(diff, fabsf(got->z - exp->z));
6642                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f) for vertex %d %s, expected (%f, %f, %f).\n",
6643                     mesh_number, got->x, got->y, got->z, vertex_number, usage_strings[decl_ptr->Usage], exp->x, exp->y, exp->z);
6644                 break;
6645             }
6646             case D3DDECLTYPE_FLOAT4:
6647             {
6648                 D3DXVECTOR4 *got = (D3DXVECTOR4*)(got_ptr + decl_ptr->Offset);
6649                 D3DXVECTOR4 *exp = (D3DXVECTOR4*)(exp_ptr + decl_ptr->Offset);
6650                 FLOAT diff = max(fabsf(got->x - exp->x), fabsf(got->y - exp->y));
6651                 diff = max(diff, fabsf(got->z - exp->z));
6652                 diff = max(diff, fabsf(got->w - exp->w));
6653                 ok_(__FILE__,line)(diff <= PRECISION, "Mesh %d: Got (%f, %f, %f, %f) for vertex %d %s, expected (%f, %f, %f, %f).\n",
6654                     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);
6655                 break;
6656             }
6657             case D3DDECLTYPE_D3DCOLOR:
6658             {
6659                 BYTE *got = got_ptr + decl_ptr->Offset;
6660                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6661                 BOOL same_color = got[0] == exp[0] && got[1] == exp[1]
6662                                   && got[2] == exp[2] && got[3] == exp[3];
6663                 const char *color_types[] = {"diffuse", "specular", "undefined color"};
6664                 BYTE usage_index = decl_ptr->UsageIndex;
6665                 if (usage_index > 1) usage_index = 2;
6666                 ok_(__FILE__,line)(same_color, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6667                     mesh_number, got[0], got[1], got[2], got[3], vertex_number, color_types[usage_index], exp[0], exp[1], exp[2], exp[3]);
6668                 break;
6669             }
6670             case D3DDECLTYPE_UBYTE4:
6671             case D3DDECLTYPE_UBYTE4N:
6672             {
6673                 BYTE *got = got_ptr + decl_ptr->Offset;
6674                 const BYTE *exp = exp_ptr + decl_ptr->Offset;
6675                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6676                             && got[2] == exp[2] && got[3] == exp[3];
6677                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6678                     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]);
6679                 break;
6680             }
6681             case D3DDECLTYPE_SHORT2:
6682             case D3DDECLTYPE_SHORT2N:
6683             {
6684                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6685                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6686                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6687                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd) for vertex %d %s, expected (%hd, %hd).\n",
6688                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6689                 break;
6690             }
6691             case D3DDECLTYPE_SHORT4:
6692             case D3DDECLTYPE_SHORT4N:
6693             {
6694                 SHORT *got = (SHORT*)(got_ptr + decl_ptr->Offset);
6695                 SHORT *exp = (SHORT*)(exp_ptr + decl_ptr->Offset);
6696                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6697                             && got[2] == exp[2] && got[3] == exp[3];
6698                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hd, %hd, %hd, %hd) for vertex %d %s, expected (%hd, %hd, %hd, %hd).\n",
6699                     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]);
6700                 break;
6701             }
6702             case D3DDECLTYPE_USHORT2N:
6703             {
6704                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6705                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6706                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6707                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu) for vertex %d %s, expected (%hu, %hu).\n",
6708                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6709                 break;
6710             }
6711             case D3DDECLTYPE_USHORT4N:
6712             {
6713                 USHORT *got = (USHORT*)(got_ptr + decl_ptr->Offset);
6714                 USHORT *exp = (USHORT*)(exp_ptr + decl_ptr->Offset);
6715                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6716                             && got[2] == exp[2] && got[3] == exp[3];
6717                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hu, %hu, %hu, %hu) for vertex %d %s, expected (%hu, %hu, %hu, %hu).\n",
6718                     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]);
6719                 break;
6720             }
6721             case D3DDECLTYPE_UDEC3:
6722             {
6723                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6724                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6725                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6726                 struct udec3 got_udec3 = dword_to_udec3(*got);
6727                 struct udec3 exp_udec3 = dword_to_udec3(*exp);
6728                 ok_(__FILE__,line)(same, "Mesh %d: Got (%u, %u, %u, %u) for vertex %d %s, expected (%u, %u, %u, %u).\n",
6729                     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);
6730 
6731                 break;
6732             }
6733             case D3DDECLTYPE_DEC3N:
6734             {
6735                 DWORD *got = (DWORD*)(got_ptr + decl_ptr->Offset);
6736                 DWORD *exp = (DWORD*)(exp_ptr + decl_ptr->Offset);
6737                 BOOL same = memcmp(got, exp, sizeof(*got)) == 0;
6738                 struct dec3n got_dec3n = dword_to_dec3n(*got);
6739                 struct dec3n exp_dec3n = dword_to_dec3n(*exp);
6740                 ok_(__FILE__,line)(same, "Mesh %d: Got (%d, %d, %d, %d) for vertex %d %s, expected (%d, %d, %d, %d).\n",
6741                     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);
6742                 break;
6743             }
6744             case D3DDECLTYPE_FLOAT16_2:
6745             {
6746                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6747                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6748                 BOOL same = got[0] == exp[0] && got[1] == exp[1];
6749                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx) for vertex %d %s, expected (%hx, %hx).\n",
6750                     mesh_number, got[0], got[1], vertex_number, usage_strings[decl_ptr->Usage], exp[0], exp[1]);
6751                 break;
6752             }
6753             case D3DDECLTYPE_FLOAT16_4:
6754             {
6755                 WORD *got = (WORD*)(got_ptr + decl_ptr->Offset);
6756                 WORD *exp = (WORD*)(exp_ptr + decl_ptr->Offset);
6757                 BOOL same = got[0] == exp[0] && got[1] == exp[1]
6758                             && got[2] == exp[2] && got[3] == exp[3];
6759                 ok_(__FILE__,line)(same, "Mesh %d: Got (%hx, %hx, %hx, %hx) for vertex %d %s, expected (%hx, %hx, %hx, %hx).\n",
6760                     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]);
6761                 break;
6762             }
6763             default:
6764                 break;
6765         }
6766     }
6767 }
6768 
test_weld_vertices(void)6769 static void test_weld_vertices(void)
6770 {
6771     HRESULT hr;
6772     struct test_context *test_context = NULL;
6773     DWORD i;
6774     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
6775     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
6776     BYTE *vertices = NULL;
6777     DWORD *indices = NULL;
6778     WORD *indices_16bit = NULL;
6779     const UINT VERTS_PER_FACE = 3;
6780 #ifndef __REACTOS__
6781     const D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
6782 #else
6783 #define up {0.0f, 0.0f, 1.0f}
6784 #endif
6785     struct vertex_normal
6786     {
6787         D3DXVECTOR3 position;
6788         D3DXVECTOR3 normal;
6789     };
6790     struct vertex_blendweight
6791     {
6792         D3DXVECTOR3 position;
6793         FLOAT blendweight;
6794     };
6795     struct vertex_texcoord
6796     {
6797         D3DXVECTOR3 position;
6798         D3DXVECTOR2 texcoord;
6799     };
6800     struct vertex_color
6801     {
6802         D3DXVECTOR3 position;
6803         DWORD color;
6804     };
6805     struct vertex_color_ubyte4
6806     {
6807         D3DXVECTOR3 position;
6808         BYTE color[4];
6809     };
6810     struct vertex_texcoord_short2
6811     {
6812         D3DXVECTOR3 position;
6813         SHORT texcoord[2];
6814     };
6815     struct vertex_texcoord_ushort2n
6816     {
6817         D3DXVECTOR3 position;
6818         USHORT texcoord[2];
6819     };
6820     struct vertex_normal_short4
6821     {
6822         D3DXVECTOR3 position;
6823         SHORT normal[4];
6824     };
6825     struct vertex_texcoord_float16_2
6826     {
6827         D3DXVECTOR3 position;
6828         WORD texcoord[2];
6829     };
6830     struct vertex_texcoord_float16_4
6831     {
6832         D3DXVECTOR3 position;
6833         WORD texcoord[4];
6834     };
6835     struct vertex_normal_udec3
6836     {
6837         D3DXVECTOR3 position;
6838         DWORD normal;
6839     };
6840     struct vertex_normal_dec3n
6841     {
6842         D3DXVECTOR3 position;
6843         DWORD normal;
6844     };
6845     UINT vertex_size_normal = sizeof(struct vertex_normal);
6846     UINT vertex_size_blendweight = sizeof(struct vertex_blendweight);
6847     UINT vertex_size_texcoord = sizeof(struct vertex_texcoord);
6848     UINT vertex_size_color = sizeof(struct vertex_color);
6849     UINT vertex_size_color_ubyte4 = sizeof(struct vertex_color_ubyte4);
6850     UINT vertex_size_texcoord_short2 = sizeof(struct vertex_texcoord_short2);
6851     UINT vertex_size_normal_short4 = sizeof(struct vertex_normal_short4);
6852     UINT vertex_size_texcoord_float16_2 = sizeof(struct vertex_texcoord_float16_2);
6853     UINT vertex_size_texcoord_float16_4 = sizeof(struct vertex_texcoord_float16_4);
6854     UINT vertex_size_normal_udec3 = sizeof(struct vertex_normal_udec3);
6855     UINT vertex_size_normal_dec3n = sizeof(struct vertex_normal_dec3n);
6856     D3DVERTEXELEMENT9 declaration_normal[] =
6857     {
6858         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6859         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6860         D3DDECL_END()
6861     };
6862     D3DVERTEXELEMENT9 declaration_normal3[] =
6863     {
6864         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 3},
6865         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6866         D3DDECL_END()
6867     };
6868     D3DVERTEXELEMENT9 declaration_blendweight[] =
6869     {
6870         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6871         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
6872         D3DDECL_END()
6873     };
6874     D3DVERTEXELEMENT9 declaration_texcoord[] =
6875     {
6876         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6877         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6878         D3DDECL_END()
6879     };
6880     D3DVERTEXELEMENT9 declaration_color[] =
6881     {
6882         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6883         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6884         D3DDECL_END()
6885     };
6886     D3DVERTEXELEMENT9 declaration_color_ubyte4n[] =
6887     {
6888         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6889         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6890         D3DDECL_END()
6891     };
6892     D3DVERTEXELEMENT9 declaration_color_ubyte4[] =
6893     {
6894         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6895         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
6896         D3DDECL_END()
6897     };
6898     D3DVERTEXELEMENT9 declaration_texcoord_short2[] =
6899     {
6900         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6901         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6902         D3DDECL_END()
6903     };
6904     D3DVERTEXELEMENT9 declaration_texcoord_short2n[] =
6905     {
6906         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6907         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6908         D3DDECL_END()
6909     };
6910     D3DVERTEXELEMENT9 declaration_texcoord_ushort2n[] =
6911     {
6912         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6913         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6914         D3DDECL_END()
6915     };
6916     D3DVERTEXELEMENT9 declaration_normal_short4[] =
6917     {
6918         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6919         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6920         D3DDECL_END()
6921     };
6922     D3DVERTEXELEMENT9 declaration_normal_short4n[] =
6923     {
6924         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6925         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6926         D3DDECL_END()
6927     };
6928     D3DVERTEXELEMENT9 declaration_normal_ushort4n[] =
6929     {
6930         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6931         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6932         D3DDECL_END()
6933     };
6934     D3DVERTEXELEMENT9 declaration_texcoord10[] =
6935     {
6936         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6937         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 10},
6938         D3DDECL_END()
6939     };
6940     D3DVERTEXELEMENT9 declaration_color2[] =
6941     {
6942         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6943         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 2},
6944         D3DDECL_END()
6945     };
6946     D3DVERTEXELEMENT9 declaration_color1[] =
6947     {
6948         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6949         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
6950         D3DDECL_END()
6951     };
6952     D3DVERTEXELEMENT9 declaration_texcoord_float16_2[] =
6953     {
6954         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6955         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6956         D3DDECL_END()
6957     };
6958     D3DVERTEXELEMENT9 declaration_texcoord_float16_4[] =
6959     {
6960         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6961         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
6962         D3DDECL_END()
6963     };
6964     D3DVERTEXELEMENT9 declaration_normal_udec3[] =
6965    {
6966         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6967         {0, 12, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6968         D3DDECL_END()
6969     };
6970     D3DVERTEXELEMENT9 declaration_normal_dec3n[] =
6971     {
6972         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
6973         {0, 12, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
6974         D3DDECL_END()
6975     };
6976     /* Test 0. One face and no welding.
6977      *
6978      * 0--1
6979      * | /
6980      * |/
6981      * 2
6982      */
6983     const struct vertex vertices0[] =
6984     {
6985         {{ 0.0f,  3.0f,  0.f}, up},
6986         {{ 2.0f,  3.0f,  0.f}, up},
6987         {{ 0.0f,  0.0f,  0.f}, up},
6988     };
6989     const DWORD indices0[] = {0, 1, 2};
6990     const DWORD attributes0[] = {0};
6991     const DWORD exp_indices0[] = {0, 1, 2};
6992     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
6993     const UINT num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
6994     const DWORD flags0 = D3DXWELDEPSILONS_WELDALL;
6995     /* epsilons0 is NULL */
6996     const DWORD adjacency0[] = {-1, -1, -1};
6997     const struct vertex exp_vertices0[] =
6998     {
6999         {{ 0.0f,  3.0f,  0.f}, up},
7000         {{ 2.0f,  3.0f,  0.f}, up},
7001         {{ 0.0f,  0.0f,  0.f}, up},
7002     };
7003     const DWORD exp_face_remap0[] = {0};
7004     const DWORD exp_vertex_remap0[] = {0, 1, 2};
7005     const DWORD exp_new_num_vertices0 = ARRAY_SIZE(exp_vertices0);
7006     /* Test 1. Two vertices should be removed without regard to epsilon.
7007      *
7008      * 0--1 3
7009      * | / /|
7010      * |/ / |
7011      * 2 5--4
7012      */
7013     const struct vertex_normal vertices1[] =
7014     {
7015         {{ 0.0f,  3.0f,  0.f}, up},
7016         {{ 2.0f,  3.0f,  0.f}, up},
7017         {{ 0.0f,  0.0f,  0.f}, up},
7018 
7019         {{ 3.0f,  3.0f,  0.f}, up},
7020         {{ 3.0f,  0.0f,  0.f}, up},
7021         {{ 1.0f,  0.0f,  0.f}, up},
7022     };
7023     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
7024     const DWORD attributes1[] = {0, 0};
7025     const UINT num_vertices1 = ARRAY_SIZE(vertices1);
7026     const UINT num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
7027     const DWORD flags1 = D3DXWELDEPSILONS_WELDALL;
7028     /* epsilons1 is NULL */
7029     const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
7030     const struct vertex_normal exp_vertices1[] =
7031     {
7032         {{ 0.0f,  3.0f,  0.f}, up},
7033         {{ 2.0f,  3.0f,  0.f}, up},
7034         {{ 0.0f,  0.0f,  0.f}, up},
7035 
7036         {{ 3.0f,  0.0f,  0.f}, up}
7037     };
7038     const DWORD exp_indices1[] = {0, 1, 2, 1, 3, 2};
7039     const DWORD exp_face_remap1[] = {0, 1};
7040     const DWORD exp_vertex_remap1[] = {0, 1, 2, 4, -1, -1};
7041     const DWORD exp_new_num_vertices1 = ARRAY_SIZE(exp_vertices1);
7042     /* Test 2. Two faces. No vertices should be removed because of normal
7043      * epsilon, but the positions should be replaced. */
7044     const struct vertex_normal vertices2[] =
7045     {
7046         {{ 0.0f,  3.0f,  0.f}, up},
7047         {{ 2.0f,  3.0f,  0.f}, up},
7048         {{ 0.0f,  0.0f,  0.f}, up},
7049 
7050         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7051         {{ 3.0f,  0.0f,  0.f}, up},
7052         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7053     };
7054     const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
7055     const DWORD attributes2[] = {0, 0};
7056     const UINT num_vertices2 = ARRAY_SIZE(vertices2);
7057     const UINT num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
7058     DWORD flags2 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7059     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};
7060     const DWORD adjacency2[] = {-1, 1, -1, -1, -1, 0};
7061     const struct vertex_normal exp_vertices2[] =
7062     {
7063         {{ 0.0f,  3.0f,  0.f}, up},
7064         {{ 2.0f,  3.0f,  0.f}, up},
7065         {{ 0.0f,  0.0f,  0.f}, up},
7066 
7067         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7068         {{ 3.0f,  0.0f,  0.f}, up},
7069         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7070     };
7071     const DWORD exp_indices2[] = {0, 1, 2, 3, 4, 5};
7072     const DWORD exp_face_remap2[] = {0, 1};
7073     const DWORD exp_vertex_remap2[] = {0, 1, 2, 3, 4, 5};
7074     const DWORD exp_new_num_vertices2 = ARRAY_SIZE(exp_vertices2);
7075     /* Test 3. Two faces. One vertex should be removed because of normal epsilon. */
7076     const struct vertex_normal vertices3[] =
7077     {
7078         {{ 0.0f,  3.0f,  0.f}, up},
7079         {{ 2.0f,  3.0f,  0.f}, up},
7080         {{ 0.0f,  0.0f,  0.f}, up},
7081 
7082         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7083         {{ 3.0f,  0.0f,  0.f}, up},
7084         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7085     };
7086     const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
7087     const DWORD attributes3[] = {0, 0};
7088     const UINT num_vertices3 = ARRAY_SIZE(vertices3);
7089     const UINT num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
7090     DWORD flags3 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7091     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};
7092     const DWORD adjacency3[] = {-1, 1, -1, -1, -1, 0};
7093     const struct vertex_normal exp_vertices3[] =
7094     {
7095         {{ 0.0f,  3.0f,  0.f}, up},
7096         {{ 2.0f,  3.0f,  0.f}, up},
7097         {{ 0.0f,  0.0f,  0.f}, up},
7098 
7099         {{ 3.0f,  0.0f,  0.f}, up},
7100         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7101     };
7102     const DWORD exp_indices3[] = {0, 1, 2, 1, 3, 4};
7103     const DWORD exp_face_remap3[] = {0, 1};
7104     const DWORD exp_vertex_remap3[] = {0, 1, 2, 4, 5, -1};
7105     const DWORD exp_new_num_vertices3 = ARRAY_SIZE(exp_vertices3);
7106     /* Test 4  Two faces. Two vertices should be removed. */
7107     const struct vertex_normal vertices4[] =
7108     {
7109         {{ 0.0f,  3.0f,  0.f}, up},
7110         {{ 2.0f,  3.0f,  0.f}, up},
7111         {{ 0.0f,  0.0f,  0.f}, up},
7112 
7113         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7114         {{ 3.0f,  0.0f,  0.f}, up},
7115         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7116     };
7117     const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
7118     const DWORD attributes4[] = {0, 0};
7119     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
7120     const UINT num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
7121     DWORD flags4 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7122     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};
7123     const DWORD adjacency4[] = {-1, 1, -1, -1, -1, 0};
7124     const struct vertex_normal exp_vertices4[] =
7125     {
7126         {{ 0.0f,  3.0f,  0.f}, up},
7127         {{ 2.0f,  3.0f,  0.f}, up},
7128         {{ 0.0f,  0.0f,  0.f}, up},
7129 
7130         {{ 3.0f,  0.0f,  0.f}, up},
7131     };
7132     const DWORD exp_indices4[] = {0, 1, 2, 1, 3, 2};
7133     const DWORD exp_face_remap4[] = {0, 1};
7134     const DWORD exp_vertex_remap4[] = {0, 1, 2, 4, -1, -1};
7135     const DWORD exp_new_num_vertices4 = ARRAY_SIZE(exp_vertices4);
7136     /* Test 5. Odd face ordering.
7137      *
7138      * 0--1 6 3
7139      * | / /| |\
7140      * |/ / | | \
7141      * 2 8--7 5--4
7142      */
7143     const struct vertex_normal vertices5[] =
7144     {
7145         {{ 0.0f,  3.0f,  0.f}, up},
7146         {{ 2.0f,  3.0f,  0.f}, up},
7147         {{ 0.0f,  0.0f,  0.f}, up},
7148 
7149         {{ 3.0f,  3.0f,  0.f}, up},
7150         {{ 3.0f,  0.0f,  0.f}, up},
7151         {{ 1.0f,  0.0f,  0.f}, up},
7152 
7153         {{ 4.0f,  3.0f,  0.f}, up},
7154         {{ 6.0f,  0.0f,  0.f}, up},
7155         {{ 4.0f,  0.0f,  0.f}, up},
7156     };
7157     const DWORD indices5[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
7158     const DWORD exp_indices5[] = {0, 1, 2, 1, 4, 2, 1, 3, 4};
7159     const DWORD attributes5[] = {0, 0, 0};
7160     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
7161     const UINT num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
7162     DWORD flags5 = D3DXWELDEPSILONS_WELDALL;
7163     const DWORD adjacency5[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
7164     const struct vertex_normal exp_vertices5[] =
7165     {
7166         {{ 0.0f,  3.0f,  0.f}, up},
7167         {{ 2.0f,  3.0f,  0.f}, up},
7168         {{ 0.0f,  0.0f,  0.f}, up},
7169 
7170         {{ 3.0f,  0.0f,  0.f}, up},
7171         {{ 1.0f,  0.0f,  0.f}, up},
7172     };
7173     const DWORD exp_face_remap5[] = {0, 1, 2};
7174     const DWORD exp_vertex_remap5[] = {0, 1, 2, 4, 5, -1, -1, -1, -1};
7175     const DWORD exp_new_num_vertices5 = ARRAY_SIZE(exp_vertices5);
7176     /* Test 6. Two faces. Do not remove flag is used, so no vertices should be
7177      * removed. */
7178     const struct vertex_normal vertices6[] =
7179     {
7180         {{ 0.0f,  3.0f,  0.f}, up},
7181         {{ 2.0f,  3.0f,  0.f}, up},
7182         {{ 0.0f,  0.0f,  0.f}, up},
7183 
7184         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7185         {{ 3.0f,  0.0f,  0.f}, up},
7186         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7187     };
7188     const DWORD indices6[] = {0, 1, 2, 3, 4, 5};
7189     const DWORD attributes6[] = {0, 0};
7190     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
7191     const UINT num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
7192     DWORD flags6 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTREMOVEVERTICES;
7193     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};
7194     const DWORD adjacency6[] = {-1, 1, -1, -1, -1, 0};
7195     const struct vertex_normal exp_vertices6[] =
7196     {
7197         {{ 0.0f,  3.0f,  0.f}, up},
7198         {{ 2.0f,  3.0f,  0.f}, up},
7199         {{ 0.0f,  0.0f,  0.f}, up},
7200 
7201         {{ 2.0f,  3.0f,  0.f}, up},
7202         {{ 3.0f,  0.0f,  0.f}, up},
7203         {{ 0.0f,  0.0f,  0.f}, up},
7204 
7205     };
7206     const DWORD exp_indices6[] = {0, 1, 2, 3, 4, 5};
7207     const DWORD exp_face_remap6[] = {0, 1};
7208     const DWORD exp_vertex_remap6[] = {0, 1, 2, 3, 4, 5};
7209     const DWORD exp_new_num_vertices6 = ARRAY_SIZE(exp_vertices6);
7210     /* Test 7. Same as test 6 but with 16 bit indices. */
7211     const WORD indices6_16bit[] = {0, 1, 2, 3, 4, 5};
7212     /* Test 8. No flags. Same result as D3DXWELDEPSILONS_WELDPARTIALMATCHES. */
7213     const struct vertex_normal vertices8[] =
7214     {
7215         {{ 0.0f,  3.0f,  0.f}, up},
7216         {{ 2.0f,  3.0f,  0.f}, up},
7217         {{ 0.0f,  0.0f,  0.f}, up},
7218 
7219         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7220         {{ 3.0f,  0.0f,  0.f}, up},
7221         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7222     };
7223     const DWORD indices8[] = {0, 1, 2, 1, 3, 4};
7224     const DWORD attributes8[] = {0, 0};
7225     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
7226     const UINT num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
7227     DWORD flags8 = 0;
7228     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};
7229     const DWORD adjacency8[] = {-1, 1, -1, -1, -1, 0};
7230     const struct vertex_normal exp_vertices8[] =
7231     {
7232         {{ 0.0f,  3.0f,  0.f}, up},
7233         {{ 2.0f,  3.0f,  0.f}, up},
7234         {{ 0.0f,  0.0f,  0.f}, up},
7235 
7236         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7237         {{ 3.0f,  0.0f,  0.f}, up},
7238     };
7239     const DWORD exp_indices8[] = {0, 1, 2, 1, 3, 4};
7240     const DWORD exp_face_remap8[] = {0, 1};
7241     const DWORD exp_vertex_remap8[] = {0, 1, 2, 3, 4, -1};
7242     const DWORD exp_new_num_vertices8 = ARRAY_SIZE(exp_vertices8);
7243     /* Test 9. Vertices are removed even though they belong to separate
7244      * attribute groups if D3DXWELDEPSILONS_DONOTSPLIT is set. */
7245     const struct vertex_normal vertices9[] =
7246     {
7247         {{ 0.0f,  3.0f,  0.f}, up},
7248         {{ 2.0f,  3.0f,  0.f}, up},
7249         {{ 0.0f,  0.0f,  0.f}, up},
7250 
7251         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7252         {{ 3.0f,  0.0f,  0.f}, up},
7253         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7254     };
7255     const DWORD indices9[] = {0, 1, 2, 3, 4, 5};
7256     const DWORD attributes9[] = {0, 1};
7257     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
7258     const UINT num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
7259     DWORD flags9 = D3DXWELDEPSILONS_WELDPARTIALMATCHES | D3DXWELDEPSILONS_DONOTSPLIT;
7260     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};
7261     const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
7262     const struct vertex_normal exp_vertices9[] =
7263     {
7264         {{ 0.0f,  3.0f,  0.f}, up},
7265         {{ 2.0f,  3.0f,  0.f}, up},
7266         {{ 0.0f,  0.0f,  0.f}, up},
7267 
7268         {{ 3.0f,  0.0f,  0.f}, up},
7269     };
7270     const DWORD exp_indices9[] = {0, 1, 2, 1, 3, 2};
7271     const DWORD exp_face_remap9[] = {0, 1};
7272     const DWORD exp_vertex_remap9[] = {0, 1, 2, 4, -1, -1};
7273     const DWORD exp_new_num_vertices9 = ARRAY_SIZE(exp_vertices9);
7274     /* Test 10. Weld blendweight (FLOAT1). */
7275     const struct vertex_blendweight vertices10[] =
7276     {
7277         {{ 0.0f,  3.0f,  0.f}, 1.0f},
7278         {{ 2.0f,  3.0f,  0.f}, 1.0f},
7279         {{ 0.0f,  0.0f,  0.f}, 1.0f},
7280 
7281         {{ 3.0f,  3.0f,  0.f}, 0.9},
7282         {{ 3.0f,  0.0f,  0.f}, 1.0},
7283         {{ 1.0f,  0.0f,  0.f}, 0.4},
7284     };
7285     const DWORD indices10[] = {0, 1, 2, 3, 4, 5};
7286     const DWORD attributes10[] = {0, 0};
7287     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
7288     const UINT num_faces10 = ARRAY_SIZE(indices10) / VERTS_PER_FACE;
7289     DWORD flags10 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7290     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};
7291     const DWORD adjacency10[] = {-1, 1, -1, -1, -1, 0};
7292     const struct vertex_blendweight exp_vertices10[] =
7293     {
7294         {{ 0.0f,  3.0f,  0.f}, 1.0f},
7295         {{ 2.0f,  3.0f,  0.f}, 1.0f},
7296         {{ 0.0f,  0.0f,  0.f}, 1.0f},
7297 
7298         {{ 3.0f,  0.0f,  0.f}, 1.0},
7299         {{ 0.0f,  0.0f,  0.f}, 0.4},
7300     };
7301     const DWORD exp_indices10[] = {0, 1, 2, 1, 3, 4};
7302     const DWORD exp_face_remap10[] = {0, 1};
7303     const DWORD exp_vertex_remap10[] = {0, 1, 2, 4, 5, -1};
7304     const DWORD exp_new_num_vertices10 = ARRAY_SIZE(exp_vertices10);
7305     /* Test 11. Weld texture coordinates. */
7306     const struct vertex_texcoord vertices11[] =
7307     {
7308         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7309         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7310         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7311 
7312         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7313         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7314         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7315     };
7316     const DWORD indices11[] = {0, 1, 2, 3, 4, 5};
7317     const DWORD attributes11[] = {0, 0};
7318     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
7319     const UINT num_faces11 = ARRAY_SIZE(indices11) / VERTS_PER_FACE;
7320     DWORD flags11 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7321     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};
7322     const DWORD adjacency11[] = {-1, 1, -1, -1, -1, 0};
7323     const struct vertex_texcoord exp_vertices11[] =
7324     {
7325         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7326         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7327         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7328 
7329         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7330         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7331     };
7332     const DWORD exp_indices11[] = {0, 1, 2, 1, 3, 4};
7333     const DWORD exp_face_remap11[] = {0, 1};
7334     const DWORD exp_vertex_remap11[] = {0, 1, 2, 4, 5, -1};
7335     const DWORD exp_new_num_vertices11 = ARRAY_SIZE(exp_vertices11);
7336     /* Test 12. Weld with color. */
7337     const struct vertex_color vertices12[] =
7338     {
7339         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7340         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7341         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7342 
7343         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7344         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7345         {{ 1.0f,  0.0f,  0.f}, 0x88888888},
7346     };
7347     const DWORD indices12[] = {0, 1, 2, 3, 4, 5};
7348     const DWORD attributes12[] = {0, 0};
7349     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
7350     const UINT num_faces12 = ARRAY_SIZE(indices12) / VERTS_PER_FACE;
7351     DWORD flags12 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7352     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};
7353     const DWORD adjacency12[] = {-1, 1, -1, -1, -1, 0};
7354     const struct vertex_color exp_vertices12[] =
7355     {
7356         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7357         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7358         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7359 
7360         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7361         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7362     };
7363     const DWORD exp_indices12[] = {0, 1, 2, 3, 4, 2};
7364     const DWORD exp_face_remap12[] = {0, 1};
7365     const DWORD exp_vertex_remap12[] = {0, 1, 2, 3, 4, -1};
7366     const DWORD exp_new_num_vertices12 = ARRAY_SIZE(exp_vertices12);
7367     /* Test 13. Two faces. One vertex should be removed because of normal epsilon.
7368      * This is similar to test 3, but the declaration has been changed to NORMAL3.
7369      */
7370     const struct vertex_normal vertices13[] =
7371     {
7372         {{ 0.0f,  3.0f,  0.f}, up},
7373         {{ 2.0f,  3.0f,  0.f}, up},
7374         {{ 0.0f,  0.0f,  0.f}, up},
7375 
7376         {{ 3.0f,  3.0f,  0.f}, {0.0f, 0.5f, 0.5f}},
7377         {{ 3.0f,  0.0f,  0.f}, up},
7378         {{ 1.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7379     };
7380     const DWORD indices13[] = {0, 1, 2, 3, 4, 5};
7381     const DWORD attributes13[] = {0, 0};
7382     const UINT num_vertices13 = ARRAY_SIZE(vertices3);
7383     const UINT num_faces13 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
7384     DWORD flags13 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7385     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};
7386     const DWORD adjacency13[] = {-1, 1, -1, -1, -1, 0};
7387     const struct vertex_normal exp_vertices13[] =
7388     {
7389         {{ 0.0f,  3.0f,  0.f}, up},
7390         {{ 2.0f,  3.0f,  0.f}, up},
7391         {{ 0.0f,  0.0f,  0.f}, up},
7392 
7393         {{ 3.0f,  0.0f,  0.f}, up},
7394         {{ 0.0f,  0.0f,  0.f}, {0.2f, 0.4f, 0.4f}},
7395     };
7396     const DWORD exp_indices13[] = {0, 1, 2, 1, 3, 4};
7397     const DWORD exp_face_remap13[] = {0, 1};
7398     const DWORD exp_vertex_remap13[] = {0, 1, 2, 4, 5, -1};
7399     const DWORD exp_new_num_vertices13 = ARRAY_SIZE(exp_vertices13);
7400     /* Test 14. Another test for welding with color. */
7401     const struct vertex_color vertices14[] =
7402     {
7403         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7404         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7405         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7406 
7407         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7408         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7409         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7410     };
7411     const DWORD indices14[] = {0, 1, 2, 3, 4, 5};
7412     const DWORD attributes14[] = {0, 0};
7413     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
7414     const UINT num_faces14 = ARRAY_SIZE(indices14) / VERTS_PER_FACE;
7415     DWORD flags14 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7416     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};
7417     const DWORD adjacency14[] = {-1, 1, -1, -1, -1, 0};
7418     const struct vertex_color exp_vertices14[] =
7419     {
7420         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7421         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7422         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7423 
7424         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7425         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7426     };
7427     const DWORD exp_indices14[] = {0, 1, 2, 3, 4, 2};
7428     const DWORD exp_face_remap14[] = {0, 1};
7429     const DWORD exp_vertex_remap14[] = {0, 1, 2, 3, 4, -1};
7430     const DWORD exp_new_num_vertices14 = ARRAY_SIZE(exp_vertices14);
7431     /* Test 15. Weld with color, but as UBYTE4N instead of D3DCOLOR. It shows
7432      * that UBYTE4N and D3DCOLOR are compared the same way.
7433      */
7434     const struct vertex_color_ubyte4 vertices15[] =
7435     {
7436         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7437         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7438         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7439 
7440         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7441         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7442         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7443     };
7444     const DWORD indices15[] = {0, 1, 2, 3, 4, 5};
7445     const DWORD attributes15[] = {0, 0};
7446     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
7447     const UINT num_faces15 = ARRAY_SIZE(indices15) / VERTS_PER_FACE;
7448     DWORD flags15 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7449     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};
7450     const DWORD adjacency15[] = {-1, 1, -1, -1, -1, 0};
7451     const struct vertex_color_ubyte4 exp_vertices15[] =
7452     {
7453         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7454         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7455         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7456 
7457         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7458         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7459     };
7460     const DWORD exp_indices15[] = {0, 1, 2, 3, 4, 2};
7461     const DWORD exp_face_remap15[] = {0, 1};
7462     const DWORD exp_vertex_remap15[] = {0, 1, 2, 3, 4, -1};
7463     const DWORD exp_new_num_vertices15 = ARRAY_SIZE(exp_vertices15);
7464     /* Test 16. Weld with color, but as UBYTE4 instead of D3DCOLOR. It shows
7465      * that UBYTE4 is not normalized and that epsilon is truncated and compared
7466      * directly to each of the four bytes.
7467      */
7468     const struct vertex_color_ubyte4 vertices16[] =
7469     {
7470         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7471         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7472         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7473 
7474         {{ 3.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7475         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7476         {{ 1.0f,  0.0f,  0.f}, {  1,   1,   1,   1}},
7477     };
7478     const DWORD indices16[] = {0, 1, 2, 3, 4, 5};
7479     const DWORD attributes16[] = {0, 0};
7480     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
7481     const UINT num_faces16 = ARRAY_SIZE(indices16) / VERTS_PER_FACE;
7482     DWORD flags16 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7483     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};
7484     const DWORD adjacency16[] = {-1, 1, -1, -1, -1, 0};
7485     const struct vertex_color_ubyte4 exp_vertices16[] =
7486     {
7487         {{ 0.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7488         {{ 2.0f,  3.0f,  0.f}, {255, 255, 255, 255}},
7489         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7490 
7491         {{ 2.0f,  3.0f,  0.f}, {  0,   0,   0,   0}},
7492         {{ 3.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
7493     };
7494     const DWORD exp_indices16[] = {0, 1, 2, 3, 4, 2};
7495     const DWORD exp_face_remap16[] = {0, 1};
7496     const DWORD exp_vertex_remap16[] = {0, 1, 2, 3, 4, -1};
7497     const DWORD exp_new_num_vertices16 = ARRAY_SIZE(exp_vertices16);
7498     /* Test 17. Weld texture coordinates but as SHORT2 instead of D3DXVECTOR2.*/
7499     const struct vertex_texcoord_short2 vertices17[] =
7500     {
7501         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7502         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7503         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7504 
7505         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7506         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7507         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7508     };
7509     const DWORD indices17[] = {0, 1, 2, 3, 4, 5};
7510     const DWORD attributes17[] = {0, 0};
7511     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
7512     const UINT num_faces17 = ARRAY_SIZE(indices17) / VERTS_PER_FACE;
7513     DWORD flags17 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7514     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};
7515     const DWORD adjacency17[] = {-1, 1, -1, -1, -1, 0};
7516     const struct vertex_texcoord_short2 exp_vertices17[] =
7517     {
7518         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7519         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7520         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7521 
7522         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7523         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7524     };
7525     const DWORD exp_indices17[] = {0, 1, 2, 3, 4, 2};
7526     const DWORD exp_face_remap17[] = {0, 1};
7527     const DWORD exp_vertex_remap17[] = {0, 1, 2, 3, 4, -1};
7528     const DWORD exp_new_num_vertices17 = ARRAY_SIZE(exp_vertices17);
7529     /* Test 18. Weld texture coordinates but as SHORT2N instead of D3DXVECTOR2. */
7530     const struct vertex_texcoord_short2 vertices18[] =
7531     {
7532         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7533         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7534         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7535 
7536         {{ 3.0f,  3.0f,  0.f}, {32767, 32767}},
7537         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7538         {{ 1.0f,  0.0f,  0.f}, {32766, 32766}},
7539     };
7540     const DWORD indices18[] = {0, 1, 2, 3, 4, 5};
7541     const DWORD attributes18[] = {0, 0};
7542     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
7543     const UINT num_faces18 = ARRAY_SIZE(indices18) / VERTS_PER_FACE;
7544     DWORD flags18 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7545     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};
7546     const DWORD adjacency18[] = {-1, 1, -1, -1, -1, 0};
7547     const struct vertex_texcoord_short2 exp_vertices18[] =
7548     {
7549         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7550         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7551         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7552 
7553         {{ 2.0f,  3.0f,  0.f}, {32767, 32767}},
7554         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7555     };
7556     const DWORD exp_indices18[] = {0, 1, 2, 3, 4, 2};
7557     const DWORD exp_face_remap18[] = {0, 1};
7558     const DWORD exp_vertex_remap18[] = {0, 1, 2, 3, 4, -1};
7559     const DWORD exp_new_num_vertices18 = ARRAY_SIZE(exp_vertices18);
7560     /* Test 19.  Weld texture coordinates but as USHORT2N instead of D3DXVECTOR2. */
7561     const struct vertex_texcoord_ushort2n vertices19[] =
7562     {
7563         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7564         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7565         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7566 
7567         {{ 3.0f,  3.0f,  0.f}, {65535, 65535}},
7568         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7569         {{ 1.0f,  0.0f,  0.f}, {65534, 65534}},
7570     };
7571     const DWORD indices19[] = {0, 1, 2, 3, 4, 5};
7572     const DWORD attributes19[] = {0, 0};
7573     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
7574     const UINT num_faces19 = ARRAY_SIZE(indices19) / VERTS_PER_FACE;
7575     DWORD flags19 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7576     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};
7577     const DWORD adjacency19[] = {-1, 1, -1, -1, -1, 0};
7578     const struct vertex_texcoord_ushort2n exp_vertices19[] =
7579     {
7580         {{ 0.0f,  3.0f,  0.f}, { 0, 0}},
7581         {{ 2.0f,  3.0f,  0.f}, { 0, 0}},
7582         {{ 0.0f,  0.0f,  0.f}, { 0, 0}},
7583 
7584         {{ 2.0f,  3.0f,  0.f}, {65535, 65535}},
7585         {{ 3.0f,  0.0f,  0.f}, {0, 0}},
7586     };
7587     const DWORD exp_indices19[] = {0, 1, 2, 3, 4, 2};
7588     const DWORD exp_face_remap19[] = {0, 1};
7589     const DWORD exp_vertex_remap19[] = {0, 1, 2, 3, 4, -1};
7590     const DWORD exp_new_num_vertices19 = ARRAY_SIZE(exp_vertices19);
7591     /* Test 20.  Weld normal as SHORT4 instead of D3DXVECTOR3. */
7592     const struct vertex_normal_short4 vertices20[] =
7593     {
7594         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7595         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7596         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7597 
7598         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7599         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7600         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7601     };
7602     const DWORD indices20[] = {0, 1, 2, 3, 4, 5};
7603     const DWORD attributes20[] = {0, 0};
7604     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
7605     const UINT num_faces20 = ARRAY_SIZE(indices20) / VERTS_PER_FACE;
7606     DWORD flags20 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7607     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};
7608     const DWORD adjacency20[] = {-1, 1, -1, -1, -1, 0};
7609     const struct vertex_normal_short4 exp_vertices20[] =
7610     {
7611         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7612         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7613         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7614 
7615         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7616         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7617     };
7618     const DWORD exp_indices20[] = {0, 1, 2, 3, 4, 2};
7619     const DWORD exp_face_remap20[] = {0, 1};
7620     const DWORD exp_vertex_remap20[] = {0, 1, 2, 3, 4, -1};
7621     const DWORD exp_new_num_vertices20 = ARRAY_SIZE(exp_vertices20);
7622     /* Test 21.  Weld normal as SHORT4N instead of D3DXVECTOR3. */
7623     const struct vertex_normal_short4 vertices21[] =
7624     {
7625         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7626         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7627         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7628 
7629         {{ 3.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7630         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7631         {{ 1.0f,  0.0f,  0.f}, {32766, 32766, 32766, 32766}},
7632     };
7633     const DWORD indices21[] = {0, 1, 2, 3, 4, 5};
7634     const DWORD attributes21[] = {0, 0};
7635     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
7636     const UINT num_faces21 = ARRAY_SIZE(indices21) / VERTS_PER_FACE;
7637     DWORD flags21 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7638     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};
7639     const DWORD adjacency21[] = {-1, 1, -1, -1, -1, 0};
7640     const struct vertex_normal_short4 exp_vertices21[] =
7641     {
7642         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7643         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7644         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7645 
7646         {{ 2.0f,  3.0f,  0.f}, {32767, 32767, 32767, 32767}},
7647         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7648     };
7649     const DWORD exp_indices21[] = {0, 1, 2, 3, 4, 2};
7650     const DWORD exp_face_remap21[] = {0, 1};
7651     const DWORD exp_vertex_remap21[] = {0, 1, 2, 3, 4, -1};
7652     const DWORD exp_new_num_vertices21 = ARRAY_SIZE(exp_vertices21);
7653     /* Test 22.  Weld normal as USHORT4N instead of D3DXVECTOR3. */
7654     const struct vertex_normal_short4 vertices22[] =
7655     {
7656         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7657         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7658         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7659 
7660         {{ 3.0f,  3.0f,  0.f}, {-1, -1, -1, -1}},
7661         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7662         {{ 1.0f,  0.0f,  0.f}, {-2, -2, -2, -2}},
7663     };
7664     const DWORD indices22[] = {0, 1, 2, 3, 4, 5};
7665     const DWORD attributes22[] = {0, 0};
7666     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
7667     const UINT num_faces22 = ARRAY_SIZE(indices22) / VERTS_PER_FACE;
7668     DWORD flags22 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7669     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};
7670     const DWORD adjacency22[] = {-1, 1, -1, -1, -1, 0};
7671     const struct vertex_normal_short4 exp_vertices22[] =
7672     {
7673         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7674         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
7675         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7676 
7677         {{ 2.0f,  3.0f,  0.f}, {-1, -1, -1, -1}},
7678         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 0}},
7679     };
7680     const DWORD exp_indices22[] = {0, 1, 2, 3, 4, 2};
7681     const DWORD exp_face_remap22[] = {0, 1};
7682     const DWORD exp_vertex_remap22[] = {0, 1, 2, 3, 4, -1};
7683     const DWORD exp_new_num_vertices22 = ARRAY_SIZE(exp_vertices22);
7684     /* Test 23. Weld texture coordinates as FLOAT16_2. Similar to test 11, but
7685      * with texture coordinates converted to float16 in hex. */
7686     const struct vertex_texcoord_float16_2 vertices23[] =
7687     {
7688         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7689         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7690         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7691 
7692         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
7693         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7694         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7695     };
7696     const DWORD indices23[] = {0, 1, 2, 3, 4, 5};
7697     const DWORD attributes23[] = {0, 0};
7698     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
7699     const UINT num_faces23 = ARRAY_SIZE(indices23) / VERTS_PER_FACE;
7700     DWORD flags23 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7701     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};
7702     const DWORD adjacency23[] = {-1, 1, -1, -1, -1, 0};
7703     const struct vertex_texcoord_float16_2 exp_vertices23[] =
7704     {
7705         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7706         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
7707         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
7708 
7709         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
7710         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
7711     };
7712     const DWORD exp_indices23[] = {0, 1, 2, 1, 3, 4};
7713     const DWORD exp_face_remap23[] = {0, 1};
7714     const DWORD exp_vertex_remap23[] = {0, 1, 2, 4, 5, -1};
7715     const DWORD exp_new_num_vertices23 = ARRAY_SIZE(exp_vertices23);
7716     /* Test 24. Weld texture coordinates as FLOAT16_4. Similar to test 24. */
7717     const struct vertex_texcoord_float16_4 vertices24[] =
7718     {
7719         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7720         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7721         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7722 
7723         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0x3266, 0x34cd}},
7724         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7725         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7726     };
7727     const DWORD indices24[] = {0, 1, 2, 3, 4, 5};
7728     const DWORD attributes24[] = {0, 0};
7729     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
7730     const UINT num_faces24 = ARRAY_SIZE(indices24) / VERTS_PER_FACE;
7731     DWORD flags24 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7732     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};
7733     const DWORD adjacency24[] = {-1, 1, -1, -1, -1, 0};
7734     const struct vertex_texcoord_float16_4 exp_vertices24[] =
7735     {
7736         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7737         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0x3800, 0x399a}},
7738         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0xb266, 0xb4cd}},
7739 
7740         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
7741         {{ 0.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
7742     };
7743     const DWORD exp_indices24[] = {0, 1, 2, 1, 3, 4};
7744     const DWORD exp_face_remap24[] = {0, 1};
7745     const DWORD exp_vertex_remap24[] = {0, 1, 2, 4, 5, -1};
7746     const DWORD exp_new_num_vertices24 = ARRAY_SIZE(exp_vertices24);
7747     /* Test 25. Weld texture coordinates with usage index 10 (TEXCOORD10). The
7748      * usage index is capped at 7, so the epsilon for TEXCOORD7 is used instead.
7749      */
7750     const struct vertex_texcoord vertices25[] =
7751     {
7752         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7753         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7754         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7755 
7756         {{ 3.0f,  3.0f,  0.f}, {0.2f, 0.3f}},
7757         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7758         {{ 1.0f,  0.0f,  0.f}, {0.1f, 0.2f}}
7759     };
7760     const DWORD indices25[] = {0, 1, 2, 3, 4, 5};
7761     const DWORD attributes25[] = {0, 0};
7762     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
7763     const UINT num_faces25 = ARRAY_SIZE(indices25) / VERTS_PER_FACE;
7764     DWORD flags25 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7765     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};
7766     const DWORD adjacency25[] = {-1, 1, -1, -1, -1, 0};
7767     const struct vertex_texcoord exp_vertices25[] =
7768     {
7769         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f}},
7770         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.7f}},
7771         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
7772 
7773         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f}},
7774         {{ 0.0f,  0.0f,  0.f}, {0.1f, 0.2f}},
7775     };
7776     const DWORD exp_indices25[] = {0, 1, 2, 1, 3, 4};
7777     const DWORD exp_face_remap25[] = {0, 1};
7778     const DWORD exp_vertex_remap25[] = {0, 1, 2, 4, 5, -1};
7779     const DWORD exp_new_num_vertices25 = ARRAY_SIZE(exp_vertices25);
7780     /* Test 26. Weld color with usage index larger than 1. Shows that none of
7781      * the epsilon values are used. */
7782     const struct vertex_color vertices26[] =
7783     {
7784         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7785         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7786         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7787 
7788         {{ 3.0f,  3.0f,  0.f}, 0x00000000},
7789         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7790         {{ 1.0f,  0.0f,  0.f}, 0x01010101},
7791     };
7792     const DWORD indices26[] = {0, 1, 2, 3, 4, 5};
7793     const DWORD attributes26[] = {0, 0};
7794     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
7795     const UINT num_faces26 = ARRAY_SIZE(indices26) / VERTS_PER_FACE;
7796     DWORD flags26 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7797     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};
7798     const DWORD adjacency26[] = {-1, 1, -1, -1, -1, 0};
7799     const struct vertex_color exp_vertices26[] =
7800     {
7801         {{ 0.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7802         {{ 2.0f,  3.0f,  0.f}, 0xFFFFFFFF},
7803         {{ 0.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7804 
7805         {{ 2.0f,  3.0f,  0.f}, 0x00000000},
7806         {{ 3.0f,  0.0f,  0.f}, 0xFFFFFFFF},
7807         {{ 0.0f,  0.0f,  0.f}, 0x01010101},
7808     };
7809     const DWORD exp_indices26[] = {0, 1, 2, 3, 4, 5};
7810     const DWORD exp_face_remap26[] = {0, 1};
7811     const DWORD exp_vertex_remap26[] = {0, 1, 2, 3, 4, 5};
7812     const DWORD exp_new_num_vertices26 = ARRAY_SIZE(exp_vertices26);
7813     /* Test 27. Weld color with usage index 1 (specular). */
7814     /* Previously this test used float color values and index > 1 but that case
7815      * appears to be effectively unhandled in native so the test gave
7816      * inconsistent results. */
7817     const struct vertex_color vertices27[] =
7818     {
7819         {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
7820         {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
7821         {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
7822 
7823         {{ 3.0f,  3.0f,  0.0f}, 0x11213141},
7824         {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
7825         {{ 1.0f,  0.0f,  0.0f}, 0x51617181},
7826     };
7827     const DWORD indices27[] = {0, 1, 2, 3, 4, 5};
7828     const DWORD attributes27[] = {0, 0};
7829     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
7830     const UINT num_faces27 = ARRAY_SIZE(indices27) / VERTS_PER_FACE;
7831     DWORD flags27 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7832     const D3DXWELDEPSILONS epsilons27 =
7833     {
7834         1.1f, 0.0f, 0.0f, 0.0f, 2.0f / 255.0f, 0.0f,
7835         {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, 0.0f
7836     };
7837     const DWORD adjacency27[] = {-1, 1, -1, -1, -1, 0};
7838     const struct vertex_color exp_vertices27[] =
7839     {
7840         {{ 0.0f,  3.0f,  0.0f}, 0x00000000},
7841         {{ 2.0f,  3.0f,  0.0f}, 0x10203040},
7842         {{ 0.0f,  0.0f,  0.0f}, 0x50607080},
7843 
7844         {{ 3.0f,  0.0f,  0.0f}, 0xffffffff},
7845     };
7846     const DWORD exp_indices27[] = {0, 1, 2, 1, 3, 2};
7847     const DWORD exp_face_remap27[] = {0, 1};
7848     const DWORD exp_vertex_remap27[] = {0, 1, 2, 4, -1, -1};
7849     const DWORD exp_new_num_vertices27 = ARRAY_SIZE(exp_vertices27);
7850     /* Test 28. Weld one normal with UDEC3. */
7851     const DWORD dword_udec3_zero = init_udec3_dword(0, 0, 0, 1);
7852     const DWORD dword_udec3_1023 = init_udec3_dword(1023, 1023, 1023, 1);
7853     const DWORD dword_udec3_1022 = init_udec3_dword(1022, 1022, 1022, 1);
7854     const struct vertex_normal_udec3 vertices28[] =
7855     {
7856         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7857         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7858         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7859 
7860         {{ 3.0f,  3.0f,  0.f}, dword_udec3_1023},
7861         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7862         {{ 1.0f,  0.0f,  0.f}, dword_udec3_1022},
7863     };
7864     const DWORD indices28[] = {0, 1, 2, 3, 4, 5};
7865     const DWORD attributes28[] = {0, 0};
7866     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
7867     const UINT num_faces28 = ARRAY_SIZE(indices28) / VERTS_PER_FACE;
7868     DWORD flags28 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7869     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};
7870     const DWORD adjacency28[] = {-1, 1, -1, -1, -1, 0};
7871     const struct vertex_normal_udec3 exp_vertices28[] =
7872     {
7873         {{ 0.0f,  3.0f,  0.f}, dword_udec3_zero},
7874         {{ 2.0f,  3.0f,  0.f}, dword_udec3_zero},
7875         {{ 0.0f,  0.0f,  0.f}, dword_udec3_zero},
7876 
7877         {{ 2.0f,  3.0f,  0.f}, dword_udec3_1023},
7878         {{ 3.0f,  0.0f,  0.f}, dword_udec3_zero},
7879     };
7880     const DWORD exp_indices28[] = {0, 1, 2, 3, 4, 2};
7881     const DWORD exp_face_remap28[] = {0, 1};
7882     const DWORD exp_vertex_remap28[] = {0, 1, 2, 3, 4, -1};
7883     const DWORD exp_new_num_vertices28 = ARRAY_SIZE(exp_vertices28);
7884     /* Test 29. Weld one normal with DEC3N. */
7885     const DWORD dword_dec3n_zero = init_dec3n_dword(0, 0, 0, 1);
7886     const DWORD dword_dec3n_511 = init_dec3n_dword(511, 511, 511, 1);
7887     const DWORD dword_dec3n_510 = init_dec3n_dword(510, 510, 510, 1);
7888     const struct vertex_normal_dec3n vertices29[] =
7889     {
7890         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7891         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7892         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7893 
7894         {{ 3.0f,  3.0f,  0.f}, dword_dec3n_511},
7895         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7896         {{ 1.0f,  0.0f,  0.f}, dword_dec3n_510},
7897     };
7898     const DWORD indices29[] = {0, 1, 2, 3, 4, 5};
7899     const DWORD attributes29[] = {0, 0};
7900     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
7901     const UINT num_faces29 = ARRAY_SIZE(indices29) / VERTS_PER_FACE;
7902     DWORD flags29 = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7903     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};
7904     const DWORD adjacency29[] = {-1, 1, -1, -1, -1, 0};
7905     const struct vertex_normal_dec3n exp_vertices29[] =
7906     {
7907         {{ 0.0f,  3.0f,  0.f}, dword_dec3n_zero},
7908         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_zero},
7909         {{ 0.0f,  0.0f,  0.f}, dword_dec3n_zero},
7910 
7911         {{ 2.0f,  3.0f,  0.f}, dword_dec3n_511},
7912         {{ 3.0f,  0.0f,  0.f}, dword_dec3n_zero},
7913     };
7914     const DWORD exp_indices29[] = {0, 1, 2, 3, 4, 2};
7915     const DWORD exp_face_remap29[] = {0, 1};
7916     const DWORD exp_vertex_remap29[] = {0, 1, 2, 3, 4, -1};
7917     const DWORD exp_new_num_vertices29 = ARRAY_SIZE(exp_vertices29);
7918     /* All mesh data */
7919     DWORD *adjacency_out = NULL;
7920     DWORD *face_remap = NULL;
7921     ID3DXMesh *mesh = NULL;
7922     ID3DXBuffer *vertex_remap = NULL;
7923     struct
7924     {
7925         const BYTE *vertices;
7926         const DWORD *indices;
7927         const DWORD *attributes;
7928         const DWORD num_vertices;
7929         const DWORD num_faces;
7930         const DWORD options;
7931         D3DVERTEXELEMENT9 *declaration;
7932         const UINT vertex_size;
7933         const DWORD flags;
7934         const D3DXWELDEPSILONS *epsilons;
7935         const DWORD *adjacency;
7936         const BYTE *exp_vertices;
7937         const DWORD *exp_indices;
7938         const DWORD *exp_face_remap;
7939         const DWORD *exp_vertex_remap;
7940         const DWORD exp_new_num_vertices;
7941     }
7942     tc[] =
7943     {
7944         {
7945             (BYTE*)vertices0,
7946             indices0,
7947             attributes0,
7948             num_vertices0,
7949             num_faces0,
7950             options,
7951             declaration_normal,
7952             vertex_size_normal,
7953             flags0,
7954             NULL,
7955             adjacency0,
7956             (BYTE*)exp_vertices0,
7957             exp_indices0,
7958             exp_face_remap0,
7959             exp_vertex_remap0,
7960             exp_new_num_vertices0
7961         },
7962         {
7963             (BYTE*)vertices1,
7964             indices1,
7965             attributes1,
7966             num_vertices1,
7967             num_faces1,
7968             options,
7969             declaration_normal,
7970             vertex_size_normal,
7971             flags1,
7972             NULL,
7973             adjacency1,
7974             (BYTE*)exp_vertices1,
7975             exp_indices1,
7976             exp_face_remap1,
7977             exp_vertex_remap1,
7978             exp_new_num_vertices1
7979         },
7980         {
7981             (BYTE*)vertices2,
7982             indices2,
7983             attributes2,
7984             num_vertices2,
7985             num_faces2,
7986             options,
7987             declaration_normal,
7988             vertex_size_normal,
7989             flags2,
7990             &epsilons2,
7991             adjacency2,
7992             (BYTE*)exp_vertices2,
7993             exp_indices2,
7994             exp_face_remap2,
7995             exp_vertex_remap2,
7996             exp_new_num_vertices2
7997         },
7998         {
7999             (BYTE*)vertices3,
8000             indices3,
8001             attributes3,
8002             num_vertices3,
8003             num_faces3,
8004             options,
8005             declaration_normal,
8006             vertex_size_normal,
8007             flags3,
8008             &epsilons3,
8009             adjacency3,
8010             (BYTE*)exp_vertices3,
8011             exp_indices3,
8012             exp_face_remap3,
8013             exp_vertex_remap3,
8014             exp_new_num_vertices3
8015         },
8016         {
8017             (BYTE*)vertices4,
8018             indices4,
8019             attributes4,
8020             num_vertices4,
8021             num_faces4,
8022             options,
8023             declaration_normal,
8024             vertex_size_normal,
8025             flags4,
8026             &epsilons4,
8027             adjacency4,
8028             (BYTE*)exp_vertices4,
8029             exp_indices4,
8030             exp_face_remap4,
8031             exp_vertex_remap4,
8032             exp_new_num_vertices4
8033         },
8034         /* Unusual ordering. */
8035         {
8036             (BYTE*)vertices5,
8037             indices5,
8038             attributes5,
8039             num_vertices5,
8040             num_faces5,
8041             options,
8042             declaration_normal,
8043             vertex_size_normal,
8044             flags5,
8045             NULL,
8046             adjacency5,
8047             (BYTE*)exp_vertices5,
8048             exp_indices5,
8049             exp_face_remap5,
8050             exp_vertex_remap5,
8051             exp_new_num_vertices5
8052         },
8053         {
8054             (BYTE*)vertices6,
8055             indices6,
8056             attributes6,
8057             num_vertices6,
8058             num_faces6,
8059             options,
8060             declaration_normal,
8061             vertex_size_normal,
8062             flags6,
8063             &epsilons6,
8064             adjacency6,
8065             (BYTE*)exp_vertices6,
8066             exp_indices6,
8067             exp_face_remap6,
8068             exp_vertex_remap6,
8069             exp_new_num_vertices6
8070         },
8071         {
8072             (BYTE*)vertices6,
8073             (DWORD*)indices6_16bit,
8074             attributes6,
8075             num_vertices6,
8076             num_faces6,
8077             options_16bit,
8078             declaration_normal,
8079             vertex_size_normal,
8080             flags6,
8081             &epsilons6,
8082             adjacency6,
8083             (BYTE*)exp_vertices6,
8084             exp_indices6,
8085             exp_face_remap6,
8086             exp_vertex_remap6,
8087             exp_new_num_vertices6
8088         },
8089         {
8090             (BYTE*)vertices8,
8091             indices8,
8092             attributes8,
8093             num_vertices8,
8094             num_faces8,
8095             options,
8096             declaration_normal,
8097             vertex_size_normal,
8098             flags8,
8099             &epsilons8,
8100             adjacency8,
8101             (BYTE*)exp_vertices8,
8102             exp_indices8,
8103             exp_face_remap8,
8104             exp_vertex_remap8,
8105             exp_new_num_vertices8
8106         },
8107         {
8108             (BYTE*)vertices9,
8109             indices9,
8110             attributes9,
8111             num_vertices9,
8112             num_faces9,
8113             options,
8114             declaration_normal,
8115             vertex_size_normal,
8116             flags9,
8117             &epsilons9,
8118             adjacency9,
8119             (BYTE*)exp_vertices9,
8120             exp_indices9,
8121             exp_face_remap9,
8122             exp_vertex_remap9,
8123             exp_new_num_vertices9
8124         },
8125         {
8126             (BYTE*)vertices10,
8127             indices10,
8128             attributes10,
8129             num_vertices10,
8130             num_faces10,
8131             options,
8132             declaration_blendweight,
8133             vertex_size_blendweight,
8134             flags10,
8135             &epsilons10,
8136             adjacency10,
8137             (BYTE*)exp_vertices10,
8138             exp_indices10,
8139             exp_face_remap10,
8140             exp_vertex_remap10,
8141             exp_new_num_vertices10
8142         },
8143         {
8144             (BYTE*)vertices11,
8145             indices11,
8146             attributes11,
8147             num_vertices11,
8148             num_faces11,
8149             options,
8150             declaration_texcoord,
8151             vertex_size_texcoord,
8152             flags11,
8153             &epsilons11,
8154             adjacency11,
8155             (BYTE*)exp_vertices11,
8156             exp_indices11,
8157             exp_face_remap11,
8158             exp_vertex_remap11,
8159             exp_new_num_vertices11
8160         },
8161         {
8162             (BYTE*)vertices12,
8163             indices12,
8164             attributes12,
8165             num_vertices12,
8166             num_faces12,
8167             options,
8168             declaration_color,
8169             vertex_size_color,
8170             flags12,
8171             &epsilons12,
8172             adjacency12,
8173             (BYTE*)exp_vertices12,
8174             exp_indices12,
8175             exp_face_remap12,
8176             exp_vertex_remap12,
8177             exp_new_num_vertices12
8178         },
8179         {
8180             (BYTE*)vertices13,
8181             indices13,
8182             attributes13,
8183             num_vertices13,
8184             num_faces13,
8185             options,
8186             declaration_normal3,
8187             vertex_size_normal,
8188             flags13,
8189             &epsilons13,
8190             adjacency13,
8191             (BYTE*)exp_vertices13,
8192             exp_indices13,
8193             exp_face_remap13,
8194             exp_vertex_remap13,
8195             exp_new_num_vertices13
8196         },
8197         {
8198             (BYTE*)vertices14,
8199             indices14,
8200             attributes14,
8201             num_vertices14,
8202             num_faces14,
8203             options,
8204             declaration_color,
8205             vertex_size_color,
8206             flags14,
8207             &epsilons14,
8208             adjacency14,
8209             (BYTE*)exp_vertices14,
8210             exp_indices14,
8211             exp_face_remap14,
8212             exp_vertex_remap14,
8213             exp_new_num_vertices14
8214         },
8215         {
8216             (BYTE*)vertices15,
8217             indices15,
8218             attributes15,
8219             num_vertices15,
8220             num_faces15,
8221             options,
8222             declaration_color_ubyte4n,
8223             vertex_size_color_ubyte4, /* UBYTE4 same size as UBYTE4N */
8224             flags15,
8225             &epsilons15,
8226             adjacency15,
8227             (BYTE*)exp_vertices15,
8228             exp_indices15,
8229             exp_face_remap15,
8230             exp_vertex_remap15,
8231             exp_new_num_vertices15
8232         },
8233         {
8234             (BYTE*)vertices16,
8235             indices16,
8236             attributes16,
8237             num_vertices16,
8238             num_faces16,
8239             options,
8240             declaration_color_ubyte4,
8241             vertex_size_color_ubyte4,
8242             flags16,
8243             &epsilons16,
8244             adjacency16,
8245             (BYTE*)exp_vertices16,
8246             exp_indices16,
8247             exp_face_remap16,
8248             exp_vertex_remap16,
8249             exp_new_num_vertices16
8250         },
8251         {
8252             (BYTE*)vertices17,
8253             indices17,
8254             attributes17,
8255             num_vertices17,
8256             num_faces17,
8257             options,
8258             declaration_texcoord_short2,
8259             vertex_size_texcoord_short2,
8260             flags17,
8261             &epsilons17,
8262             adjacency17,
8263             (BYTE*)exp_vertices17,
8264             exp_indices17,
8265             exp_face_remap17,
8266             exp_vertex_remap17,
8267             exp_new_num_vertices17
8268         },
8269         {
8270             (BYTE*)vertices18,
8271             indices18,
8272             attributes18,
8273             num_vertices18,
8274             num_faces18,
8275             options,
8276             declaration_texcoord_short2n,
8277             vertex_size_texcoord_short2, /* SHORT2 same size as SHORT2N */
8278             flags18,
8279             &epsilons18,
8280             adjacency18,
8281             (BYTE*)exp_vertices18,
8282             exp_indices18,
8283             exp_face_remap18,
8284             exp_vertex_remap18,
8285             exp_new_num_vertices18
8286         },
8287         {
8288             (BYTE*)vertices19,
8289             indices19,
8290             attributes19,
8291             num_vertices19,
8292             num_faces19,
8293             options,
8294             declaration_texcoord_ushort2n,
8295             vertex_size_texcoord_short2, /* SHORT2 same size as USHORT2N */
8296             flags19,
8297             &epsilons19,
8298             adjacency19,
8299             (BYTE*)exp_vertices19,
8300             exp_indices19,
8301             exp_face_remap19,
8302             exp_vertex_remap19,
8303             exp_new_num_vertices19
8304         },
8305         {
8306             (BYTE*)vertices20,
8307             indices20,
8308             attributes20,
8309             num_vertices20,
8310             num_faces20,
8311             options,
8312             declaration_normal_short4,
8313             vertex_size_normal_short4,
8314             flags20,
8315             &epsilons20,
8316             adjacency20,
8317             (BYTE*)exp_vertices20,
8318             exp_indices20,
8319             exp_face_remap20,
8320             exp_vertex_remap20,
8321             exp_new_num_vertices20
8322         },
8323         {
8324             (BYTE*)vertices21,
8325             indices21,
8326             attributes21,
8327             num_vertices21,
8328             num_faces21,
8329             options,
8330             declaration_normal_short4n,
8331             vertex_size_normal_short4, /* SHORT4 same size as SHORT4N */
8332             flags21,
8333             &epsilons21,
8334             adjacency21,
8335             (BYTE*)exp_vertices21,
8336             exp_indices21,
8337             exp_face_remap21,
8338             exp_vertex_remap21,
8339             exp_new_num_vertices21
8340         },
8341         {
8342             (BYTE*)vertices22,
8343             indices22,
8344             attributes22,
8345             num_vertices22,
8346             num_faces22,
8347             options,
8348             declaration_normal_ushort4n,
8349             vertex_size_normal_short4, /* SHORT4 same size as USHORT4N */
8350             flags22,
8351             &epsilons22,
8352             adjacency22,
8353             (BYTE*)exp_vertices22,
8354             exp_indices22,
8355             exp_face_remap22,
8356             exp_vertex_remap22,
8357             exp_new_num_vertices22
8358         },
8359         {
8360             (BYTE*)vertices23,
8361             indices23,
8362             attributes23,
8363             num_vertices23,
8364             num_faces23,
8365             options,
8366             declaration_texcoord_float16_2,
8367             vertex_size_texcoord_float16_2,
8368             flags23,
8369             &epsilons23,
8370             adjacency23,
8371             (BYTE*)exp_vertices23,
8372             exp_indices23,
8373             exp_face_remap23,
8374             exp_vertex_remap23,
8375             exp_new_num_vertices23
8376         },
8377         {
8378             (BYTE*)vertices24,
8379             indices24,
8380             attributes24,
8381             num_vertices24,
8382             num_faces24,
8383             options,
8384             declaration_texcoord_float16_4,
8385             vertex_size_texcoord_float16_4,
8386             flags24,
8387             &epsilons24,
8388             adjacency24,
8389             (BYTE*)exp_vertices24,
8390             exp_indices24,
8391             exp_face_remap24,
8392             exp_vertex_remap24,
8393             exp_new_num_vertices24
8394         },
8395         {
8396             (BYTE*)vertices25,
8397             indices25,
8398             attributes25,
8399             num_vertices25,
8400             num_faces25,
8401             options,
8402             declaration_texcoord10,
8403             vertex_size_texcoord,
8404             flags25,
8405             &epsilons25,
8406             adjacency25,
8407             (BYTE*)exp_vertices25,
8408             exp_indices25,
8409             exp_face_remap25,
8410             exp_vertex_remap25,
8411             exp_new_num_vertices25
8412         },
8413         {
8414             (BYTE*)vertices26,
8415             indices26,
8416             attributes26,
8417             num_vertices26,
8418             num_faces26,
8419             options,
8420             declaration_color2,
8421             vertex_size_color,
8422             flags26,
8423             &epsilons26,
8424             adjacency26,
8425             (BYTE*)exp_vertices26,
8426             exp_indices26,
8427             exp_face_remap26,
8428             exp_vertex_remap26,
8429             exp_new_num_vertices26
8430         },
8431         {
8432             (BYTE*)vertices27,
8433             indices27,
8434             attributes27,
8435             num_vertices27,
8436             num_faces27,
8437             options,
8438             declaration_color1,
8439             vertex_size_color,
8440             flags27,
8441             &epsilons27,
8442             adjacency27,
8443             (BYTE*)exp_vertices27,
8444             exp_indices27,
8445             exp_face_remap27,
8446             exp_vertex_remap27,
8447             exp_new_num_vertices27
8448         },
8449         {
8450             (BYTE*)vertices28,
8451             indices28,
8452             attributes28,
8453             num_vertices28,
8454             num_faces28,
8455             options,
8456             declaration_normal_udec3,
8457             vertex_size_normal_udec3,
8458             flags28,
8459             &epsilons28,
8460             adjacency28,
8461             (BYTE*)exp_vertices28,
8462             exp_indices28,
8463             exp_face_remap28,
8464             exp_vertex_remap28,
8465             exp_new_num_vertices28
8466         },
8467         {
8468             (BYTE*)vertices29,
8469             indices29,
8470             attributes29,
8471             num_vertices29,
8472             num_faces29,
8473             options,
8474             declaration_normal_dec3n,
8475             vertex_size_normal_dec3n,
8476             flags29,
8477             &epsilons29,
8478             adjacency29,
8479             (BYTE*)exp_vertices29,
8480             exp_indices29,
8481             exp_face_remap29,
8482             exp_vertex_remap29,
8483             exp_new_num_vertices29
8484         }
8485     };
8486 #ifdef __REACTOS__
8487 #undef up
8488 #endif
8489 
8490     test_context = new_test_context();
8491     if (!test_context)
8492     {
8493         skip("Couldn't create test context\n");
8494         goto cleanup;
8495     }
8496 
8497     for (i = 0; i < ARRAY_SIZE(tc); i++)
8498     {
8499         DWORD j;
8500         DWORD *vertex_remap_ptr;
8501         DWORD new_num_vertices;
8502 
8503         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
8504                             tc[i].declaration, test_context->device, &mesh,
8505                             tc[i].vertices, tc[i].vertex_size,
8506                             tc[i].indices, tc[i].attributes);
8507         if (FAILED(hr))
8508         {
8509             skip("Couldn't initialize test mesh %d.\n", i);
8510             goto cleanup;
8511         }
8512 
8513         /* Allocate out parameters */
8514         adjacency_out = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency_out));
8515         if (!adjacency_out)
8516         {
8517             skip("Couldn't allocate adjacency_out array.\n");
8518             goto cleanup;
8519         }
8520         face_remap = HeapAlloc(GetProcessHeap(), 0, tc[i].num_faces * sizeof(*face_remap));
8521         if (!face_remap)
8522         {
8523             skip("Couldn't allocate face_remap array.\n");
8524             goto cleanup;
8525         }
8526 
8527         hr = D3DXWeldVertices(mesh, tc[i].flags, tc[i].epsilons, tc[i].adjacency,
8528                               adjacency_out, face_remap, &vertex_remap);
8529         ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
8530         /* Check number of vertices*/
8531         new_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
8532         ok(new_num_vertices == tc[i].exp_new_num_vertices,
8533            "Mesh %d: new_num_vertices == %d, expected %d.\n",
8534            i, new_num_vertices, tc[i].exp_new_num_vertices);
8535         /* Check index buffer */
8536         if (tc[i].options & D3DXMESH_32BIT)
8537         {
8538             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices);
8539             if (FAILED(hr))
8540             {
8541                 skip("Couldn't lock index buffer.\n");
8542                 goto cleanup;
8543             }
8544             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8545             {
8546                 ok(indices[j] == tc[i].exp_indices[j],
8547                    "Mesh %d: indices[%d] == %d, expected %d\n",
8548                    i, j, indices[j], tc[i].exp_indices[j]);
8549             }
8550         }
8551         else
8552         {
8553             hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void**)&indices_16bit);
8554             if (FAILED(hr))
8555             {
8556                 skip("Couldn't lock index buffer.\n");
8557                 goto cleanup;
8558             }
8559             for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8560             {
8561                 ok(indices_16bit[j] == tc[i].exp_indices[j],
8562                    "Mesh %d: indices_16bit[%d] == %d, expected %d\n",
8563                    i, j, indices_16bit[j], tc[i].exp_indices[j]);
8564             }
8565         }
8566         mesh->lpVtbl->UnlockIndexBuffer(mesh);
8567         indices = NULL;
8568         indices_16bit = NULL;
8569         /* Check adjacency_out */
8570         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8571         {
8572             ok(adjacency_out[j] == tc[i].adjacency[j],
8573                "Mesh %d: adjacency_out[%d] == %d, expected %d\n",
8574                i, j, adjacency_out[j], tc[i].adjacency[j]);
8575         }
8576         /* Check face_remap */
8577         for (j = 0; j < tc[i].num_faces; j++)
8578         {
8579             ok(face_remap[j] == tc[i].exp_face_remap[j],
8580                "Mesh %d: face_remap[%d] == %d, expected %d\n",
8581                i, j, face_remap[j], tc[i].exp_face_remap[j]);
8582         }
8583         /* Check vertex_remap */
8584         vertex_remap_ptr = vertex_remap->lpVtbl->GetBufferPointer(vertex_remap);
8585         for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
8586         {
8587             ok(vertex_remap_ptr[j] == tc[i].exp_vertex_remap[j],
8588                "Mesh %d: vertex_remap_ptr[%d] == %d, expected %d\n",
8589                i, j, vertex_remap_ptr[j], tc[i].exp_vertex_remap[j]);
8590         }
8591         /* Check vertex buffer */
8592         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void*)&vertices);
8593         if (FAILED(hr))
8594         {
8595             skip("Couldn't lock vertex buffer.\n");
8596             goto cleanup;
8597         }
8598         /* Check contents of re-ordered vertex buffer */
8599         for (j = 0; j < tc[i].exp_new_num_vertices; j++)
8600         {
8601             int index = tc[i].vertex_size*j;
8602             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].declaration);
8603         }
8604         mesh->lpVtbl->UnlockVertexBuffer(mesh);
8605         vertices = NULL;
8606 
8607         /* Free mesh and output data */
8608         HeapFree(GetProcessHeap(), 0, adjacency_out);
8609         adjacency_out = NULL;
8610         HeapFree(GetProcessHeap(), 0, face_remap);
8611         face_remap = NULL;
8612         vertex_remap->lpVtbl->Release(vertex_remap);
8613         vertex_remap = NULL;
8614         mesh->lpVtbl->Release(mesh);
8615         mesh = NULL;
8616     }
8617 
8618 cleanup:
8619     HeapFree(GetProcessHeap(), 0, adjacency_out);
8620     HeapFree(GetProcessHeap(), 0, face_remap);
8621     if (indices) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8622     if (indices_16bit) mesh->lpVtbl->UnlockIndexBuffer(mesh);
8623     if (mesh) mesh->lpVtbl->Release(mesh);
8624     if (vertex_remap) vertex_remap->lpVtbl->Release(vertex_remap);
8625     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
8626     free_test_context(test_context);
8627 }
8628 
test_clone_mesh(void)8629 static void test_clone_mesh(void)
8630 {
8631     HRESULT hr;
8632     struct test_context *test_context = NULL;
8633     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
8634     D3DVERTEXELEMENT9 declaration_pn[] =
8635     {
8636         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8637         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8638         D3DDECL_END()
8639     };
8640     D3DVERTEXELEMENT9 declaration_pntc[] =
8641     {
8642         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8643         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8644         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8645         D3DDECL_END()
8646     };
8647     D3DVERTEXELEMENT9 declaration_ptcn[] =
8648     {
8649         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8650         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8651         {0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8652         D3DDECL_END()
8653     };
8654     D3DVERTEXELEMENT9 declaration_ptc[] =
8655     {
8656         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8657         {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8658         D3DDECL_END()
8659     };
8660     D3DVERTEXELEMENT9 declaration_ptc_float16_2[] =
8661     {
8662         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8663         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8664         D3DDECL_END()
8665     };
8666     D3DVERTEXELEMENT9 declaration_ptc_float16_4[] =
8667     {
8668         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8669         {0, 12, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8670         D3DDECL_END()
8671     };
8672     D3DVERTEXELEMENT9 declaration_ptc_float1[] =
8673     {
8674         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8675         {0, 12, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8676         D3DDECL_END()
8677     };
8678     D3DVERTEXELEMENT9 declaration_ptc_float3[] =
8679     {
8680         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8681         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8682         D3DDECL_END()
8683     };
8684     D3DVERTEXELEMENT9 declaration_ptc_float4[] =
8685     {
8686         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8687         {0, 12, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8688         D3DDECL_END()
8689     };
8690     D3DVERTEXELEMENT9 declaration_ptc_d3dcolor[] =
8691     {
8692         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8693         {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8694         D3DDECL_END()
8695     };
8696     D3DVERTEXELEMENT9 declaration_ptc_ubyte4[] =
8697     {
8698         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8699         {0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8700         D3DDECL_END()
8701     };
8702     D3DVERTEXELEMENT9 declaration_ptc_ubyte4n[] =
8703     {
8704         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8705         {0, 12, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8706         D3DDECL_END()
8707     };
8708     D3DVERTEXELEMENT9 declaration_ptc_short2[] =
8709     {
8710         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8711         {0, 12, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8712         D3DDECL_END()
8713     };
8714     D3DVERTEXELEMENT9 declaration_ptc_short4[] =
8715     {
8716         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8717         {0, 12, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8718         D3DDECL_END()
8719     };
8720     D3DVERTEXELEMENT9 declaration_ptc_short2n[] =
8721     {
8722         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8723         {0, 12, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8724         D3DDECL_END()
8725     };
8726     D3DVERTEXELEMENT9 declaration_ptc_short4n[] =
8727     {
8728         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8729         {0, 12, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8730         D3DDECL_END()
8731     };
8732     D3DVERTEXELEMENT9 declaration_ptc_ushort2n[] =
8733     {
8734         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8735         {0, 12, D3DDECLTYPE_USHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8736         D3DDECL_END()
8737     };
8738     D3DVERTEXELEMENT9 declaration_ptc_ushort4n[] =
8739     {
8740         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8741         {0, 12, D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
8742         D3DDECL_END()
8743     };
8744     D3DVERTEXELEMENT9 declaration_ptc_float16_2_partialu[] =
8745     {
8746         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8747         {0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_PARTIALU, D3DDECLUSAGE_TEXCOORD, 0},
8748         D3DDECL_END()
8749     };
8750     D3DVERTEXELEMENT9 declaration_pntc1[] =
8751     {
8752         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
8753         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
8754         {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
8755         D3DDECL_END()
8756     };
8757     const unsigned int VERTS_PER_FACE = 3;
8758     BYTE *vertices = NULL;
8759     INT i;
8760     struct vertex_pn
8761     {
8762         D3DXVECTOR3 position;
8763         D3DXVECTOR3 normal;
8764     };
8765     struct vertex_pntc
8766     {
8767         D3DXVECTOR3 position;
8768         D3DXVECTOR3 normal;
8769         D3DXVECTOR2 texcoords;
8770     };
8771     struct vertex_ptcn
8772     {
8773         D3DXVECTOR3 position;
8774         D3DXVECTOR2 texcoords;
8775         D3DXVECTOR3 normal;
8776     };
8777     struct vertex_ptc
8778     {
8779         D3DXVECTOR3 position;
8780         D3DXVECTOR2 texcoords;
8781     };
8782     struct vertex_ptc_float16_2
8783     {
8784         D3DXVECTOR3 position;
8785         WORD texcoords[2]; /* float16_2 */
8786     };
8787     struct vertex_ptc_float16_4
8788     {
8789         D3DXVECTOR3 position;
8790         WORD texcoords[4]; /* float16_4 */
8791     };
8792     struct vertex_ptc_float1
8793     {
8794         D3DXVECTOR3 position;
8795         FLOAT texcoords;
8796     };
8797     struct vertex_ptc_float3
8798     {
8799         D3DXVECTOR3 position;
8800         FLOAT texcoords[3];
8801     };
8802     struct vertex_ptc_float4
8803     {
8804         D3DXVECTOR3 position;
8805         FLOAT texcoords[4];
8806     };
8807     struct vertex_ptc_d3dcolor
8808     {
8809         D3DXVECTOR3 position;
8810         BYTE texcoords[4];
8811     };
8812     struct vertex_ptc_ubyte4
8813     {
8814         D3DXVECTOR3 position;
8815         BYTE texcoords[4];
8816     };
8817     struct vertex_ptc_ubyte4n
8818     {
8819         D3DXVECTOR3 position;
8820         BYTE texcoords[4];
8821     };
8822     struct vertex_ptc_short2
8823     {
8824         D3DXVECTOR3 position;
8825         SHORT texcoords[2];
8826     };
8827     struct vertex_ptc_short4
8828     {
8829         D3DXVECTOR3 position;
8830         SHORT texcoords[4];
8831     };
8832     struct vertex_ptc_ushort2n
8833     {
8834         D3DXVECTOR3 position;
8835         USHORT texcoords[2];
8836     };
8837     struct vertex_ptc_ushort4n
8838     {
8839         D3DXVECTOR3 position;
8840         USHORT texcoords[4];
8841     };
8842     struct vertex_ptc_udec3
8843     {
8844         D3DXVECTOR3 position;
8845         DWORD texcoords;
8846     };
8847     struct vertex_ptc_dec3n
8848     {
8849         D3DXVECTOR3 position;
8850         DWORD texcoords;
8851     };
8852 #ifndef __REACTOS__
8853     D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
8854     D3DXVECTOR2 zero_vec2 = {0.0f, 0.0f};
8855 #else
8856 #define up {0.0f, 0.0f, 1.0f}
8857 #define zero_vec2 {0.0f, 0.0f}
8858 #endif
8859     /* Test 0. Check that a mesh can be cloned if the new declaration is the
8860      * same as the one used to create the mesh.
8861      *
8862      * 0--1 3
8863      * | / /|
8864      * |/ / |
8865      * 2 5--4
8866      */
8867     const struct vertex_pn vertices0[] =
8868     {
8869         {{ 0.0f,  3.0f,  0.f}, up},
8870         {{ 2.0f,  3.0f,  0.f}, up},
8871         {{ 0.0f,  0.0f,  0.f}, up},
8872 
8873         {{ 3.0f,  3.0f,  0.f}, up},
8874         {{ 3.0f,  0.0f,  0.f}, up},
8875         {{ 1.0f,  0.0f,  0.f}, up},
8876     };
8877     const UINT num_vertices0 = ARRAY_SIZE(vertices0);
8878     const UINT num_faces0 = ARRAY_SIZE(vertices0) / VERTS_PER_FACE;
8879     const UINT vertex_size0 = sizeof(*vertices0);
8880     /* Test 1. Check that 16-bit indices are handled. */
8881     const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
8882     /* Test 2. Check that the size of each vertex is increased and the data
8883      * moved if the new declaration adds an element after the original elements.
8884      */
8885     const struct vertex_pntc exp_vertices2[] =
8886     {
8887         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
8888         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
8889         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
8890 
8891         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
8892         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
8893         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
8894     };
8895     const UINT exp_vertex_size2 = sizeof(*exp_vertices2);
8896     /* Test 3. Check that the size of each vertex is increased and the data
8897      * moved if the new declaration adds an element between the original
8898      * elements.
8899      */
8900     const struct vertex_ptcn exp_vertices3[] =
8901     {
8902         {{ 0.0f,  3.0f,  0.f}, zero_vec2, up},
8903         {{ 2.0f,  3.0f,  0.f}, zero_vec2, up},
8904         {{ 0.0f,  0.0f,  0.f}, zero_vec2, up},
8905 
8906         {{ 3.0f,  3.0f,  0.f}, zero_vec2, up},
8907         {{ 3.0f,  0.0f,  0.f}, zero_vec2, up},
8908         {{ 1.0f,  0.0f,  0.f}, zero_vec2, up},
8909     };
8910     const UINT exp_vertex_size3 = sizeof(*exp_vertices3);
8911     /* Test 4. Test that data types can be converted, e.g. FLOAT2 to FLOAT16_2. */
8912     const struct vertex_ptc vertices4[] =
8913     {
8914         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8915         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8916         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8917 
8918         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8919         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8920         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8921     };
8922     const UINT num_vertices4 = ARRAY_SIZE(vertices4);
8923     const UINT num_faces4 = ARRAY_SIZE(vertices4) / VERTS_PER_FACE;
8924     const UINT vertex_size4 = sizeof(*vertices4);
8925     const struct vertex_ptc_float16_2 exp_vertices4[] =
8926     {
8927         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8928         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
8929         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
8930 
8931         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
8932         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
8933         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
8934     };
8935     const UINT exp_vertex_size4 = sizeof(*exp_vertices4);
8936     /* Test 5. Convert FLOAT2 to FLOAT16_4. */
8937     const struct vertex_ptc vertices5[] =
8938     {
8939         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8940         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8941         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8942 
8943         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8944         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8945         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8946     };
8947     const UINT num_vertices5 = ARRAY_SIZE(vertices5);
8948     const UINT num_faces5 = ARRAY_SIZE(vertices5) / VERTS_PER_FACE;
8949     const UINT vertex_size5 = sizeof(*vertices5);
8950     const struct vertex_ptc_float16_4 exp_vertices5[] =
8951     {
8952         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8953         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a, 0, 0x3c00}}, /* {0.5f, 0.7f, 0.0f, 1.0f} */
8954         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd, 0, 0x3c00}}, /* {-0.2f, -0.3f, 0.0f, 1.0f} */
8955 
8956         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd, 0, 0x3c00}}, /* {0.2f, 0.3f, 0.0f, 1.0f} */
8957         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00, 0, 0x3c00}}, /* {1.0f, 1.0f, 0.0f, 1.0f} */
8958         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0, 0x3c00}}, /* {0.1f, 0.2f, 0.0f, 1.0f} */
8959     };
8960     const UINT exp_vertex_size5 = sizeof(*exp_vertices5);
8961     /* Test 6. Convert FLOAT2 to FLOAT1. */
8962     const struct vertex_ptc vertices6[] =
8963     {
8964         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8965         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8966         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8967 
8968         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8969         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8970         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8971     };
8972     const UINT num_vertices6 = ARRAY_SIZE(vertices6);
8973     const UINT num_faces6 = ARRAY_SIZE(vertices6) / VERTS_PER_FACE;
8974     const UINT vertex_size6 = sizeof(*vertices6);
8975     const struct vertex_ptc_float1 exp_vertices6[] =
8976     {
8977         {{ 0.0f,  3.0f,  0.f},  1.0f},
8978         {{ 2.0f,  3.0f,  0.f},  0.5f},
8979         {{ 0.0f,  0.0f,  0.f}, -0.2f},
8980 
8981         {{ 3.0f,  3.0f,  0.f},  0.2f},
8982         {{ 3.0f,  0.0f,  0.f},  1.0f},
8983         {{ 1.0f,  0.0f,  0.f},  0.1f},
8984     };
8985     const UINT exp_vertex_size6 = sizeof(*exp_vertices6);
8986     /* Test 7. Convert FLOAT2 to FLOAT3. */
8987     const struct vertex_ptc vertices7[] =
8988     {
8989         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
8990         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
8991         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
8992 
8993         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
8994         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
8995         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
8996     };
8997     const UINT num_vertices7 = ARRAY_SIZE(vertices7);
8998     const UINT num_faces7 = ARRAY_SIZE(vertices7) / VERTS_PER_FACE;
8999     const UINT vertex_size7 = sizeof(*vertices7);
9000     const struct vertex_ptc_float3 exp_vertices7[] =
9001     {
9002         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
9003         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f}},
9004         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f}},
9005 
9006         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f}},
9007         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f}},
9008         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f}},
9009     };
9010     const UINT exp_vertex_size7 = sizeof(*exp_vertices7);
9011     /* Test 8. Convert FLOAT2 to FLOAT4. */
9012     const struct vertex_ptc vertices8[] =
9013     {
9014         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9015         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9016         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
9017 
9018         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9019         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
9020         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
9021     };
9022     const UINT num_vertices8 = ARRAY_SIZE(vertices8);
9023     const UINT num_faces8 = ARRAY_SIZE(vertices8) / VERTS_PER_FACE;
9024     const UINT vertex_size8 = sizeof(*vertices8);
9025     const struct vertex_ptc_float4 exp_vertices8[] =
9026     {
9027         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
9028         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f, 0.0f, 1.0f}},
9029         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f, 0.0f, 1.0f}},
9030 
9031         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f, 0.0f, 1.0f}},
9032         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f, 0.0f, 1.0f}},
9033         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f, 0.0f, 1.0f}},
9034     };
9035     const UINT exp_vertex_size8 = sizeof(*exp_vertices8);
9036     /* Test 9. Convert FLOAT2 to D3DCOLOR. */
9037     const struct vertex_ptc vertices9[] =
9038     {
9039         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9040         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9041         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.6f}},
9042 
9043         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9044         {{ 3.0f,  0.0f,  0.f}, { 2.0f, 256.0f}},
9045         {{ 1.0f,  0.0f,  0.f}, { 0.11f,  0.2f}},
9046     };
9047     const UINT num_vertices9 = ARRAY_SIZE(vertices9);
9048     const UINT num_faces9 = ARRAY_SIZE(vertices9) / VERTS_PER_FACE;
9049     const UINT vertex_size9 = sizeof(*vertices9);
9050     const struct vertex_ptc_d3dcolor exp_vertices9[] =
9051     {
9052         {{ 0.0f,  3.0f,  0.f}, {0, 255, 255, 255}},
9053         {{ 2.0f,  3.0f,  0.f}, {0, 179, 128, 255}},
9054         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9055 
9056         {{ 3.0f,  3.0f,  0.f}, {0, 77, 51, 255}},
9057         {{ 3.0f,  0.0f,  0.f}, {0, 255, 255, 255}},
9058         {{ 1.0f,  0.0f,  0.f}, {0, 51, 28, 255}},
9059     };
9060     const UINT exp_vertex_size9 = sizeof(*exp_vertices9);
9061     /* Test 10. Convert FLOAT2 to UBYTE4. */
9062     const struct vertex_ptc vertices10[] =
9063     {
9064         {{ 0.0f,  3.0f,  0.f}, { 0.0f,  1.0f}},
9065         {{ 2.0f,  3.0f,  0.f}, { 2.0f,  3.0f}},
9066         {{ 0.0f,  0.0f,  0.f}, { 254.0f,  255.0f}},
9067 
9068         {{ 3.0f,  3.0f,  0.f}, { 256.0f, 257.0f}},
9069         {{ 3.0f,  0.0f,  0.f}, { 1.4f, 1.5f}},
9070         {{ 1.0f,  0.0f,  0.f}, {-4.0f, -5.0f}},
9071     };
9072     const UINT num_vertices10 = ARRAY_SIZE(vertices10);
9073     const UINT num_faces10 = ARRAY_SIZE(vertices10) / VERTS_PER_FACE;
9074     const UINT vertex_size10 = sizeof(*vertices10);
9075     const struct vertex_ptc_ubyte4 exp_vertices10[] =
9076     {
9077         {{ 0.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9078         {{ 2.0f,  3.0f,  0.f}, {2, 3, 0, 1}},
9079         {{ 0.0f,  0.0f,  0.f}, {254, 255, 0, 1}},
9080 
9081         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9082         {{ 3.0f,  0.0f,  0.f}, {1, 2, 0, 1}},
9083         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9084     };
9085     const UINT exp_vertex_size10 = sizeof(*exp_vertices10);
9086     /* Test 11. Convert FLOAT2 to SHORT2. */
9087     const struct vertex_ptc vertices11[] =
9088     {
9089         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
9090         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
9091         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
9092 
9093         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9094         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
9095         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
9096 
9097         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
9098         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
9099         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
9100     };
9101     const UINT num_vertices11 = ARRAY_SIZE(vertices11);
9102     const UINT num_faces11 = ARRAY_SIZE(vertices11) / VERTS_PER_FACE;
9103     const UINT vertex_size11 = sizeof(*vertices11);
9104     const struct vertex_ptc_short2 exp_vertices11[] =
9105     {
9106         {{ 0.0f,  3.0f,  0.f}, {1, 0}},
9107         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9108         {{ 0.0f,  0.0f,  0.f}, {0, -4}},
9109 
9110         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1}},
9111         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN}},
9112         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
9113 
9114         {{ 4.0f,  3.0f,  0.f}, {-2, 1}},
9115         {{ 6.0f,  0.0f,  0.f}, {32765, -32767}},
9116         {{ 4.0f,  0.0f,  0.f}, {-4, 1}},
9117     };
9118     const UINT exp_vertex_size11 = sizeof(*exp_vertices11);
9119     /* Test 12. Convert FLOAT2 to SHORT4. */
9120     const struct vertex_ptc vertices12[] =
9121     {
9122         {{ 0.0f,  3.0f,  0.f}, { 1.0f, -1.0f}},
9123         {{ 2.0f,  3.0f,  0.f}, { 0.4f,  0.5f}},
9124         {{ 0.0f,  0.0f,  0.f}, {-0.5f, -5.0f}},
9125 
9126         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9127         {{ 3.0f,  0.0f,  0.f}, {SHRT_MAX + 1.0f, SHRT_MIN - 1.0f}},
9128         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX + 2.0f, SHRT_MIN - 2.0f}},
9129 
9130         {{ 4.0f,  3.0f,  0.f}, {2 * SHRT_MAX, 2 * SHRT_MIN}},
9131         {{ 6.0f,  0.0f,  0.f}, {3 * SHRT_MAX, 3 * SHRT_MIN}},
9132         {{ 4.0f,  0.0f,  0.f}, {4 * SHRT_MAX, 4 * SHRT_MIN}},
9133     };
9134     const UINT num_vertices12 = ARRAY_SIZE(vertices12);
9135     const UINT num_faces12 = ARRAY_SIZE(vertices12) / VERTS_PER_FACE;
9136     const UINT vertex_size12 = sizeof(*vertices12);
9137     const struct vertex_ptc_short4 exp_vertices12[] =
9138     {
9139         {{ 0.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
9140         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9141         {{ 0.0f,  0.0f,  0.f}, {0, -4, 0, 1}},
9142 
9143         {{ 3.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 1, 0, 1}},
9144         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MIN, 0, 1}},
9145         {{ 1.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, 0, 1}},
9146 
9147         {{ 4.0f,  3.0f,  0.f}, {-2, 1, 0, 1}},
9148         {{ 6.0f,  0.0f,  0.f}, {32765, -32767, 0, 1}},
9149         {{ 4.0f,  0.0f,  0.f}, {-4, 1, 0, 1}},
9150     };
9151     const UINT exp_vertex_size12 = sizeof(*exp_vertices12);
9152     /* Test 13. Convert FLOAT2 to UBYTE4N. */
9153     const struct vertex_ptc vertices13[] =
9154     {
9155         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  2.0f}},
9156         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9157         {{ 0.0f,  0.0f,  0.f}, {-0.4f, -0.5f}},
9158 
9159         {{ 3.0f,  3.0f,  0.f}, {-0.6f,  -1.0f}},
9160         {{ 3.0f,  0.0f,  0.f}, {UCHAR_MAX,  UCHAR_MAX + 1}},
9161         {{ 1.0f,  0.0f,  0.f}, {2 * UCHAR_MAX, -UCHAR_MAX}},
9162     };
9163     const UINT num_vertices13 = ARRAY_SIZE(vertices13);
9164     const UINT num_faces13 = ARRAY_SIZE(vertices13) / VERTS_PER_FACE;
9165     const UINT vertex_size13 = sizeof(*vertices13);
9166     const struct vertex_ptc_ubyte4n exp_vertices13[] =
9167     {
9168         {{ 0.0f,  3.0f,  0.f}, {255, 255, 0, 255}},
9169         {{ 2.0f,  3.0f,  0.f}, {128, 179, 0, 255}},
9170         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9171 
9172         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, 255}},
9173         {{ 3.0f,  0.0f,  0.f}, {255, 255, 0, 255}},
9174         {{ 1.0f,  0.0f,  0.f}, {255, 0, 0, 255}},
9175     };
9176     const UINT exp_vertex_size13 = sizeof(*exp_vertices13);
9177     /* Test 14. Convert FLOAT2 to SHORT2N. */
9178     const struct vertex_ptc vertices14[] =
9179     {
9180         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9181         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9182         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9183 
9184         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9185         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
9186         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9187     };
9188     const UINT num_vertices14 = ARRAY_SIZE(vertices14);
9189     const UINT num_faces14 = ARRAY_SIZE(vertices14) / VERTS_PER_FACE;
9190     const UINT vertex_size14 = sizeof(*vertices14);
9191     const struct vertex_ptc_short2 exp_vertices14[] =
9192     {
9193         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX}},
9194         {{ 2.0f,  3.0f,  0.f}, {13107, 16384}},
9195         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2}},
9196 
9197         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383}},
9198         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3}},
9199         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2}},
9200     };
9201     const UINT exp_vertex_size14 = sizeof(*exp_vertices14);
9202     /* Test 15. Convert FLOAT2 to SHORT4N. */
9203     const struct vertex_ptc vertices15[] =
9204     {
9205         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9206         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9207         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9208 
9209         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9210         {{ 3.0f,  0.0f,  0.f}, {-0.9f, -0.99997}},
9211         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN}},
9212     };
9213     const UINT num_vertices15 = ARRAY_SIZE(vertices15);
9214     const UINT num_faces15 = ARRAY_SIZE(vertices15) / VERTS_PER_FACE;
9215     const UINT vertex_size15 = sizeof(*vertices15);
9216     const struct vertex_ptc_short4 exp_vertices15[] =
9217     {
9218         {{ 0.0f,  3.0f,  0.f}, {SHRT_MAX, SHRT_MAX, 0, SHRT_MAX}},
9219         {{ 2.0f,  3.0f,  0.f}, {13107, 16384, 0, SHRT_MAX}},
9220         {{ 0.0f,  0.0f,  0.f}, {19660, SHRT_MIN + 2, 0, SHRT_MAX}},
9221 
9222         {{ 3.0f,  3.0f,  0.f}, {-13106, -16383, 0, SHRT_MAX}},
9223         {{ 3.0f,  0.0f,  0.f}, {-29489, SHRT_MIN + 3, 0, SHRT_MAX}},
9224         {{ 1.0f,  0.0f,  0.f}, {SHRT_MAX, SHRT_MIN + 2, 0, SHRT_MAX}},
9225     };
9226     const UINT exp_vertex_size15 = sizeof(*exp_vertices15);
9227     /* Test 16. Convert FLOAT2 to USHORT2N. */
9228     const struct vertex_ptc vertices16[] =
9229     {
9230         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9231         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9232         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9233 
9234         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9235         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
9236         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
9237     };
9238     const UINT num_vertices16 = ARRAY_SIZE(vertices16);
9239     const UINT num_faces16 = ARRAY_SIZE(vertices16) / VERTS_PER_FACE;
9240     const UINT vertex_size16 = sizeof(*vertices16);
9241     const struct vertex_ptc_ushort2n exp_vertices16[] =
9242     {
9243         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX}},
9244         {{ 2.0f,  3.0f,  0.f}, {26214, 32768}},
9245         {{ 0.0f,  0.0f,  0.f}, {39321, 0}},
9246 
9247         {{ 3.0f,  3.0f,  0.f}, {0, 0}},
9248         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1}},
9249         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0}},
9250     };
9251     const UINT exp_vertex_size16 = sizeof(*exp_vertices16);
9252     /* Test 17. Convert FLOAT2 to USHORT4N. */
9253     const struct vertex_ptc vertices17[] =
9254     {
9255         {{ 0.0f,  3.0f,  0.f}, {1.0f,  2.0f}},
9256         {{ 2.0f,  3.0f,  0.f}, {0.4f,  0.5f}},
9257         {{ 0.0f,  0.0f,  0.f}, {0.6f, -1.0f}},
9258 
9259         {{ 3.0f,  3.0f,  0.f}, {-0.4f, -0.5f}},
9260         {{ 3.0f,  0.0f,  0.f}, {-0.9f,  0.99998f}},
9261         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0.0f}},
9262     };
9263     const UINT num_vertices17 = ARRAY_SIZE(vertices17);
9264     const UINT num_faces17 = ARRAY_SIZE(vertices17) / VERTS_PER_FACE;
9265     const UINT vertex_size17 = sizeof(*vertices17);
9266     const struct vertex_ptc_ushort4n exp_vertices17[] =
9267     {
9268         {{ 0.0f,  3.0f,  0.f}, {USHRT_MAX, USHRT_MAX, 0, USHRT_MAX}},
9269         {{ 2.0f,  3.0f,  0.f}, {26214, 32768, 0, USHRT_MAX}},
9270         {{ 0.0f,  0.0f,  0.f}, {39321, 0, 0, USHRT_MAX}},
9271 
9272         {{ 3.0f,  3.0f,  0.f}, {0, 0, 0, USHRT_MAX}},
9273         {{ 3.0f,  0.0f,  0.f}, {0, USHRT_MAX - 1, 0, USHRT_MAX}},
9274         {{ 1.0f,  0.0f,  0.f}, {USHRT_MAX, 0, 0, USHRT_MAX}},
9275     };
9276     const UINT exp_vertex_size17 = sizeof(*exp_vertices17);
9277     /* Test 18. Test that the method field is compared by converting a FLOAT2 to
9278      * FLOAT16_2. where the method field has been change from
9279      * D3DDECLMETHOD_DEFAULT to D3DDECLMETHOD_PARTIALU. */
9280     const struct vertex_ptc vertices18[] =
9281     {
9282         {{ 0.0f,  3.0f,  0.f}, { 1.0f,  1.0f}},
9283         {{ 2.0f,  3.0f,  0.f}, { 0.5f,  0.7f}},
9284         {{ 0.0f,  0.0f,  0.f}, {-0.2f, -0.3f}},
9285 
9286         {{ 3.0f,  3.0f,  0.f}, { 0.2f,  0.3f}},
9287         {{ 3.0f,  0.0f,  0.f}, { 1.0f,  1.0f}},
9288         {{ 1.0f,  0.0f,  0.f}, { 0.1f,  0.2f}},
9289     };
9290     const UINT num_vertices18 = ARRAY_SIZE(vertices18);
9291     const UINT num_faces18 = ARRAY_SIZE(vertices18) / VERTS_PER_FACE;
9292     const UINT vertex_size18 = sizeof(*vertices18);
9293     const struct vertex_ptc_float16_2 exp_vertices18[] =
9294     {
9295         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9296         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9297         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9298 
9299         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9300         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9301         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9302     };
9303     const UINT exp_vertex_size18 = sizeof(*exp_vertices18);
9304     /* Test 19. Test that data is lost if usage index changes, e.g. TEXCOORD0
9305      * TEXCOORD1. */
9306     const struct vertex_pntc vertices19[] =
9307     {
9308         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
9309         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
9310         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
9311 
9312         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
9313         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
9314         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
9315     };
9316     const UINT num_vertices19 = ARRAY_SIZE(vertices19);
9317     const UINT num_faces19 = ARRAY_SIZE(vertices19) / VERTS_PER_FACE;
9318     const UINT vertex_size19 = sizeof(*vertices19);
9319     const struct vertex_pntc exp_vertices19[] =
9320     {
9321         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
9322         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
9323         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
9324 
9325         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
9326         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
9327         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
9328     };
9329     const UINT exp_vertex_size19 = sizeof(*exp_vertices19);
9330     /* Test 20. Another test that data is lost if usage index changes, e.g.
9331      * TEXCOORD1 to TEXCOORD0. */
9332     const struct vertex_pntc vertices20[] =
9333     {
9334         {{ 0.0f,  3.0f,  0.f}, up, { 1.0f,  1.0f}},
9335         {{ 2.0f,  3.0f,  0.f}, up, { 0.5f,  0.7f}},
9336         {{ 0.0f,  0.0f,  0.f}, up, {-0.2f, -0.3f}},
9337 
9338         {{ 3.0f,  3.0f,  0.f}, up, { 0.2f,  0.3f}},
9339         {{ 3.0f,  0.0f,  0.f}, up, { 1.0f,  1.0f}},
9340         {{ 1.0f,  0.0f,  0.f}, up, { 0.1f,  0.2f}},
9341     };
9342     const UINT num_vertices20 = ARRAY_SIZE(vertices20);
9343     const UINT num_faces20 = ARRAY_SIZE(vertices20) / VERTS_PER_FACE;
9344     const UINT vertex_size20 = sizeof(*vertices20);
9345     const struct vertex_pntc exp_vertices20[] =
9346     {
9347         {{ 0.0f,  3.0f,  0.f}, up, zero_vec2},
9348         {{ 2.0f,  3.0f,  0.f}, up, zero_vec2},
9349         {{ 0.0f,  0.0f,  0.f}, up, zero_vec2},
9350 
9351         {{ 3.0f,  3.0f,  0.f}, up, zero_vec2},
9352         {{ 3.0f,  0.0f,  0.f}, up, zero_vec2},
9353         {{ 1.0f,  0.0f,  0.f}, up, zero_vec2},
9354     };
9355     const UINT exp_vertex_size20 = sizeof(*exp_vertices20);
9356     /* Test 21. Convert FLOAT1 to FLOAT2. */
9357     const struct vertex_ptc_float1 vertices21[] =
9358     {
9359         {{ 0.0f,  3.0f,  0.f},  1.0f},
9360         {{ 2.0f,  3.0f,  0.f},  0.5f},
9361         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9362 
9363         {{ 3.0f,  3.0f,  0.f},  0.2f},
9364         {{ 3.0f,  0.0f,  0.f},  1.0f},
9365         {{ 1.0f,  0.0f,  0.f},  0.1f},
9366     };
9367     const UINT num_vertices21 = ARRAY_SIZE(vertices21);
9368     const UINT num_faces21 = ARRAY_SIZE(vertices21) / VERTS_PER_FACE;
9369     const UINT vertex_size21 = sizeof(*vertices21);
9370     const struct vertex_ptc exp_vertices21[] =
9371     {
9372         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f}},
9373         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f}},
9374         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f}},
9375 
9376         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f}},
9377         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f}},
9378         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f}},
9379     };
9380     const UINT exp_vertex_size21 = sizeof(*exp_vertices21);
9381     /* Test 22. Convert FLOAT1 to FLOAT3. */
9382     const struct vertex_ptc_float1 vertices22[] =
9383     {
9384         {{ 0.0f,  3.0f,  0.f},  1.0f},
9385         {{ 2.0f,  3.0f,  0.f},  0.5f},
9386         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9387 
9388         {{ 3.0f,  3.0f,  0.f},  0.2f},
9389         {{ 3.0f,  0.0f,  0.f},  1.0f},
9390         {{ 1.0f,  0.0f,  0.f},  0.1f},
9391     };
9392     const UINT num_vertices22 = ARRAY_SIZE(vertices22);
9393     const UINT num_faces22 = ARRAY_SIZE(vertices22) / VERTS_PER_FACE;
9394     const UINT vertex_size22 = sizeof(*vertices22);
9395     const struct vertex_ptc_float3 exp_vertices22[] =
9396     {
9397         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
9398         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f}},
9399         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f}},
9400 
9401         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f}},
9402         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f}},
9403         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f}},
9404     };
9405     const UINT exp_vertex_size22 = sizeof(*exp_vertices22);
9406     /* Test 23. Convert FLOAT1 to FLOAT4. */
9407     const struct vertex_ptc_float1 vertices23[] =
9408     {
9409         {{ 0.0f,  3.0f,  0.f},  1.0f},
9410         {{ 2.0f,  3.0f,  0.f},  0.5f},
9411         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9412 
9413         {{ 3.0f,  3.0f,  0.f},  0.2f},
9414         {{ 3.0f,  0.0f,  0.f},  1.0f},
9415         {{ 1.0f,  0.0f,  0.f},  0.1f},
9416     };
9417     const UINT num_vertices23 = ARRAY_SIZE(vertices23);
9418     const UINT num_faces23 = ARRAY_SIZE(vertices23) / VERTS_PER_FACE;
9419     const UINT vertex_size23 = sizeof(*vertices23);
9420     const struct vertex_ptc_float4 exp_vertices23[] =
9421     {
9422         {{ 0.0f,  3.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
9423         {{ 2.0f,  3.0f,  0.f}, { 0.5f, 0.0f, 0.0f, 1.0f}},
9424         {{ 0.0f,  0.0f,  0.f}, {-0.2f, 0.0f, 0.0f, 1.0f}},
9425 
9426         {{ 3.0f,  3.0f,  0.f}, { 0.2f, 0.0f, 0.0f, 1.0f}},
9427         {{ 3.0f,  0.0f,  0.f}, { 1.0f, 0.0f, 0.0f, 1.0f}},
9428         {{ 1.0f,  0.0f,  0.f}, { 0.1f, 0.0f, 0.0f, 1.0f}},
9429     };
9430     const UINT exp_vertex_size23 = sizeof(*exp_vertices23);
9431     /* Test 24. Convert FLOAT1 to D3DCOLOR. */
9432     const struct vertex_ptc_float1 vertices24[] =
9433     {
9434         {{ 0.0f,  3.0f,  0.f},  1.0f},
9435         {{ 2.0f,  3.0f,  0.f},  0.5f},
9436         {{ 0.0f,  0.0f,  0.f}, -0.2f},
9437 
9438         {{ 3.0f,  3.0f,  0.f},  0.2f},
9439         {{ 3.0f,  0.0f,  0.f},  1.0f},
9440         {{ 1.0f,  0.0f,  0.f},  0.11f},
9441     };
9442     const UINT num_vertices24 = ARRAY_SIZE(vertices24);
9443     const UINT num_faces24 = ARRAY_SIZE(vertices24) / VERTS_PER_FACE;
9444     const UINT vertex_size24 = sizeof(*vertices24);
9445     const struct vertex_ptc_d3dcolor exp_vertices24[] =
9446     {
9447         {{ 0.0f,  3.0f,  0.f}, {0, 0, 255, 255}},
9448         {{ 2.0f,  3.0f,  0.f}, {0, 0, 128, 255}},
9449         {{ 0.0f,  0.0f,  0.f}, {0, 0, 0, 255}},
9450 
9451         {{ 3.0f,  3.0f,  0.f}, {0, 0, 51, 255}},
9452         {{ 3.0f,  0.0f,  0.f}, {0, 0, 255, 255}},
9453         {{ 1.0f,  0.0f,  0.f}, {0, 0, 28, 255}},
9454     };
9455     const UINT exp_vertex_size24 = sizeof(*exp_vertices24);
9456     /* Test 25. Convert FLOAT1 to ubyte4. */
9457     const struct vertex_ptc_float1 vertices25[] =
9458     {
9459         {{ 0.0f,  3.0f,  0.f}, 0.0f},
9460         {{ 2.0f,  3.0f,  0.f}, 1.4f},
9461         {{ 0.0f,  0.0f,  0.f}, 1.5f},
9462 
9463         {{ 3.0f,  3.0f,  0.f}, 255.0f},
9464         {{ 3.0f,  0.0f,  0.f}, 256.0f},
9465         {{ 1.0f,  0.0f,  0.f}, -1.0f},
9466     };
9467     const UINT num_vertices25 = ARRAY_SIZE(vertices25);
9468     const UINT num_faces25 = ARRAY_SIZE(vertices25) / VERTS_PER_FACE;
9469     const UINT vertex_size25 = sizeof(*vertices25);
9470     const struct vertex_ptc_ubyte4 exp_vertices25[] =
9471     {
9472         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 1}},
9473         {{ 2.0f,  3.0f,  0.f}, {1, 0, 0, 1}},
9474         {{ 0.0f,  0.0f,  0.f}, {2, 0, 0, 1}},
9475 
9476         {{ 3.0f,  3.0f,  0.f}, {255, 0, 0, 1}},
9477         {{ 3.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9478         {{ 1.0f,  0.0f,  0.f}, {0, 0, 0, 1}},
9479     };
9480     const UINT exp_vertex_size25 = sizeof(*exp_vertices25);
9481     /* Test 26. Convert FLOAT4 to D3DCOLOR. */
9482     const struct vertex_ptc_float4 vertices26[] =
9483     {
9484         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.5f}},
9485         {{ 2.0f,  3.0f,  0.f}, {-0.4f, -0.5f, -1.0f, -2.0f}},
9486         {{ 0.0f,  0.0f,  0.f}, {254.0f, 255.0f, 256.0f, 257.0f}},
9487 
9488         {{ 3.0f,  3.0f,  0.f}, {0.1f, 0.2f, 0.3f, 0.4f}},
9489         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.6f, 0.7f, 0.8f}},
9490         {{ 1.0f,  0.0f,  0.f}, {0.9f, 0.99f, 0.995f, 0.999f}},
9491     };
9492     const UINT num_vertices26 = ARRAY_SIZE(vertices26);
9493     const UINT num_faces26 = ARRAY_SIZE(vertices26) / VERTS_PER_FACE;
9494     const UINT vertex_size26 = sizeof(*vertices26);
9495     const struct vertex_ptc_d3dcolor exp_vertices26[] =
9496     {
9497         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9498         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9499         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9500 
9501         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9502         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9503         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9504     };
9505     const UINT exp_vertex_size26 = sizeof(*exp_vertices26);
9506     /* Test 27. Convert D3DCOLOR to FLOAT4. */
9507     const struct vertex_ptc_d3dcolor vertices27[] =
9508     {
9509         {{ 0.0f,  3.0f,  0.f}, {102, 255, 0, 128}},
9510         {{ 2.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9511         {{ 0.0f,  0.0f,  0.f}, {255, 255, 255, 255}},
9512 
9513         {{ 3.0f,  3.0f,  0.f}, {77, 51, 26, 102}},
9514         {{ 3.0f,  0.0f,  0.f}, {179, 153, 128, 204}},
9515         {{ 1.0f,  0.0f,  0.f}, {254, 252, 230, 255}},
9516     };
9517     const UINT num_vertices27 = ARRAY_SIZE(vertices27);
9518     const UINT num_faces27 = ARRAY_SIZE(vertices27) / VERTS_PER_FACE;
9519     const UINT vertex_size27 = sizeof(*vertices27);
9520     const struct vertex_ptc_float4 exp_vertices27[] =
9521     {
9522         {{ 0.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.4f, 0.501961f}},
9523         {{ 2.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9524         {{ 0.0f,  0.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9525 
9526         {{ 3.0f,  3.0f,  0.f}, {0.101961f, 0.2f, 0.301961f, 0.4f}},
9527         {{ 3.0f,  0.0f,  0.f}, {0.501961f, 0.6f, 0.701961f, 0.8f}},
9528         {{ 1.0f,  0.0f,  0.f}, {0.901961f, 0.988235f, 0.996078f, 1.0f}},
9529     };
9530     const UINT exp_vertex_size27 = sizeof(*exp_vertices27);
9531     /* Test 28. Convert UBYTE4 to FLOAT4. */
9532     const struct vertex_ptc_ubyte4 vertices28[] =
9533     {
9534         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9535         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9536         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9537 
9538         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9539         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9540         {{ 1.0f,  0.0f,  0.f}, {50, 60, 127, 255}},
9541     };
9542     const UINT num_vertices28 = ARRAY_SIZE(vertices28);
9543     const UINT num_faces28 = ARRAY_SIZE(vertices28) / VERTS_PER_FACE;
9544     const UINT vertex_size28 = sizeof(*vertices28);
9545     const struct vertex_ptc_float4 exp_vertices28[] =
9546     {
9547         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9548         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9549         {{ 0.0f,  0.0f,  0.f}, {1.0f,  0.0f, 1.0f, 0.0f}},
9550 
9551         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9552         {{ 3.0f,  0.0f,  0.f}, {10.0f, 20.0f, 30.0f, 40.0f}},
9553         {{ 1.0f,  0.0f,  0.f}, {50.0f, 60.0f, 127.0f, 255.0f}},
9554     };
9555     const UINT exp_vertex_size28 = sizeof(*exp_vertices28);
9556     /* Test 29. Convert SHORT2 to FLOAT4. */
9557     const struct vertex_ptc_short2 vertices29[] =
9558     {
9559         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9560         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9561         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9562 
9563         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9564         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX}},
9565         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9566     };
9567     const UINT num_vertices29 = ARRAY_SIZE(vertices29);
9568     const UINT num_faces29 = ARRAY_SIZE(vertices29) / VERTS_PER_FACE;
9569     const UINT vertex_size29 = sizeof(*vertices29);
9570     const struct vertex_ptc_float4 exp_vertices29[] =
9571     {
9572         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9573         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9574         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 0.0f, 1.0f}},
9575 
9576         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9577         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 0.0f, 1.0f}},
9578         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, 0.0f, 1.0f}},
9579     };
9580     const UINT exp_vertex_size29 = sizeof(*exp_vertices29);
9581     /* Test 29. Convert SHORT4 to FLOAT4. */
9582     const struct vertex_ptc_short4 vertices30[] =
9583     {
9584         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9585         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9586         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9587 
9588         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9589         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1, 0}},
9590         {{ 1.0f,  0.0f,  0.f}, {-42, 42, SHRT_MAX, SHRT_MIN}},
9591     };
9592     const UINT num_vertices30 = ARRAY_SIZE(vertices30);
9593     const UINT num_faces30 = ARRAY_SIZE(vertices30) / VERTS_PER_FACE;
9594     const UINT vertex_size30 = sizeof(*vertices30);
9595     const struct vertex_ptc_float4 exp_vertices30[] =
9596     {
9597         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9598         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f }},
9599         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9600 
9601         {{ 3.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9602         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN, SHRT_MAX, 1.0f, 0.0f}},
9603         {{ 1.0f,  0.0f,  0.f}, {-42.0f, 42.0f, SHRT_MAX, SHRT_MIN}},
9604     };
9605     const UINT exp_vertex_size30 = sizeof(*exp_vertices30);
9606     /* Test 31. Convert UBYTE4N to FLOAT4. */
9607     const struct vertex_ptc_ubyte4n vertices31[] =
9608     {
9609         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9610         {{ 2.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9611         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9612 
9613         {{ 3.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9614         {{ 3.0f,  0.0f,  0.f}, {10, 20, 30, 40}},
9615         {{ 1.0f,  0.0f,  0.f}, {50, 60, 70, UCHAR_MAX}},
9616     };
9617     const UINT num_vertices31 = ARRAY_SIZE(vertices31);
9618     const UINT num_faces31 = ARRAY_SIZE(vertices31) / VERTS_PER_FACE;
9619     const UINT vertex_size31 = sizeof(*vertices31);
9620     const struct vertex_ptc_float4 exp_vertices31[] =
9621     {
9622         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9623         {{ 2.0f,  3.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX, (FLOAT)1/UCHAR_MAX}},
9624         {{ 0.0f,  0.0f,  0.f}, {(FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX, 0.0f}},
9625 
9626         {{ 3.0f,  3.0f,  0.f}, {0.0f, (FLOAT)1/UCHAR_MAX, 0.0f, (FLOAT)1/UCHAR_MAX}},
9627         {{ 3.0f,  0.0f,  0.f}, {(FLOAT)10/UCHAR_MAX, (FLOAT)20/UCHAR_MAX, (FLOAT)30/UCHAR_MAX, (FLOAT)40/UCHAR_MAX}},
9628         {{ 1.0f,  0.0f,  0.f}, {(FLOAT)50/UCHAR_MAX, (FLOAT)60/UCHAR_MAX, (FLOAT)70/UCHAR_MAX, 1.0f}},
9629     };
9630     const UINT exp_vertex_size31 = sizeof(*exp_vertices31);
9631     /* Test 32. Convert SHORT2N to FLOAT4. */
9632     const struct vertex_ptc_short2 vertices32[] =
9633     {
9634         {{ 0.0f,  3.0f,  0.f}, {0, 0}},
9635         {{ 2.0f,  3.0f,  0.f}, {0, 1}},
9636         {{ 0.0f,  0.0f,  0.f}, {1, 0}},
9637 
9638         {{ 3.0f,  3.0f,  0.f}, {1, 1}},
9639         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX}},
9640         {{ 1.0f,  0.0f,  0.f}, {-42, 42}},
9641     };
9642     const UINT num_vertices32 = ARRAY_SIZE(vertices32);
9643     const UINT num_faces32 = ARRAY_SIZE(vertices32) / VERTS_PER_FACE;
9644     const UINT vertex_size32 = sizeof(*vertices32);
9645     const struct vertex_ptc_float4 exp_vertices32[] =
9646     {
9647         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 1.0f}},
9648         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9649         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 0.0f, 1.0f}},
9650 
9651         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 0.0f, 1.0f}},
9652         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, 0.0f, 1.0f}},
9653         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 0.0f, 1.0f}},
9654     };
9655     const UINT exp_vertex_size32 = sizeof(*exp_vertices32);
9656     /* Test 33. Convert SHORT4N to FLOAT4. */
9657     const struct vertex_ptc_short4 vertices33[] =
9658     {
9659         {{ 0.0f,  3.0f,  0.f}, {0, 0, 0, 0}},
9660         {{ 2.0f,  3.0f,  0.f}, {0, 1, 0, 1}},
9661         {{ 0.0f,  0.0f,  0.f}, {1, 0, 1, 0}},
9662 
9663         {{ 3.0f,  3.0f,  0.f}, {1, 1, 1, 1}},
9664         {{ 3.0f,  0.0f,  0.f}, {SHRT_MIN + 1, SHRT_MAX, SHRT_MIN + 1, SHRT_MAX}},
9665         {{ 1.0f,  0.0f,  0.f}, {-42, 42, 1, 1}},
9666     };
9667     const UINT num_vertices33 = ARRAY_SIZE(vertices33);
9668     const UINT num_faces33 = ARRAY_SIZE(vertices33) / VERTS_PER_FACE;
9669     const UINT vertex_size33 = sizeof(*vertices33);
9670     const struct vertex_ptc_float4 exp_vertices33[] =
9671     {
9672         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9673         {{ 2.0f,  3.0f,  0.f}, {0.0f, 1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX}},
9674         {{ 0.0f,  0.0f,  0.f}, {1.0f/SHRT_MAX, 0.0f, 1.0f/SHRT_MAX, 0.0f}},
9675 
9676         {{ 3.0f,  3.0f,  0.f}, {1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9677         {{ 3.0f,  0.0f,  0.f}, {-1.0f, 1.0f, -1.0f, 1.0f}},
9678         {{ 1.0f,  0.0f,  0.f}, {-42.0f/SHRT_MAX, 42.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f/SHRT_MAX}},
9679     };
9680     const UINT exp_vertex_size33 = sizeof(*exp_vertices33);
9681     /* Test 34. Convert FLOAT16_2 to FLOAT4. */
9682     const struct vertex_ptc_float16_2 vertices34[] =
9683     {
9684         {{ 0.0f,  3.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9685         {{ 2.0f,  3.0f,  0.f}, {0x3800, 0x399a}}, /* {0.5f, 0.7f} */
9686         {{ 0.0f,  0.0f,  0.f}, {0xb266, 0xb4cd}}, /* {-0.2f, -0.3f} */
9687 
9688         {{ 3.0f,  3.0f,  0.f}, {0x3266, 0x34cd}}, /* {0.2f, 0.3f} */
9689         {{ 3.0f,  0.0f,  0.f}, {0x3c00, 0x3c00}}, /* {1.0f, 1.0f} */
9690         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266}}, /* {0.1f, 0.2f} */
9691     };
9692     const UINT num_vertices34 = ARRAY_SIZE(vertices34);
9693     const UINT num_faces34 = ARRAY_SIZE(vertices34) / VERTS_PER_FACE;
9694     const UINT vertex_size34 = sizeof(*vertices34);
9695     const struct vertex_ptc_float4 exp_vertices34[] =
9696     {
9697         {{ 0.0f,  3.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9698         {{ 2.0f,  3.0f,  0.f}, {0.5f, 0.700195f, 0.0f, 1.0f}},
9699         {{ 0.0f,  0.0f,  0.f}, {-0.199951f, -0.300049f, 0.0f, 1.0f}},
9700 
9701         {{ 3.0f,  3.0f,  0.f}, {0.199951f, 0.300049f, 0.0f, 1.0f}},
9702         {{ 3.0f,  0.0f,  0.f}, {1.0f, 1.0f, 0.0f, 1.0f}},
9703         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.0f, 1.0f}},
9704     };
9705     const UINT exp_vertex_size34 = sizeof(*exp_vertices34);
9706     /* Test 35. Convert FLOAT16_4 to FLOAT4. */
9707     const struct vertex_ptc_float16_4 vertices35[] =
9708     {
9709         {{ 0.0f,  3.0f,  0.f}, {0x0000, 0x0000, 0x0000, 0x0000}},
9710         {{ 2.0f,  3.0f,  0.f}, {0x3c00, 0x3c00, 0x3c00, 0x3c00}},
9711         {{ 0.0f,  0.0f,  0.f}, {0x3c00, 0x0000, 0x3c00, 0x0000}},
9712 
9713         {{ 3.0f,  3.0f,  0.f}, {0x0000, 0x3c00, 0x0000, 0x3c00}},
9714         {{ 3.0f,  0.0f,  0.f}, {0x3800, 0x399a, 0xb266, 0xb4cd}},
9715         {{ 1.0f,  0.0f,  0.f}, {0x2e66, 0x3266, 0x2e66, 0x3266}},
9716     };
9717     const UINT num_vertices35 = ARRAY_SIZE(vertices35);
9718     const UINT num_faces35 = ARRAY_SIZE(vertices35) / VERTS_PER_FACE;
9719     const UINT vertex_size35 = sizeof(*vertices35);
9720     const struct vertex_ptc_float4 exp_vertices35[] =
9721     {
9722         {{ 0.0f,  3.0f,  0.f}, {0.0f, 0.0f, 0.0f, 0.0f}},
9723         {{ 2.0f,  3.0f,  0.f}, {1.0f, 1.0f, 1.0f, 1.0f}},
9724         {{ 0.0f,  0.0f,  0.f}, {1.0f, 0.0f, 1.0f, 0.0f}},
9725 
9726         {{ 3.0f,  3.0f,  0.f}, {0.0f, 1.0f, 0.0f, 1.0f}},
9727         {{ 3.0f,  0.0f,  0.f}, {0.5f, 0.700195f, -0.199951f, -0.300049f}},
9728         {{ 1.0f,  0.0f,  0.f}, {0.099976f, 0.199951f, 0.099976f, 0.199951f}},
9729     };
9730     const UINT exp_vertex_size35 = sizeof(*exp_vertices35);
9731     /* Test 36. Check that vertex buffer sharing is ok. */
9732     const struct vertex_pn vertices36[] =
9733     {
9734         {{ 0.0f,  3.0f,  0.f}, up},
9735         {{ 2.0f,  3.0f,  0.f}, up},
9736         {{ 0.0f,  0.0f,  0.f}, up},
9737     };
9738     const UINT num_vertices36 = ARRAY_SIZE(vertices36);
9739     const UINT num_faces36 = ARRAY_SIZE(vertices36) / VERTS_PER_FACE;
9740     const UINT vertex_size36 = sizeof(*vertices36);
9741     const DWORD clone_options36 = options | D3DXMESH_VB_SHARE;
9742     /* Common mesh data */
9743     ID3DXMesh *mesh = NULL;
9744     ID3DXMesh *mesh_clone = NULL;
9745     struct
9746     {
9747         const BYTE *vertices;
9748         const DWORD *indices;
9749         const DWORD *attributes;
9750         const UINT num_vertices;
9751         const UINT num_faces;
9752         const UINT vertex_size;
9753         const DWORD create_options;
9754         const DWORD clone_options;
9755         D3DVERTEXELEMENT9 *declaration;
9756         D3DVERTEXELEMENT9 *new_declaration;
9757         const BYTE *exp_vertices;
9758         const UINT exp_vertex_size;
9759     }
9760     tc[] =
9761     {
9762         {
9763             (BYTE*)vertices0,
9764             NULL,
9765             NULL,
9766             num_vertices0,
9767             num_faces0,
9768             vertex_size0,
9769             options,
9770             options,
9771             declaration_pn,
9772             declaration_pn,
9773             (BYTE*)vertices0,
9774             vertex_size0
9775         },
9776         {
9777             (BYTE*)vertices0,
9778             NULL,
9779             NULL,
9780             num_vertices0,
9781             num_faces0,
9782             vertex_size0,
9783             options_16bit,
9784             options_16bit,
9785             declaration_pn,
9786             declaration_pn,
9787             (BYTE*)vertices0,
9788             vertex_size0
9789         },
9790         {
9791             (BYTE*)vertices0,
9792             NULL,
9793             NULL,
9794             num_vertices0,
9795             num_faces0,
9796             vertex_size0,
9797             options,
9798             options,
9799             declaration_pn,
9800             declaration_pntc,
9801             (BYTE*)exp_vertices2,
9802             exp_vertex_size2
9803         },
9804         {
9805             (BYTE*)vertices0,
9806             NULL,
9807             NULL,
9808             num_vertices0,
9809             num_faces0,
9810             vertex_size0,
9811             options,
9812             options,
9813             declaration_pn,
9814             declaration_ptcn,
9815             (BYTE*)exp_vertices3,
9816             exp_vertex_size3
9817         },
9818         {
9819             (BYTE*)vertices4,
9820             NULL,
9821             NULL,
9822             num_vertices4,
9823             num_faces4,
9824             vertex_size4,
9825             options,
9826             options,
9827             declaration_ptc,
9828             declaration_ptc_float16_2,
9829             (BYTE*)exp_vertices4,
9830             exp_vertex_size4
9831         },
9832         {
9833             (BYTE*)vertices5,
9834             NULL,
9835             NULL,
9836             num_vertices5,
9837             num_faces5,
9838             vertex_size5,
9839             options,
9840             options,
9841             declaration_ptc,
9842             declaration_ptc_float16_4,
9843             (BYTE*)exp_vertices5,
9844             exp_vertex_size5
9845         },
9846         {
9847             (BYTE*)vertices6,
9848             NULL,
9849             NULL,
9850             num_vertices6,
9851             num_faces6,
9852             vertex_size6,
9853             options,
9854             options,
9855             declaration_ptc,
9856             declaration_ptc_float1,
9857             (BYTE*)exp_vertices6,
9858             exp_vertex_size6
9859         },
9860         {
9861             (BYTE*)vertices7,
9862             NULL,
9863             NULL,
9864             num_vertices7,
9865             num_faces7,
9866             vertex_size7,
9867             options,
9868             options,
9869             declaration_ptc,
9870             declaration_ptc_float3,
9871             (BYTE*)exp_vertices7,
9872             exp_vertex_size7
9873         },
9874         {
9875             (BYTE*)vertices8,
9876             NULL,
9877             NULL,
9878             num_vertices8,
9879             num_faces8,
9880             vertex_size8,
9881             options,
9882             options,
9883             declaration_ptc,
9884             declaration_ptc_float4,
9885             (BYTE*)exp_vertices8,
9886             exp_vertex_size8
9887         },
9888         {
9889             (BYTE*)vertices9,
9890             NULL,
9891             NULL,
9892             num_vertices9,
9893             num_faces9,
9894             vertex_size9,
9895             options,
9896             options,
9897             declaration_ptc,
9898             declaration_ptc_d3dcolor,
9899             (BYTE*)exp_vertices9,
9900             exp_vertex_size9
9901         },
9902         {
9903             (BYTE*)vertices10,
9904             NULL,
9905             NULL,
9906             num_vertices10,
9907             num_faces10,
9908             vertex_size10,
9909             options,
9910             options,
9911             declaration_ptc,
9912             declaration_ptc_ubyte4,
9913             (BYTE*)exp_vertices10,
9914             exp_vertex_size10
9915         },
9916         {
9917             (BYTE*)vertices11,
9918             NULL,
9919             NULL,
9920             num_vertices11,
9921             num_faces11,
9922             vertex_size11,
9923             options,
9924             options,
9925             declaration_ptc,
9926             declaration_ptc_short2,
9927             (BYTE*)exp_vertices11,
9928             exp_vertex_size11
9929         },
9930         {
9931             (BYTE*)vertices12,
9932             NULL,
9933             NULL,
9934             num_vertices12,
9935             num_faces12,
9936             vertex_size12,
9937             options,
9938             options,
9939             declaration_ptc,
9940             declaration_ptc_short4,
9941             (BYTE*)exp_vertices12,
9942             exp_vertex_size12
9943         },
9944         {
9945             (BYTE*)vertices13,
9946             NULL,
9947             NULL,
9948             num_vertices13,
9949             num_faces13,
9950             vertex_size13,
9951             options,
9952             options,
9953             declaration_ptc,
9954             declaration_ptc_ubyte4n,
9955             (BYTE*)exp_vertices13,
9956             exp_vertex_size13
9957         },
9958         {
9959             (BYTE*)vertices14,
9960             NULL,
9961             NULL,
9962             num_vertices14,
9963             num_faces14,
9964             vertex_size14,
9965             options,
9966             options,
9967             declaration_ptc,
9968             declaration_ptc_short2n,
9969             (BYTE*)exp_vertices14,
9970             exp_vertex_size14
9971         },
9972         {
9973             (BYTE*)vertices15,
9974             NULL,
9975             NULL,
9976             num_vertices15,
9977             num_faces15,
9978             vertex_size15,
9979             options,
9980             options,
9981             declaration_ptc,
9982             declaration_ptc_short4n,
9983             (BYTE*)exp_vertices15,
9984             exp_vertex_size15
9985         },
9986         {
9987             (BYTE*)vertices16,
9988             NULL,
9989             NULL,
9990             num_vertices16,
9991             num_faces16,
9992             vertex_size16,
9993             options,
9994             options,
9995             declaration_ptc,
9996             declaration_ptc_ushort2n,
9997             (BYTE*)exp_vertices16,
9998             exp_vertex_size16
9999         },
10000         {
10001             (BYTE*)vertices17,
10002             NULL,
10003             NULL,
10004             num_vertices17,
10005             num_faces17,
10006             vertex_size17,
10007             options,
10008             options,
10009             declaration_ptc,
10010             declaration_ptc_ushort4n,
10011             (BYTE*)exp_vertices17,
10012             exp_vertex_size17
10013         },
10014         {
10015             (BYTE*)vertices18,
10016             NULL,
10017             NULL,
10018             num_vertices18,
10019             num_faces18,
10020             vertex_size18,
10021             options,
10022             options,
10023             declaration_ptc,
10024             declaration_ptc_float16_2_partialu,
10025             (BYTE*)exp_vertices18,
10026             exp_vertex_size18
10027         },
10028         {
10029             (BYTE*)vertices19,
10030             NULL,
10031             NULL,
10032             num_vertices19,
10033             num_faces19,
10034             vertex_size19,
10035             options,
10036             options,
10037             declaration_pntc,
10038             declaration_pntc1,
10039             (BYTE*)exp_vertices19,
10040             exp_vertex_size19
10041         },
10042         {
10043             (BYTE*)vertices20,
10044             NULL,
10045             NULL,
10046             num_vertices20,
10047             num_faces20,
10048             vertex_size20,
10049             options,
10050             options,
10051             declaration_pntc1,
10052             declaration_pntc,
10053             (BYTE*)exp_vertices20,
10054             exp_vertex_size20
10055         },
10056         {
10057             (BYTE*)vertices21,
10058             NULL,
10059             NULL,
10060             num_vertices21,
10061             num_faces21,
10062             vertex_size21,
10063             options,
10064             options,
10065             declaration_ptc_float1,
10066             declaration_ptc,
10067             (BYTE*)exp_vertices21,
10068             exp_vertex_size21
10069         },
10070         {
10071             (BYTE*)vertices22,
10072             NULL,
10073             NULL,
10074             num_vertices22,
10075             num_faces22,
10076             vertex_size22,
10077             options,
10078             options,
10079             declaration_ptc_float1,
10080             declaration_ptc_float3,
10081             (BYTE*)exp_vertices22,
10082             exp_vertex_size22
10083         },
10084         {
10085             (BYTE*)vertices23,
10086             NULL,
10087             NULL,
10088             num_vertices23,
10089             num_faces23,
10090             vertex_size23,
10091             options,
10092             options,
10093             declaration_ptc_float1,
10094             declaration_ptc_float4,
10095             (BYTE*)exp_vertices23,
10096             exp_vertex_size23
10097         },
10098         {
10099             (BYTE*)vertices24,
10100             NULL,
10101             NULL,
10102             num_vertices24,
10103             num_faces24,
10104             vertex_size24,
10105             options,
10106             options,
10107             declaration_ptc_float1,
10108             declaration_ptc_d3dcolor,
10109             (BYTE*)exp_vertices24,
10110             exp_vertex_size24
10111         },
10112         {
10113             (BYTE*)vertices25,
10114             NULL,
10115             NULL,
10116             num_vertices25,
10117             num_faces25,
10118             vertex_size25,
10119             options,
10120             options,
10121             declaration_ptc_float1,
10122             declaration_ptc_ubyte4,
10123             (BYTE*)exp_vertices25,
10124             exp_vertex_size25
10125         },
10126         {
10127             (BYTE*)vertices26,
10128             NULL,
10129             NULL,
10130             num_vertices26,
10131             num_faces26,
10132             vertex_size26,
10133             options,
10134             options,
10135             declaration_ptc_float4,
10136             declaration_ptc_d3dcolor,
10137             (BYTE*)exp_vertices26,
10138             exp_vertex_size26
10139         },
10140         {
10141             (BYTE*)vertices27,
10142             NULL,
10143             NULL,
10144             num_vertices27,
10145             num_faces27,
10146             vertex_size27,
10147             options,
10148             options,
10149             declaration_ptc_d3dcolor,
10150             declaration_ptc_float4,
10151             (BYTE*)exp_vertices27,
10152             exp_vertex_size27
10153         },
10154         {
10155             (BYTE*)vertices28,
10156             NULL,
10157             NULL,
10158             num_vertices28,
10159             num_faces28,
10160             vertex_size28,
10161             options,
10162             options,
10163             declaration_ptc_ubyte4,
10164             declaration_ptc_float4,
10165             (BYTE*)exp_vertices28,
10166             exp_vertex_size28
10167         },
10168         {
10169             (BYTE*)vertices29,
10170             NULL,
10171             NULL,
10172             num_vertices29,
10173             num_faces29,
10174             vertex_size29,
10175             options,
10176             options,
10177             declaration_ptc_short2,
10178             declaration_ptc_float4,
10179             (BYTE*)exp_vertices29,
10180             exp_vertex_size29
10181         },
10182         {
10183             (BYTE*)vertices30,
10184             NULL,
10185             NULL,
10186             num_vertices30,
10187             num_faces30,
10188             vertex_size30,
10189             options,
10190             options,
10191             declaration_ptc_short4,
10192             declaration_ptc_float4,
10193             (BYTE*)exp_vertices30,
10194             exp_vertex_size30
10195         },
10196         {
10197             (BYTE*)vertices31,
10198             NULL,
10199             NULL,
10200             num_vertices31,
10201             num_faces31,
10202             vertex_size31,
10203             options,
10204             options,
10205             declaration_ptc_ubyte4n,
10206             declaration_ptc_float4,
10207             (BYTE*)exp_vertices31,
10208             exp_vertex_size31
10209         },
10210         {
10211             (BYTE*)vertices32,
10212             NULL,
10213             NULL,
10214             num_vertices32,
10215             num_faces32,
10216             vertex_size32,
10217             options,
10218             options,
10219             declaration_ptc_short2n,
10220             declaration_ptc_float4,
10221             (BYTE*)exp_vertices32,
10222             exp_vertex_size32
10223         },
10224         {
10225             (BYTE*)vertices33,
10226             NULL,
10227             NULL,
10228             num_vertices33,
10229             num_faces33,
10230             vertex_size33,
10231             options,
10232             options,
10233             declaration_ptc_short4n,
10234             declaration_ptc_float4,
10235             (BYTE*)exp_vertices33,
10236             exp_vertex_size33
10237         },
10238         {
10239             (BYTE*)vertices34,
10240             NULL,
10241             NULL,
10242             num_vertices34,
10243             num_faces34,
10244             vertex_size34,
10245             options,
10246             options,
10247             declaration_ptc_float16_2,
10248             declaration_ptc_float4,
10249             (BYTE*)exp_vertices34,
10250             exp_vertex_size34
10251         },
10252         {
10253             (BYTE*)vertices35,
10254             NULL,
10255             NULL,
10256             num_vertices35,
10257             num_faces35,
10258             vertex_size35,
10259             options,
10260             options,
10261             declaration_ptc_float16_4,
10262             declaration_ptc_float4,
10263             (BYTE*)exp_vertices35,
10264             exp_vertex_size35
10265         },
10266         {
10267             (BYTE*)vertices36,
10268             NULL,
10269             NULL,
10270             num_vertices36,
10271             num_faces36,
10272             vertex_size36,
10273             options,
10274             clone_options36,
10275             declaration_pn,
10276             declaration_pn,
10277             (BYTE*)vertices36,
10278             vertex_size36
10279         },
10280     };
10281 #ifdef __REACTOS__
10282 #undef up
10283 #undef zero_vec2
10284 #endif
10285 
10286     test_context = new_test_context();
10287     if (!test_context)
10288     {
10289         skip("Couldn't create test context\n");
10290         goto cleanup;
10291     }
10292 
10293     for (i = 0; i < ARRAY_SIZE(tc); i++)
10294     {
10295         UINT j;
10296         D3DVERTEXELEMENT9 new_declaration[MAX_FVF_DECL_SIZE];
10297         UINT exp_new_decl_length, new_decl_length;
10298         UINT exp_new_decl_size, new_decl_size;
10299 
10300         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10301                               tc[i].create_options,
10302                               tc[i].declaration,
10303                               test_context->device, &mesh,
10304                               tc[i].vertices, tc[i].vertex_size,
10305                               tc[i].indices, tc[i].attributes);
10306         if (FAILED(hr))
10307         {
10308             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10309             goto cleanup;
10310         }
10311 
10312         hr = mesh->lpVtbl->CloneMesh(mesh, tc[i].clone_options, tc[i].new_declaration,
10313                                      test_context->device, &mesh_clone);
10314         ok(hr == D3D_OK, "Test %u, got unexpected hr %#x.\n", i, hr);
10315 
10316         hr = mesh_clone->lpVtbl->GetDeclaration(mesh_clone, new_declaration);
10317         ok(hr == D3D_OK, "Test %u, got unexpected hr %#x.\n", i, hr);
10318         /* Check declaration elements */
10319         for (j = 0; tc[i].new_declaration[j].Stream != 0xFF; j++)
10320         {
10321             ok(memcmp(&tc[i].new_declaration[j], &new_declaration[j], sizeof(*new_declaration)) == 0,
10322                "Test case %d failed. Declaration element %d did not match.\n", i, j);
10323         }
10324 
10325         /* Check declaration length */
10326         exp_new_decl_length = D3DXGetDeclLength(tc[i].new_declaration);
10327         new_decl_length = D3DXGetDeclLength(new_declaration);
10328         ok(new_decl_length == exp_new_decl_length,
10329            "Test case %d failed. Got new declaration length %d, expected %d\n",
10330            i, new_decl_length, exp_new_decl_length);
10331 
10332         /* Check declaration size */
10333         exp_new_decl_size = D3DXGetDeclVertexSize(tc[i].new_declaration, 0);
10334         new_decl_size = D3DXGetDeclVertexSize(new_declaration, 0);
10335         ok(new_decl_size == exp_new_decl_size,
10336            "Test case %d failed. Got new declaration size %d, expected %d\n",
10337            i, new_decl_size, exp_new_decl_size);
10338 
10339         /* Check vertex data in cloned mesh */
10340         hr = mesh_clone->lpVtbl->LockVertexBuffer(mesh_clone, 0, (void**)&vertices);
10341         if (FAILED(hr))
10342         {
10343             skip("Couldn't lock cloned vertex buffer.\n");
10344             goto cleanup;
10345         }
10346         for (j = 0; j < tc[i].num_vertices; j++)
10347         {
10348             UINT index = tc[i].exp_vertex_size * j;
10349             check_vertex_components(__LINE__, i, j, &vertices[index], &tc[i].exp_vertices[index], tc[i].new_declaration);
10350         }
10351         hr = mesh_clone->lpVtbl->UnlockVertexBuffer(mesh_clone);
10352         if (FAILED(hr))
10353         {
10354             skip("Couldn't unlock vertex buffer.\n");
10355             goto cleanup;
10356         }
10357         vertices = NULL;
10358         mesh->lpVtbl->Release(mesh);
10359         mesh = NULL;
10360         mesh_clone->lpVtbl->Release(mesh_clone);
10361         mesh_clone = NULL;
10362     }
10363 
10364     /* The following test shows that it is not possible to share a vertex buffer
10365      * with D3DXMESH_VB_SHARE and change the vertex declaration at the same
10366      * time. It reuses the test data from test 2.
10367      */
10368     hr = init_test_mesh(tc[2].num_faces, tc[2].num_vertices,
10369                         tc[2].create_options,
10370                         tc[2].declaration,
10371                         test_context->device, &mesh,
10372                         tc[2].vertices, tc[2].vertex_size,
10373                         tc[2].indices, tc[2].attributes);
10374     if (FAILED(hr))
10375     {
10376         skip("Couldn't initialize test mesh for D3DXMESH_VB_SHARE case."
10377              " Got %x expected D3D_OK\n", hr);
10378         goto cleanup;
10379     }
10380 
10381     hr = mesh->lpVtbl->CloneMesh(mesh, tc[2].create_options | D3DXMESH_VB_SHARE,
10382                                  tc[2].new_declaration, test_context->device,
10383                                  &mesh_clone);
10384     ok(hr == D3DERR_INVALIDCALL, "CloneMesh D3DXMESH_VB_SHARE with new"
10385        " declaration. Got %x, expected D3DERR_INVALIDCALL\n",
10386        hr);
10387     mesh->lpVtbl->Release(mesh);
10388     mesh = NULL;
10389     mesh_clone = NULL;
10390 
10391 cleanup:
10392     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
10393     if (mesh) mesh->lpVtbl->Release(mesh);
10394     if (mesh_clone) mesh_clone->lpVtbl->Release(mesh_clone);
10395     free_test_context(test_context);
10396 }
10397 
test_valid_mesh(void)10398 static void test_valid_mesh(void)
10399 {
10400     HRESULT hr;
10401     struct test_context *test_context = NULL;
10402     UINT i;
10403     const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
10404     const D3DVERTEXELEMENT9 declaration[] =
10405     {
10406         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10407         D3DDECL_END()
10408     };
10409     const unsigned int VERTS_PER_FACE = 3;
10410     /* mesh0 (one face)
10411      *
10412      * 0--1
10413      * | /
10414      * |/
10415      * 2
10416      */
10417     const D3DXVECTOR3 vertices0[] =
10418     {
10419         { 0.0f,  3.0f,  0.f},
10420         { 2.0f,  3.0f,  0.f},
10421         { 0.0f,  0.0f,  0.f},
10422     };
10423     const DWORD indices0[] = {0, 1, 2};
10424     const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
10425     const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
10426     const DWORD adjacency0[] = {-1, -1, -1};
10427     const HRESULT exp_hr0 = D3D_OK;
10428     /* mesh1 (Simple bow-tie)
10429      *
10430      * 0--1 1--3
10431      * | /   \ |
10432      * |/     \|
10433      * 2       4
10434      */
10435     const D3DXVECTOR3 vertices1[] =
10436     {
10437         { 0.0f,  3.0f,  0.f},
10438         { 2.0f,  3.0f,  0.f},
10439         { 0.0f,  0.0f,  0.f},
10440 
10441         { 4.0f,  3.0f,  0.f},
10442         { 4.0f,  0.0f,  0.f},
10443     };
10444     const DWORD indices1[] = {0, 1, 2, 1, 3, 4};
10445     const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
10446     const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
10447     const DWORD adjacency1[] = {-1, -1, -1, -1, -1, -1};
10448     const HRESULT exp_hr1 = D3DXERR_INVALIDMESH;
10449     /* Common mesh data */
10450     ID3DXMesh *mesh = NULL;
10451     UINT vertex_size = sizeof(D3DXVECTOR3);
10452     ID3DXBuffer *errors_and_warnings = NULL;
10453     struct
10454     {
10455         const D3DXVECTOR3 *vertices;
10456         const DWORD *indices;
10457         const UINT num_vertices;
10458         const UINT num_faces;
10459         const DWORD *adjacency;
10460         const HRESULT exp_hr;
10461     }
10462     tc[] =
10463     {
10464         {
10465             vertices0,
10466             indices0,
10467             num_vertices0,
10468             num_faces0,
10469             adjacency0,
10470             exp_hr0,
10471         },
10472         {
10473             vertices1,
10474             indices1,
10475             num_vertices1,
10476             num_faces1,
10477             adjacency1,
10478             exp_hr1,
10479         },
10480     };
10481 
10482     test_context = new_test_context();
10483     if (!test_context)
10484     {
10485         skip("Couldn't create test context\n");
10486         goto cleanup;
10487     }
10488 
10489     for (i = 0; i < ARRAY_SIZE(tc); i++)
10490     {
10491         hr = init_test_mesh(tc[i].num_faces, tc[i].num_vertices,
10492                             options, declaration,
10493                             test_context->device, &mesh,
10494                             tc[i].vertices, vertex_size,
10495                             tc[i].indices, NULL);
10496         if (FAILED(hr))
10497         {
10498             skip("Couldn't initialize test mesh %d. Got %x expected D3D_OK\n", i, hr);
10499             goto cleanup;
10500         }
10501 
10502         hr = D3DXValidMesh(mesh, tc[i].adjacency, &errors_and_warnings);
10503         todo_wine ok(hr == tc[i].exp_hr, "Test %u, got unexpected hr %#x, expected %#x.\n", i, hr, tc[i].exp_hr);
10504 
10505         /* Note errors_and_warnings is deliberately not checked because that
10506          * would require copying wast amounts of the text output. */
10507         if (errors_and_warnings)
10508         {
10509             ID3DXBuffer_Release(errors_and_warnings);
10510             errors_and_warnings = NULL;
10511         }
10512         mesh->lpVtbl->Release(mesh);
10513         mesh = NULL;
10514     }
10515 
10516 cleanup:
10517     if (mesh) mesh->lpVtbl->Release(mesh);
10518     free_test_context(test_context);
10519 }
10520 
test_optimize_vertices(void)10521 static void test_optimize_vertices(void)
10522 {
10523     HRESULT hr;
10524     DWORD vertex_remap[3];
10525     const DWORD indices[] = {0, 1, 2};
10526     const UINT num_faces = 1;
10527     const UINT num_vertices = 3;
10528 
10529     hr = D3DXOptimizeVertices(indices, num_faces,
10530                               num_vertices, FALSE,
10531                               vertex_remap);
10532     ok(hr == D3D_OK, "D3DXOptimizeVertices failed. Got %x, expected D3D_OK.\n", hr);
10533 
10534     /* vertex_remap must not be NULL */
10535     hr = D3DXOptimizeVertices(indices, num_faces,
10536                               num_vertices, FALSE,
10537                               NULL);
10538     ok(hr == D3DERR_INVALIDCALL, "D3DXOptimizeVertices passed NULL vertex_remap "
10539             "pointer. Got %x, expected D3DERR_INVALIDCALL.\n", hr);
10540 }
10541 
test_optimize_faces(void)10542 static void test_optimize_faces(void)
10543 {
10544     HRESULT hr;
10545     UINT i;
10546     DWORD smallest_face_remap;
10547     /* mesh0
10548      *
10549      * 0--1
10550      * | /
10551      * |/
10552      * 2
10553      */
10554     const DWORD indices0[] = {0, 1, 2};
10555     const UINT num_faces0 = 1;
10556     const UINT num_vertices0 = 3;
10557     const DWORD exp_face_remap0[] = {0};
10558     /* mesh1
10559      *
10560      * 0--1 3
10561      * | / /|
10562      * |/ / |
10563      * 2 5--4
10564      */
10565     const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
10566     const UINT num_faces1 = 2;
10567     const UINT num_vertices1 = 6;
10568     const DWORD exp_face_remap1[] = {1, 0};
10569     /* mesh2
10570      *
10571      * 0--1
10572      * | /|
10573      * |/ |
10574      * 2--3
10575      */
10576     const DWORD indices2[] = {0, 1, 2, 1, 3, 2};
10577     const UINT num_faces2 = 2;
10578     const UINT num_vertices2 = 4;
10579     const DWORD exp_face_remap2[] = {1, 0};
10580     /* mesh3
10581      *
10582      * 0--1
10583      * | /|
10584      * |/ |
10585      * 2--3
10586      * | /|
10587      * |/ |
10588      * 4--5
10589      */
10590     const DWORD indices3[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
10591     const UINT num_faces3 = 4;
10592     const UINT num_vertices3 = 6;
10593     const DWORD exp_face_remap3[] = {3, 2, 1, 0};
10594     /* mesh4
10595      *
10596      * 0--1
10597      * | /|
10598      * |/ |
10599      * 2--3
10600      * | /|
10601      * |/ |
10602      * 4--5
10603      */
10604     const WORD indices4[] = {0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 4, 5};
10605     const UINT num_faces4 = 4;
10606     const UINT num_vertices4 = 6;
10607     const DWORD exp_face_remap4[] = {3, 2, 1, 0};
10608     /* Test cases are stored in the tc array */
10609     struct
10610     {
10611         const VOID *indices;
10612         const UINT num_faces;
10613         const UINT num_vertices;
10614         const BOOL indices_are_32bit;
10615         const DWORD *exp_face_remap;
10616     }
10617     tc[] =
10618     {
10619         {
10620             indices0,
10621             num_faces0,
10622             num_vertices0,
10623             TRUE,
10624             exp_face_remap0
10625         },
10626         {
10627             indices1,
10628             num_faces1,
10629             num_vertices1,
10630             TRUE,
10631             exp_face_remap1
10632         },
10633         {
10634             indices2,
10635             num_faces2,
10636             num_vertices2,
10637             TRUE,
10638             exp_face_remap2
10639         },
10640         {
10641             indices3,
10642             num_faces3,
10643             num_vertices3,
10644             TRUE,
10645             exp_face_remap3
10646         },
10647         {
10648             indices4,
10649             num_faces4,
10650             num_vertices4,
10651             FALSE,
10652             exp_face_remap4
10653         },
10654     };
10655 
10656     /* Go through all test cases */
10657     for (i = 0; i < ARRAY_SIZE(tc); i++)
10658     {
10659         DWORD j;
10660         DWORD *face_remap;
10661         face_remap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
10662                                tc[i].num_faces*sizeof(*face_remap));
10663 
10664         hr = D3DXOptimizeFaces(tc[i].indices, tc[i].num_faces,
10665                                tc[i].num_vertices, tc[i].indices_are_32bit,
10666                                face_remap);
10667         ok(hr == D3D_OK, "Test %u, got unexpected hr %#x.\n", i, hr);
10668 
10669         /* Compare face remap with expected face remap */
10670         for (j = 0; j < tc[i].num_faces; j++)
10671         {
10672             ok(tc[i].exp_face_remap[j] == face_remap[j],
10673                "Test case %d: Got face %d at %d, expected %d\n", i,
10674                face_remap[j], j, tc[i].exp_face_remap[j]);
10675         }
10676 
10677         HeapFree(GetProcessHeap(), 0, face_remap);
10678     }
10679 
10680     /* face_remap must not be NULL */
10681     hr = D3DXOptimizeFaces(tc[0].indices, tc[0].num_faces,
10682                            tc[0].num_vertices, tc[0].indices_are_32bit,
10683                            NULL);
10684     ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#x.\n", hr);
10685 
10686     /* Number of faces must be smaller than 2^15 */
10687     hr = D3DXOptimizeFaces(tc[0].indices, 2 << 15,
10688                            tc[0].num_vertices, FALSE,
10689                            &smallest_face_remap);
10690     ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#x.\n", hr);
10691 }
10692 
clear_normals(ID3DXMesh * mesh)10693 static HRESULT clear_normals(ID3DXMesh *mesh)
10694 {
10695     HRESULT hr;
10696     BYTE *vertices;
10697     size_t normal_size;
10698     DWORD i, num_vertices, vertex_stride;
10699     const D3DXVECTOR4 normal = {NAN, NAN, NAN, NAN};
10700     D3DVERTEXELEMENT9 *normal_declaration = NULL;
10701     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
10702 
10703     if (FAILED(hr = mesh->lpVtbl->GetDeclaration(mesh, declaration)))
10704         return hr;
10705 
10706     for (i = 0; declaration[i].Stream != 0xff; i++)
10707     {
10708         if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
10709         {
10710             normal_declaration = &declaration[i];
10711             break;
10712         }
10713     }
10714 
10715     if (!normal_declaration)
10716         return D3DERR_INVALIDCALL;
10717 
10718     if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
10719     {
10720         normal_size = sizeof(D3DXVECTOR3);
10721     }
10722     else if (normal_declaration->Type == D3DDECLTYPE_FLOAT4)
10723     {
10724         normal_size = sizeof(D3DXVECTOR4);
10725     }
10726     else
10727     {
10728         trace("Cannot clear normals\n");
10729         return E_NOTIMPL;
10730     }
10731 
10732     num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
10733     vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
10734 
10735     if (FAILED(hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
10736         return hr;
10737 
10738     vertices += normal_declaration->Offset;
10739 
10740     for (i = 0; i < num_vertices; i++, vertices += vertex_stride)
10741         memcpy(vertices, &normal, normal_size);
10742 
10743     return mesh->lpVtbl->UnlockVertexBuffer(mesh);
10744 }
10745 
compare_normals(unsigned int line,const char * test_name,ID3DXMesh * mesh,const D3DXVECTOR3 * normals,unsigned int num_normals)10746 static void compare_normals(unsigned int line, const char *test_name,
10747         ID3DXMesh *mesh, const D3DXVECTOR3 *normals, unsigned int num_normals)
10748 {
10749     unsigned int i;
10750     BYTE *vertices;
10751     DWORD num_vertices, vertex_stride;
10752     D3DVERTEXELEMENT9 *normal_declaration = NULL;
10753     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
10754 
10755     if (FAILED(mesh->lpVtbl->GetDeclaration(mesh, declaration)))
10756     {
10757         ok_(__FILE__, line)(0, "%s: Failed to get declaration\n", test_name);
10758         return;
10759     }
10760 
10761     for (i = 0; declaration[i].Stream != 0xff; i++)
10762     {
10763         if (declaration[i].Usage == D3DDECLUSAGE_NORMAL && !declaration[i].UsageIndex)
10764         {
10765             normal_declaration = &declaration[i];
10766             break;
10767         }
10768     }
10769 
10770     if (!normal_declaration)
10771     {
10772         ok_(__FILE__, line)(0, "%s: Mesh has no normals\n", test_name);
10773         return;
10774     }
10775 
10776     if (normal_declaration->Type != D3DDECLTYPE_FLOAT3 && normal_declaration->Type != D3DDECLTYPE_FLOAT4)
10777     {
10778         ok_(__FILE__, line)(0, "%s: Mesh has invalid normals type\n", test_name);
10779         return;
10780     }
10781 
10782     num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
10783     vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
10784 
10785     ok_(__FILE__, line)(num_vertices == num_normals, "%s: Expected %u vertices, got %u\n", test_name,
10786             num_normals, num_vertices);
10787 
10788     if (FAILED(mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
10789     {
10790         ok_(__FILE__, line)(0, "%s: Failed to compare normals\n", test_name);
10791         return;
10792     }
10793 
10794     vertices += normal_declaration->Offset;
10795 
10796     for (i = 0; i < min(num_vertices, num_normals); i++, vertices += vertex_stride)
10797     {
10798         if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
10799         {
10800             const D3DXVECTOR3 *n = (D3DXVECTOR3 *)vertices;
10801             ok_(__FILE__, line)(compare_vec3(*n, normals[i]),
10802                     "%s: normal %2u, expected (%f, %f, %f), got (%f, %f, %f)\n",
10803                     test_name, i, normals[i].x, normals[i].y, normals[i].z, n->x, n->y, n->z);
10804         }
10805         else
10806         {
10807             const D3DXVECTOR4 *n = (D3DXVECTOR4 *)vertices;
10808             const D3DXVECTOR4 normal = {normals[i].x, normals[i].y, normals[i].z, 1.0f};
10809             ok_(__FILE__, line)(compare_vec4(*n, normal),
10810                     "%s: normal %2u, expected (%f, %f, %f, %f), got (%f, %f, %f, %f)\n",
10811                     test_name, i, normals[i].x, normals[i].y, normals[i].z, 1.0f,
10812                     n->x, n->y, n->z, n->w);
10813         }
10814     }
10815 
10816     mesh->lpVtbl->UnlockVertexBuffer(mesh);
10817 }
10818 
compute_normals_D3DXComputeNormals(ID3DXMesh * mesh,const DWORD * adjacency)10819 static HRESULT compute_normals_D3DXComputeNormals(ID3DXMesh *mesh, const DWORD *adjacency)
10820 {
10821     return D3DXComputeNormals((ID3DXBaseMesh *)mesh, adjacency);
10822 }
10823 
compute_normals_D3DXComputeTangentFrameEx(ID3DXMesh * mesh,const DWORD * adjacency)10824 static HRESULT compute_normals_D3DXComputeTangentFrameEx(ID3DXMesh *mesh, const DWORD *adjacency)
10825 {
10826     return D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
10827             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
10828             adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL);
10829 }
10830 
test_compute_normals(void)10831 static void test_compute_normals(void)
10832 {
10833     HRESULT hr;
10834     ULONG refcount;
10835     ID3DXMesh *mesh, *cloned_mesh;
10836     ID3DXBuffer *adjacency;
10837     IDirect3DDevice9 *device;
10838     struct test_context *test_context;
10839     unsigned int i;
10840 
10841     static const struct compute_normals_func
10842     {
10843         const char *name;
10844         HRESULT (*apply)(ID3DXMesh *mesh, const DWORD *adjacency);
10845     }
10846     compute_normals_funcs[] =
10847     {
10848         {"D3DXComputeNormals",        compute_normals_D3DXComputeNormals       },
10849         {"D3DXComputeTangentFrameEx", compute_normals_D3DXComputeTangentFrameEx}
10850     };
10851 
10852     static const D3DXVECTOR3 box_normals[24] =
10853     {
10854         {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f},
10855         { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f, 0.0f},
10856         { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f, 0.0f},
10857         { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f}, { 0.0f,-1.0f, 0.0f},
10858         { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f},
10859         { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}, { 0.0f, 0.0f,-1.0f}
10860     };
10861     const float box_normal_component = 1.0f / sqrtf(3.0f);
10862     const D3DXVECTOR3 box_normals_adjacency[24] =
10863     {
10864         {-box_normal_component, -box_normal_component, -box_normal_component},
10865         {-box_normal_component, -box_normal_component,  box_normal_component},
10866         {-box_normal_component,  box_normal_component,  box_normal_component},
10867         {-box_normal_component,  box_normal_component, -box_normal_component},
10868         {-box_normal_component,  box_normal_component, -box_normal_component},
10869         {-box_normal_component,  box_normal_component,  box_normal_component},
10870         { box_normal_component,  box_normal_component,  box_normal_component},
10871         { box_normal_component,  box_normal_component, -box_normal_component},
10872         { box_normal_component,  box_normal_component, -box_normal_component},
10873         { box_normal_component,  box_normal_component,  box_normal_component},
10874         { box_normal_component, -box_normal_component,  box_normal_component},
10875         { box_normal_component, -box_normal_component, -box_normal_component},
10876         {-box_normal_component, -box_normal_component,  box_normal_component},
10877         {-box_normal_component, -box_normal_component, -box_normal_component},
10878         { box_normal_component, -box_normal_component, -box_normal_component},
10879         { box_normal_component, -box_normal_component,  box_normal_component},
10880         {-box_normal_component, -box_normal_component,  box_normal_component},
10881         { box_normal_component, -box_normal_component,  box_normal_component},
10882         { box_normal_component,  box_normal_component,  box_normal_component},
10883         {-box_normal_component,  box_normal_component,  box_normal_component},
10884         {-box_normal_component, -box_normal_component, -box_normal_component},
10885         {-box_normal_component,  box_normal_component, -box_normal_component},
10886         { box_normal_component,  box_normal_component, -box_normal_component},
10887         { box_normal_component, -box_normal_component, -box_normal_component}
10888     };
10889     static const D3DXVECTOR3 box_normals_adjacency_area[24] =
10890     {
10891         {-0.666667f, -0.333333f, -0.666667f}, {-0.333333f, -0.666667f,  0.666667f},
10892         {-0.816496f,  0.408248f,  0.408248f}, {-0.408248f,  0.816496f, -0.408248f},
10893         {-0.408248f,  0.816496f, -0.408248f}, {-0.816496f,  0.408248f,  0.408248f},
10894         { 0.333333f,  0.666667f,  0.666667f}, { 0.666667f,  0.333333f, -0.666667f},
10895         { 0.666667f,  0.333333f, -0.666667f}, { 0.333333f,  0.666667f,  0.666667f},
10896         { 0.816496f, -0.408248f,  0.408248f}, { 0.408248f, -0.816496f, -0.408248f},
10897         {-0.333333f, -0.666667f,  0.666667f}, {-0.666667f, -0.333333f, -0.666667f},
10898         { 0.408248f, -0.816496f, -0.408248f}, { 0.816496f, -0.408248f,  0.408248f},
10899         {-0.333333f, -0.666667f,  0.666667f}, { 0.816497f, -0.408248f,  0.408248f},
10900         { 0.333333f,  0.666667f,  0.666667f}, {-0.816497f,  0.408248f,  0.408248f},
10901         {-0.666667f, -0.333333f, -0.666667f}, {-0.408248f,  0.816497f, -0.408248f},
10902         { 0.666667f,  0.333333f, -0.666667f}, { 0.408248f, -0.816496f, -0.408248f}
10903     };
10904     static const D3DXVECTOR3 box_normals_position1f[24] = {{0}};
10905     static const D3DXVECTOR3 box_normals_position2f[24] =
10906     {
10907         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
10908         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f,  1.0f},
10909         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
10910         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
10911         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f},
10912         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f},
10913         {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f,  1.0f}, {0.0f, 0.0f, -1.0f},
10914         {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, -1.0f}
10915     };
10916 
10917     static const D3DXVECTOR3 sphere_normals[22] =
10918     {
10919         { 0.000000f, -0.000000f,  1.000000f}, { 0.000000f,  0.582244f,  0.813014f},
10920         { 0.582244f, -0.000000f,  0.813014f}, {-0.000000f, -0.582244f,  0.813014f},
10921         {-0.582244f,  0.000000f,  0.813014f}, {-0.000000f,  0.890608f,  0.454772f},
10922         { 0.890608f,  0.000000f,  0.454772f}, { 0.000000f, -0.890608f,  0.454772f},
10923         {-0.890608f, -0.000000f,  0.454772f}, { 0.000000f,  1.000000f, -0.000000f},
10924         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10925         {-1.000000f,  0.000000f, -0.000000f}, { 0.000000f,  0.890608f, -0.454773f},
10926         { 0.890608f, -0.000000f, -0.454772f}, {-0.000000f, -0.890608f, -0.454773f},
10927         {-0.890608f,  0.000000f, -0.454773f}, { 0.000000f,  0.582244f, -0.813015f},
10928         { 0.582244f, -0.000000f, -0.813015f}, { 0.000000f, -0.582244f, -0.813015f},
10929         {-0.582243f,  0.000000f, -0.813015f}, { 0.000000f,  0.000000f, -1.000000f}
10930     };
10931     static const D3DXVECTOR3 sphere_normals_area[22] =
10932     {
10933         { 0.000000f, -0.000000f,  1.000000f}, {-0.215311f,  0.554931f,  0.803550f},
10934         { 0.554931f,  0.215311f,  0.803550f}, { 0.215311f, -0.554931f,  0.803550f},
10935         {-0.554931f, -0.215311f,  0.803550f}, {-0.126638f,  0.872121f,  0.472618f},
10936         { 0.872121f,  0.126638f,  0.472618f}, { 0.126638f, -0.872121f,  0.472618f},
10937         {-0.872121f, -0.126637f,  0.472618f}, { 0.000000f,  1.000000f, -0.000000f},
10938         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10939         {-1.000000f,  0.000000f, -0.000000f}, { 0.126638f,  0.872121f, -0.472618f},
10940         { 0.872121f, -0.126638f, -0.472618f}, {-0.126638f, -0.872121f, -0.472618f},
10941         {-0.872121f,  0.126638f, -0.472618f}, { 0.215311f,  0.554931f, -0.803550f},
10942         { 0.554931f, -0.215311f, -0.803550f}, {-0.215311f, -0.554931f, -0.803550f},
10943         {-0.554931f,  0.215311f, -0.803550f}, { 0.000000f,  0.000000f, -1.000000f}
10944     };
10945     static const D3DXVECTOR3 sphere_normals_equal[22] =
10946     {
10947         { 0.000000f, -0.000000f,  1.000000f}, {-0.134974f,  0.522078f,  0.842150f},
10948         { 0.522078f,  0.134974f,  0.842150f}, { 0.134974f, -0.522078f,  0.842150f},
10949         {-0.522078f, -0.134974f,  0.842150f}, {-0.026367f,  0.857121f,  0.514440f},
10950         { 0.857121f,  0.026367f,  0.514440f}, { 0.026367f, -0.857121f,  0.514440f},
10951         {-0.857121f, -0.026367f,  0.514440f}, { 0.000000f,  1.000000f, -0.000000f},
10952         { 1.000000f, -0.000000f, -0.000000f}, {-0.000000f, -1.000000f, -0.000000f},
10953         {-1.000000f,  0.000000f, -0.000000f}, { 0.026367f,  0.857121f, -0.514440f},
10954         { 0.857121f, -0.026367f, -0.514440f}, {-0.026367f, -0.857121f, -0.514440f},
10955         {-0.857121f,  0.026367f, -0.514440f}, { 0.134975f,  0.522078f, -0.842150f},
10956         { 0.522078f, -0.134975f, -0.842150f}, {-0.134974f, -0.522078f, -0.842150f},
10957         {-0.522078f,  0.134974f, -0.842150f}, { 0.000000f,  0.000000f, -1.000000f}
10958     };
10959 
10960     static const D3DVERTEXELEMENT9 position3f_normal1f_declaration[] =
10961     {
10962         {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10963         {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10964         D3DDECL_END()
10965     };
10966     static const D3DVERTEXELEMENT9 position3f_normal2f_declaration[] =
10967     {
10968         {0, 0,                   D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10969         {0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10970         D3DDECL_END()
10971     };
10972     static const D3DVERTEXELEMENT9 normal4f_position3f_declaration[] =
10973     {
10974         {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10975         {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10976         D3DDECL_END()
10977     };
10978     static const D3DVERTEXELEMENT9 position1f_normal3f_declaration[] =
10979     {
10980         {0, 0,                   D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10981         {0, sizeof(float),       D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10982         D3DDECL_END()
10983     };
10984     static const D3DVERTEXELEMENT9 position2f_normal3f_declaration[] =
10985     {
10986         {0, 0,                   D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10987         {0, sizeof(D3DXVECTOR2), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10988         D3DDECL_END()
10989     };
10990     static const D3DVERTEXELEMENT9 position4f_normal3f_declaration[] =
10991     {
10992         {0, 0,                   D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
10993         {0, sizeof(D3DXVECTOR4), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
10994         D3DDECL_END()
10995     };
10996 
10997     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
10998     {
10999         hr = compute_normals_funcs[i].apply(NULL, NULL);
11000         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", compute_normals_funcs[i].name, hr);
11001     }
11002 
11003     if (!(test_context = new_test_context()))
11004     {
11005         skip("Couldn't create test context\n");
11006         return;
11007     }
11008     device = test_context->device;
11009 
11010     hr = D3DXCreateBox(device, 1.0f, 1.0f, 1.0f, &mesh, &adjacency);
11011     ok(SUCCEEDED(hr), "D3DXCreateBox failed %#x\n", hr);
11012 
11013     /* Check wrong input */
11014     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11015             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11016     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11017 
11018     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DDECLUSAGE_NORMAL, 0,
11019             D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA | D3DXTANGENT_WEIGHT_EQUAL,
11020             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11021     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11022 
11023     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11024             D3DDECLUSAGE_NORMAL, 0, 0, NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11025     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11026 
11027     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11028             D3DDECLUSAGE_NORMAL, 1, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
11029             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11030     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11031 
11032     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11033             D3DX_DEFAULT, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
11034             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11035     ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11036 
11037     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11038             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_CALCULATE_NORMALS,
11039             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11040     todo_wine ok(hr == D3DERR_INVALIDCALL, "D3DXComputeTangentFrameEx returned %#x, expected D3DERR_INVALIDCALL\n", hr);
11041 
11042     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
11043     {
11044         const struct compute_normals_func *func = &compute_normals_funcs[i];
11045 
11046         /* Mesh without normals */
11047         hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_XYZ, device, &cloned_mesh);
11048         ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
11049 
11050         hr = func->apply(cloned_mesh, NULL);
11051         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11052 
11053         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11054         ok(!refcount, "Mesh has %u references left\n", refcount);
11055 
11056         /* Mesh without positions */
11057         hr = mesh->lpVtbl->CloneMeshFVF(mesh, 0, D3DFVF_NORMAL, device, &cloned_mesh);
11058         ok(SUCCEEDED(hr), "CloneMeshFVF failed %#x\n", hr);
11059 
11060         hr = func->apply(cloned_mesh, NULL);
11061         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11062 
11063         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11064         ok(!refcount, "Mesh has %u references left\n", refcount);
11065 
11066         /* Mesh with D3DDECLTYPE_FLOAT1 normals */
11067         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal1f_declaration, device, &cloned_mesh);
11068         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11069 
11070         hr = func->apply(cloned_mesh, NULL);
11071         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11072 
11073         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11074         ok(!refcount, "Mesh has %u references left\n", refcount);
11075 
11076         /* Mesh with D3DDECLTYPE_FLOAT2 normals */
11077         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position3f_normal2f_declaration, device, &cloned_mesh);
11078         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11079 
11080         hr = func->apply(cloned_mesh, NULL);
11081         ok(hr == D3DERR_INVALIDCALL, "%s returned %#x, expected D3DERR_INVALIDCALL\n", func->name, hr);
11082 
11083         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11084         ok(!refcount, "Mesh has %u references left\n", refcount);
11085 
11086         /* Mesh without adjacency data */
11087         hr = clear_normals(mesh);
11088         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11089 
11090         hr = func->apply(mesh, NULL);
11091         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11092 
11093         compare_normals(__LINE__, func->name, mesh, box_normals, ARRAY_SIZE(box_normals));
11094 
11095         /* Mesh with adjacency data */
11096         hr = clear_normals(mesh);
11097         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11098 
11099         hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11100         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11101 
11102         compare_normals(__LINE__, func->name, mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
11103 
11104         /* Mesh with custom vertex format, D3DDECLTYPE_FLOAT4 normals and adjacency */
11105         hr = mesh->lpVtbl->CloneMesh(mesh, 0, normal4f_position3f_declaration, device, &cloned_mesh);
11106         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11107 
11108         hr = clear_normals(cloned_mesh);
11109         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11110 
11111         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11112         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11113 
11114         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
11115 
11116         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11117         ok(!refcount, "Mesh has %u references left\n", refcount);
11118 
11119         /* Mesh with D3DDECLTYPE_FLOAT1 positions and D3DDECLTYPE_FLOAT3 normals */
11120         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position1f_normal3f_declaration, device, &cloned_mesh);
11121         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11122 
11123         hr = clear_normals(cloned_mesh);
11124         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11125 
11126         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11127         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11128 
11129         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position1f, ARRAY_SIZE(box_normals_position1f));
11130 
11131         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11132         ok(!refcount, "Mesh has %u references left\n", refcount);
11133 
11134         /* Mesh with D3DDECLTYPE_FLOAT2 positions and D3DDECLTYPE_FLOAT3 normals */
11135         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position2f_normal3f_declaration, device, &cloned_mesh);
11136         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11137 
11138         hr = clear_normals(cloned_mesh);
11139         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11140 
11141         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11142         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11143 
11144         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_position2f, ARRAY_SIZE(box_normals_position2f));
11145 
11146         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11147         ok(!refcount, "Mesh has %u references left\n", refcount);
11148 
11149         /* Mesh with D3DDECLTYPE_FLOAT4 positions and D3DDECLTYPE_FLOAT3 normals */
11150         hr = mesh->lpVtbl->CloneMesh(mesh, 0, position4f_normal3f_declaration, device, &cloned_mesh);
11151         ok(SUCCEEDED(hr), "CloneMesh failed %#x\n", hr);
11152 
11153         hr = clear_normals(cloned_mesh);
11154         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11155 
11156         hr = func->apply(cloned_mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11157         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11158 
11159         compare_normals(__LINE__, func->name, cloned_mesh, box_normals_adjacency, ARRAY_SIZE(box_normals_adjacency));
11160 
11161         refcount = cloned_mesh->lpVtbl->Release(cloned_mesh);
11162         ok(!refcount, "Mesh has %u references left\n", refcount);
11163     }
11164 
11165     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11166             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11167             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11168     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11169 
11170     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
11171 
11172     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11173             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11174             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11175     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11176 
11177     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
11178 
11179     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11180             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11181             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11182     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11183 
11184     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals, ARRAY_SIZE(box_normals));
11185 
11186     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11187             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11188             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11189     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11190 
11191     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, box_normals_adjacency_area, ARRAY_SIZE(box_normals_adjacency_area));
11192 
11193     refcount = mesh->lpVtbl->Release(mesh);
11194     ok(!refcount, "Mesh has %u references left\n", refcount);
11195     refcount = ID3DXBuffer_Release(adjacency);
11196     ok(!refcount, "Buffer has %u references left\n", refcount);
11197 
11198     hr = D3DXCreateSphere(device, 1.0f, 4, 6, &mesh, &adjacency);
11199     ok(SUCCEEDED(hr), "D3DXCreateSphere failed %#x\n", hr);
11200 
11201     for (i = 0; i < ARRAY_SIZE(compute_normals_funcs); i++)
11202     {
11203         const struct compute_normals_func *func = &compute_normals_funcs[i];
11204 
11205         /* Sphere without adjacency data */
11206         hr = clear_normals(mesh);
11207         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11208 
11209         hr = func->apply(mesh, NULL);
11210         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11211 
11212         compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
11213 
11214         /* Sphere with adjacency data */
11215         hr = clear_normals(mesh);
11216         ok(SUCCEEDED(hr), "Failed to clear normals, returned %#x\n", hr);
11217 
11218         hr = func->apply(mesh, ID3DXBuffer_GetBufferPointer(adjacency));
11219         ok(hr == D3D_OK, "%s returned %#x, expected D3D_OK\n", func->name, hr);
11220 
11221         compare_normals(__LINE__, func->name, mesh, sphere_normals, ARRAY_SIZE(sphere_normals));
11222     }
11223 
11224     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11225             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11226             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11227     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11228 
11229     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
11230 
11231     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11232             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_BY_AREA,
11233             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11234     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11235 
11236     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_area, ARRAY_SIZE(sphere_normals_area));
11237 
11238     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11239             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11240             NULL, -1.01f, -0.01f, -1.01f, NULL, NULL);
11241     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11242 
11243     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
11244 
11245     hr = D3DXComputeTangentFrameEx(mesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0,
11246             D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL,
11247             ID3DXBuffer_GetBufferPointer(adjacency), -1.01f, -0.01f, -1.01f, NULL, NULL);
11248     ok(hr == D3D_OK, "D3DXComputeTangentFrameEx returned %#x, expected D3D_OK\n", hr);
11249 
11250     compare_normals(__LINE__, "D3DXComputeTangentFrameEx", mesh, sphere_normals_equal, ARRAY_SIZE(sphere_normals_equal));
11251 
11252     refcount = mesh->lpVtbl->Release(mesh);
11253     ok(!refcount, "Mesh has %u references left\n", refcount);
11254     refcount = ID3DXBuffer_Release(adjacency);
11255     ok(!refcount, "Buffer has %u references left\n", refcount);
11256 
11257     free_test_context(test_context);
11258 }
11259 
D3DXCreateAnimationControllerTest(void)11260 static void D3DXCreateAnimationControllerTest(void)
11261 {
11262     HRESULT hr;
11263     ID3DXAnimationController *animation;
11264     UINT value;
11265 
11266     hr = D3DXCreateAnimationController(0, 0, 0, 0, NULL);
11267     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11268 
11269     animation = (void*)0xdeadbeef;
11270     hr = D3DXCreateAnimationController(0, 1, 1, 1, &animation);
11271     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11272     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11273 
11274     animation = (void*)0xdeadbeef;
11275     hr = D3DXCreateAnimationController(1, 0, 1, 1, &animation);
11276     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11277     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11278 
11279     animation = (void*)0xdeadbeef;
11280     hr = D3DXCreateAnimationController(1, 1, 0, 1, &animation);
11281     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11282     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11283 
11284     animation = (void*)0xdeadbeef;
11285     hr = D3DXCreateAnimationController(1, 1, 1, 0, &animation);
11286     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11287     ok(animation == (void*)0xdeadbeef, "Got unexpected animation %p.\n", animation);
11288 
11289     hr = D3DXCreateAnimationController(1, 1, 1, 1, &animation);
11290     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11291 
11292     value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
11293     ok(value == 1, "Got unexpected value %u.\n", value);
11294 
11295     value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
11296     ok(value == 1, "Got unexpected value %u.\n", value);
11297 
11298     value = animation->lpVtbl->GetMaxNumTracks(animation);
11299     ok(value == 1, "Got unexpected value %u.\n", value);
11300 
11301     value = animation->lpVtbl->GetMaxNumEvents(animation);
11302     ok(value == 1, "Got unexpected value %u.\n", value);
11303 
11304     animation->lpVtbl->Release(animation);
11305 
11306     hr = D3DXCreateAnimationController(100, 101, 102, 103, &animation);
11307     ok(hr == D3D_OK, "Got unexpected hr returned %#x.\n", hr);
11308 
11309     value = animation->lpVtbl->GetMaxNumAnimationOutputs(animation);
11310     ok(value == 100, "Got unexpected value %u.\n", value);
11311 
11312     value = animation->lpVtbl->GetMaxNumAnimationSets(animation);
11313     ok(value == 101, "Got unexpected value %u.\n", value);
11314 
11315     value = animation->lpVtbl->GetMaxNumTracks(animation);
11316     ok(value == 102, "Got unexpected value %u.\n", value);
11317 
11318     value = animation->lpVtbl->GetMaxNumEvents(animation);
11319     ok(value == 103, "Got unexpected value %u.\n", value);
11320 
11321     animation->lpVtbl->Release(animation);
11322 }
11323 
D3DXCreateKeyframedAnimationSetTest(void)11324 static void D3DXCreateKeyframedAnimationSetTest(void)
11325 {
11326     ID3DXKeyframedAnimationSet *set;
11327     D3DXPLAYBACK_TYPE type;
11328     unsigned int count;
11329     const char *name;
11330     HRESULT hr;
11331 
11332     hr = D3DXCreateKeyframedAnimationSet("wine_bottle", 5.0, D3DXPLAY_LOOP, 0, 0, NULL, &set);
11333     ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#x.\n", hr);
11334 
11335     hr = D3DXCreateKeyframedAnimationSet("wine_bottle", 5.0, D3DXPLAY_LOOP, 10, 0, NULL, &set);
11336     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
11337 
11338     name = set->lpVtbl->GetName(set);
11339     ok(!strcmp(name, "wine_bottle"), "Got unexpected name %s.\n", debugstr_a(name));
11340 
11341     type = set->lpVtbl->GetPlaybackType(set);
11342     ok(type == D3DXPLAY_LOOP, "Got unexpected value %u.\n", type);
11343 
11344     count = set->lpVtbl->GetNumAnimations(set);
11345     ok(!count, "Got unexpected value %u.\n", count);
11346 
11347     set->lpVtbl->Release(set);
11348 }
11349 
test_D3DXFrameFind(void)11350 static void test_D3DXFrameFind(void)
11351 {
11352     static char n1[] = "name1";
11353     static char n2[] = "name2";
11354     static char n3[] = "name3";
11355     static char n4[] = "name4";
11356     static char n5[] = "name5";
11357     static char n6[] = "name6";
11358     static char N1[] = "Name1";
11359     D3DXFRAME root, sibling, sibling2, child, *ret;
11360     D3DXFRAME child2, child3;
11361 
11362     ret = D3DXFrameFind(NULL, NULL);
11363     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11364 
11365     ret = D3DXFrameFind(NULL, "test");
11366     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11367 
11368     memset(&root, 0, sizeof(root));
11369 
11370     ret = D3DXFrameFind(&root, NULL);
11371     ok(ret == &root, "Unexpected frame, %p.\n", ret);
11372 
11373     root.Name = n1;
11374     ret = D3DXFrameFind(&root, NULL);
11375     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11376 
11377     ret = D3DXFrameFind(&root, n1);
11378     ok(ret == &root, "Unexpected frame, %p.\n", ret);
11379 
11380     ret = D3DXFrameFind(&root, N1);
11381     ok(ret == NULL, "Unexpected frame, %p.\n", ret);
11382 
11383     /* Test siblings order traversal. */
11384     memset(&sibling, 0, sizeof(sibling));
11385     sibling.Name = n2;
11386     root.pFrameSibling = &sibling;
11387     ret = D3DXFrameFind(&root, n2);
11388     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11389 
11390     memset(&sibling2, 0, sizeof(sibling2));
11391     sibling2.Name = n2;
11392     sibling.pFrameSibling = &sibling2;
11393     ret = D3DXFrameFind(&root, n2);
11394     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11395 
11396     sibling2.Name = n3;
11397     ret = D3DXFrameFind(&root, n3);
11398     ok(ret == &sibling2, "Unexpected frame, %p.\n", ret);
11399 
11400     /* Siblings first. */
11401     memset(&child, 0, sizeof(child));
11402     child.Name = n2;
11403     root.pFrameFirstChild = &child;
11404     ret = D3DXFrameFind(&root, n2);
11405     ok(ret == &sibling, "Unexpected frame, %p.\n", ret);
11406 
11407     child.Name = n4;
11408     ret = D3DXFrameFind(&root, n4);
11409     ok(ret == &child, "Unexpected frame, %p.\n", ret);
11410 
11411     /* Link a grandchild and another one for sibling. */
11412     memset(&child2, 0, sizeof(child2));
11413     memset(&child3, 0, sizeof(child3));
11414     child2.Name = child3.Name = n5;
11415     sibling.pFrameFirstChild = &child2;
11416     child.pFrameFirstChild = &child3;
11417     ret = D3DXFrameFind(&root, n5);
11418     ok(ret == &child2, "Unexpected frame, %p.\n", ret);
11419 
11420     child3.Name = n6;
11421     ret = D3DXFrameFind(&root, n6);
11422     ok(ret == &child3, "Unexpected frame, %p.\n", ret);
11423 }
11424 
get_mesh_data(const void * memory,SIZE_T length)11425 static ID3DXFileData *get_mesh_data(const void *memory, SIZE_T length)
11426 {
11427     ID3DXFileData *file_data, *ret = NULL;
11428     ID3DXFileEnumObject *enum_obj = NULL;
11429     D3DXF_FILELOADMEMORY source;
11430     ID3DXFile *file;
11431     SIZE_T i, count;
11432     GUID guid;
11433 
11434     if (FAILED(D3DXFileCreate(&file)))
11435         return NULL;
11436 
11437     if (FAILED(file->lpVtbl->RegisterTemplates(file, D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
11438         goto cleanup;
11439 
11440     source.lpMemory = memory;
11441     source.dSize = length;
11442     if (FAILED(file->lpVtbl->CreateEnumObject(file, &source, D3DXF_FILELOAD_FROMMEMORY, &enum_obj)))
11443         goto cleanup;
11444 
11445     if (FAILED(enum_obj->lpVtbl->GetChildren(enum_obj, &count)))
11446         goto cleanup;
11447 
11448     for (i = 0; i < count; ++i)
11449     {
11450         if (FAILED(enum_obj->lpVtbl->GetChild(enum_obj, i, &file_data)))
11451             goto cleanup;
11452 
11453         if (SUCCEEDED(file_data->lpVtbl->GetType(file_data, &guid))
11454                 && IsEqualGUID(&guid, &TID_D3DRMMesh))
11455         {
11456             ret = file_data;
11457             break;
11458         }
11459         else
11460         {
11461             file_data->lpVtbl->Release(file_data);
11462         }
11463     }
11464 
11465 cleanup:
11466     if (enum_obj)
11467         enum_obj->lpVtbl->Release(enum_obj);
11468     file->lpVtbl->Release(file);
11469 
11470     return ret;
11471 }
11472 
test_load_skin_mesh_from_xof(void)11473 static void test_load_skin_mesh_from_xof(void)
11474 {
11475     static const char simple_xfile[] =
11476         "xof 0303txt 0032"
11477         "Mesh {"
11478             "3;"
11479             "0.0; 0.0; 0.0;,"
11480             "0.0; 1.0; 0.0;,"
11481             "1.0; 1.0; 0.0;;"
11482             "1;"
11483             "3; 0, 1, 2;;"
11484         "}";
11485     static const D3DVERTEXELEMENT9 expected_declaration[] =
11486     {
11487         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
11488         D3DDECL_END(),
11489     };
11490     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
11491     ID3DXBuffer *adjacency, *materials, *effects;
11492     DWORD max_influences[3], count, fvf;
11493     D3DPRESENT_PARAMETERS d3dpp;
11494     IDirect3DDevice9 *device;
11495     ID3DXSkinInfo *skin_info;
11496     ID3DXFileData *file_data;
11497     const char *bone_name;
11498     D3DXMATRIX *matrix;
11499     float influence;
11500     ID3DXMesh *mesh;
11501     IDirect3D9 *d3d;
11502     ULONG refcount;
11503     HRESULT hr;
11504     HWND hwnd;
11505 
11506     if (!(hwnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
11507             640, 480, NULL, NULL, NULL, NULL)))
11508     {
11509         skip("Failed to create application window.\n");
11510         return;
11511     }
11512 
11513     d3d = Direct3DCreate9(D3D_SDK_VERSION);
11514     if (!d3d)
11515     {
11516         skip("Failed to create d3d object.\n");
11517         DestroyWindow(hwnd);
11518         return;
11519     }
11520 
11521     memset(&d3dpp, 0, sizeof(d3dpp));
11522     d3dpp.Windowed = TRUE;
11523     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
11524 
11525     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
11526             D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
11527     IDirect3D9_Release(d3d);
11528     if (FAILED(hr))
11529     {
11530         skip("Failed to create device, hr %#x.\n", hr);
11531         DestroyWindow(hwnd);
11532         return;
11533     }
11534 
11535     file_data = get_mesh_data(simple_xfile, sizeof(simple_xfile) - 1);
11536     ok(!!file_data, "Failed to load mesh data.\n");
11537 
11538     adjacency = materials = effects = (void *)0xdeadbeef;
11539     count = ~0u;
11540     skin_info = (void *)0xdeadbeef;
11541     mesh = (void *)0xdeadbeef;
11542 
11543     hr = D3DXLoadSkinMeshFromXof(file_data, 0, device, &adjacency, &materials, &effects, &count,
11544             &skin_info, &mesh);
11545     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
11546     ok(!!adjacency, "Got unexpected value %p.\n", adjacency);
11547     ok(!materials, "Got unexpected value %p.\n", materials);
11548     ok(!effects, "Got unexpected value %p.\n", effects);
11549     ok(!count, "Got unexpected value %u.\n", count);
11550     ok(!!skin_info, "Got unexpected value %p.\n", skin_info);
11551     ok(!!mesh, "Got unexpected value %p.\n", mesh);
11552     count = mesh->lpVtbl->GetNumVertices(mesh);
11553     ok(count == 3, "Got unexpected value %u.\n", count);
11554     count = mesh->lpVtbl->GetNumFaces(mesh);
11555     ok(count == 1, "Got unexpected value %u.\n", count);
11556 
11557     hr = skin_info->lpVtbl->GetDeclaration(skin_info, declaration);
11558     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
11559     compare_elements(declaration, expected_declaration, __LINE__, 0);
11560 
11561     fvf = skin_info->lpVtbl->GetFVF(skin_info);
11562     ok(fvf == D3DFVF_XYZ, "Got unexpected value %u.\n", fvf);
11563 
11564     count = skin_info->lpVtbl->GetNumBones(skin_info);
11565     ok(!count, "Got unexpected value %u.\n", count);
11566 
11567     influence = skin_info->lpVtbl->GetMinBoneInfluence(skin_info);
11568     ok(!influence, "Got unexpected value %.8e.\n", influence);
11569 
11570     memset(max_influences, 0x55, sizeof(max_influences));
11571     hr = skin_info->lpVtbl->GetMaxVertexInfluences(skin_info, max_influences);
11572     todo_wine ok(hr == D3D_OK, "Got unexpected value %#x.\n", hr);
11573     todo_wine ok(!max_influences[0], "Got unexpected value %u.\n", max_influences[0]);
11574     ok(max_influences[1] == 0x55555555, "Got unexpected value %u.\n", max_influences[1]);
11575     ok(max_influences[2] == 0x55555555, "Got unexpected value %u.\n", max_influences[2]);
11576 
11577     bone_name = skin_info->lpVtbl->GetBoneName(skin_info, 0);
11578     ok(!bone_name, "Got unexpected value %p.\n", bone_name);
11579 
11580     count = skin_info->lpVtbl->GetNumBoneInfluences(skin_info, 0);
11581     ok(!count, "Got unexpected value %u.\n", count);
11582 
11583     count = skin_info->lpVtbl->GetNumBoneInfluences(skin_info, 1);
11584     ok(!count, "Got unexpected value %u.\n", count);
11585 
11586     matrix = skin_info->lpVtbl->GetBoneOffsetMatrix(skin_info, -1);
11587     ok(!matrix, "Got unexpected value %p.\n", matrix);
11588 
11589     matrix = skin_info->lpVtbl->GetBoneOffsetMatrix(skin_info, 0);
11590     ok(!matrix, "Got unexpected value %p.\n", matrix);
11591 
11592     skin_info->lpVtbl->Release(skin_info);
11593     mesh->lpVtbl->Release(mesh);
11594     adjacency->lpVtbl->Release(adjacency);
11595     file_data->lpVtbl->Release(file_data);
11596     refcount = IDirect3DDevice9_Release(device);
11597     ok(!refcount, "Device has %u references left.\n", refcount);
11598     DestroyWindow(hwnd);
11599 }
11600 
START_TEST(mesh)11601 START_TEST(mesh)
11602 {
11603     D3DXBoundProbeTest();
11604     D3DXComputeBoundingBoxTest();
11605     D3DXComputeBoundingSphereTest();
11606     D3DXGetFVFVertexSizeTest();
11607     D3DXIntersectTriTest();
11608     D3DXCreateMeshTest();
11609     D3DXCreateMeshFVFTest();
11610     D3DXLoadMeshTest();
11611     D3DXCreateBoxTest();
11612     D3DXCreatePolygonTest();
11613     D3DXCreateSphereTest();
11614     D3DXCreateCylinderTest();
11615     D3DXCreateTextTest();
11616     D3DXCreateTorusTest();
11617     D3DXCreateAnimationControllerTest();
11618     D3DXCreateKeyframedAnimationSetTest();
11619     test_get_decl_length();
11620     test_get_decl_vertex_size();
11621     test_fvf_decl_conversion();
11622     D3DXGenerateAdjacencyTest();
11623     test_update_semantics();
11624     test_create_skin_info();
11625     test_update_skinned_mesh();
11626     test_convert_adjacency_to_point_reps();
11627     test_convert_point_reps_to_adjacency();
11628     test_weld_vertices();
11629     test_clone_mesh();
11630     test_valid_mesh();
11631     test_optimize_vertices();
11632     test_optimize_faces();
11633     test_compute_normals();
11634     test_D3DXFrameFind();
11635     test_load_skin_mesh_from_xof();
11636 }
11637