2 * Copyright 2008 David Adam
3 * Copyright 2008 Luis Busquets
4 * Copyright 2009 Henri Verbeet for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/test.h"
27 /* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose
28 * function call traces of ID3DXAllocateHierarchy callbacks. */
29 #define TRACECALLBACK if(winetest_debug > 1) trace
31 #define admitted_error 0.0001f
33 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
35 #define compare_vertex_sizes(type, exp) \
36 got=D3DXGetFVFVertexSize(type); \
37 ok(got==exp, "Expected: %d, Got: %d\n", exp, got);
39 #define compare_float(got, exp) \
43 ok(_got == _exp, "Expected: %g, Got: %g\n", _exp, _got); \
46 static BOOL compare(FLOAT u, FLOAT v)
48 return (fabs(u-v) < admitted_error);
51 static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v)
53 return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
56 #define check_floats(got, exp, dim) check_floats_(__LINE__, "", got, exp, dim)
57 static void check_floats_(int line, const char *prefix, const float *got, const float *exp, int dim)
60 char exp_buffer[256] = "";
61 char got_buffer[256] = "";
62 char *exp_buffer_ptr = exp_buffer;
63 char *got_buffer_ptr = got_buffer;
66 for (i = 0; i < dim; i++) {
68 exp_buffer_ptr += sprintf(exp_buffer_ptr, ", ");
69 got_buffer_ptr += sprintf(got_buffer_ptr, ", ");
71 equal = equal && compare(*exp, *got);
72 exp_buffer_ptr += sprintf(exp_buffer_ptr, "%g", *exp);
73 got_buffer_ptr += sprintf(got_buffer_ptr, "%g", *got);
76 ok_(__FILE__,line)(equal, "%sExpected (%s), got (%s)", prefix, exp_buffer, got_buffer);
87 static BOOL compare_face(face a, face b)
89 return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
94 DWORD number_of_vertices;
95 struct vertex *vertices;
97 DWORD number_of_faces;
104 static void free_mesh(struct mesh *mesh)
106 HeapFree(GetProcessHeap(), 0, mesh->faces);
107 HeapFree(GetProcessHeap(), 0, mesh->vertices);
110 static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
112 mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
117 mesh->number_of_vertices = number_of_vertices;
119 mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
122 HeapFree(GetProcessHeap(), 0, mesh->vertices);
125 mesh->number_of_faces = number_of_faces;
130 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
133 DWORD number_of_vertices, number_of_faces;
134 IDirect3DVertexBuffer9 *vertex_buffer;
135 IDirect3DIndexBuffer9 *index_buffer;
136 D3DVERTEXBUFFER_DESC vertex_buffer_description;
137 D3DINDEXBUFFER_DESC index_buffer_description;
138 struct vertex *vertices;
142 number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
143 ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
144 name, number_of_vertices, mesh->number_of_vertices);
146 number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
147 ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
148 name, number_of_faces, mesh->number_of_faces);
151 hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
152 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
156 skip("Couldn't get vertex buffer\n");
160 hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
161 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
165 skip("Couldn't get vertex buffer description\n");
169 ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
170 name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
171 ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
172 name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
173 ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
174 ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
175 name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
176 ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
177 name, vertex_buffer_description.FVF, mesh->fvf);
180 expected = number_of_vertices * mesh->vertex_size;
184 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
186 ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
187 name, vertex_buffer_description.Size, expected);
190 /* specify offset and size to avoid potential overruns */
191 hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
192 (LPVOID *)&vertices, D3DLOCK_DISCARD);
193 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
197 skip("Couldn't lock vertex buffer\n");
201 for (i = 0; i < number_of_vertices; i++)
203 ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
204 "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
205 vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
206 mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
207 ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
208 "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
209 vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
210 mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
213 IDirect3DVertexBuffer9_Unlock(vertex_buffer);
216 IDirect3DVertexBuffer9_Release(vertex_buffer);
220 hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
221 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
225 skip("Couldn't get index buffer\n");
229 hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
230 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
234 skip("Couldn't get index buffer description\n");
238 ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
239 name, index_buffer_description.Format, D3DFMT_INDEX16);
240 ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
241 name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
242 todo_wine ok(index_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, index_buffer_description.Usage, 0);
243 ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
244 name, index_buffer_description.Pool, D3DPOOL_MANAGED);
245 expected = number_of_faces * sizeof(WORD) * 3;
246 ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
247 name, index_buffer_description.Size, expected);
250 /* specify offset and size to avoid potential overruns */
251 hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
252 (LPVOID *)&faces, D3DLOCK_DISCARD);
253 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
257 skip("Couldn't lock index buffer\n");
261 for (i = 0; i < number_of_faces; i++)
263 ok(compare_face(faces[i], mesh->faces[i]),
264 "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
265 faces[i][0], faces[i][1], faces[i][2],
266 mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
269 IDirect3DIndexBuffer9_Unlock(index_buffer);
272 IDirect3DIndexBuffer9_Release(index_buffer);
276 static void D3DXBoundProbeTest(void)
279 D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
282 /*____________Test the Box case___________________________*/
283 bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
284 top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
286 raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
287 rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
288 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
289 ok(result == TRUE, "expected TRUE, received FALSE\n");
291 raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
292 rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
293 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
294 ok(result == FALSE, "expected FALSE, received TRUE\n");
296 rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
297 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
298 ok(result == TRUE, "expected TRUE, received FALSE\n");
300 bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
301 top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
302 rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
303 raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
304 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
305 ok(result == FALSE, "expected FALSE, received TRUE\n");
307 bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
308 top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
310 raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
311 rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
312 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
313 ok(result == TRUE, "expected TRUE, received FALSE\n");
315 bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
316 top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
318 raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
319 rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
320 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
321 ok(result == FALSE, "expected FALSE, received TRUE\n");
323 raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
324 rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
325 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
326 ok(result == TRUE, "expected TRUE, received FALSE\n");
328 /*____________Test the Sphere case________________________*/
329 radius = sqrt(77.0f);
330 center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
331 raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
333 rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
334 result = D3DXSphereBoundProbe(¢er, radius, &rayposition, &raydirection);
335 ok(result == TRUE, "expected TRUE, received FALSE\n");
337 rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
338 result = D3DXSphereBoundProbe(¢er, radius, &rayposition, &raydirection);
339 ok(result == FALSE, "expected FALSE, received TRUE\n");
341 rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
342 result = D3DXSphereBoundProbe(¢er, radius, &rayposition, &raydirection);
343 ok(result == FALSE, "expected FALSE, received TRUE\n");
346 static void D3DXComputeBoundingBoxTest(void)
348 D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
351 vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
352 vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
353 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
354 vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
355 vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
357 exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
358 exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
360 hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
362 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
363 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);
364 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);
366 /*________________________*/
368 vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
369 vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
370 vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
371 vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
372 vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
374 exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
375 exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
377 hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
379 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
380 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);
381 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);
383 /*________________________*/
385 vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
386 vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
387 vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
388 vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
389 vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
391 exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
392 exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
394 hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
396 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
397 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);
398 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);
400 /*________________________*/
401 hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
402 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
404 /*________________________*/
405 hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
406 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
408 /*________________________*/
409 hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
410 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
413 static void D3DXComputeBoundingSphereTest(void)
415 D3DXVECTOR3 exp_cen, got_cen, vertex[5];
416 FLOAT exp_rad, got_rad;
419 vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
420 vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
421 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
422 vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
423 vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
426 exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
428 hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
430 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
431 ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
432 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);
434 /*________________________*/
436 vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
437 vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
438 vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
439 vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
440 vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
442 exp_rad = 13.707883f;
443 exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
445 hr = D3DXComputeBoundingSphere(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
447 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
448 ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
449 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);
451 /*________________________*/
452 hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
453 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
455 /*________________________*/
456 hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
457 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
459 /*________________________*/
460 hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
461 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
464 static void print_elements(const D3DVERTEXELEMENT9 *elements)
466 D3DVERTEXELEMENT9 last = D3DDECL_END();
467 const D3DVERTEXELEMENT9 *ptr = elements;
470 while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
473 "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
474 count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
480 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
481 unsigned int line, unsigned int test_id)
483 D3DVERTEXELEMENT9 last = D3DDECL_END();
486 for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
488 int end1 = memcmp(&elements[i], &last, sizeof(last));
489 int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
492 if (!end1 && !end2) break;
494 status = !end1 ^ !end2;
495 ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
496 line, test_id, end1 ? "shorter" : "longer");
499 print_elements(elements);
503 status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
504 ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
507 print_elements(elements);
513 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
514 HRESULT expected_hr, unsigned int line, unsigned int test_id)
517 D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
519 hr = D3DXDeclaratorFromFVF(test_fvf, decl);
520 ok(hr == expected_hr,
521 "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
522 line, test_id, hr, expected_hr);
523 if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
526 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
527 HRESULT expected_hr, unsigned int line, unsigned int test_id)
530 DWORD result_fvf = 0xdeadbeef;
532 hr = D3DXFVFFromDeclarator(decl, &result_fvf);
533 ok(hr == expected_hr,
534 "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
535 line, test_id, hr, expected_hr);
538 ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
539 line, test_id, result_fvf, expected_fvf);
543 static void test_fvf_decl_conversion(void)
547 D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
556 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
560 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
564 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
568 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
569 {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
573 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
574 {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
576 }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
578 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
579 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
581 }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
583 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
584 {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
588 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
589 {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
590 {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
592 }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
594 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
595 {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
596 {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
598 }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
600 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
601 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
605 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
606 {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
607 {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
609 }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
611 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
612 {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
613 {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
615 }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
617 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
618 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
622 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
623 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
624 {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
626 }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
628 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
629 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
630 {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
632 }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
634 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
635 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
636 {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
638 }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
640 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
641 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
642 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
644 }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
646 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
650 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
651 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
653 }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
655 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
659 {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
663 {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
666 /* Make sure textures of different sizes work. */
668 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
670 }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
672 {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
674 }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
676 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
678 }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
680 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
682 }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
683 /* Make sure the TEXCOORD index works correctly - try several textures. */
685 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
686 {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
687 {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
688 {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
690 }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
691 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
692 /* Now try some combination tests. */
694 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
695 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
696 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
697 {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
698 {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
699 {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
701 }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
702 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
704 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
705 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
706 {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
707 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
708 {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
709 {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
711 }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
712 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
716 for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
718 test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
719 test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
722 /* Usage indices for position and normal are apparently ignored. */
724 const D3DVERTEXELEMENT9 decl[] =
726 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
729 test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
732 const D3DVERTEXELEMENT9 decl[] =
734 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
737 test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
739 /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
740 * there are no blend matrices. */
742 const D3DVERTEXELEMENT9 decl[] =
744 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
747 test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
750 const D3DVERTEXELEMENT9 decl[] =
752 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
755 test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
757 /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
759 const D3DVERTEXELEMENT9 decl[] =
761 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
762 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
763 {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
766 test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
767 decl, D3D_OK, __LINE__, 0);
769 /* These are supposed to fail, both ways. */
771 const D3DVERTEXELEMENT9 decl[] =
773 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
776 test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
777 test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
780 const D3DVERTEXELEMENT9 decl[] =
782 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
783 {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
786 test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
787 test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
790 const D3DVERTEXELEMENT9 decl[] =
792 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
793 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
794 {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
797 test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
798 test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
800 /* Test a declaration that can't be converted to an FVF. */
802 const D3DVERTEXELEMENT9 decl[] =
804 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
805 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
806 {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
807 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
808 {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
809 /* 8 bytes padding */
810 {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
813 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
815 /* Elements must be ordered by offset. */
817 const D3DVERTEXELEMENT9 decl[] =
819 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
820 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
823 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
825 /* Basic tests for element order. */
827 const D3DVERTEXELEMENT9 decl[] =
829 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
830 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
831 {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
834 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
837 const D3DVERTEXELEMENT9 decl[] =
839 {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
840 {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
843 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
846 const D3DVERTEXELEMENT9 decl[] =
848 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
849 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
852 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
854 /* Textures must be ordered by texcoords. */
856 const D3DVERTEXELEMENT9 decl[] =
858 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
859 {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
860 {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
861 {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
864 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
866 /* Duplicate elements are not allowed. */
868 const D3DVERTEXELEMENT9 decl[] =
870 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
871 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
872 {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
875 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
877 /* Invalid FVFs cannot be converted to a declarator. */
878 test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
881 static void D3DXGetFVFVertexSizeTest(void)
885 compare_vertex_sizes (D3DFVF_XYZ, 12);
887 compare_vertex_sizes (D3DFVF_XYZB3, 24);
889 compare_vertex_sizes (D3DFVF_XYZB5, 32);
891 compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
893 compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
895 compare_vertex_sizes (
898 D3DFVF_TEXCOORDSIZE1(0), 16);
899 compare_vertex_sizes (
902 D3DFVF_TEXCOORDSIZE1(0) |
903 D3DFVF_TEXCOORDSIZE1(1), 20);
905 compare_vertex_sizes (
908 D3DFVF_TEXCOORDSIZE2(0), 20);
910 compare_vertex_sizes (
913 D3DFVF_TEXCOORDSIZE2(0) |
914 D3DFVF_TEXCOORDSIZE2(1), 28);
916 compare_vertex_sizes (
919 D3DFVF_TEXCOORDSIZE2(0) |
920 D3DFVF_TEXCOORDSIZE2(1) |
921 D3DFVF_TEXCOORDSIZE2(2) |
922 D3DFVF_TEXCOORDSIZE2(3) |
923 D3DFVF_TEXCOORDSIZE2(4) |
924 D3DFVF_TEXCOORDSIZE2(5), 60);
926 compare_vertex_sizes (
929 D3DFVF_TEXCOORDSIZE2(0) |
930 D3DFVF_TEXCOORDSIZE2(1) |
931 D3DFVF_TEXCOORDSIZE2(2) |
932 D3DFVF_TEXCOORDSIZE2(3) |
933 D3DFVF_TEXCOORDSIZE2(4) |
934 D3DFVF_TEXCOORDSIZE2(5) |
935 D3DFVF_TEXCOORDSIZE2(6) |
936 D3DFVF_TEXCOORDSIZE2(7), 76);
938 compare_vertex_sizes (
941 D3DFVF_TEXCOORDSIZE3(0), 24);
943 compare_vertex_sizes (
946 D3DFVF_TEXCOORDSIZE3(0) |
947 D3DFVF_TEXCOORDSIZE3(1) |
948 D3DFVF_TEXCOORDSIZE3(2) |
949 D3DFVF_TEXCOORDSIZE3(3), 60);
951 compare_vertex_sizes (
954 D3DFVF_TEXCOORDSIZE4(0), 28);
956 compare_vertex_sizes (
959 D3DFVF_TEXCOORDSIZE4(0) |
960 D3DFVF_TEXCOORDSIZE4(1), 44);
962 compare_vertex_sizes (
965 D3DFVF_TEXCOORDSIZE4(0) |
966 D3DFVF_TEXCOORDSIZE4(1) |
967 D3DFVF_TEXCOORDSIZE4(2), 60);
969 compare_vertex_sizes (
975 D3DFVF_TEXCOORDSIZE4(0) |
976 D3DFVF_TEXCOORDSIZE4(1) |
977 D3DFVF_TEXCOORDSIZE4(2) |
978 D3DFVF_TEXCOORDSIZE4(3) |
979 D3DFVF_TEXCOORDSIZE4(4) |
980 D3DFVF_TEXCOORDSIZE4(5) |
981 D3DFVF_TEXCOORDSIZE4(6) |
982 D3DFVF_TEXCOORDSIZE4(7), 180);
985 static void D3DXIntersectTriTest(void)
987 BOOL exp_res, got_res;
988 D3DXVECTOR3 position, ray, vertex[3];
989 FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
991 vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
992 vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
993 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
995 position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
997 ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
999 exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
1001 got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1002 ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1003 ok( compare(exp_u,got_u), "Expected u = %f, got %f\n",exp_u,got_u);
1004 ok( compare(exp_v,got_v), "Expected v = %f, got %f\n",exp_v,got_v);
1005 ok( compare(exp_dist,got_dist), "Expected distance = %f, got %f\n",exp_dist,got_dist);
1007 /*Only positive ray is taken in account*/
1009 vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1010 vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1011 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
1013 position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
1015 ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
1019 got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1020 ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1022 /*Intersection between ray and triangle in a same plane is considered as empty*/
1024 vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
1025 vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
1026 vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
1028 position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
1030 ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
1034 got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1035 ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1038 static void D3DXCreateMeshTest(void)
1043 IDirect3DDevice9 *device, *test_device;
1044 D3DPRESENT_PARAMETERS d3dpp;
1045 ID3DXMesh *d3dxmesh;
1047 D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1051 static const D3DVERTEXELEMENT9 decl1[3] = {
1052 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1053 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1056 static const D3DVERTEXELEMENT9 decl2[] = {
1057 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1058 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1059 {0, 24, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
1060 {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
1061 {0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
1062 /* 8 bytes padding */
1063 {0, 44, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
1067 static const D3DVERTEXELEMENT9 decl3[] = {
1068 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1069 {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1073 hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1074 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1076 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1077 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1079 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1082 skip("Couldn't create application window\n");
1085 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1088 skip("Couldn't create IDirect3D9 object\n");
1093 ZeroMemory(&d3dpp, sizeof(d3dpp));
1094 d3dpp.Windowed = TRUE;
1095 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1096 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1099 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1100 IDirect3D9_Release(d3d);
1105 hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1106 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1108 hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1109 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1111 hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
1112 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1116 d3dxmesh->lpVtbl->Release(d3dxmesh);
1119 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1120 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1122 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
1123 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1125 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1126 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1131 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1132 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1134 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1135 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1136 ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1140 IDirect3DDevice9_Release(device);
1144 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1145 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1147 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1148 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1152 size = sizeof(decl1) / sizeof(decl1[0]);
1153 for (i = 0; i < size - 1; i++)
1155 ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1156 ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1157 ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1158 ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1159 ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1160 ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1162 ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1166 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1167 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1170 if (!new_mesh(&mesh, 3, 1))
1172 skip("Couldn't create mesh\n");
1176 memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1177 memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1178 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1180 compare_mesh("createmesh1", d3dxmesh, &mesh);
1185 d3dxmesh->lpVtbl->Release(d3dxmesh);
1188 /* Test a declaration that can't be converted to an FVF. */
1189 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1190 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1195 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1196 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1198 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1199 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1200 ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1204 IDirect3DDevice9_Release(device);
1208 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1209 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1213 size = sizeof(decl2) / sizeof(decl2[0]);
1214 for (i = 0; i < size - 1; i++)
1216 ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1217 ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1218 ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1219 ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1220 ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1221 ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1223 ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1227 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1228 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1231 if (!new_mesh(&mesh, 3, 1))
1233 skip("Couldn't create mesh\n");
1237 memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1238 memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1240 mesh.vertex_size = 60;
1242 compare_mesh("createmesh2", d3dxmesh, &mesh);
1247 mesh.vertex_size = d3dxmesh->lpVtbl->GetNumBytesPerVertex(d3dxmesh);
1248 ok(mesh.vertex_size == 60, "Got vertex size %u, expected %u\n", mesh.vertex_size, 60);
1250 d3dxmesh->lpVtbl->Release(d3dxmesh);
1253 /* Test a declaration with multiple streams. */
1254 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
1255 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1257 IDirect3DDevice9_Release(device);
1258 IDirect3D9_Release(d3d);
1262 static void D3DXCreateMeshFVFTest(void)
1267 IDirect3DDevice9 *device, *test_device;
1268 D3DPRESENT_PARAMETERS d3dpp;
1269 ID3DXMesh *d3dxmesh;
1271 D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1275 static const D3DVERTEXELEMENT9 decl[3] = {
1276 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1277 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1280 hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1281 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1283 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, NULL, &d3dxmesh);
1284 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1286 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1289 skip("Couldn't create application window\n");
1292 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1295 skip("Couldn't create IDirect3D9 object\n");
1300 ZeroMemory(&d3dpp, sizeof(d3dpp));
1301 d3dpp.Windowed = TRUE;
1302 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1303 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1306 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1307 IDirect3D9_Release(d3d);
1312 hr = D3DXCreateMeshFVF(0, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1313 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1315 hr = D3DXCreateMeshFVF(1, 0, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1316 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1318 hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1319 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1323 d3dxmesh->lpVtbl->Release(d3dxmesh);
1326 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1327 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1329 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, NULL);
1330 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1332 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1333 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1338 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1339 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1341 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1342 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1343 ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1347 IDirect3DDevice9_Release(device);
1351 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1352 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1354 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1355 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1359 size = sizeof(decl) / sizeof(decl[0]);
1360 for (i = 0; i < size - 1; i++)
1362 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1363 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1364 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1365 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1366 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1367 test_decl[i].UsageIndex, decl[i].UsageIndex);
1368 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1370 ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1374 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1375 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1378 if (!new_mesh(&mesh, 3, 1))
1380 skip("Couldn't create mesh\n");
1384 memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1385 memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1386 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1388 compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1393 d3dxmesh->lpVtbl->Release(d3dxmesh);
1396 IDirect3DDevice9_Release(device);
1397 IDirect3D9_Release(d3d);
1401 #define check_vertex_buffer(mesh, vertices, num_vertices, fvf) \
1402 check_vertex_buffer_(__LINE__, mesh, vertices, num_vertices, fvf)
1403 static void check_vertex_buffer_(int line, ID3DXMesh *mesh, const void *vertices, DWORD num_vertices, DWORD fvf)
1405 DWORD mesh_num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
1406 DWORD mesh_fvf = mesh->lpVtbl->GetFVF(mesh);
1407 const void *mesh_vertices;
1410 ok_(__FILE__,line)(fvf == mesh_fvf, "expected FVF %x, got %x\n", fvf, mesh_fvf);
1411 ok_(__FILE__,line)(num_vertices == mesh_num_vertices,
1412 "Expected %u vertices, got %u\n", num_vertices, mesh_num_vertices);
1414 hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
1415 ok_(__FILE__,line)(hr == D3D_OK, "LockVertexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1419 if (mesh_fvf == fvf) {
1420 DWORD vertex_size = D3DXGetFVFVertexSize(fvf);
1422 for (i = 0; i < min(num_vertices, mesh_num_vertices); i++)
1424 const FLOAT *exp_float = vertices;
1425 const FLOAT *got_float = mesh_vertices;
1429 BOOL last_beta_dword = FALSE;
1432 switch (fvf & D3DFVF_POSITION_MASK) {
1433 case D3DFVF_XYZ: pos_dim = 3; break;
1434 case D3DFVF_XYZRHW: pos_dim = 4; break;
1440 pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
1441 if (fvf & (D3DFVF_LASTBETA_UBYTE4 | D3DFVF_LASTBETA_D3DCOLOR))
1444 last_beta_dword = TRUE;
1447 case D3DFVF_XYZW: pos_dim = 4; break;
1449 sprintf(prefix, "vertex[%u] position, ", i);
1450 check_floats_(line, prefix, got_float, exp_float, pos_dim);
1451 exp_float += pos_dim;
1452 got_float += pos_dim;
1454 if (last_beta_dword) {
1455 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1456 "Vertex[%u]: Expected last beta %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1461 if (fvf & D3DFVF_NORMAL) {
1462 sprintf(prefix, "vertex[%u] normal, ", i);
1463 check_floats_(line, prefix, got_float, exp_float, 3);
1467 if (fvf & D3DFVF_PSIZE) {
1468 ok_(__FILE__,line)(compare(*exp_float, *got_float),
1469 "Vertex[%u]: Expected psize %g, got %g\n", i, *exp_float, *got_float);
1473 if (fvf & D3DFVF_DIFFUSE) {
1474 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1475 "Vertex[%u]: Expected diffuse %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1479 if (fvf & D3DFVF_SPECULAR) {
1480 ok_(__FILE__,line)(*(DWORD*)exp_float == *(DWORD*)got_float,
1481 "Vertex[%u]: Expected specular %08x, got %08x\n", i, *(DWORD*)exp_float, *(DWORD*)got_float);
1486 texcount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
1487 for (j = 0; j < texcount; j++) {
1488 DWORD dim = (((fvf >> (16 + 2 * j)) + 1) & 0x03) + 1;
1489 sprintf(prefix, "vertex[%u] texture, ", i);
1490 check_floats_(line, prefix, got_float, exp_float, dim);
1495 vertices = (BYTE*)vertices + vertex_size;
1496 mesh_vertices = (BYTE*)mesh_vertices + vertex_size;
1500 mesh->lpVtbl->UnlockVertexBuffer(mesh);
1503 #define check_index_buffer(mesh, indices, num_indices, index_size) \
1504 check_index_buffer_(__LINE__, mesh, indices, num_indices, index_size)
1505 static void check_index_buffer_(int line, ID3DXMesh *mesh, const void *indices, DWORD num_indices, DWORD index_size)
1507 DWORD mesh_index_size = (mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT) ? 4 : 2;
1508 DWORD mesh_num_indices = mesh->lpVtbl->GetNumFaces(mesh) * 3;
1509 const void *mesh_indices;
1513 ok_(__FILE__,line)(index_size == mesh_index_size,
1514 "Expected index size %u, got %u\n", index_size, mesh_index_size);
1515 ok_(__FILE__,line)(num_indices == mesh_num_indices,
1516 "Expected %u indices, got %u\n", num_indices, mesh_num_indices);
1518 hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
1519 ok_(__FILE__,line)(hr == D3D_OK, "LockIndexBuffer returned %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1523 if (mesh_index_size == index_size) {
1524 for (i = 0; i < min(num_indices, mesh_num_indices); i++)
1526 if (index_size == 4)
1527 ok_(__FILE__,line)(*(DWORD*)indices == *(DWORD*)mesh_indices,
1528 "Index[%u]: expected %u, got %u\n", i, *(DWORD*)indices, *(DWORD*)mesh_indices);
1530 ok_(__FILE__,line)(*(WORD*)indices == *(WORD*)mesh_indices,
1531 "Index[%u]: expected %u, got %u\n", i, *(WORD*)indices, *(WORD*)mesh_indices);
1532 indices = (BYTE*)indices + index_size;
1533 mesh_indices = (BYTE*)mesh_indices + index_size;
1536 mesh->lpVtbl->UnlockIndexBuffer(mesh);
1539 #define check_matrix(got, expected) check_matrix_(__LINE__, got, expected)
1540 static void check_matrix_(int line, const D3DXMATRIX *got, const D3DXMATRIX *expected)
1543 for (i = 0; i < 4; i++) {
1544 for (j = 0; j < 4; j++) {
1545 ok_(__FILE__,line)(compare(U(*expected).m[i][j], U(*got).m[i][j]),
1546 "matrix[%u][%u]: expected %g, got %g\n",
1547 i, j, U(*expected).m[i][j], U(*got).m[i][j]);
1552 static void check_colorvalue_(int line, const char *prefix, const D3DCOLORVALUE got, const D3DCOLORVALUE expected)
1554 ok_(__FILE__,line)(expected.r == got.r && expected.g == got.g && expected.b == got.b && expected.a == got.a,
1555 "%sExpected (%g, %g, %g, %g), got (%g, %g, %g, %g)\n", prefix,
1556 expected.r, expected.g, expected.b, expected.a, got.r, got.g, got.b, got.a);
1559 #define check_materials(got, got_count, expected, expected_count) \
1560 check_materials_(__LINE__, got, got_count, expected, expected_count)
1561 static void check_materials_(int line, const D3DXMATERIAL *got, DWORD got_count, const D3DXMATERIAL *expected, DWORD expected_count)
1564 ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
1566 ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
1569 for (i = 0; i < min(expected_count, got_count); i++)
1571 if (!expected[i].pTextureFilename)
1572 ok_(__FILE__,line)(got[i].pTextureFilename == NULL,
1573 "Expected NULL pTextureFilename, got %p\n", got[i].pTextureFilename);
1575 ok_(__FILE__,line)(!strcmp(expected[i].pTextureFilename, got[i].pTextureFilename),
1576 "Expected '%s' for pTextureFilename, got '%s'\n", expected[i].pTextureFilename, got[i].pTextureFilename);
1577 check_colorvalue_(line, "Diffuse: ", got[i].MatD3D.Diffuse, expected[i].MatD3D.Diffuse);
1578 check_colorvalue_(line, "Ambient: ", got[i].MatD3D.Ambient, expected[i].MatD3D.Ambient);
1579 check_colorvalue_(line, "Specular: ", got[i].MatD3D.Specular, expected[i].MatD3D.Specular);
1580 check_colorvalue_(line, "Emissive: ", got[i].MatD3D.Emissive, expected[i].MatD3D.Emissive);
1581 ok_(__FILE__,line)(expected[i].MatD3D.Power == got[i].MatD3D.Power,
1582 "Power: Expected %g, got %g\n", expected[i].MatD3D.Power, got[i].MatD3D.Power);
1586 #define check_generated_adjacency(mesh, got, epsilon) check_generated_adjacency_(__LINE__, mesh, got, epsilon)
1587 static void check_generated_adjacency_(int line, ID3DXMesh *mesh, const DWORD *got, FLOAT epsilon)
1590 DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
1593 expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
1595 skip_(__FILE__, line)("Out of memory\n");
1598 hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
1599 ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1603 for (i = 0; i < num_faces; i++)
1605 ok_(__FILE__, line)(expected[i * 3] == got[i * 3] &&
1606 expected[i * 3 + 1] == got[i * 3 + 1] &&
1607 expected[i * 3 + 2] == got[i * 3 + 2],
1608 "Face %u adjacencies: Expected (%u, %u, %u), got (%u, %u, %u)\n", i,
1609 expected[i * 3], expected[i * 3 + 1], expected[i * 3 + 2],
1610 got[i * 3], got[i * 3 + 1], got[i * 3 + 2]);
1613 HeapFree(GetProcessHeap(), 0, expected);
1616 #define check_generated_effects(materials, num_materials, effects) \
1617 check_generated_effects_(__LINE__, materials, num_materials, effects)
1618 static void check_generated_effects_(int line, const D3DXMATERIAL *materials, DWORD num_materials, const D3DXEFFECTINSTANCE *effects)
1621 static const struct {
1627 #define EFFECT_TABLE_ENTRY(str, field) \
1628 {str, sizeof(str), sizeof(materials->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
1629 EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
1630 EFFECT_TABLE_ENTRY("Power", Power),
1631 EFFECT_TABLE_ENTRY("Specular", Specular),
1632 EFFECT_TABLE_ENTRY("Emissive", Emissive),
1633 EFFECT_TABLE_ENTRY("Ambient", Ambient),
1634 #undef EFFECT_TABLE_ENTRY
1637 if (!num_materials) {
1638 ok_(__FILE__, line)(effects == NULL, "Expected NULL effects, got %p\n", effects);
1641 for (i = 0; i < num_materials; i++)
1644 DWORD expected_num_defaults = ARRAY_SIZE(params) + (materials[i].pTextureFilename ? 1 : 0);
1646 ok_(__FILE__,line)(expected_num_defaults == effects[i].NumDefaults,
1647 "effect[%u] NumDefaults: Expected %u, got %u\n", i,
1648 expected_num_defaults, effects[i].NumDefaults);
1649 for (j = 0; j < min(ARRAY_SIZE(params), effects[i].NumDefaults); j++)
1652 D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1653 ok_(__FILE__,line)(!strcmp(params[j].name, got_param->pParamName),
1654 "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1655 params[j].name, got_param->pParamName);
1656 ok_(__FILE__,line)(D3DXEDT_FLOATS == got_param->Type,
1657 "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1658 D3DXEDT_FLOATS, got_param->Type);
1659 ok_(__FILE__,line)(params[j].num_bytes == got_param->NumBytes,
1660 "effect[%u].pDefaults[%u].NumBytes: Expected %u, got %u\n", i, j,
1661 params[j].num_bytes, got_param->NumBytes);
1662 for (k = 0; k < min(params[j].num_bytes, got_param->NumBytes) / 4; k++)
1664 FLOAT expected = ((FLOAT*)((BYTE*)&materials[i] + params[j].value_offset))[k];
1665 FLOAT got = ((FLOAT*)got_param->pValue)[k];
1666 ok_(__FILE__,line)(compare(expected, got),
1667 "effect[%u].pDefaults[%u] float value %u: Expected %g, got %g\n", i, j, k, expected, got);
1670 if (effects[i].NumDefaults > ARRAY_SIZE(params)) {
1671 D3DXEFFECTDEFAULT *got_param = &effects[i].pDefaults[j];
1672 static const char *expected_name = "Texture0@Name";
1674 ok_(__FILE__,line)(!strcmp(expected_name, got_param->pParamName),
1675 "effect[%u].pDefaults[%u].pParamName: Expected '%s', got '%s'\n", i, j,
1676 expected_name, got_param->pParamName);
1677 ok_(__FILE__,line)(D3DXEDT_STRING == got_param->Type,
1678 "effect[%u].pDefaults[%u].Type: Expected %u, got %u\n", i, j,
1679 D3DXEDT_STRING, got_param->Type);
1680 if (materials[i].pTextureFilename) {
1681 ok_(__FILE__,line)(strlen(materials[i].pTextureFilename) + 1 == got_param->NumBytes,
1682 "effect[%u] texture filename length: Expected %u, got %u\n", i,
1683 (DWORD)strlen(materials[i].pTextureFilename) + 1, got_param->NumBytes);
1684 ok_(__FILE__,line)(!strcmp(materials[i].pTextureFilename, got_param->pValue),
1685 "effect[%u] texture filename: Expected '%s', got '%s'\n", i,
1686 materials[i].pTextureFilename, (char*)got_param->pValue);
1692 static LPSTR strdupA(LPCSTR p)
1695 if (!p) return NULL;
1696 ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
1697 if (ret) strcpy(ret, p);
1701 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
1703 TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
1705 HeapFree(GetProcessHeap(), 0, frame->Name);
1706 HeapFree(GetProcessHeap(), 0, frame);
1711 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface, LPCSTR name, LPD3DXFRAME *new_frame)
1715 TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
1716 frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
1718 return E_OUTOFMEMORY;
1720 frame->Name = strdupA(name);
1722 HeapFree(GetProcessHeap(), 0, frame);
1723 return E_OUTOFMEMORY;
1730 static HRESULT destroy_mesh_container(LPD3DXMESHCONTAINER mesh_container)
1734 if (!mesh_container)
1736 HeapFree(GetProcessHeap(), 0, mesh_container->Name);
1737 if (U(mesh_container->MeshData).pMesh)
1738 IUnknown_Release(U(mesh_container->MeshData).pMesh);
1739 if (mesh_container->pMaterials) {
1740 for (i = 0; i < mesh_container->NumMaterials; i++)
1741 HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials[i].pTextureFilename);
1742 HeapFree(GetProcessHeap(), 0, mesh_container->pMaterials);
1744 if (mesh_container->pEffects) {
1745 for (i = 0; i < mesh_container->NumMaterials; i++) {
1746 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pEffectFilename);
1747 if (mesh_container->pEffects[i].pDefaults) {
1749 for (j = 0; j < mesh_container->pEffects[i].NumDefaults; j++) {
1750 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pParamName);
1751 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults[j].pValue);
1753 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects[i].pDefaults);
1756 HeapFree(GetProcessHeap(), 0, mesh_container->pEffects);
1758 HeapFree(GetProcessHeap(), 0, mesh_container->pAdjacency);
1759 if (mesh_container->pSkinInfo)
1760 IUnknown_Release(mesh_container->pSkinInfo);
1761 HeapFree(GetProcessHeap(), 0, mesh_container);
1765 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_DestroyMeshContainer(ID3DXAllocateHierarchy *iface, LPD3DXMESHCONTAINER mesh_container)
1767 TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyMeshContainer(%p, %p)\n", iface, mesh_container);
1768 return destroy_mesh_container(mesh_container);
1771 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_CreateMeshContainer(ID3DXAllocateHierarchy *iface,
1772 LPCSTR name, CONST D3DXMESHDATA *mesh_data, CONST D3DXMATERIAL *materials,
1773 CONST D3DXEFFECTINSTANCE *effects, DWORD num_materials, CONST DWORD *adjacency,
1774 LPD3DXSKININFO skin_info, LPD3DXMESHCONTAINER *new_mesh_container)
1776 LPD3DXMESHCONTAINER mesh_container = NULL;
1779 TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateMeshContainer(%p, '%s', %u, %p, %p, %p, %d, %p, %p, %p)\n",
1780 iface, name, mesh_data->Type, U(*mesh_data).pMesh, materials, effects,
1781 num_materials, adjacency, skin_info, *new_mesh_container);
1783 mesh_container = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mesh_container));
1784 if (!mesh_container)
1785 return E_OUTOFMEMORY;
1788 mesh_container->Name = strdupA(name);
1789 if (!mesh_container->Name)
1793 mesh_container->NumMaterials = num_materials;
1794 if (num_materials) {
1795 mesh_container->pMaterials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*materials));
1796 if (!mesh_container->pMaterials)
1799 memcpy(mesh_container->pMaterials, materials, num_materials * sizeof(*materials));
1800 for (i = 0; i < num_materials; i++)
1801 mesh_container->pMaterials[i].pTextureFilename = NULL;
1802 for (i = 0; i < num_materials; i++) {
1803 if (materials[i].pTextureFilename) {
1804 mesh_container->pMaterials[i].pTextureFilename = strdupA(materials[i].pTextureFilename);
1805 if (!mesh_container->pMaterials[i].pTextureFilename)
1810 mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
1811 if (!mesh_container->pEffects)
1813 for (i = 0; i < num_materials; i++) {
1815 const D3DXEFFECTINSTANCE *effect_src = &effects[i];
1816 D3DXEFFECTINSTANCE *effect_dest = &mesh_container->pEffects[i];
1818 if (effect_src->pEffectFilename) {
1819 effect_dest->pEffectFilename = strdupA(effect_src->pEffectFilename);
1820 if (!effect_dest->pEffectFilename)
1823 effect_dest->pDefaults = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1824 effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
1825 if (!effect_dest->pDefaults)
1827 effect_dest->NumDefaults = effect_src->NumDefaults;
1828 for (j = 0; j < effect_src->NumDefaults; j++) {
1829 const D3DXEFFECTDEFAULT *default_src = &effect_src->pDefaults[j];
1830 D3DXEFFECTDEFAULT *default_dest = &effect_dest->pDefaults[j];
1832 if (default_src->pParamName) {
1833 default_dest->pParamName = strdupA(default_src->pParamName);
1834 if (!default_dest->pParamName)
1837 default_dest->NumBytes = default_src->NumBytes;
1838 default_dest->Type = default_src->Type;
1839 default_dest->pValue = HeapAlloc(GetProcessHeap(), 0, default_src->NumBytes);
1840 memcpy(default_dest->pValue, default_src->pValue, default_src->NumBytes);
1845 ok(adjacency != NULL, "Expected non-NULL adjacency, got NULL\n");
1847 if (mesh_data->Type == D3DXMESHTYPE_MESH || mesh_data->Type == D3DXMESHTYPE_PMESH) {
1848 ID3DXBaseMesh *basemesh = (ID3DXBaseMesh*)U(*mesh_data).pMesh;
1849 DWORD num_faces = basemesh->lpVtbl->GetNumFaces(basemesh);
1850 size_t size = num_faces * sizeof(DWORD) * 3;
1851 mesh_container->pAdjacency = HeapAlloc(GetProcessHeap(), 0, size);
1852 if (!mesh_container->pAdjacency)
1854 memcpy(mesh_container->pAdjacency, adjacency, size);
1856 ok(mesh_data->Type == D3DXMESHTYPE_PATCHMESH, "Unknown mesh type %u\n", mesh_data->Type);
1857 if (mesh_data->Type == D3DXMESHTYPE_PATCHMESH)
1858 trace("FIXME: copying adjacency data for patch mesh not implemented");
1862 memcpy(&mesh_container->MeshData, mesh_data, sizeof(*mesh_data));
1863 if (U(*mesh_data).pMesh)
1864 IUnknown_AddRef(U(*mesh_data).pMesh);
1866 mesh_container->pSkinInfo = skin_info;
1867 skin_info->lpVtbl->AddRef(skin_info);
1869 *new_mesh_container = mesh_container;
1873 destroy_mesh_container(mesh_container);
1874 return E_OUTOFMEMORY;
1877 static ID3DXAllocateHierarchyVtbl ID3DXAllocateHierarchyImpl_Vtbl = {
1878 ID3DXAllocateHierarchyImpl_CreateFrame,
1879 ID3DXAllocateHierarchyImpl_CreateMeshContainer,
1880 ID3DXAllocateHierarchyImpl_DestroyFrame,
1881 ID3DXAllocateHierarchyImpl_DestroyMeshContainer,
1883 static ID3DXAllocateHierarchy alloc_hier = { &ID3DXAllocateHierarchyImpl_Vtbl };
1885 static void D3DXLoadMeshTest(void)
1887 static const char empty_xfile[] = "xof 0303txt 0032";
1888 /*________________________*/
1889 static const char simple_xfile[] =
1899 static const WORD simple_index_buffer[] = {0, 1, 2};
1900 static const D3DXVECTOR3 simple_vertex_buffer[] = {
1901 {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}
1903 const DWORD simple_fvf = D3DFVF_XYZ;
1904 static const char framed_xfile[] =
1907 "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;; }"
1908 "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */
1909 "1.0, 0.0, 0.0, 0.0,"
1910 "0.0, 1.0, 0.0, 0.0,"
1911 "0.0, 0.0, 1.0, 0.0,"
1912 "0.0, 0.0, 2.0, 1.0;;"
1914 "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;; }"
1915 "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */
1916 "1.0, 0.0, 0.0, 0.0,"
1917 "0.0, 1.0, 0.0, 0.0,"
1918 "0.0, 0.0, 1.0, 0.0,"
1919 "0.0, 0.0, 3.0, 1.0;;"
1921 "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;; }"
1923 static const WORD framed_index_buffer[] = { 0, 1, 2 };
1924 static const D3DXVECTOR3 framed_vertex_buffers[3][3] = {
1925 {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}},
1926 {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}},
1927 {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {3.0, 1.0, 0.0}},
1929 const DWORD framed_fvf = D3DFVF_XYZ;
1930 /*________________________*/
1931 static const char box_xfile[] =
1934 "8;" /* DWORD nVertices; */
1935 /* array Vector vertices[nVertices]; */
1944 "6;" /* DWORD nFaces; */
1945 /* array MeshFace faces[nFaces]; */
1946 "4; 0, 1, 3, 2;," /* (left side) */
1947 "4; 2, 3, 7, 6;," /* (top side) */
1948 "4; 6, 7, 5, 4;," /* (right side) */
1949 "4; 1, 0, 4, 5;," /* (bottom side) */
1950 "4; 1, 5, 7, 3;," /* (back side) */
1951 "4; 0, 2, 6, 4;;" /* (front side) */
1953 "6;" /* DWORD nNormals; */
1954 /* array Vector normals[nNormals]; */
1961 "6;" /* DWORD nFaceNormals; */
1962 /* array MeshFace faceNormals[nFaceNormals]; */
1970 "MeshMaterialList materials {"
1971 "2;" /* DWORD nMaterials; */
1972 "6;" /* DWORD nFaceIndexes; */
1973 /* array DWORD faceIndexes[nFaceIndexes]; */
1974 "0, 0, 0, 1, 1, 1;;"
1976 /* ColorRGBA faceColor; */
1977 "0.0; 0.0; 1.0; 1.0;;"
1980 /* ColorRGB specularColor; */
1982 /* ColorRGB emissiveColor; */
1986 /* ColorRGBA faceColor; */
1987 "1.0; 1.0; 1.0; 1.0;;"
1990 /* ColorRGB specularColor; */
1992 /* ColorRGB emissiveColor; */
1994 "TextureFilename { \"texture.jpg\"; }"
1998 static const WORD box_index_buffer[] = {
2012 static const struct {
2013 D3DXVECTOR3 position;
2015 } box_vertex_buffer[] = {
2016 {{0.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}},
2017 {{0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}},
2018 {{0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}},
2019 {{0.0, 1.0, 1.0}, {-1.0, 0.0, 0.0}},
2020 {{1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}},
2021 {{1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}},
2022 {{1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
2023 {{1.0, 1.0, 1.0}, {0.0, 1.0, 0.0}},
2024 {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}},
2025 {{0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}},
2026 {{1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}},
2027 {{1.0, 1.0, 1.0}, {1.0, 0.0, 0.0}},
2028 {{0.0, 0.0, 1.0}, {0.0, -1.0, 0.0}},
2029 {{0.0, 0.0, 0.0}, {0.0, -1.0, 0.0}},
2030 {{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}},
2031 {{1.0, 0.0, 1.0}, {0.0, -1.0, 0.0}},
2032 {{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}},
2033 {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}},
2034 {{1.0, 1.0, 1.0}, {0.0, 0.0, 1.0}},
2035 {{0.0, 1.0, 1.0}, {0.0, 0.0, 1.0}},
2036 {{0.0, 0.0, 0.0}, {0.0, 0.0, -1.0}},
2037 {{0.0, 1.0, 0.0}, {0.0, 0.0, -1.0}},
2038 {{1.0, 1.0, 0.0}, {0.0, 0.0, -1.0}},
2039 {{1.0, 0.0, 0.0}, {0.0, 0.0, -1.0}},
2041 static const D3DXMATERIAL box_materials[] = {
2044 {0.0, 0.0, 1.0, 1.0}, /* Diffuse */
2045 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2046 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2047 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2050 NULL, /* pTextureFilename */
2054 {1.0, 1.0, 1.0, 1.0}, /* Diffuse */
2055 {0.0, 0.0, 0.0, 1.0}, /* Ambient */
2056 {1.0, 1.0, 1.0, 1.0}, /* Specular */
2057 {0.0, 0.0, 0.0, 1.0}, /* Emissive */
2060 (char *)"texture.jpg", /* pTextureFilename */
2063 const DWORD box_fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2064 /*________________________*/
2067 IDirect3D9 *d3d = NULL;
2068 IDirect3DDevice9 *device = NULL;
2069 D3DPRESENT_PARAMETERS d3dpp;
2070 ID3DXMesh *mesh = NULL;
2071 D3DXFRAME *frame_hier = NULL;
2072 D3DXMATRIX transform;
2074 wnd = CreateWindow("static", "d3dx9_test", WS_POPUP, 0, 0, 1000, 1000, NULL, NULL, NULL, NULL);
2077 skip("Couldn't create application window\n");
2080 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2083 skip("Couldn't create IDirect3D9 object\n");
2087 ZeroMemory(&d3dpp, sizeof(d3dpp));
2088 d3dpp.Windowed = TRUE;
2089 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2090 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2093 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2097 hr = D3DXLoadMeshHierarchyFromXInMemory(NULL, sizeof(simple_xfile) - 1,
2098 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2099 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2101 hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, 0,
2102 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2103 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2105 hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2106 D3DXMESH_MANAGED, NULL, &alloc_hier, NULL, &frame_hier, NULL);
2107 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2109 hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2110 D3DXMESH_MANAGED, device, NULL, NULL, &frame_hier, NULL);
2111 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2113 hr = D3DXLoadMeshHierarchyFromXInMemory(empty_xfile, sizeof(empty_xfile) - 1,
2114 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2115 ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
2117 hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2118 D3DXMESH_MANAGED, device, &alloc_hier, NULL, NULL, NULL);
2119 ok(hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
2121 hr = D3DXLoadMeshHierarchyFromXInMemory(simple_xfile, sizeof(simple_xfile) - 1,
2122 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2123 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2124 if (SUCCEEDED(hr)) {
2125 D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2127 ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2128 D3DXMatrixIdentity(&transform);
2129 check_matrix(&frame_hier->TransformationMatrix, &transform);
2131 ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2132 ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2133 D3DXMESHTYPE_MESH, container->MeshData.Type);
2134 mesh = U(container->MeshData).pMesh;
2135 check_vertex_buffer(mesh, simple_vertex_buffer, ARRAY_SIZE(simple_vertex_buffer), simple_fvf);
2136 check_index_buffer(mesh, simple_index_buffer, ARRAY_SIZE(simple_index_buffer), sizeof(*simple_index_buffer));
2137 check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2138 check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2139 check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2140 hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2141 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2145 hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1,
2146 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2147 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2148 if (SUCCEEDED(hr)) {
2149 D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2151 ok(frame_hier->Name == NULL, "Expected NULL, got '%s'\n", frame_hier->Name);
2152 D3DXMatrixIdentity(&transform);
2153 check_matrix(&frame_hier->TransformationMatrix, &transform);
2155 ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2156 ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2157 D3DXMESHTYPE_MESH, container->MeshData.Type);
2158 mesh = U(container->MeshData).pMesh;
2159 check_vertex_buffer(mesh, box_vertex_buffer, ARRAY_SIZE(box_vertex_buffer), box_fvf);
2160 check_index_buffer(mesh, box_index_buffer, ARRAY_SIZE(box_index_buffer), sizeof(*box_index_buffer));
2161 check_materials(container->pMaterials, container->NumMaterials, box_materials, ARRAY_SIZE(box_materials));
2162 check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2163 check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2164 hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2165 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2169 hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1,
2170 D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL);
2171 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2172 if (SUCCEEDED(hr)) {
2173 D3DXMESHCONTAINER *container = frame_hier->pMeshContainer;
2176 ok(!strcmp(frame_hier->Name, ""), "Expected '', got '%s'\n", frame_hier->Name);
2177 /* last frame transform replaces the first */
2178 D3DXMatrixIdentity(&transform);
2179 U(transform).m[3][2] = 3.0;
2180 check_matrix(&frame_hier->TransformationMatrix, &transform);
2182 for (i = 0; i < 3; i++) {
2183 ok(!strcmp(container->Name, ""), "Expected '', got '%s'\n", container->Name);
2184 ok(container->MeshData.Type == D3DXMESHTYPE_MESH, "Expected %d, got %d\n",
2185 D3DXMESHTYPE_MESH, container->MeshData.Type);
2186 mesh = U(container->MeshData).pMesh;
2187 check_vertex_buffer(mesh, framed_vertex_buffers[i], ARRAY_SIZE(framed_vertex_buffers[0]), framed_fvf);
2188 check_index_buffer(mesh, framed_index_buffer, ARRAY_SIZE(framed_index_buffer), sizeof(*framed_index_buffer));
2189 check_materials(container->pMaterials, container->NumMaterials, NULL, 0);
2190 check_generated_effects(container->pMaterials, container->NumMaterials, container->pEffects);
2191 check_generated_adjacency(mesh, container->pAdjacency, 0.0f);
2192 container = container->pNextMeshContainer;
2194 ok(container == NULL, "Expected NULL, got %p\n", container);
2195 hr = D3DXFrameDestroy(frame_hier, &alloc_hier);
2196 ok(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
2201 if (device) IDirect3DDevice9_Release(device);
2202 if (d3d) IDirect3D9_Release(d3d);
2203 if (wnd) DestroyWindow(wnd);
2206 static void D3DXCreateBoxTest(void)
2212 IDirect3DDevice9* device;
2213 D3DPRESENT_PARAMETERS d3dpp;
2215 ID3DXBuffer* ppBuffer;
2217 static const DWORD adjacency[36]=
2223 1, 3, 11, 5, 6, 10};
2226 wc.lpfnWndProc = DefWindowProcA;
2227 wc.lpszClassName = "d3dx9_test_wc";
2228 if (!RegisterClass(&wc))
2230 skip("RegisterClass failed\n");
2234 wnd = CreateWindow("d3dx9_test_wc", "d3dx9_test",
2235 WS_SYSMENU | WS_POPUP , 0, 0, 640, 480, 0, 0, 0, 0);
2236 ok(wnd != NULL, "Expected to have a window, received NULL\n");
2239 skip("Couldn't create application window\n");
2243 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2246 skip("Couldn't create IDirect3D9 object\n");
2251 memset(&d3dpp, 0, sizeof(d3dpp));
2252 d3dpp.Windowed = TRUE;
2253 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2254 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2257 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2258 IDirect3D9_Release(d3d);
2263 hr = D3DXCreateBuffer(36 * sizeof(DWORD), &ppBuffer);
2264 ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2265 if (FAILED(hr)) goto end;
2267 hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
2268 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2270 hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
2271 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2273 hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
2274 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2276 hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
2277 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2279 hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
2280 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
2282 hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
2283 todo_wine ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
2287 skip("D3DXCreateBox failed\n");
2291 buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
2293 todo_wine ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
2295 box->lpVtbl->Release(box);
2298 IDirect3DDevice9_Release(device);
2299 IDirect3D9_Release(d3d);
2300 ID3DXBuffer_Release(ppBuffer);
2310 static void free_sincos_table(struct sincos_table *sincos_table)
2312 HeapFree(GetProcessHeap(), 0, sincos_table->cos);
2313 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2316 /* pre compute sine and cosine tables; caller must free */
2317 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
2322 sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2323 if (!sincos_table->sin)
2327 sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2328 if (!sincos_table->cos)
2330 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2334 angle = angle_start;
2335 for (i = 0; i < n; i++)
2337 sincos_table->sin[i] = sin(angle);
2338 sincos_table->cos[i] = cos(angle);
2339 angle += angle_step;
2345 static WORD vertex_index(UINT slices, int slice, int stack)
2347 return stack*slices+slice+1;
2350 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
2351 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
2353 float theta_step, theta_start;
2354 struct sincos_table theta;
2355 float phi_step, phi_start;
2356 struct sincos_table phi;
2357 DWORD number_of_vertices, number_of_faces;
2361 /* theta = angle on xy plane wrt x axis */
2362 theta_step = M_PI / stacks;
2363 theta_start = theta_step;
2365 /* phi = angle on xz plane wrt z axis */
2366 phi_step = -2 * M_PI / slices;
2367 phi_start = M_PI / 2;
2369 if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
2373 if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
2375 free_sincos_table(&theta);
2379 number_of_vertices = 2 + slices * (stacks-1);
2380 number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
2382 if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2384 free_sincos_table(&phi);
2385 free_sincos_table(&theta);
2392 mesh->vertices[vertex].normal.x = 0.0f;
2393 mesh->vertices[vertex].normal.y = 0.0f;
2394 mesh->vertices[vertex].normal.z = 1.0f;
2395 mesh->vertices[vertex].position.x = 0.0f;
2396 mesh->vertices[vertex].position.y = 0.0f;
2397 mesh->vertices[vertex].position.z = radius;
2400 for (stack = 0; stack < stacks - 1; stack++)
2402 for (slice = 0; slice < slices; slice++)
2404 mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
2405 mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
2406 mesh->vertices[vertex].normal.z = theta.cos[stack];
2407 mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
2408 mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
2409 mesh->vertices[vertex].position.z = radius * theta.cos[stack];
2416 /* top stack is triangle fan */
2417 mesh->faces[face][0] = 0;
2418 mesh->faces[face][1] = slice + 1;
2419 mesh->faces[face][2] = slice;
2424 /* stacks in between top and bottom are quad strips */
2425 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2426 mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2427 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2430 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2431 mesh->faces[face][1] = vertex_index(slices, slice, stack);
2432 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2440 mesh->faces[face][0] = 0;
2441 mesh->faces[face][1] = 1;
2442 mesh->faces[face][2] = slice;
2447 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2448 mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2449 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2452 mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2453 mesh->faces[face][1] = vertex_index(slices, 0, stack);
2454 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
2459 mesh->vertices[vertex].position.x = 0.0f;
2460 mesh->vertices[vertex].position.y = 0.0f;
2461 mesh->vertices[vertex].position.z = -radius;
2462 mesh->vertices[vertex].normal.x = 0.0f;
2463 mesh->vertices[vertex].normal.y = 0.0f;
2464 mesh->vertices[vertex].normal.z = -1.0f;
2466 /* bottom stack is triangle fan */
2467 for (slice = 1; slice < slices; slice++)
2469 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2470 mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
2471 mesh->faces[face][2] = vertex;
2475 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2476 mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
2477 mesh->faces[face][2] = vertex;
2479 free_sincos_table(&phi);
2480 free_sincos_table(&theta);
2485 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
2492 hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
2493 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2496 skip("Couldn't create sphere\n");
2500 if (!compute_sphere(&mesh, radius, slices, stacks))
2502 skip("Couldn't create mesh\n");
2503 sphere->lpVtbl->Release(sphere);
2507 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2509 sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
2510 compare_mesh(name, sphere, &mesh);
2514 sphere->lpVtbl->Release(sphere);
2517 static void D3DXCreateSphereTest(void)
2522 IDirect3DDevice9* device;
2523 D3DPRESENT_PARAMETERS d3dpp;
2524 ID3DXMesh* sphere = NULL;
2526 hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
2527 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2529 hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
2530 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2532 hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
2533 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2535 hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
2536 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2538 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
2539 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2542 skip("Couldn't create application window\n");
2547 skip("Couldn't create IDirect3D9 object\n");
2552 ZeroMemory(&d3dpp, sizeof(d3dpp));
2553 d3dpp.Windowed = TRUE;
2554 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2555 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2558 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2559 IDirect3D9_Release(d3d);
2564 hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
2565 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2567 hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
2568 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2570 hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
2571 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2573 hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
2574 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2576 test_sphere(device, 0.0f, 2, 2);
2577 test_sphere(device, 1.0f, 2, 2);
2578 test_sphere(device, 1.0f, 3, 2);
2579 test_sphere(device, 1.0f, 4, 4);
2580 test_sphere(device, 1.0f, 3, 4);
2581 test_sphere(device, 5.0f, 6, 7);
2582 test_sphere(device, 10.0f, 11, 12);
2584 IDirect3DDevice9_Release(device);
2585 IDirect3D9_Release(d3d);
2589 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
2591 float theta_step, theta_start;
2592 struct sincos_table theta;
2593 FLOAT delta_radius, radius, radius_step;
2594 FLOAT z, z_step, z_normal;
2595 DWORD number_of_vertices, number_of_faces;
2599 /* theta = angle on xy plane wrt x axis */
2600 theta_step = -2 * M_PI / slices;
2601 theta_start = M_PI / 2;
2603 if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
2608 number_of_vertices = 2 + (slices * (3 + stacks));
2609 number_of_faces = 2 * slices + stacks * (2 * slices);
2611 if (!new_mesh(mesh, number_of_vertices, number_of_faces))
2613 free_sincos_table(&theta);
2620 delta_radius = radius1 - radius2;
2622 radius_step = delta_radius / stacks;
2625 z_step = length / stacks;
2626 z_normal = delta_radius / length;
2627 if (isnan(z_normal))
2632 mesh->vertices[vertex].normal.x = 0.0f;
2633 mesh->vertices[vertex].normal.y = 0.0f;
2634 mesh->vertices[vertex].normal.z = -1.0f;
2635 mesh->vertices[vertex].position.x = 0.0f;
2636 mesh->vertices[vertex].position.y = 0.0f;
2637 mesh->vertices[vertex++].position.z = z;
2639 for (slice = 0; slice < slices; slice++, vertex++)
2641 mesh->vertices[vertex].normal.x = 0.0f;
2642 mesh->vertices[vertex].normal.y = 0.0f;
2643 mesh->vertices[vertex].normal.z = -1.0f;
2644 mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2645 mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2646 mesh->vertices[vertex].position.z = z;
2650 mesh->faces[face][0] = 0;
2651 mesh->faces[face][1] = slice;
2652 mesh->faces[face++][2] = slice + 1;
2656 mesh->faces[face][0] = 0;
2657 mesh->faces[face][1] = slice;
2658 mesh->faces[face++][2] = 1;
2660 for (stack = 1; stack <= stacks+1; stack++)
2662 for (slice = 0; slice < slices; slice++, vertex++)
2664 mesh->vertices[vertex].normal.x = theta.cos[slice];
2665 mesh->vertices[vertex].normal.y = theta.sin[slice];
2666 mesh->vertices[vertex].normal.z = z_normal;
2667 D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
2668 mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2669 mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2670 mesh->vertices[vertex].position.z = z;
2672 if (stack > 1 && slice > 0)
2674 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2675 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2676 mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
2678 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
2679 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2680 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
2686 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
2687 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2688 mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
2690 mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
2691 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
2692 mesh->faces[face++][2] = vertex_index(slices, 0, stack);
2695 if (stack < stacks + 1)
2698 radius -= radius_step;
2702 for (slice = 0; slice < slices; slice++, vertex++)
2704 mesh->vertices[vertex].normal.x = 0.0f;
2705 mesh->vertices[vertex].normal.y = 0.0f;
2706 mesh->vertices[vertex].normal.z = 1.0f;
2707 mesh->vertices[vertex].position.x = radius * theta.cos[slice];
2708 mesh->vertices[vertex].position.y = radius * theta.sin[slice];
2709 mesh->vertices[vertex].position.z = z;
2713 mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
2714 mesh->faces[face][1] = number_of_vertices - 1;
2715 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
2719 mesh->vertices[vertex].position.x = 0.0f;
2720 mesh->vertices[vertex].position.y = 0.0f;
2721 mesh->vertices[vertex].position.z = z;
2722 mesh->vertices[vertex].normal.x = 0.0f;
2723 mesh->vertices[vertex].normal.y = 0.0f;
2724 mesh->vertices[vertex].normal.z = 1.0f;
2726 mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
2727 mesh->faces[face][1] = number_of_vertices - 1;
2728 mesh->faces[face][2] = vertex_index(slices, 0, stack);
2730 free_sincos_table(&theta);
2735 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
2738 ID3DXMesh *cylinder;
2742 hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
2743 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2746 skip("Couldn't create cylinder\n");
2750 if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
2752 skip("Couldn't create mesh\n");
2753 cylinder->lpVtbl->Release(cylinder);
2757 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2759 sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
2760 compare_mesh(name, cylinder, &mesh);
2764 cylinder->lpVtbl->Release(cylinder);
2767 static void D3DXCreateCylinderTest(void)
2772 IDirect3DDevice9* device;
2773 D3DPRESENT_PARAMETERS d3dpp;
2774 ID3DXMesh* cylinder = NULL;
2776 hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
2777 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2779 hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
2780 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2782 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
2783 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2786 skip("Couldn't create application window\n");
2791 skip("Couldn't create IDirect3D9 object\n");
2796 ZeroMemory(&d3dpp, sizeof(d3dpp));
2797 d3dpp.Windowed = TRUE;
2798 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2799 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2802 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2803 IDirect3D9_Release(d3d);
2808 hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
2809 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2811 hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
2812 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
2814 if (SUCCEEDED(hr) && cylinder)
2816 cylinder->lpVtbl->Release(cylinder);
2819 hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
2820 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2822 hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
2823 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
2825 if (SUCCEEDED(hr) && cylinder)
2827 cylinder->lpVtbl->Release(cylinder);
2830 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
2831 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2833 /* Test with length == 0.0f succeeds */
2834 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
2835 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
2837 if (SUCCEEDED(hr) && cylinder)
2839 cylinder->lpVtbl->Release(cylinder);
2842 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
2843 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2845 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
2846 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2848 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
2849 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2851 test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
2852 test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
2853 test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
2854 test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
2855 test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
2856 test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
2858 IDirect3DDevice9_Release(device);
2859 IDirect3D9_Release(d3d);
2863 struct dynamic_array
2865 int count, capacity;
2870 POINTTYPE_CURVE = 0,
2872 POINTTYPE_CURVE_START,
2873 POINTTYPE_CURVE_END,
2874 POINTTYPE_CURVE_MIDDLE,
2880 enum pointtype corner;
2883 /* is a dynamic_array */
2886 int count, capacity;
2887 struct point2d *items;
2890 /* is a dynamic_array */
2891 struct outline_array
2893 int count, capacity;
2894 struct outline *items;
2899 struct outline_array outlines;
2903 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
2905 if (count > array->capacity) {
2908 if (array->items && array->capacity) {
2909 new_capacity = max(array->capacity * 2, count);
2910 new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
2912 new_capacity = max(16, count);
2913 new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
2917 array->items = new_buffer;
2918 array->capacity = new_capacity;
2923 static struct point2d *add_point(struct outline *array)
2925 struct point2d *item;
2927 if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
2930 item = &array->items[array->count++];
2931 ZeroMemory(item, sizeof(*item));
2935 static struct outline *add_outline(struct outline_array *array)
2937 struct outline *item;
2939 if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
2942 item = &array->items[array->count++];
2943 ZeroMemory(item, sizeof(*item));
2947 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
2949 D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
2951 D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
2952 pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
2953 pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
2959 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
2960 const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
2961 float max_deviation)
2963 D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
2966 D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
2967 D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
2968 D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
2970 deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
2971 if (deviation < max_deviation) {
2972 struct point2d *pt = add_point(outline);
2973 if (!pt) return E_OUTOFMEMORY;
2975 pt->corner = POINTTYPE_CURVE;
2976 /* the end point is omitted because the end line merges into the next segment of
2977 * the split bezier curve, and the end of the split bezier curve is added outside
2978 * this recursive function. */
2980 HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
2981 if (hr != S_OK) return hr;
2982 hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
2983 if (hr != S_OK) return hr;
2989 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
2991 /* dot product = cos(theta) */
2992 return D3DXVec2Dot(dir1, dir2) > cos_theta;
2995 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
2997 return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
3000 static BOOL attempt_line_merge(struct outline *outline,
3002 const D3DXVECTOR2 *nextpt,
3005 D3DXVECTOR2 curdir, lastdir;
3006 struct point2d *prevpt, *pt;
3008 const float cos_half = cos(D3DXToRadian(0.5f));
3010 pt = &outline->items[pt_index];
3011 pt_index = (pt_index - 1 + outline->count) % outline->count;
3012 prevpt = &outline->items[pt_index];
3015 pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
3017 if (outline->count < 2)
3020 /* remove last point if the next line continues the last line */
3021 unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3022 unit_vec2(&curdir, &pt->pos, nextpt);
3023 if (is_direction_similar(&lastdir, &curdir, cos_half))
3026 if (pt->corner == POINTTYPE_CURVE_END)
3027 prevpt->corner = pt->corner;
3028 if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
3029 prevpt->corner = POINTTYPE_CURVE_MIDDLE;
3033 if (outline->count < 2)
3036 pt_index = (pt_index - 1 + outline->count) % outline->count;
3037 prevpt = &outline->items[pt_index];
3038 unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
3039 unit_vec2(&curdir, &pt->pos, nextpt);
3044 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
3045 float max_deviation, float emsquare)
3047 const float cos_45 = cos(D3DXToRadian(45.0f));
3048 const float cos_90 = cos(D3DXToRadian(90.0f));
3049 TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
3051 while ((char *)header < (char *)raw_outline + datasize)
3053 TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
3054 struct point2d *lastpt, *pt;
3055 D3DXVECTOR2 lastdir;
3056 D3DXVECTOR2 *pt_flt;
3058 struct outline *outline = add_outline(&glyph->outlines);
3061 return E_OUTOFMEMORY;
3063 pt = add_point(outline);
3065 return E_OUTOFMEMORY;
3066 pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
3068 pt->corner = POINTTYPE_CORNER;
3070 if (header->dwType != TT_POLYGON_TYPE)
3071 trace("Unknown header type %d\n", header->dwType);
3073 while ((char *)curve < (char *)header + header->cb)
3075 D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
3076 BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
3079 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3083 pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
3085 attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
3090 int count = curve->cpfx;
3095 D3DXVECTOR2 bezier_end;
3097 D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
3098 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
3101 bezier_start = bezier_end;
3105 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
3109 pt = add_point(outline);
3111 return E_OUTOFMEMORY;
3113 pt->pos = pt_flt[j];
3114 pt->corner = POINTTYPE_CURVE_END;
3116 for (j = 0; j < curve->cpfx; j++)
3118 pt = add_point(outline);
3120 return E_OUTOFMEMORY;
3121 pt->pos = pt_flt[j];
3122 pt->corner = POINTTYPE_CORNER;
3126 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3129 /* remove last point if the next line continues the last line */
3130 if (outline->count >= 3) {
3133 lastpt = &outline->items[outline->count - 1];
3134 pt = &outline->items[0];
3135 if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
3136 if (lastpt->corner == POINTTYPE_CURVE_END)
3138 if (pt->corner == POINTTYPE_CURVE_START)
3139 pt->corner = POINTTYPE_CURVE_MIDDLE;
3141 pt->corner = POINTTYPE_CURVE_END;
3144 lastpt = &outline->items[outline->count - 1];
3146 /* outline closed with a line from end to start point */
3147 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
3149 lastpt = &outline->items[0];
3150 to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
3151 if (lastpt->corner == POINTTYPE_CURVE_START)
3152 lastpt->corner = POINTTYPE_CORNER;
3153 pt = &outline->items[1];
3154 if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
3155 *lastpt = outline->items[outline->count];
3158 lastpt = &outline->items[outline->count - 1];
3159 pt = &outline->items[0];
3160 unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
3161 for (j = 0; j < outline->count; j++)
3166 pt = &outline->items[(j + 1) % outline->count];
3167 unit_vec2(&curdir, &lastpt->pos, &pt->pos);
3169 switch (lastpt->corner)
3171 case POINTTYPE_CURVE_START:
3172 case POINTTYPE_CURVE_END:
3173 if (!is_direction_similar(&lastdir, &curdir, cos_45))
3174 lastpt->corner = POINTTYPE_CORNER;
3176 case POINTTYPE_CURVE_MIDDLE:
3177 if (!is_direction_similar(&lastdir, &curdir, cos_90))
3178 lastpt->corner = POINTTYPE_CORNER;
3180 lastpt->corner = POINTTYPE_CURVE;
3188 header = (TTPOLYGONHEADER *)((char *)header + header->cb);
3193 static BOOL compute_text_mesh(struct mesh *mesh, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion, FLOAT otmEMSquare)
3195 HRESULT hr = E_FAIL;
3196 DWORD nb_vertices, nb_faces;
3197 DWORD nb_corners, nb_outline_points;
3200 char *raw_outline = NULL;
3201 struct glyphinfo *glyphs = NULL;
3204 struct vertex *vertex_ptr;
3207 if (deviation == 0.0f)
3208 deviation = 1.0f / otmEMSquare;
3210 textlen = strlen(text);
3211 glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
3218 for (i = 0; i < textlen; i++)
3220 /* get outline points from data returned from GetGlyphOutline */
3221 const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
3224 glyphs[i].offset_x = offset_x;
3226 datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
3231 HeapFree(GetProcessHeap(), 0, raw_outline);
3232 raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
3237 datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
3239 create_outline(&glyphs[i], raw_outline, datasize, deviation, otmEMSquare);
3241 offset_x += gm.gmCellIncX / (float)otmEMSquare;
3244 /* corner points need an extra vertex for the different side faces normals */
3246 nb_outline_points = 0;
3247 for (i = 0; i < textlen; i++)
3250 for (j = 0; j < glyphs[i].outlines.count; j++)
3253 struct outline *outline = &glyphs[i].outlines.items[j];
3254 nb_outline_points += outline->count;
3255 nb_corners++; /* first outline point always repeated as a corner */
3256 for (k = 1; k < outline->count; k++)
3257 if (outline->items[k].corner)
3262 nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
3263 nb_faces = nb_outline_points * 2;
3265 if (!new_mesh(mesh, nb_vertices, nb_faces))
3268 /* convert 2D vertices and faces into 3D mesh */
3269 vertex_ptr = mesh->vertices;
3270 face_ptr = mesh->faces;
3271 for (i = 0; i < textlen; i++)
3275 /* side vertices and faces */
3276 for (j = 0; j < glyphs[i].outlines.count; j++)
3278 struct vertex *outline_vertices = vertex_ptr;
3279 struct outline *outline = &glyphs[i].outlines.items[j];
3281 struct point2d *prevpt = &outline->items[outline->count - 1];
3282 struct point2d *pt = &outline->items[0];
3284 for (k = 1; k <= outline->count; k++)
3287 struct point2d *nextpt = &outline->items[k % outline->count];
3288 WORD vtx_idx = vertex_ptr - mesh->vertices;
3291 if (pt->corner == POINTTYPE_CURVE_START)
3292 D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
3293 else if (pt->corner)
3294 D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3296 D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
3297 D3DXVec2Normalize(&vec, &vec);
3298 vtx.normal.x = -vec.y;
3299 vtx.normal.y = vec.x;
3302 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
3303 vtx.position.y = pt->pos.y;
3305 *vertex_ptr++ = vtx;
3307 vtx.position.z = -extrusion;
3308 *vertex_ptr++ = vtx;
3310 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
3311 vtx.position.y = nextpt->pos.y;
3312 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
3313 vtx.position.z = -extrusion;
3314 *vertex_ptr++ = vtx;
3316 *vertex_ptr++ = vtx;
3318 (*face_ptr)[0] = vtx_idx;
3319 (*face_ptr)[1] = vtx_idx + 2;
3320 (*face_ptr)[2] = vtx_idx + 1;
3323 (*face_ptr)[0] = vtx_idx;
3324 (*face_ptr)[1] = vtx_idx + 3;
3325 (*face_ptr)[2] = vtx_idx + 2;
3328 if (nextpt->corner) {
3329 if (nextpt->corner == POINTTYPE_CURVE_END) {
3330 struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
3331 D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
3333 D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3335 D3DXVec2Normalize(&vec, &vec);
3336 vtx.normal.x = -vec.y;
3337 vtx.normal.y = vec.x;
3340 *vertex_ptr++ = vtx;
3341 vtx.position.z = -extrusion;
3342 *vertex_ptr++ = vtx;
3345 (*face_ptr)[0] = vtx_idx;
3346 (*face_ptr)[1] = vtx_idx + 3;
3347 (*face_ptr)[2] = vtx_idx + 1;
3350 (*face_ptr)[0] = vtx_idx;
3351 (*face_ptr)[1] = vtx_idx + 2;
3352 (*face_ptr)[2] = vtx_idx + 3;
3360 *vertex_ptr++ = *outline_vertices++;
3361 *vertex_ptr++ = *outline_vertices++;
3365 /* FIXME: compute expected faces */
3366 /* Add placeholder to separate glyph outlines */
3367 vertex_ptr->position.x = 0;
3368 vertex_ptr->position.y = 0;
3369 vertex_ptr->position.z = 0;
3370 vertex_ptr->normal.x = 0;
3371 vertex_ptr->normal.y = 0;
3372 vertex_ptr->normal.z = 1;
3379 for (i = 0; i < textlen; i++)
3382 for (j = 0; j < glyphs[i].outlines.count; j++)
3383 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items[j].items);
3384 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items);
3386 HeapFree(GetProcessHeap(), 0, glyphs);
3388 HeapFree(GetProcessHeap(), 0, raw_outline);
3390 return hr == D3D_OK;
3393 static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh, int textlen, float extrusion)
3396 DWORD number_of_vertices, number_of_faces;
3397 IDirect3DVertexBuffer9 *vertex_buffer = NULL;
3398 IDirect3DIndexBuffer9 *index_buffer = NULL;
3399 D3DVERTEXBUFFER_DESC vertex_buffer_description;
3400 D3DINDEXBUFFER_DESC index_buffer_description;
3401 struct vertex *vertices = NULL;
3404 int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
3406 number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
3407 number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
3410 hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
3411 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3414 skip("Couldn't get vertex buffers\n");
3418 hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
3419 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3423 skip("Couldn't get vertex buffer description\n");
3427 ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
3428 name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
3429 ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
3430 name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
3431 ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
3432 ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
3433 name, vertex_buffer_description.Pool, D3DPOOL_MANAGED);
3434 ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
3435 name, vertex_buffer_description.FVF, mesh->fvf);
3438 expected = number_of_vertices * mesh->vertex_size;
3442 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
3444 ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
3445 name, vertex_buffer_description.Size, expected);
3448 hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
3449 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3452 skip("Couldn't get index buffer\n");
3456 hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
3457 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3461 skip("Couldn't get index buffer description\n");
3465 ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
3466 name, index_buffer_description.Format, D3DFMT_INDEX16);
3467 ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
3468 name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
3469 todo_wine ok(index_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, index_buffer_description.Usage, 0);
3470 ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_MANAGED)\n",
3471 name, index_buffer_description.Pool, D3DPOOL_MANAGED);
3472 expected = number_of_faces * sizeof(WORD) * 3;
3473 ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
3474 name, index_buffer_description.Size, expected);
3477 /* specify offset and size to avoid potential overruns */
3478 hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
3479 (LPVOID *)&vertices, D3DLOCK_DISCARD);
3480 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3483 skip("Couldn't lock vertex buffer\n");
3486 hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
3487 (LPVOID *)&faces, D3DLOCK_DISCARD);
3488 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3491 skip("Couldn't lock index buffer\n");
3499 for (i = 0; i < textlen; i++)
3501 int nb_outline_vertices1, nb_outline_faces1;
3502 int nb_outline_vertices2, nb_outline_faces2;
3503 int nb_back_vertices, nb_back_faces;
3504 int first_vtx1, first_vtx2;
3505 int first_face1, first_face2;
3508 first_vtx1 = vtx_idx1;
3509 first_vtx2 = vtx_idx2;
3510 for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
3511 if (vertices[vtx_idx1].normal.z != 0)
3514 for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
3515 if (mesh->vertices[vtx_idx2].normal.z != 0)
3518 nb_outline_vertices1 = vtx_idx1 - first_vtx1;
3519 nb_outline_vertices2 = vtx_idx2 - first_vtx2;
3520 ok(nb_outline_vertices1 == nb_outline_vertices2,
3521 "Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
3522 nb_outline_vertices1, nb_outline_vertices2);
3524 for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
3526 vtx_idx1 = first_vtx1 + j;
3527 vtx_idx2 = first_vtx2 + j;
3528 ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
3529 "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3530 vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
3531 mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
3532 ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
3533 "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3534 vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3535 mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
3537 vtx_idx1 = first_vtx1 + nb_outline_vertices1;
3538 vtx_idx2 = first_vtx2 + nb_outline_vertices2;
3540 first_face1 = face_idx1;
3541 first_face2 = face_idx2;
3542 for (; face_idx1 < number_of_faces; face_idx1++)
3544 if (faces[face_idx1][0] >= vtx_idx1 ||
3545 faces[face_idx1][1] >= vtx_idx1 ||
3546 faces[face_idx1][2] >= vtx_idx1)
3549 for (; face_idx2 < mesh->number_of_faces; face_idx2++)
3551 if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
3552 mesh->faces[face_idx2][1] >= vtx_idx2 ||
3553 mesh->faces[face_idx2][2] >= vtx_idx2)
3556 nb_outline_faces1 = face_idx1 - first_face1;
3557 nb_outline_faces2 = face_idx2 - first_face2;
3558 ok(nb_outline_faces1 == nb_outline_faces2,
3559 "Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
3560 nb_outline_faces1, nb_outline_faces2);
3562 for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
3564 face_idx1 = first_face1 + j;
3565 face_idx2 = first_face2 + j;
3566 ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
3567 faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
3568 faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
3569 "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
3570 faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
3571 mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
3572 mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
3573 mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
3575 face_idx1 = first_face1 + nb_outline_faces1;
3576 face_idx2 = first_face2 + nb_outline_faces2;
3578 /* partial test on back vertices and faces */
3579 first_vtx1 = vtx_idx1;
3580 for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
3583 if (vertices[vtx_idx1].normal.z != 1.0f)
3586 vtx.position.z = 0.0f;
3587 vtx.normal.x = 0.0f;
3588 vtx.normal.y = 0.0f;
3589 vtx.normal.z = 1.0f;
3590 ok(compare(vertices[vtx_idx1].position.z, vtx.position.z),
3591 "Test %s, glyph %d, vertex position.z %d, result %g, expected %g\n", name, i, vtx_idx1,
3592 vertices[vtx_idx1].position.z, vtx.position.z);
3593 ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
3594 "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3595 vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3596 vtx.normal.x, vtx.normal.y, vtx.normal.z);
3598 nb_back_vertices = vtx_idx1 - first_vtx1;
3599 first_face1 = face_idx1;
3600 for (; face_idx1 < number_of_faces; face_idx1++)
3602 const D3DXVECTOR3 *vtx1, *vtx2, *vtx3;
3604 D3DXVECTOR3 v1 = {0, 0, 0};
3605 D3DXVECTOR3 v2 = {0, 0, 0};
3606 D3DXVECTOR3 forward = {0.0f, 0.0f, 1.0f};
3608 if (faces[face_idx1][0] >= vtx_idx1 ||
3609 faces[face_idx1][1] >= vtx_idx1 ||
3610 faces[face_idx1][2] >= vtx_idx1)
3613 vtx1 = &vertices[faces[face_idx1][0]].position;
3614 vtx2 = &vertices[faces[face_idx1][1]].position;
3615 vtx3 = &vertices[faces[face_idx1][2]].position;
3617 D3DXVec3Subtract(&v1, vtx2, vtx1);
3618 D3DXVec3Subtract(&v2, vtx3, vtx2);
3619 D3DXVec3Cross(&normal, &v1, &v2);
3620 D3DXVec3Normalize(&normal, &normal);
3621 ok(!D3DXVec3Length(&normal) || compare_vec3(normal, forward),
3622 "Test %s, glyph %d, face %d normal, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, face_idx1,
3623 normal.x, normal.y, normal.z, forward.x, forward.y, forward.z);
3625 nb_back_faces = face_idx1 - first_face1;
3627 /* compare front and back faces & vertices */
3628 if (extrusion == 0.0f) {
3629 /* Oddly there are only back faces in this case */
3630 nb_back_vertices /= 2;
3632 face_idx1 -= nb_back_faces;
3633 vtx_idx1 -= nb_back_vertices;
3635 for (j = 0; j < nb_back_vertices; j++)
3637 struct vertex vtx = vertices[first_vtx1];
3638 vtx.position.z = -extrusion;
3639 vtx.normal.x = 0.0f;
3640 vtx.normal.y = 0.0f;
3641 vtx.normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
3642 ok(compare_vec3(vertices[vtx_idx1].position, vtx.position),
3643 "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3644 vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
3645 vtx.position.x, vtx.position.y, vtx.position.z);
3646 ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
3647 "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
3648 vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
3649 vtx.normal.x, vtx.normal.y, vtx.normal.z);
3653 for (j = 0; j < nb_back_faces; j++)
3656 if (extrusion == 0.0f) {
3663 ok(faces[face_idx1][0] == faces[first_face1][0] + nb_back_vertices &&
3664 faces[face_idx1][1] == faces[first_face1][f1] + nb_back_vertices &&
3665 faces[face_idx1][2] == faces[first_face1][f2] + nb_back_vertices,
3666 "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
3667 faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
3668 faces[first_face1][0] - nb_back_faces,
3669 faces[first_face1][f1] - nb_back_faces,
3670 faces[first_face1][f2] - nb_back_faces);
3675 /* skip to the outline for the next glyph */
3676 for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
3677 if (mesh->vertices[vtx_idx2].normal.z == 0)
3680 for (; face_idx2 < mesh->number_of_faces; face_idx2++)
3682 if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
3683 mesh->faces[face_idx2][1] >= vtx_idx2 ||
3684 mesh->faces[face_idx2][2] >= vtx_idx2) break;
3689 if (vertices) IDirect3DVertexBuffer9_Unlock(vertex_buffer);
3690 if (faces) IDirect3DIndexBuffer9_Unlock(index_buffer);
3691 if (index_buffer) IDirect3DIndexBuffer9_Release(index_buffer);
3692 if (vertex_buffer) IDirect3DVertexBuffer9_Release(vertex_buffer);
3695 static void test_createtext(IDirect3DDevice9 *device, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion)
3698 ID3DXMesh *d3dxmesh;
3701 OUTLINETEXTMETRIC otm;
3703 GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
3706 HFONT font = NULL, oldfont = NULL;
3708 sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion);
3710 hr = D3DXCreateText(device, hdc, text, deviation, extrusion, &d3dxmesh, NULL, glyphmetrics_float);
3711 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
3714 skip("Couldn't create text with D3DXCreateText\n");
3718 /* must select a modified font having lfHeight = otm.otmEMSquare before
3719 * calling GetGlyphOutline to get the expected values */
3720 if (!GetObject(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf) ||
3721 !GetOutlineTextMetrics(hdc, sizeof(otm), &otm))
3723 d3dxmesh->lpVtbl->Release(d3dxmesh);
3724 skip("Couldn't get text outline\n");
3727 lf.lfHeight = otm.otmEMSquare;
3729 font = CreateFontIndirect(&lf);
3731 d3dxmesh->lpVtbl->Release(d3dxmesh);
3732 skip("Couldn't create the modified font\n");
3735 oldfont = SelectObject(hdc, font);
3737 for (i = 0; i < strlen(text); i++)
3739 const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
3740 GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
3741 compare_float(glyphmetrics_float[i].gmfBlackBoxX, gm.gmBlackBoxX / (float)otm.otmEMSquare);
3742 compare_float(glyphmetrics_float[i].gmfBlackBoxY, gm.gmBlackBoxY / (float)otm.otmEMSquare);
3743 compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.x, gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare);
3744 compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.y, gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare);
3745 compare_float(glyphmetrics_float[i].gmfCellIncX, gm.gmCellIncX / (float)otm.otmEMSquare);
3746 compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
3749 ZeroMemory(&mesh, sizeof(mesh));
3750 if (!compute_text_mesh(&mesh, hdc, text, deviation, extrusion, otm.otmEMSquare))
3752 skip("Couldn't create mesh\n");
3753 d3dxmesh->lpVtbl->Release(d3dxmesh);
3756 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3758 compare_text_outline_mesh(name, d3dxmesh, &mesh, strlen(text), extrusion);
3762 d3dxmesh->lpVtbl->Release(d3dxmesh);
3763 SelectObject(hdc, oldfont);
3764 HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
3767 static void D3DXCreateTextTest(void)
3773 IDirect3DDevice9* device;
3774 D3DPRESENT_PARAMETERS d3dpp;
3775 ID3DXMesh* d3dxmesh = NULL;
3777 OUTLINETEXTMETRIC otm;
3778 int number_of_vertices;
3779 int number_of_faces;
3781 wnd = CreateWindow("static", "d3dx9_test", WS_POPUP, 0, 0, 1000, 1000, NULL, NULL, NULL, NULL);
3782 d3d = Direct3DCreate9(D3D_SDK_VERSION);
3785 skip("Couldn't create application window\n");
3790 skip("Couldn't create IDirect3D9 object\n");
3795 ZeroMemory(&d3dpp, sizeof(d3dpp));
3796 d3dpp.Windowed = TRUE;
3797 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
3798 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
3801 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
3802 IDirect3D9_Release(d3d);
3807 hdc = CreateCompatibleDC(NULL);
3809 hFont = CreateFont(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
3810 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
3812 SelectObject(hdc, hFont);
3813 GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
3815 hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, NULL, NULL, NULL);
3816 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3818 /* D3DXCreateTextA page faults from passing NULL text */
3820 hr = D3DXCreateTextW(device, hdc, NULL, 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
3821 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3823 hr = D3DXCreateText(device, hdc, "", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
3824 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3826 hr = D3DXCreateText(device, hdc, " ", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
3827 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3829 hr = D3DXCreateText(NULL, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
3830 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3832 hr = D3DXCreateText(device, NULL, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
3833 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3835 hr = D3DXCreateText(device, hdc, "wine", -FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
3836 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3838 hr = D3DXCreateText(device, hdc, "wine", 0.001f, -FLT_MIN, &d3dxmesh, NULL, NULL);
3839 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3841 /* deviation = 0.0f treated as if deviation = 1.0f / otm.otmEMSquare */
3842 hr = D3DXCreateText(device, hdc, "wine", 1.0f / otm.otmEMSquare, 0.4f, &d3dxmesh, NULL, NULL);
3843 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
3844 number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
3845 number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
3846 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
3848 hr = D3DXCreateText(device, hdc, "wine", 0.0f, 0.4f, &d3dxmesh, NULL, NULL);
3849 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
3850 ok(number_of_vertices == d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh),
3851 "Got %d vertices, expected %d\n",
3852 d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_vertices);
3853 ok(number_of_faces == d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh),
3854 "Got %d faces, expected %d\n",
3855 d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_faces);
3856 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
3859 /* too much detail requested, so will appear to hang */
3860 trace("Waiting for D3DXCreateText to finish with deviation = FLT_MIN ...\n");
3861 hr = D3DXCreateText(device, hdc, "wine", FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
3862 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
3863 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
3864 trace("D3DXCreateText finish with deviation = FLT_MIN\n");
3867 hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
3868 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
3869 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
3871 test_createtext(device, hdc, "wine", FLT_MAX, 0.4f);
3872 test_createtext(device, hdc, "wine", 0.001f, FLT_MIN);
3873 test_createtext(device, hdc, "wine", 0.001f, 0.0f);
3874 test_createtext(device, hdc, "wine", 0.001f, FLT_MAX);
3875 test_createtext(device, hdc, "wine", 0.0f, 1.0f);
3879 IDirect3DDevice9_Release(device);
3880 IDirect3D9_Release(d3d);
3884 static void test_get_decl_length(void)
3886 static const D3DVERTEXELEMENT9 declaration1[] =
3888 {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3889 {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3890 {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3891 {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3892 {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3893 {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3894 {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3895 {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3896 {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3897 {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3898 {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3899 {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3900 {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3901 {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3902 {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3905 static const D3DVERTEXELEMENT9 declaration2[] =
3907 {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3908 {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3909 {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3910 {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3911 {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3912 {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3913 {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3914 {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3915 {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3916 {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3917 {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3918 {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3919 {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3920 {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3921 {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3922 {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3927 size = D3DXGetDeclLength(declaration1);
3928 ok(size == 15, "Got size %u, expected 15.\n", size);
3930 size = D3DXGetDeclLength(declaration2);
3931 ok(size == 16, "Got size %u, expected 16.\n", size);
3934 static void test_get_decl_vertex_size(void)
3936 static const D3DVERTEXELEMENT9 declaration1[] =
3938 {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3939 {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3940 {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3941 {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3942 {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3943 {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3944 {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3945 {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3946 {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3947 {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3948 {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3949 {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3950 {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3951 {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3952 {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3955 static const D3DVERTEXELEMENT9 declaration2[] =
3957 {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3958 {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3959 {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3960 {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3961 {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3962 {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3963 {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3964 {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3965 {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3966 {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3967 {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3968 {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3969 {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3970 {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3971 {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3972 {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3975 static const UINT sizes1[] =
3982 static const UINT sizes2[] =
3990 size = D3DXGetDeclVertexSize(NULL, 0);
3991 ok(size == 0, "Got size %#x, expected 0.\n", size);
3993 for (i = 0; i < 16; ++i)
3995 size = D3DXGetDeclVertexSize(declaration1, i);
3996 ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
3999 for (i = 0; i < 8; ++i)
4001 size = D3DXGetDeclVertexSize(declaration2, i);
4002 ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
4006 static void D3DXGenerateAdjacencyTest(void)
4011 IDirect3DDevice9 *device;
4012 D3DPRESENT_PARAMETERS d3dpp;
4013 ID3DXMesh *d3dxmesh = NULL;
4014 D3DXVECTOR3 *vertices = NULL;
4015 WORD *indices = NULL;
4019 D3DXVECTOR3 vertices[6];
4021 WORD indices[3 * 3];
4023 DWORD adjacency[3 * 3];
4025 { /* for epsilon < 0, indices must match for faces to be adjacent */
4026 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}},
4027 2, {0, 1, 2, 0, 2, 3},
4029 {-1, -1, 1, 0, -1, -1},
4032 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}},
4033 2, {0, 1, 2, 3, 4, 5},
4035 {-1, -1, -1, -1, -1, -1},
4037 { /* for epsilon == 0, indices or vertices must match for faces to be adjacent */
4038 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}},
4039 2, {0, 1, 2, 3, 4, 5},
4041 {-1, -1, 1, 0, -1, -1},
4043 { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4044 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}},
4045 2, {0, 1, 2, 3, 4, 5},
4047 {-1, -1, -1, -1, -1, -1},
4049 { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
4050 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}},
4051 2, {0, 1, 2, 3, 4, 5},
4053 {-1, -1, 1, 0, -1, -1},
4055 { /* length between vertices are compared to epsilon, not the individual dimension deltas */
4056 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}},
4057 2, {0, 1, 2, 3, 4, 5},
4058 0.353, /* < sqrt(0.25*0.25 + 0.25*0.25) */
4059 {-1, -1, -1, -1, -1, -1},
4062 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}},
4063 2, {0, 1, 2, 3, 4, 5},
4064 0.354, /* > sqrt(0.25*0.25 + 0.25*0.25) */
4065 {-1, -1, 1, 0, -1, -1},
4067 { /* adjacent faces must have opposite winding orders at the shared edge */
4068 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}},
4069 2, {0, 1, 2, 0, 3, 2},
4071 {-1, -1, -1, -1, -1, -1},
4075 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
4078 skip("Couldn't create application window\n");
4081 d3d = Direct3DCreate9(D3D_SDK_VERSION);
4084 skip("Couldn't create IDirect3D9 object\n");
4089 ZeroMemory(&d3dpp, sizeof(d3dpp));
4090 d3dpp.Windowed = TRUE;
4091 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
4092 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
4095 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
4096 IDirect3D9_Release(d3d);
4101 for (i = 0; i < ARRAY_SIZE(test_data); i++)
4103 DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
4106 if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4109 hr = D3DXCreateMeshFVF(test_data[i].num_faces, test_data[i].num_vertices, 0, D3DFVF_XYZ, device, &d3dxmesh);
4110 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4112 hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&vertices);
4113 ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4114 if (FAILED(hr)) continue;
4115 CopyMemory(vertices, test_data[i].vertices, test_data[i].num_vertices * sizeof(test_data[0].vertices[0]));
4116 d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
4118 hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&indices);
4119 ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
4120 if (FAILED(hr)) continue;
4121 CopyMemory(indices, test_data[i].indices, test_data[i].num_faces * 3 * sizeof(test_data[0].indices[0]));
4122 d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
4125 hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, NULL);
4126 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
4129 hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, test_data[i].epsilon, adjacency);
4130 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
4131 if (FAILED(hr)) continue;
4133 for (j = 0; j < test_data[i].num_faces * 3; j++)
4134 ok(adjacency[j] == test_data[i].adjacency[j],
4135 "Test %d adjacency %d: Got result %u, expected %u\n", i, j,
4136 adjacency[j], test_data[i].adjacency[j]);
4138 if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4143 D3DXBoundProbeTest();
4144 D3DXComputeBoundingBoxTest();
4145 D3DXComputeBoundingSphereTest();
4146 D3DXGetFVFVertexSizeTest();
4147 D3DXIntersectTriTest();
4148 D3DXCreateMeshTest();
4149 D3DXCreateMeshFVFTest();
4151 D3DXCreateBoxTest();
4152 D3DXCreateSphereTest();
4153 D3DXCreateCylinderTest();
4154 D3DXCreateTextTest();
4155 test_get_decl_length();
4156 test_get_decl_vertex_size();
4157 test_fvf_decl_conversion();
4158 D3DXGenerateAdjacencyTest();