d3dx9: Implemented ConvertPointRepsToAdjacency.
[wine/multimedia.git] / dlls / d3dx9_36 / tests / mesh.c
blob39c78e634a17de9059f40522d67c1b2f8003ac8e
1 /*
2 * Copyright 2008 David Adam
3 * Copyright 2008 Luis Busquets
4 * Copyright 2009 Henri Verbeet for CodeWeavers
5 * Copyright 2011 Michael Mc Donnell
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.
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.
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
22 #define COBJMACROS
23 #include <stdio.h>
24 #include <float.h>
25 #include "wine/test.h"
26 #include "d3dx9.h"
28 /* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose
29 * function call traces of ID3DXAllocateHierarchy callbacks. */
30 #define TRACECALLBACK if(winetest_debug > 1) trace
32 #define admitted_error 0.0001f
34 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
36 #define compare_vertex_sizes(type, exp) \
37 got=D3DXGetFVFVertexSize(type); \
38 ok(got==exp, "Expected: %d, Got: %d\n", exp, got);
40 #define compare_float(got, exp) \
41 do { \
42 float _got = (got); \
43 float _exp = (exp); \
44 ok(_got == _exp, "Expected: %g, Got: %g\n", _exp, _got); \
45 } while (0)
47 static BOOL compare(FLOAT u, FLOAT v)
49 return (fabs(u-v) < admitted_error);
52 static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v)
54 return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
57 #define check_floats(got, exp, dim) check_floats_(__LINE__, "", got, exp, dim)
58 static void check_floats_(int line, const char *prefix, const float *got, const float *exp, int dim)
60 int i;
61 char exp_buffer[256] = "";
62 char got_buffer[256] = "";
63 char *exp_buffer_ptr = exp_buffer;
64 char *got_buffer_ptr = got_buffer;
65 BOOL equal = TRUE;
67 for (i = 0; i < dim; i++) {
68 if (i) {
69 exp_buffer_ptr += sprintf(exp_buffer_ptr, ", ");
70 got_buffer_ptr += sprintf(got_buffer_ptr, ", ");
72 equal = equal && compare(*exp, *got);
73 exp_buffer_ptr += sprintf(exp_buffer_ptr, "%g", *exp);
74 got_buffer_ptr += sprintf(got_buffer_ptr, "%g", *got);
75 exp++, got++;
77 ok_(__FILE__,line)(equal, "%sExpected (%s), got (%s)", prefix, exp_buffer, got_buffer);
80 struct vertex
82 D3DXVECTOR3 position;
83 D3DXVECTOR3 normal;
86 typedef WORD face[3];
88 static BOOL compare_face(face a, face b)
90 return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
93 struct test_context
95 HWND hwnd;
96 IDirect3D9 *d3d;
97 IDirect3DDevice9 *device;
100 /* Initializes a test context struct. Use it to initialize DirectX.
102 * Returns NULL if an error occurred.
104 static struct test_context *new_test_context(void)
106 HRESULT hr;
107 HWND hwnd = NULL;
108 IDirect3D9 *d3d = NULL;
109 IDirect3DDevice9 *device = NULL;
110 D3DPRESENT_PARAMETERS d3dpp = {0};
111 struct test_context *test_context;
113 hwnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
114 if (!hwnd)
116 skip("Couldn't create application window\n");
117 goto error;
120 d3d = Direct3DCreate9(D3D_SDK_VERSION);
121 if (!d3d)
123 skip("Couldn't create IDirect3D9 object\n");
124 goto error;
127 memset(&d3dpp, 0, sizeof(d3dpp));
128 d3dpp.Windowed = TRUE;
129 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
130 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
131 D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
132 if (FAILED(hr))
134 skip("Couldn't create IDirect3DDevice9 object %#x\n", hr);
135 goto error;
138 test_context = HeapAlloc(GetProcessHeap(), 0, sizeof(*test_context));
139 if (!test_context)
141 skip("Couldn't allocate memory for test_context\n");
142 goto error;
144 test_context->hwnd = hwnd;
145 test_context->d3d = d3d;
146 test_context->device = device;
148 return test_context;
150 error:
151 if (device)
152 IDirect3DDevice9_Release(device);
154 if (d3d)
155 IDirect3D9_Release(d3d);
157 if (hwnd)
158 DestroyWindow(hwnd);
160 return NULL;
163 static void free_test_context(struct test_context *test_context)
165 if (!test_context)
166 return;
168 if (test_context->device)
169 IDirect3DDevice9_Release(test_context->device);
171 if (test_context->d3d)
172 IDirect3D9_Release(test_context->d3d);
174 if (test_context->hwnd)
175 DestroyWindow(test_context->hwnd);
177 HeapFree(GetProcessHeap(), 0, test_context);
180 struct mesh
182 DWORD number_of_vertices;
183 struct vertex *vertices;
185 DWORD number_of_faces;
186 face *faces;
188 DWORD fvf;
189 UINT vertex_size;
192 static void free_mesh(struct mesh *mesh)
194 HeapFree(GetProcessHeap(), 0, mesh->faces);
195 HeapFree(GetProcessHeap(), 0, mesh->vertices);
198 static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
200 mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
201 if (!mesh->vertices)
203 return FALSE;
205 mesh->number_of_vertices = number_of_vertices;
207 mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
208 if (!mesh->faces)
210 HeapFree(GetProcessHeap(), 0, mesh->vertices);
211 return FALSE;
213 mesh->number_of_faces = number_of_faces;
215 return TRUE;
218 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
220 HRESULT hr;
221 DWORD number_of_vertices, number_of_faces;
222 IDirect3DVertexBuffer9 *vertex_buffer;
223 IDirect3DIndexBuffer9 *index_buffer;
224 D3DVERTEXBUFFER_DESC vertex_buffer_description;
225 D3DINDEXBUFFER_DESC index_buffer_description;
226 struct vertex *vertices;
227 face *faces;
228 int expected, i;
230 number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
231 ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
232 name, number_of_vertices, mesh->number_of_vertices);
234 number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
235 ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
236 name, number_of_faces, mesh->number_of_faces);
238 /* vertex buffer */
239 hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
240 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
242 if (hr != D3D_OK)
244 skip("Couldn't get vertex buffer\n");
246 else
248 hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
249 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
251 if (hr != D3D_OK)
253 skip("Couldn't get vertex buffer description\n");
255 else
257 ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
258 name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
259 ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
260 name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
261 ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
262 ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
263 name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
264 ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
265 name, vertex_buffer_description.FVF, mesh->fvf);
266 if (mesh->fvf == 0)
268 expected = number_of_vertices * mesh->vertex_size;
270 else
272 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
274 ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
275 name, vertex_buffer_description.Size, expected);
278 /* specify offset and size to avoid potential overruns */
279 hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
280 (LPVOID *)&vertices, D3DLOCK_DISCARD);
281 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
283 if (hr != D3D_OK)
285 skip("Couldn't lock vertex buffer\n");
287 else
289 for (i = 0; i < number_of_vertices; i++)
291 ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
292 "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
293 vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
294 mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
295 ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
296 "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
297 vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
298 mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
301 IDirect3DVertexBuffer9_Unlock(vertex_buffer);
304 IDirect3DVertexBuffer9_Release(vertex_buffer);
307 /* index buffer */
308 hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
309 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
311 if (!index_buffer)
313 skip("Couldn't get index buffer\n");
315 else
317 hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
318 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
320 if (hr != D3D_OK)
322 skip("Couldn't get index buffer description\n");
324 else
326 ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
327 name, index_buffer_description.Format, D3DFMT_INDEX16);
328 ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
329 name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
330 todo_wine ok(index_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, index_buffer_description.Usage, 0);
331 ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
332 name, index_buffer_description.Pool, D3DPOOL_MANAGED);
333 expected = number_of_faces * sizeof(WORD) * 3;
334 ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
335 name, index_buffer_description.Size, expected);
338 /* specify offset and size to avoid potential overruns */
339 hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
340 (LPVOID *)&faces, D3DLOCK_DISCARD);
341 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
343 if (hr != D3D_OK)
345 skip("Couldn't lock index buffer\n");
347 else
349 for (i = 0; i < number_of_faces; i++)
351 ok(compare_face(faces[i], mesh->faces[i]),
352 "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
353 faces[i][0], faces[i][1], faces[i][2],
354 mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
357 IDirect3DIndexBuffer9_Unlock(index_buffer);
360 IDirect3DIndexBuffer9_Release(index_buffer);
364 static void D3DXBoundProbeTest(void)
366 BOOL result;
367 D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
368 FLOAT radius;
370 /*____________Test the Box case___________________________*/
371 bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
372 top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
374 raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
375 rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
376 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
377 ok(result == TRUE, "expected TRUE, received FALSE\n");
379 raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
380 rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
381 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
382 ok(result == FALSE, "expected FALSE, received TRUE\n");
384 rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
385 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
386 ok(result == TRUE, "expected TRUE, received FALSE\n");
388 bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
389 top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
390 rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
391 raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
392 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
393 ok(result == FALSE, "expected FALSE, received TRUE\n");
395 bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
396 top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
398 raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
399 rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
400 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
401 ok(result == TRUE, "expected TRUE, received FALSE\n");
403 bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
404 top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
406 raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
407 rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
408 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
409 ok(result == FALSE, "expected FALSE, received TRUE\n");
411 raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
412 rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
413 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
414 ok(result == TRUE, "expected TRUE, received FALSE\n");
416 /*____________Test the Sphere case________________________*/
417 radius = sqrt(77.0f);
418 center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
419 raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
421 rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
422 result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
423 ok(result == TRUE, "expected TRUE, received FALSE\n");
425 rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
426 result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
427 ok(result == FALSE, "expected FALSE, received TRUE\n");
429 rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
430 result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
431 ok(result == FALSE, "expected FALSE, received TRUE\n");
434 static void D3DXComputeBoundingBoxTest(void)
436 D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
437 HRESULT hr;
439 vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
440 vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
441 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
442 vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
443 vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
445 exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
446 exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
448 hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
450 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
451 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);
452 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);
454 /*________________________*/
456 vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
457 vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
458 vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
459 vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
460 vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
462 exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
463 exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
465 hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
467 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
468 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);
469 ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
471 /*________________________*/
473 vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
474 vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
475 vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
476 vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
477 vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
479 exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
480 exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
482 hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
484 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
485 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);
486 ok( compare_vec3(exp_max,got_max), "Expected max: (%f, %f, %f), got: (%f, %f, %f)\n", exp_max.x,exp_max.y,exp_max.z,got_max.x,got_max.y,got_max.z);
488 /*________________________*/
489 hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
490 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
492 /*________________________*/
493 hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
494 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
496 /*________________________*/
497 hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
498 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
501 static void D3DXComputeBoundingSphereTest(void)
503 D3DXVECTOR3 exp_cen, got_cen, vertex[5];
504 FLOAT exp_rad, got_rad;
505 HRESULT hr;
507 vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
508 vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
509 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
510 vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
511 vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
513 exp_rad = 6.928203f;
514 exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
516 hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
518 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
519 ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
520 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);
522 /*________________________*/
524 vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
525 vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
526 vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
527 vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
528 vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
530 exp_rad = 13.707883f;
531 exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
533 hr = D3DXComputeBoundingSphere(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
535 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
536 ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
537 ok( compare_vec3(exp_cen,got_cen), "Expected center: (%f, %f, %f), got center: (%f, %f, %f)\n", exp_cen.x,exp_cen.y,exp_cen.z,got_cen.x,got_cen.y,got_cen.z);
539 /*________________________*/
540 hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
541 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
543 /*________________________*/
544 hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
545 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
547 /*________________________*/
548 hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
549 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
552 static void print_elements(const D3DVERTEXELEMENT9 *elements)
554 D3DVERTEXELEMENT9 last = D3DDECL_END();
555 const D3DVERTEXELEMENT9 *ptr = elements;
556 int count = 0;
558 while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
560 trace(
561 "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
562 count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
563 ptr++;
564 count++;
568 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
569 unsigned int line, unsigned int test_id)
571 D3DVERTEXELEMENT9 last = D3DDECL_END();
572 unsigned int i;
574 for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
576 int end1 = memcmp(&elements[i], &last, sizeof(last));
577 int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
578 int status;
580 if (!end1 && !end2) break;
582 status = !end1 ^ !end2;
583 ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
584 line, test_id, end1 ? "shorter" : "longer");
585 if (status)
587 print_elements(elements);
588 break;
591 status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
592 ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
593 if (status)
595 print_elements(elements);
596 break;
601 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
602 HRESULT expected_hr, unsigned int line, unsigned int test_id)
604 HRESULT hr;
605 D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
607 hr = D3DXDeclaratorFromFVF(test_fvf, decl);
608 ok(hr == expected_hr,
609 "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
610 line, test_id, hr, expected_hr);
611 if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
614 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
615 HRESULT expected_hr, unsigned int line, unsigned int test_id)
617 HRESULT hr;
618 DWORD result_fvf = 0xdeadbeef;
620 hr = D3DXFVFFromDeclarator(decl, &result_fvf);
621 ok(hr == expected_hr,
622 "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
623 line, test_id, hr, expected_hr);
624 if (SUCCEEDED(hr))
626 ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
627 line, test_id, result_fvf, expected_fvf);
631 static void test_fvf_decl_conversion(void)
633 static const struct
635 D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
636 DWORD fvf;
638 test_data[] =
641 D3DDECL_END(),
642 }, 0},
644 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
645 D3DDECL_END(),
646 }, D3DFVF_XYZ},
648 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
649 D3DDECL_END(),
650 }, D3DFVF_XYZRHW},
652 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
653 D3DDECL_END(),
654 }, D3DFVF_XYZRHW},
656 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
657 {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
658 D3DDECL_END(),
659 }, D3DFVF_XYZB1},
661 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
662 {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
663 D3DDECL_END(),
664 }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
666 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
667 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
668 D3DDECL_END(),
669 }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
671 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
672 {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
673 D3DDECL_END(),
674 }, D3DFVF_XYZB2},
676 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
677 {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
678 {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
679 D3DDECL_END(),
680 }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
682 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
683 {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
684 {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
685 D3DDECL_END(),
686 }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
688 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
689 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
690 D3DDECL_END(),
691 }, D3DFVF_XYZB3},
693 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
694 {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
695 {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
696 D3DDECL_END(),
697 }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
699 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
700 {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
701 {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
702 D3DDECL_END(),
703 }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
705 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
706 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
707 D3DDECL_END(),
708 }, D3DFVF_XYZB4},
710 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
711 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
712 {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
713 D3DDECL_END(),
714 }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
716 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
717 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
718 {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
719 D3DDECL_END(),
720 }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
722 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
723 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
724 {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
725 D3DDECL_END(),
726 }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
728 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
729 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
730 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
731 D3DDECL_END(),
732 }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
734 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
735 D3DDECL_END(),
736 }, D3DFVF_NORMAL},
738 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
739 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
740 D3DDECL_END(),
741 }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
743 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
744 D3DDECL_END(),
745 }, D3DFVF_PSIZE},
747 {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
748 D3DDECL_END(),
749 }, D3DFVF_DIFFUSE},
751 {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
752 D3DDECL_END(),
753 }, D3DFVF_SPECULAR},
754 /* Make sure textures of different sizes work. */
756 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
757 D3DDECL_END(),
758 }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
760 {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
761 D3DDECL_END(),
762 }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
764 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
765 D3DDECL_END(),
766 }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
768 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
769 D3DDECL_END(),
770 }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
771 /* Make sure the TEXCOORD index works correctly - try several textures. */
773 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
774 {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
775 {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
776 {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
777 D3DDECL_END(),
778 }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
779 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
780 /* Now try some combination tests. */
782 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
783 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
784 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
785 {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
786 {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
787 {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
788 D3DDECL_END(),
789 }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
790 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
792 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
793 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
794 {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
795 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
796 {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
797 {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
798 D3DDECL_END(),
799 }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
800 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
802 unsigned int i;
804 for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
806 test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
807 test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
810 /* Usage indices for position and normal are apparently ignored. */
812 const D3DVERTEXELEMENT9 decl[] =
814 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
815 D3DDECL_END(),
817 test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
820 const D3DVERTEXELEMENT9 decl[] =
822 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
823 D3DDECL_END(),
825 test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
827 /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
828 * there are no blend matrices. */
830 const D3DVERTEXELEMENT9 decl[] =
832 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
833 D3DDECL_END(),
835 test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
838 const D3DVERTEXELEMENT9 decl[] =
840 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
841 D3DDECL_END(),
843 test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
845 /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
847 const D3DVERTEXELEMENT9 decl[] =
849 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
850 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
851 {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
852 D3DDECL_END(),
854 test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
855 decl, D3D_OK, __LINE__, 0);
857 /* These are supposed to fail, both ways. */
859 const D3DVERTEXELEMENT9 decl[] =
861 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
862 D3DDECL_END(),
864 test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
865 test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
868 const D3DVERTEXELEMENT9 decl[] =
870 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
871 {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
872 D3DDECL_END(),
874 test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
875 test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
878 const D3DVERTEXELEMENT9 decl[] =
880 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
881 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
882 {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
883 D3DDECL_END(),
885 test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
886 test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
888 /* Test a declaration that can't be converted to an FVF. */
890 const D3DVERTEXELEMENT9 decl[] =
892 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
893 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
894 {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
895 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
896 {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
897 /* 8 bytes padding */
898 {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
899 D3DDECL_END(),
901 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
903 /* Elements must be ordered by offset. */
905 const D3DVERTEXELEMENT9 decl[] =
907 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
908 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
909 D3DDECL_END(),
911 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
913 /* Basic tests for element order. */
915 const D3DVERTEXELEMENT9 decl[] =
917 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
918 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
919 {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
920 D3DDECL_END(),
922 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
925 const D3DVERTEXELEMENT9 decl[] =
927 {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
928 {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
929 D3DDECL_END(),
931 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
934 const D3DVERTEXELEMENT9 decl[] =
936 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
937 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
938 D3DDECL_END(),
940 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
942 /* Textures must be ordered by texcoords. */
944 const D3DVERTEXELEMENT9 decl[] =
946 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
947 {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
948 {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
949 {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
950 D3DDECL_END(),
952 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
954 /* Duplicate elements are not allowed. */
956 const D3DVERTEXELEMENT9 decl[] =
958 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
959 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
960 {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
961 D3DDECL_END(),
963 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
965 /* Invalid FVFs cannot be converted to a declarator. */
966 test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
969 static void D3DXGetFVFVertexSizeTest(void)
971 UINT got;
973 compare_vertex_sizes (D3DFVF_XYZ, 12);
975 compare_vertex_sizes (D3DFVF_XYZB3, 24);
977 compare_vertex_sizes (D3DFVF_XYZB5, 32);
979 compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
981 compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
983 compare_vertex_sizes (
984 D3DFVF_XYZ |
985 D3DFVF_TEX1 |
986 D3DFVF_TEXCOORDSIZE1(0), 16);
987 compare_vertex_sizes (
988 D3DFVF_XYZ |
989 D3DFVF_TEX2 |
990 D3DFVF_TEXCOORDSIZE1(0) |
991 D3DFVF_TEXCOORDSIZE1(1), 20);
993 compare_vertex_sizes (
994 D3DFVF_XYZ |
995 D3DFVF_TEX1 |
996 D3DFVF_TEXCOORDSIZE2(0), 20);
998 compare_vertex_sizes (
999 D3DFVF_XYZ |
1000 D3DFVF_TEX2 |
1001 D3DFVF_TEXCOORDSIZE2(0) |
1002 D3DFVF_TEXCOORDSIZE2(1), 28);
1004 compare_vertex_sizes (
1005 D3DFVF_XYZ |
1006 D3DFVF_TEX6 |
1007 D3DFVF_TEXCOORDSIZE2(0) |
1008 D3DFVF_TEXCOORDSIZE2(1) |
1009 D3DFVF_TEXCOORDSIZE2(2) |
1010 D3DFVF_TEXCOORDSIZE2(3) |
1011 D3DFVF_TEXCOORDSIZE2(4) |
1012 D3DFVF_TEXCOORDSIZE2(5), 60);
1014 compare_vertex_sizes (
1015 D3DFVF_XYZ |
1016 D3DFVF_TEX8 |
1017 D3DFVF_TEXCOORDSIZE2(0) |
1018 D3DFVF_TEXCOORDSIZE2(1) |
1019 D3DFVF_TEXCOORDSIZE2(2) |
1020 D3DFVF_TEXCOORDSIZE2(3) |
1021 D3DFVF_TEXCOORDSIZE2(4) |
1022 D3DFVF_TEXCOORDSIZE2(5) |
1023 D3DFVF_TEXCOORDSIZE2(6) |
1024 D3DFVF_TEXCOORDSIZE2(7), 76);
1026 compare_vertex_sizes (
1027 D3DFVF_XYZ |
1028 D3DFVF_TEX1 |
1029 D3DFVF_TEXCOORDSIZE3(0), 24);
1031 compare_vertex_sizes (
1032 D3DFVF_XYZ |
1033 D3DFVF_TEX4 |
1034 D3DFVF_TEXCOORDSIZE3(0) |
1035 D3DFVF_TEXCOORDSIZE3(1) |
1036 D3DFVF_TEXCOORDSIZE3(2) |
1037 D3DFVF_TEXCOORDSIZE3(3), 60);
1039 compare_vertex_sizes (
1040 D3DFVF_XYZ |
1041 D3DFVF_TEX1 |
1042 D3DFVF_TEXCOORDSIZE4(0), 28);
1044 compare_vertex_sizes (
1045 D3DFVF_XYZ |
1046 D3DFVF_TEX2 |
1047 D3DFVF_TEXCOORDSIZE4(0) |
1048 D3DFVF_TEXCOORDSIZE4(1), 44);
1050 compare_vertex_sizes (
1051 D3DFVF_XYZ |
1052 D3DFVF_TEX3 |
1053 D3DFVF_TEXCOORDSIZE4(0) |
1054 D3DFVF_TEXCOORDSIZE4(1) |
1055 D3DFVF_TEXCOORDSIZE4(2), 60);
1057 compare_vertex_sizes (
1058 D3DFVF_XYZB5 |
1059 D3DFVF_NORMAL |
1060 D3DFVF_DIFFUSE |
1061 D3DFVF_SPECULAR |
1062 D3DFVF_TEX8 |
1063 D3DFVF_TEXCOORDSIZE4(0) |
1064 D3DFVF_TEXCOORDSIZE4(1) |
1065 D3DFVF_TEXCOORDSIZE4(2) |
1066 D3DFVF_TEXCOORDSIZE4(3) |
1067 D3DFVF_TEXCOORDSIZE4(4) |
1068 D3DFVF_TEXCOORDSIZE4(5) |
1069 D3DFVF_TEXCOORDSIZE4(6) |
1070 D3DFVF_TEXCOORDSIZE4(7), 180);
1073 static void D3DXIntersectTriTest(void)
1075 BOOL exp_res, got_res;
1076 D3DXVECTOR3 position, ray, vertex[3];
1077 FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
1079 vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1080 vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1081 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1083 position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
1085 ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1087 exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
1089 got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1090 ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1091 ok( compare(exp_u,got_u), "Expected u = %f, got %f\n",exp_u,got_u);
1092 ok( compare(exp_v,got_v), "Expected v = %f, got %f\n",exp_v,got_v);
1093 ok( compare(exp_dist,got_dist), "Expected distance = %f, got %f\n",exp_dist,got_dist);
1095 /*Only positive ray is taken in account*/
1097 vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1098 vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1099 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1101 position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
1103 ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1105 exp_res = FALSE;
1107 got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1108 ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1110 /*Intersection between ray and triangle in a same plane is considered as empty*/
1112 vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1113 vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1114 vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
1116 position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
1118 ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
1120 exp_res = FALSE;
1122 got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1123 ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1126 static void D3DXCreateMeshTest(void)
1128 HRESULT hr;
1129 HWND wnd;
1130 IDirect3D9 *d3d;
1131 IDirect3DDevice9 *device, *test_device;
1132 D3DPRESENT_PARAMETERS d3dpp;
1133 ID3DXMesh *d3dxmesh;
1134 int i, size;
1135 D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1136 DWORD options;
1137 struct mesh mesh;
1139 static const D3DVERTEXELEMENT9 decl1[3] = {
1140 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1141 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1142 D3DDECL_END(), };
1144 static const D3DVERTEXELEMENT9 decl2[] = {
1145 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1146 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1147 {0, 24, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
1148 {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
1149 {0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
1150 /* 8 bytes padding */
1151 {0, 44, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
1152 D3DDECL_END(),
1155 static const D3DVERTEXELEMENT9 decl3[] = {
1156 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1157 {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1158 D3DDECL_END(),
1161 hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1162 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1164 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1165 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1167 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1168 if (!wnd)
1170 skip("Couldn't create application window\n");
1171 return;
1173 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1174 if (!d3d)
1176 skip("Couldn't create IDirect3D9 object\n");
1177 DestroyWindow(wnd);
1178 return;
1181 ZeroMemory(&d3dpp, sizeof(d3dpp));
1182 d3dpp.Windowed = TRUE;
1183 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1184 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1185 if (FAILED(hr))
1187 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1188 IDirect3D9_Release(d3d);
1189 DestroyWindow(wnd);
1190 return;
1193 hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1194 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1196 hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1197 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1199 hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
1200 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1202 if (hr == D3D_OK)
1204 d3dxmesh->lpVtbl->Release(d3dxmesh);
1207 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1208 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1210 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
1211 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1213 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1214 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1216 if (hr == D3D_OK)
1218 /* device */
1219 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1220 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1222 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1223 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1224 ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1226 if (hr == D3D_OK)
1228 IDirect3DDevice9_Release(device);
1231 /* declaration */
1232 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1233 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1235 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1236 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1238 if (hr == D3D_OK)
1240 size = sizeof(decl1) / sizeof(decl1[0]);
1241 for (i = 0; i < size - 1; i++)
1243 ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1244 ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1245 ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1246 ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1247 ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1248 ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1250 ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1253 /* options */
1254 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1255 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1257 /* rest */
1258 if (!new_mesh(&mesh, 3, 1))
1260 skip("Couldn't create mesh\n");
1262 else
1264 memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1265 memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1266 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1268 compare_mesh("createmesh1", d3dxmesh, &mesh);
1270 free_mesh(&mesh);
1273 d3dxmesh->lpVtbl->Release(d3dxmesh);
1276 /* Test a declaration that can't be converted to an FVF. */
1277 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1278 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1280 if (hr == D3D_OK)
1282 /* device */
1283 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1284 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1286 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1287 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1288 ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1290 if (hr == D3D_OK)
1292 IDirect3DDevice9_Release(device);
1295 /* declaration */
1296 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1297 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1299 if (hr == D3D_OK)
1301 size = sizeof(decl2) / sizeof(decl2[0]);
1302 for (i = 0; i < size - 1; i++)
1304 ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1305 ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1306 ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1307 ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1308 ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1309 ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1311 ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1314 /* options */
1315 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1316 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1318 /* rest */
1319 if (!new_mesh(&mesh, 3, 1))
1321 skip("Couldn't create mesh\n");
1323 else
1325 memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1326 memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1327 mesh.fvf = 0;
1328 mesh.vertex_size = 60;
1330 compare_mesh("createmesh2", d3dxmesh, &mesh);
1332 free_mesh(&mesh);
1335 mesh.vertex_size = d3dxmesh->lpVtbl->GetNumBytesPerVertex(d3dxmesh);
1336 ok(mesh.vertex_size == 60, "Got vertex size %u, expected %u\n", mesh.vertex_size, 60);
1338 d3dxmesh->lpVtbl->Release(d3dxmesh);
1341 /* Test a declaration with multiple streams. */
1342 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
1343 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1345 IDirect3DDevice9_Release(device);
1346 IDirect3D9_Release(d3d);
1347 DestroyWindow(wnd);
1350 static void D3DXCreateMeshFVFTest(void)
1352 HRESULT hr;
1353 HWND wnd;
1354 IDirect3D9 *d3d;
1355 IDirect3DDevice9 *device, *test_device;
1356 D3DPRESENT_PARAMETERS d3dpp;
1357 ID3DXMesh *d3dxmesh;
1358 int i, size;
1359 D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1360 DWORD options;
1361 struct mesh mesh;
1363 static const D3DVERTEXELEMENT9 decl[3] = {
1364 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1365 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1366 D3DDECL_END(), };
1368 hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1369 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1371 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, NULL, &d3dxmesh);
1372 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1374 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1375 if (!wnd)
1377 skip("Couldn't create application window\n");
1378 return;
1380 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1381 if (!d3d)
1383 skip("Couldn't create IDirect3D9 object\n");
1384 DestroyWindow(wnd);
1385 return;
1388 ZeroMemory(&d3dpp, sizeof(d3dpp));
1389 d3dpp.Windowed = TRUE;
1390 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1391 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1392 if (FAILED(hr))
1394 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1395 IDirect3D9_Release(d3d);
1396 DestroyWindow(wnd);
1397 return;
1400 hr = D3DXCreateMeshFVF(0, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1401 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1403 hr = D3DXCreateMeshFVF(1, 0, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1404 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1406 hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1407 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1409 if (hr == D3D_OK)
1411 d3dxmesh->lpVtbl->Release(d3dxmesh);
1414 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1415 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1417 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, NULL);
1418 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1420 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1421 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1423 if (hr == D3D_OK)
1425 /* device */
1426 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1427 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1429 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1430 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1431 ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1433 if (hr == D3D_OK)
1435 IDirect3DDevice9_Release(device);
1438 /* declaration */
1439 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1440 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1442 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1443 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1445 if (hr == D3D_OK)
1447 size = sizeof(decl) / sizeof(decl[0]);
1448 for (i = 0; i < size - 1; i++)
1450 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1451 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1452 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1453 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1454 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1455 test_decl[i].UsageIndex, decl[i].UsageIndex);
1456 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1458 ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1461 /* options */
1462 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1463 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1465 /* rest */
1466 if (!new_mesh(&mesh, 3, 1))
1468 skip("Couldn't create mesh\n");
1470 else
1472 memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1473 memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1474 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1476 compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1478 free_mesh(&mesh);
1481 d3dxmesh->lpVtbl->Release(d3dxmesh);
1484 IDirect3DDevice9_Release(device);
1485 IDirect3D9_Release(d3d);
1486 DestroyWindow(wnd);
1489 #define check_vertex_buffer(mesh, vertices, num_vertices, fvf) \
1490 check_vertex_buffer_(__LINE__, mesh, vertices, num_vertices, fvf)
1491 static void check_vertex_buffer_(int line, ID3DXMesh *mesh, const void *vertices, DWORD num_vertices, DWORD fvf)
1493 DWORD mesh_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
1494 DWORD mesh_fvf = mesh->lpVtbl->GetFVF(mesh);
1495 const void *mesh_vertices;
1496 HRESULT hr;
1498 ok_(__FILE__,line)(fvf == mesh_fvf, "expected FVF %x, got %x\n", fvf, mesh_fvf);
1499 ok_(__FILE__,line)(num_vertices == mesh_num_vertices,
1500 "Expected %u vertices, got %u\n", num_vertices, mesh_num_vertices);
1502 hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
1503 ok_(__FILE__,line)(hr == D3D_OK, "LockVertexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1504 if (FAILED(hr))
1505 return;
1507 if (mesh_fvf == fvf) {
1508 DWORD vertex_size = D3DXGetFVFVertexSize(fvf);
1509 int i;
1510 for (i = 0; i < min(num_vertices, mesh_num_vertices); i++)
1512 const FLOAT *exp_float = vertices;
1513 const FLOAT *got_float = mesh_vertices;
1514 DWORD texcount;
1515 DWORD pos_dim = 0;
1516 int j;
1517 BOOL last_beta_dword = FALSE;
1518 char prefix[128];
1520 switch (fvf & D3DFVF_POSITION_MASK) {
1521 case D3DFVF_XYZ: pos_dim = 3; break;
1522 case D3DFVF_XYZRHW: pos_dim = 4; break;
1523 case D3DFVF_XYZB1:
1524 case D3DFVF_XYZB2:
1525 case D3DFVF_XYZB3:
1526 case D3DFVF_XYZB4:
1527 case D3DFVF_XYZB5:
1528 pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
1529 if (fvf & (D3DFVF_LASTBETA_UBYTE4 | D3DFVF_LASTBETA_D3DCOLOR))
1531 pos_dim--;
1532 last_beta_dword = TRUE;
1534 break;
1535 case D3DFVF_XYZW: pos_dim = 4; break;
1537 sprintf(prefix, "vertex[%u] position, ", i);
1538 check_floats_(line, prefix, got_float, exp_float, pos_dim);
1539 exp_float += pos_dim;
1540 got_float += pos_dim;
1542 if (last_beta_dword) {
1543 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1544 "Vertex[%u]: Expected last beta %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1545 exp_float++;
1546 got_float++;
1549 if (fvf & D3DFVF_NORMAL) {
1550 sprintf(prefix, "vertex[%u] normal, ", i);
1551 check_floats_(line, prefix, got_float, exp_float, 3);
1552 exp_float += 3;
1553 got_float += 3;
1555 if (fvf & D3DFVF_PSIZE) {
1556 ok_(__FILE__,line)(compare(*exp_float, *got_float),
1557 "Vertex[%u]: Expected psize %g, got %g\n", i, *exp_float, *got_float);
1558 exp_float++;
1559 got_float++;
1561 if (fvf & D3DFVF_DIFFUSE) {
1562 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1563 "Vertex[%u]: Expected diffuse %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1564 exp_float++;
1565 got_float++;
1567 if (fvf & D3DFVF_SPECULAR) {
1568 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1569 "Vertex[%u]: Expected specular %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1570 exp_float++;
1571 got_float++;
1574 texcount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
1575 for (j = 0; j < texcount; j++) {
1576 DWORD dim = (((fvf >> (16 + 2 * j)) + 1) & 0x03) + 1;
1577 sprintf(prefix, "vertex[%u] texture, ", i);
1578 check_floats_(line, prefix, got_float, exp_float, dim);
1579 exp_float += dim;
1580 got_float += dim;
1583 vertices = (BYTE*)vertices + vertex_size;
1584 mesh_vertices = (BYTE*)mesh_vertices + vertex_size;
1588 mesh->lpVtbl->UnlockVertexBuffer(mesh);
1591 #define check_index_buffer(mesh, indices, num_indices, index_size) \
1592 check_index_buffer_(__LINE__, mesh, indices, num_indices, index_size)
1593 static void check_index_buffer_(int line, ID3DXMesh *mesh, const void *indices, DWORD num_indices, DWORD index_size)
1595 DWORD mesh_index_size = (mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT) ? 4 : 2;
1596 DWORD mesh_num_indices = mesh->lpVtbl->GetNumFaces(mesh) * 3;
1597 const void *mesh_indices;
1598 HRESULT hr;
1599 DWORD i;
1601 ok_(__FILE__,line)(index_size == mesh_index_size,
1602 "Expected index size %u, got %u\n", index_size, mesh_index_size);
1603 ok_(__FILE__,line)(num_indices == mesh_num_indices,
1604 "Expected %u indices, got %u\n", num_indices, mesh_num_indices);
1606 hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
1607 ok_(__FILE__,line)(hr == D3D_OK, "LockIndexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1608 if (FAILED(hr))
1609 return;
1611 if (mesh_index_size == index_size) {
1612 for (i = 0; i < min(num_indices, mesh_num_indices); i++)
1614 if (index_size == 4)
1615 ok_(__FILE__,line)(*(DWORD*)indices == *(DWORD*)mesh_indices,
1616 "Index[%u]: expected %u, got %u\n", i, *(DWORD*)indices, *(DWORD*)mesh_indices);
1617 else
1618 ok_(__FILE__,line)(*(WORD*)indices == *(WORD*)mesh_indices,
1619 "Index[%u]: expected %u, got %u\n", i, *(WORD*)indices, *(WORD*)mesh_indices);
1620 indices = (BYTE*)indices + index_size;
1621 mesh_indices = (BYTE*)mesh_indices + index_size;
1624 mesh->lpVtbl->UnlockIndexBuffer(mesh);
1627 #define check_matrix(got, expected) check_matrix_(__LINE__, got, expected)
1628 static void check_matrix_(int line, const D3DXMATRIX *got, const D3DXMATRIX *expected)
1630 int i, j;
1631 for (i = 0; i < 4; i++) {
1632 for (j = 0; j < 4; j++) {
1633 ok_(__FILE__,line)(compare(U(*expected).m[i][j], U(*got).m[i][j]),
1634 "matrix[%u][%u]: expected %g, got %g\n",
1635 i, j, U(*expected).m[i][j], U(*got).m[i][j]);
1640 static void check_colorvalue_(int line, const char *prefix, const D3DCOLORVALUE got, const D3DCOLORVALUE expected)
1642 ok_(__FILE__,line)(expected.r == got.r && expected.g == got.g && expected.b == got.b && expected.a == got.a,
1643 "%sExpected (%g, %g, %g, %g), got (%g, %g, %g, %g)\n", prefix,
1644 expected.r, expected.g, expected.b, expected.a, got.r, got.g, got.b, got.a);
1647 #define check_materials(got, got_count, expected, expected_count) \
1648 check_materials_(__LINE__, got, got_count, expected, expected_count)
1649 static void check_materials_(int line, const D3DXMATERIAL *got, DWORD got_count, const D3DXMATERIAL *expected, DWORD expected_count)
1651 int i;
1652 ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
1653 if (!expected) {
1654 ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
1655 return;
1657 for (i = 0; i < min(expected_count, got_count); i++)
1659 if (!expected[i].pTextureFilename)
1660 ok_(__FILE__,line)(got[i].pTextureFilename == NULL,
1661 "Expected NULL pTextureFilename, got %p\n", got[i].pTextureFilename);
1662 else
1663 ok_(__FILE__,line)(!strcmp(expected[i].pTextureFilename, got[i].pTextureFilename),
1664 "Expected '%s' for pTextureFilename, got '%s'\n", expected[i].pTextureFilename, got[i].pTextureFilename);
1665 check_colorvalue_(line, "Diffuse: ", got[i].MatD3D.Diffuse, expected[i].MatD3D.Diffuse);
1666 check_colorvalue_(line, "Ambient: ", got[i].MatD3D.Ambient, expected[i].MatD3D.Ambient);
1667 check_colorvalue_(line, "Specular: ", got[i].MatD3D.Specular, expected[i].MatD3D.Specular);
1668 check_colorvalue_(line, "Emissive: ", got[i].MatD3D.Emissive, expected[i].MatD3D.Emissive);
1669 ok_(__FILE__,line)(expected[i].MatD3D.Power == got[i].MatD3D.Power,
1670 "Power: Expected %g, got %g\n", expected[i].MatD3D.Power, got[i].MatD3D.Power);
1674 #define check_generated_adjacency(mesh, got, epsilon) check_generated_adjacency_(__LINE__, mesh, got, epsilon)
1675 static void check_generated_adjacency_(int line, ID3DXMesh *mesh, const DWORD *got, FLOAT epsilon)
1677 DWORD *expected;
1678 DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
1679 HRESULT hr;
1681 expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
1682 if (!expected) {
1683 skip_(__FILE__, line)("Out of memory\n");
1684 return;
1686 hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
1687 ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1688 if (SUCCEEDED(hr))
1690 int i;
1691 for (i = 0; i < num_faces; i++)
1693 ok_(__FILE__, line)(expected[i * 3] == got[i * 3] &&
1694 expected[i * 3 + 1] == got[i * 3 + 1] &&
1695 expected[i * 3 + 2] == got[i * 3 + 2],
1696 "Face %u adjacencies: Expected (%u, %u, %u), got (%u, %u, %u)\n", i,
1697 expected[i * 3], expected[i * 3 + 1], expected[i * 3 + 2],
1698 got[i * 3], got[i * 3 + 1], got[i * 3 + 2]);
1701 HeapFree(GetProcessHeap(), 0, expected);
1704 #define check_generated_effects(materials, num_materials, effects) \
1705 check_generated_effects_(__LINE__, materials, num_materials, effects)
1706 static void check_generated_effects_(int line, const D3DXMATERIAL *materials, DWORD num_materials, const D3DXEFFECTINSTANCE *effects)
1708 int i;
1709 static const struct {
1710 const char *name;
1711 DWORD name_size;
1712 DWORD num_bytes;
1713 DWORD value_offset;
1714 } params[] = {
1715 #define EFFECT_TABLE_ENTRY(str, field) \
1716 {str, sizeof(str), sizeof(materials->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
1717 EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
1718 EFFECT_TABLE_ENTRY("Power", Power),
1719 EFFECT_TABLE_ENTRY("Specular", Specular),
1720 EFFECT_TABLE_ENTRY("Emissive", Emissive),
1721 EFFECT_TABLE_ENTRY("Ambient", Ambient),
1722 #undef EFFECT_TABLE_ENTRY
1725 if (!num_materials) {
1726 ok_(__FILE__, line)(effects == NULL, "Expected NULL effects, got %p\n", effects);
1727 return;
1729 for (i = 0; i < num_materials; i++)
1731 int j;
1732 DWORD expected_num_defaults = ARRAY_SIZE(params) + (materials[i].pTextureFilename ? 1 : 0);
1734 ok_(__FILE__,line)(expected_num_defaults == effects[i].NumDefaults,
1735 "effect[%u] NumDefaults: Expected %u, got %u\n", i,
1736 expected_num_defaults, effects[i].NumDefaults);
1737 for (j = 0; j < min(ARRAY_SIZE(params), effects[i].NumDefaults); j++)
1739 int k;
1740 D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1741 ok_(__FILE__,line)(!strcmp(params[j].name, got_param->pParamName),
1742 "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1743 params[j].name, got_param->pParamName);
1744 ok_(__FILE__,line)(D3DXEDT_FLOATS == got_param->Type,
1745 "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1746 D3DXEDT_FLOATS, got_param->Type);
1747 ok_(__FILE__,line)(params[j].num_bytes == got_param->NumBytes,
1748 "effect[%u].pDefaults[%u].NumBytes: Expected %u, got %u\n", i, j,
1749 params[j].num_bytes, got_param->NumBytes);
1750 for (k = 0; k < min(params[j].num_bytes, got_param->NumBytes) / 4; k++)
1752 FLOAT expected = ((FLOAT*)((BYTE*)&materials[i] + params[j].value_offset))[k];
1753 FLOAT got = ((FLOAT*)got_param->pValue)[k];
1754 ok_(__FILE__,line)(compare(expected, got),
1755 "effect[%u].pDefaults[%u] float value %u: Expected %g, got %g\n", i, j, k, expected, got);
1758 if (effects[i].NumDefaults > ARRAY_SIZE(params)) {
1759 D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1760 static const char *expected_name = "Texture0@Name";
1762 ok_(__FILE__,line)(!strcmp(expected_name, got_param->pParamName),
1763 "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1764 expected_name, got_param->pParamName);
1765 ok_(__FILE__,line)(D3DXEDT_STRING == got_param->Type,
1766 "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1767 D3DXEDT_STRING, got_param->Type);
1768 if (materials[i].pTextureFilename) {
1769 ok_(__FILE__,line)(strlen(materials[i].pTextureFilename) + 1 == got_param->NumBytes,
1770 "effect[%u] texture filename length: Expected %u, got %u\n", i,
1771 (DWORD)strlen(materials[i].pTextureFilename) + 1, got_param->NumBytes);
1772 ok_(__FILE__,line)(!strcmp(materials[i].pTextureFilename, got_param->pValue),
1773 "effect[%u] texture filename: Expected '%s', got '%s'\n", i,
1774 materials[i].pTextureFilename, (char*)got_param->pValue);
1780 static LPSTR strdupA(LPCSTR p)
1782 LPSTR ret;
1783 if (!p) return NULL;
1784 ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
1785 if (ret) strcpy(ret, p);
1786 return ret;
1789 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
1791 TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
1792 if (frame) {
1793 HeapFree(GetProcessHeap(), 0, frame->Name);
1794 HeapFree(GetProcessHeap(), 0, frame);
1796 return D3D_OK;
1799 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface, LPCSTR name, LPD3DXFRAME *new_frame)
1801 LPD3DXFRAME frame;
1803 TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
1804 frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
1805 if (!frame)
1806 return E_OUTOFMEMORY;
1807 if (name) {
1808 frame->Name = strdupA(name);
1809 if (!frame->Name) {
1810 HeapFree(GetProcessHeap(), 0, frame);
1811 return E_OUTOFMEMORY;
1814 *new_frame = frame;
1815 return D3D_OK;
1818 static HRESULT destroy_mesh_container(LPD3DXMESHCONTAINER mesh_container)
1820 int i;
1822 if (!mesh_container)
1823 return D3D_OK;
1824 HeapFree(GetProcessHeap(), 0, mesh_container->Name);
1825 if (U(mesh_container->MeshData).pMesh)
1826 IUnknown_Release(U(mesh_container->MeshData).pMesh);
1827 if (mesh_container->pMaterials) {
1828 for (i = 0; i < mesh_container->NumMaterials; i++)
1829 HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials[i].pTextureFilename);
1830 HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials);
1832 if (mesh_container->pEffects) {
1833 for (i = 0; i < mesh_container->NumMaterials; i++) {
1834 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pEffectFilename);
1835 if (mesh_container->pEffects[i].pDefaults) {
1836 int j;
1837 for (j = 0; j < mesh_container->pEffects[i].NumDefaults; j++) {
1838 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pParamName);
1839 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pValue);
1841 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults);
1844 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects);
1846 HeapFree(GetProcessHeap(), 0, mesh_container->pAdjacency);
1847 if (mesh_container->pSkinInfo)
1848 IUnknown_Release(mesh_container->pSkinInfo);
1849 HeapFree(GetProcessHeap(), 0, mesh_container);
1850 return D3D_OK;
1853 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_DestroyMeshContainer(ID3DXAllocateHierarchy *iface, LPD3DXMESHCONTAINER mesh_container)
1855 TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyMeshContainer(%p, %p)\n", iface, mesh_container);
1856 return destroy_mesh_container(mesh_container);
1859 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_CreateMeshContainer(ID3DXAllocateHierarchy *iface,
1860 LPCSTR name, CONST D3DXMESHDATA *mesh_data, CONST D3DXMATERIAL *materials,
1861 CONST D3DXEFFECTINSTANCE *effects, DWORD num_materials, CONST DWORD *adjacency,
1862 LPD3DXSKININFO skin_info, LPD3DXMESHCONTAINER *new_mesh_container)
1864 LPD3DXMESHCONTAINER mesh_container = NULL;
1865 int i;
1867 TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateMeshContainer(%p, '%s', %u, %p, %p, %p, %d, %p, %p, %p)\n",
1868 iface, name, mesh_data->Type, U(*mesh_data).pMesh, materials, effects,
1869 num_materials, adjacency, skin_info, *new_mesh_container);
1871 mesh_container = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mesh_container));
1872 if (!mesh_container)
1873 return E_OUTOFMEMORY;
1875 if (name) {
1876 mesh_container->Name = strdupA(name);
1877 if (!mesh_container->Name)
1878 goto error;
1881 mesh_container->NumMaterials = num_materials;
1882 if (num_materials) {
1883 mesh_container->pMaterials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*materials));
1884 if (!mesh_container->pMaterials)
1885 goto error;
1887 memcpy(mesh_container->pMaterials, materials, num_materials * sizeof(*materials));
1888 for (i = 0; i < num_materials; i++)
1889 mesh_container->pMaterials[i].pTextureFilename = NULL;
1890 for (i = 0; i < num_materials; i++) {
1891 if (materials[i].pTextureFilename) {
1892 mesh_container->pMaterials[i].pTextureFilename = strdupA(materials[i].pTextureFilename);
1893 if (!mesh_container->pMaterials[i].pTextureFilename)
1894 goto error;
1898 mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
1899 if (!mesh_container->pEffects)
1900 goto error;
1901 for (i = 0; i < num_materials; i++) {
1902 int j;
1903 const D3DXEFFECTINSTANCE *effect_src = &effects[i];
1904 D3DXEFFECTINSTANCE *effect_dest = &mesh_container->pEffects[i];
1906 if (effect_src->pEffectFilename) {
1907 effect_dest->pEffectFilename = strdupA(effect_src->pEffectFilename);
1908 if (!effect_dest->pEffectFilename)
1909 goto error;
1911 effect_dest->pDefaults = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1912 effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
1913 if (!effect_dest->pDefaults)
1914 goto error;
1915 effect_dest->NumDefaults = effect_src->NumDefaults;
1916 for (j = 0; j < effect_src->NumDefaults; j++) {
1917 const D3DXEFFECTDEFAULT *default_src = &effect_src->pDefaults[j];
1918 D3DXEFFECTDEFAULT *default_dest = &effect_dest->pDefaults[j];
1920 if (default_src->pParamName) {
1921 default_dest->pParamName = strdupA(default_src->pParamName);
1922 if (!default_dest->pParamName)
1923 goto error;
1925 default_dest->NumBytes = default_src->NumBytes;
1926 default_dest->Type = default_src->Type;
1927 default_dest->pValue = HeapAlloc(GetProcessHeap(), 0, default_src->NumBytes);
1928 memcpy(default_dest->pValue, default_src->pValue, default_src->NumBytes);
1933 ok(adjacency != NULL, "Expected non-NULL adjacency, got NULL\n");
1934 if (adjacency) {
1935 if (mesh_data->Type == D3DXMESHTYPE_MESH || mesh_data->Type == D3DXMESHTYPE_PMESH) {
1936 ID3DXBaseMesh *basemesh = (ID3DXBaseMesh*)U(*mesh_data).pMesh;
1937 DWORD num_faces = basemesh->lpVtbl->GetNumFaces(basemesh);
1938 size_t size = num_faces * sizeof(DWORD) * 3;
1939 mesh_container->pAdjacency = HeapAlloc(GetProcessHeap(), 0, size);
1940 if (!mesh_container->pAdjacency)
1941 goto error;
1942 memcpy(mesh_container->pAdjacency, adjacency, size);
1943 } else {
1944 ok(mesh_data->Type == D3DXMESHTYPE_PATCHMESH, "Unknown mesh type %u\n", mesh_data->Type);
1945 if (mesh_data->Type == D3DXMESHTYPE_PATCHMESH)
1946 trace("FIXME: copying adjacency data for patch mesh not implemented\n");
1950 memcpy(&mesh_container->MeshData, mesh_data, sizeof(*mesh_data));
1951 if (U(*mesh_data).pMesh)
1952 IUnknown_AddRef(U(*mesh_data).pMesh);
1953 if (skin_info) {
1954 mesh_container->pSkinInfo = skin_info;
1955 skin_info->lpVtbl->AddRef(skin_info);
1957 *new_mesh_container = mesh_container;
1959 return S_OK;
1960 error:
1961 destroy_mesh_container(mesh_container);
1962 return E_OUTOFMEMORY;
1965 static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
1966 ID3DXAllocateHierarchyImpl_CreateFrame,
1967 ID3DXAllocateHierarchyImpl_CreateMeshContainer,
1968 ID3DXAllocateHierarchyImpl_DestroyFrame,
1969 ID3DXAllocateHierarchyImpl_DestroyMeshContainer,
1971 static ID3DXAllocateHierarchy alloc_hier = { &ID3DXAllocateHierarchyImpl_Vtbl };
1973 #define test_LoadMeshFromX(device, xfile_str, vertex_array, fvf, index_array, materials_array, check_adjacency) \
1974 test_LoadMeshFromX_(__LINE__, device, xfile_str, sizeof(xfile_str) - 1, vertex_array, ARRAY_SIZE(vertex_array), fvf, \
1975 index_array, ARRAY_SIZE(index_array), sizeof(*index_array), materials_array, ARRAY_SIZE(materials_array), \
1976 check_adjacency);
1977 static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char *xfile_str, size_t xfile_strlen,
1978 const void *vertices, DWORD num_vertices, DWORD fvf, const void *indices, DWORD num_indices, size_t index_size,
1979 const D3DXMATERIAL *expected_materials, DWORD expected_num_materials, BOOL check_adjacency)
1981 HRESULT hr;
1982 ID3DXBuffer *materials = NULL;
1983 ID3DXBuffer *effects = NULL;
1984 ID3DXBuffer *adjacency = NULL;
1985 ID3DXMesh *mesh = NULL;
1986 DWORD num_materials = 0;
1988 /* Adjacency is not checked when the X file contains multiple meshes,
1989 * since calling GenerateAdjacency on the merged mesh is not equivalent
1990 * to calling GenerateAdjacency on the individual meshes and then merging
1991 * the adjacency data. */
1992 hr = D3DXLoadMeshFromXInMemory(xfile_str, xfile_strlen, D3DXMESH_MANAGED, device,
1993 check_adjacency ? &adjacency : NULL, &materials, &effects, &num_materials, &mesh);
1994 ok_(__FILE__,line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1995 if (SUCCEEDED(hr)) {
1996 D3DXMATERIAL *materials_ptr = materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL;
1997 D3DXEFFECTINSTANCE *effects_ptr = effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL;
1998 DWORD *adjacency_ptr = check_adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL;
2000 check_vertex_buffer_(line, mesh, vertices, num_vertices, fvf);
2001 check_index_buffer_(line, mesh, indices, num_indices, index_size);
2002 check_materials_(line, materials_ptr, num_materials, expected_materials, expected_num_materials);
2003 check_generated_effects_(line, materials_ptr, num_materials, effects_ptr);
2004 if (check_adjacency)
2005 check_generated_adjacency_(line, mesh, adjacency_ptr, 0.0f);
2007 if (materials) ID3DXBuffer_Release(materials);
2008 if (effects) ID3DXBuffer_Release(effects);
2009 if (adjacency) ID3DXBuffer_Release(adjacency);
2010 IUnknown_Release(mesh);
2014 static void D3DXLoadMeshTest(void)
2016 static const char empty_xfile[] = "xof 0303txt 0032";
2017 /*________________________*/
2018 static const char simple_xfile[] =
2019 "xof 0303txt 0032"
2020 "Mesh {"
2021 "3;"
2022 "0.0; 0.0; 0.0;,"
2023 "0.0; 1.0; 0.0;,"
2024 "1.0; 1.0; 0.0;;"
2025 "1;"
2026 "3; 0, 1, 2;;"
2027 "}";
2028 static const WORD simple_index_buffer[] = {0, 1, 2};
2029 static const D3DXVECTOR3 simple_vertex_buffer[] = {
2030 {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}
2032 const DWORD simple_fvf = D3DFVF_XYZ;
2033 static const char framed_xfile[] =
2034 "xof 0303txt 0032"
2035 "Frame {"
2036 "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;; }"
2037 "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */
2038 "1.0, 0.0, 0.0, 0.0,"
2039 "0.0, 1.0, 0.0, 0.0,"
2040 "0.0, 0.0, 1.0, 0.0,"
2041 "0.0, 0.0, 2.0, 1.0;;"
2043 "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;; }"
2044 "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */
2045 "1.0, 0.0, 0.0, 0.0,"
2046 "0.0, 1.0, 0.0, 0.0,"
2047 "0.0, 0.0, 1.0, 0.0,"
2048 "0.0, 0.0, 3.0, 1.0;;"
2050 "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;; }"
2051 "}";
2052 static const WORD framed_index_buffer[] = { 0, 1, 2 };
2053 static const D3DXVECTOR3 framed_vertex_buffers[3][3] = {
2054 {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}},
2055 {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}},
2056 {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {3.0, 1.0, 0.0}},
2058 static const WORD merged_index_buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
2059 /* frame transforms accumulates for D3DXLoadMeshFromX */
2060 static const D3DXVECTOR3 merged_vertex_buffer[] = {
2061 {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0},
2062 {0.0, 0.0, 2.0}, {0.0, 1.0, 2.0}, {2.0, 1.0, 2.0},
2063 {0.0, 0.0, 5.0}, {0.0, 1.0, 5.0}, {3.0, 1.0, 5.0},
2065 const DWORD framed_fvf = D3DFVF_XYZ;
2066 /*________________________*/
2067 static const char box_xfile[] =
2068 "xof 0303txt 0032"
2069 "Mesh {"
2070 "8;" /* DWORD nVertices; */
2071 /* array Vector vertices[nVertices]; */
2072 "0.0; 0.0; 0.0;,"
2073 "0.0; 0.0; 1.0;,"
2074 "0.0; 1.0; 0.0;,"
2075 "0.0; 1.0; 1.0;,"
2076 "1.0; 0.0; 0.0;,"
2077 "1.0; 0.0; 1.0;,"
2078 "1.0; 1.0; 0.0;,"
2079 "1.0; 1.0; 1.0;;"
2080 "6;" /* DWORD nFaces; */
2081 /* array MeshFace faces[nFaces]; */
2082 "4; 0, 1, 3, 2;," /* (left side) */
2083 "4; 2, 3, 7, 6;," /* (top side) */
2084 "4; 6, 7, 5, 4;," /* (right side) */
2085 "4; 1, 0, 4, 5;," /* (bottom side) */
2086 "4; 1, 5, 7, 3;," /* (back side) */
2087 "4; 0, 2, 6, 4;;" /* (front side) */
2088 "MeshNormals {"
2089 "6;" /* DWORD nNormals; */
2090 /* array Vector normals[nNormals]; */
2091 "-1.0; 0.0; 0.0;,"
2092 "0.0; 1.0; 0.0;,"
2093 "1.0; 0.0; 0.0;,"
2094 "0.0; -1.0; 0.0;,"
2095 "0.0; 0.0; 1.0;,"
2096 "0.0; 0.0; -1.0;;"
2097 "6;" /* DWORD nFaceNormals; */
2098 /* array MeshFace faceNormals[nFaceNormals]; */
2099 "4; 0, 0, 0, 0;,"
2100 "4; 1, 1, 1, 1;,"
2101 "4; 2, 2, 2, 2;,"
2102 "4; 3, 3, 3, 3;,"
2103 "4; 4, 4, 4, 4;,"
2104 "4; 5, 5, 5, 5;;"
2106 "MeshMaterialList materials {"
2107 "2;" /* DWORD nMaterials; */
2108 "6;" /* DWORD nFaceIndexes; */
2109 /* array DWORD faceIndexes[nFaceIndexes]; */
2110 "0, 0, 0, 1, 1, 1;;"
2111 "Material {"
2112 /* ColorRGBA faceColor; */
2113 "0.0; 0.0; 1.0; 1.0;;"
2114 /* FLOAT power; */
2115 "0.5;"
2116 /* ColorRGB specularColor; */
2117 "1.0; 1.0; 1.0;;"
2118 /* ColorRGB emissiveColor; */
2119 "0.0; 0.0; 0.0;;"
2121 "Material {"
2122 /* ColorRGBA faceColor; */
2123 "1.0; 1.0; 1.0; 1.0;;"
2124 /* FLOAT power; */
2125 "1.0;"
2126 /* ColorRGB specularColor; */
2127 "1.0; 1.0; 1.0;;"
2128 /* ColorRGB emissiveColor; */
2129 "0.0; 0.0; 0.0;;"
2130 "TextureFilename { \"texture.jpg\"; }"
2133 "MeshVertexColors {"
2134 "8;" /* DWORD nVertexColors; */
2135 /* array IndexedColor vertexColors[nVertexColors]; */
2136 "0; 0.0; 0.0; 0.0; 0.0;;"
2137 "1; 0.0; 0.0; 1.0; 0.1;;"
2138 "2; 0.0; 1.0; 0.0; 0.2;;"
2139 "3; 0.0; 1.0; 1.0; 0.3;;"
2140 "4; 1.0; 0.0; 0.0; 0.4;;"
2141 "5; 1.0; 0.0; 1.0; 0.5;;"
2142 "6; 1.0; 1.0; 0.0; 0.6;;"
2143 "7; 1.0; 1.0; 1.0; 0.7;;"
2145 "MeshTextureCoords {"
2146 "8;" /* DWORD nTextureCoords; */
2147 /* array Coords2d textureCoords[nTextureCoords]; */
2148 "0.0; 1.0;,"
2149 "1.0; 1.0;,"
2150 "0.0; 0.0;,"
2151 "1.0; 0.0;,"
2152 "1.0; 1.0;,"
2153 "0.0; 1.0;,"
2154 "1.0; 0.0;,"
2155 "0.0; 0.0;;"
2157 "}";
2158 static const WORD box_index_buffer[] = {
2159 0, 1, 3,
2160 0, 3, 2,
2161 8, 9, 7,
2162 8, 7, 6,
2163 10, 11, 5,
2164 10, 5, 4,
2165 12, 13, 14,
2166 12, 14, 15,
2167 16, 17, 18,
2168 16, 18, 19,
2169 20, 21, 22,
2170 20, 22, 23,
2172 static const struct {
2173 D3DXVECTOR3 position;
2174 D3DXVECTOR3 normal;
2175 D3DCOLOR diffuse;
2176 D3DXVECTOR2 tex_coords;
2177 } box_vertex_buffer[] = {
2178 {{0.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, 0x00000000, {0.0, 1.0}},
2179 {{0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2180 {{0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2181 {{0.0, 1.0, 1.0}, {-1.0, 0.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2182 {{1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2183 {{1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2184 {{1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2185 {{1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2186 {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, 0x3300ff00, {0.0, 0.0}},
2187 {{0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, 0x4d00ffff, {1.0, 0.0}},
2188 {{1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, 0x99ffff00, {1.0, 0.0}},
2189 {{1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}, 0xb3ffffff, {0.0, 0.0}},
2190 {{0.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x1a0000ff, {1.0, 1.0}},
2191 {{0.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x00000000, {0.0, 1.0}},
2192 {{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, 0x66ff0000, {1.0, 1.0}},
2193 {{1.0, 0.0, 1.0}, {0.0, -1.0, 0.0}, 0x80ff00ff, {0.0, 1.0}},
2194 {{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x1a0000ff, {1.0, 1.0}},
2195 {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, 0x80ff00ff, {0.0, 1.0}},
2196 {{1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0xb3ffffff, {0.0, 0.0}},
2197 {{0.0, 1.0, 1.0}, {0.0, 0.0, 1.0}, 0x4d00ffff, {1.0, 0.0}},
2198 {{0.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x00000000, {0.0, 1.0}},
2199 {{0.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x3300ff00, {0.0, 0.0}},
2200 {{1.0, 1.0, 0.0}, {0.0, 0.0, -1.0}, 0x99ffff00, {1.0, 0.0}},
2201 {{1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}, 0x66ff0000, {1.0, 1.0}},
2203 static const D3DXMATERIAL box_materials[] = {
2206 {0.0, 0.0, 1.0, 1.0}, /* Diffuse */
2207 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2208 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2209 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2210 0.5, /* Power */
2212 NULL, /* pTextureFilename */
2216 {1.0, 1.0, 1.0, 1.0}, /* Diffuse */
2217 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2218 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2219 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2220 1.0, /* Power */
2222 (char *)"texture.jpg", /* pTextureFilename */
2225 const DWORD box_fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
2226 /*________________________*/
2227 static const D3DXMATERIAL default_materials[] = {
2230 {0.5, 0.5, 0.5, 0.0}, /* Diffuse */
2231 {0.0, 0.0, 0.0, 0.0}, /* Ambient */
2232 {0.5, 0.5, 0.5, 0.0}, /* Specular */
2233 {0.0, 0.0, 0.0, 0.0}, /* Emissive */
2234 0.0, /* Power */
2236 NULL, /* pTextureFilename */
2239 HRESULT hr;
2240 HWND wnd = NULL;
2241 IDirect3D9 *d3d = NULL;
2242 IDirect3DDevice9 *device = NULL;
2243 D3DPRESENT_PARAMETERS d3dpp;
2244 ID3DXMesh *mesh = NULL;
2245 D3DXFRAME *frame_hier = NULL;
2246 D3DXMATRIX transform;
2248 wnd = CreateWindow("static", "d3dx9_test", WS_POPUP, 0, 0, 1000, 1000, NULL, NULL, NULL, NULL);
2249 if (!wnd)
2251 skip("Couldn't create application window\n");
2252 return;
2254 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2255 if (!d3d)
2257 skip("Couldn't create IDirect3D9 object\n");
2258 goto cleanup;
2261 ZeroMemory(&d3dpp, sizeof(d3dpp));
2262 d3dpp.Windowed = TRUE;
2263 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2264 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2265 if (FAILED(hr))
2267 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2268 goto cleanup;
2271 hr = D3DXLoadMeshHierarchyFromXInMemory(NULL, sizeof(simple_xfile) - 1,
2272 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2273 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2275 hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, 0,
2276 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2277 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2279 hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2280 D3DXMESH_MANAGED, NULL, &alloc_hier, NULL, &frame_hier, NULL);
2281 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2283 hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2284 D3DXMESH_MANAGED, device, NULL, NULL, &frame_hier, NULL);
2285 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2287 hr = D3DXLoadMeshHierarchyFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1,
2288 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2289 ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2291 hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2292 D3DXMESH_MANAGED, device, &alloc_hier, NULL, NULL, NULL);
2293 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2295 hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2296 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2297 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2298 if (SUCCEEDED(hr)) {
2299 D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2301 ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2302 D3DXMatrixIdentity(&transform);
2303 check_matrix(&frame_hier->TransformationMatrix, &transform);
2305 ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2306 ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2307 D3DXMESHTYPE_MESH, container->MeshData.Type);
2308 mesh = U(container->MeshData).pMesh;
2309 check_vertex_buffer(mesh, simple_vertex_buffer, ARRAY_SIZE(simple_vertex_buffer), simple_fvf);
2310 check_index_buffer(mesh, simple_index_buffer, ARRAY_SIZE(simple_index_buffer), sizeof(*simple_index_buffer));
2311 check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2312 check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2313 check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2314 hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2315 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2316 frame_hier = NULL;
2319 hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1,
2320 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2321 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2322 if (SUCCEEDED(hr)) {
2323 D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2325 ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2326 D3DXMatrixIdentity(&transform);
2327 check_matrix(&frame_hier->TransformationMatrix, &transform);
2329 ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2330 ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2331 D3DXMESHTYPE_MESH, container->MeshData.Type);
2332 mesh = U(container->MeshData).pMesh;
2333 check_vertex_buffer(mesh, box_vertex_buffer, ARRAY_SIZE(box_vertex_buffer), box_fvf);
2334 check_index_buffer(mesh, box_index_buffer, ARRAY_SIZE(box_index_buffer), sizeof(*box_index_buffer));
2335 check_materials(container->pMaterials, container->NumMaterials, box_materials, ARRAY_SIZE(box_materials));
2336 check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2337 check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2338 hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2339 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2340 frame_hier = NULL;
2343 hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1,
2344 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2345 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2346 if (SUCCEEDED(hr)) {
2347 D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2348 int i;
2350 ok(!strcmp(frame_hier->Name, ""), "Expected '', got '%s'\n", frame_hier->Name);
2351 /* last frame transform replaces the first */
2352 D3DXMatrixIdentity(&transform);
2353 U(transform).m[3][2] = 3.0;
2354 check_matrix(&frame_hier->TransformationMatrix, &transform);
2356 for (i = 0; i < 3; i++) {
2357 ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2358 ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2359 D3DXMESHTYPE_MESH, container->MeshData.Type);
2360 mesh = U(container->MeshData).pMesh;
2361 check_vertex_buffer(mesh, framed_vertex_buffers[i], ARRAY_SIZE(framed_vertex_buffers[0]), framed_fvf);
2362 check_index_buffer(mesh, framed_index_buffer, ARRAY_SIZE(framed_index_buffer), sizeof(*framed_index_buffer));
2363 check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2364 check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2365 check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2366 container = container->pNextMeshContainer;
2368 ok(container == NULL, "Expected NULL, got %p\n", container);
2369 hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2370 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2371 frame_hier = NULL;
2375 hr = D3DXLoadMeshFromXInMemory(NULL, 0, D3DXMESH_MANAGED,
2376 device, NULL, NULL, NULL, NULL, &mesh);
2377 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2379 hr = D3DXLoadMeshFromXInMemory(NULL, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2380 device, NULL, NULL, NULL, NULL, &mesh);
2381 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2383 hr = D3DXLoadMeshFromXInMemory(simple_xfile, 0, D3DXMESH_MANAGED,
2384 device, NULL, NULL, NULL, NULL, &mesh);
2385 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2387 hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2388 device, NULL, NULL, NULL, NULL, NULL);
2389 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2391 hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2392 NULL, NULL, NULL, NULL, NULL, &mesh);
2393 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2395 hr = D3DXLoadMeshFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1, D3DXMESH_MANAGED,
2396 device, NULL, NULL, NULL, NULL, &mesh);
2397 ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2399 hr = D3DXLoadMeshFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1, D3DXMESH_MANAGED,
2400 device, NULL, NULL, NULL, NULL, &mesh);
2401 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2402 if (SUCCEEDED(hr))
2403 IUnknown_Release(mesh);
2405 test_LoadMeshFromX(device, simple_xfile, simple_vertex_buffer, simple_fvf, simple_index_buffer, default_materials, TRUE);
2406 test_LoadMeshFromX(device, box_xfile, box_vertex_buffer, box_fvf, box_index_buffer, box_materials, TRUE);
2407 test_LoadMeshFromX(device, framed_xfile, merged_vertex_buffer, framed_fvf, merged_index_buffer, default_materials, FALSE);
2409 cleanup:
2410 if (device) IDirect3DDevice9_Release(device);
2411 if (d3d) IDirect3D9_Release(d3d);
2412 if (wnd) DestroyWindow(wnd);
2415 static void D3DXCreateBoxTest(void)
2417 HRESULT hr;
2418 HWND wnd;
2419 WNDCLASS wc={0};
2420 IDirect3D9* d3d;
2421 IDirect3DDevice9* device;
2422 D3DPRESENT_PARAMETERS d3dpp;
2423 ID3DXMesh* box;
2424 ID3DXBuffer* ppBuffer;
2425 DWORD *buffer;
2426 static const DWORD adjacency[36]=
2427 {6, 9, 1, 2, 10, 0,
2428 1, 9, 3, 4, 10, 2,
2429 3, 8, 5, 7, 11, 4,
2430 0, 11, 7, 5, 8, 6,
2431 7, 4, 9, 2, 0, 8,
2432 1, 3, 11, 5, 6, 10};
2433 unsigned int i;
2435 wc.lpfnWndProc = DefWindowProcA;
2436 wc.lpszClassName = "d3dx9_test_wc";
2437 if (!RegisterClass(&wc))
2439 skip("RegisterClass failed\n");
2440 return;
2443 wnd = CreateWindow("d3dx9_test_wc", "d3dx9_test",
2444 WS_SYSMENU | WS_POPUP , 0, 0, 640, 480, 0, 0, 0, 0);
2445 ok(wnd != NULL, "Expected to have a window, received NULL\n");
2446 if (!wnd)
2448 skip("Couldn't create application window\n");
2449 return;
2452 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2453 if (!d3d)
2455 skip("Couldn't create IDirect3D9 object\n");
2456 DestroyWindow(wnd);
2457 return;
2460 memset(&d3dpp, 0, sizeof(d3dpp));
2461 d3dpp.Windowed = TRUE;
2462 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2463 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2464 if (FAILED(hr))
2466 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2467 IDirect3D9_Release(d3d);
2468 DestroyWindow(wnd);
2469 return;
2472 hr = D3DXCreateBuffer(36 * sizeof(DWORD), &ppBuffer);
2473 ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2474 if (FAILED(hr)) goto end;
2476 hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
2477 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2479 hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
2480 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2482 hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
2483 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2485 hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
2486 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2488 hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
2489 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2491 hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
2492 todo_wine ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2494 if (FAILED(hr))
2496 skip("D3DXCreateBox failed\n");
2497 goto end;
2500 buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
2501 for(i=0; i<36; i++)
2502 todo_wine ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
2504 box->lpVtbl->Release(box);
2506 end:
2507 IDirect3DDevice9_Release(device);
2508 IDirect3D9_Release(d3d);
2509 ID3DXBuffer_Release(ppBuffer);
2510 DestroyWindow(wnd);
2513 struct sincos_table
2515 float *sin;
2516 float *cos;
2519 static void free_sincos_table(struct sincos_table *sincos_table)
2521 HeapFree(GetProcessHeap(), 0, sincos_table->cos);
2522 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2525 /* pre compute sine and cosine tables; caller must free */
2526 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
2528 float angle;
2529 int i;
2531 sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2532 if (!sincos_table->sin)
2534 return FALSE;
2536 sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2537 if (!sincos_table->cos)
2539 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2540 return FALSE;
2543 angle = angle_start;
2544 for (i = 0; i < n; i++)
2546 sincos_table->sin[i] = sin(angle);
2547 sincos_table->cos[i] = cos(angle);
2548 angle += angle_step;
2551 return TRUE;
2554 static WORD vertex_index(UINT slices, int slice, int stack)
2556 return stack*slices+slice+1;
2559 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
2560 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
2562 float theta_step, theta_start;
2563 struct sincos_table theta;
2564 float phi_step, phi_start;
2565 struct sincos_table phi;
2566 DWORD number_of_vertices, number_of_faces;
2567 DWORD vertex, face;
2568 int slice, stack;
2570 /* theta = angle on xy plane wrt x axis */
2571 theta_step = M_PI / stacks;
2572 theta_start = theta_step;
2574 /* phi = angle on xz plane wrt z axis */
2575 phi_step = -2 * M_PI / slices;
2576 phi_start = M_PI / 2;
2578 if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
2580 return FALSE;
2582 if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
2584 free_sincos_table(&theta);
2585 return FALSE;
2588 number_of_vertices = 2 + slices * (stacks-1);
2589 number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
2591 if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2593 free_sincos_table(&phi);
2594 free_sincos_table(&theta);
2595 return FALSE;
2598 vertex = 0;
2599 face = 0;
2601 mesh->vertices[vertex].normal.x = 0.0f;
2602 mesh->vertices[vertex].normal.y = 0.0f;
2603 mesh->vertices[vertex].normal.z = 1.0f;
2604 mesh->vertices[vertex].position.x = 0.0f;
2605 mesh->vertices[vertex].position.y = 0.0f;
2606 mesh->vertices[vertex].position.z = radius;
2607 vertex++;
2609 for (stack = 0; stack < stacks - 1; stack++)
2611 for (slice = 0; slice < slices; slice++)
2613 mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
2614 mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
2615 mesh->vertices[vertex].normal.z = theta.cos[stack];
2616 mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
2617 mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
2618 mesh->vertices[vertex].position.z = radius * theta.cos[stack];
2619 vertex++;
2621 if (slice > 0)
2623 if (stack == 0)
2625 /* top stack is triangle fan */
2626 mesh->faces[face][0] = 0;
2627 mesh->faces[face][1] = slice + 1;
2628 mesh->faces[face][2] = slice;
2629 face++;
2631 else
2633 /* stacks in between top and bottom are quad strips */
2634 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2635 mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2636 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2637 face++;
2639 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2640 mesh->faces[face][1] = vertex_index(slices, slice, stack);
2641 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2642 face++;
2647 if (stack == 0)
2649 mesh->faces[face][0] = 0;
2650 mesh->faces[face][1] = 1;
2651 mesh->faces[face][2] = slice;
2652 face++;
2654 else
2656 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2657 mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2658 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2659 face++;
2661 mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2662 mesh->faces[face][1] = vertex_index(slices, 0, stack);
2663 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2664 face++;
2668 mesh->vertices[vertex].position.x = 0.0f;
2669 mesh->vertices[vertex].position.y = 0.0f;
2670 mesh->vertices[vertex].position.z = -radius;
2671 mesh->vertices[vertex].normal.x = 0.0f;
2672 mesh->vertices[vertex].normal.y = 0.0f;
2673 mesh->vertices[vertex].normal.z = -1.0f;
2675 /* bottom stack is triangle fan */
2676 for (slice = 1; slice < slices; slice++)
2678 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2679 mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2680 mesh->faces[face][2] = vertex;
2681 face++;
2684 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2685 mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2686 mesh->faces[face][2] = vertex;
2688 free_sincos_table(&phi);
2689 free_sincos_table(&theta);
2691 return TRUE;
2694 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
2696 HRESULT hr;
2697 ID3DXMesh *sphere;
2698 struct mesh mesh;
2699 char name[256];
2701 hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
2702 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2703 if (hr != D3D_OK)
2705 skip("Couldn't create sphere\n");
2706 return;
2709 if (!compute_sphere(&mesh, radius, slices, stacks))
2711 skip("Couldn't create mesh\n");
2712 sphere->lpVtbl->Release(sphere);
2713 return;
2716 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2718 sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
2719 compare_mesh(name, sphere, &mesh);
2721 free_mesh(&mesh);
2723 sphere->lpVtbl->Release(sphere);
2726 static void D3DXCreateSphereTest(void)
2728 HRESULT hr;
2729 HWND wnd;
2730 IDirect3D9* d3d;
2731 IDirect3DDevice9* device;
2732 D3DPRESENT_PARAMETERS d3dpp;
2733 ID3DXMesh* sphere = NULL;
2735 hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
2736 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2738 hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
2739 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2741 hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
2742 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2744 hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
2745 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2747 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
2748 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2749 if (!wnd)
2751 skip("Couldn't create application window\n");
2752 return;
2754 if (!d3d)
2756 skip("Couldn't create IDirect3D9 object\n");
2757 DestroyWindow(wnd);
2758 return;
2761 ZeroMemory(&d3dpp, sizeof(d3dpp));
2762 d3dpp.Windowed = TRUE;
2763 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2764 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2765 if (FAILED(hr))
2767 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2768 IDirect3D9_Release(d3d);
2769 DestroyWindow(wnd);
2770 return;
2773 hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
2774 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2776 hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
2777 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2779 hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
2780 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2782 hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
2783 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2785 test_sphere(device, 0.0f, 2, 2);
2786 test_sphere(device, 1.0f, 2, 2);
2787 test_sphere(device, 1.0f, 3, 2);
2788 test_sphere(device, 1.0f, 4, 4);
2789 test_sphere(device, 1.0f, 3, 4);
2790 test_sphere(device, 5.0f, 6, 7);
2791 test_sphere(device, 10.0f, 11, 12);
2793 IDirect3DDevice9_Release(device);
2794 IDirect3D9_Release(d3d);
2795 DestroyWindow(wnd);
2798 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
2800 float theta_step, theta_start;
2801 struct sincos_table theta;
2802 FLOAT delta_radius, radius, radius_step;
2803 FLOAT z, z_step, z_normal;
2804 DWORD number_of_vertices, number_of_faces;
2805 DWORD vertex, face;
2806 int slice, stack;
2808 /* theta = angle on xy plane wrt x axis */
2809 theta_step = -2 * M_PI / slices;
2810 theta_start = M_PI / 2;
2812 if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
2814 return FALSE;
2817 number_of_vertices = 2 + (slices * (3 + stacks));
2818 number_of_faces = 2 * slices + stacks * (2 * slices);
2820 if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2822 free_sincos_table(&theta);
2823 return FALSE;
2826 vertex = 0;
2827 face = 0;
2829 delta_radius = radius1 - radius2;
2830 radius = radius1;
2831 radius_step = delta_radius / stacks;
2833 z = -length / 2;
2834 z_step = length / stacks;
2835 z_normal = delta_radius / length;
2836 if (isnan(z_normal))
2838 z_normal = 0.0f;
2841 mesh->vertices[vertex].normal.x = 0.0f;
2842 mesh->vertices[vertex].normal.y = 0.0f;
2843 mesh->vertices[vertex].normal.z = -1.0f;
2844 mesh->vertices[vertex].position.x = 0.0f;
2845 mesh->vertices[vertex].position.y = 0.0f;
2846 mesh->vertices[vertex++].position.z = z;
2848 for (slice = 0; slice < slices; slice++, vertex++)
2850 mesh->vertices[vertex].normal.x = 0.0f;
2851 mesh->vertices[vertex].normal.y = 0.0f;
2852 mesh->vertices[vertex].normal.z = -1.0f;
2853 mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2854 mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2855 mesh->vertices[vertex].position.z = z;
2857 if (slice > 0)
2859 mesh->faces[face][0] = 0;
2860 mesh->faces[face][1] = slice;
2861 mesh->faces[face++][2] = slice + 1;
2865 mesh->faces[face][0] = 0;
2866 mesh->faces[face][1] = slice;
2867 mesh->faces[face++][2] = 1;
2869 for (stack = 1; stack <= stacks+1; stack++)
2871 for (slice = 0; slice < slices; slice++, vertex++)
2873 mesh->vertices[vertex].normal.x = theta.cos[slice];
2874 mesh->vertices[vertex].normal.y = theta.sin[slice];
2875 mesh->vertices[vertex].normal.z = z_normal;
2876 D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
2877 mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2878 mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2879 mesh->vertices[vertex].position.z = z;
2881 if (stack > 1 && slice > 0)
2883 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2884 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2885 mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
2887 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2888 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2889 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
2893 if (stack > 1)
2895 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2896 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2897 mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
2899 mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2900 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2901 mesh->faces[face++][2] = vertex_index(slices, 0, stack);
2904 if (stack < stacks + 1)
2906 z += z_step;
2907 radius -= radius_step;
2911 for (slice = 0; slice < slices; slice++, vertex++)
2913 mesh->vertices[vertex].normal.x = 0.0f;
2914 mesh->vertices[vertex].normal.y = 0.0f;
2915 mesh->vertices[vertex].normal.z = 1.0f;
2916 mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2917 mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2918 mesh->vertices[vertex].position.z = z;
2920 if (slice > 0)
2922 mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
2923 mesh->faces[face][1] = number_of_vertices - 1;
2924 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
2928 mesh->vertices[vertex].position.x = 0.0f;
2929 mesh->vertices[vertex].position.y = 0.0f;
2930 mesh->vertices[vertex].position.z = z;
2931 mesh->vertices[vertex].normal.x = 0.0f;
2932 mesh->vertices[vertex].normal.y = 0.0f;
2933 mesh->vertices[vertex].normal.z = 1.0f;
2935 mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
2936 mesh->faces[face][1] = number_of_vertices - 1;
2937 mesh->faces[face][2] = vertex_index(slices, 0, stack);
2939 free_sincos_table(&theta);
2941 return TRUE;
2944 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
2946 HRESULT hr;
2947 ID3DXMesh *cylinder;
2948 struct mesh mesh;
2949 char name[256];
2951 hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
2952 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2953 if (hr != D3D_OK)
2955 skip("Couldn't create cylinder\n");
2956 return;
2959 if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
2961 skip("Couldn't create mesh\n");
2962 cylinder->lpVtbl->Release(cylinder);
2963 return;
2966 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2968 sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
2969 compare_mesh(name, cylinder, &mesh);
2971 free_mesh(&mesh);
2973 cylinder->lpVtbl->Release(cylinder);
2976 static void D3DXCreateCylinderTest(void)
2978 HRESULT hr;
2979 HWND wnd;
2980 IDirect3D9* d3d;
2981 IDirect3DDevice9* device;
2982 D3DPRESENT_PARAMETERS d3dpp;
2983 ID3DXMesh* cylinder = NULL;
2985 hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
2986 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2988 hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
2989 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2991 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
2992 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2993 if (!wnd)
2995 skip("Couldn't create application window\n");
2996 return;
2998 if (!d3d)
3000 skip("Couldn't create IDirect3D9 object\n");
3001 DestroyWindow(wnd);
3002 return;
3005 ZeroMemory(&d3dpp, sizeof(d3dpp));
3006 d3dpp.Windowed = TRUE;
3007 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
3008 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
3009 if (FAILED(hr))
3011 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
3012 IDirect3D9_Release(d3d);
3013 DestroyWindow(wnd);
3014 return;
3017 hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3018 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3020 hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
3021 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3023 if (SUCCEEDED(hr) && cylinder)
3025 cylinder->lpVtbl->Release(cylinder);
3028 hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
3029 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3031 hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
3032 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3034 if (SUCCEEDED(hr) && cylinder)
3036 cylinder->lpVtbl->Release(cylinder);
3039 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
3040 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3042 /* Test with length == 0.0f succeeds */
3043 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
3044 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
3046 if (SUCCEEDED(hr) && cylinder)
3048 cylinder->lpVtbl->Release(cylinder);
3051 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
3052 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3054 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
3055 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3057 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
3058 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
3060 test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
3061 test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
3062 test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
3063 test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
3064 test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
3065 test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
3067 IDirect3DDevice9_Release(device);
3068 IDirect3D9_Release(d3d);
3069 DestroyWindow(wnd);
3072 struct dynamic_array
3074 int count, capacity;
3075 void *items;
3078 enum pointtype {
3079 POINTTYPE_CURVE = 0,
3080 POINTTYPE_CORNER,
3081 POINTTYPE_CURVE_START,
3082 POINTTYPE_CURVE_END,
3083 POINTTYPE_CURVE_MIDDLE,
3086 struct point2d
3088 D3DXVECTOR2 pos;
3089 enum pointtype corner;
3092 /* is a dynamic_array */
3093 struct outline
3095 int count, capacity;
3096 struct point2d *items;
3099 /* is a dynamic_array */
3100 struct outline_array
3102 int count, capacity;
3103 struct outline *items;
3106 struct glyphinfo
3108 struct outline_array outlines;
3109 float offset_x;
3112 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
3114 if (count > array->capacity) {
3115 void *new_buffer;
3116 int new_capacity;
3117 if (array->items && array->capacity) {
3118 new_capacity = max(array->capacity * 2, count);
3119 new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
3120 } else {
3121 new_capacity = max(16, count);
3122 new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
3124 if (!new_buffer)
3125 return FALSE;
3126 array->items = new_buffer;
3127 array->capacity = new_capacity;
3129 return TRUE;
3132 static struct point2d *add_point(struct outline *array)
3134 struct point2d *item;
3136 if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3137 return NULL;
3139 item = &array->items[array->count++];
3140 ZeroMemory(item, sizeof(*item));
3141 return item;
3144 static struct outline *add_outline(struct outline_array *array)
3146 struct outline *item;
3148 if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
3149 return NULL;
3151 item = &array->items[array->count++];
3152 ZeroMemory(item, sizeof(*item));
3153 return item;
3156 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
3158 D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
3159 while (count--) {
3160 D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
3161 pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
3162 pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
3163 pt++;
3165 return ret;
3168 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
3169 const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
3170 float max_deviation)
3172 D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
3173 float deviation;
3175 D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
3176 D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
3177 D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
3179 deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
3180 if (deviation < max_deviation) {
3181 struct point2d *pt = add_point(outline);
3182 if (!pt) return E_OUTOFMEMORY;
3183 pt->pos = *p2;
3184 pt->corner = POINTTYPE_CURVE;
3185 /* the end point is omitted because the end line merges into the next segment of
3186 * the split bezier curve, and the end of the split bezier curve is added outside
3187 * this recursive function. */
3188 } else {
3189 HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
3190 if (hr != S_OK) return hr;
3191 hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
3192 if (hr != S_OK) return hr;
3195 return S_OK;
3198 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
3200 /* dot product = cos(theta) */
3201 return D3DXVec2Dot(dir1, dir2) > cos_theta;
3204 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
3206 return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
3209 static BOOL attempt_line_merge(struct outline *outline,
3210 int pt_index,
3211 const D3DXVECTOR2 *nextpt,
3212 BOOL to_curve)
3214 D3DXVECTOR2 curdir, lastdir;
3215 struct point2d *prevpt, *pt;
3216 BOOL ret = FALSE;
3217 const float cos_half = cos(D3DXToRadian(0.5f));
3219 pt = &outline->items[pt_index];
3220 pt_index = (pt_index - 1 + outline->count) % outline->count;
3221 prevpt = &outline->items[pt_index];
3223 if (to_curve)
3224 pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
3226 if (outline->count < 2)
3227 return FALSE;
3229 /* remove last point if the next line continues the last line */
3230 unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3231 unit_vec2(&curdir, &pt->pos, nextpt);
3232 if (is_direction_similar(&lastdir, &curdir, cos_half))
3234 outline->count--;
3235 if (pt->corner == POINTTYPE_CURVE_END)
3236 prevpt->corner = pt->corner;
3237 if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
3238 prevpt->corner = POINTTYPE_CURVE_MIDDLE;
3239 pt = prevpt;
3241 ret = TRUE;
3242 if (outline->count < 2)
3243 return ret;
3245 pt_index = (pt_index - 1 + outline->count) % outline->count;
3246 prevpt = &outline->items[pt_index];
3247 unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3248 unit_vec2(&curdir, &pt->pos, nextpt);
3250 return ret;
3253 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
3254 float max_deviation, float emsquare)
3256 const float cos_45 = cos(D3DXToRadian(45.0f));
3257 const float cos_90 = cos(D3DXToRadian(90.0f));
3258 TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
3260 while ((char *)header < (char *)raw_outline + datasize)
3262 TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
3263 struct point2d *lastpt, *pt;
3264 D3DXVECTOR2 lastdir;
3265 D3DXVECTOR2 *pt_flt;
3266 int j;
3267 struct outline *outline = add_outline(&glyph->outlines);
3269 if (!outline)
3270 return E_OUTOFMEMORY;
3272 pt = add_point(outline);
3273 if (!pt)
3274 return E_OUTOFMEMORY;
3275 pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
3276 pt->pos = *pt_flt;
3277 pt->corner = POINTTYPE_CORNER;
3279 if (header->dwType != TT_POLYGON_TYPE)
3280 trace("Unknown header type %d\n", header->dwType);
3282 while ((char *)curve < (char *)header + header->cb)
3284 D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
3285 BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
3287 if (!curve->cpfx) {
3288 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3289 continue;
3292 pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
3294 attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
3296 if (to_curve)
3298 HRESULT hr;
3299 int count = curve->cpfx;
3300 j = 0;
3302 while (count > 2)
3304 D3DXVECTOR2 bezier_end;
3306 D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
3307 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
3308 if (hr != S_OK)
3309 return hr;
3310 bezier_start = bezier_end;
3311 count--;
3312 j++;
3314 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
3315 if (hr != S_OK)
3316 return hr;
3318 pt = add_point(outline);
3319 if (!pt)
3320 return E_OUTOFMEMORY;
3321 j++;
3322 pt->pos = pt_flt[j];
3323 pt->corner = POINTTYPE_CURVE_END;
3324 } else {
3325 for (j = 0; j < curve->cpfx; j++)
3327 pt = add_point(outline);
3328 if (!pt)
3329 return E_OUTOFMEMORY;
3330 pt->pos = pt_flt[j];
3331 pt->corner = POINTTYPE_CORNER;
3335 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3338 /* remove last point if the next line continues the last line */
3339 if (outline->count >= 3) {
3340 BOOL to_curve;
3342 lastpt = &outline->items[outline->count - 1];
3343 pt = &outline->items[0];
3344 if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
3345 if (lastpt->corner == POINTTYPE_CURVE_END)
3347 if (pt->corner == POINTTYPE_CURVE_START)
3348 pt->corner = POINTTYPE_CURVE_MIDDLE;
3349 else
3350 pt->corner = POINTTYPE_CURVE_END;
3352 outline->count--;
3353 lastpt = &outline->items[outline->count - 1];
3354 } else {
3355 /* outline closed with a line from end to start point */
3356 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
3358 lastpt = &outline->items[0];
3359 to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
3360 if (lastpt->corner == POINTTYPE_CURVE_START)
3361 lastpt->corner = POINTTYPE_CORNER;
3362 pt = &outline->items[1];
3363 if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
3364 *lastpt = outline->items[outline->count];
3367 lastpt = &outline->items[outline->count - 1];
3368 pt = &outline->items[0];
3369 unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
3370 for (j = 0; j < outline->count; j++)
3372 D3DXVECTOR2 curdir;
3374 lastpt = pt;
3375 pt = &outline->items[(j + 1) % outline->count];
3376 unit_vec2(&curdir, &lastpt->pos, &pt->pos);
3378 switch (lastpt->corner)
3380 case POINTTYPE_CURVE_START:
3381 case POINTTYPE_CURVE_END:
3382 if (!is_direction_similar(&lastdir, &curdir, cos_45))
3383 lastpt->corner = POINTTYPE_CORNER;
3384 break;
3385 case POINTTYPE_CURVE_MIDDLE:
3386 if (!is_direction_similar(&lastdir, &curdir, cos_90))
3387 lastpt->corner = POINTTYPE_CORNER;
3388 else
3389 lastpt->corner = POINTTYPE_CURVE;
3390 break;
3391 default:
3392 break;
3394 lastdir = curdir;
3397 header = (TTPOLYGONHEADER *)((char *)header + header->cb);
3399 return S_OK;
3402 static BOOL compute_text_mesh(struct mesh *mesh, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion, FLOAT otmEMSquare)
3404 HRESULT hr = E_FAIL;
3405 DWORD nb_vertices, nb_faces;
3406 DWORD nb_corners, nb_outline_points;
3407 int textlen = 0;
3408 float offset_x;
3409 char *raw_outline = NULL;
3410 struct glyphinfo *glyphs = NULL;
3411 GLYPHMETRICS gm;
3412 int i;
3413 struct vertex *vertex_ptr;
3414 face *face_ptr;
3416 if (deviation == 0.0f)
3417 deviation = 1.0f / otmEMSquare;
3419 textlen = strlen(text);
3420 glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
3421 if (!glyphs) {
3422 hr = E_OUTOFMEMORY;
3423 goto error;
3426 offset_x = 0.0f;
3427 for (i = 0; i < textlen; i++)
3429 /* get outline points from data returned from GetGlyphOutline */
3430 const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
3431 int datasize;
3433 glyphs[i].offset_x = offset_x;
3435 datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
3436 if (datasize < 0) {
3437 hr = E_FAIL;
3438 goto error;
3440 HeapFree(GetProcessHeap(), 0, raw_outline);
3441 raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
3442 if (!glyphs) {
3443 hr = E_OUTOFMEMORY;
3444 goto error;
3446 datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
3448 create_outline(&glyphs[i], raw_outline, datasize, deviation, otmEMSquare);
3450 offset_x += gm.gmCellIncX / (float)otmEMSquare;
3453 /* corner points need an extra vertex for the different side faces normals */
3454 nb_corners = 0;
3455 nb_outline_points = 0;
3456 for (i = 0; i < textlen; i++)
3458 int j;
3459 for (j = 0; j < glyphs[i].outlines.count; j++)
3461 int k;
3462 struct outline *outline = &glyphs[i].outlines.items[j];
3463 nb_outline_points += outline->count;
3464 nb_corners++; /* first outline point always repeated as a corner */
3465 for (k = 1; k < outline->count; k++)
3466 if (outline->items[k].corner)
3467 nb_corners++;
3471 nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
3472 nb_faces = nb_outline_points * 2;
3474 if (!new_mesh(mesh, nb_vertices, nb_faces))
3475 goto error;
3477 /* convert 2D vertices and faces into 3D mesh */
3478 vertex_ptr = mesh->vertices;
3479 face_ptr = mesh->faces;
3480 for (i = 0; i < textlen; i++)
3482 int j;
3484 /* side vertices and faces */
3485 for (j = 0; j < glyphs[i].outlines.count; j++)
3487 struct vertex *outline_vertices = vertex_ptr;
3488 struct outline *outline = &glyphs[i].outlines.items[j];
3489 int k;
3490 struct point2d *prevpt = &outline->items[outline->count - 1];
3491 struct point2d *pt = &outline->items[0];
3493 for (k = 1; k <= outline->count; k++)
3495 struct vertex vtx;
3496 struct point2d *nextpt = &outline->items[k % outline->count];
3497 WORD vtx_idx = vertex_ptr - mesh->vertices;
3498 D3DXVECTOR2 vec;
3500 if (pt->corner == POINTTYPE_CURVE_START)
3501 D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
3502 else if (pt->corner)
3503 D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3504 else
3505 D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
3506 D3DXVec2Normalize(&vec, &vec);
3507 vtx.normal.x = -vec.y;
3508 vtx.normal.y = vec.x;
3509 vtx.normal.z = 0;
3511 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
3512 vtx.position.y = pt->pos.y;
3513 vtx.position.z = 0;
3514 *vertex_ptr++ = vtx;
3516 vtx.position.z = -extrusion;
3517 *vertex_ptr++ = vtx;
3519 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
3520 vtx.position.y = nextpt->pos.y;
3521 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
3522 vtx.position.z = -extrusion;
3523 *vertex_ptr++ = vtx;
3524 vtx.position.z = 0;
3525 *vertex_ptr++ = vtx;
3527 (*face_ptr)[0] = vtx_idx;
3528 (*face_ptr)[1] = vtx_idx + 2;
3529 (*face_ptr)[2] = vtx_idx + 1;
3530 face_ptr++;
3532 (*face_ptr)[0] = vtx_idx;
3533 (*face_ptr)[1] = vtx_idx + 3;
3534 (*face_ptr)[2] = vtx_idx + 2;
3535 face_ptr++;
3536 } else {
3537 if (nextpt->corner) {
3538 if (nextpt->corner == POINTTYPE_CURVE_END) {
3539 struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
3540 D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
3541 } else {
3542 D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3544 D3DXVec2Normalize(&vec, &vec);
3545 vtx.normal.x = -vec.y;
3546 vtx.normal.y = vec.x;
3548 vtx.position.z = 0;
3549 *vertex_ptr++ = vtx;
3550 vtx.position.z = -extrusion;
3551 *vertex_ptr++ = vtx;
3554 (*face_ptr)[0] = vtx_idx;
3555 (*face_ptr)[1] = vtx_idx + 3;
3556 (*face_ptr)[2] = vtx_idx + 1;
3557 face_ptr++;
3559 (*face_ptr)[0] = vtx_idx;
3560 (*face_ptr)[1] = vtx_idx + 2;
3561 (*face_ptr)[2] = vtx_idx + 3;
3562 face_ptr++;
3565 prevpt = pt;
3566 pt = nextpt;
3568 if (!pt->corner) {
3569 *vertex_ptr++ = *outline_vertices++;
3570 *vertex_ptr++ = *outline_vertices++;
3574 /* FIXME: compute expected faces */
3575 /* Add placeholder to separate glyph outlines */
3576 vertex_ptr->position.x = 0;
3577 vertex_ptr->position.y = 0;
3578 vertex_ptr->position.z = 0;
3579 vertex_ptr->normal.x = 0;
3580 vertex_ptr->normal.y = 0;
3581 vertex_ptr->normal.z = 1;
3582 vertex_ptr++;
3585 hr = D3D_OK;
3586 error:
3587 if (glyphs) {
3588 for (i = 0; i < textlen; i++)
3590 int j;
3591 for (j = 0; j < glyphs[i].outlines.count; j++)
3592 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items[j].items);
3593 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items);
3595 HeapFree(GetProcessHeap(), 0, glyphs);
3597 HeapFree(GetProcessHeap(), 0, raw_outline);
3599 return hr == D3D_OK;
3602 static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh, int textlen, float extrusion)
3604 HRESULT hr;
3605 DWORD number_of_vertices, number_of_faces;
3606 IDirect3DVertexBuffer9 *vertex_buffer = NULL;
3607 IDirect3DIndexBuffer9 *index_buffer = NULL;
3608 D3DVERTEXBUFFER_DESC vertex_buffer_description;
3609 D3DINDEXBUFFER_DESC index_buffer_description;
3610 struct vertex *vertices = NULL;
3611 face *faces = NULL;
3612 int expected, i;
3613 int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
3615 number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
3616 number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
3618 /* vertex buffer */
3619 hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
3620 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3621 if (hr != D3D_OK)
3623 skip("Couldn't get vertex buffers\n");
3624 goto error;
3627 hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
3628 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3630 if (hr != D3D_OK)
3632 skip("Couldn't get vertex buffer description\n");
3634 else
3636 ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
3637 name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
3638 ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
3639 name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
3640 ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
3641 ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
3642 name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
3643 ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
3644 name, vertex_buffer_description.FVF, mesh->fvf);
3645 if (mesh->fvf == 0)
3647 expected = number_of_vertices * mesh->vertex_size;
3649 else
3651 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
3653 ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
3654 name, vertex_buffer_description.Size, expected);
3657 hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
3658 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3659 if (hr != D3D_OK)
3661 skip("Couldn't get index buffer\n");
3662 goto error;
3665 hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
3666 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3668 if (hr != D3D_OK)
3670 skip("Couldn't get index buffer description\n");
3672 else
3674 ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
3675 name, index_buffer_description.Format, D3DFMT_INDEX16);
3676 ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
3677 name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
3678 todo_wine ok(index_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, index_buffer_description.Usage, 0);
3679 ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
3680 name, index_buffer_description.Pool, D3DPOOL_MANAGED);
3681 expected = number_of_faces * sizeof(WORD) * 3;
3682 ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
3683 name, index_buffer_description.Size, expected);
3686 /* specify offset and size to avoid potential overruns */
3687 hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
3688 (LPVOID *)&vertices, D3DLOCK_DISCARD);
3689 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3690 if (hr != D3D_OK)
3692 skip("Couldn't lock vertex buffer\n");
3693 goto error;
3695 hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
3696 (LPVOID *)&faces, D3DLOCK_DISCARD);
3697 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3698 if (hr != D3D_OK)
3700 skip("Couldn't lock index buffer\n");
3701 goto error;
3704 face_idx1 = 0;
3705 vtx_idx2 = 0;
3706 face_idx2 = 0;
3707 vtx_idx1 = 0;
3708 for (i = 0; i < textlen; i++)
3710 int nb_outline_vertices1, nb_outline_faces1;
3711 int nb_outline_vertices2, nb_outline_faces2;
3712 int nb_back_vertices, nb_back_faces;
3713 int first_vtx1, first_vtx2;
3714 int first_face1, first_face2;
3715 int j;
3717 first_vtx1 = vtx_idx1;
3718 first_vtx2 = vtx_idx2;
3719 for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
3720 if (vertices[vtx_idx1].normal.z != 0)
3721 break;
3723 for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
3724 if (mesh->vertices[vtx_idx2].normal.z != 0)
3725 break;
3727 nb_outline_vertices1 = vtx_idx1 - first_vtx1;
3728 nb_outline_vertices2 = vtx_idx2 - first_vtx2;
3729 ok(nb_outline_vertices1 == nb_outline_vertices2,
3730 "Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
3731 nb_outline_vertices1, nb_outline_vertices2);
3733 for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
3735 vtx_idx1 = first_vtx1 + j;
3736 vtx_idx2 = first_vtx2 + j;
3737 ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
3738 "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3739 vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
3740 mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
3741 ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
3742 "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3743 vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3744 mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
3746 vtx_idx1 = first_vtx1 + nb_outline_vertices1;
3747 vtx_idx2 = first_vtx2 + nb_outline_vertices2;
3749 first_face1 = face_idx1;
3750 first_face2 = face_idx2;
3751 for (; face_idx1 < number_of_faces; face_idx1++)
3753 if (faces[face_idx1][0] >= vtx_idx1 ||
3754 faces[face_idx1][1] >= vtx_idx1 ||
3755 faces[face_idx1][2] >= vtx_idx1)
3756 break;
3758 for (; face_idx2 < mesh->number_of_faces; face_idx2++)
3760 if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
3761 mesh->faces[face_idx2][1] >= vtx_idx2 ||
3762 mesh->faces[face_idx2][2] >= vtx_idx2)
3763 break;
3765 nb_outline_faces1 = face_idx1 - first_face1;
3766 nb_outline_faces2 = face_idx2 - first_face2;
3767 ok(nb_outline_faces1 == nb_outline_faces2,
3768 "Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
3769 nb_outline_faces1, nb_outline_faces2);
3771 for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
3773 face_idx1 = first_face1 + j;
3774 face_idx2 = first_face2 + j;
3775 ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
3776 faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
3777 faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
3778 "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
3779 faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
3780 mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
3781 mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
3782 mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
3784 face_idx1 = first_face1 + nb_outline_faces1;
3785 face_idx2 = first_face2 + nb_outline_faces2;
3787 /* partial test on back vertices and faces */
3788 first_vtx1 = vtx_idx1;
3789 for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
3790 struct vertex vtx;
3792 if (vertices[vtx_idx1].normal.z != 1.0f)
3793 break;
3795 vtx.position.z = 0.0f;
3796 vtx.normal.x = 0.0f;
3797 vtx.normal.y = 0.0f;
3798 vtx.normal.z = 1.0f;
3799 ok(compare(vertices[vtx_idx1].position.z, vtx.position.z),
3800 "Test %s, glyph %d, vertex position.z %d, result %g, expected %g\n", name, i, vtx_idx1,
3801 vertices[vtx_idx1].position.z, vtx.position.z);
3802 ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
3803 "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3804 vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3805 vtx.normal.x, vtx.normal.y, vtx.normal.z);
3807 nb_back_vertices = vtx_idx1 - first_vtx1;
3808 first_face1 = face_idx1;
3809 for (; face_idx1 < number_of_faces; face_idx1++)
3811 const D3DXVECTOR3 *vtx1, *vtx2, *vtx3;
3812 D3DXVECTOR3 normal;
3813 D3DXVECTOR3 v1 = {0, 0, 0};
3814 D3DXVECTOR3 v2 = {0, 0, 0};
3815 D3DXVECTOR3 forward = {0.0f, 0.0f, 1.0f};
3817 if (faces[face_idx1][0] >= vtx_idx1 ||
3818 faces[face_idx1][1] >= vtx_idx1 ||
3819 faces[face_idx1][2] >= vtx_idx1)
3820 break;
3822 vtx1 = &vertices[faces[face_idx1][0]].position;
3823 vtx2 = &vertices[faces[face_idx1][1]].position;
3824 vtx3 = &vertices[faces[face_idx1][2]].position;
3826 D3DXVec3Subtract(&v1, vtx2, vtx1);
3827 D3DXVec3Subtract(&v2, vtx3, vtx2);
3828 D3DXVec3Cross(&normal, &v1, &v2);
3829 D3DXVec3Normalize(&normal, &normal);
3830 ok(!D3DXVec3Length(&normal) || compare_vec3(normal, forward),
3831 "Test %s, glyph %d, face %d normal, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, face_idx1,
3832 normal.x, normal.y, normal.z, forward.x, forward.y, forward.z);
3834 nb_back_faces = face_idx1 - first_face1;
3836 /* compare front and back faces & vertices */
3837 if (extrusion == 0.0f) {
3838 /* Oddly there are only back faces in this case */
3839 nb_back_vertices /= 2;
3840 nb_back_faces /= 2;
3841 face_idx1 -= nb_back_faces;
3842 vtx_idx1 -= nb_back_vertices;
3844 for (j = 0; j < nb_back_vertices; j++)
3846 struct vertex vtx = vertices[first_vtx1];
3847 vtx.position.z = -extrusion;
3848 vtx.normal.x = 0.0f;
3849 vtx.normal.y = 0.0f;
3850 vtx.normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
3851 ok(compare_vec3(vertices[vtx_idx1].position, vtx.position),
3852 "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3853 vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
3854 vtx.position.x, vtx.position.y, vtx.position.z);
3855 ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
3856 "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3857 vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3858 vtx.normal.x, vtx.normal.y, vtx.normal.z);
3859 vtx_idx1++;
3860 first_vtx1++;
3862 for (j = 0; j < nb_back_faces; j++)
3864 int f1, f2;
3865 if (extrusion == 0.0f) {
3866 f1 = 1;
3867 f2 = 2;
3868 } else {
3869 f1 = 2;
3870 f2 = 1;
3872 ok(faces[face_idx1][0] == faces[first_face1][0] + nb_back_vertices &&
3873 faces[face_idx1][1] == faces[first_face1][f1] + nb_back_vertices &&
3874 faces[face_idx1][2] == faces[first_face1][f2] + nb_back_vertices,
3875 "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
3876 faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
3877 faces[first_face1][0] - nb_back_faces,
3878 faces[first_face1][f1] - nb_back_faces,
3879 faces[first_face1][f2] - nb_back_faces);
3880 first_face1++;
3881 face_idx1++;
3884 /* skip to the outline for the next glyph */
3885 for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
3886 if (mesh->vertices[vtx_idx2].normal.z == 0)
3887 break;
3889 for (; face_idx2 < mesh->number_of_faces; face_idx2++)
3891 if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
3892 mesh->faces[face_idx2][1] >= vtx_idx2 ||
3893 mesh->faces[face_idx2][2] >= vtx_idx2) break;
3897 error:
3898 if (vertices) IDirect3DVertexBuffer9_Unlock(vertex_buffer);
3899 if (faces) IDirect3DIndexBuffer9_Unlock(index_buffer);
3900 if (index_buffer) IDirect3DIndexBuffer9_Release(index_buffer);
3901 if (vertex_buffer) IDirect3DVertexBuffer9_Release(vertex_buffer);
3904 static void test_createtext(IDirect3DDevice9 *device, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion)
3906 HRESULT hr;
3907 ID3DXMesh *d3dxmesh;
3908 struct mesh mesh;
3909 char name[256];
3910 OUTLINETEXTMETRIC otm;
3911 GLYPHMETRICS gm;
3912 GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
3913 int i;
3914 LOGFONT lf;
3915 HFONT font = NULL, oldfont = NULL;
3917 sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion);
3919 hr = D3DXCreateText(device, hdc, text, deviation, extrusion, &d3dxmesh, NULL, glyphmetrics_float);
3920 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3921 if (hr != D3D_OK)
3923 skip("Couldn't create text with D3DXCreateText\n");
3924 return;
3927 /* must select a modified font having lfHeight = otm.otmEMSquare before
3928 * calling GetGlyphOutline to get the expected values */
3929 if (!GetObject(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf) ||
3930 !GetOutlineTextMetrics(hdc, sizeof(otm), &otm))
3932 d3dxmesh->lpVtbl->Release(d3dxmesh);
3933 skip("Couldn't get text outline\n");
3934 return;
3936 lf.lfHeight = otm.otmEMSquare;
3937 lf.lfWidth = 0;
3938 font = CreateFontIndirect(&lf);
3939 if (!font) {
3940 d3dxmesh->lpVtbl->Release(d3dxmesh);
3941 skip("Couldn't create the modified font\n");
3942 return;
3944 oldfont = SelectObject(hdc, font);
3946 for (i = 0; i < strlen(text); i++)
3948 const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
3949 GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
3950 compare_float(glyphmetrics_float[i].gmfBlackBoxX, gm.gmBlackBoxX / (float)otm.otmEMSquare);
3951 compare_float(glyphmetrics_float[i].gmfBlackBoxY, gm.gmBlackBoxY / (float)otm.otmEMSquare);
3952 compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.x, gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare);
3953 compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.y, gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare);
3954 compare_float(glyphmetrics_float[i].gmfCellIncX, gm.gmCellIncX / (float)otm.otmEMSquare);
3955 compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
3958 ZeroMemory(&mesh, sizeof(mesh));
3959 if (!compute_text_mesh(&mesh, hdc, text, deviation, extrusion, otm.otmEMSquare))
3961 skip("Couldn't create mesh\n");
3962 d3dxmesh->lpVtbl->Release(d3dxmesh);
3963 return;
3965 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3967 compare_text_outline_mesh(name, d3dxmesh, &mesh, strlen(text), extrusion);
3969 free_mesh(&mesh);
3971 d3dxmesh->lpVtbl->Release(d3dxmesh);
3972 SelectObject(hdc, oldfont);
3973 HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
3976 static void D3DXCreateTextTest(void)
3978 HRESULT hr;
3979 HWND wnd;
3980 HDC hdc;
3981 IDirect3D9* d3d;
3982 IDirect3DDevice9* device;
3983 D3DPRESENT_PARAMETERS d3dpp;
3984 ID3DXMesh* d3dxmesh = NULL;
3985 HFONT hFont;
3986 OUTLINETEXTMETRIC otm;
3987 int number_of_vertices;
3988 int number_of_faces;
3990 wnd = CreateWindow("static", "d3dx9_test", WS_POPUP, 0, 0, 1000, 1000, NULL, NULL, NULL, NULL);
3991 d3d = Direct3DCreate9(D3D_SDK_VERSION);
3992 if (!wnd)
3994 skip("Couldn't create application window\n");
3995 return;
3997 if (!d3d)
3999 skip("Couldn't create IDirect3D9 object\n");
4000 DestroyWindow(wnd);
4001 return;
4004 ZeroMemory(&d3dpp, sizeof(d3dpp));
4005 d3dpp.Windowed = TRUE;
4006 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
4007 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
4008 if (FAILED(hr))
4010 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
4011 IDirect3D9_Release(d3d);
4012 DestroyWindow(wnd);
4013 return;
4016 hdc = CreateCompatibleDC(NULL);
4018 hFont = CreateFont(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
4019 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
4020 "Arial");
4021 SelectObject(hdc, hFont);
4022 GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
4024 hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, NULL, NULL, NULL);
4025 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4027 /* D3DXCreateTextA page faults from passing NULL text */
4029 hr = D3DXCreateTextW(device, hdc, NULL, 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4030 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4032 hr = D3DXCreateText(device, hdc, "", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4033 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4035 hr = D3DXCreateText(device, hdc, " ", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4036 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4038 hr = D3DXCreateText(NULL, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4039 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4041 hr = D3DXCreateText(device, NULL, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4042 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4044 hr = D3DXCreateText(device, hdc, "wine", -FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4045 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4047 hr = D3DXCreateText(device, hdc, "wine", 0.001f, -FLT_MIN, &d3dxmesh, NULL, NULL);
4048 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4050 /* deviation = 0.0f treated as if deviation = 1.0f / otm.otmEMSquare */
4051 hr = D3DXCreateText(device, hdc, "wine", 1.0f / otm.otmEMSquare, 0.4f, &d3dxmesh, NULL, NULL);
4052 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4053 number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
4054 number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
4055 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4057 hr = D3DXCreateText(device, hdc, "wine", 0.0f, 0.4f, &d3dxmesh, NULL, NULL);
4058 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4059 ok(number_of_vertices == d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh),
4060 "Got %d vertices, expected %d\n",
4061 d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_vertices);
4062 ok(number_of_faces == d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh),
4063 "Got %d faces, expected %d\n",
4064 d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_faces);
4065 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4067 #if 0
4068 /* too much detail requested, so will appear to hang */
4069 trace("Waiting for D3DXCreateText to finish with deviation = FLT_MIN ...\n");
4070 hr = D3DXCreateText(device, hdc, "wine", FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
4071 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4072 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4073 trace("D3DXCreateText finish with deviation = FLT_MIN\n");
4074 #endif
4076 hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
4077 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4078 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4080 test_createtext(device, hdc, "wine", FLT_MAX, 0.4f);
4081 test_createtext(device, hdc, "wine", 0.001f, FLT_MIN);
4082 test_createtext(device, hdc, "wine", 0.001f, 0.0f);
4083 test_createtext(device, hdc, "wine", 0.001f, FLT_MAX);
4084 test_createtext(device, hdc, "wine", 0.0f, 1.0f);
4086 DeleteDC(hdc);
4088 IDirect3DDevice9_Release(device);
4089 IDirect3D9_Release(d3d);
4090 DestroyWindow(wnd);
4093 static void test_get_decl_length(void)
4095 static const D3DVERTEXELEMENT9 declaration1[] =
4097 {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4098 {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4099 {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4100 {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4101 {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4102 {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4103 {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4104 {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4105 {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4106 {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4107 {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4108 {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4109 {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4110 {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4111 {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4112 D3DDECL_END(),
4114 static const D3DVERTEXELEMENT9 declaration2[] =
4116 {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4117 {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4118 {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4119 {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4120 {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4121 {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4122 {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4123 {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4124 {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4125 {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4126 {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4127 {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4128 {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4129 {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4130 {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4131 {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4132 D3DDECL_END(),
4134 UINT size;
4136 size = D3DXGetDeclLength(declaration1);
4137 ok(size == 15, "Got size %u, expected 15.\n", size);
4139 size = D3DXGetDeclLength(declaration2);
4140 ok(size == 16, "Got size %u, expected 16.\n", size);
4143 static void test_get_decl_vertex_size(void)
4145 static const D3DVERTEXELEMENT9 declaration1[] =
4147 {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4148 {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4149 {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4150 {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4151 {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4152 {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4153 {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4154 {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4155 {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4156 {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4157 {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4158 {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4159 {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4160 {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4161 {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4162 D3DDECL_END(),
4164 static const D3DVERTEXELEMENT9 declaration2[] =
4166 {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4167 {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4168 {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4169 {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4170 {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4171 {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4172 {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4173 {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4174 {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4175 {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4176 {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4177 {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4178 {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4179 {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4180 {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4181 {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4182 D3DDECL_END(),
4184 static const UINT sizes1[] =
4186 4, 8, 12, 16,
4187 4, 4, 4, 8,
4188 4, 4, 8, 4,
4189 4, 4, 8, 0,
4191 static const UINT sizes2[] =
4193 12, 16, 20, 24,
4194 12, 12, 16, 16,
4196 unsigned int i;
4197 UINT size;
4199 size = D3DXGetDeclVertexSize(NULL, 0);
4200 ok(size == 0, "Got size %#x, expected 0.\n", size);
4202 for (i = 0; i < 16; ++i)
4204 size = D3DXGetDeclVertexSize(declaration1, i);
4205 ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
4208 for (i = 0; i < 8; ++i)
4210 size = D3DXGetDeclVertexSize(declaration2, i);
4211 ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
4215 static void D3DXGenerateAdjacencyTest(void)
4217 HRESULT hr;
4218 HWND wnd;
4219 IDirect3D9 *d3d;
4220 IDirect3DDevice9 *device;
4221 D3DPRESENT_PARAMETERS d3dpp;
4222 ID3DXMesh *d3dxmesh = NULL;
4223 D3DXVECTOR3 *vertices = NULL;
4224 WORD *indices = NULL;
4225 int i;
4226 struct {
4227 DWORD num_vertices;
4228 D3DXVECTOR3 vertices[6];
4229 DWORD num_faces;
4230 WORD indices[3 * 3];
4231 FLOAT epsilon;
4232 DWORD adjacency[3 * 3];
4233 } test_data[] = {
4234 { /* for epsilon < 0, indices must match for faces to be adjacent */
4235 4, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
4236 2, {0, 1, 2, 0, 2, 3},
4237 -1.0,
4238 {-1, -1, 1, 0, -1, -1},
4241 6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
4242 2, {0, 1, 2, 3, 4, 5},
4243 -1.0,
4244 {-1, -1, -1, -1, -1, -1},
4246 { /* for epsilon == 0, indices or vertices must match for faces to be adjacent */
4247 6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
4248 2, {0, 1, 2, 3, 4, 5},
4249 0.0,
4250 {-1, -1, 1, 0, -1, -1},
4252 { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4253 6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.25}, {1.0, 1.0, 0.25}, {0.0, 1.0, 0.25}},
4254 2, {0, 1, 2, 3, 4, 5},
4255 0.25,
4256 {-1, -1, -1, -1, -1, -1},
4258 { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4259 6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.0, 0.25}, {1.0, 1.0, 0.25}, {0.0, 1.0, 0.25}},
4260 2, {0, 1, 2, 3, 4, 5},
4261 0.250001,
4262 {-1, -1, 1, 0, -1, -1},
4264 { /* length between vertices are compared to epsilon, not the individual dimension deltas */
4265 6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.25, 0.25}, {1.0, 1.25, 0.25}, {0.0, 1.25, 0.25}},
4266 2, {0, 1, 2, 3, 4, 5},
4267 0.353, /* < sqrt(0.25*0.25 + 0.25*0.25) */
4268 {-1, -1, -1, -1, -1, -1},
4271 6, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 0.25, 0.25}, {1.0, 1.25, 0.25}, {0.0, 1.25, 0.25}},
4272 2, {0, 1, 2, 3, 4, 5},
4273 0.354, /* > sqrt(0.25*0.25 + 0.25*0.25) */
4274 {-1, -1, 1, 0, -1, -1},
4276 { /* adjacent faces must have opposite winding orders at the shared edge */
4277 4, {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
4278 2, {0, 1, 2, 0, 3, 2},
4279 0.0,
4280 {-1, -1, -1, -1, -1, -1},
4284 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
4285 if (!wnd)
4287 skip("Couldn't create application window\n");
4288 return;
4290 d3d = Direct3DCreate9(D3D_SDK_VERSION);
4291 if (!d3d)
4293 skip("Couldn't create IDirect3D9 object\n");
4294 DestroyWindow(wnd);
4295 return;
4298 ZeroMemory(&d3dpp, sizeof(d3dpp));
4299 d3dpp.Windowed = TRUE;
4300 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
4301 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
4302 if (FAILED(hr))
4304 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
4305 IDirect3D9_Release(d3d);
4306 DestroyWindow(wnd);
4307 return;
4310 for (i = 0; i < ARRAY_SIZE(test_data); i++)
4312 DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
4313 int j;
4315 if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4316 d3dxmesh = NULL;
4318 hr = D3DXCreateMeshFVF(test_data[i].num_faces, test_data[i].num_vertices, 0, D3DFVF_XYZ, device, &d3dxmesh);
4319 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4321 hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&vertices);
4322 ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4323 if (FAILED(hr)) continue;
4324 CopyMemory(vertices, test_data[i].vertices, test_data[i].num_vertices * sizeof(test_data[0].vertices[0]));
4325 d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
4327 hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&indices);
4328 ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4329 if (FAILED(hr)) continue;
4330 CopyMemory(indices, test_data[i].indices, test_data[i].num_faces * 3 * sizeof(test_data[0].indices[0]));
4331 d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
4333 if (i == 0) {
4334 hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, NULL);
4335 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4338 hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, test_data[i].epsilon, adjacency);
4339 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4340 if (FAILED(hr)) continue;
4342 for (j = 0; j < test_data[i].num_faces * 3; j++)
4343 ok(adjacency[j] == test_data[i].adjacency[j],
4344 "Test %d adjacency %d: Got result %u, expected %u\n", i, j,
4345 adjacency[j], test_data[i].adjacency[j]);
4347 if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4350 static void test_update_semantics(void)
4352 HRESULT hr;
4353 struct test_context *test_context = NULL;
4354 ID3DXMesh *mesh = NULL;
4355 D3DVERTEXELEMENT9 declaration0[] =
4357 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4358 {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4359 {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4360 D3DDECL_END()
4362 D3DVERTEXELEMENT9 declaration_pos_type_color[] =
4364 {0, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4365 {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4366 {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4367 D3DDECL_END()
4369 D3DVERTEXELEMENT9 declaration_smaller[] =
4371 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4372 {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4373 D3DDECL_END()
4375 D3DVERTEXELEMENT9 declaration_larger[] =
4377 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4378 {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4379 {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4380 {0, 40, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4381 D3DDECL_END()
4383 D3DVERTEXELEMENT9 declaration_multiple_streams[] =
4385 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4386 {1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
4387 {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4388 {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4390 D3DDECL_END()
4392 D3DVERTEXELEMENT9 declaration_double_usage[] =
4394 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4395 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4396 {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4397 {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4398 D3DDECL_END()
4400 D3DVERTEXELEMENT9 declaration_undefined_type[] =
4402 {0, 0, D3DDECLTYPE_UNUSED+1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4403 {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4404 {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4405 D3DDECL_END()
4407 D3DVERTEXELEMENT9 declaration_not_4_byte_aligned_offset[] =
4409 {0, 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4410 {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4411 {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4412 D3DDECL_END()
4414 static const struct
4416 D3DXVECTOR3 position0;
4417 D3DXVECTOR3 position1;
4418 D3DXVECTOR3 normal;
4419 DWORD color;
4421 vertices[] =
4423 { { 0.0f, 1.0f, 0.f}, { 1.0f, 0.0f, 0.f}, {0.0f, 0.0f, 1.0f}, 0xffff0000 },
4424 { { 1.0f, -1.0f, 0.f}, {-1.0f, -1.0f, 0.f}, {0.0f, 0.0f, 1.0f}, 0xff00ff00 },
4425 { {-1.0f, -1.0f, 0.f}, {-1.0f, 1.0f, 0.f}, {0.0f, 0.0f, 1.0f}, 0xff0000ff },
4427 unsigned int faces[] = {0, 1, 2};
4428 unsigned int attributes[] = {0};
4429 unsigned int num_faces = ARRAY_SIZE(faces) / 3;
4430 unsigned int num_vertices = ARRAY_SIZE(vertices);
4431 int offset = sizeof(D3DXVECTOR3);
4432 DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4433 void *vertex_buffer;
4434 void *index_buffer;
4435 DWORD *attributes_buffer;
4436 D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
4437 D3DVERTEXELEMENT9 *decl_ptr;
4438 DWORD exp_vertex_size = sizeof(*vertices);
4439 DWORD vertex_size = 0;
4440 int equal;
4441 int i = 0;
4442 int *decl_mem;
4443 int filler_a = 0xaaaaaaaa;
4444 int filler_b = 0xbbbbbbbb;
4446 test_context = new_test_context();
4447 if (!test_context)
4449 skip("Couldn't create a test_context\n");
4450 goto cleanup;
4453 hr = D3DXCreateMesh(num_faces, num_vertices, options, declaration0,
4454 test_context->device, &mesh);
4455 if (FAILED(hr))
4457 skip("Couldn't create test mesh %#x\n", hr);
4458 goto cleanup;
4461 mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
4462 memcpy(vertex_buffer, vertices, sizeof(vertices));
4463 mesh->lpVtbl->UnlockVertexBuffer(mesh);
4465 mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
4466 memcpy(index_buffer, faces, sizeof(faces));
4467 mesh->lpVtbl->UnlockIndexBuffer(mesh);
4469 mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
4470 memcpy(attributes_buffer, attributes, sizeof(attributes));
4471 mesh->lpVtbl->UnlockAttributeBuffer(mesh);
4473 /* Get the declaration and try to change it */
4474 hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4475 if (FAILED(hr))
4477 skip("Couldn't get vertex declaration %#x\n", hr);
4478 goto cleanup;
4480 equal = memcmp(declaration, declaration0, sizeof(declaration0));
4481 ok(equal == 0, "Vertex declarations were not equal\n");
4483 for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4485 if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4487 /* Use second vertex position instead of first */
4488 decl_ptr->Offset = offset;
4492 hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4493 ok(hr == D3D_OK, "Test UpdateSematics, got %#x expected %#x\n", hr, D3D_OK);
4495 /* Check that declaration was written by getting it again */
4496 memset(declaration, 0, sizeof(declaration));
4497 hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4498 if (FAILED(hr))
4500 skip("Couldn't get vertex declaration %#x\n", hr);
4501 goto cleanup;
4504 for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4506 if (decl_ptr->Usage == D3DDECLUSAGE_POSITION)
4508 ok(decl_ptr->Offset == offset, "Test UpdateSematics, got offset %d expected %d\n",
4509 decl_ptr->Offset, offset);
4513 /* Check that GetDeclaration only writes up to the D3DDECL_END() marker and
4514 * not the full MAX_FVF_DECL_SIZE elements.
4516 memset(declaration, filler_a, sizeof(declaration));
4517 memcpy(declaration, declaration0, sizeof(declaration0));
4518 hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4519 ok(hr == D3D_OK, "Test UpdateSematics, "
4520 "got %#x expected D3D_OK\n", hr);
4521 memset(declaration, filler_b, sizeof(declaration));
4522 hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4523 ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4524 decl_mem = (int*)declaration;
4525 for (i = sizeof(declaration0)/sizeof(*decl_mem); i < sizeof(declaration)/sizeof(*decl_mem); i++)
4527 equal = memcmp(&decl_mem[i], &filler_b, sizeof(filler_b));
4528 ok(equal == 0,
4529 "GetDeclaration wrote past the D3DDECL_END() marker. "
4530 "Got %#x, expected %#x\n", decl_mem[i], filler_b);
4531 if (equal != 0) break;
4534 /* UpdateSemantics does not check for overlapping fields */
4535 memset(declaration, 0, sizeof(declaration));
4536 hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4537 if (FAILED(hr))
4539 skip("Couldn't get vertex declaration %#x\n", hr);
4540 goto cleanup;
4543 for (decl_ptr = declaration; decl_ptr->Stream != 0xFF; decl_ptr++)
4545 if (decl_ptr->Type == D3DDECLTYPE_FLOAT3)
4547 decl_ptr->Type = D3DDECLTYPE_FLOAT4;
4551 hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
4552 ok(hr == D3D_OK, "Test UpdateSematics for overlapping fields, "
4553 "got %#x expected D3D_OK\n", hr);
4555 /* Set the position type to color instead of float3 */
4556 hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_pos_type_color);
4557 ok(hr == D3D_OK, "Test UpdateSematics position type color, "
4558 "got %#x expected D3D_OK\n", hr);
4560 /* The following test cases show that NULL, smaller or larger declarations,
4561 * and declarations with non-zero Stream values are not accepted.
4562 * UpdateSemantics returns D3DERR_INVALIDCALL and the previously set
4563 * declaration will be used by DrawSubset, GetNumBytesPerVertex, and
4564 * GetDeclaration.
4567 /* Null declaration (invalid declaration) */
4568 mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4569 hr = mesh->lpVtbl->UpdateSemantics(mesh, NULL);
4570 ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics null pointer declaration, "
4571 "got %#x expected D3DERR_INVALIDCALL\n", hr);
4572 vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4573 ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4574 vertex_size, exp_vertex_size);
4575 memset(declaration, 0, sizeof(declaration));
4576 hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4577 ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4578 equal = memcmp(declaration, declaration0, sizeof(declaration0));
4579 ok(equal == 0, "Vertex declarations were not equal\n");
4581 /* Smaller vertex declaration (invalid declaration) */
4582 mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4583 hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_smaller);
4584 ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics for smaller vertex declaration, "
4585 "got %#x expected D3DERR_INVALIDCALL\n", hr);
4586 vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4587 ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4588 vertex_size, exp_vertex_size);
4589 memset(declaration, 0, sizeof(declaration));
4590 hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4591 ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4592 equal = memcmp(declaration, declaration0, sizeof(declaration0));
4593 ok(equal == 0, "Vertex declarations were not equal\n");
4595 /* Larger vertex declaration (invalid declaration) */
4596 mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4597 hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_larger);
4598 ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics for larger vertex declaration, "
4599 "got %#x expected D3DERR_INVALIDCALL\n", hr);
4600 vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4601 ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4602 vertex_size, exp_vertex_size);
4603 memset(declaration, 0, sizeof(declaration));
4604 hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4605 ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4606 equal = memcmp(declaration, declaration0, sizeof(declaration0));
4607 ok(equal == 0, "Vertex declarations were not equal\n");
4609 /* Use multiple streams and keep the same vertex size (invalid declaration) */
4610 mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4611 hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_multiple_streams);
4612 ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics using multiple streams, "
4613 "got %#x expected D3DERR_INVALIDCALL\n", hr);
4614 vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4615 ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4616 vertex_size, exp_vertex_size);
4617 memset(declaration, 0, sizeof(declaration));
4618 hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4619 ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4620 equal = memcmp(declaration, declaration0, sizeof(declaration0));
4621 ok(equal == 0, "Vertex declarations were not equal\n");
4623 /* The next following test cases show that some invalid declarations are
4624 * accepted with a D3D_OK. An access violation is thrown on Windows if
4625 * DrawSubset is called. The methods GetNumBytesPerVertex and GetDeclaration
4626 * are not affected, which indicates that the declaration is cached.
4629 /* Double usage (invalid declaration) */
4630 mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4631 hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_double_usage);
4632 ok(hr == D3D_OK, "Test UpdateSematics double usage, "
4633 "got %#x expected D3D_OK\n", hr);
4634 vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4635 ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4636 vertex_size, exp_vertex_size);
4637 memset(declaration, 0, sizeof(declaration));
4638 hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4639 ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4640 equal = memcmp(declaration, declaration_double_usage, sizeof(declaration_double_usage));
4641 ok(equal == 0, "Vertex declarations were not equal\n");
4643 /* Set the position to an undefined type (invalid declaration) */
4644 mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4645 hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_undefined_type);
4646 ok(hr == D3D_OK, "Test UpdateSematics undefined type, "
4647 "got %#x expected D3D_OK\n", hr);
4648 vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4649 ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4650 vertex_size, exp_vertex_size);
4651 memset(declaration, 0, sizeof(declaration));
4652 hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4653 ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4654 equal = memcmp(declaration, declaration_undefined_type, sizeof(declaration_undefined_type));
4655 ok(equal == 0, "Vertex declarations were not equal\n");
4657 /* Use a not 4 byte aligned offset (invalid declaration) */
4658 mesh->lpVtbl->UpdateSemantics(mesh, declaration0); /* Set a valid declaration */
4659 hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_not_4_byte_aligned_offset);
4660 ok(hr == D3D_OK, "Test UpdateSematics not 4 byte aligned offset, "
4661 "got %#x expected D3D_OK\n", hr);
4662 vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
4663 ok(vertex_size == exp_vertex_size, "Got vertex declaration size %u, expected %u\n",
4664 vertex_size, exp_vertex_size);
4665 memset(declaration, 0, sizeof(declaration));
4666 hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
4667 ok(hr == D3D_OK, "Couldn't get vertex declaration. Got %#x, expected D3D_OK\n", hr);
4668 equal = memcmp(declaration, declaration_not_4_byte_aligned_offset,
4669 sizeof(declaration_not_4_byte_aligned_offset));
4670 ok(equal == 0, "Vertex declarations were not equal\n");
4672 cleanup:
4673 if (mesh)
4674 mesh->lpVtbl->Release(mesh);
4676 free_test_context(test_context);
4679 static void test_create_skin_info(void)
4681 HRESULT hr;
4682 ID3DXSkinInfo *skininfo = NULL;
4683 D3DVERTEXELEMENT9 empty_declaration[] = { D3DDECL_END() };
4684 D3DVERTEXELEMENT9 declaration_out[MAX_FVF_DECL_SIZE];
4685 const D3DVERTEXELEMENT9 declaration_with_nonzero_stream[] = {
4686 {1, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
4687 D3DDECL_END()
4690 hr = D3DXCreateSkinInfo(0, empty_declaration, 0, &skininfo);
4691 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4692 if (skininfo) IUnknown_Release(skininfo);
4693 skininfo = NULL;
4695 hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
4696 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4698 hr = D3DXCreateSkinInfo(1, declaration_with_nonzero_stream, 1, &skininfo);
4699 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4701 hr = D3DXCreateSkinInfoFVF(1, 0, 1, &skininfo);
4702 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4703 if (skininfo) {
4704 DWORD dword_result;
4705 FLOAT flt_result;
4706 LPCSTR string_result;
4707 D3DXMATRIX *transform;
4708 D3DXMATRIX identity_matrix;
4710 /* test initial values */
4711 hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4712 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4713 if (SUCCEEDED(hr))
4714 compare_elements(declaration_out, empty_declaration, __LINE__, 0);
4716 dword_result = skininfo->lpVtbl->GetNumBones(skininfo);
4717 ok(dword_result == 1, "Expected 1, got %u\n", dword_result);
4719 flt_result = skininfo->lpVtbl->GetMinBoneInfluence(skininfo);
4720 ok(flt_result == 0.0f, "Expected 0.0, got %g\n", flt_result);
4722 string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4723 ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
4725 dword_result = skininfo->lpVtbl->GetFVF(skininfo);
4726 ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4728 dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 0);
4729 ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4731 dword_result = skininfo->lpVtbl->GetNumBoneInfluences(skininfo, 1);
4732 ok(dword_result == 0, "Expected 0, got %u\n", dword_result);
4734 transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, -1);
4735 ok(transform == NULL, "Expected NULL, got %p\n", transform);
4738 /* test [GS]etBoneOffsetMatrix */
4739 hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 1, &identity_matrix);
4740 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4742 hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, NULL);
4743 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4745 D3DXMatrixIdentity(&identity_matrix);
4746 hr = skininfo->lpVtbl->SetBoneOffsetMatrix(skininfo, 0, &identity_matrix);
4747 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4749 transform = skininfo->lpVtbl->GetBoneOffsetMatrix(skininfo, 0);
4750 check_matrix(transform, &identity_matrix);
4754 /* test [GS]etBoneName */
4755 const char *name_in = "testBoneName";
4756 const char *string_result2;
4758 hr = skininfo->lpVtbl->SetBoneName(skininfo, 1, name_in);
4759 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4761 hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, NULL);
4762 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4764 hr = skininfo->lpVtbl->SetBoneName(skininfo, 0, name_in);
4765 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4767 string_result = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4768 ok(string_result != NULL, "Expected non-NULL string, got %p\n", string_result);
4769 ok(!strcmp(string_result, name_in), "Expected '%s', got '%s'\n", name_in, string_result);
4771 string_result2 = skininfo->lpVtbl->GetBoneName(skininfo, 0);
4772 ok(string_result == string_result2, "Expected %p, got %p\n", string_result, string_result2);
4774 string_result = skininfo->lpVtbl->GetBoneName(skininfo, 1);
4775 ok(string_result == NULL, "Expected NULL, got %p\n", string_result);
4779 /* test [GS]etBoneInfluence */
4780 DWORD vertices[2];
4781 FLOAT weights[2];
4782 int i;
4783 DWORD num_influences;
4784 DWORD exp_vertices[2];
4785 FLOAT exp_weights[2];
4787 /* vertex and weight arrays untouched when num_influences is 0 */
4788 vertices[0] = 0xdeadbeef;
4789 weights[0] = FLT_MAX;
4790 hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4791 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4792 ok(vertices[0] == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", vertices[0]);
4793 ok(weights[0] == FLT_MAX, "expected %g, got %g\n", FLT_MAX, weights[0]);
4795 hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 1, vertices, weights);
4796 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4798 hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, NULL);
4799 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4801 hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, NULL);
4802 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4804 hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, NULL, weights);
4805 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4808 /* no vertex or weight value checking */
4809 exp_vertices[0] = 0;
4810 exp_vertices[1] = 0x87654321;
4811 exp_weights[0] = 0.5;
4812 exp_weights[1] = 0.0f / 0.0f; /* NAN */
4813 num_influences = 2;
4815 hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 1, num_influences, vertices, weights);
4816 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4818 hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, weights);
4819 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4821 hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, vertices, NULL);
4822 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4824 hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, NULL, NULL);
4825 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4827 hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, num_influences, exp_vertices, exp_weights);
4828 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4830 memset(vertices, 0, sizeof(vertices));
4831 memset(weights, 0, sizeof(weights));
4832 hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4833 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4834 for (i = 0; i < num_influences; i++) {
4835 ok(exp_vertices[i] == vertices[i],
4836 "influence[%d]: expected vertex %u, got %u\n", i, exp_vertices[i], vertices[i]);
4837 ok((isnan(exp_weights[i]) && isnan(weights[i])) || exp_weights[i] == weights[i],
4838 "influence[%d]: expected weights %g, got %g\n", i, exp_weights[i], weights[i]);
4841 /* vertices and weights aren't returned after setting num_influences to 0 */
4842 memset(vertices, 0, sizeof(vertices));
4843 memset(weights, 0, sizeof(weights));
4844 hr = skininfo->lpVtbl->SetBoneInfluence(skininfo, 0, 0, vertices, weights);
4845 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4847 vertices[0] = 0xdeadbeef;
4848 weights[0] = FLT_MAX;
4849 hr = skininfo->lpVtbl->GetBoneInfluence(skininfo, 0, vertices, weights);
4850 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4851 ok(vertices[0] == 0xdeadbeef, "expected vertex 0xdeadbeef, got %u\n", vertices[0]);
4852 ok(weights[0] == FLT_MAX, "expected weight %g, got %g\n", FLT_MAX, weights[0]);
4856 /* test [GS]etFVF and [GS]etDeclaration */
4857 D3DVERTEXELEMENT9 declaration_in[MAX_FVF_DECL_SIZE];
4858 DWORD fvf = D3DFVF_XYZ;
4859 DWORD got_fvf;
4861 hr = skininfo->lpVtbl->SetDeclaration(skininfo, NULL);
4862 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4864 hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_with_nonzero_stream);
4865 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4867 hr = skininfo->lpVtbl->SetFVF(skininfo, 0);
4868 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4870 hr = D3DXDeclaratorFromFVF(fvf, declaration_in);
4871 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4872 hr = skininfo->lpVtbl->SetDeclaration(skininfo, declaration_in);
4873 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4874 got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4875 ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
4876 hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4877 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4878 compare_elements(declaration_out, declaration_in, __LINE__, 0);
4880 hr = skininfo->lpVtbl->SetDeclaration(skininfo, empty_declaration);
4881 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4882 got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4883 ok(got_fvf == 0, "Expected 0, got %#x\n", got_fvf);
4884 hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4885 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4886 compare_elements(declaration_out, empty_declaration, __LINE__, 0);
4888 hr = skininfo->lpVtbl->SetFVF(skininfo, fvf);
4889 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4890 got_fvf = skininfo->lpVtbl->GetFVF(skininfo);
4891 ok(fvf == got_fvf, "Expected %#x, got %#x\n", fvf, got_fvf);
4892 hr = skininfo->lpVtbl->GetDeclaration(skininfo, declaration_out);
4893 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
4894 compare_elements(declaration_out, declaration_in, __LINE__, 0);
4897 if (skininfo) IUnknown_Release(skininfo);
4898 skininfo = NULL;
4900 hr = D3DXCreateSkinInfoFVF(1, D3DFVF_XYZ, 1, NULL);
4901 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4903 hr = D3DXCreateSkinInfo(1, NULL, 1, &skininfo);
4904 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
4907 static void test_convert_adjacency_to_point_reps(void)
4909 HRESULT hr;
4910 struct test_context *test_context = NULL;
4911 const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
4912 const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
4913 const D3DVERTEXELEMENT9 declaration[] =
4915 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
4916 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
4917 {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
4918 D3DDECL_END()
4920 const unsigned int VERTS_PER_FACE = 3;
4921 void *vertex_buffer;
4922 void *index_buffer;
4923 DWORD *attributes_buffer;
4924 int i, j;
4925 enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
4926 struct vertex_pnc
4928 D3DXVECTOR3 position;
4929 D3DXVECTOR3 normal;
4930 enum color color; /* In case of manual visual inspection */
4932 D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
4933 /* mesh0 (one face)
4935 * 0--1
4936 * | /
4937 * |/
4940 const struct vertex_pnc vertices0[] =
4942 {{ 0.0f, 3.0f, 0.f}, up, RED},
4943 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
4944 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
4946 const DWORD indices0[] = {0, 1, 2};
4947 const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
4948 const unsigned int num_faces0 = ARRAY_SIZE(indices0) / VERTS_PER_FACE;
4949 const DWORD adjacency0[] = {-1, -1, -1};
4950 const DWORD exp_point_rep0[] = {0, 1, 2};
4951 /* mesh1 (right)
4953 * 0--1 3
4954 * | / /|
4955 * |/ / |
4956 * 2 5--4
4958 const struct vertex_pnc vertices1[] =
4960 {{ 0.0f, 3.0f, 0.f}, up, RED},
4961 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
4962 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
4964 {{ 3.0f, 3.0f, 0.f}, up, GREEN},
4965 {{ 3.0f, 0.0f, 0.f}, up, RED},
4966 {{ 1.0f, 0.0f, 0.f}, up, BLUE},
4968 const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
4969 const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
4970 const unsigned int num_faces1 = ARRAY_SIZE(indices1) / VERTS_PER_FACE;
4971 const DWORD adjacency1[] = {-1, 1, -1, -1, -1, 0};
4972 const DWORD exp_point_rep1[] = {0, 1, 2, 1, 4, 2};
4973 /* mesh2 (left)
4975 * 3 0--1
4976 * /| | /
4977 * / | |/
4978 * 5--4 2
4980 const struct vertex_pnc vertices2[] =
4982 {{ 0.0f, 3.0f, 0.f}, up, RED},
4983 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
4984 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
4986 {{-1.0f, 3.0f, 0.f}, up, RED},
4987 {{-1.0f, 0.0f, 0.f}, up, GREEN},
4988 {{-3.0f, 0.0f, 0.f}, up, BLUE},
4990 const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
4991 const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
4992 const unsigned int num_faces2 = ARRAY_SIZE(indices2) / VERTS_PER_FACE;
4993 const DWORD adjacency2[] = {-1, -1, 1, 0, -1, -1};
4994 const DWORD exp_point_rep2[] = {0, 1, 2, 0, 2, 5};
4995 /* mesh3 (above)
4998 * /|
4999 * / |
5000 * 5--4
5001 * 0--1
5002 * | /
5003 * |/
5006 struct vertex_pnc vertices3[] =
5008 {{ 0.0f, 3.0f, 0.f}, up, RED},
5009 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5010 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5012 {{ 2.0f, 7.0f, 0.f}, up, BLUE},
5013 {{ 2.0f, 4.0f, 0.f}, up, GREEN},
5014 {{ 0.0f, 4.0f, 0.f}, up, RED},
5016 const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5017 const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5018 const unsigned int num_faces3 = ARRAY_SIZE(indices3) / VERTS_PER_FACE;
5019 const DWORD adjacency3[] = {1, -1, -1, -1, 0, -1};
5020 const DWORD exp_point_rep3[] = {0, 1, 2, 3, 1, 0};
5021 /* mesh4 (below, tip against tip)
5023 * 0--1
5024 * | /
5025 * |/
5028 * |\
5029 * | \
5030 * 5--4
5032 struct vertex_pnc vertices4[] =
5034 {{ 0.0f, 3.0f, 0.f}, up, RED},
5035 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5036 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5038 {{ 0.0f, -4.0f, 0.f}, up, BLUE},
5039 {{ 2.0f, -7.0f, 0.f}, up, GREEN},
5040 {{ 0.0f, -7.0f, 0.f}, up, RED},
5042 const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5043 const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5044 const unsigned int num_faces4 = ARRAY_SIZE(indices4) / VERTS_PER_FACE;
5045 const DWORD adjacency4[] = {-1, -1, -1, -1, -1, -1};
5046 const DWORD exp_point_rep4[] = {0, 1, 2, 3, 4, 5};
5047 /* mesh5 (gap in mesh)
5049 * 0 3-----4 15
5050 * / \ \ / / \
5051 * / \ \ / / \
5052 * 2-----1 5 17-----16
5053 * 6-----7 9 12-----13
5054 * \ / / \ \ /
5055 * \ / / \ \ /
5056 * 8 10-----11 14
5059 const struct vertex_pnc vertices5[] =
5061 {{ 0.0f, 1.0f, 0.f}, up, RED},
5062 {{ 1.0f, -1.0f, 0.f}, up, GREEN},
5063 {{-1.0f, -1.0f, 0.f}, up, BLUE},
5065 {{ 0.1f, 1.0f, 0.f}, up, RED},
5066 {{ 2.1f, 1.0f, 0.f}, up, BLUE},
5067 {{ 1.1f, -1.0f, 0.f}, up, GREEN},
5069 {{-1.0f, -1.1f, 0.f}, up, BLUE},
5070 {{ 1.0f, -1.1f, 0.f}, up, GREEN},
5071 {{ 0.0f, -3.1f, 0.f}, up, RED},
5073 {{ 1.1f, -1.1f, 0.f}, up, GREEN},
5074 {{ 2.1f, -3.1f, 0.f}, up, BLUE},
5075 {{ 0.1f, -3.1f, 0.f}, up, RED},
5077 {{ 1.2f, -1.1f, 0.f}, up, GREEN},
5078 {{ 3.2f, -1.1f, 0.f}, up, RED},
5079 {{ 2.2f, -3.1f, 0.f}, up, BLUE},
5081 {{ 2.2f, 1.0f, 0.f}, up, BLUE},
5082 {{ 3.2f, -1.0f, 0.f}, up, RED},
5083 {{ 1.2f, -1.0f, 0.f}, up, GREEN},
5085 const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5086 const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5087 const unsigned int num_faces5 = ARRAY_SIZE(indices5) / VERTS_PER_FACE;
5088 const DWORD adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5089 const DWORD exp_point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5090 const WORD indices5_16bit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5091 /* mesh6 (indices re-ordering)
5093 * 0--1 6 3
5094 * | / /| |\
5095 * |/ / | | \
5096 * 2 8--7 5--4
5098 const struct vertex_pnc vertices6[] =
5100 {{ 0.0f, 3.0f, 0.f}, up, RED},
5101 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5102 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5104 {{ 3.0f, 3.0f, 0.f}, up, GREEN},
5105 {{ 3.0f, 0.0f, 0.f}, up, RED},
5106 {{ 1.0f, 0.0f, 0.f}, up, BLUE},
5108 {{ 4.0f, 3.0f, 0.f}, up, GREEN},
5109 {{ 6.0f, 0.0f, 0.f}, up, BLUE},
5110 {{ 4.0f, 0.0f, 0.f}, up, RED},
5112 const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5113 const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5114 const unsigned int num_faces6 = ARRAY_SIZE(indices6) / VERTS_PER_FACE;
5115 const DWORD adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5116 const DWORD exp_point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5117 /* mesh7 (expands collapsed triangle)
5119 * 0--1 3
5120 * | / /|
5121 * |/ / |
5122 * 2 5--4
5124 const struct vertex_pnc vertices7[] =
5126 {{ 0.0f, 3.0f, 0.f}, up, RED},
5127 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5128 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5130 {{ 3.0f, 3.0f, 0.f}, up, GREEN},
5131 {{ 3.0f, 0.0f, 0.f}, up, RED},
5132 {{ 1.0f, 0.0f, 0.f}, up, BLUE},
5134 const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5135 const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5136 const unsigned int num_faces7 = ARRAY_SIZE(indices7) / VERTS_PER_FACE;
5137 const DWORD adjacency7[] = {-1, -1, -1, -1, -1, -1};
5138 const DWORD exp_point_rep7[] = {0, 1, 2, 3, 4, 5};
5139 /* mesh8 (indices re-ordering and double replacement)
5141 * 0--1 9 6
5142 * | / /| |\
5143 * |/ / | | \
5144 * 2 11-10 8--7
5145 * 3--4
5146 * | /
5147 * |/
5150 const struct vertex_pnc vertices8[] =
5152 {{ 0.0f, 3.0f, 0.f}, up, RED},
5153 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5154 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5156 {{ 4.0, -4.0, 0.f}, up, RED},
5157 {{ 6.0, -4.0, 0.f}, up, BLUE},
5158 {{ 4.0, -7.0, 0.f}, up, GREEN},
5160 {{ 4.0f, 3.0f, 0.f}, up, GREEN},
5161 {{ 6.0f, 0.0f, 0.f}, up, BLUE},
5162 {{ 4.0f, 0.0f, 0.f}, up, RED},
5164 {{ 3.0f, 3.0f, 0.f}, up, GREEN},
5165 {{ 3.0f, 0.0f, 0.f}, up, RED},
5166 {{ 1.0f, 0.0f, 0.f}, up, BLUE},
5168 const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5169 const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5170 const unsigned int num_faces8 = ARRAY_SIZE(indices8) / VERTS_PER_FACE;
5171 const DWORD adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5172 const DWORD exp_point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5173 /* mesh9 (right, shared vertices)
5175 * 0--1
5176 * | /|
5177 * |/ |
5178 * 2--3
5180 const struct vertex_pnc vertices9[] =
5182 {{ 0.0f, 3.0f, 0.f}, up, RED},
5183 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5184 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5186 {{ 2.0f, 0.0f, 0.f}, up, RED},
5188 const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5189 const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5190 const unsigned int num_faces9 = ARRAY_SIZE(indices9) / VERTS_PER_FACE;
5191 const DWORD adjacency9[] = {-1, 1, -1, -1, -1, 0};
5192 const DWORD exp_point_rep9[] = {0, 1, 2, 3};
5193 /* All mesh data */
5194 ID3DXMesh *mesh = NULL;
5195 ID3DXMesh *mesh_null_check = NULL;
5196 unsigned int attributes[] = {0};
5197 struct
5199 const struct vertex_pnc *vertices;
5200 const DWORD *indices;
5201 const DWORD num_vertices;
5202 const DWORD num_faces;
5203 const DWORD *adjacency;
5204 const DWORD *exp_point_reps;
5205 const DWORD options;
5207 tc[] =
5210 vertices0,
5211 indices0,
5212 num_vertices0,
5213 num_faces0,
5214 adjacency0,
5215 exp_point_rep0,
5216 options
5219 vertices1,
5220 indices1,
5221 num_vertices1,
5222 num_faces1,
5223 adjacency1,
5224 exp_point_rep1,
5225 options
5228 vertices2,
5229 indices2,
5230 num_vertices2,
5231 num_faces2,
5232 adjacency2,
5233 exp_point_rep2,
5234 options
5237 vertices3,
5238 indices3,
5239 num_vertices3,
5240 num_faces3,
5241 adjacency3,
5242 exp_point_rep3,
5243 options
5246 vertices4,
5247 indices4,
5248 num_vertices4,
5249 num_faces4,
5250 adjacency4,
5251 exp_point_rep4,
5252 options
5255 vertices5,
5256 indices5,
5257 num_vertices5,
5258 num_faces5,
5259 adjacency5,
5260 exp_point_rep5,
5261 options
5264 vertices6,
5265 indices6,
5266 num_vertices6,
5267 num_faces6,
5268 adjacency6,
5269 exp_point_rep6,
5270 options
5273 vertices7,
5274 indices7,
5275 num_vertices7,
5276 num_faces7,
5277 adjacency7,
5278 exp_point_rep7,
5279 options
5282 vertices8,
5283 indices8,
5284 num_vertices8,
5285 num_faces8,
5286 adjacency8,
5287 exp_point_rep8,
5288 options
5291 vertices9,
5292 indices9,
5293 num_vertices9,
5294 num_faces9,
5295 adjacency9,
5296 exp_point_rep9,
5297 options
5300 vertices5,
5301 (DWORD*)indices5_16bit,
5302 num_vertices5,
5303 num_faces5,
5304 adjacency5,
5305 exp_point_rep5,
5306 options_16bit
5309 DWORD *point_reps = NULL;
5311 test_context = new_test_context();
5312 if (!test_context)
5314 skip("Couldn't create test context\n");
5315 goto cleanup;
5318 for (i = 0; i < ARRAY_SIZE(tc); i++)
5320 hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options, declaration,
5321 test_context->device, &mesh);
5322 if (FAILED(hr))
5324 skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5325 goto cleanup;
5328 if (i == 0) /* Save first mesh for later NULL checks */
5329 mesh_null_check = mesh;
5331 point_reps = HeapAlloc(GetProcessHeap(), 0, tc[i].num_vertices * sizeof(*point_reps));
5332 if (!point_reps)
5334 skip("Couldn't allocate point reps array.\n");
5335 goto cleanup;
5338 hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5339 if (FAILED(hr))
5341 skip("Couldn't lock vertex buffer.\n");
5342 goto cleanup;
5344 memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5345 hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5346 if (FAILED(hr))
5348 skip("Couldn't unlock vertex buffer.\n");
5349 goto cleanup;
5352 hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5353 if (FAILED(hr))
5355 skip("Couldn't lock index buffer.\n");
5356 goto cleanup;
5358 if (tc[i].options & D3DXMESH_32BIT)
5360 memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5362 else
5364 memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5366 hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5367 if (FAILED(hr)) {
5368 skip("Couldn't unlock index buffer.\n");
5369 goto cleanup;
5372 hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5373 if (FAILED(hr))
5375 skip("Couldn't lock attributes buffer.\n");
5376 goto cleanup;
5378 memcpy(attributes_buffer, attributes, sizeof(attributes));
5379 hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5380 if (FAILED(hr))
5382 skip("Couldn't unlock attributes buffer.\n");
5383 goto cleanup;
5386 /* Convert adjacency to point representation */
5387 memset(point_reps, -1, tc[i].num_vertices * sizeof(*point_reps));
5388 hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, tc[i].adjacency, point_reps);
5389 ok(hr == D3D_OK, "ConvertAdjacencyToPointReps failed case %d. "
5390 "Got %x expected D3D_OK\n", i, hr);
5392 /* Check point representation */
5393 for (j = 0; j < tc[i].num_vertices; j++)
5395 ok(point_reps[j] == tc[i].exp_point_reps[j],
5396 "Unexpected point representation at (%d, %d)."
5397 " Got %d expected %d\n",
5398 i, j, point_reps[j], tc[i].exp_point_reps[j]);
5401 HeapFree(GetProcessHeap(), 0, point_reps);
5402 point_reps = NULL;
5404 if (i != 0) /* First mesh will be freed during cleanup */
5405 mesh->lpVtbl->Release(mesh);
5408 /* NULL checks */
5409 hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, tc[0].adjacency, NULL);
5410 ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps point_reps NULL. "
5411 "Got %x expected D3DERR_INVALIDCALL\n", hr);
5412 hr = mesh_null_check->lpVtbl->ConvertAdjacencyToPointReps(mesh_null_check, NULL, NULL);
5413 ok(hr == D3DERR_INVALIDCALL, "ConvertAdjacencyToPointReps adjacency and point_reps NULL. "
5414 "Got %x expected D3DERR_INVALIDCALL\n", hr);
5416 cleanup:
5417 if (mesh_null_check)
5418 mesh_null_check->lpVtbl->Release(mesh_null_check);
5419 HeapFree(GetProcessHeap(), 0, point_reps);
5420 free_test_context(test_context);
5423 static void test_convert_point_reps_to_adjacency(void)
5425 HRESULT hr;
5426 struct test_context *test_context = NULL;
5427 const DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
5428 const DWORD options_16bit = D3DXMESH_SYSTEMMEM;
5429 const D3DVERTEXELEMENT9 declaration[] =
5431 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
5432 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
5433 {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
5434 D3DDECL_END()
5436 const unsigned int VERTS_PER_FACE = 3;
5437 void *vertex_buffer;
5438 void *index_buffer;
5439 DWORD *attributes_buffer;
5440 int i, j;
5441 enum color { RED = 0xffff0000, GREEN = 0xff00ff00, BLUE = 0xff0000ff};
5442 struct vertex_pnc
5444 D3DXVECTOR3 position;
5445 D3DXVECTOR3 normal;
5446 enum color color; /* In case of manual visual inspection */
5448 D3DXVECTOR3 up = {0.0f, 0.0f, 1.0f};
5449 /* mesh0 (one face)
5451 * 0--1
5452 * | /
5453 * |/
5456 const struct vertex_pnc vertices0[] =
5458 {{ 0.0f, 3.0f, 0.f}, up, RED},
5459 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5460 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5462 const DWORD indices0[] = {0, 1, 2};
5463 const unsigned int num_vertices0 = ARRAY_SIZE(vertices0);
5464 const unsigned int num_faces0 = num_vertices0 / VERTS_PER_FACE;
5465 const DWORD exp_adjacency0[] = {-1, -1, -1};
5466 const DWORD exp_id_adjacency0[] = {-1, -1, -1};
5467 const DWORD point_rep0[] = {0, 1, 2};
5468 /* mesh1 (right)
5470 * 0--1 3
5471 * | / /|
5472 * |/ / |
5473 * 2 5--4
5475 const struct vertex_pnc vertices1[] =
5477 {{ 0.0f, 3.0f, 0.f}, up, RED},
5478 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5479 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5481 {{ 3.0f, 3.0f, 0.f}, up, GREEN},
5482 {{ 3.0f, 0.0f, 0.f}, up, RED},
5483 {{ 1.0f, 0.0f, 0.f}, up, BLUE},
5485 const DWORD indices1[] = {0, 1, 2, 3, 4, 5};
5486 const unsigned int num_vertices1 = ARRAY_SIZE(vertices1);
5487 const unsigned int num_faces1 = num_vertices1 / VERTS_PER_FACE;
5488 const DWORD exp_adjacency1[] = {-1, 1, -1, -1, -1, 0};
5489 const DWORD exp_id_adjacency1[] = {-1, -1, -1, -1, -1, -1};
5490 const DWORD point_rep1[] = {0, 1, 2, 1, 4, 2};
5491 /* mesh2 (left)
5493 * 3 0--1
5494 * /| | /
5495 * / | |/
5496 * 5--4 2
5498 const struct vertex_pnc vertices2[] =
5500 {{ 0.0f, 3.0f, 0.f}, up, RED},
5501 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5502 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5504 {{-1.0f, 3.0f, 0.f}, up, RED},
5505 {{-1.0f, 0.0f, 0.f}, up, GREEN},
5506 {{-3.0f, 0.0f, 0.f}, up, BLUE},
5508 const DWORD indices2[] = {0, 1, 2, 3, 4, 5};
5509 const unsigned int num_vertices2 = ARRAY_SIZE(vertices2);
5510 const unsigned int num_faces2 = num_vertices2 / VERTS_PER_FACE;
5511 const DWORD exp_adjacency2[] = {-1, -1, 1, 0, -1, -1};
5512 const DWORD exp_id_adjacency2[] = {-1, -1, -1, -1, -1, -1};
5513 const DWORD point_rep2[] = {0, 1, 2, 0, 2, 5};
5514 /* mesh3 (above)
5517 * /|
5518 * / |
5519 * 5--4
5520 * 0--1
5521 * | /
5522 * |/
5525 struct vertex_pnc vertices3[] =
5527 {{ 0.0f, 3.0f, 0.f}, up, RED},
5528 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5529 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5531 {{ 2.0f, 7.0f, 0.f}, up, BLUE},
5532 {{ 2.0f, 4.0f, 0.f}, up, GREEN},
5533 {{ 0.0f, 4.0f, 0.f}, up, RED},
5535 const DWORD indices3[] = {0, 1, 2, 3, 4, 5};
5536 const unsigned int num_vertices3 = ARRAY_SIZE(vertices3);
5537 const unsigned int num_faces3 = num_vertices3 / VERTS_PER_FACE;
5538 const DWORD exp_adjacency3[] = {1, -1, -1, -1, 0, -1};
5539 const DWORD exp_id_adjacency3[] = {-1, -1, -1, -1, -1, -1};
5540 const DWORD point_rep3[] = {0, 1, 2, 3, 1, 0};
5541 /* mesh4 (below, tip against tip)
5543 * 0--1
5544 * | /
5545 * |/
5548 * |\
5549 * | \
5550 * 5--4
5552 struct vertex_pnc vertices4[] =
5554 {{ 0.0f, 3.0f, 0.f}, up, RED},
5555 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5556 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5558 {{ 0.0f, -4.0f, 0.f}, up, BLUE},
5559 {{ 2.0f, -7.0f, 0.f}, up, GREEN},
5560 {{ 0.0f, -7.0f, 0.f}, up, RED},
5562 const DWORD indices4[] = {0, 1, 2, 3, 4, 5};
5563 const unsigned int num_vertices4 = ARRAY_SIZE(vertices4);
5564 const unsigned int num_faces4 = num_vertices4 / VERTS_PER_FACE;
5565 const DWORD exp_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5566 const DWORD exp_id_adjacency4[] = {-1, -1, -1, -1, -1, -1};
5567 const DWORD point_rep4[] = {0, 1, 2, 3, 4, 5};
5568 /* mesh5 (gap in mesh)
5570 * 0 3-----4 15
5571 * / \ \ / / \
5572 * / \ \ / / \
5573 * 2-----1 5 17-----16
5574 * 6-----7 9 12-----13
5575 * \ / / \ \ /
5576 * \ / / \ \ /
5577 * 8 10-----11 14
5580 const struct vertex_pnc vertices5[] =
5582 {{ 0.0f, 1.0f, 0.f}, up, RED},
5583 {{ 1.0f, -1.0f, 0.f}, up, GREEN},
5584 {{-1.0f, -1.0f, 0.f}, up, BLUE},
5586 {{ 0.1f, 1.0f, 0.f}, up, RED},
5587 {{ 2.1f, 1.0f, 0.f}, up, BLUE},
5588 {{ 1.1f, -1.0f, 0.f}, up, GREEN},
5590 {{-1.0f, -1.1f, 0.f}, up, BLUE},
5591 {{ 1.0f, -1.1f, 0.f}, up, GREEN},
5592 {{ 0.0f, -3.1f, 0.f}, up, RED},
5594 {{ 1.1f, -1.1f, 0.f}, up, GREEN},
5595 {{ 2.1f, -3.1f, 0.f}, up, BLUE},
5596 {{ 0.1f, -3.1f, 0.f}, up, RED},
5598 {{ 1.2f, -1.1f, 0.f}, up, GREEN},
5599 {{ 3.2f, -1.1f, 0.f}, up, RED},
5600 {{ 2.2f, -3.1f, 0.f}, up, BLUE},
5602 {{ 2.2f, 1.0f, 0.f}, up, BLUE},
5603 {{ 3.2f, -1.0f, 0.f}, up, RED},
5604 {{ 1.2f, -1.0f, 0.f}, up, GREEN},
5606 const DWORD indices5[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
5607 const unsigned int num_vertices5 = ARRAY_SIZE(vertices5);
5608 const unsigned int num_faces5 = num_vertices5 / VERTS_PER_FACE;
5609 const DWORD exp_adjacency5[] = {-1, 2, -1, -1, 5, -1, 0, -1, -1, 4, -1, -1, 5, -1, 3, -1, 4, 1};
5610 const DWORD exp_id_adjacency5[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5611 const DWORD point_rep5[] = {0, 1, 2, 3, 4, 5, 2, 1, 8, 5, 10, 11, 5, 13, 10, 4, 13, 5};
5612 /* mesh6 (indices re-ordering)
5614 * 0--1 6 3
5615 * | / /| |\
5616 * |/ / | | \
5617 * 2 8--7 5--4
5619 const struct vertex_pnc vertices6[] =
5621 {{ 0.0f, 3.0f, 0.f}, up, RED},
5622 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5623 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5625 {{ 3.0f, 3.0f, 0.f}, up, GREEN},
5626 {{ 3.0f, 0.0f, 0.f}, up, RED},
5627 {{ 1.0f, 0.0f, 0.f}, up, BLUE},
5629 {{ 4.0f, 3.0f, 0.f}, up, GREEN},
5630 {{ 6.0f, 0.0f, 0.f}, up, BLUE},
5631 {{ 4.0f, 0.0f, 0.f}, up, RED},
5633 const DWORD indices6[] = {0, 1, 2, 6, 7, 8, 3, 4, 5};
5634 const unsigned int num_vertices6 = ARRAY_SIZE(vertices6);
5635 const unsigned int num_faces6 = num_vertices6 / VERTS_PER_FACE;
5636 const DWORD exp_adjacency6[] = {-1, 1, -1, 2, -1, 0, -1, -1, 1};
5637 const DWORD exp_id_adjacency6[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1};
5638 const DWORD point_rep6[] = {0, 1, 2, 1, 4, 5, 1, 5, 2};
5639 /* mesh7 (expands collapsed triangle)
5641 * 0--1 3
5642 * | / /|
5643 * |/ / |
5644 * 2 5--4
5646 const struct vertex_pnc vertices7[] =
5648 {{ 0.0f, 3.0f, 0.f}, up, RED},
5649 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5650 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5652 {{ 3.0f, 3.0f, 0.f}, up, GREEN},
5653 {{ 3.0f, 0.0f, 0.f}, up, RED},
5654 {{ 1.0f, 0.0f, 0.f}, up, BLUE},
5656 const DWORD indices7[] = {0, 1, 2, 3, 3, 3}; /* Face 1 is collapsed*/
5657 const unsigned int num_vertices7 = ARRAY_SIZE(vertices7);
5658 const unsigned int num_faces7 = num_vertices7 / VERTS_PER_FACE;
5659 const DWORD exp_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5660 const DWORD exp_id_adjacency7[] = {-1, -1, -1, -1, -1, -1};
5661 const DWORD point_rep7[] = {0, 1, 2, 3, 4, 5};
5662 /* mesh8 (indices re-ordering and double replacement)
5664 * 0--1 9 6
5665 * | / /| |\
5666 * |/ / | | \
5667 * 2 11-10 8--7
5668 * 3--4
5669 * | /
5670 * |/
5673 const struct vertex_pnc vertices8[] =
5675 {{ 0.0f, 3.0f, 0.f}, up, RED},
5676 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5677 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5679 {{ 4.0, -4.0, 0.f}, up, RED},
5680 {{ 6.0, -4.0, 0.f}, up, BLUE},
5681 {{ 4.0, -7.0, 0.f}, up, GREEN},
5683 {{ 4.0f, 3.0f, 0.f}, up, GREEN},
5684 {{ 6.0f, 0.0f, 0.f}, up, BLUE},
5685 {{ 4.0f, 0.0f, 0.f}, up, RED},
5687 {{ 3.0f, 3.0f, 0.f}, up, GREEN},
5688 {{ 3.0f, 0.0f, 0.f}, up, RED},
5689 {{ 1.0f, 0.0f, 0.f}, up, BLUE},
5691 const DWORD indices8[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5692 const WORD indices8_16bit[] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 3, 4, 5};
5693 const unsigned int num_vertices8 = ARRAY_SIZE(vertices8);
5694 const unsigned int num_faces8 = num_vertices8 / VERTS_PER_FACE;
5695 const DWORD exp_adjacency8[] = {-1, 1, -1, 2, -1, 0, -1, 3, 1, 2, -1, -1};
5696 const DWORD exp_id_adjacency8[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5697 const DWORD point_rep8[] = {0, 1, 2, 3, 4, 5, 1, 4, 3, 1, 3, 2};
5698 /* mesh9 (right, shared vertices)
5700 * 0--1
5701 * | /|
5702 * |/ |
5703 * 2--3
5705 const struct vertex_pnc vertices9[] =
5707 {{ 0.0f, 3.0f, 0.f}, up, RED},
5708 {{ 2.0f, 3.0f, 0.f}, up, GREEN},
5709 {{ 0.0f, 0.0f, 0.f}, up, BLUE},
5711 {{ 2.0f, 0.0f, 0.f}, up, RED},
5713 const DWORD indices9[] = {0, 1, 2, 1, 3, 2};
5714 const unsigned int num_vertices9 = ARRAY_SIZE(vertices9);
5715 const unsigned int num_faces9 = 2;
5716 const DWORD exp_adjacency9[] = {-1, 1, -1, -1, -1, 0};
5717 const DWORD exp_id_adjacency9[] = {-1, 1, -1, -1, -1, 0};
5718 const DWORD point_rep9[] = {0, 1, 2, 3};
5719 /* All mesh data */
5720 ID3DXMesh *mesh = NULL;
5721 ID3DXMesh *mesh_null_check = NULL;
5722 unsigned int attributes[] = {0};
5723 struct
5725 const struct vertex_pnc *vertices;
5726 const DWORD *indices;
5727 const DWORD num_vertices;
5728 const DWORD num_faces;
5729 const DWORD *point_reps;
5730 const DWORD *exp_adjacency;
5731 const DWORD *exp_id_adjacency;
5732 const DWORD options;
5734 tc[] =
5737 vertices0,
5738 indices0,
5739 num_vertices0,
5740 num_faces0,
5741 point_rep0,
5742 exp_adjacency0,
5743 exp_id_adjacency0,
5744 options
5747 vertices1,
5748 indices1,
5749 num_vertices1,
5750 num_faces1,
5751 point_rep1,
5752 exp_adjacency1,
5753 exp_id_adjacency1,
5754 options
5757 vertices2,
5758 indices2,
5759 num_vertices2,
5760 num_faces2,
5761 point_rep2,
5762 exp_adjacency2,
5763 exp_id_adjacency2,
5764 options
5767 vertices3,
5768 indices3,
5769 num_vertices3,
5770 num_faces3,
5771 point_rep3,
5772 exp_adjacency3,
5773 exp_id_adjacency3,
5774 options
5777 vertices4,
5778 indices4,
5779 num_vertices4,
5780 num_faces4,
5781 point_rep4,
5782 exp_adjacency4,
5783 exp_id_adjacency4,
5784 options
5787 vertices5,
5788 indices5,
5789 num_vertices5,
5790 num_faces5,
5791 point_rep5,
5792 exp_adjacency5,
5793 exp_id_adjacency5,
5794 options
5797 vertices6,
5798 indices6,
5799 num_vertices6,
5800 num_faces6,
5801 point_rep6,
5802 exp_adjacency6,
5803 exp_id_adjacency6,
5804 options
5807 vertices7,
5808 indices7,
5809 num_vertices7,
5810 num_faces7,
5811 point_rep7,
5812 exp_adjacency7,
5813 exp_id_adjacency7,
5814 options
5817 vertices8,
5818 indices8,
5819 num_vertices8,
5820 num_faces8,
5821 point_rep8,
5822 exp_adjacency8,
5823 exp_id_adjacency8,
5824 options
5827 vertices9,
5828 indices9,
5829 num_vertices9,
5830 num_faces9,
5831 point_rep9,
5832 exp_adjacency9,
5833 exp_id_adjacency9,
5834 options
5837 vertices8,
5838 (DWORD*)indices8_16bit,
5839 num_vertices8,
5840 num_faces8,
5841 point_rep8,
5842 exp_adjacency8,
5843 exp_id_adjacency8,
5844 options_16bit
5847 DWORD *adjacency = NULL;
5849 test_context = new_test_context();
5850 if (!test_context)
5852 skip("Couldn't create test context\n");
5853 goto cleanup;
5856 for (i = 0; i < ARRAY_SIZE(tc); i++)
5858 hr = D3DXCreateMesh(tc[i].num_faces, tc[i].num_vertices, tc[i].options,
5859 declaration, test_context->device, &mesh);
5860 if (FAILED(hr))
5862 skip("Couldn't create mesh %d. Got %x expected D3D_OK\n", i, hr);
5863 goto cleanup;
5866 if (i == 0) /* Save first mesh for later NULL checks */
5867 mesh_null_check = mesh;
5869 adjacency = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
5870 if (!adjacency)
5872 skip("Couldn't allocate adjacency array.\n");
5873 goto cleanup;
5876 hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &vertex_buffer);
5877 if (FAILED(hr))
5879 skip("Couldn't lock vertex buffer.\n");
5880 goto cleanup;
5882 memcpy(vertex_buffer, tc[i].vertices, tc[i].num_vertices * sizeof(*tc[i].vertices));
5883 hr = mesh->lpVtbl->UnlockVertexBuffer(mesh);
5884 if (FAILED(hr))
5886 skip("Couldn't unlock vertex buffer.\n");
5887 goto cleanup;
5889 hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &index_buffer);
5890 if (FAILED(hr))
5892 skip("Couldn't lock index buffer.\n");
5893 goto cleanup;
5895 if (tc[i].options & D3DXMESH_32BIT)
5897 memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(DWORD));
5899 else
5901 memcpy(index_buffer, tc[i].indices, VERTS_PER_FACE * tc[i].num_faces * sizeof(WORD));
5903 hr = mesh->lpVtbl->UnlockIndexBuffer(mesh);
5904 if (FAILED(hr)) {
5905 skip("Couldn't unlock index buffer.\n");
5906 goto cleanup;
5909 hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes_buffer);
5910 if (FAILED(hr))
5912 skip("Couldn't lock attributes buffer.\n");
5913 goto cleanup;
5915 memcpy(attributes_buffer, attributes, sizeof(attributes));
5916 hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh);
5917 if (FAILED(hr))
5919 skip("Couldn't unlock attributes buffer.\n");
5920 goto cleanup;
5923 /* Convert point representation to adjacency*/
5924 memset(adjacency, -2, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
5925 hr = mesh->lpVtbl->ConvertPointRepsToAdjacency(mesh, tc[i].point_reps, adjacency);
5926 ok(hr == D3D_OK, "ConvertPointRepsToAdjacency failed case %d. "
5927 "Got %x expected D3D_OK\n", i, hr);
5928 /* Check adjacency */
5929 for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
5931 ok(adjacency[j] == tc[i].exp_adjacency[j],
5932 "Unexpected adjacency information at (%d, %d)."
5933 " Got %d expected %d\n",
5934 i, j, adjacency[j], tc[i].exp_adjacency[j]);
5937 /* NULL point representation is considered identity. */
5938 memset(adjacency, -2, VERTS_PER_FACE * tc[i].num_faces * sizeof(*adjacency));
5939 hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh, NULL, adjacency);
5940 ok(hr == D3D_OK, "ConvertPointRepsToAdjacency NULL point_reps. "
5941 "Got %x expected D3D_OK\n", hr);
5942 for (j = 0; j < VERTS_PER_FACE * tc[i].num_faces; j++)
5944 ok(adjacency[j] == tc[i].exp_id_adjacency[j],
5945 "Unexpected adjacency information (id) at (%d, %d)."
5946 " Got %d expected %d\n",
5947 i, j, adjacency[j], tc[i].exp_id_adjacency[j]);
5950 HeapFree(GetProcessHeap(), 0, adjacency);
5951 if (i != 0) /* First mesh will be freed during cleanup */
5952 mesh->lpVtbl->Release(mesh);
5955 /* NULL checks */
5956 hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, tc[0].point_reps, NULL);
5957 ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL adjacency. "
5958 "Got %x expected D3DERR_INVALIDCALL\n", hr);
5959 hr = mesh_null_check->lpVtbl->ConvertPointRepsToAdjacency(mesh_null_check, NULL, NULL);
5960 ok(hr == D3DERR_INVALIDCALL, "ConvertPointRepsToAdjacency NULL point_reps and adjacency. "
5961 "Got %x expected D3DERR_INVALIDCALL\n", hr);
5963 cleanup:
5964 if (mesh_null_check)
5965 mesh_null_check->lpVtbl->Release(mesh_null_check);
5966 HeapFree(GetProcessHeap(), 0, adjacency);
5967 free_test_context(test_context);
5970 START_TEST(mesh)
5972 D3DXBoundProbeTest();
5973 D3DXComputeBoundingBoxTest();
5974 D3DXComputeBoundingSphereTest();
5975 D3DXGetFVFVertexSizeTest();
5976 D3DXIntersectTriTest();
5977 D3DXCreateMeshTest();
5978 D3DXCreateMeshFVFTest();
5979 D3DXLoadMeshTest();
5980 D3DXCreateBoxTest();
5981 D3DXCreateSphereTest();
5982 D3DXCreateCylinderTest();
5983 D3DXCreateTextTest();
5984 test_get_decl_length();
5985 test_get_decl_vertex_size();
5986 test_fvf_decl_conversion();
5987 D3DXGenerateAdjacencyTest();
5988 test_update_semantics();
5989 test_create_skin_info();
5990 test_convert_adjacency_to_point_reps();
5991 test_convert_point_reps_to_adjacency();