ReactOS  0.4.15-dev-1187-g119f102
mesh.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 David Adam
3  * Copyright 2008 Luis Busquets
4  * Copyright 2009 Henri Verbeet for CodeWeavers
5  * Copyright 2011 Michael Mc Donnell
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #define COBJMACROS
23 #include <stdio.h>
24 #include <float.h>
25 #include <limits.h>
26 #include "wine/test.h"
27 #include "d3dx9.h"
28 #include "initguid.h"
29 #include "rmxftmpl.h"
30 #include "rmxfguid.h"
31 
32 #ifndef NAN
33 /* From wine/port.h */
34 static inline float __port_nan(void)
35 {
36  static const unsigned __nan_bytes = 0x7fc00000;
37  return *(const float *)&__nan_bytes;
38 }
39 #define NAN __port_nan()
40 #endif
41 
42 /* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose
43  * function call traces of ID3DXAllocateHierarchy callbacks. */
44 #define TRACECALLBACK if(winetest_debug > 1) trace
45 
46 #define admitted_error 0.0001f
47 
48 #define compare_vertex_sizes(type, exp) \
49  got=D3DXGetFVFVertexSize(type); \
50  ok(got==exp, "Expected: %d, Got: %d\n", exp, got);
51 
52 #define compare_float(got, exp) \
53  do { \
54  float _got = (got); \
55  float _exp = (exp); \
56  ok(_got == _exp, "Expected: %g, Got: %g\n", _exp, _got); \
57  } while (0)
58 
60 {
61  return (fabs(u-v) < admitted_error);
62 }
63 
65 {
66  return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
67 }
68 
70 {
71  return compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) && compare(u.w, v.w);
72 }
73 
74 #define check_floats(got, exp, dim) check_floats_(__LINE__, "", got, exp, dim)
75 static void check_floats_(int line, const char *prefix, const float *got, const float *exp, int dim)
76 {
77  int i;
78  char exp_buffer[256] = "";
79  char got_buffer[256] = "";
80  char *exp_buffer_ptr = exp_buffer;
81  char *got_buffer_ptr = got_buffer;
82  BOOL equal = TRUE;
83 
84  for (i = 0; i < dim; i++) {
85  if (i) {
86  exp_buffer_ptr += sprintf(exp_buffer_ptr, ", ");
87  got_buffer_ptr += sprintf(got_buffer_ptr, ", ");
88  }
89  equal = equal && compare(*exp, *got);
90  exp_buffer_ptr += sprintf(exp_buffer_ptr, "%g", *exp);
91  got_buffer_ptr += sprintf(got_buffer_ptr, "%g", *got);
92  exp++, got++;
93  }
94  ok_(__FILE__,line)(equal, "%sExpected (%s), got (%s)", prefix, exp_buffer, got_buffer);
95 }
96 
97 struct vertex
98 {
101 };
102 
103 typedef WORD face[3];
104 
106 {
107  return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
108 }
109 
111 {
113  IDirect3D9 *d3d;
114  IDirect3DDevice9 *device;
115 };
116 
117 /* Initializes a test context struct. Use it to initialize DirectX.
118  *
119  * Returns NULL if an error occurred.
120  */
121 static struct test_context *new_test_context(void)
122 {
123  HRESULT hr;
124  HWND hwnd = NULL;
125  IDirect3D9 *d3d = NULL;
126  IDirect3DDevice9 *device = NULL;
127  D3DPRESENT_PARAMETERS d3dpp = {0};
128  struct test_context *test_context;
129 
130  if (!(hwnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
131  640, 480, NULL, NULL, NULL, NULL)))
132  {
133  skip("Couldn't create application window\n");
134  goto error;
135  }
136 
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;
149  if (FAILED(hr))
150  {
151  skip("Couldn't create IDirect3DDevice9 object %#x\n", hr);
152  goto error;
153  }
154 
156  if (!test_context)
157  {
158  skip("Couldn't allocate memory for test_context\n");
159  goto error;
160  }
162  test_context->d3d = d3d;
164 
165  return test_context;
166 
167 error:
168  if (device)
170 
171  if (d3d)
173 
174  if (hwnd)
176 
177  return NULL;
178 }
179 
181 {
182  if (!test_context)
183  return;
184 
185  if (test_context->device)
187 
188  if (test_context->d3d)
190 
191  if (test_context->hwnd)
193 
195 }
196 
197 struct mesh
198 {
200  struct vertex *vertices;
201 
204 
207 };
208 
209 static void free_mesh(struct mesh *mesh)
210 {
213 }
214 
215 static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
216 {
217  mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
218  if (!mesh->vertices)
219  {
220  return FALSE;
221  }
222  mesh->number_of_vertices = number_of_vertices;
223 
224  mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
225  if (!mesh->faces)
226  {
228  return FALSE;
229  }
230  mesh->number_of_faces = number_of_faces;
231 
232  return TRUE;
233 }
234 
235 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
236 {
237  HRESULT hr;
238  DWORD number_of_vertices, number_of_faces;
239  IDirect3DVertexBuffer9 *vertex_buffer;
240  IDirect3DIndexBuffer9 *index_buffer;
241  D3DVERTEXBUFFER_DESC vertex_buffer_description;
242  D3DINDEXBUFFER_DESC index_buffer_description;
243  struct vertex *vertices;
244  face *faces;
245  int expected, i;
246 
247  number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
248  ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
249  name, number_of_vertices, mesh->number_of_vertices);
250 
251  number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
252  ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
253  name, number_of_faces, mesh->number_of_faces);
254 
255  /* vertex buffer */
256  hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
257  ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
258 
259  if (hr != D3D_OK)
260  {
261  skip("Couldn't get vertex buffer\n");
262  }
263  else
264  {
265  hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
266  ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
267 
268  if (hr != D3D_OK)
269  {
270  skip("Couldn't get vertex buffer description\n");
271  }
272  else
273  {
274  ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
275  name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
276  ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
277  name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
278  ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
279  ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
280  name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
281  ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
282  name, vertex_buffer_description.FVF, mesh->fvf);
283  if (mesh->fvf == 0)
284  {
285  expected = number_of_vertices * mesh->vertex_size;
286  }
287  else
288  {
289  expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
290  }
291  ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
292  name, vertex_buffer_description.Size, expected);
293  }
294 
295  /* specify offset and size to avoid potential overruns */
296  hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
297  (void **)&vertices, D3DLOCK_DISCARD);
298  ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
299 
300  if (hr != D3D_OK)
301  {
302  skip("Couldn't lock vertex buffer\n");
303  }
304  else
305  {
306  for (i = 0; i < number_of_vertices; i++)
307  {
308  ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
309  "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
310  vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
311  mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
312  ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
313  "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
314  vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
315  mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
316  }
317 
319  }
320 
322  }
323 
324  /* index buffer */
325  hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
326  ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
327 
328  if (!index_buffer)
329  {
330  skip("Couldn't get index buffer\n");
331  }
332  else
333  {
334  hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
335  ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
336 
337  if (hr != D3D_OK)
338  {
339  skip("Couldn't get index buffer description\n");
340  }
341  else
342  {
343  ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
344  name, index_buffer_description.Format, D3DFMT_INDEX16);
345  ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
346  name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
347  ok(index_buffer_description.Usage == 0, "Test %s, result %#x, expected %#x.\n",
348  name, index_buffer_description.Usage, 0);
349  ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
350  name, index_buffer_description.Pool, D3DPOOL_MANAGED);
351  expected = number_of_faces * sizeof(WORD) * 3;
352  ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
353  name, index_buffer_description.Size, expected);
354  }
355 
356  /* specify offset and size to avoid potential overruns */
357  hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
358  (void **)&faces, D3DLOCK_DISCARD);
359  ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
360 
361  if (hr != D3D_OK)
362  {
363  skip("Couldn't lock index buffer\n");
364  }
365  else
366  {
367  for (i = 0; i < number_of_faces; i++)
368  {
369  ok(compare_face(faces[i], mesh->faces[i]),
370  "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
371  faces[i][0], faces[i][1], faces[i][2],
372  mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
373  }
374 
375  IDirect3DIndexBuffer9_Unlock(index_buffer);
376  }
377 
378  IDirect3DIndexBuffer9_Release(index_buffer);
379  }
380 }
381 
382 static void D3DXBoundProbeTest(void)
383 {
384  BOOL result;
385  D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
386  FLOAT radius;
387 
388 /*____________Test the Box case___________________________*/
389  bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
390  top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
391 
392  raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
393  rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
394  result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
395  ok(result == TRUE, "expected TRUE, received FALSE\n");
396 
397  raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
398  rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
399  result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
400  ok(result == FALSE, "expected FALSE, received TRUE\n");
401 
402  rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
403  result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
404  ok(result == TRUE, "expected TRUE, received FALSE\n");
405 
406  bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
407  top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
408  rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
409  raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
410  result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
411  ok(result == FALSE, "expected FALSE, received TRUE\n");
412 
413  bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
414  top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
415 
416  raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
417  rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
418  result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
419  ok(result == TRUE, "expected TRUE, received FALSE\n");
420 
421  bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
422  top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
423 
424  raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
425  rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
426  result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
427  ok(result == FALSE, "expected FALSE, received TRUE\n");
428 
429  raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
430  rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
431  result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
432  ok(result == TRUE, "expected TRUE, received FALSE\n");
433 
434 /*____________Test the Sphere case________________________*/
435  radius = sqrt(77.0f);
436  center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
437  raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
438 
439  rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
440  result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
441  ok(result == TRUE, "expected TRUE, received FALSE\n");
442 
443  rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
444  result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
445  ok(result == FALSE, "expected FALSE, received TRUE\n");
446 
447  rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
448  result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
449  ok(result == FALSE, "expected FALSE, received TRUE\n");
450 }
451 
452 static void D3DXComputeBoundingBoxTest(void)
453 {
454  D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
455  HRESULT hr;
456 
457  vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
458  vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
459  vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
460  vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
461  vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
462 
463  exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
464  exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
465 
466  hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
467 
468  ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
469  ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
470  ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
471 
472 /*________________________*/
473 
474  vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
475  vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
476  vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
477  vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
478  vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
479 
480  exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
481  exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
482 
483  hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
484 
485  ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
486  ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
487  ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
488 
489 /*________________________*/
490 
491  vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
492  vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
493  vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
494  vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
495  vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
496 
497  exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
498  exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
499 
500  hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
501 
502  ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
503  ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
504  ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
505 
506 /*________________________*/
508  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
509 
510 /*________________________*/
512  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
513 
514 /*________________________*/
516  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
517 }
518 
520 {
521  D3DXVECTOR3 exp_cen, got_cen, vertex[5];
522  FLOAT exp_rad, got_rad;
523  HRESULT hr;
524 
525  vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
526  vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
527  vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
528  vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
529  vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
530 
531  exp_rad = 6.928203f;
532  exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
533 
535 
536  ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
537  ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
538  ok( compare_vec3(exp_cen,got_cen), "Expected center: (%f, %f, %f), got center: (%f, %f, %f)\n", exp_cen.x,exp_cen.y,exp_cen.z,got_cen.x,got_cen.y,got_cen.z);
539 
540 /*________________________*/
541 
542  vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
543  vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
544  vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
545  vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
546  vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
547 
548  exp_rad = 13.707883f;
549  exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
550 
552 
553  ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
554  ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
555  ok( compare_vec3(exp_cen,got_cen), "Expected center: (%f, %f, %f), got center: (%f, %f, %f)\n", exp_cen.x,exp_cen.y,exp_cen.z,got_cen.x,got_cen.y,got_cen.z);
556 
557 /*________________________*/
559  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
560 
561 /*________________________*/
563  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
564 
565 /*________________________*/
567  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
568 }
569 
570 static void print_elements(const D3DVERTEXELEMENT9 *elements)
571 {
573  const D3DVERTEXELEMENT9 *ptr = elements;
574  int count = 0;
575 
576  while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
577  {
578  trace(
579  "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
580  count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
581  ptr++;
582  count++;
583  }
584 }
585 
586 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
587  unsigned int line, unsigned int test_id)
588 {
590  unsigned int i;
591 
592  for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
593  {
594  int end1 = memcmp(&elements[i], &last, sizeof(last));
595  int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
596  int status;
597 
598  if (!end1 && !end2) break;
599 
600  status = !end1 ^ !end2;
601  ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
602  line, test_id, end1 ? "shorter" : "longer");
603  if (status)
604  {
605  print_elements(elements);
606  break;
607  }
608 
609  status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
610  ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
611  if (status)
612  {
613  print_elements(elements);
614  break;
615  }
616  }
617 }
618 
619 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
620  HRESULT expected_hr, unsigned int line, unsigned int test_id)
621 {
622  HRESULT hr;
624 
625  hr = D3DXDeclaratorFromFVF(test_fvf, decl);
626  ok(hr == expected_hr,
627  "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
628  line, test_id, hr, expected_hr);
629  if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
630 }
631 
632 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
633  HRESULT expected_hr, unsigned int line, unsigned int test_id)
634 {
635  HRESULT hr;
636  DWORD result_fvf = 0xdeadbeef;
637 
638  hr = D3DXFVFFromDeclarator(decl, &result_fvf);
639  ok(hr == expected_hr,
640  "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
641  line, test_id, hr, expected_hr);
642  if (SUCCEEDED(hr))
643  {
644  ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
645  line, test_id, result_fvf, expected_fvf);
646  }
647 }
648 
649 static void test_fvf_decl_conversion(void)
650 {
651  static const struct
652  {
654  DWORD fvf;
655  }
656  test_data[] =
657  {
658  {{
659  D3DDECL_END(),
660  }, 0},
661  {{
663  D3DDECL_END(),
664  }, D3DFVF_XYZ},
665  {{
667  D3DDECL_END(),
668  }, D3DFVF_XYZRHW},
669  {{
671  D3DDECL_END(),
672  }, D3DFVF_XYZRHW},
673  {{
676  D3DDECL_END(),
677  }, D3DFVF_XYZB1},
678  {{
681  D3DDECL_END(),
683  {{
686  D3DDECL_END(),
688  {{
691  D3DDECL_END(),
692  }, D3DFVF_XYZB2},
693  {{
697  D3DDECL_END(),
699  {{
703  D3DDECL_END(),
705  {{
708  D3DDECL_END(),
709  }, D3DFVF_XYZB3},
710  {{
714  D3DDECL_END(),
716  {{
720  D3DDECL_END(),
722  {{
725  D3DDECL_END(),
726  }, D3DFVF_XYZB4},
727  {{
731  D3DDECL_END(),
733  {{
737  D3DDECL_END(),
739  {{
743  D3DDECL_END(),
745  {{
749  D3DDECL_END(),
751  {{
753  D3DDECL_END(),
754  }, D3DFVF_NORMAL},
755  {{
758  D3DDECL_END(),
760  {{
761  {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
762  D3DDECL_END(),
763  }, D3DFVF_PSIZE},
764  {{
766  D3DDECL_END(),
767  }, D3DFVF_DIFFUSE},
768  {{
770  D3DDECL_END(),
771  }, D3DFVF_SPECULAR},
772  /* Make sure textures of different sizes work. */
773  {{
775  D3DDECL_END(),
777  {{
779  D3DDECL_END(),
781  {{
783  D3DDECL_END(),
785  {{
787  D3DDECL_END(),
789  /* Make sure the TEXCOORD index works correctly - try several textures. */
790  {{
795  D3DDECL_END(),
798  /* Now try some combination tests. */
799  {{
806  D3DDECL_END(),
809  {{
811  {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
812  {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
816  D3DDECL_END(),
819  };
820  unsigned int i;
821 
822  for (i = 0; i < ARRAY_SIZE(test_data); ++i)
823  {
824  test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
825  test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
826  }
827 
828  /* Usage indices for position and normal are apparently ignored. */
829  {
830  const D3DVERTEXELEMENT9 decl[] =
831  {
833  D3DDECL_END(),
834  };
835  test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
836  }
837  {
838  const D3DVERTEXELEMENT9 decl[] =
839  {
841  D3DDECL_END(),
842  };
843  test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
844  }
845  /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
846  * there are no blend matrices. */
847  {
848  const D3DVERTEXELEMENT9 decl[] =
849  {
851  D3DDECL_END(),
852  };
854  }
855  {
856  const D3DVERTEXELEMENT9 decl[] =
857  {
859  D3DDECL_END(),
860  };
862  }
863  /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
864  {
865  const D3DVERTEXELEMENT9 decl[] =
866  {
870  D3DDECL_END(),
871  };
873  decl, D3D_OK, __LINE__, 0);
874  }
875  /* These are supposed to fail, both ways. */
876  {
877  const D3DVERTEXELEMENT9 decl[] =
878  {
880  D3DDECL_END(),
881  };
882  test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
883  test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
884  }
885  {
886  const D3DVERTEXELEMENT9 decl[] =
887  {
889  {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
890  D3DDECL_END(),
891  };
894  }
895  {
896  const D3DVERTEXELEMENT9 decl[] =
897  {
901  D3DDECL_END(),
902  };
903  test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
904  test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
905  }
906  /* Test a declaration that can't be converted to an FVF. */
907  {
908  const D3DVERTEXELEMENT9 decl[] =
909  {
911  {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
912  {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
915  /* 8 bytes padding */
917  D3DDECL_END(),
918  };
919  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
920  }
921  /* Elements must be ordered by offset. */
922  {
923  const D3DVERTEXELEMENT9 decl[] =
924  {
927  D3DDECL_END(),
928  };
929  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
930  }
931  /* Basic tests for element order. */
932  {
933  const D3DVERTEXELEMENT9 decl[] =
934  {
937  {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
938  D3DDECL_END(),
939  };
940  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
941  }
942  {
943  const D3DVERTEXELEMENT9 decl[] =
944  {
947  D3DDECL_END(),
948  };
949  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
950  }
951  {
952  const D3DVERTEXELEMENT9 decl[] =
953  {
956  D3DDECL_END(),
957  };
958  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
959  }
960  /* Textures must be ordered by texcoords. */
961  {
962  const D3DVERTEXELEMENT9 decl[] =
963  {
968  D3DDECL_END(),
969  };
970  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
971  }
972  /* Duplicate elements are not allowed. */
973  {
974  const D3DVERTEXELEMENT9 decl[] =
975  {
979  D3DDECL_END(),
980  };
981  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
982  }
983  /* Invalid FVFs cannot be converted to a declarator. */
984  test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
985 }
986 
987 static void D3DXGetFVFVertexSizeTest(void)
988 {
989  UINT got;
990 
992 
994 
996 
998 
1000 
1002  D3DFVF_XYZ |
1003  D3DFVF_TEX1 |
1004  D3DFVF_TEXCOORDSIZE1(0), 16);
1006  D3DFVF_XYZ |
1007  D3DFVF_TEX2 |
1009  D3DFVF_TEXCOORDSIZE1(1), 20);
1010 
1012  D3DFVF_XYZ |
1013  D3DFVF_TEX1 |
1014  D3DFVF_TEXCOORDSIZE2(0), 20);
1015 
1017  D3DFVF_XYZ |
1018  D3DFVF_TEX2 |
1020  D3DFVF_TEXCOORDSIZE2(1), 28);
1021 
1023  D3DFVF_XYZ |
1024  D3DFVF_TEX6 |
1030  D3DFVF_TEXCOORDSIZE2(5), 60);
1031 
1033  D3DFVF_XYZ |
1034  D3DFVF_TEX8 |
1042  D3DFVF_TEXCOORDSIZE2(7), 76);
1043 
1045  D3DFVF_XYZ |
1046  D3DFVF_TEX1 |
1047  D3DFVF_TEXCOORDSIZE3(0), 24);
1048 
1050  D3DFVF_XYZ |
1051  D3DFVF_TEX4 |
1055  D3DFVF_TEXCOORDSIZE3(3), 60);
1056 
1058  D3DFVF_XYZ |
1059  D3DFVF_TEX1 |
1060  D3DFVF_TEXCOORDSIZE4(0), 28);
1061 
1063  D3DFVF_XYZ |
1064  D3DFVF_TEX2 |
1066  D3DFVF_TEXCOORDSIZE4(1), 44);
1067 
1069  D3DFVF_XYZ |
1070  D3DFVF_TEX3 |
1073  D3DFVF_TEXCOORDSIZE4(2), 60);
1074 
1076  D3DFVF_XYZB5 |
1077  D3DFVF_NORMAL |
1078  D3DFVF_DIFFUSE |
1079  D3DFVF_SPECULAR |
1080  D3DFVF_TEX8 |
1088  D3DFVF_TEXCOORDSIZE4(7), 180);
1089 }
1090 
1091 static void D3DXIntersectTriTest(void)
1092 {
1093  BOOL exp_res, got_res;
1094  D3DXVECTOR3 position, ray, vertex[3];
1095  FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
1096 
1097  vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1098  vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1099  vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1100 
1101  position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
1102 
1103  ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1104 
1105  exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
1106 
1107  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1108  ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1109  ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1110  ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1111  ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1112 
1113  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1114  ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1115 
1116  vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1117  vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1118  vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 0.0f;
1119 
1120  got_u = got_v = got_dist = 0.0f;
1121  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1122  ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1123  ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1124  ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1125  ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1126 
1127  vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1128  vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = -0.5f;
1129  vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = -1.0f;
1130  exp_u = 0.375f;
1131  exp_v = 0.5625f;
1132  exp_dist = 7.9375f;
1133  got_u = got_v = got_dist = 0.0f;
1134  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1135  ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1136  ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1137  ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1138  ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1139 
1140 
1141 /*Only positive ray is taken in account*/
1142 
1143  vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1144  vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1145  vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1146 
1147  position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
1148 
1149  ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1150 
1151  exp_res = FALSE;
1152 
1153  got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1154  ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1155 
1156  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1157  ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1158 
1159 /*Intersection between ray and triangle in a same plane is considered as empty*/
1160 
1161  vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1162  vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1163  vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
1164 
1165  position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
1166 
1167  ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
1168 
1169  exp_res = FALSE;
1170 
1171  got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1172  ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1173 
1174  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1175  ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1176 }
1177 
1178 static void D3DXCreateMeshTest(void)
1179 {
1180  HRESULT hr;
1181  IDirect3DDevice9 *device, *test_device;
1182  ID3DXMesh *d3dxmesh;
1183  int i, size;
1185  DWORD options;
1186  struct mesh mesh;
1187  struct test_context *test_context;
1188 
1189  static const D3DVERTEXELEMENT9 decl1[] =
1190  {
1193  D3DDECL_END(),
1194  };
1195 
1196  static const D3DVERTEXELEMENT9 decl2[] =
1197  {
1203  /* 8 bytes padding */
1205  D3DDECL_END(),
1206  };
1207 
1208  static const D3DVERTEXELEMENT9 decl3[] =
1209  {
1212  D3DDECL_END(),
1213  };
1214 
1215  hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1216  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1217 
1218  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1219  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1220 
1222  if (!test_context)
1223  {
1224  skip("Couldn't create test context\n");
1225  return;
1226  }
1228 
1229  hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1230  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1231 
1232  hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1233  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1234 
1235  hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
1236  ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1237 
1238  if (hr == D3D_OK)
1239  {
1240  d3dxmesh->lpVtbl->Release(d3dxmesh);
1241  }
1242 
1243  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1244  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1245 
1246  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
1247  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1248 
1249  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1250  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1251 
1252  if (hr == D3D_OK)
1253  {
1254  /* device */
1255  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1256  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1257 
1258  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1259  ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1260  ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1261 
1262  if (hr == D3D_OK)
1263  {
1265  }
1266 
1267  /* declaration */
1268  hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1269  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1270 
1271  hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1272  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1273 
1274  if (hr == D3D_OK)
1275  {
1276  size = ARRAY_SIZE(decl1);
1277  for (i = 0; i < size - 1; i++)
1278  {
1279  ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1280  ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1281  ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1282  ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1283  ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1284  ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1285  }
1286  ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1287  }
1288 
1289  /* options */
1290  options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1291  ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1292 
1293  /* rest */
1294  if (!new_mesh(&mesh, 3, 1))
1295  {
1296  skip("Couldn't create mesh\n");
1297  }
1298  else
1299  {
1301  memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1303 
1304  compare_mesh("createmesh1", d3dxmesh, &mesh);
1305 
1306  free_mesh(&mesh);
1307  }
1308 
1309  d3dxmesh->lpVtbl->Release(d3dxmesh);
1310  }
1311 
1312  /* Test a declaration that can't be converted to an FVF. */
1313  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1314  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1315 
1316  if (hr == D3D_OK)
1317  {
1318  /* device */
1319  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1320  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1321 
1322  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1323  ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1324  ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1325 
1326  if (hr == D3D_OK)
1327  {
1329  }
1330 
1331  /* declaration */
1332  hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1333  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1334 
1335  if (hr == D3D_OK)
1336  {
1337  size = ARRAY_SIZE(decl2);
1338  for (i = 0; i < size - 1; i++)
1339  {
1340  ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1341  ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1342  ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1343  ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1344  ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1345  ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1346  }
1347  ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1348  }
1349 
1350  /* options */
1351  options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1352  ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1353 
1354  /* rest */
1355  if (!new_mesh(&mesh, 3, 1))
1356  {
1357  skip("Couldn't create mesh\n");
1358  }
1359  else
1360  {
1362  memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1363  mesh.fvf = 0;
1364  mesh.vertex_size = 60;
1365 
1366  compare_mesh("createmesh2", d3dxmesh, &mesh);
1367 
1368  free_mesh(&mesh);
1369  }
1370 
1371  mesh.vertex_size = d3dxmesh->lpVtbl->GetNumBytesPerVertex(d3dxmesh);
1372  ok(mesh.vertex_size == 60, "Got vertex size %u, expected %u\n", mesh.vertex_size, 60);
1373 
1374  d3dxmesh->lpVtbl->Release(d3dxmesh);
1375  }
1376 
1377  /* Test a declaration with multiple streams. */
1378  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
1379  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1380 
1382 }
1383 
1384 static void D3DXCreateMeshFVFTest(void)
1385 {
1386  HRESULT hr;
1387  IDirect3DDevice9 *device, *test_device;
1388  ID3DXMesh *d3dxmesh;
1389  int i, size;
1391  DWORD options;
1392  struct mesh mesh;
1393  struct test_context *test_context;
1394 
1395  static const D3DVERTEXELEMENT9 decl[] =
1396  {
1399  D3DDECL_END(),
1400  };
1401 
1402  hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1403  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1404 
1406  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1407 
1409  if (!test_context)
1410  {
1411  skip("Couldn't create test context\n");
1412  return;
1413  }
1415 
1417  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1418 
1420  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1421 
1422  hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1423  ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1424 
1425  if (hr == D3D_OK)
1426  {
1427  d3dxmesh->lpVtbl->Release(d3dxmesh);
1428  }
1429 
1430  hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1431  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1432 
1434  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1435 
1437  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1438 
1439  if (hr == D3D_OK)
1440  {
1441  /* device */
1442  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1443  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1444 
1445  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1446  ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1447  ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1448 
1449  if (hr == D3D_OK)
1450  {
1452  }
1453 
1454  /* declaration */
1455  hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1456  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1457 
1458  hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1459  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1460 
1461  if (hr == D3D_OK)
1462  {
1463  size = ARRAY_SIZE(decl);
1464  for (i = 0; i < size - 1; i++)
1465  {
1466  ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1467  ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1468  ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1469  ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1470  ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1471  test_decl[i].UsageIndex, decl[i].UsageIndex);
1472  ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1473  }
1474  ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1475  }
1476 
1477  /* options */
1478  options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1479  ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1480 
1481  /* rest */
1482  if (!new_mesh(&mesh, 3, 1))
1483  {
1484  skip("Couldn't create mesh\n");
1485  }
1486  else
1487  {
1489  memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1491 
1492  compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1493 
1494  free_mesh(&mesh);
1495  }
1496 
1497  d3dxmesh->lpVtbl->Release(d3dxmesh);
1498  }
1499 
1501 }
1502 
1503 #define check_vertex_buffer(mesh, vertices, num_vertices, fvf) \
1504  check_vertex_buffer_(__LINE__, mesh, vertices, num_vertices, fvf)
1505 static void check_vertex_buffer_(int line, ID3DXMesh *mesh, const void *vertices, DWORD num_vertices, DWORD fvf)
1506 {
1507  DWORD mesh_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
1508  DWORD mesh_fvf = mesh->lpVtbl->GetFVF(mesh);
1509  const void *mesh_vertices;
1510  HRESULT hr;
1511 
1512  ok_(__FILE__,line)(fvf == mesh_fvf, "expected FVF %x, got %x\n", fvf, mesh_fvf);
1513  ok_(__FILE__,line)(num_vertices == mesh_num_vertices,
1514  "Expected %u vertices, got %u\n", num_vertices, mesh_num_vertices);
1515 
1516  hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
1517  ok_(__FILE__,line)(hr == D3D_OK, "LockVertexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1518  if (FAILED(hr))
1519  return;
1520 
1521  if (mesh_fvf == fvf) {
1522  DWORD vertex_size = D3DXGetFVFVertexSize(fvf), i;
1523 
1524  for (i = 0; i < min(num_vertices, mesh_num_vertices); i++)
1525  {
1526  const FLOAT *exp_float = vertices;
1527  const FLOAT *got_float = mesh_vertices;
1528  DWORD texcount;
1529  DWORD pos_dim = 0;
1530  int j;
1531  BOOL last_beta_dword = FALSE;
1532  char prefix[128];
1533 
1534  switch (fvf & D3DFVF_POSITION_MASK) {
1535  case D3DFVF_XYZ: pos_dim = 3; break;
1536  case D3DFVF_XYZRHW: pos_dim = 4; break;
1537  case D3DFVF_XYZB1:
1538  case D3DFVF_XYZB2:
1539  case D3DFVF_XYZB3:
1540  case D3DFVF_XYZB4:
1541  case D3DFVF_XYZB5:
1542  pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
1544  {
1545  pos_dim--;
1546  last_beta_dword = TRUE;
1547  }
1548  break;
1549  case D3DFVF_XYZW: pos_dim = 4; break;
1550  }
1551  sprintf(prefix, "vertex[%u] position, ", i);
1552  check_floats_(line, prefix, got_float, exp_float, pos_dim);
1553  exp_float += pos_dim;
1554  got_float += pos_dim;
1555 
1556  if (last_beta_dword) {
1557  ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1558  "Vertex[%u]: Expected last beta %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1559  exp_float++;
1560  got_float++;
1561  }
1562 
1563  if (fvf & D3DFVF_NORMAL) {
1564  sprintf(prefix, "vertex[%u] normal, ", i);
1565  check_floats_(line, prefix, got_float, exp_float, 3);
1566  exp_float += 3;
1567  got_float += 3;
1568  }
1569  if (fvf & D3DFVF_PSIZE) {
1570  ok_(__FILE__,line)(compare(*exp_float, *got_float),
1571  "Vertex[%u]: Expected psize %g, got %g\n", i, *exp_float, *got_float);
1572  exp_float++;
1573  got_float++;
1574  }
1575  if (fvf & D3DFVF_DIFFUSE) {
1576  ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1577  "Vertex[%u]: Expected diffuse %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1578  exp_float++;
1579  got_float++;
1580  }
1581  if (fvf & D3DFVF_SPECULAR) {
1582  ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1583  "Vertex[%u]: Expected specular %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1584  exp_float++;
1585  got_float++;
1586  }
1587 
1588  texcount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
1589  for (j = 0; j < texcount; j++) {
1590  DWORD dim = (((fvf >> (16 + 2 * j)) + 1) & 0x03) + 1;
1591  sprintf(prefix, "vertex[%u] texture, ", i);
1592  check_floats_(line, prefix, got_float, exp_float, dim);
1593  exp_float += dim;
1594  got_float += dim;
1595  }
1596 
1597  vertices = (BYTE*)vertices + vertex_size;
1598  mesh_vertices = (BYTE*)mesh_vertices + vertex_size;
1599  }
1600  }
1601 
1602  mesh->lpVtbl->UnlockVertexBuffer(mesh);
1603 }
1604 
1605 #define check_index_buffer(mesh, indices, num_indices, index_size) \
1606  check_index_buffer_(__LINE__, mesh, indices, num_indices, index_size)
1607 static void check_index_buffer_(int line, ID3DXMesh *mesh, const void *indices, DWORD num_indices, DWORD index_size)
1608 {
1609  DWORD mesh_index_size = (mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT) ? 4 : 2;
1610  DWORD mesh_num_indices = mesh->lpVtbl->GetNumFaces(mesh) * 3;
1611  const void *mesh_indices;
1612  HRESULT hr;
1613  DWORD i;
1614 
1615  ok_(__FILE__,line)(index_size == mesh_index_size,
1616  "Expected index size %u, got %u\n", index_size, mesh_index_size);
1617  ok_(__FILE__,line)(num_indices == mesh_num_indices,
1618  "Expected %u indices, got %u\n", num_indices, mesh_num_indices);
1619 
1620  hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
1621  ok_(__FILE__,line)(hr == D3D_OK, "LockIndexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1622  if (FAILED(hr))
1623  return;
1624 
1625  if (mesh_index_size == index_size) {
1626  for (i = 0; i < min(num_indices, mesh_num_indices); i++)
1627  {
1628  if (index_size == 4)
1629  ok_(__FILE__,line)(*(DWORD*)indices == *(DWORD*)mesh_indices,
1630  "Index[%u]: expected %u, got %u\n", i, *(DWORD*)indices, *(DWORD*)mesh_indices);
1631  else
1632  ok_(__FILE__,line)(*(WORD*)indices == *(WORD*)mesh_indices,
1633  "Index[%u]: expected %u, got %u\n", i, *(WORD*)indices, *(WORD*)mesh_indices);
1634  indices = (BYTE*)indices + index_size;
1635  mesh_indices = (BYTE*)mesh_indices + index_size;
1636  }
1637  }
1638  mesh->lpVtbl->UnlockIndexBuffer(mesh);
1639 }
1640 
1641 #define check_matrix(got, expected) check_matrix_(__LINE__, got, expected)
1642 static void check_matrix_(int line, const D3DXMATRIX *got, const D3DXMATRIX *expected)
1643 {
1644  int i, j;
1645  for (i = 0; i < 4; i++) {
1646  for (j = 0; j < 4; j++) {
1647  ok_(__FILE__,line)(compare(U(*expected).m[i][j], U(*got).m[i][j]),
1648  "matrix[%u][%u]: expected %g, got %g\n",
1649  i, j, U(*expected).m[i][j], U(*got).m[i][j]);
1650  }
1651  }
1652 }
1653 
1654 static void check_colorvalue_(int line, const char *prefix, const D3DCOLORVALUE got, const D3DCOLORVALUE expected)
1655 {
1656  ok_(__FILE__,line)(expected.r == got.r && expected.g == got.g && expected.b == got.b && expected.a == got.a,
1657  "%sExpected (%g, %g, %g, %g), got (%g, %g, %g, %g)\n", prefix,
1658  expected.r, expected.g, expected.b, expected.a, got.r, got.g, got.b, got.a);
1659 }
1660 
1661 #define check_materials(got, got_count, expected, expected_count) \
1662  check_materials_(__LINE__, got, got_count, expected, expected_count)
1663 static void check_materials_(int line, const D3DXMATERIAL *got, DWORD got_count, const D3DXMATERIAL *expected, DWORD expected_count)
1664 {
1665  int i;
1666  ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
1667  if (!expected) {
1668  ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
1669  return;
1670  }
1671  for (i = 0; i < min(expected_count, got_count); i++)
1672  {
1673  if (!expected[i].pTextureFilename)
1674  ok_(__FILE__,line)(got[i].pTextureFilename == NULL,
1675  "Expected NULL pTextureFilename, got %p\n", got[i].pTextureFilename);
1676  else
1677  ok_(__FILE__,line)(!strcmp(expected[i].pTextureFilename, got[i].pTextureFilename),
1678  "Expected '%s' for pTextureFilename, got '%s'\n", expected[i].pTextureFilename, got[i].pTextureFilename);
1679  check_colorvalue_(line, "Diffuse: ", got[i].MatD3D.Diffuse, expected[i].MatD3D.Diffuse);
1680  check_colorvalue_(line, "Ambient: ", got[i].MatD3D.Ambient, expected[i].MatD3D.Ambient);
1681  check_colorvalue_(line, "Specular: ", got[i].MatD3D.Specular, expected[i].MatD3D.Specular);
1682  check_colorvalue_(line, "Emissive: ", got[i].MatD3D.Emissive, expected[i].MatD3D.Emissive);
1683  ok_(__FILE__,line)(expected[i].MatD3D.Power == got[i].MatD3D.Power,
1684  "Power: Expected %g, got %g\n", expected[i].MatD3D.Power, got[i].MatD3D.Power);
1685  }
1686 }
1687 
1688 #define check_generated_adjacency(mesh, got, epsilon) check_generated_adjacency_(__LINE__, mesh, got, epsilon)
1689 static void check_generated_adjacency_(int line, ID3DXMesh *mesh, const DWORD *got, FLOAT epsilon)
1690 {
1691  DWORD *expected;
1692  DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
1693  HRESULT hr;
1694 
1695  expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
1696  if (!expected) {
1697  skip_(__FILE__, line)("Out of memory\n");
1698  return;
1699  }
1700  hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
1701  ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1702  if (SUCCEEDED(hr))
1703  {
1704  int i;
1705  for (i = 0; i < num_faces; i++)
1706  {
1707  ok_(__FILE__, line)(expected[i * 3] == got[i * 3] &&
1708  expected[i * 3 + 1] == got[i * 3 + 1] &&
1709  expected[i * 3 + 2] == got[i * 3 + 2],
1710  "Face %u adjacencies: Expected (%u, %u, %u), got (%u, %u, %u)\n", i,
1711  expected[i * 3], expected[i * 3 + 1], expected[i * 3 + 2],
1712  got[i * 3], got[i * 3 + 1], got[i * 3 + 2]);
1713  }
1714  }
1716 }
1717 
1718 #define check_generated_effects(materials, num_materials, effects) \
1719  check_generated_effects_(__LINE__, materials, num_materials, effects)
1720 static void check_generated_effects_(int line, const D3DXMATERIAL *materials, DWORD num_materials, const D3DXEFFECTINSTANCE *effects)
1721 {
1722  int i;
1723  static const struct {
1724  const char *name;
1725  DWORD name_size;
1726  DWORD num_bytes;
1727  DWORD value_offset;
1728  } params[] = {
1729 #define EFFECT_TABLE_ENTRY(str, field) \
1730  {str, sizeof(str), sizeof(materials->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
1731  EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
1732  EFFECT_TABLE_ENTRY("Power", Power),
1733  EFFECT_TABLE_ENTRY("Specular", Specular),
1734  EFFECT_TABLE_ENTRY("Emissive", Emissive),
1735  EFFECT_TABLE_ENTRY("Ambient", Ambient),
1736 #undef EFFECT_TABLE_ENTRY
1737  };
1738 
1739  if (!num_materials) {
1740  ok_(__FILE__, line)(effects == NULL, "Expected NULL effects, got %p\n", effects);
1741  return;
1742  }
1743  for (i = 0; i < num_materials; i++)
1744  {
1745  int j;
1746  DWORD expected_num_defaults = ARRAY_SIZE(params) + (materials[i].pTextureFilename ? 1 : 0);
1747 
1748  ok_(__FILE__,line)(expected_num_defaults == effects[i].NumDefaults,
1749  "effect[%u] NumDefaults: Expected %u, got %u\n", i,
1750  expected_num_defaults, effects[i].NumDefaults);
1751  for (j = 0; j < min(ARRAY_SIZE(params), effects[i].NumDefaults); j++)
1752  {
1753  int k;
1754  D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1755  ok_(__FILE__,line)(!strcmp(params[j].name, got_param->pParamName),
1756  "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1757  params[j].name, got_param->pParamName);
1758  ok_(__FILE__,line)(D3DXEDT_FLOATS == got_param->Type,
1759  "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1760  D3DXEDT_FLOATS, got_param->Type);
1761  ok_(__FILE__,line)(params[j].num_bytes == got_param->NumBytes,
1762  "effect[%u].pDefaults[%u].NumBytes: Expected %u, got %u\n", i, j,
1763  params[j].num_bytes, got_param->NumBytes);
1764  for (k = 0; k < min(params[j].num_bytes, got_param->NumBytes) / 4; k++)
1765  {
1766  FLOAT expected = ((FLOAT*)((BYTE*)&materials[i] + params[j].value_offset))[k];
1767  FLOAT got = ((FLOAT*)got_param->pValue)[k];
1768  ok_(__FILE__,line)(compare(expected, got),
1769  "effect[%u].pDefaults[%u] float value %u: Expected %g, got %g\n", i, j, k, expected, got);
1770  }
1771  }
1772  if (effects[i].NumDefaults > ARRAY_SIZE(params)) {
1773  D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1774  static const char *expected_name = "Texture0@Name";
1775 
1776  ok_(__FILE__,line)(!strcmp(expected_name, got_param->pParamName),
1777  "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1778  expected_name, got_param->pParamName);
1779  ok_(__FILE__,line)(D3DXEDT_STRING == got_param->Type,
1780  "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1781  D3DXEDT_STRING, got_param->Type);
1782  if (materials[i].pTextureFilename) {
1783  ok_(__FILE__,line)(strlen(materials[i].pTextureFilename) + 1 == got_param->NumBytes,
1784  "effect[%u] texture filename length: Expected %u, got %u\n", i,
1785  (DWORD)strlen(materials[i].pTextureFilename) + 1, got_param->NumBytes);
1786  ok_(__FILE__,line)(!strcmp(materials[i].pTextureFilename, got_param->pValue),
1787  "effect[%u] texture filename: Expected '%s', got '%s'\n", i,
1788  materials[i].pTextureFilename, (char*)got_param->pValue);
1789  }
1790  }
1791  }
1792 }
1793 
1794 static char *strdupA(const char *p)
1795 {
1796  char *ret;
1797  if (!p) return NULL;
1798  ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
1799  if (ret) strcpy(ret, p);
1800  return ret;
1801 }
1802 
1803 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
1804 {
1805  TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
1806  if (frame) {
1807  HeapFree(GetProcessHeap(), 0, frame->Name);
1808  HeapFree(GetProcessHeap(), 0, frame);
1809  }
1810  return D3D_OK;
1811 }
1812 
1813 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface,
1814  const char *name, D3DXFRAME **new_frame)
1815 {
1816  D3DXFRAME *frame;
1817 
1818  TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
1819  frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
1820  if (!frame)
1821  return E_OUTOFMEMORY;
1822  if (name) {
1823  frame->Name = strdupA(name);
1824  if (!frame->Name) {
1825  HeapFree(GetProcessHeap(), 0, frame);
1826  return E_OUTOFMEMORY;
1827  }
1828  }
1829  *new_frame = frame;
1830  return D3D_OK;
1831 }
1832 
1834 {
1835  int i;
1836 
1837  if (!mesh_container)
1838  return D3D_OK;
1839  HeapFree(GetProcessHeap(), 0, mesh_container->Name);
1840  if (U(mesh_container->MeshData).pMesh)
1841  IUnknown_Release(U(mesh_container->MeshData).pMesh);
1842  if (mesh_container->pMaterials) {
1843  for (i = 0; i < mesh_container->NumMaterials; i++)
1844  HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials[i].pTextureFilename);
1845  HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials);
1846  }
1847  if (mesh_container->pEffects) {
1848  for (i = 0; i < mesh_container->NumMaterials; i++) {
1849  HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pEffectFilename);
1850  if (mesh_container->pEffects[i].pDefaults) {
1851  int j;
1852  for (j = 0; j < mesh_container->pEffects[i].NumDefaults; j++) {
1853  HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pParamName);
1854  HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pValue);
1855  }
1856  HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults);
1857  }
1858  }
1859  HeapFree(GetProcessHeap(), 0, mesh_container->pEffects);
1860  }
1861  HeapFree(GetProcessHeap(), 0, mesh_container->pAdjacency);
1862  if (mesh_container->pSkinInfo)
1863  IUnknown_Release(mesh_container->pSkinInfo);
1865  return D3D_OK;
1866 }
1867 
1869 {
1870  TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyMeshContainer(%p, %p)\n", iface, mesh_container);
1872 }
1873 
1875  const char *name, const D3DXMESHDATA *mesh_data, const D3DXMATERIAL *materials,
1876  const D3DXEFFECTINSTANCE *effects, DWORD num_materials, const DWORD *adjacency,
1877  ID3DXSkinInfo *skin_info, D3DXMESHCONTAINER **new_mesh_container)
1878 {
1880  int i;
1881 
1882  TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateMeshContainer(%p, '%s', %u, %p, %p, %p, %d, %p, %p, %p)\n",
1883  iface, name, mesh_data->Type, U(*mesh_data).pMesh, materials, effects,
1884  num_materials, adjacency, skin_info, *new_mesh_container);
1885 
1887  if (!mesh_container)
1888  return E_OUTOFMEMORY;
1889 
1890  if (name) {
1891  mesh_container->Name = strdupA(name);
1892  if (!mesh_container->Name)
1893  goto error;
1894  }
1895 
1896  mesh_container->NumMaterials = num_materials;
1897  if (num_materials) {
1898  mesh_container->pMaterials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*materials));
1899  if (!mesh_container->pMaterials)
1900  goto error;
1901 
1902  memcpy(mesh_container->pMaterials, materials, num_materials * sizeof(*materials));
1903  for (i = 0; i < num_materials; i++)
1904  mesh_container->pMaterials[i].pTextureFilename = NULL;
1905  for (i = 0; i < num_materials; i++) {
1906  if (materials[i].pTextureFilename) {
1907  mesh_container->pMaterials[i].pTextureFilename = strdupA(materials[i].pTextureFilename);
1908  if (!mesh_container->pMaterials[i].pTextureFilename)
1909  goto error;
1910  }
1911  }
1912 
1913  mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
1914  if (!mesh_container->pEffects)
1915  goto error;
1916  for (i = 0; i < num_materials; i++) {
1917  int j;
1918  const D3DXEFFECTINSTANCE *effect_src = &effects[i];
1919  D3DXEFFECTINSTANCE *effect_dest = &mesh_container->pEffects[i];
1920 
1921  if (effect_src->pEffectFilename) {
1922  effect_dest->pEffectFilename = strdupA(effect_src->pEffectFilename);
1923  if (!effect_dest->pEffectFilename)
1924  goto error;
1925  }
1927  effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
1928  if (!effect_dest->pDefaults)
1929  goto error;
1930  effect_dest->NumDefaults = effect_src->NumDefaults;
1931  for (j = 0; j < effect_src->NumDefaults; j++) {
1932  const D3DXEFFECTDEFAULT *default_src = &effect_src->pDefaults[j];
1933  D3DXEFFECTDEFAULT *default_dest = &effect_dest->pDefaults[j];
1934 
1935  if (default_src->pParamName) {
1936  default_dest->pParamName = strdupA(default_src->pParamName);
1937  if (!default_dest->pParamName)
1938  goto error;
1939  }
1940  default_dest->NumBytes = default_src->NumBytes;
1941  default_dest->Type = default_src->Type;
1942  default_dest->pValue = HeapAlloc(GetProcessHeap(), 0, default_src->NumBytes);
1943  memcpy(default_dest->pValue, default_src->pValue, default_src->NumBytes);
1944  }
1945  }
1946  }
1947 
1948  ok(adjacency != NULL, "Expected non-NULL adjacency, got NULL\n");
1949  if (adjacency) {
1950  if (mesh_data->Type == D3DXMESHTYPE_MESH || mesh_data->Type == D3DXMESHTYPE_PMESH) {
1951  ID3DXBaseMesh *basemesh = (ID3DXBaseMesh*)U(*mesh_data).pMesh;
1952  DWORD num_faces = basemesh->lpVtbl->GetNumFaces(basemesh);
1953  size_t size = num_faces * sizeof(DWORD) * 3;
1954  mesh_container->pAdjacency = HeapAlloc(GetProcessHeap(), 0, size);
1955  if (!mesh_container->pAdjacency)
1956  goto error;
1957  memcpy(mesh_container->pAdjacency, adjacency, size);
1958  } else {
1959  ok(mesh_data->Type == D3DXMESHTYPE_PATCHMESH, "Unknown mesh type %u\n", mesh_data->Type);
1960  if (mesh_data->Type == D3DXMESHTYPE_PATCHMESH)
1961  trace("FIXME: copying adjacency data for patch mesh not implemented\n");
1962  }
1963  }
1964 
1965  memcpy(&mesh_container->MeshData, mesh_data, sizeof(*mesh_data));
1966  if (U(*mesh_data).pMesh)
1967  IUnknown_AddRef(U(*mesh_data).pMesh);
1968  if (skin_info) {
1969  mesh_container->pSkinInfo = skin_info;
1970  skin_info->lpVtbl->AddRef(skin_info);
1971  }
1972  *new_mesh_container = mesh_container;
1973 
1974  return S_OK;
1975 error:
1977  return E_OUTOFMEMORY;
1978 }
1979 
1980 static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
1985 };
1986 static ID3DXAllocateHierarchy alloc_hier = { &ID3DXAllocateHierarchyImpl_Vtbl };
1987 
1988 #define test_LoadMeshFromX(device, xfile_str, vertex_array, fvf, index_array, materials_array, check_adjacency) \
1989  test_LoadMeshFromX_(__LINE__, device, xfile_str, sizeof(xfile_str) - 1, vertex_array, ARRAY_SIZE(vertex_array), fvf, \
1990  index_array, ARRAY_SIZE(index_array), sizeof(*index_array), materials_array, ARRAY_SIZE(materials_array), \
1991  check_adjacency);
1992 static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char *xfile_str, size_t xfile_strlen,
1993  const void *vertices, DWORD num_vertices, DWORD fvf, const void *indices, DWORD num_indices, size_t index_size,
1994  const D3DXMATERIAL *expected_materials, DWORD expected_num_materials, BOOL check_adjacency)
1995 {
1996  HRESULT hr;
1997  ID3DXBuffer *materials = NULL;
1998  ID3DXBuffer *effects = NULL;
1999  ID3DXBuffer *adjacency = NULL;
2000  ID3DXMesh *mesh = NULL;
2001  DWORD num_materials = 0;
2002 
2003  /* Adjacency is not checked when the X file contains multiple meshes,
2004  * since calling GenerateAdjacency on the merged mesh is not equivalent
2005  * to calling GenerateAdjacency on the individual meshes and then merging
2006  * the adjacency data. */
2007  hr = D3DXLoadMeshFromXInMemory(xfile_str, xfile_strlen, D3DXMESH_MANAGED, device,
2008  check_adjacency ? &adjacency : NULL, &materials, &effects, &num_materials, &mesh);
2009  ok_(__FILE__,line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2010  if (SUCCEEDED(hr)) {
2011  D3DXMATERIAL *materials_ptr = materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL;
2012  D3DXEFFECTINSTANCE *effects_ptr = effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL;
2013  DWORD *adjacency_ptr = check_adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL;
2014 
2015  check_vertex_buffer_(line, mesh, vertices, num_vertices, fvf);
2016  check_index_buffer_(line, mesh, indices, num_indices, index_size);
2017  check_materials_(line, materials_ptr, num_materials, expected_materials, expected_num_materials);
2018  check_generated_effects_(line, materials_ptr, num_materials, effects_ptr);
2019  if (check_adjacency)
2020  check_generated_adjacency_(line, mesh, adjacency_ptr, 0.0f);
2021 
2022  if (materials) ID3DXBuffer_Release(materials);
2023  if (effects) ID3DXBuffer_Release(effects);
2024  if (adjacency) ID3DXBuffer_Release(adjacency);
2025  IUnknown_Release(mesh);
2026  }
2027 }
2028 
2029 static void D3DXLoadMeshTest(void)
2030 {
2031  static const char empty_xfile[] = "xof 0303txt 0032";
2032  /*________________________*/
2033  static const char simple_xfile[] =
2034  "xof 0303txt 0032"
2035  "Mesh {"
2036  "3;"
2037  "0.0; 0.0; 0.0;,"
2038  "0.0; 1.0; 0.0;,"
2039  "1.0; 1.0; 0.0;;"
2040  "1;"
2041  "3; 0, 1, 2;;"
2042  "}";
2043  static const WORD simple_index_buffer[] = {0, 1, 2};
2044  static const D3DXVECTOR3 simple_vertex_buffer[] = {
2045  {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}
2046  };
2047  const DWORD simple_fvf = D3DFVF_XYZ;
2048  static const char framed_xfile[] =
2049  "xof 0303txt 0032"
2050  "Frame {"
2051  "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 1.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2052  "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */
2053  "1.0, 0.0, 0.0, 0.0,"
2054  "0.0, 1.0, 0.0, 0.0,"
2055  "0.0, 0.0, 1.0, 0.0,"
2056  "0.0, 0.0, 2.0, 1.0;;"
2057  "}"
2058  "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 2.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2059  "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */
2060  "1.0, 0.0, 0.0, 0.0,"
2061  "0.0, 1.0, 0.0, 0.0,"
2062  "0.0, 0.0, 1.0, 0.0,"
2063  "0.0, 0.0, 3.0, 1.0;;"
2064  "}"
2065  "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 3.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2066  "}";
2067  static const WORD framed_index_buffer[] = { 0, 1, 2 };
2068  static const D3DXVECTOR3 framed_vertex_buffers[3][3] = {
2069  {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}},
2070  {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}},
2071  {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {3.0, 1.0, 0.0}},
2072  };
2073  static const WORD merged_index_buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
2074  /* frame transforms accumulates for D3DXLoadMeshFromX */
2075  static const D3DXVECTOR3 merged_vertex_buffer[] = {
2076  {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0},
2077  {0.0, 0.0, 2.0}, {0.0, 1.0, 2.0}, {2.0, 1.0, 2.0},
2078  {0.0, 0.0, 5.0}, {0.0, 1.0, 5.0}, {3.0, 1.0, 5.0},
2079  };
2080  const DWORD framed_fvf = D3DFVF_XYZ;
2081  /*________________________*/
2082  static const char box_xfile[] =
2083  "xof 0303txt 0032"
2084  "Mesh {"
2085  "8;" /* DWORD nVertices; */
2086  /* array Vector vertices[nVertices]; */
2087  "0.0; 0.0; 0.0;,"
2088  "0.0; 0.0; 1.0;,"
2089  "0.0; 1.0; 0.0;,"
2090  "0.0; 1.0; 1.0;,"
2091  "1.0; 0.0; 0.0;,"
2092  "1.0; 0.0; 1.0;,"
2093  "1.0; 1.0; 0.0;,"
2094  "1.0; 1.0; 1.0;;"
2095  "6;" /* DWORD nFaces; */
2096  /* array MeshFace faces[nFaces]; */
2097  "4; 0, 1, 3, 2;," /* (left side) */
2098  "4; 2, 3, 7, 6;," /* (top side) */
2099  "4; 6, 7, 5, 4;," /* (right side) */
2100  "4; 1, 0, 4, 5;," /* (bottom side) */
2101  "4; 1, 5, 7, 3;," /* (back side) */
2102  "4; 0, 2, 6, 4;;" /* (front side) */
2103  "MeshNormals {"
2104  "6;" /* DWORD nNormals; */
2105  /* array Vector normals[nNormals]; */
2106  "-1.0; 0.0; 0.0;,"
2107  "0.0; 1.0; 0.0;,"
2108  "1.0; 0.0; 0.0;,"
2109  "0.0; -1.0; 0.0;,"
2110  "0.0; 0.0; 1.0;,"
2111  "0.0; 0.0; -1.0;;"
2112  "6;" /* DWORD nFaceNormals; */
2113  /* array MeshFace faceNormals[nFaceNormals]; */
2114  "4; 0, 0, 0, 0;,"
2115  "4; 1, 1, 1, 1;,"
2116  "4; 2, 2, 2, 2;,"
2117  "4; 3, 3, 3, 3;,"
2118  "4; 4, 4, 4, 4;,"
2119  "4; 5, 5, 5, 5;;"
2120  "}"
2121  "MeshMaterialList materials {"
2122  "2;" /* DWORD nMaterials; */
2123  "6;" /* DWORD nFaceIndexes; */
2124  /* array DWORD faceIndexes[nFaceIndexes]; */
2125  "0, 0, 0, 1, 1, 1;;"
2126  "Material {"
2127  /* ColorRGBA faceColor; */
2128  "0.0; 0.0; 1.0; 1.0;;"
2129  /* FLOAT power; */
2130  "0.5;"
2131  /* ColorRGB specularColor; */
2132  "1.0; 1.0; 1.0;;"
2133  /* ColorRGB emissiveColor; */
2134  "0.0; 0.0; 0.0;;"
2135  "}"
2136  "Material {"
2137  /* ColorRGBA faceColor; */
2138  "1.0; 1.0; 1.0; 1.0;;"
2139  /* FLOAT power; */
2140  "1.0;"
2141  /* ColorRGB specularColor; */
2142  "1.0; 1.0; 1.0;;"
2143  /* ColorRGB emissiveColor; */
2144  "0.0; 0.0; 0.0;;"
2145  "TextureFilename { \"texture.jpg\"; }"
2146  "}"
2147  "}"
2148  "MeshVertexColors {"
2149  "8;" /* DWORD nVertexColors; */
2150  /* array IndexedColor vertexColors[nVertexColors]; */
2151  "0; 0.0; 0.0; 0.0; 0.0;;"
2152  "1; 0.0; 0.0; 1.0; 0.1;;"
2153  "2; 0.0; 1.0; 0.0; 0.2;;"
2154  "3; 0.0; 1.0; 1.0; 0.3;;"
2155  "4; 1.0; 0.0; 0.0; 0.4;;"
2156  "5; 1.0; 0.0; 1.0; 0.5;;"
2157  "6; 1.0; 1.0; 0.0; 0.6;;"
2158  "7; 1.0; 1.0; 1.0; 0.7;;"
2159  "}"
2160  "MeshTextureCoords {"
2161  "8;" /* DWORD nTextureCoords; */
2162  /* array Coords2d textureCoords[nTextureCoords]; */
2163  "0.0; 1.0;,"
2164  "1.0; 1.0;,"
2165  "0.0; 0.0;,"
2166  "1.0; 0.0;,"
2167  "1.0; 1.0;,"
2168  "0.0; 1.0;,"
2169  "1.0; 0.0;,"
2170  "0.0; 0.0;;"
2171  "}"
2172  "}";
2173  static const WORD box_index_buffer[] = {
2174  0, 1, 3,
2175  0, 3, 2,
2176  8, 9, 7,
2177  8, 7, 6,
2178  10, 11, 5,
2179  10, 5, 4,
2180  12, 13, 14,
2181  12, 14, 15,
2182  16, 17, 18,
2183  16, 18, 19,
2184  20, 21, 22,
2185  20, 22, 23,
2186  };
2187  static const struct {
2188  D3DXVECTOR3 position;
2190  D3DCOLOR diffuse;
2191  D3DXVECTOR2 tex_coords;
2192  } box_vertex_buffer[] = {
2193  {{0.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, 0x00000000, {0.0, 1.0}},
2194  {{0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2195  {{0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2196  {{0.0, 1.0, 1.0}, {-1.0, 0.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2197  {{1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2198  {{1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2199  {{1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2200  {{1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2201  {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2202  {{0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2203  {{1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2204  {{1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2205  {{0.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2206  {{0.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x00000000, {0.0, 1.0}},
2207  {{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2208  {{1.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2209  {{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x1a0000ff, {1.0, 1.0}},
2210  {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x80ff00ff, {0.0, 1.0}},
2211  {{1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0xb3ffffff, {0.0, 0.0}},
2212  {{0.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0x4d00ffff, {1.0, 0.0}},
2213  {{0.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x00000000, {0.0, 1.0}},
2214  {{0.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x3300ff00, {0.0, 0.0}},
2215  {{1.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x99ffff00, {1.0, 0.0}},
2216  {{1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x66ff0000, {1.0, 1.0}},
2217  };
2218  static const D3DXMATERIAL box_materials[] = {
2219  {
2220  {
2221  {0.0, 0.0, 1.0, 1.0}, /* Diffuse */
2222  {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2223  {1.0, 1.0, 1.0, 1.0}, /* Specular */
2224  {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2225  0.5, /* Power */
2226  },
2227  NULL, /* pTextureFilename */
2228  },
2229  {
2230  {
2231  {1.0, 1.0, 1.0, 1.0}, /* Diffuse */
2232  {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2233  {1.0, 1.0, 1.0, 1.0}, /* Specular */
2234  {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2235  1.0, /* Power */
2236  },
2237  (char *)"texture.jpg", /* pTextureFilename */
2238  },
2239  };
2240  static const char box_anim_xfile[] =
2241  "xof 0303txt 0032"
2242  "Mesh CubeMesh {"
2243  "8;" /* DWORD nVertices; */
2244  /* array Vector vertices[nVertices]; */
2245  "0.0; 0.0; 0.0;,"
2246  "0.0; 0.0; 1.0;,"
2247  "0.0; 1.0; 0.0;,"
2248  "0.0; 1.0; 1.0;,"
2249  "1.0; 0.0; 0.0;,"
2250  "1.0; 0.0; 1.0;,"
2251  "1.0; 1.0; 0.0;,"
2252  "1.0; 1.0; 1.0;;"
2253  "6;" /* DWORD nFaces; */
2254  /* array MeshFace faces[nFaces]; */
2255  "4; 0, 1, 3, 2;," /* left side */
2256  "4; 2, 3, 7, 6;," /* top side */
2257  "4; 6, 7, 5, 4;," /* right side */
2258  "4; 1, 0, 4, 5;," /* bottom side */
2259  "4; 1, 5, 7, 3;," /* back side */
2260  "4; 0, 2, 6, 4;;" /* front side */
2261  "MeshNormals {"
2262  "6;" /* DWORD nNormals; */
2263  /* array Vector normals[nNormals]; */
2264  "-1.0; 0.0; 0.0;,"
2265  "0.0; 1.0; 0.0;,"
2266  "1.0; 0.0; 0.0;,"
2267  "0.0; -1.0; 0.0;,"
2268  "0.0; 0.0; 1.0;,"
2269  "0.0; 0.0; -1.0;;"
2270  "6;" /* DWORD nFaceNormals; */
2271  /* array MeshFace faceNormals[nFaceNormals]; */
2272  "4; 0, 0, 0, 0;,"
2273  "4; 1, 1, 1, 1;,"
2274  "4; 2, 2, 2, 2;,"
2275  "4; 3, 3, 3, 3;,"
2276  "4; 4, 4, 4, 4;,"
2277  "4; 5, 5, 5, 5;;"
2278  "}"
2279  "MeshMaterialList materials {"
2280  "2;" /* DWORD nMaterials; */
2281  "6;" /* DWORD nFaceIndexes; */
2282  /* array DWORD faceIndexes[nFaceIndexes]; */
2283  "0, 0, 0, 1, 1, 1;;"
2284  "Material {"
2285  /* ColorRGBA faceColor; */
2286  "0.0; 0.0; 1.0; 1.0;;"
2287  /* FLOAT power; */
2288  "0.5;"
2289  /* ColorRGB specularColor; */
2290  "1.0; 1.0; 1.0;;"
2291  /* ColorRGB emissiveColor; */
2292  "0.0; 0.0; 0.0;;"
2293  "}"
2294  "Material {"
2295  /* ColorRGBA faceColor; */
2296  "1.0; 1.0; 1.0; 1.0;;"
2297  /* FLOAT power; */
2298  "1.0;"
2299  /* ColorRGB specularColor; */
2300  "1.0; 1.0; 1.0;;"
2301  /* ColorRGB emissiveColor; */
2302  "0.0; 0.0; 0.0;;"
2303  "TextureFilename { \"texture.jpg\"; }"
2304  "}"
2305  "}"
2306  "MeshVertexColors {"
2307  "8;" /* DWORD nVertexColors; */
2308  /* array IndexedColor vertexColors[nVertexColors]; */
2309  "0; 0.0; 0.0; 0.0; 0.0;;"
2310  "1; 0.0; 0.0; 1.0; 0.1;;"
2311  "2; 0.0; 1.0; 0.0; 0.2;;"
2312  "3; 0.0; 1.0; 1.0; 0.3;;"
2313  "4; 1.0; 0.0; 0.0; 0.4;;"
2314  "5; 1.0; 0.0; 1.0; 0.5;;"
2315  "6; 1.0; 1.0; 0.0; 0.6;;"
2316  "7; 1.0; 1.0; 1.0; 0.7;;"
2317  "}"
2318  "MeshTextureCoords {"
2319  "8;" /* DWORD nTextureCoords; */
2320  /* array Coords2d textureCoords[nTextureCoords]; */
2321  "0.0; 1.0;,"
2322  "1.0; 1.0;,"
2323  "0.0; 0.0;,"
2324  "1.0; 0.0;,"
2325  "1.0; 1.0;,"
2326  "0.0; 1.0;,"
2327  "1.0; 0.0;,"
2328  "0.0; 0.0;;"
2329  "}"
2330  "}"
2331  "Frame CubeFrame {"
2332  "FrameTransformMatrix {"
2333  /* Matrix4x4 frameMatrix; */
2334  "1.0, 0.0, 0.0, 0.0,"
2335  "0.0, 1.0, 0.0, 0.0,"
2336  "0.0, 0.0, 1.0, 0.0,"
2337  "0.0, 0.0, 0.0, 1.0;;"
2338  "}"
2339  "{CubeMesh}"
2340  "}"
2341  "AnimationSet AnimationSet0 {"
2342  "Animation Animation0 {"
2343  "{CubeFrame}"
2344  "AnimationKey {"
2345  "2;" /* DWORD keyType; */
2346  "9;" /* DWORD nKeys; */
2347  /* array TimedFloatKeys keys[nKeys]; */
2348  "10; 3; -100.0, 0.0, 0.0;;,"
2349  "20; 3; -75.0, 0.0, 0.0;;,"
2350  "30; 3; -50.0, 0.0, 0.0;;,"
2351  "40; 3; -25.5, 0.0, 0.0;;,"
2352  "50; 3; 0.0, 0.0, 0.0;;,"
2353  "60; 3; 25.5, 0.0, 0.0;;,"
2354  "70; 3; 50.0, 0.0, 0.0;;,"
2355  "80; 3; 75.5, 0.0, 0.0;;,"
2356  "90; 3; 100.0, 0.0, 0.0;;;"
2357  "}"
2358  "}"
2359  "}";
2360 
2362  /*________________________*/
2363  static const D3DXMATERIAL default_materials[] = {
2364  {
2365  {
2366  {0.5, 0.5, 0.5, 0.0}, /* Diffuse */
2367  {0.0, 0.0, 0.0, 0.0}, /* Ambient */
2368  {0.5, 0.5, 0.5, 0.0}, /* Specular */
2369  {0.0, 0.0, 0.0, 0.0}, /* Emissive */
2370  0.0, /* Power */
2371  },
2372  NULL, /* pTextureFilename */
2373  }
2374  };
2375  HRESULT hr;
2376  IDirect3DDevice9 *device = NULL;
2377  ID3DXMesh *mesh = NULL;
2378  D3DXFRAME *frame_hier = NULL;
2380  struct test_context *test_context;
2381  ID3DXAnimationController *controller;
2382 
2383  if (!(test_context = new_test_context()))
2384  {
2385  skip("Couldn't create test context\n");
2386  return;
2387  }
2389 
2390  hr = D3DXLoadMeshHierarchyFromXInMemory(NULL, sizeof(simple_xfile) - 1,
2391  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2392  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2393 
2394  hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, 0,
2395  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2396  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2397 
2398  hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2399  D3DXMESH_MANAGED, NULL, &alloc_hier, NULL, &frame_hier, NULL);
2400  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2401 
2402  hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2403  D3DXMESH_MANAGED, device, NULL, NULL, &frame_hier, NULL);
2404  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2405 
2406  hr = D3DXLoadMeshHierarchyFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1,
2407  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2408  ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2409 
2410  hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2412  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2413 
2414  hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2415  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2416  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2417  if (SUCCEEDED(hr)) {
2419 
2420  ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2421  D3DXMatrixIdentity(&transform);
2423 
2424  ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2425  ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2426  D3DXMESHTYPE_MESH, container->MeshData.Type);
2427  mesh = U(container->MeshData).pMesh;
2428  check_vertex_buffer(mesh, simple_vertex_buffer, ARRAY_SIZE(simple_vertex_buffer), simple_fvf);
2429  check_index_buffer(mesh, simple_index_buffer, ARRAY_SIZE(simple_index_buffer), sizeof(*simple_index_buffer));
2430  check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2431  check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2432  check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2433  hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2434  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2435  frame_hier = NULL;
2436  }
2437 
2438  controller = (ID3DXAnimationController *)0xdeadbeef;
2439  hr = D3DXLoadMeshHierarchyFromXInMemory(box_anim_xfile, sizeof(box_anim_xfile) - 1,
2440  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2441  todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2442  if (SUCCEEDED(hr))
2443  {
2444  ok(controller != NULL, "Animation Controller NULL.\n");
2445 
2446  hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2447  ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2448  if (controller)
2449  controller->lpVtbl->Release(controller);
2450 
2451  frame_hier = NULL;
2452  }
2453 
2454  controller = (ID3DXAnimationController *)0xdeadbeef;
2455  hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1,
2456  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2457  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2458  if (SUCCEEDED(hr))
2459  {
2461 
2462  ok(!controller, "Animation Controller returned.\n");
2463  ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2464  D3DXMatrixIdentity(&transform);
2466 
2467  ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2468  ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2469  D3DXMESHTYPE_MESH, container->MeshData.Type);
2470  mesh = U(container->MeshData).pMesh;
2471  check_vertex_buffer(mesh, box_vertex_buffer, ARRAY_SIZE(box_vertex_buffer), box_fvf);
2472  check_index_buffer(mesh, box_index_buffer, ARRAY_SIZE(box_index_buffer), sizeof(*box_index_buffer));
2473  check_materials(container->pMaterials, container->NumMaterials, box_materials, ARRAY_SIZE(box_materials));
2474  check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2475  check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2476  hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2477  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2478  frame_hier = NULL;
2479  }
2480 
2481  hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1,
2482  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2483  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2484  if (SUCCEEDED(hr)) {
2486  int i;
2487 
2488  ok(!strcmp(frame_hier->Name, ""), "Expected '', got '%s'\n", frame_hier->Name);
2489  /* last frame transform replaces the first */
2490  D3DXMatrixIdentity(&transform);
2491  U(transform).m[3][2] = 3.0;
2493 
2494  for (i = 0; i < 3; i++) {
2495  ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2496  ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2497  D3DXMESHTYPE_MESH, container->MeshData.Type);
2498  mesh = U(container->MeshData).pMesh;
2499  check_vertex_buffer(mesh, framed_vertex_buffers[i], ARRAY_SIZE(framed_vertex_buffers[0]), framed_fvf);
2500  check_index_buffer(mesh, framed_index_buffer, ARRAY_SIZE(framed_index_buffer), sizeof(*framed_index_buffer));
2501  check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2502  check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2503  check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2504  container = container->pNextMeshContainer;
2505  }
2506  ok(container == NULL, "Expected NULL, got %p\n", container);
2507  hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2508  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2509  frame_hier = NULL;
2510  }
2511 
2512 
2514  device, NULL, NULL, NULL, NULL, &mesh);
2515  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2516 
2517  hr = D3DXLoadMeshFromXInMemory(NULL, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2518  device, NULL, NULL, NULL, NULL, &mesh);
2519  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2520 
2521  hr = D3DXLoadMeshFromXInMemory(simple_xfile, 0, D3DXMESH_MANAGED,
2522  device, NULL, NULL, NULL, NULL, &mesh);
2523  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2524 
2525  hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2526  device, NULL, NULL, NULL, NULL, NULL);
2527  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2528 
2529  hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2530  NULL, NULL, NULL, NULL, NULL, &mesh);
2531  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2532 
2533  hr = D3DXLoadMeshFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1, D3DXMESH_MANAGED,
2534  device, NULL, NULL, NULL, NULL, &mesh);
2535  ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2536 
2537  hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2538  device, NULL, NULL, NULL, NULL, &mesh);
2539  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2540  if (SUCCEEDED(hr))
2541  IUnknown_Release(mesh);
2542 
2543  test_LoadMeshFromX(device, simple_xfile, simple_vertex_buffer, simple_fvf, simple_index_buffer, default_materials, TRUE);
2544  test_LoadMeshFromX(device, box_xfile, box_vertex_buffer, box_fvf, box_index_buffer, box_materials, TRUE);
2545  test_LoadMeshFromX(device, framed_xfile, merged_vertex_buffer, framed_fvf, merged_index_buffer, default_materials, FALSE);
2546 
2548 }
2549 
2550 static ID3DXFileData *get_mesh_data(const char *memory, SIZE_T length)
2551 {
2553  ID3DXFileEnumObject *enumobj = NULL;
2554  ID3DXFileData *filedata = NULL;
2555  ID3DXFileData *ret = NULL;
2556  ID3DXFile *d3dxfile = NULL;
2557  SIZE_T i, nb_children;
2558  HRESULT hr;
2559  GUID guid;
2560 
2561  hr = D3DXFileCreate(&d3dxfile);
2562  if (FAILED(hr)) return NULL;
2563 
2564  hr = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES);
2565  if (FAILED(hr)) goto cleanup;
2566 
2567  source.lpMemory = (void *)memory;
2568  source.dSize = length;
2569 
2570  hr = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &source, D3DXF_FILELOAD_FROMMEMORY, &enumobj);
2571  if (FAILED(hr)) goto cleanup;
2572 
2573  hr = enumobj->lpVtbl->GetChildren(enumobj, &nb_children);
2574  if (FAILED(hr)) goto cleanup;
2575 
2576  for (i = 0; i < nb_children; i++)
2577  {
2578  hr = enumobj->lpVtbl->GetChild(enumobj, i, &filedata);
2579  if (FAILED(hr)) goto cleanup;
2580 
2581  hr = filedata->lpVtbl->GetType(filedata, &guid);
2582  if (SUCCEEDED(hr) && IsEqualGUID(&guid, &TID_D3DRMMesh))
2583  {
2584  ret = filedata;
2585  break;
2586  }
2587  else
2588  filedata->lpVtbl->Release(filedata);
2589  }
2590 
2591 cleanup:
2592  if (enumobj) enumobj->lpVtbl->Release(enumobj);
2593  if (d3dxfile) d3dxfile->lpVtbl->Release(d3dxfile);
2594 
2595  return ret;
2596 }
2597 
2599 {
2600  static const char simple_xfile[] =
2601  "xof 0303txt 0032"
2602  "Mesh {"
2603  "3;"
2604  "0.0; 0.0; 0.0;,"
2605  "0.0; 1.0; 0.0;,"
2606  "1.0; 1.0; 0.0;;"
2607  "1;"
2608  "3; 0, 1, 2;;"
2609  "}";
2610  ID3DXBuffer *adjacency, *materials, *effects;
2611  D3DPRESENT_PARAMETERS d3dpp;
2612  IDirect3DDevice9 *device;
2613  ID3DXFileData *filedata;
2614  ID3DXSkinInfo *skininfo;
2615  ID3DXMesh *mesh;
2616  IDirect3D9 *d3d;
2617  DWORD mat_count;
2618  HRESULT hr;
2619  HWND hwnd;
2620 
2621  if (!(hwnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0,
2622  640, 480, NULL, NULL, NULL, NULL)))
2623  {
2624  skip("Couldn't create application window\n");
2625  return;
2626  }
2627 
2629  if (!d3d)
2630  {
2631  skip("Couldn't create IDirect3D9 object\n");
2633  return;
2634  }
2635 
2636  ZeroMemory(&d3dpp, sizeof(d3dpp));
2637  d3dpp.Windowed = TRUE;
2639 
2642  if (FAILED(hr))
2643  {
2644  skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2646  return;
2647  }
2648 
2649  filedata = get_mesh_data(simple_xfile, sizeof(simple_xfile) - 1);
2650  ok(filedata != NULL, "Failed to load mesh data\n");
2651 
2652  adjacency = materials = effects = NULL;
2653  skininfo = NULL;
2654  mesh = NULL;
2655 
2656  hr = D3DXLoadSkinMeshFromXof(filedata, 0, device, &adjacency, &materials, &effects, &mat_count, &skininfo, &mesh);
2657  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2658  ok(skininfo != NULL, "Expected non-null skininfo\n");
2659 
2660  /* FIXME: Add additional tests for skininfo interface. */
2661 
2662  if (adjacency) adjacency->lpVtbl->Release(adjacency);
2663  if (materials) materials->lpVtbl->Release(materials);
2664  if (effects) effects->lpVtbl->Release(effects);
2665  if (skininfo) skininfo->lpVtbl->Release(skininfo);
2666  if (mesh) mesh->lpVtbl->Release(mesh);
2667 
2668  filedata->lpVtbl->Release(filedata);
2671 }
2672 
2673 static BOOL compute_box(struct mesh *mesh, float width, float height, float depth)
2674 {
2675  unsigned int i, face;
2676  static const D3DXVECTOR3 unit_box[] =
2677  {
2678  {-1.0f, -1.0f, -1.0f}, {-1.0f, -1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, -1.0f},
2679  {-1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, -1.0f},
2680  { 1.0f, 1.0f, -1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, -1.0f, 1.0f}, { 1.0f, -1.0f, -1.0f},
2681  {-1.0f, -1.0f, 1.0f}, {-1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, 1.0f},
2682  {-1.0f, -1.0f, 1.0f}, { 1.0f, -1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f},
2683  {-1.0f, -1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, { 1.0f, 1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}
2684  };
2685  static const D3DXVECTOR3 normals[] =
2686  {
2687  {-1.0f, 0.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f},
2688  { 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, -1.0f}
2689  };
2690 
2691  if (!new_mesh(mesh, 24, 12))
2692  {
2693  return FALSE;
2694  }
2695 
2696  width /= 2.0f;
2697  height /= 2.0f;
2698  depth /= 2.0f;
2699 
2700  for (i = 0; i < 24; i++)
2701  {
2702  mesh->vertices[i].position.x = width * unit_box[i].x;
2703  mesh->vertices[i].position.y = height * unit_box[i].y;
2704  mesh->vertices[i].position.z = depth * unit_box[i].z;
2705  mesh->vertices[i].normal.x = normals[i / 4].x;
2706  mesh->vertices[i].normal.y = normals[i / 4].y;
2707  mesh->vertices[i].normal.z = normals[i / 4].z;
2708  }
2709 
2710  face = 0;
2711  for (i = 0; i < 12; i++)
2712  {
2713  mesh->faces[i][0] = face++;
2714  mesh->faces[i][1] = face++;
2715  mesh->faces[i][2] = (i % 2) ? face - 4 : face;
2716  }
2717 
2718  return TRUE;
2719 }
2720 
2721 static void test_box(IDirect3DDevice9 *device, float width, float height, float depth)
2722 {
2723  HRESULT hr;
2724  ID3DXMesh *box;
2725  struct mesh mesh;
2726  char name[256];
2727 
2729  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2730  if (hr != D3D_OK)
2731  {
2732  skip("Couldn't create box\n");
2733  return;
2734  }
2735 
2736  if (!compute_box(&mesh, width, height, depth))
2737  {
2738  skip("Couldn't create mesh\n");
2739  box->lpVtbl->Release(box);
2740  return;
2741  }
2742 
2744 
2745  sprintf(name, "box (%g, %g, %g)", width, height, depth);
2746  compare_mesh(name, box, &mesh);
2747 
2748  free_mesh(&mesh);
2749 
2750  box->lpVtbl->Release(box);
2751 }
2752 static void D3DXCreateBoxTest(void)
2753 {
2754  HRESULT hr;
2755  IDirect3DDevice9* device;
2756  ID3DXMesh* box;
2757  ID3DXBuffer* ppBuffer;
2758  DWORD *buffer;
2759  static const DWORD adjacency[36]=
2760  {6, 9, 1, 2, 10, 0,
2761  1, 9, 3, 4, 10, 2,
2762  3, 8, 5, 7, 11, 4,
2763  0, 11, 7, 5, 8, 6,
2764  7, 4, 9, 2, 0, 8,
2765  1, 3, 11, 5, 6, 10};
2766  unsigned int i;
2767  struct test_context *test_context;
2768 
2769  if (!(test_context = new_test_context()))
2770  {
2771  skip("Couldn't create test context\n");
2772  return;
2773  }
2775 
2776  hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
2777  ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2778 
2779  hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
2780  ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2781 
2782  hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
2783  ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2784 
2785  hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
2786  ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2787 
2788  hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
2789  ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2790 
2791  ppBuffer = NULL;
2792  hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
2793  ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2794 
2796  for(i=0; i<36; i++)
2797  ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
2798 
2799  box->lpVtbl->Release(box);
2800  ID3DXBuffer_Release(ppBuffer);
2801 
2802  test_box(device, 10.9f, 20.0f, 4.9f);
2803 
2805 }
2806 
2807 static BOOL compute_polygon(struct mesh *mesh, float length, unsigned int sides)
2808 {
2809  unsigned int i;
2810  float angle, scale;
2811 
2812  if (!new_mesh(mesh, sides + 1, sides))
2813  return FALSE;
2814 
2815  angle = D3DX_PI / sides;
2816  scale = 0.5f * length / sinf(angle);
2817  angle *= 2.0f;
2818 
2819  mesh->vertices[0].position.x = 0.0f;
2820  mesh->vertices[0].position.y = 0.0f;
2821  mesh->vertices[0].position.z = 0.0f;
2822  mesh->vertices[0].normal.x = 0.0f;
2823  mesh->vertices[0].normal.y = 0.0f;
2824  mesh->vertices[0].normal.z = 1.0f;
2825 
2826  for (i = 0; i < sides; ++i)
2827  {
2828  mesh->vertices[i + 1].position.x = cosf(angle * i) * scale;
2829  mesh->vertices[i + 1].position.y = sinf(angle * i) * scale;
2830  mesh->vertices[i + 1].position.z = 0.0f;
2831  mesh->vertices[i + 1].normal.x = 0.0f;
2832  mesh->vertices[i + 1].normal.y = 0.0f;
2833  mesh->vertices[i + 1].normal.z = 1.0f;
2834 
2835  mesh->faces[i][0] = 0;
2836  mesh->faces[i][1] = i + 1;
2837  mesh->faces[i][2] = i + 2;
2838  }
2839 
2840  mesh->faces[sides - 1][2] = 1;
2841 
2842  return TRUE;
2843 }
2844 
2845 static void test_polygon(IDirect3DDevice9 *device, float length, unsigned int sides)
2846 {
2847  HRESULT hr;
2848  ID3DXMesh *polygon;
2849  struct mesh mesh;
2850  char name[64];
2851 
2852  hr = D3DXCreatePolygon(device, length, sides, &polygon, NULL);
2853  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2854  if (hr != D3D_OK)
2855  {
2856  skip("Couldn't create polygon\n");
2857  return;
2858  }
2859 
2860  if (!compute_polygon(&mesh, length, sides))
2861  {
2862  skip("Couldn't create mesh\n");
2863  polygon->lpVtbl->Release(polygon);
2864  return;
2865  }
2866 
2868 
2869  sprintf(name, "polygon (%g, %u)", length, sides);
2870  compare_mesh(name, polygon, &mesh);
2871 
2872  free_mesh(&mesh);
2873 
2874  polygon->lpVtbl->Release(polygon);
2875 }
2876 
2877 static void D3DXCreatePolygonTest(void)
2878 {
2879  HRESULT hr;
2880  IDirect3DDevice9 *device;
2881  ID3DXMesh *polygon;
2882  ID3DXBuffer *adjacency;
2883  DWORD (*buffer)[3], buffer_size;
2884  unsigned int i;
2885  struct test_context *test_context;
2886 
2887  if (!(test_context = new_test_context()))
2888  {
2889  skip("Couldn't create test context\n");
2890  return;
2891  }
2893 
2894  hr = D3DXCreatePolygon(device, 2.0f, 11, NULL, &adjacency);
2895  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2896 
2897  hr = D3DXCreatePolygon(NULL, 2.0f, 11, &polygon, &adjacency);
2898  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2899 
2900  hr = D3DXCreatePolygon(device, -2.0f, 11, &polygon, &adjacency);
2901  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2902 
2903  polygon = (void *)0xdeadbeef;
2904  adjacency = (void *)0xdeadbeef;
2905  hr = D3DXCreatePolygon(device, 2.0f, 0, &polygon, &adjacency);
2906  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2907  ok(polygon == (void *)0xdeadbeef, "Polygon was changed to %p\n", polygon);
2908  ok(adjacency == (void *)0xdeadbeef, "Adjacency was changed to %p\n", adjacency);
2909 
2910  hr = D3DXCreatePolygon(device, 2.0f, 2, &polygon, &adjacency);
2911  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2912 
2913  adjacency = NULL;
2914  hr = D3DXCreatePolygon(device, 3.0f, 11, &polygon, &adjacency);
2915  ok(hr == D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2916 
2918  ok(buffer_size == 33 * sizeof(DWORD), "Wrong adjacency buffer size %u\n", buffer_size);
2919 
2920  buffer = ID3DXBuffer_GetBufferPointer(adjacency);
2921  for (i = 0; i < 11; ++i)
2922  {
2923  ok(buffer[i][0] == (i + 10) % 11, "Wrong adjacency[%d][0] = %u\n", i, buffer[i][0]);
2924  ok(buffer[i][1] == ~0U, "Wrong adjacency[%d][1] = %u\n", i, buffer[i][1]);
2925  ok(buffer[i][2] == (i + 1) % 11, "Wrong adjacency[%d][2] = %u\n", i, buffer[i][2]);
2926  }
2927 
2928  polygon->lpVtbl->Release(polygon);
2929  ID3DXBuffer_Release(adjacency);
2930 
2931  test_polygon(device, 2.0f, 3);
2932  test_polygon(device, 10.0f, 3);
2933  test_polygon(device, 10.0f, 5);
2934  test_polygon(device, 10.0f, 10);
2935  test_polygon(device, 20.0f, 10);
2936  test_polygon(device, 20.0f, 32000);
2937 
2939 }
2940 
2941 struct sincos_table
2942 {
2943  float *sin;
2944  float *cos;
2945 };
2946 
2948 {
2951 }
2952 
2953 /* pre compute sine and cosine tables; caller must free */
2954 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
2955 {
2956  float angle;
2957  int i;
2958 
2959  sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2960  if (!sincos_table->sin)
2961  {
2962  return FALSE;
2963  }
2964  sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2965  if (!sincos_table->cos)
2966  {
2968  return FALSE;
2969  }
2970 
2971  angle = angle_start;
2972  for (i = 0; i < n; i++)
2973  {
2974  sincos_table->sin[i] = sin(angle);
2975  sincos_table->cos[i] = cos(angle);
2976  angle += angle_step;
2977  }
2978 
2979  return TRUE;
2980 }
2981 
2982 static WORD vertex_index(UINT slices, int slice, int stack)
2983 {
2984  return stack*slices+slice+1;
2985 }
2986 
2987 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
2988 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
2989 {
2990  float theta_step, theta_start;
2991  struct sincos_table theta;
2992  float phi_step, phi_start;
2993  struct sincos_table phi;
2994  DWORD number_of_vertices, number_of_faces;
2995  DWORD vertex, face;
2996  int slice, stack;
2997 
2998  /* theta = angle on xy plane wrt x axis */
2999  theta_step = D3DX_PI / stacks;
3000  theta_start = theta_step;
3001 
3002  /* phi = angle on xz plane wrt z axis */
3003  phi_step = -2 * D3DX_PI / slices;
3004  phi_start = D3DX_PI / 2;
3005 
3006  if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
3007  {
3008  return FALSE;
3009  }
3010  if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
3011  {
3012  free_sincos_table(&theta);
3013  return FALSE;
3014  }
3015 
3016  number_of_vertices = 2 + slices * (stacks-1);
3017  number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
3018 
3019  if (!new_mesh(mesh, number_of_vertices, number_of_faces))
3020  {
3021  free_sincos_table(&phi);
3022  free_sincos_table(&theta);
3023  return FALSE;
3024  }
3025 
3026  vertex = 0;
3027  face = 0;
3028 
3029  mesh->vertices[vertex].normal.x = 0.0f;
3030  mesh->vertices[vertex].normal.y = 0.0f;
3031  mesh->vertices[vertex].normal.z = 1.0f;
3032  mesh->vertices[vertex].position.x = 0.0f;
3033  mesh->vertices[vertex].position.y = 0.0f;
3034  mesh->vertices[vertex].position.z = radius;
3035  vertex++;
3036 
3037  for (stack = 0; stack < stacks - 1; stack++)
3038  {
3039  for (slice = 0; slice < slices; slice++)
3040  {
3041  mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
3042  mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
3043  mesh->vertices[vertex].normal.z = theta.cos[stack];
3044  mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
3045  mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
3046  mesh->vertices[vertex].position.z = radius * theta.cos[stack];
3047  vertex++;
3048 
3049  if (slice > 0)
3050  {
3051  if (stack == 0)
3052  {
3053  /* top stack is triangle fan */
3054  mesh->faces[face][0] = 0;
3055  mesh->faces[face][1] = slice + 1;
3056  mesh->faces[face][2] = slice;
3057  face++;
3058  }
3059  else
3060  {
3061  /* stacks in between top and bottom are quad strips */
3062  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3063  mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
3064  mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
3065  face++;
3066 
3067  mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
3068  mesh->faces[face][1] = vertex_index(slices, slice, stack);
3069  mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
3070  face++;
3071  }
3072  }
3073  }
3074 
3075  if (stack == 0)
3076  {
3077  mesh->faces[face][0] = 0;
3078  mesh->faces[face][1] = 1;
3079  mesh->faces[face][2] = slice;
3080  face++;
3081  }
3082  else
3083  {
3084  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3085  mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
3086  mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
3087  face++;
3088 
3089  mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
3090  mesh->faces[face][1] = vertex_index(slices, 0, stack);
3091  mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
3092  face++;
3093  }
3094  }
3095 
3096  mesh->vertices[vertex].position.x = 0.0f;
3097  mesh->vertices[vertex].position.y = 0.0f;
3098  mesh->vertices[vertex].position.z = -radius;
3099  mesh->vertices[vertex].normal.x = 0.0f;
3100  mesh->vertices[vertex].normal.y = 0.0f;
3101  mesh->vertices[vertex].normal.z = -1.0f;
3102 
3103  /* bottom stack is triangle fan */
3104  for (slice = 1; slice < slices; slice++)
3105  {
3106  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3107  mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
3108  mesh->faces[face][2] = vertex;
3109  face++;
3110  }
3111 
3112  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3113  mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
3114  mesh->faces[face][2] = vertex;
3115 
3116  free_sincos_table(&phi);
3117  free_sincos_table(&theta);
3118 
3119  return TRUE;
3120 }
3121 
3122 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
3123 {
3124  HRESULT hr;
3125  ID3DXMesh *sphere;
3126  struct mesh mesh;
3127  char name[256];
3128 
3129  hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
3130  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3131  if (hr != D3D_OK)
3132  {
3133  skip("Couldn't create sphere\n");
3134  return;
3135  }
3136 
3137  if (!compute_sphere(&mesh, radius, slices, stacks))
3138  {
3139  skip("Couldn't create mesh\n");
3140  sphere->lpVtbl->Release(sphere);
3141  return;
3142  }
3143 
3145 
3146  sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
3147  compare_mesh(name, sphere, &mesh);
3148 
3149  free_mesh(&mesh);
3150 
3151  sphere->lpVtbl->Release(sphere);
3152 }
3153 
3154 static void D3DXCreateSphereTest(void)
3155 {
3156  HRESULT hr;
3157  IDirect3DDevice9* device;
3158  ID3DXMesh* sphere = NULL;
3159  struct test_context *test_context;
3160 
3161  hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
3162  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3163 
3164  hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
3165  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3166 
3167  hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
3168  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3169 
3170  hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
3171  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3172 
3173  if (!(test_context = new_test_context()))
3174  {
3175  skip("Couldn't create test context\n");
3176  return;
3177  }
3179 
3180  hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
3181  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3182 
3183  hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
3184  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3185 
3186  hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
3187  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3188 
3189  hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
3190  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3191 
3192  test_sphere(device, 0.0f, 2, 2);
3193  test_sphere(device, 1.0f, 2, 2);
3194  test_sphere(device, 1.0f, 3, 2);
3195  test_sphere(device, 1.0f, 4, 4);
3196  test_sphere(device, 1.0f, 3, 4);
3197  test_sphere(device, 5.0f, 6, 7);
3198  test_sphere(device, 10.0f, 11, 12);
3199 
3201 }
3202 
3203 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3204 {
3205  float theta_step, theta_start;
3206  struct sincos_table theta;
3207  FLOAT delta_radius, radius, radius_step;
3208  FLOAT z, z_step, z_normal;
3209  DWORD number_of_vertices, number_of_faces;
3210  DWORD vertex, face;
3211  int slice, stack;
3212 
3213  /* theta = angle on xy plane wrt x axis */
3214  theta_step = -2 * D3DX_PI / slices;
3215  theta_start = D3DX_PI / 2;
3216 
3217  if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
3218  {
3219  return FALSE;
3220  }
3221 
3222  number_of_vertices = 2 + (slices * (3 + stacks));
3223  number_of_faces = 2 * slices + stacks * (2 * slices);
3224 
3225  if (!new_mesh(mesh, number_of_vertices, number_of_faces))
3226  {
3227  free_sincos_table(&theta);
3228  return FALSE;
3229  }
3230 
3231  vertex = 0;
3232  face = 0;
3233 
3234  delta_radius = radius1 - radius2;
3235  radius = radius1;
3236  radius_step = delta_radius / stacks;
3237 
3238  z = -length / 2;
3239  z_step = length / stacks;
3240  z_normal = delta_radius / length;
3241  if (isnan(z_normal))
3242  {
3243  z_normal = 0.0f;
3244  }
3245 
3246  mesh->vertices[vertex].normal.x = 0.0f;
3247  mesh->vertices[vertex].normal.y = 0.0f;
3248  mesh->vertices[vertex].normal.z = -1.0f;
3249  mesh->vertices[vertex].position.x = 0.0f;
3250  mesh->vertices[vertex].position.y = 0.0f;
3251  mesh->vertices[vertex++].position.z = z;
3252 
3253  for (slice = 0; slice < slices; slice++, vertex++)
3254  {
3255  mesh->vertices[vertex].normal.x = 0.0f;
3256  mesh->vertices[vertex].normal.y = 0.0f;
3257  mesh->vertices[vertex].normal.z = -1.0f;
3258  mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3259  mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3260  mesh->vertices[vertex].position.z = z;
3261 
3262  if (slice > 0)
3263  {
3264  mesh->faces[face][0] = 0;
3265  mesh->faces[face][1] = slice;
3266  mesh->faces[face++][2] = slice + 1;
3267  }
3268  }
3269 
3270  mesh->faces[face][0] = 0;
3271  mesh->faces[face][1] = slice;
3272  mesh->faces[face++][2] = 1;
3273 
3274  for (stack = 1; stack <= stacks+1; stack++)
3275  {
3276  for (slice = 0; slice < slices; slice++, vertex++)
3277  {
3278  mesh->vertices[vertex].normal.x = theta.cos[slice];
3279  mesh->vertices[vertex].normal.y = theta.sin[slice];
3280  mesh->vertices[vertex].normal.z = z_normal;
3281  D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
3282  mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3283  mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3284  mesh->vertices[vertex].position.z = z;
3285 
3286  if (stack > 1 && slice > 0)
3287  {
3288  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3289  mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3290  mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
3291 
3292  mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
3293  mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3294  mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3295  }
3296  }
3297 
3298  if (stack > 1)
3299  {
3300  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3301  mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3302  mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
3303 
3304  mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
3305  mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3306  mesh->faces[face++][2] = vertex_index(slices, 0, stack);
3307  }
3308 
3309  if (stack < stacks + 1)
3310  {
3311  z += z_step;
3312  radius -= radius_step;
3313  }
3314  }
3315 
3316  for (slice = 0; slice < slices; slice++, vertex++)
3317  {
3318  mesh->vertices[vertex].normal.x = 0.0f;
3319  mesh->vertices[vertex].normal.y = 0.0f;
3320  mesh->vertices[vertex].normal.z = 1.0f;
3321  mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3322  mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3323  mesh->vertices[vertex].position.z = z;
3324 
3325  if (slice > 0)
3326  {
3327  mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3328  mesh->faces[face][1] = number_of_vertices - 1;
3329  mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3330  }
3331  }
3332 
3333  mesh->vertices[vertex].position.x = 0.0f;
3334  mesh->vertices[vertex].position.y = 0.0f;
3335  mesh->vertices[vertex].position.z = z;
3336  mesh->vertices[vertex].normal.x = 0.0f;
3337  mesh->vertices[vertex].normal.y = 0.0f;
3338  mesh->vertices[vertex].normal.z = 1.0f;
3339 
3340  mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3341  mesh->faces[face][1] = number_of_vertices - 1;
3342  mesh->faces[face][2] = vertex_index(slices, 0, stack);
3343 
3344  free_sincos_table(&theta);
3345 
3346  return TRUE;
3347 }
3348 
3349 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3350 {
3351  HRESULT hr;
3352  ID3DXMesh *cylinder;
3353  struct mesh mesh;
3354  char name[256];
3355 
3356  hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
3357  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3358  if (hr != D3D_OK)
3359  {
3360  skip("Couldn't create cylinder\n");
3361  return;
3362  }
3363 
3364  if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
3365  {
3366  skip("Couldn't create mesh\n");
3367  cylinder->lpVtbl->Release(cylinder);
3368  return;
3369  }
3370 
3372 
3373  sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
3375 
3376  free_mesh(&mesh);
3377 
3378  cylinder->lpVtbl->Release(cylinder);
3379 }
3380 
3381 static void D3DXCreateCylinderTest(void)
3382 {
3383  HRESULT hr;
3384  IDirect3DDevice9* device;
3385  ID3DXMesh* cylinder = NULL;
3386  struct test_context *test_context;
3387 
3388  hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
3389  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3390 
3391  hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3392  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3393 
3394  if (!(test_context = new_test_context()))
3395  {
3396  skip("Couldn't create test context\n");
3397  return;
3398  }
3400 
3401  hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3402  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3403 
3404  hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3405  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3406 
3407  if (SUCCEEDED(hr) && cylinder)
3408  {
3409  cylinder->lpVtbl->Release(cylinder);
3410  }
3411 
3412  hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
3413  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3414 
3415  hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
3416  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3417 
3418  if (SUCCEEDED(hr) && cylinder)
3419  {
3420  cylinder->lpVtbl->Release(cylinder);
3421  }
3422 
3423  hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
3424  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3425 
3426  /* Test with length == 0.0f succeeds */
3427  hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
3428  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3429 
3430  if (SUCCEEDED(hr) && cylinder)
3431  {
3432  cylinder->lpVtbl->Release(cylinder);
3433  }
3434 
3435  hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
3436  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3437 
3438  hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
3439  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3440 
3441  hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
3442  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3443 
3444  test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
3445  test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
3446  test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
3447  test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
3448  test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
3449  test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
3450 
3452 }
3453 
3454 static BOOL compute_torus(struct mesh *mesh, float innerradius, float outerradius, UINT sides, UINT rings)
3455 {
3456  float phi, phi_step, sin_phi, cos_phi;
3457  float theta, theta_step, sin_theta, cos_theta;
3458  unsigned int numvert, numfaces, i, j;
3459 
3460  numvert = sides * rings;
3461  numfaces = numvert * 2;
3462 
3463  if (!new_mesh(mesh, numvert, numfaces))
3464  return FALSE;
3465 
3466  phi_step = D3DX_PI / sides * 2.0f;
3467  theta_step = D3DX_PI / rings * -2.0f;
3468 
3469  theta = 0.0f;
3470 
3471  for (i = 0; i < rings; ++i)
3472  {
3473  phi = 0.0f;
3474 
3475  cos_theta = cosf(theta);
3476  sin_theta = sinf(theta);
3477 
3478  for (j = 0; j < sides; ++j)
3479  {
3480  sin_phi = sinf(phi);
3481  cos_phi = cosf(phi);
3482 
3483  mesh->vertices[i * sides + j].position.x = (innerradius * cos_phi + outerradius) * cos_theta;
3484  mesh->vertices[i * sides + j].position.y = (innerradius * cos_phi + outerradius) * sin_theta;
3485  mesh->vertices[i * sides + j].position.z = innerradius * sin_phi;
3486  mesh->vertices[i * sides + j].normal.x = cos_phi * cos_theta;
3487  mesh->vertices[i * sides + j].normal.y = cos_phi * sin_theta;
3488  mesh->vertices[i * sides + j].normal.z = sin_phi;
3489 
3490  phi += phi_step;
3491  }
3492 
3493  theta += theta_step;
3494  }
3495 
3496  for (i = 0; i < numfaces - sides * 2; ++i)
3497  {
3498  mesh->faces[i][0] = i % 2 ? i / 2 + sides : i / 2;
3499  mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3500  mesh->faces[i][2] = (i + 1) % (sides * 2) ? (i + 1) / 2 + sides : (i + 1) / 2;
3501  }
3502 
3503  for (j = 0; i < numfaces; ++i, ++j)
3504  {
3505  mesh->faces[i][0] = i % 2 ? j / 2 : i / 2;
3506  mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3507  mesh->faces[i][2] = i == numfaces - 1 ? 0 : (j + 1) / 2;
3508  }
3509 
3510  return TRUE;
3511 }
3512 
3513 static void test_torus(IDirect3DDevice9 *device, float innerradius, float outerradius, UINT sides, UINT rings)
3514 {
3515  HRESULT hr;
3516  ID3DXMesh *torus;
3517  struct mesh mesh;
3518  char name[256];
3519 
3520  hr = D3DXCreateTorus(device, innerradius, outerradius, sides, rings, &torus, NULL);
3521  ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK)\n", hr);
3522  if (hr != D3D_OK)
3523  {
3524  skip("Couldn't create torus\n");
3525  return;
3526  }
3527 
3528  if (!compute_torus(&mesh, innerradius, outerradius, sides, rings))
3529  {
3530  skip("Couldn't create mesh\n");
3531  torus->lpVtbl->Release(torus);
3532  return;
3533  }
3534 
3536 
3537  sprintf(name, "torus (%g, %g, %u, %u)", innerradius, outerradius, sides, rings);
3538  compare_mesh(name, torus, &mesh);
3539 
3540  free_mesh(&mesh);
3541 
3542  torus->lpVtbl->Release(torus);
3543 }
3544 
3545 static void D3DXCreateTorusTest(void)
3546 {
3547  HRESULT hr;
3548  IDirect3DDevice9* device;
3549  ID3DXMesh* torus = NULL;
3550  struct test_context *test_context;
3551 
3552  if (!(test_context = new_test_context()))
3553  {
3554  skip("Couldn't create test context\n");
3555  return;
3556  }
3558 
3559  hr = D3DXCreateTorus(NULL, 0.0f, 0.0f, 3, 3, &torus, NULL);
3560  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3561 
3562  hr = D3DXCreateTorus(device, -1.0f, 0.0f, 3, 3, &torus, NULL);
3563  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3564 
3565  hr = D3DXCreateTorus(device, 0.0f, -1.0f, 3, 3, &torus, NULL);
3566  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3567 
3568  hr = D3DXCreateTorus(device, 0.0f, 0.0f, 2, 3, &torus, NULL);
3569  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3570 
3571  hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 2, &torus, NULL);
3572  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3573 
3574  hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 3, NULL, NULL);
3575  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3576 
3577  test_torus(device, 0.0f, 0.0f, 3, 3);
3578  test_torus(device, 1.0f, 1.0f, 3, 3);
3579  test_torus(device, 1.0f, 1.0f, 32, 64);
3580  test_torus(device, 0.0f, 1.0f, 5, 5);
3581  test_torus(device, 1.0f, 0.0f, 5, 5);
3582  test_torus(device, 5.0f, 0.2f, 8, 8);
3583  test_torus(device, 0.2f, 1.0f, 60, 3);
3584  test_torus(device, 0.2f, 1.0f, 8, 70);
3585 
3587 }
3588 
3589 struct dynamic_array
3590 {
3591  int count, capacity;
3592  void *items;
3593 };
3594 
3601 };
3602 
3603 struct point2d
3604 {
3605  D3DXVECTOR2 pos;
3606  enum pointtype corner;
3607 };
3608 
3609 /* is a dynamic_array */
3610 struct outline
3611 {
3612  int count, capacity;
3613  struct point2d *items;
3614 };
3615 
3616 /* is a dynamic_array */
3617 struct outline_array
3618 {
3619  int count, capacity;
3620  struct outline *items;
3621 };
3622 
3623 struct glyphinfo
3624 {
3625  struct outline_array outlines;
3626  float offset_x;
3627 };
3628 
3629 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
3630 {
3631  if (count > array->capacity) {
3632  void *new_buffer;
3633  int new_capacity;
3634  if (array->items && array->capacity) {
3635  new_capacity = max(array->capacity * 2, count);
3636  new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
3637  } else {
3638  new_capacity = max(16, count);
3639  new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
3640  }
3641  if (!new_buffer)
3642  return FALSE;
3643  array->items = new_buffer;
3644  array->capacity = new_capacity;
3645  }
3646  return TRUE;
3647 }
3648 
3649 static struct point2d *add_point(struct outline *array)
3650 {
3651  struct point2d *item;
3652 
3653  if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3654  return NULL;
3655 
3656  item = &array->items[array->count++];
3657  ZeroMemory(item, sizeof(*item));
3658  return item;
3659 }
3660 
3661 static struct outline *add_outline(struct outline_array *array)
3662 {
3663  struct outline *item;
3664 
3665  if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3666  return NULL;
3667 
3668  item = &array->items[array->count++];
3669  ZeroMemory(item, sizeof(*item));
3670  return item;
3671 }
3672 
3673 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
3674 {
3676  while (count--) {
3677  D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
3678  pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
3679  pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
3680  pt++;
3681  }
3682  return ret;
3683 }
3684 
3686  const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
3687  float max_deviation)
3688 {
3689  D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
3690  float deviation;
3691 
3692  D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
3693  D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
3694  D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
3695 
3696  deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
3697  if (deviation < max_deviation) {
3698  struct point2d *pt = add_point(outline);
3699  if (!pt) return E_OUTOFMEMORY;
3700  pt->pos = *p2;
3701  pt->corner = POINTTYPE_CURVE;
3702  /* the end point is omitted because the end line merges into the next segment of
3703  * the split bezier curve, and the end of the split bezier curve is added outside
3704  * this recursive function. */
3705  } else {
3706  HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
3707  if (hr != S_OK) return hr;
3708  hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
3709  if (hr != S_OK) return hr;
3710  }
3711 
3712  return S_OK;
3713 }
3714 
3715 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
3716 {
3717  /* dot product = cos(theta) */
3718  return D3DXVec2Dot(dir1, dir2) > cos_theta;
3719 }
3720 
3721 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
3722 {