ReactOS  0.4.15-dev-2985-g54406bf
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  rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
439  result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
440  ok(result == TRUE, "Got unexpected result %#x.\n", result);
441 
442  rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
443  result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
444  ok(result == FALSE, "Got unexpected result %#x.\n", result);
445 
446  raydirection.x = -2.0f; raydirection.y = 4.0f; raydirection.z = -2.0f;
447  result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
448  ok(result == TRUE, "Got unexpected result %#x.\n", result);
449 
450  rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
451  result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
452  ok(result == FALSE, "Got unexpected result %#x.\n", result);
453 
454  raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
455  result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
456  ok(result == FALSE, "Got unexpected result %#x.\n", result);
457 
458  radius = 1.0f;
459  rayposition.x = 2.0f; rayposition.y = 2.0f; rayposition.z = 3.0f;
460  result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
461  ok(result == FALSE, "Got unexpected result %#x.\n", result);
462 
463  raydirection.x = 0.0f; raydirection.y = 0.0f; raydirection.z = 1.0f;
464  result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
465  ok(result == TRUE, "Got unexpected result %#x.\n", result);
466 
467  if (0)
468  {
469  /* All these crash on native. */
470  D3DXSphereBoundProbe(&center, radius, &rayposition, NULL);
471  D3DXSphereBoundProbe(&center, radius, NULL, &raydirection);
472  D3DXSphereBoundProbe(NULL, radius, &rayposition, &raydirection);
473  }
474 }
475 
476 static void D3DXComputeBoundingBoxTest(void)
477 {
478  D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
479  HRESULT hr;
480 
481  vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
482  vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
483  vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
484  vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
485  vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
486 
487  exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
488  exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
489 
490  hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
491 
492  ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
493  ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
494  ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
495 
496 /*________________________*/
497 
498  vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
499  vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
500  vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
501  vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
502  vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
503 
504  exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
505  exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
506 
507  hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
508 
509  ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
510  ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
511  ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
512 
513 /*________________________*/
514 
515  vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
516  vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
517  vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
518  vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
519  vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
520 
521  exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
522  exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
523 
524  hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
525 
526  ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
527  ok( compare_vec3(exp_min,got_min), "Expected min: (%f, %f, %f), got: (%f, %f, %f)\n", exp_min.x,exp_min.y,exp_min.z,got_min.x,got_min.y,got_min.z);
528  ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
529 
530 /*________________________*/
532  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
533 
534 /*________________________*/
536  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
537 
538 /*________________________*/
540  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
541 }
542 
544 {
545  D3DXVECTOR3 exp_cen, got_cen, vertex[5];
546  FLOAT exp_rad, got_rad;
547  HRESULT hr;
548 
549  vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
550  vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
551  vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
552  vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
553  vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
554 
555  exp_rad = 6.928203f;
556  exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
557 
559 
560  ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
561  ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
562  ok( compare_vec3(exp_cen,got_cen), "Expected center: (%f, %f, %f), got center: (%f, %f, %f)\n", exp_cen.x,exp_cen.y,exp_cen.z,got_cen.x,got_cen.y,got_cen.z);
563 
564 /*________________________*/
565 
566  vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
567  vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
568  vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
569  vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
570  vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
571 
572  exp_rad = 13.707883f;
573  exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
574 
576 
577  ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
578  ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
579  ok( compare_vec3(exp_cen,got_cen), "Expected center: (%f, %f, %f), got center: (%f, %f, %f)\n", exp_cen.x,exp_cen.y,exp_cen.z,got_cen.x,got_cen.y,got_cen.z);
580 
581 /*________________________*/
583  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
584 
585 /*________________________*/
587  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
588 
589 /*________________________*/
591  ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
592 }
593 
594 static void print_elements(const D3DVERTEXELEMENT9 *elements)
595 {
597  const D3DVERTEXELEMENT9 *ptr = elements;
598  int count = 0;
599 
600  while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
601  {
602  trace(
603  "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
604  count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
605  ptr++;
606  count++;
607  }
608 }
609 
610 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
611  unsigned int line, unsigned int test_id)
612 {
614  unsigned int i;
615 
616  for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
617  {
618  int end1 = memcmp(&elements[i], &last, sizeof(last));
619  int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
620  int status;
621 
622  if (!end1 && !end2) break;
623 
624  status = !end1 ^ !end2;
625  ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
626  line, test_id, end1 ? "shorter" : "longer");
627  if (status)
628  {
629  print_elements(elements);
630  break;
631  }
632 
633  status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
634  ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
635  if (status)
636  {
637  print_elements(elements);
638  break;
639  }
640  }
641 }
642 
643 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
644  HRESULT expected_hr, unsigned int line, unsigned int test_id)
645 {
646  HRESULT hr;
648 
649  hr = D3DXDeclaratorFromFVF(test_fvf, decl);
650  ok(hr == expected_hr,
651  "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
652  line, test_id, hr, expected_hr);
653  if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
654 }
655 
656 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
657  HRESULT expected_hr, unsigned int line, unsigned int test_id)
658 {
659  HRESULT hr;
660  DWORD result_fvf = 0xdeadbeef;
661 
662  hr = D3DXFVFFromDeclarator(decl, &result_fvf);
663  ok(hr == expected_hr,
664  "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
665  line, test_id, hr, expected_hr);
666  if (SUCCEEDED(hr))
667  {
668  ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
669  line, test_id, result_fvf, expected_fvf);
670  }
671 }
672 
673 static void test_fvf_decl_conversion(void)
674 {
675  static const struct
676  {
678  DWORD fvf;
679  }
680  test_data[] =
681  {
682  {{
683  D3DDECL_END(),
684  }, 0},
685  {{
687  D3DDECL_END(),
688  }, D3DFVF_XYZ},
689  {{
691  D3DDECL_END(),
692  }, D3DFVF_XYZRHW},
693  {{
695  D3DDECL_END(),
696  }, D3DFVF_XYZRHW},
697  {{
700  D3DDECL_END(),
701  }, D3DFVF_XYZB1},
702  {{
705  D3DDECL_END(),
707  {{
710  D3DDECL_END(),
712  {{
715  D3DDECL_END(),
716  }, D3DFVF_XYZB2},
717  {{
721  D3DDECL_END(),
723  {{
727  D3DDECL_END(),
729  {{
732  D3DDECL_END(),
733  }, D3DFVF_XYZB3},
734  {{
738  D3DDECL_END(),
740  {{
744  D3DDECL_END(),
746  {{
749  D3DDECL_END(),
750  }, D3DFVF_XYZB4},
751  {{
755  D3DDECL_END(),
757  {{
761  D3DDECL_END(),
763  {{
767  D3DDECL_END(),
769  {{
773  D3DDECL_END(),
775  {{
777  D3DDECL_END(),
778  }, D3DFVF_NORMAL},
779  {{
782  D3DDECL_END(),
784  {{
785  {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
786  D3DDECL_END(),
787  }, D3DFVF_PSIZE},
788  {{
790  D3DDECL_END(),
791  }, D3DFVF_DIFFUSE},
792  {{
794  D3DDECL_END(),
795  }, D3DFVF_SPECULAR},
796  /* Make sure textures of different sizes work. */
797  {{
799  D3DDECL_END(),
801  {{
803  D3DDECL_END(),
805  {{
807  D3DDECL_END(),
809  {{
811  D3DDECL_END(),
813  /* Make sure the TEXCOORD index works correctly - try several textures. */
814  {{
819  D3DDECL_END(),
822  /* Now try some combination tests. */
823  {{
830  D3DDECL_END(),
833  {{
835  {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
836  {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
840  D3DDECL_END(),
843  };
844  unsigned int i;
845 
846  for (i = 0; i < ARRAY_SIZE(test_data); ++i)
847  {
848  test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
849  test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
850  }
851 
852  /* Usage indices for position and normal are apparently ignored. */
853  {
854  const D3DVERTEXELEMENT9 decl[] =
855  {
857  D3DDECL_END(),
858  };
859  test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
860  }
861  {
862  const D3DVERTEXELEMENT9 decl[] =
863  {
865  D3DDECL_END(),
866  };
867  test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
868  }
869  /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
870  * there are no blend matrices. */
871  {
872  const D3DVERTEXELEMENT9 decl[] =
873  {
875  D3DDECL_END(),
876  };
878  }
879  {
880  const D3DVERTEXELEMENT9 decl[] =
881  {
883  D3DDECL_END(),
884  };
886  }
887  /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
888  {
889  const D3DVERTEXELEMENT9 decl[] =
890  {
894  D3DDECL_END(),
895  };
897  decl, D3D_OK, __LINE__, 0);
898  }
899  /* These are supposed to fail, both ways. */
900  {
901  const D3DVERTEXELEMENT9 decl[] =
902  {
904  D3DDECL_END(),
905  };
906  test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
907  test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
908  }
909  {
910  const D3DVERTEXELEMENT9 decl[] =
911  {
913  {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
914  D3DDECL_END(),
915  };
918  }
919  {
920  const D3DVERTEXELEMENT9 decl[] =
921  {
925  D3DDECL_END(),
926  };
927  test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
928  test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
929  }
930  /* Test a declaration that can't be converted to an FVF. */
931  {
932  const D3DVERTEXELEMENT9 decl[] =
933  {
935  {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
936  {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
939  /* 8 bytes padding */
941  D3DDECL_END(),
942  };
943  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
944  }
945  /* Elements must be ordered by offset. */
946  {
947  const D3DVERTEXELEMENT9 decl[] =
948  {
951  D3DDECL_END(),
952  };
953  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
954  }
955  /* Basic tests for element order. */
956  {
957  const D3DVERTEXELEMENT9 decl[] =
958  {
961  {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
962  D3DDECL_END(),
963  };
964  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
965  }
966  {
967  const D3DVERTEXELEMENT9 decl[] =
968  {
971  D3DDECL_END(),
972  };
973  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
974  }
975  {
976  const D3DVERTEXELEMENT9 decl[] =
977  {
980  D3DDECL_END(),
981  };
982  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
983  }
984  /* Textures must be ordered by texcoords. */
985  {
986  const D3DVERTEXELEMENT9 decl[] =
987  {
992  D3DDECL_END(),
993  };
994  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
995  }
996  /* Duplicate elements are not allowed. */
997  {
998  const D3DVERTEXELEMENT9 decl[] =
999  {
1001  {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
1002  {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
1003  D3DDECL_END(),
1004  };
1005  test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
1006  }
1007  /* Invalid FVFs cannot be converted to a declarator. */
1008  test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
1009 }
1010 
1011 static void D3DXGetFVFVertexSizeTest(void)
1012 {
1013  UINT got;
1014 
1016 
1018 
1020 
1022 
1024 
1026  D3DFVF_XYZ |
1027  D3DFVF_TEX1 |
1028  D3DFVF_TEXCOORDSIZE1(0), 16);
1030  D3DFVF_XYZ |
1031  D3DFVF_TEX2 |
1033  D3DFVF_TEXCOORDSIZE1(1), 20);
1034 
1036  D3DFVF_XYZ |
1037  D3DFVF_TEX1 |
1038  D3DFVF_TEXCOORDSIZE2(0), 20);
1039 
1041  D3DFVF_XYZ |
1042  D3DFVF_TEX2 |
1044  D3DFVF_TEXCOORDSIZE2(1), 28);
1045 
1047  D3DFVF_XYZ |
1048  D3DFVF_TEX6 |
1054  D3DFVF_TEXCOORDSIZE2(5), 60);
1055 
1057  D3DFVF_XYZ |
1058  D3DFVF_TEX8 |
1066  D3DFVF_TEXCOORDSIZE2(7), 76);
1067 
1069  D3DFVF_XYZ |
1070  D3DFVF_TEX1 |
1071  D3DFVF_TEXCOORDSIZE3(0), 24);
1072 
1074  D3DFVF_XYZ |
1075  D3DFVF_TEX4 |
1079  D3DFVF_TEXCOORDSIZE3(3), 60);
1080 
1082  D3DFVF_XYZ |
1083  D3DFVF_TEX1 |
1084  D3DFVF_TEXCOORDSIZE4(0), 28);
1085 
1087  D3DFVF_XYZ |
1088  D3DFVF_TEX2 |
1090  D3DFVF_TEXCOORDSIZE4(1), 44);
1091 
1093  D3DFVF_XYZ |
1094  D3DFVF_TEX3 |
1097  D3DFVF_TEXCOORDSIZE4(2), 60);
1098 
1100  D3DFVF_XYZB5 |
1101  D3DFVF_NORMAL |
1102  D3DFVF_DIFFUSE |
1103  D3DFVF_SPECULAR |
1104  D3DFVF_TEX8 |
1112  D3DFVF_TEXCOORDSIZE4(7), 180);
1113 }
1114 
1115 static void D3DXIntersectTriTest(void)
1116 {
1117  BOOL exp_res, got_res;
1118  D3DXVECTOR3 position, ray, vertex[3];
1119  FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
1120 
1121  vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1122  vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1123  vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1124 
1125  position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
1126 
1127  ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1128 
1129  exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
1130 
1131  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1132  ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1133  ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1134  ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1135  ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1136 
1137  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1138  ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1139 
1140  vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1141  vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1142  vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 0.0f;
1143 
1144  got_u = got_v = got_dist = 0.0f;
1145  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1146  ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1147  ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1148  ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1149  ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1150 
1151  vertex[2].x = 1.0f; vertex[2].y = 0.0f; vertex[2].z = 0.0f;
1152  vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = -0.5f;
1153  vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = -1.0f;
1154  exp_u = 0.375f;
1155  exp_v = 0.5625f;
1156  exp_dist = 7.9375f;
1157  got_u = got_v = got_dist = 0.0f;
1158  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, &got_u, &got_v, &got_dist);
1159  ok(got_res == exp_res, "Expected result %d, got %d.\n", exp_res, got_res);
1160  ok(compare(exp_u, got_u), "Expected u %f, got %f.\n", exp_u, got_u);
1161  ok(compare(exp_v, got_v), "Expected v %f, got %f.\n", exp_v, got_v);
1162  ok(compare(exp_dist, got_dist), "Expected distance %f, got %f.\n", exp_dist, got_dist);
1163 
1164 
1165 /*Only positive ray is taken in account*/
1166 
1167  vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1168  vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1169  vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1170 
1171  position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
1172 
1173  ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1174 
1175  exp_res = FALSE;
1176 
1177  got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1178  ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1179 
1180  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1181  ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1182 
1183 /*Intersection between ray and triangle in a same plane is considered as empty*/
1184 
1185  vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1186  vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1187  vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
1188 
1189  position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
1190 
1191  ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
1192 
1193  exp_res = FALSE;
1194 
1195  got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1196  ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1197 
1198  got_res = D3DXIntersectTri(&vertex[0], &vertex[1], &vertex[2], &position, &ray, NULL, NULL, NULL);
1199  ok(got_res == exp_res, "Expected result = %d, got %d\n", exp_res, got_res);
1200 }
1201 
1202 static void D3DXCreateMeshTest(void)
1203 {
1204  HRESULT hr;
1205  IDirect3DDevice9 *device, *test_device;
1206  ID3DXMesh *d3dxmesh;
1207  int i, size;
1209  DWORD options;
1210  struct mesh mesh;
1211  struct test_context *test_context;
1212 
1213  static const D3DVERTEXELEMENT9 decl1[] =
1214  {
1217  D3DDECL_END(),
1218  };
1219 
1220  static const D3DVERTEXELEMENT9 decl2[] =
1221  {
1227  /* 8 bytes padding */
1229  D3DDECL_END(),
1230  };
1231 
1232  static const D3DVERTEXELEMENT9 decl3[] =
1233  {
1236  D3DDECL_END(),
1237  };
1238 
1239  hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1240  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1241 
1242  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1243  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1244 
1246  if (!test_context)
1247  {
1248  skip("Couldn't create test context\n");
1249  return;
1250  }
1252 
1253  hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1254  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1255 
1256  hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1257  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1258 
1259  hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
1260  ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1261 
1262  if (hr == D3D_OK)
1263  {
1264  d3dxmesh->lpVtbl->Release(d3dxmesh);
1265  }
1266 
1267  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1268  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1269 
1270  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
1271  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1272 
1273  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1274  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1275 
1276  if (hr == D3D_OK)
1277  {
1278  /* device */
1279  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1280  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1281 
1282  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1283  ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1284  ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1285 
1286  if (hr == D3D_OK)
1287  {
1289  }
1290 
1291  /* declaration */
1292  hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1293  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1294 
1295  hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1296  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1297 
1298  if (hr == D3D_OK)
1299  {
1300  size = ARRAY_SIZE(decl1);
1301  for (i = 0; i < size - 1; i++)
1302  {
1303  ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1304  ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1305  ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1306  ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1307  ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1308  ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1309  }
1310  ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1311  }
1312 
1313  /* options */
1314  options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1315  ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1316 
1317  /* rest */
1318  if (!new_mesh(&mesh, 3, 1))
1319  {
1320  skip("Couldn't create mesh\n");
1321  }
1322  else
1323  {
1325  memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1327 
1328  compare_mesh("createmesh1", d3dxmesh, &mesh);
1329 
1330  free_mesh(&mesh);
1331  }
1332 
1333  d3dxmesh->lpVtbl->Release(d3dxmesh);
1334  }
1335 
1336  /* Test a declaration that can't be converted to an FVF. */
1337  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1338  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1339 
1340  if (hr == D3D_OK)
1341  {
1342  /* device */
1343  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1344  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1345 
1346  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1347  ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1348  ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1349 
1350  if (hr == D3D_OK)
1351  {
1353  }
1354 
1355  /* declaration */
1356  hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1357  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1358 
1359  if (hr == D3D_OK)
1360  {
1361  size = ARRAY_SIZE(decl2);
1362  for (i = 0; i < size - 1; i++)
1363  {
1364  ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1365  ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1366  ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1367  ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1368  ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1369  ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1370  }
1371  ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1372  }
1373 
1374  /* options */
1375  options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1376  ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1377 
1378  /* rest */
1379  if (!new_mesh(&mesh, 3, 1))
1380  {
1381  skip("Couldn't create mesh\n");
1382  }
1383  else
1384  {
1386  memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1387  mesh.fvf = 0;
1388  mesh.vertex_size = 60;
1389 
1390  compare_mesh("createmesh2", d3dxmesh, &mesh);
1391 
1392  free_mesh(&mesh);
1393  }
1394 
1395  mesh.vertex_size = d3dxmesh->lpVtbl->GetNumBytesPerVertex(d3dxmesh);
1396  ok(mesh.vertex_size == 60, "Got vertex size %u, expected %u\n", mesh.vertex_size, 60);
1397 
1398  d3dxmesh->lpVtbl->Release(d3dxmesh);
1399  }
1400 
1401  /* Test a declaration with multiple streams. */
1402  hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
1403  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1404 
1406 }
1407 
1408 static void D3DXCreateMeshFVFTest(void)
1409 {
1410  HRESULT hr;
1411  IDirect3DDevice9 *device, *test_device;
1412  ID3DXMesh *d3dxmesh;
1413  int i, size;
1415  DWORD options;
1416  struct mesh mesh;
1417  struct test_context *test_context;
1418 
1419  static const D3DVERTEXELEMENT9 decl[] =
1420  {
1423  D3DDECL_END(),
1424  };
1425 
1426  hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1427  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1428 
1430  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1431 
1433  if (!test_context)
1434  {
1435  skip("Couldn't create test context\n");
1436  return;
1437  }
1439 
1441  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1442 
1444  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1445 
1446  hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1447  ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1448 
1449  if (hr == D3D_OK)
1450  {
1451  d3dxmesh->lpVtbl->Release(d3dxmesh);
1452  }
1453 
1454  hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1455  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1456 
1458  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1459 
1461  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1462 
1463  if (hr == D3D_OK)
1464  {
1465  /* device */
1466  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1467  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1468 
1469  hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1470  ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1471  ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1472 
1473  if (hr == D3D_OK)
1474  {
1476  }
1477 
1478  /* declaration */
1479  hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1480  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1481 
1482  hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1483  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1484 
1485  if (hr == D3D_OK)
1486  {
1487  size = ARRAY_SIZE(decl);
1488  for (i = 0; i < size - 1; i++)
1489  {
1490  ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1491  ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1492  ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1493  ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1494  ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1495  test_decl[i].UsageIndex, decl[i].UsageIndex);
1496  ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1497  }
1498  ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1499  }
1500 
1501  /* options */
1502  options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1503  ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1504 
1505  /* rest */
1506  if (!new_mesh(&mesh, 3, 1))
1507  {
1508  skip("Couldn't create mesh\n");
1509  }
1510  else
1511  {
1513  memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1515 
1516  compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1517 
1518  free_mesh(&mesh);
1519  }
1520 
1521  d3dxmesh->lpVtbl->Release(d3dxmesh);
1522  }
1523 
1525 }
1526 
1527 #define check_vertex_buffer(mesh, vertices, num_vertices, fvf) \
1528  check_vertex_buffer_(__LINE__, mesh, vertices, num_vertices, fvf)
1529 static void check_vertex_buffer_(int line, ID3DXMesh *mesh, const void *vertices, DWORD num_vertices, DWORD fvf)
1530 {
1531  DWORD mesh_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
1532  DWORD mesh_fvf = mesh->lpVtbl->GetFVF(mesh);
1533  const void *mesh_vertices;
1534  HRESULT hr;
1535 
1536  ok_(__FILE__,line)(fvf == mesh_fvf, "expected FVF %x, got %x\n", fvf, mesh_fvf);
1537  ok_(__FILE__,line)(num_vertices == mesh_num_vertices,
1538  "Expected %u vertices, got %u\n", num_vertices, mesh_num_vertices);
1539 
1540  hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
1541  ok_(__FILE__,line)(hr == D3D_OK, "LockVertexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1542  if (FAILED(hr))
1543  return;
1544 
1545  if (mesh_fvf == fvf) {
1546  DWORD vertex_size = D3DXGetFVFVertexSize(fvf), i;
1547 
1548  for (i = 0; i < min(num_vertices, mesh_num_vertices); i++)
1549  {
1550  const FLOAT *exp_float = vertices;
1551  const FLOAT *got_float = mesh_vertices;
1552  DWORD texcount;
1553  DWORD pos_dim = 0;
1554  int j;
1555  BOOL last_beta_dword = FALSE;
1556  char prefix[128];
1557 
1558  switch (fvf & D3DFVF_POSITION_MASK) {
1559  case D3DFVF_XYZ: pos_dim = 3; break;
1560  case D3DFVF_XYZRHW: pos_dim = 4; break;
1561  case D3DFVF_XYZB1:
1562  case D3DFVF_XYZB2:
1563  case D3DFVF_XYZB3:
1564  case D3DFVF_XYZB4:
1565  case D3DFVF_XYZB5:
1566  pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
1568  {
1569  pos_dim--;
1570  last_beta_dword = TRUE;
1571  }
1572  break;
1573  case D3DFVF_XYZW: pos_dim = 4; break;
1574  }
1575  sprintf(prefix, "vertex[%u] position, ", i);
1576  check_floats_(line, prefix, got_float, exp_float, pos_dim);
1577  exp_float += pos_dim;
1578  got_float += pos_dim;
1579 
1580  if (last_beta_dword) {
1581  ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1582  "Vertex[%u]: Expected last beta %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1583  exp_float++;
1584  got_float++;
1585  }
1586 
1587  if (fvf & D3DFVF_NORMAL) {
1588  sprintf(prefix, "vertex[%u] normal, ", i);
1589  check_floats_(line, prefix, got_float, exp_float, 3);
1590  exp_float += 3;
1591  got_float += 3;
1592  }
1593  if (fvf & D3DFVF_PSIZE) {
1594  ok_(__FILE__,line)(compare(*exp_float, *got_float),
1595  "Vertex[%u]: Expected psize %g, got %g\n", i, *exp_float, *got_float);
1596  exp_float++;
1597  got_float++;
1598  }
1599  if (fvf & D3DFVF_DIFFUSE) {
1600  ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1601  "Vertex[%u]: Expected diffuse %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1602  exp_float++;
1603  got_float++;
1604  }
1605  if (fvf & D3DFVF_SPECULAR) {
1606  ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1607  "Vertex[%u]: Expected specular %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1608  exp_float++;
1609  got_float++;
1610  }
1611 
1612  texcount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
1613  for (j = 0; j < texcount; j++) {
1614  DWORD dim = (((fvf >> (16 + 2 * j)) + 1) & 0x03) + 1;
1615  sprintf(prefix, "vertex[%u] texture, ", i);
1616  check_floats_(line, prefix, got_float, exp_float, dim);
1617  exp_float += dim;
1618  got_float += dim;
1619  }
1620 
1621  vertices = (BYTE*)vertices + vertex_size;
1622  mesh_vertices = (BYTE*)mesh_vertices + vertex_size;
1623  }
1624  }
1625 
1626  mesh->lpVtbl->UnlockVertexBuffer(mesh);
1627 }
1628 
1629 #define check_index_buffer(mesh, indices, num_indices, index_size) \
1630  check_index_buffer_(__LINE__, mesh, indices, num_indices, index_size)
1631 static void check_index_buffer_(int line, ID3DXMesh *mesh, const void *indices, DWORD num_indices, DWORD index_size)
1632 {
1633  DWORD mesh_index_size = (mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT) ? 4 : 2;
1634  DWORD mesh_num_indices = mesh->lpVtbl->GetNumFaces(mesh) * 3;
1635  const void *mesh_indices;
1636  HRESULT hr;
1637  DWORD i;
1638 
1639  ok_(__FILE__,line)(index_size == mesh_index_size,
1640  "Expected index size %u, got %u\n", index_size, mesh_index_size);
1641  ok_(__FILE__,line)(num_indices == mesh_num_indices,
1642  "Expected %u indices, got %u\n", num_indices, mesh_num_indices);
1643 
1644  hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
1645  ok_(__FILE__,line)(hr == D3D_OK, "LockIndexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1646  if (FAILED(hr))
1647  return;
1648 
1649  if (mesh_index_size == index_size) {
1650  for (i = 0; i < min(num_indices, mesh_num_indices); i++)
1651  {
1652  if (index_size == 4)
1653  ok_(__FILE__,line)(*(DWORD*)indices == *(DWORD*)mesh_indices,
1654  "Index[%u]: expected %u, got %u\n", i, *(DWORD*)indices, *(DWORD*)mesh_indices);
1655  else
1656  ok_(__FILE__,line)(*(WORD*)indices == *(WORD*)mesh_indices,
1657  "Index[%u]: expected %u, got %u\n", i, *(WORD*)indices, *(WORD*)mesh_indices);
1658  indices = (BYTE*)indices + index_size;
1659  mesh_indices = (BYTE*)mesh_indices + index_size;
1660  }
1661  }
1662  mesh->lpVtbl->UnlockIndexBuffer(mesh);
1663 }
1664 
1665 #define check_matrix(got, expected) check_matrix_(__LINE__, got, expected)
1666 static void check_matrix_(int line, const D3DXMATRIX *got, const D3DXMATRIX *expected)
1667 {
1668  int i, j;
1669  for (i = 0; i < 4; i++) {
1670  for (j = 0; j < 4; j++) {
1671  ok_(__FILE__,line)(compare(U(*expected).m[i][j], U(*got).m[i][j]),
1672  "matrix[%u][%u]: expected %g, got %g\n",
1673  i, j, U(*expected).m[i][j], U(*got).m[i][j]);
1674  }
1675  }
1676 }
1677 
1678 static void check_colorvalue_(int line, const char *prefix, const D3DCOLORVALUE got, const D3DCOLORVALUE expected)
1679 {
1680  ok_(__FILE__,line)(expected.r == got.r && expected.g == got.g && expected.b == got.b && expected.a == got.a,
1681  "%sExpected (%g, %g, %g, %g), got (%g, %g, %g, %g)\n", prefix,
1682  expected.r, expected.g, expected.b, expected.a, got.r, got.g, got.b, got.a);
1683 }
1684 
1685 #define check_materials(got, got_count, expected, expected_count) \
1686  check_materials_(__LINE__, got, got_count, expected, expected_count)
1687 static void check_materials_(int line, const D3DXMATERIAL *got, DWORD got_count, const D3DXMATERIAL *expected, DWORD expected_count)
1688 {
1689  int i;
1690  ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
1691  if (!expected) {
1692  ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
1693  return;
1694  }
1695  for (i = 0; i < min(expected_count, got_count); i++)
1696  {
1697  if (!expected[i].pTextureFilename)
1698  ok_(__FILE__,line)(got[i].pTextureFilename == NULL,
1699  "Expected NULL pTextureFilename, got %p\n", got[i].pTextureFilename);
1700  else
1701  ok_(__FILE__,line)(!strcmp(expected[i].pTextureFilename, got[i].pTextureFilename),
1702  "Expected '%s' for pTextureFilename, got '%s'\n", expected[i].pTextureFilename, got[i].pTextureFilename);
1703  check_colorvalue_(line, "Diffuse: ", got[i].MatD3D.Diffuse, expected[i].MatD3D.Diffuse);
1704  check_colorvalue_(line, "Ambient: ", got[i].MatD3D.Ambient, expected[i].MatD3D.Ambient);
1705  check_colorvalue_(line, "Specular: ", got[i].MatD3D.Specular, expected[i].MatD3D.Specular);
1706  check_colorvalue_(line, "Emissive: ", got[i].MatD3D.Emissive, expected[i].MatD3D.Emissive);
1707  ok_(__FILE__,line)(expected[i].MatD3D.Power == got[i].MatD3D.Power,
1708  "Power: Expected %g, got %g\n", expected[i].MatD3D.Power, got[i].MatD3D.Power);
1709  }
1710 }
1711 
1712 #define check_generated_adjacency(mesh, got, epsilon) check_generated_adjacency_(__LINE__, mesh, got, epsilon)
1713 static void check_generated_adjacency_(int line, ID3DXMesh *mesh, const DWORD *got, FLOAT epsilon)
1714 {
1715  DWORD *expected;
1716  DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
1717  HRESULT hr;
1718 
1719  expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
1720  if (!expected) {
1721  skip_(__FILE__, line)("Out of memory\n");
1722  return;
1723  }
1724  hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
1725  ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1726  if (SUCCEEDED(hr))
1727  {
1728  int i;
1729  for (i = 0; i < num_faces; i++)
1730  {
1731  ok_(__FILE__, line)(expected[i * 3] == got[i * 3] &&
1732  expected[i * 3 + 1] == got[i * 3 + 1] &&
1733  expected[i * 3 + 2] == got[i * 3 + 2],
1734  "Face %u adjacencies: Expected (%u, %u, %u), got (%u, %u, %u)\n", i,
1735  expected[i * 3], expected[i * 3 + 1], expected[i * 3 + 2],
1736  got[i * 3], got[i * 3 + 1], got[i * 3 + 2]);
1737  }
1738  }
1740 }
1741 
1742 #define check_generated_effects(materials, num_materials, effects) \
1743  check_generated_effects_(__LINE__, materials, num_materials, effects)
1744 static void check_generated_effects_(int line, const D3DXMATERIAL *materials, DWORD num_materials, const D3DXEFFECTINSTANCE *effects)
1745 {
1746  int i;
1747  static const struct {
1748  const char *name;
1749  DWORD name_size;
1750  DWORD num_bytes;
1751  DWORD value_offset;
1752  } params[] = {
1753 #define EFFECT_TABLE_ENTRY(str, field) \
1754  {str, sizeof(str), sizeof(materials->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
1755  EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
1756  EFFECT_TABLE_ENTRY("Power", Power),
1757  EFFECT_TABLE_ENTRY("Specular", Specular),
1758  EFFECT_TABLE_ENTRY("Emissive", Emissive),
1759  EFFECT_TABLE_ENTRY("Ambient", Ambient),
1760 #undef EFFECT_TABLE_ENTRY
1761  };
1762 
1763  if (!num_materials) {
1764  ok_(__FILE__, line)(effects == NULL, "Expected NULL effects, got %p\n", effects);
1765  return;
1766  }
1767  for (i = 0; i < num_materials; i++)
1768  {
1769  int j;
1770  DWORD expected_num_defaults = ARRAY_SIZE(params) + (materials[i].pTextureFilename ? 1 : 0);
1771 
1772  ok_(__FILE__,line)(expected_num_defaults == effects[i].NumDefaults,
1773  "effect[%u] NumDefaults: Expected %u, got %u\n", i,
1774  expected_num_defaults, effects[i].NumDefaults);
1775  for (j = 0; j < min(ARRAY_SIZE(params), effects[i].NumDefaults); j++)
1776  {
1777  int k;
1778  D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1779  ok_(__FILE__,line)(!strcmp(params[j].name, got_param->pParamName),
1780  "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1781  params[j].name, got_param->pParamName);
1782  ok_(__FILE__,line)(D3DXEDT_FLOATS == got_param->Type,
1783  "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1784  D3DXEDT_FLOATS, got_param->Type);
1785  ok_(__FILE__,line)(params[j].num_bytes == got_param->NumBytes,
1786  "effect[%u].pDefaults[%u].NumBytes: Expected %u, got %u\n", i, j,
1787  params[j].num_bytes, got_param->NumBytes);
1788  for (k = 0; k < min(params[j].num_bytes, got_param->NumBytes) / 4; k++)
1789  {
1790  FLOAT expected = ((FLOAT*)((BYTE*)&materials[i] + params[j].value_offset))[k];
1791  FLOAT got = ((FLOAT*)got_param->pValue)[k];
1792  ok_(__FILE__,line)(compare(expected, got),
1793  "effect[%u].pDefaults[%u] float value %u: Expected %g, got %g\n", i, j, k, expected, got);
1794  }
1795  }
1796  if (effects[i].NumDefaults > ARRAY_SIZE(params)) {
1797  D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1798  static const char *expected_name = "Texture0@Name";
1799 
1800  ok_(__FILE__,line)(!strcmp(expected_name, got_param->pParamName),
1801  "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1802  expected_name, got_param->pParamName);
1803  ok_(__FILE__,line)(D3DXEDT_STRING == got_param->Type,
1804  "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1805  D3DXEDT_STRING, got_param->Type);
1806  if (materials[i].pTextureFilename) {
1807  ok_(__FILE__,line)(strlen(materials[i].pTextureFilename) + 1 == got_param->NumBytes,
1808  "effect[%u] texture filename length: Expected %u, got %u\n", i,
1809  (DWORD)strlen(materials[i].pTextureFilename) + 1, got_param->NumBytes);
1810  ok_(__FILE__,line)(!strcmp(materials[i].pTextureFilename, got_param->pValue),
1811  "effect[%u] texture filename: Expected '%s', got '%s'\n", i,
1812  materials[i].pTextureFilename, (char*)got_param->pValue);
1813  }
1814  }
1815  }
1816 }
1817 
1818 static char *strdupA(const char *p)
1819 {
1820  char *ret;
1821  if (!p) return NULL;
1822  ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
1823  if (ret) strcpy(ret, p);
1824  return ret;
1825 }
1826 
1827 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
1828 {
1829  TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
1830  if (frame) {
1831  HeapFree(GetProcessHeap(), 0, frame->Name);
1832  HeapFree(GetProcessHeap(), 0, frame);
1833  }
1834  return D3D_OK;
1835 }
1836 
1837 static HRESULT CALLBACK ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface,
1838  const char *name, D3DXFRAME **new_frame)
1839 {
1840  D3DXFRAME *frame;
1841 
1842  TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
1843  frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
1844  if (!frame)
1845  return E_OUTOFMEMORY;
1846  if (name) {
1847  frame->Name = strdupA(name);
1848  if (!frame->Name) {
1849  HeapFree(GetProcessHeap(), 0, frame);
1850  return E_OUTOFMEMORY;
1851  }
1852  }
1853  *new_frame = frame;
1854  return D3D_OK;
1855 }
1856 
1858 {
1859  int i;
1860 
1861  if (!mesh_container)
1862  return D3D_OK;
1863  HeapFree(GetProcessHeap(), 0, mesh_container->Name);
1864  if (U(mesh_container->MeshData).pMesh)
1865  IUnknown_Release(U(mesh_container->MeshData).pMesh);
1866  if (mesh_container->pMaterials) {
1867  for (i = 0; i < mesh_container->NumMaterials; i++)
1868  HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials[i].pTextureFilename);
1869  HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials);
1870  }
1871  if (mesh_container->pEffects) {
1872  for (i = 0; i < mesh_container->NumMaterials; i++) {
1873  HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pEffectFilename);
1874  if (mesh_container->pEffects[i].pDefaults) {
1875  int j;
1876  for (j = 0; j < mesh_container->pEffects[i].NumDefaults; j++) {
1877  HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pParamName);
1878  HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pValue);
1879  }
1880  HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults);
1881  }
1882  }
1883  HeapFree(GetProcessHeap(), 0, mesh_container->pEffects);
1884  }
1885  HeapFree(GetProcessHeap(), 0, mesh_container->pAdjacency);
1886  if (mesh_container->pSkinInfo)
1887  IUnknown_Release(mesh_container->pSkinInfo);
1889  return D3D_OK;
1890 }
1891 
1893 {
1894  TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyMeshContainer(%p, %p)\n", iface, mesh_container);
1896 }
1897 
1899  const char *name, const D3DXMESHDATA *mesh_data, const D3DXMATERIAL *materials,
1900  const D3DXEFFECTINSTANCE *effects, DWORD num_materials, const DWORD *adjacency,
1901  ID3DXSkinInfo *skin_info, D3DXMESHCONTAINER **new_mesh_container)
1902 {
1904  int i;
1905 
1906  TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateMeshContainer(%p, '%s', %u, %p, %p, %p, %d, %p, %p, %p)\n",
1907  iface, name, mesh_data->Type, U(*mesh_data).pMesh, materials, effects,
1908  num_materials, adjacency, skin_info, *new_mesh_container);
1909 
1911  if (!mesh_container)
1912  return E_OUTOFMEMORY;
1913 
1914  if (name) {
1915  mesh_container->Name = strdupA(name);
1916  if (!mesh_container->Name)
1917  goto error;
1918  }
1919 
1920  mesh_container->NumMaterials = num_materials;
1921  if (num_materials) {
1922  mesh_container->pMaterials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*materials));
1923  if (!mesh_container->pMaterials)
1924  goto error;
1925 
1926  memcpy(mesh_container->pMaterials, materials, num_materials * sizeof(*materials));
1927  for (i = 0; i < num_materials; i++)
1928  mesh_container->pMaterials[i].pTextureFilename = NULL;
1929  for (i = 0; i < num_materials; i++) {
1930  if (materials[i].pTextureFilename) {
1931  mesh_container->pMaterials[i].pTextureFilename = strdupA(materials[i].pTextureFilename);
1932  if (!mesh_container->pMaterials[i].pTextureFilename)
1933  goto error;
1934  }
1935  }
1936 
1937  mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
1938  if (!mesh_container->pEffects)
1939  goto error;
1940  for (i = 0; i < num_materials; i++) {
1941  int j;
1942  const D3DXEFFECTINSTANCE *effect_src = &effects[i];
1943  D3DXEFFECTINSTANCE *effect_dest = &mesh_container->pEffects[i];
1944 
1945  if (effect_src->pEffectFilename) {
1946  effect_dest->pEffectFilename = strdupA(effect_src->pEffectFilename);
1947  if (!effect_dest->pEffectFilename)
1948  goto error;
1949  }
1951  effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
1952  if (!effect_dest->pDefaults)
1953  goto error;
1954  effect_dest->NumDefaults = effect_src->NumDefaults;
1955  for (j = 0; j < effect_src->NumDefaults; j++) {
1956  const D3DXEFFECTDEFAULT *default_src = &effect_src->pDefaults[j];
1957  D3DXEFFECTDEFAULT *default_dest = &effect_dest->pDefaults[j];
1958 
1959  if (default_src->pParamName) {
1960  default_dest->pParamName = strdupA(default_src->pParamName);
1961  if (!default_dest->pParamName)
1962  goto error;
1963  }
1964  default_dest->NumBytes = default_src->NumBytes;
1965  default_dest->Type = default_src->Type;
1966  default_dest->pValue = HeapAlloc(GetProcessHeap(), 0, default_src->NumBytes);
1967  memcpy(default_dest->pValue, default_src->pValue, default_src->NumBytes);
1968  }
1969  }
1970  }
1971 
1972  ok(adjacency != NULL, "Expected non-NULL adjacency, got NULL\n");
1973  if (adjacency) {
1974  if (mesh_data->Type == D3DXMESHTYPE_MESH || mesh_data->Type == D3DXMESHTYPE_PMESH) {
1975  ID3DXBaseMesh *basemesh = (ID3DXBaseMesh*)U(*mesh_data).pMesh;
1976  DWORD num_faces = basemesh->lpVtbl->GetNumFaces(basemesh);
1977  size_t size = num_faces * sizeof(DWORD) * 3;
1978  mesh_container->pAdjacency = HeapAlloc(GetProcessHeap(), 0, size);
1979  if (!mesh_container->pAdjacency)
1980  goto error;
1981  memcpy(mesh_container->pAdjacency, adjacency, size);
1982  } else {
1983  ok(mesh_data->Type == D3DXMESHTYPE_PATCHMESH, "Unknown mesh type %u\n", mesh_data->Type);
1984  if (mesh_data->Type == D3DXMESHTYPE_PATCHMESH)
1985  trace("FIXME: copying adjacency data for patch mesh not implemented\n");
1986  }
1987  }
1988 
1989  memcpy(&mesh_container->MeshData, mesh_data, sizeof(*mesh_data));
1990  if (U(*mesh_data).pMesh)
1991  IUnknown_AddRef(U(*mesh_data).pMesh);
1992  if (skin_info) {
1993  mesh_container->pSkinInfo = skin_info;
1994  skin_info->lpVtbl->AddRef(skin_info);
1995  }
1996  *new_mesh_container = mesh_container;
1997 
1998  return S_OK;
1999 error:
2001  return E_OUTOFMEMORY;
2002 }
2003 
2004 static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
2009 };
2010 static ID3DXAllocateHierarchy alloc_hier = { &ID3DXAllocateHierarchyImpl_Vtbl };
2011 
2012 #define test_LoadMeshFromX(device, xfile_str, vertex_array, fvf, index_array, materials_array, check_adjacency) \
2013  test_LoadMeshFromX_(__LINE__, device, xfile_str, sizeof(xfile_str) - 1, vertex_array, ARRAY_SIZE(vertex_array), fvf, \
2014  index_array, ARRAY_SIZE(index_array), sizeof(*index_array), materials_array, ARRAY_SIZE(materials_array), \
2015  check_adjacency);
2016 static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char *xfile_str, size_t xfile_strlen,
2017  const void *vertices, DWORD num_vertices, DWORD fvf, const void *indices, DWORD num_indices, size_t index_size,
2018  const D3DXMATERIAL *expected_materials, DWORD expected_num_materials, BOOL check_adjacency)
2019 {
2020  HRESULT hr;
2021  ID3DXBuffer *materials = NULL;
2022  ID3DXBuffer *effects = NULL;
2023  ID3DXBuffer *adjacency = NULL;
2024  ID3DXMesh *mesh = NULL;
2025  DWORD num_materials = 0;
2026 
2027  /* Adjacency is not checked when the X file contains multiple meshes,
2028  * since calling GenerateAdjacency on the merged mesh is not equivalent
2029  * to calling GenerateAdjacency on the individual meshes and then merging
2030  * the adjacency data. */
2031  hr = D3DXLoadMeshFromXInMemory(xfile_str, xfile_strlen, D3DXMESH_MANAGED, device,
2032  check_adjacency ? &adjacency : NULL, &materials, &effects, &num_materials, &mesh);
2033  ok_(__FILE__,line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2034  if (SUCCEEDED(hr)) {
2035  D3DXMATERIAL *materials_ptr = materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL;
2036  D3DXEFFECTINSTANCE *effects_ptr = effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL;
2037  DWORD *adjacency_ptr = check_adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL;
2038 
2039  check_vertex_buffer_(line, mesh, vertices, num_vertices, fvf);
2040  check_index_buffer_(line, mesh, indices, num_indices, index_size);
2041  check_materials_(line, materials_ptr, num_materials, expected_materials, expected_num_materials);
2042  check_generated_effects_(line, materials_ptr, num_materials, effects_ptr);
2043  if (check_adjacency)
2044  check_generated_adjacency_(line, mesh, adjacency_ptr, 0.0f);
2045 
2046  if (materials) ID3DXBuffer_Release(materials);
2047  if (effects) ID3DXBuffer_Release(effects);
2048  if (adjacency) ID3DXBuffer_Release(adjacency);
2049  IUnknown_Release(mesh);
2050  }
2051 }
2052 
2053 static void D3DXLoadMeshTest(void)
2054 {
2055  static const char empty_xfile[] = "xof 0303txt 0032";
2056  /*________________________*/
2057  static const char simple_xfile[] =
2058  "xof 0303txt 0032"
2059  "Mesh {"
2060  "3;"
2061  "0.0; 0.0; 0.0;,"
2062  "0.0; 1.0; 0.0;,"
2063  "1.0; 1.0; 0.0;;"
2064  "1;"
2065  "3; 0, 1, 2;;"
2066  "}";
2067  static const WORD simple_index_buffer[] = {0, 1, 2};
2068  static const D3DXVECTOR3 simple_vertex_buffer[] = {
2069  {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}
2070  };
2071  const DWORD simple_fvf = D3DFVF_XYZ;
2072  static const char framed_xfile[] =
2073  "xof 0303txt 0032"
2074  "Frame {"
2075  "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 1.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2076  "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */
2077  "1.0, 0.0, 0.0, 0.0,"
2078  "0.0, 1.0, 0.0, 0.0,"
2079  "0.0, 0.0, 1.0, 0.0,"
2080  "0.0, 0.0, 2.0, 1.0;;"
2081  "}"
2082  "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 2.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2083  "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */
2084  "1.0, 0.0, 0.0, 0.0,"
2085  "0.0, 1.0, 0.0, 0.0,"
2086  "0.0, 0.0, 1.0, 0.0,"
2087  "0.0, 0.0, 3.0, 1.0;;"
2088  "}"
2089  "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 3.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }"
2090  "}";
2091  static const WORD framed_index_buffer[] = { 0, 1, 2 };
2092  static const D3DXVECTOR3 framed_vertex_buffers[3][3] = {
2093  {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}},
2094  {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}},
2095  {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {3.0, 1.0, 0.0}},
2096  };
2097  static const WORD merged_index_buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
2098  /* frame transforms accumulates for D3DXLoadMeshFromX */
2099  static const D3DXVECTOR3 merged_vertex_buffer[] = {
2100  {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0},
2101  {0.0, 0.0, 2.0}, {0.0, 1.0, 2.0}, {2.0, 1.0, 2.0},
2102  {0.0, 0.0, 5.0}, {0.0, 1.0, 5.0}, {3.0, 1.0, 5.0},
2103  };
2104  const DWORD framed_fvf = D3DFVF_XYZ;
2105  /*________________________*/
2106  static const char box_xfile[] =
2107  "xof 0303txt 0032"
2108  "Mesh {"
2109  "8;" /* DWORD nVertices; */
2110  /* array Vector vertices[nVertices]; */
2111  "0.0; 0.0; 0.0;,"
2112  "0.0; 0.0; 1.0;,"
2113  "0.0; 1.0; 0.0;,"
2114  "0.0; 1.0; 1.0;,"
2115  "1.0; 0.0; 0.0;,"
2116  "1.0; 0.0; 1.0;,"
2117  "1.0; 1.0; 0.0;,"
2118  "1.0; 1.0; 1.0;;"
2119  "6;" /* DWORD nFaces; */
2120  /* array MeshFace faces[nFaces]; */
2121  "4; 0, 1, 3, 2;," /* (left side) */
2122  "4; 2, 3, 7, 6;," /* (top side) */
2123  "4; 6, 7, 5, 4;," /* (right side) */
2124  "4; 1, 0, 4, 5;," /* (bottom side) */
2125  "4; 1, 5, 7, 3;," /* (back side) */
2126  "4; 0, 2, 6, 4;;" /* (front side) */
2127  "MeshNormals {"
2128  "6;" /* DWORD nNormals; */
2129  /* array Vector normals[nNormals]; */
2130  "-1.0; 0.0; 0.0;,"
2131  "0.0; 1.0; 0.0;,"
2132  "1.0; 0.0; 0.0;,"
2133  "0.0; -1.0; 0.0;,"
2134  "0.0; 0.0; 1.0;,"
2135  "0.0; 0.0; -1.0;;"
2136  "6;" /* DWORD nFaceNormals; */
2137  /* array MeshFace faceNormals[nFaceNormals]; */
2138  "4; 0, 0, 0, 0;,"
2139  "4; 1, 1, 1, 1;,"
2140  "4; 2, 2, 2, 2;,"
2141  "4; 3, 3, 3, 3;,"
2142  "4; 4, 4, 4, 4;,"
2143  "4; 5, 5, 5, 5;;"
2144  "}"
2145  "MeshMaterialList materials {"
2146  "2;" /* DWORD nMaterials; */
2147  "6;" /* DWORD nFaceIndexes; */
2148  /* array DWORD faceIndexes[nFaceIndexes]; */
2149  "0, 0, 0, 1, 1, 1;;"
2150  "Material {"
2151  /* ColorRGBA faceColor; */
2152  "0.0; 0.0; 1.0; 1.0;;"
2153  /* FLOAT power; */
2154  "0.5;"
2155  /* ColorRGB specularColor; */
2156  "1.0; 1.0; 1.0;;"
2157  /* ColorRGB emissiveColor; */
2158  "0.0; 0.0; 0.0;;"
2159  "}"
2160  "Material {"
2161  /* ColorRGBA faceColor; */
2162  "1.0; 1.0; 1.0; 1.0;;"
2163  /* FLOAT power; */
2164  "1.0;"
2165  /* ColorRGB specularColor; */
2166  "1.0; 1.0; 1.0;;"
2167  /* ColorRGB emissiveColor; */
2168  "0.0; 0.0; 0.0;;"
2169  "TextureFilename { \"texture.jpg\"; }"
2170  "}"
2171  "}"
2172  "MeshVertexColors {"
2173  "8;" /* DWORD nVertexColors; */
2174  /* array IndexedColor vertexColors[nVertexColors]; */
2175  "0; 0.0; 0.0; 0.0; 0.0;;"
2176  "1; 0.0; 0.0; 1.0; 0.1;;"
2177  "2; 0.0; 1.0; 0.0; 0.2;;"
2178  "3; 0.0; 1.0; 1.0; 0.3;;"
2179  "4; 1.0; 0.0; 0.0; 0.4;;"
2180  "5; 1.0; 0.0; 1.0; 0.5;;"
2181  "6; 1.0; 1.0; 0.0; 0.6;;"
2182  "7; 1.0; 1.0; 1.0; 0.7;;"
2183  "}"
2184  "MeshTextureCoords {"
2185  "8;" /* DWORD nTextureCoords; */
2186  /* array Coords2d textureCoords[nTextureCoords]; */
2187  "0.0; 1.0;,"
2188  "1.0; 1.0;,"
2189  "0.0; 0.0;,"
2190  "1.0; 0.0;,"
2191  "1.0; 1.0;,"
2192  "0.0; 1.0;,"
2193  "1.0; 0.0;,"
2194  "0.0; 0.0;;"
2195  "}"
2196  "}";
2197  static const WORD box_index_buffer[] = {
2198  0, 1, 3,
2199  0, 3, 2,
2200  8, 9, 7,
2201  8, 7, 6,
2202  10, 11, 5,
2203  10, 5, 4,
2204  12, 13, 14,
2205  12, 14, 15,
2206  16, 17, 18,
2207  16, 18, 19,
2208  20, 21, 22,
2209  20, 22, 23,
2210  };
2211  static const struct {
2212  D3DXVECTOR3 position;
2214  D3DCOLOR diffuse;
2215  D3DXVECTOR2 tex_coords;
2216  } box_vertex_buffer[] = {
2217  {{0.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, 0x00000000, {0.0, 1.0}},
2218  {{0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2219  {{0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2220  {{0.0, 1.0, 1.0}, {-1.0, 0.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2221  {{1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2222  {{1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2223  {{1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2224  {{1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2225  {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2226  {{0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2227  {{1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2228  {{1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2229  {{0.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2230  {{0.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x00000000, {0.0, 1.0}},
2231  {{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2232  {{1.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2233  {{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x1a0000ff, {1.0, 1.0}},
2234  {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x80ff00ff, {0.0, 1.0}},
2235  {{1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0xb3ffffff, {0.0, 0.0}},
2236  {{0.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0x4d00ffff, {1.0, 0.0}},
2237  {{0.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x00000000, {0.0, 1.0}},
2238  {{0.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x3300ff00, {0.0, 0.0}},
2239  {{1.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x99ffff00, {1.0, 0.0}},
2240  {{1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x66ff0000, {1.0, 1.0}},
2241  };
2242  static const D3DXMATERIAL box_materials[] = {
2243  {
2244  {
2245  {0.0, 0.0, 1.0, 1.0}, /* Diffuse */
2246  {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2247  {1.0, 1.0, 1.0, 1.0}, /* Specular */
2248  {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2249  0.5, /* Power */
2250  },
2251  NULL, /* pTextureFilename */
2252  },
2253  {
2254  {
2255  {1.0, 1.0, 1.0, 1.0}, /* Diffuse */
2256  {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2257  {1.0, 1.0, 1.0, 1.0}, /* Specular */
2258  {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2259  1.0, /* Power */
2260  },
2261  (char *)"texture.jpg", /* pTextureFilename */
2262  },
2263  };
2264  static const char box_anim_xfile[] =
2265  "xof 0303txt 0032"
2266  "Mesh CubeMesh {"
2267  "8;" /* DWORD nVertices; */
2268  /* array Vector vertices[nVertices]; */
2269  "0.0; 0.0; 0.0;,"
2270  "0.0; 0.0; 1.0;,"
2271  "0.0; 1.0; 0.0;,"
2272  "0.0; 1.0; 1.0;,"
2273  "1.0; 0.0; 0.0;,"
2274  "1.0; 0.0; 1.0;,"
2275  "1.0; 1.0; 0.0;,"
2276  "1.0; 1.0; 1.0;;"
2277  "6;" /* DWORD nFaces; */
2278  /* array MeshFace faces[nFaces]; */
2279  "4; 0, 1, 3, 2;," /* left side */
2280  "4; 2, 3, 7, 6;," /* top side */
2281  "4; 6, 7, 5, 4;," /* right side */
2282  "4; 1, 0, 4, 5;," /* bottom side */
2283  "4; 1, 5, 7, 3;," /* back side */
2284  "4; 0, 2, 6, 4;;" /* front side */
2285  "MeshNormals {"
2286  "6;" /* DWORD nNormals; */
2287  /* array Vector normals[nNormals]; */
2288  "-1.0; 0.0; 0.0;,"
2289  "0.0; 1.0; 0.0;,"
2290  "1.0; 0.0; 0.0;,"
2291  "0.0; -1.0; 0.0;,"
2292  "0.0; 0.0; 1.0;,"
2293  "0.0; 0.0; -1.0;;"
2294  "6;" /* DWORD nFaceNormals; */
2295  /* array MeshFace faceNormals[nFaceNormals]; */
2296  "4; 0, 0, 0, 0;,"
2297  "4; 1, 1, 1, 1;,"
2298  "4; 2, 2, 2, 2;,"
2299  "4; 3, 3, 3, 3;,"
2300  "4; 4, 4, 4, 4;,"
2301  "4; 5, 5, 5, 5;;"
2302  "}"
2303  "MeshMaterialList materials {"
2304  "2;" /* DWORD nMaterials; */
2305  "6;" /* DWORD nFaceIndexes; */
2306  /* array DWORD faceIndexes[nFaceIndexes]; */
2307  "0, 0, 0, 1, 1, 1;;"
2308  "Material {"
2309  /* ColorRGBA faceColor; */
2310  "0.0; 0.0; 1.0; 1.0;;"
2311  /* FLOAT power; */
2312  "0.5;"
2313  /* ColorRGB specularColor; */
2314  "1.0; 1.0; 1.0;;"
2315  /* ColorRGB emissiveColor; */
2316  "0.0; 0.0; 0.0;;"
2317  "}"
2318  "Material {"
2319  /* ColorRGBA faceColor; */
2320  "1.0; 1.0; 1.0; 1.0;;"
2321  /* FLOAT power; */
2322  "1.0;"
2323  /* ColorRGB specularColor; */
2324  "1.0; 1.0; 1.0;;"
2325  /* ColorRGB emissiveColor; */
2326  "0.0; 0.0; 0.0;;"
2327  "TextureFilename { \"texture.jpg\"; }"
2328  "}"
2329  "}"
2330  "MeshVertexColors {"
2331  "8;" /* DWORD nVertexColors; */
2332  /* array IndexedColor vertexColors[nVertexColors]; */
2333  "0; 0.0; 0.0; 0.0; 0.0;;"
2334  "1; 0.0; 0.0; 1.0; 0.1;;"
2335  "2; 0.0; 1.0; 0.0; 0.2;;"
2336  "3; 0.0; 1.0; 1.0; 0.3;;"
2337  "4; 1.0; 0.0; 0.0; 0.4;;"
2338  "5; 1.0; 0.0; 1.0; 0.5;;"
2339  "6; 1.0; 1.0; 0.0; 0.6;;"
2340  "7; 1.0; 1.0; 1.0; 0.7;;"
2341  "}"
2342  "MeshTextureCoords {"
2343  "8;" /* DWORD nTextureCoords; */
2344  /* array Coords2d textureCoords[nTextureCoords]; */
2345  "0.0; 1.0;,"
2346  "1.0; 1.0;,"
2347  "0.0; 0.0;,"
2348  "1.0; 0.0;,"
2349  "1.0; 1.0;,"
2350  "0.0; 1.0;,"
2351  "1.0; 0.0;,"
2352  "0.0; 0.0;;"
2353  "}"
2354  "}"
2355  "Frame CubeFrame {"
2356  "FrameTransformMatrix {"
2357  /* Matrix4x4 frameMatrix; */
2358  "1.0, 0.0, 0.0, 0.0,"
2359  "0.0, 1.0, 0.0, 0.0,"
2360  "0.0, 0.0, 1.0, 0.0,"
2361  "0.0, 0.0, 0.0, 1.0;;"
2362  "}"
2363  "{CubeMesh}"
2364  "}"
2365  "AnimationSet AnimationSet0 {"
2366  "Animation Animation0 {"
2367  "{CubeFrame}"
2368  "AnimationKey {"
2369  "2;" /* DWORD keyType; */
2370  "9;" /* DWORD nKeys; */
2371  /* array TimedFloatKeys keys[nKeys]; */
2372  "10; 3; -100.0, 0.0, 0.0;;,"
2373  "20; 3; -75.0, 0.0, 0.0;;,"
2374  "30; 3; -50.0, 0.0, 0.0;;,"
2375  "40; 3; -25.5, 0.0, 0.0;;,"
2376  "50; 3; 0.0, 0.0, 0.0;;,"
2377  "60; 3; 25.5, 0.0, 0.0;;,"
2378  "70; 3; 50.0, 0.0, 0.0;;,"
2379  "80; 3; 75.5, 0.0, 0.0;;,"
2380  "90; 3; 100.0, 0.0, 0.0;;;"
2381  "}"
2382  "}"
2383  "}";
2384 
2386  /*________________________*/
2387  static const D3DXMATERIAL default_materials[] = {
2388  {
2389  {
2390  {0.5, 0.5, 0.5, 0.0}, /* Diffuse */
2391  {0.0, 0.0, 0.0, 0.0}, /* Ambient */
2392  {0.5, 0.5, 0.5, 0.0}, /* Specular */
2393  {0.0, 0.0, 0.0, 0.0}, /* Emissive */
2394  0.0, /* Power */
2395  },
2396  NULL, /* pTextureFilename */
2397  }
2398  };
2399  HRESULT hr;
2400  IDirect3DDevice9 *device = NULL;
2401  ID3DXMesh *mesh = NULL;
2402  D3DXFRAME *frame_hier = NULL;
2404  struct test_context *test_context;
2405  ID3DXAnimationController *controller;
2406 
2407  if (!(test_context = new_test_context()))
2408  {
2409  skip("Couldn't create test context\n");
2410  return;
2411  }
2413 
2414  hr = D3DXLoadMeshHierarchyFromXInMemory(NULL, sizeof(simple_xfile) - 1,
2415  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2416  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2417 
2418  hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, 0,
2419  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2420  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2421 
2422  hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2423  D3DXMESH_MANAGED, NULL, &alloc_hier, NULL, &frame_hier, NULL);
2424  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2425 
2426  hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2427  D3DXMESH_MANAGED, device, NULL, NULL, &frame_hier, NULL);
2428  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2429 
2430  hr = D3DXLoadMeshHierarchyFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1,
2431  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2432  ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2433 
2434  hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2436  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2437 
2438  hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2439  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2440  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2441  if (SUCCEEDED(hr)) {
2443 
2444  ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2445  D3DXMatrixIdentity(&transform);
2447 
2448  ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2449  ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2450  D3DXMESHTYPE_MESH, container->MeshData.Type);
2451  mesh = U(container->MeshData).pMesh;
2452  check_vertex_buffer(mesh, simple_vertex_buffer, ARRAY_SIZE(simple_vertex_buffer), simple_fvf);
2453  check_index_buffer(mesh, simple_index_buffer, ARRAY_SIZE(simple_index_buffer), sizeof(*simple_index_buffer));
2454  check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2455  check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2456  check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2457  hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2458  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2459  frame_hier = NULL;
2460  }
2461 
2462  controller = (ID3DXAnimationController *)0xdeadbeef;
2463  hr = D3DXLoadMeshHierarchyFromXInMemory(box_anim_xfile, sizeof(box_anim_xfile) - 1,
2464  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2465  todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2466  if (SUCCEEDED(hr))
2467  {
2468  ok(controller != NULL, "Animation Controller NULL.\n");
2469 
2470  hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2471  ok(hr == D3D_OK, "Expected D3D_OK, got %#x.\n", hr);
2472  if (controller)
2473  controller->lpVtbl->Release(controller);
2474 
2475  frame_hier = NULL;
2476  }
2477 
2478  controller = (ID3DXAnimationController *)0xdeadbeef;
2479  hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1,
2480  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, &controller);
2481  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2482  if (SUCCEEDED(hr))
2483  {
2485 
2486  ok(!controller, "Animation Controller returned.\n");
2487  ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2488  D3DXMatrixIdentity(&transform);
2490 
2491  ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2492  ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2493  D3DXMESHTYPE_MESH, container->MeshData.Type);
2494  mesh = U(container->MeshData).pMesh;
2495  check_vertex_buffer(mesh, box_vertex_buffer, ARRAY_SIZE(box_vertex_buffer), box_fvf);
2496  check_index_buffer(mesh, box_index_buffer, ARRAY_SIZE(box_index_buffer), sizeof(*box_index_buffer));
2497  check_materials(container->pMaterials, container->NumMaterials, box_materials, ARRAY_SIZE(box_materials));
2498  check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2499  check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2500  hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2501  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2502  frame_hier = NULL;
2503  }
2504 
2505  hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1,
2506  D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2507  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2508  if (SUCCEEDED(hr)) {
2510  int i;
2511 
2512  ok(!strcmp(frame_hier->Name, ""), "Expected '', got '%s'\n", frame_hier->Name);
2513  /* last frame transform replaces the first */
2514  D3DXMatrixIdentity(&transform);
2515  U(transform).m[3][2] = 3.0;
2517 
2518  for (i = 0; i < 3; i++) {
2519  ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2520  ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2521  D3DXMESHTYPE_MESH, container->MeshData.Type);
2522  mesh = U(container->MeshData).pMesh;
2523  check_vertex_buffer(mesh, framed_vertex_buffers[i], ARRAY_SIZE(framed_vertex_buffers[0]), framed_fvf);
2524  check_index_buffer(mesh, framed_index_buffer, ARRAY_SIZE(framed_index_buffer), sizeof(*framed_index_buffer));
2525  check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2526  check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2527  check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2528  container = container->pNextMeshContainer;
2529  }
2530  ok(container == NULL, "Expected NULL, got %p\n", container);
2531  hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2532  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2533  frame_hier = NULL;
2534  }
2535 
2536 
2538  device, NULL, NULL, NULL, NULL, &mesh);
2539  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2540 
2541  hr = D3DXLoadMeshFromXInMemory(NULL, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2542  device, NULL, NULL, NULL, NULL, &mesh);
2543  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2544 
2545  hr = D3DXLoadMeshFromXInMemory(simple_xfile, 0, D3DXMESH_MANAGED,
2546  device, NULL, NULL, NULL, NULL, &mesh);
2547  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2548 
2549  hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2550  device, NULL, NULL, NULL, NULL, NULL);
2551  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2552 
2553  hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2554  NULL, NULL, NULL, NULL, NULL, &mesh);
2555  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2556 
2557  hr = D3DXLoadMeshFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1, D3DXMESH_MANAGED,
2558  device, NULL, NULL, NULL, NULL, &mesh);
2559  ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2560 
2561  hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2562  device, NULL, NULL, NULL, NULL, &mesh);
2563  ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2564  if (SUCCEEDED(hr))
2565  IUnknown_Release(mesh);
2566 
2567  test_LoadMeshFromX(device, simple_xfile, simple_vertex_buffer, simple_fvf, simple_index_buffer, default_materials, TRUE);
2568  test_LoadMeshFromX(device, box_xfile, box_vertex_buffer, box_fvf, box_index_buffer, box_materials, TRUE);
2569  test_LoadMeshFromX(device, framed_xfile, merged_vertex_buffer, framed_fvf, merged_index_buffer, default_materials, FALSE);
2570 
2572 }
2573 
2574 static BOOL compute_box(struct mesh *mesh, float width, float height, float depth)
2575 {
2576  unsigned int i, face;
2577  static const D3DXVECTOR3 unit_box[] =
2578  {
2579  {-1.0f, -1.0f, -1.0f}, {-1.0f, -1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, -1.0f},
2580  {-1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, -1.0f},
2581  { 1.0f, 1.0f, -1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, -1.0f, 1.0f}, { 1.0f, -1.0f, -1.0f},
2582  {-1.0f, -1.0f, 1.0f}, {-1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, 1.0f},
2583  {-1.0f, -1.0f, 1.0f}, { 1.0f, -1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f},
2584  {-1.0f, -1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, { 1.0f, 1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}
2585  };
2586  static const D3DXVECTOR3 normals[] =
2587  {
2588  {-1.0f, 0.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f},
2589  { 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, -1.0f}
2590  };
2591 
2592  if (!new_mesh(mesh, 24, 12))
2593  {
2594  return FALSE;
2595  }
2596 
2597  width /= 2.0f;
2598  height /= 2.0f;
2599  depth /= 2.0f;
2600 
2601  for (i = 0; i < 24; i++)
2602  {
2603  mesh->vertices[i].position.x = width * unit_box[i].x;
2604  mesh->vertices[i].position.y = height * unit_box[i].y;
2605  mesh->vertices[i].position.z = depth * unit_box[i].z;
2606  mesh->vertices[i].normal.x = normals[i / 4].x;
2607  mesh->vertices[i].normal.y = normals[i / 4].y;
2608  mesh->vertices[i].normal.z = normals[i / 4].z;
2609  }
2610 
2611  face = 0;
2612  for (i = 0; i < 12; i++)
2613  {
2614  mesh->faces[i][0] = face++;
2615  mesh->faces[i][1] = face++;
2616  mesh->faces[i][2] = (i % 2) ? face - 4 : face;
2617  }
2618 
2619  return TRUE;
2620 }
2621 
2622 static void test_box(IDirect3DDevice9 *device, float width, float height, float depth)
2623 {
2624  HRESULT hr;
2625  ID3DXMesh *box;
2626  struct mesh mesh;
2627  char name[256];
2628 
2630  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2631  if (hr != D3D_OK)
2632  {
2633  skip("Couldn't create box\n");
2634  return;
2635  }
2636 
2637  if (!compute_box(&mesh, width, height, depth))
2638  {
2639  skip("Couldn't create mesh\n");
2640  box->lpVtbl->Release(box);
2641  return;
2642  }
2643 
2645 
2646  sprintf(name, "box (%g, %g, %g)", width, height, depth);
2647  compare_mesh(name, box, &mesh);
2648 
2649  free_mesh(&mesh);
2650 
2651  box->lpVtbl->Release(box);
2652 }
2653 static void D3DXCreateBoxTest(void)
2654 {
2655  HRESULT hr;
2656  IDirect3DDevice9* device;
2657  ID3DXMesh* box;
2658  ID3DXBuffer* ppBuffer;
2659  DWORD *buffer;
2660  static const DWORD adjacency[36]=
2661  {6, 9, 1, 2, 10, 0,
2662  1, 9, 3, 4, 10, 2,
2663  3, 8, 5, 7, 11, 4,
2664  0, 11, 7, 5, 8, 6,
2665  7, 4, 9, 2, 0, 8,
2666  1, 3, 11, 5, 6, 10};
2667  unsigned int i;
2668  struct test_context *test_context;
2669 
2670  if (!(test_context = new_test_context()))
2671  {
2672  skip("Couldn't create test context\n");
2673  return;
2674  }
2676 
2677  hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
2678  ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2679 
2680  hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
2681  ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2682 
2683  hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
2684  ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2685 
2686  hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
2687  ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2688 
2689  hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
2690  ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2691 
2692  ppBuffer = NULL;
2693  hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
2694  ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2695 
2697  for(i=0; i<36; i++)
2698  ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
2699 
2700  box->lpVtbl->Release(box);
2701  ID3DXBuffer_Release(ppBuffer);
2702 
2703  test_box(device, 10.9f, 20.0f, 4.9f);
2704 
2706 }
2707 
2708 static BOOL compute_polygon(struct mesh *mesh, float length, unsigned int sides)
2709 {
2710  unsigned int i;
2711  float angle, scale;
2712 
2713  if (!new_mesh(mesh, sides + 1, sides))
2714  return FALSE;
2715 
2716  angle = D3DX_PI / sides;
2717  scale = 0.5f * length / sinf(angle);
2718  angle *= 2.0f;
2719 
2720  mesh->vertices[0].position.x = 0.0f;
2721  mesh->vertices[0].position.y = 0.0f;
2722  mesh->vertices[0].position.z = 0.0f;
2723  mesh->vertices[0].normal.x = 0.0f;
2724  mesh->vertices[0].normal.y = 0.0f;
2725  mesh->vertices[0].normal.z = 1.0f;
2726 
2727  for (i = 0; i < sides; ++i)
2728  {
2729  mesh->vertices[i + 1].position.x = cosf(angle * i) * scale;
2730  mesh->vertices[i + 1].position.y = sinf(angle * i) * scale;
2731  mesh->vertices[i + 1].position.z = 0.0f;
2732  mesh->vertices[i + 1].normal.x = 0.0f;
2733  mesh->vertices[i + 1].normal.y = 0.0f;
2734  mesh->vertices[i + 1].normal.z = 1.0f;
2735 
2736  mesh->faces[i][0] = 0;
2737  mesh->faces[i][1] = i + 1;
2738  mesh->faces[i][2] = i + 2;
2739  }
2740 
2741  mesh->faces[sides - 1][2] = 1;
2742 
2743  return TRUE;
2744 }
2745 
2746 static void test_polygon(IDirect3DDevice9 *device, float length, unsigned int sides)
2747 {
2748  HRESULT hr;
2749  ID3DXMesh *polygon;
2750  struct mesh mesh;
2751  char name[64];
2752 
2753  hr = D3DXCreatePolygon(device, length, sides, &polygon, NULL);
2754  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2755  if (hr != D3D_OK)
2756  {
2757  skip("Couldn't create polygon\n");
2758  return;
2759  }
2760 
2761  if (!compute_polygon(&mesh, length, sides))
2762  {
2763  skip("Couldn't create mesh\n");
2764  polygon->lpVtbl->Release(polygon);
2765  return;
2766  }
2767 
2769 
2770  sprintf(name, "polygon (%g, %u)", length, sides);
2771  compare_mesh(name, polygon, &mesh);
2772 
2773  free_mesh(&mesh);
2774 
2775  polygon->lpVtbl->Release(polygon);
2776 }
2777 
2778 static void D3DXCreatePolygonTest(void)
2779 {
2780  HRESULT hr;
2781  IDirect3DDevice9 *device;
2782  ID3DXMesh *polygon;
2783  ID3DXBuffer *adjacency;
2784  DWORD (*buffer)[3], buffer_size;
2785  unsigned int i;
2786  struct test_context *test_context;
2787 
2788  if (!(test_context = new_test_context()))
2789  {
2790  skip("Couldn't create test context\n");
2791  return;
2792  }
2794 
2795  hr = D3DXCreatePolygon(device, 2.0f, 11, NULL, &adjacency);
2796  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2797 
2798  hr = D3DXCreatePolygon(NULL, 2.0f, 11, &polygon, &adjacency);
2799  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2800 
2801  hr = D3DXCreatePolygon(device, -2.0f, 11, &polygon, &adjacency);
2802  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2803 
2804  polygon = (void *)0xdeadbeef;
2805  adjacency = (void *)0xdeadbeef;
2806  hr = D3DXCreatePolygon(device, 2.0f, 0, &polygon, &adjacency);
2807  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2808  ok(polygon == (void *)0xdeadbeef, "Polygon was changed to %p\n", polygon);
2809  ok(adjacency == (void *)0xdeadbeef, "Adjacency was changed to %p\n", adjacency);
2810 
2811  hr = D3DXCreatePolygon(device, 2.0f, 2, &polygon, &adjacency);
2812  ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2813 
2814  adjacency = NULL;
2815  hr = D3DXCreatePolygon(device, 3.0f, 11, &polygon, &adjacency);
2816  ok(hr == D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2817 
2819  ok(buffer_size == 33 * sizeof(DWORD), "Wrong adjacency buffer size %u\n", buffer_size);
2820 
2821  buffer = ID3DXBuffer_GetBufferPointer(adjacency);
2822  for (i = 0; i < 11; ++i)
2823  {
2824  ok(buffer[i][0] == (i + 10) % 11, "Wrong adjacency[%d][0] = %u\n", i, buffer[i][0]);
2825  ok(buffer[i][1] == ~0U, "Wrong adjacency[%d][1] = %u\n", i, buffer[i][1]);
2826  ok(buffer[i][2] == (i + 1) % 11, "Wrong adjacency[%d][2] = %u\n", i, buffer[i][2]);
2827  }
2828 
2829  polygon->lpVtbl->Release(polygon);
2830  ID3DXBuffer_Release(adjacency);
2831 
2832  test_polygon(device, 2.0f, 3);
2833  test_polygon(device, 10.0f, 3);
2834  test_polygon(device, 10.0f, 5);
2835  test_polygon(device, 10.0f, 10);
2836  test_polygon(device, 20.0f, 10);
2837  test_polygon(device, 20.0f, 32000);
2838 
2840 }
2841 
2842 struct sincos_table
2843 {
2844  float *sin;
2845  float *cos;
2846 };
2847 
2849 {
2852 }
2853 
2854 /* pre compute sine and cosine tables; caller must free */
2855 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
2856 {
2857  float angle;
2858  int i;
2859 
2860  sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2861  if (!sincos_table->sin)
2862  {
2863  return FALSE;
2864  }
2865  sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2866  if (!sincos_table->cos)
2867  {
2869  return FALSE;
2870  }
2871 
2872  angle = angle_start;
2873  for (i = 0; i < n; i++)
2874  {
2875  sincos_table->sin[i] = sin(angle);
2876  sincos_table->cos[i] = cos(angle);
2877  angle += angle_step;
2878  }
2879 
2880  return TRUE;
2881 }
2882 
2883 static WORD vertex_index(UINT slices, int slice, int stack)
2884 {
2885  return stack*slices+slice+1;
2886 }
2887 
2888 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
2889 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
2890 {
2891  float theta_step, theta_start;
2892  struct sincos_table theta;
2893  float phi_step, phi_start;
2894  struct sincos_table phi;
2895  DWORD number_of_vertices, number_of_faces;
2896  DWORD vertex, face;
2897  int slice, stack;
2898 
2899  /* theta = angle on xy plane wrt x axis */
2900  theta_step = D3DX_PI / stacks;
2901  theta_start = theta_step;
2902 
2903  /* phi = angle on xz plane wrt z axis */
2904  phi_step = -2 * D3DX_PI / slices;
2905  phi_start = D3DX_PI / 2;
2906 
2907  if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
2908  {
2909  return FALSE;
2910  }
2911  if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
2912  {
2913  free_sincos_table(&theta);
2914  return FALSE;
2915  }
2916 
2917  number_of_vertices = 2 + slices * (stacks-1);
2918  number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
2919 
2920  if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2921  {
2922  free_sincos_table(&phi);
2923  free_sincos_table(&theta);
2924  return FALSE;
2925  }
2926 
2927  vertex = 0;
2928  face = 0;
2929 
2930  mesh->vertices[vertex].normal.x = 0.0f;
2931  mesh->vertices[vertex].normal.y = 0.0f;
2932  mesh->vertices[vertex].normal.z = 1.0f;
2933  mesh->vertices[vertex].position.x = 0.0f;
2934  mesh->vertices[vertex].position.y = 0.0f;
2935  mesh->vertices[vertex].position.z = radius;
2936  vertex++;
2937 
2938  for (stack = 0; stack < stacks - 1; stack++)
2939  {
2940  for (slice = 0; slice < slices; slice++)
2941  {
2942  mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
2943  mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
2944  mesh->vertices[vertex].normal.z = theta.cos[stack];
2945  mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
2946  mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
2947  mesh->vertices[vertex].position.z = radius * theta.cos[stack];
2948  vertex++;
2949 
2950  if (slice > 0)
2951  {
2952  if (stack == 0)
2953  {
2954  /* top stack is triangle fan */
2955  mesh->faces[face][0] = 0;
2956  mesh->faces[face][1] = slice + 1;
2957  mesh->faces[face][2] = slice;
2958  face++;
2959  }
2960  else
2961  {
2962  /* stacks in between top and bottom are quad strips */
2963  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2964  mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2965  mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2966  face++;
2967 
2968  mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2969  mesh->faces[face][1] = vertex_index(slices, slice, stack);
2970  mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2971  face++;
2972  }
2973  }
2974  }
2975 
2976  if (stack == 0)
2977  {
2978  mesh->faces[face][0] = 0;
2979  mesh->faces[face][1] = 1;
2980  mesh->faces[face][2] = slice;
2981  face++;
2982  }
2983  else
2984  {
2985  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2986  mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2987  mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2988  face++;
2989 
2990  mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2991  mesh->faces[face][1] = vertex_index(slices, 0, stack);
2992  mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2993  face++;
2994  }
2995  }
2996 
2997  mesh->vertices[vertex].position.x = 0.0f;
2998  mesh->vertices[vertex].position.y = 0.0f;
2999  mesh->vertices[vertex].position.z = -radius;
3000  mesh->vertices[vertex].normal.x = 0.0f;
3001  mesh->vertices[vertex].normal.y = 0.0f;
3002  mesh->vertices[vertex].normal.z = -1.0f;
3003 
3004  /* bottom stack is triangle fan */
3005  for (slice = 1; slice < slices; slice++)
3006  {
3007  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3008  mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
3009  mesh->faces[face][2] = vertex;
3010  face++;
3011  }
3012 
3013  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3014  mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
3015  mesh->faces[face][2] = vertex;
3016 
3017  free_sincos_table(&phi);
3018  free_sincos_table(&theta);
3019 
3020  return TRUE;
3021 }
3022 
3023 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
3024 {
3025  HRESULT hr;
3026  ID3DXMesh *sphere;
3027  struct mesh mesh;
3028  char name[256];
3029 
3030  hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
3031  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3032  if (hr != D3D_OK)
3033  {
3034  skip("Couldn't create sphere\n");
3035  return;
3036  }
3037 
3038  if (!compute_sphere(&mesh, radius, slices, stacks))
3039  {
3040  skip("Couldn't create mesh\n");
3041  sphere->lpVtbl->Release(sphere);
3042  return;
3043  }
3044 
3046 
3047  sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
3048  compare_mesh(name, sphere, &mesh);
3049 
3050  free_mesh(&mesh);
3051 
3052  sphere->lpVtbl->Release(sphere);
3053 }
3054 
3055 static void D3DXCreateSphereTest(void)
3056 {
3057  HRESULT hr;
3058  IDirect3DDevice9* device;
3059  ID3DXMesh* sphere = NULL;
3060  struct test_context *test_context;
3061 
3062  hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
3063  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3064 
3065  hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
3066  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3067 
3068  hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
3069  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3070 
3071  hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
3072  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3073 
3074  if (!(test_context = new_test_context()))
3075  {
3076  skip("Couldn't create test context\n");
3077  return;
3078  }
3080 
3081  hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
3082  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3083 
3084  hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
3085  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3086 
3087  hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
3088  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3089 
3090  hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
3091  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3092 
3093  test_sphere(device, 0.0f, 2, 2);
3094  test_sphere(device, 1.0f, 2, 2);
3095  test_sphere(device, 1.0f, 3, 2);
3096  test_sphere(device, 1.0f, 4, 4);
3097  test_sphere(device, 1.0f, 3, 4);
3098  test_sphere(device, 5.0f, 6, 7);
3099  test_sphere(device, 10.0f, 11, 12);
3100 
3102 }
3103 
3104 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3105 {
3106  float theta_step, theta_start;
3107  struct sincos_table theta;
3108  FLOAT delta_radius, radius, radius_step;
3109  FLOAT z, z_step, z_normal;
3110  DWORD number_of_vertices, number_of_faces;
3111  DWORD vertex, face;
3112  int slice, stack;
3113 
3114  /* theta = angle on xy plane wrt x axis */
3115  theta_step = -2 * D3DX_PI / slices;
3116  theta_start = D3DX_PI / 2;
3117 
3118  if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
3119  {
3120  return FALSE;
3121  }
3122 
3123  number_of_vertices = 2 + (slices * (3 + stacks));
3124  number_of_faces = 2 * slices + stacks * (2 * slices);
3125 
3126  if (!new_mesh(mesh, number_of_vertices, number_of_faces))
3127  {
3128  free_sincos_table(&theta);
3129  return FALSE;
3130  }
3131 
3132  vertex = 0;
3133  face = 0;
3134 
3135  delta_radius = radius1 - radius2;
3136  radius = radius1;
3137  radius_step = delta_radius / stacks;
3138 
3139  z = -length / 2;
3140  z_step = length / stacks;
3141  z_normal = delta_radius / length;
3142  if (isnan(z_normal))
3143  {
3144  z_normal = 0.0f;
3145  }
3146 
3147  mesh->vertices[vertex].normal.x = 0.0f;
3148  mesh->vertices[vertex].normal.y = 0.0f;
3149  mesh->vertices[vertex].normal.z = -1.0f;
3150  mesh->vertices[vertex].position.x = 0.0f;
3151  mesh->vertices[vertex].position.y = 0.0f;
3152  mesh->vertices[vertex++].position.z = z;
3153 
3154  for (slice = 0; slice < slices; slice++, vertex++)
3155  {
3156  mesh->vertices[vertex].normal.x = 0.0f;
3157  mesh->vertices[vertex].normal.y = 0.0f;
3158  mesh->vertices[vertex].normal.z = -1.0f;
3159  mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3160  mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3161  mesh->vertices[vertex].position.z = z;
3162 
3163  if (slice > 0)
3164  {
3165  mesh->faces[face][0] = 0;
3166  mesh->faces[face][1] = slice;
3167  mesh->faces[face++][2] = slice + 1;
3168  }
3169  }
3170 
3171  mesh->faces[face][0] = 0;
3172  mesh->faces[face][1] = slice;
3173  mesh->faces[face++][2] = 1;
3174 
3175  for (stack = 1; stack <= stacks+1; stack++)
3176  {
3177  for (slice = 0; slice < slices; slice++, vertex++)
3178  {
3179  mesh->vertices[vertex].normal.x = theta.cos[slice];
3180  mesh->vertices[vertex].normal.y = theta.sin[slice];
3181  mesh->vertices[vertex].normal.z = z_normal;
3182  D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
3183  mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3184  mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3185  mesh->vertices[vertex].position.z = z;
3186 
3187  if (stack > 1 && slice > 0)
3188  {
3189  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3190  mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3191  mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
3192 
3193  mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
3194  mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3195  mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3196  }
3197  }
3198 
3199  if (stack > 1)
3200  {
3201  mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
3202  mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3203  mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
3204 
3205  mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
3206  mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
3207  mesh->faces[face++][2] = vertex_index(slices, 0, stack);
3208  }
3209 
3210  if (stack < stacks + 1)
3211  {
3212  z += z_step;
3213  radius -= radius_step;
3214  }
3215  }
3216 
3217  for (slice = 0; slice < slices; slice++, vertex++)
3218  {
3219  mesh->vertices[vertex].normal.x = 0.0f;
3220  mesh->vertices[vertex].normal.y = 0.0f;
3221  mesh->vertices[vertex].normal.z = 1.0f;
3222  mesh->vertices[vertex].position.x = radius * theta.cos[slice];
3223  mesh->vertices[vertex].position.y = radius * theta.sin[slice];
3224  mesh->vertices[vertex].position.z = z;
3225 
3226  if (slice > 0)
3227  {
3228  mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3229  mesh->faces[face][1] = number_of_vertices - 1;
3230  mesh->faces[face++][2] = vertex_index(slices, slice, stack);
3231  }
3232  }
3233 
3234  mesh->vertices[vertex].position.x = 0.0f;
3235  mesh->vertices[vertex].position.y = 0.0f;
3236  mesh->vertices[vertex].position.z = z;
3237  mesh->vertices[vertex].normal.x = 0.0f;
3238  mesh->vertices[vertex].normal.y = 0.0f;
3239  mesh->vertices[vertex].normal.z = 1.0f;
3240 
3241  mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
3242  mesh->faces[face][1] = number_of_vertices - 1;
3243  mesh->faces[face][2] = vertex_index(slices, 0, stack);
3244 
3245  free_sincos_table(&theta);
3246 
3247  return TRUE;
3248 }
3249 
3250 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
3251 {
3252  HRESULT hr;
3253  ID3DXMesh *cylinder;
3254  struct mesh mesh;
3255  char name[256];
3256 
3257  hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
3258  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3259  if (hr != D3D_OK)
3260  {
3261  skip("Couldn't create cylinder\n");
3262  return;
3263  }
3264 
3265  if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
3266  {
3267  skip("Couldn't create mesh\n");
3268  cylinder->lpVtbl->Release(cylinder);
3269  return;
3270  }
3271 
3273 
3274  sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
3276 
3277  free_mesh(&mesh);
3278 
3279  cylinder->lpVtbl->Release(cylinder);
3280 }
3281 
3282 static void D3DXCreateCylinderTest(void)
3283 {
3284  HRESULT hr;
3285  IDirect3DDevice9* device;
3286  ID3DXMesh* cylinder = NULL;
3287  struct test_context *test_context;
3288 
3289  hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
3290  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3291 
3292  hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3293  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3294 
3295  if (!(test_context = new_test_context()))
3296  {
3297  skip("Couldn't create test context\n");
3298  return;
3299  }
3301 
3302  hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3303  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3304 
3305  hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3306  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3307 
3308  if (SUCCEEDED(hr) && cylinder)
3309  {
3310  cylinder->lpVtbl->Release(cylinder);
3311  }
3312 
3313  hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
3314  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3315 
3316  hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
3317  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3318 
3319  if (SUCCEEDED(hr) && cylinder)
3320  {
3321  cylinder->lpVtbl->Release(cylinder);
3322  }
3323 
3324  hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
3325  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3326 
3327  /* Test with length == 0.0f succeeds */
3328  hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
3329  ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3330 
3331  if (SUCCEEDED(hr) && cylinder)
3332  {
3333  cylinder->lpVtbl->Release(cylinder);
3334  }
3335 
3336  hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
3337  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3338 
3339  hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
3340  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3341 
3342  hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
3343  ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3344 
3345  test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
3346  test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
3347  test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
3348  test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
3349  test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
3350  test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
3351 
3353 }
3354 
3355 static BOOL compute_torus(struct mesh *mesh, float innerradius, float outerradius, UINT sides, UINT rings)
3356 {
3357  float phi, phi_step, sin_phi, cos_phi;
3358  float theta, theta_step, sin_theta, cos_theta;
3359  unsigned int numvert, numfaces, i, j;
3360 
3361  numvert = sides * rings;
3362  numfaces = numvert * 2;
3363 
3364  if (!new_mesh(mesh, numvert, numfaces))
3365  return FALSE;
3366 
3367  phi_step = D3DX_PI / sides * 2.0f;
3368  theta_step = D3DX_PI / rings * -2.0f;
3369 
3370  theta = 0.0f;
3371 
3372  for (i = 0; i < rings; ++i)
3373  {
3374  phi = 0.0f;
3375 
3376  cos_theta = cosf(theta);
3377  sin_theta = sinf(theta);
3378 
3379  for (j = 0; j < sides; ++j)
3380  {
3381  sin_phi = sinf(phi);
3382  cos_phi = cosf(phi);
3383 
3384  mesh->vertices[i * sides + j].position.x = (innerradius * cos_phi + outerradius) * cos_theta;
3385  mesh->vertices[i * sides + j].position.y = (innerradius * cos_phi + outerradius) * sin_theta;
3386  mesh->vertices[i * sides + j].position.z = innerradius * sin_phi;
3387  mesh->vertices[i * sides + j].normal.x = cos_phi * cos_theta;
3388  mesh->vertices[i * sides + j].normal.y = cos_phi * sin_theta;
3389  mesh->vertices[i * sides + j].normal.z = sin_phi;
3390 
3391  phi += phi_step;
3392  }
3393 
3394  theta += theta_step;
3395  }
3396 
3397  for (i = 0; i < numfaces - sides * 2; ++i)
3398  {
3399  mesh->faces[i][0] = i % 2 ? i / 2 + sides : i / 2;
3400  mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3401  mesh->faces[i][2] = (i + 1) % (sides * 2) ? (i + 1) / 2 + sides : (i + 1) / 2;
3402  }
3403 
3404  for (j = 0; i < numfaces; ++i, ++j)
3405  {
3406  mesh->faces[i][0] = i % 2 ? j / 2 : i / 2;
3407  mesh->faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
3408  mesh->faces[i][2] = i == numfaces - 1 ? 0 : (j + 1) / 2;
3409  }
3410 
3411  return TRUE;
3412 }
3413 
3414 static void test_torus(IDirect3DDevice9 *device, float innerradius, float outerradius, UINT sides, UINT rings)
3415 {
3416  HRESULT hr;
3417  ID3DXMesh *torus;
3418  struct mesh mesh;
3419  char name[256];
3420 
3421  hr = D3DXCreateTorus(device, innerradius, outerradius, sides, rings, &torus, NULL);
3422  ok(hr == D3D_OK, "Got result %#x, expected 0 (D3D_OK)\n", hr);
3423  if (hr != D3D_OK)
3424  {
3425  skip("Couldn't create torus\n");
3426  return;
3427  }
3428 
3429  if (!compute_torus(&mesh, innerradius, outerradius, sides, rings))
3430  {
3431  skip("Couldn't create mesh\n");
3432  torus->lpVtbl->Release(torus);
3433  return;
3434  }
3435 
3437 
3438  sprintf(name, "torus (%g, %g, %u, %u)", innerradius, outerradius, sides, rings);
3439  compare_mesh(name, torus, &mesh);
3440 
3441  free_mesh(&mesh);
3442 
3443  torus->lpVtbl->Release(torus);
3444 }
3445 
3446 static void D3DXCreateTorusTest(void)
3447 {
3448  HRESULT hr;
3449  IDirect3DDevice9* device;
3450  ID3DXMesh* torus = NULL;
3451  struct test_context *test_context;
3452 
3453  if (!(test_context = new_test_context()))
3454  {
3455  skip("Couldn't create test context\n");
3456  return;
3457  }
3459 
3460  hr = D3DXCreateTorus(NULL, 0.0f, 0.0f, 3, 3, &torus, NULL);
3461  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3462 
3463  hr = D3DXCreateTorus(device, -1.0f, 0.0f, 3, 3, &torus, NULL);
3464  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3465 
3466  hr = D3DXCreateTorus(device, 0.0f, -1.0f, 3, 3, &torus, NULL);
3467  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3468 
3469  hr = D3DXCreateTorus(device, 0.0f, 0.0f, 2, 3, &torus, NULL);
3470  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3471 
3472  hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 2, &torus, NULL);
3473  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3474 
3475  hr = D3DXCreateTorus(device, 0.0f, 0.0f, 3, 3, NULL, NULL);
3476  ok(hr == D3DERR_INVALIDCALL, "Got result %#x, expected %#x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3477 
3478  test_torus(device, 0.0f, 0.0f, 3, 3);
3479  test_torus(device, 1.0f, 1.0f, 3, 3);
3480  test_torus(device, 1.0f, 1.0f, 32, 64);
3481  test_torus(device, 0.0f, 1.0f, 5, 5);
3482  test_torus(device, 1.0f, 0.0f, 5, 5);
3483  test_torus(device, 5.0f, 0.2f, 8, 8);
3484  test_torus(device, 0.2f, 1.0f, 60, 3);
3485  test_torus(device, 0.2f, 1.0f, 8, 70);
3486 
3488 }
3489 
3490 struct dynamic_array
3491 {
3492  int count, capacity;
3493  void *items;
3494 };
3495 
3502 };
3503 
3504 struct point2d
3505 {
3506  D3DXVECTOR2 pos;
3507  enum pointtype corner;
3508 };
3509 
3510 /* is a dynamic_array */
3511 struct outline
3512 {
3513  int count, capacity;
3514  struct point2d *items;
3515 };
3516 
3517 /* is a dynamic_array */
3518 struct outline_array
3519 {
3520  int count, capacity;
3521  struct outline *items;
3522 };
3523 
3524 struct glyphinfo
3525 {
3526  struct outline_array outlines;
3527  float offset_x;
3528 };
3529 
3530 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
3531 {
3532  if (count > array->capacity) {
3533  void *new_buffer;
3534  int new_capacity;
3535  if (array->items && array->capacity) {
3536  new_capacity = max(array->capacity * 2, count);
3537  new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
3538  } else {
3539  new_capacity = max(16, count);
3540  new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
3541  }
3542  if (!new_buffer)
3543  return FALSE;
3544  array->items = new_buffer;
3545  array->capacity = new_capacity;
3546  }
3547  return TRUE;
3548 }
3549 
3550 static struct point2d *add_point(struct outline *array)
3551 {
3552  struct point2d *item;
3553 
3554  if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3555  return NULL;
3556 
3557  item = &array->items[array->count++];
3558  ZeroMemory(item, sizeof(*item));
3559  return item;
3560 }
3561 
3562 static struct outline *add_outline(struct outline_array *array)
3563 {
3564  struct outline *item;
3565 
3566  if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3567  return NULL;
3568 
3569  item = &array->items[array->count++];
3570  ZeroMemory(item, sizeof(*item));
3571  return item;
3572 }
3573 
3574 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
3575 {
3577  while (count--) {
3578  D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
3579  pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
3580  pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
3581  pt++;
3582  }
3583  return ret;
3584 }
3585 
3587  const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
3588  float max_deviation)
3589 {
3590  D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
3591  float deviation;
3592 
3593  D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
3594  D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
3595  D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
3596 
3597  deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
3598  if (deviation < max_deviation) {
3599  struct point2d *pt = add_point(outline);
3600  if (!pt) return E_OUTOFMEMORY;
3601  pt->pos = *p2;
3602  pt->corner = POINTTYPE_CURVE;
3603  /* the end point is omitted because the end line merges into the next segment of
3604  * the split bezier curve, and the end of the split bezier curve is added outside
3605  * this recursive function. */
3606  } else {
3607  HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
3608  if (hr != S_OK) return hr;
3609  hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
3610  if (hr != S_OK) return hr;
3611  }
3612 
3613  return S_OK;
3614 }
3615 
3616 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
3617 {
3618  /* dot product = cos(theta) */
3619  return D3DXVec2Dot(dir1, dir2) > cos_theta;
3620 }
3621 
3622 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
3623 {
3624  return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
3625 }
3626 
3628  int pt_index,
3629  const D3DXVECTOR2 *nextpt,
3630  BOOL to_curve)
3631 {
3632  D3DXVECTOR2 curdir, lastdir;
3633  struct point2d *prevpt, *pt;
3634  BOOL ret = FALSE;
3635  const float cos_half = cos(D3DXToRadian(0.5f));
3636 
3637  pt = &outline->items[pt_index];
3638  pt_index = (pt_index - 1 + outline->count) % outline->count;
3639  prevpt = &outline->items[pt_index];
3640 
3641  if (to_curve)
3643 
3644  if (outline->count < 2)
3645  return FALSE;
3646 
3647  /* remove last point if the next line continues the last line */
3648  unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3649  unit_vec2(&curdir, &pt->pos, nextpt);
3650  if (is_direction_similar(&lastdir, &curdir, cos_half))
3651  {
3652  outline->count--;
3653  if (pt->corner == POINTTYPE_CURVE_END)
3654  prevpt->corner = pt->corner;
3655  if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
3656  prevpt->corner = POINTTYPE_CURVE_MIDDLE;
3657  pt = prevpt;
3658 
3659  ret = TRUE;
3660  if (outline->count < 2)
3661  return ret;
3662 
3663  pt_index = (pt_index - 1 + outline->count) % outline->count;
3664  prevpt = &outline->items[pt_index];
3665  unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3666  unit_vec2(&curdir, &pt->pos, nextpt);
3667  }
3668  return ret;
3669 }
3670 
3671 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
3672  float