ReactOS 0.4.15-dev-5666-gc548b97
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 */
34static 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)
75static 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
97struct vertex
98{
101};
102
103typedef 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 */
121static 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};
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 }
164
165 return test_context;
166
167error:
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
197struct mesh
198{
201
204
207};
208
209static void free_mesh(struct mesh *mesh)
210{
213}
214
215static 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
235static 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
382static 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
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
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
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
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
594static 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
610static 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
643static 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
656static 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
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 {{
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 {{
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 };
908 }
909 {
910 const D3DVERTEXELEMENT9 decl[] =
911 {
914 D3DDECL_END(),
915 };
918 }
919 {
920 const D3DVERTEXELEMENT9 decl[] =
921 {
925 D3DDECL_END(),
926 };
929 }
930 /* Test a declaration that can't be converted to an FVF. */
931 {
932 const D3DVERTEXELEMENT9 decl[] =
933 {
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 {
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 {
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
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 |
1104 D3DFVF_TEX8 |
1112 D3DFVF_TEXCOORDSIZE4(7), 180);
1113}
1114
1115static 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
1202static 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
1408static 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)
1529static 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)
1631static 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)
1666static 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
1678static 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)
1687static 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)
1713static 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)
1744static 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
1818static 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
1827static 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
1837static 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;
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;
1999error:
2001 return E_OUTOFMEMORY;
2002}
2003
2004static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
2009};
2010static 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);
2016static 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
2053static 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
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
2574static 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
2622static 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);
2648
2649 free_mesh(&mesh);
2650
2651 box->lpVtbl->Release(box);
2652}
2653static 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
2708static 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
2746static 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
2778static 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
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
2842struct sincos_table
2843{
2844 float *sin;
2845 float *cos;
2846};
2847
2849{
2852}
2853
2854/* pre compute sine and cosine tables; caller must free */
2855static 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
2861 if (!sincos_table->sin)
2862 {
2863 return FALSE;
2864 }
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
2883static 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 */
2889static 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
3023static 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
3055static 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
3104static 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;
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
3250static 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
3282static 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
3355static 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
3414static 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