d3dx9/tests: Test effect generation and material loading for X files.
[wine/multimedia.git] / dlls / d3dx9_36 / tests / mesh.c
blobd40407342e71abcbf3e7b037483d61b937a4861a
1 /*
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
21 #define COBJMACROS
22 #include <stdio.h>
23 #include <float.h>
24 #include "wine/test.h"
25 #include "d3dx9.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) \
40 do { \
41 float _got = (got); \
42 float _exp = (exp); \
43 ok(_got == _exp, "Expected: %g, Got: %g\n", _exp, _got); \
44 } while (0)
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)
59 int i;
60 char exp_buffer[256] = "";
61 char got_buffer[256] = "";
62 char *exp_buffer_ptr = exp_buffer;
63 char *got_buffer_ptr = got_buffer;
64 BOOL equal = TRUE;
66 for (i = 0; i < dim; i++) {
67 if (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);
74 exp++, got++;
76 ok_(__FILE__,line)(equal, "%sExpected (%s), got (%s)", prefix, exp_buffer, got_buffer);
79 struct vertex
81 D3DXVECTOR3 position;
82 D3DXVECTOR3 normal;
85 typedef WORD face[3];
87 static BOOL compare_face(face a, face b)
89 return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
92 struct mesh
94 DWORD number_of_vertices;
95 struct vertex *vertices;
97 DWORD number_of_faces;
98 face *faces;
100 DWORD fvf;
101 UINT vertex_size;
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));
113 if (!mesh->vertices)
115 return FALSE;
117 mesh->number_of_vertices = number_of_vertices;
119 mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
120 if (!mesh->faces)
122 HeapFree(GetProcessHeap(), 0, mesh->vertices);
123 return FALSE;
125 mesh->number_of_faces = number_of_faces;
127 return TRUE;
130 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
132 HRESULT hr;
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;
139 face *faces;
140 int expected, i;
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);
150 /* vertex buffer */
151 hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
152 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
154 if (hr != D3D_OK)
156 skip("Couldn't get vertex buffer\n");
158 else
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);
163 if (hr != D3D_OK)
165 skip("Couldn't get vertex buffer description\n");
167 else
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);
178 if (mesh->fvf == 0)
180 expected = number_of_vertices * mesh->vertex_size;
182 else
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);
195 if (hr != D3D_OK)
197 skip("Couldn't lock vertex buffer\n");
199 else
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);
219 /* index 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);
223 if (!index_buffer)
225 skip("Couldn't get index buffer\n");
227 else
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);
232 if (hr != D3D_OK)
234 skip("Couldn't get index buffer description\n");
236 else
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);
255 if (hr != D3D_OK)
257 skip("Couldn't lock index buffer\n");
259 else
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)
278 BOOL result;
279 D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
280 FLOAT radius;
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(&center, 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(&center, 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(&center, 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];
349 HRESULT hr;
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;
417 HRESULT hr;
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;
425 exp_rad = 6.928203f;
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;
468 int count = 0;
470 while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
472 trace(
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);
475 ptr++;
476 count++;
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();
484 unsigned int i;
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));
490 int status;
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");
497 if (status)
499 print_elements(elements);
500 break;
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);
505 if (status)
507 print_elements(elements);
508 break;
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)
516 HRESULT hr;
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)
529 HRESULT hr;
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);
536 if (SUCCEEDED(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)
545 static const struct
547 D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
548 DWORD fvf;
550 test_data[] =
553 D3DDECL_END(),
554 }, 0},
556 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
557 D3DDECL_END(),
558 }, D3DFVF_XYZ},
560 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
561 D3DDECL_END(),
562 }, D3DFVF_XYZRHW},
564 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
565 D3DDECL_END(),
566 }, D3DFVF_XYZRHW},
568 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
569 {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
570 D3DDECL_END(),
571 }, D3DFVF_XYZB1},
573 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
574 {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
575 D3DDECL_END(),
576 }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
578 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
579 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
580 D3DDECL_END(),
581 }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
583 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
584 {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
585 D3DDECL_END(),
586 }, D3DFVF_XYZB2},
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},
591 D3DDECL_END(),
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},
597 D3DDECL_END(),
598 }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
600 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
601 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
602 D3DDECL_END(),
603 }, D3DFVF_XYZB3},
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},
608 D3DDECL_END(),
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},
614 D3DDECL_END(),
615 }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
617 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
618 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
619 D3DDECL_END(),
620 }, D3DFVF_XYZB4},
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},
625 D3DDECL_END(),
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},
631 D3DDECL_END(),
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},
637 D3DDECL_END(),
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},
643 D3DDECL_END(),
644 }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
646 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
647 D3DDECL_END(),
648 }, D3DFVF_NORMAL},
650 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
651 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
652 D3DDECL_END(),
653 }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
655 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
656 D3DDECL_END(),
657 }, D3DFVF_PSIZE},
659 {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
660 D3DDECL_END(),
661 }, D3DFVF_DIFFUSE},
663 {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
664 D3DDECL_END(),
665 }, D3DFVF_SPECULAR},
666 /* Make sure textures of different sizes work. */
668 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
669 D3DDECL_END(),
670 }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
672 {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
673 D3DDECL_END(),
674 }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
676 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
677 D3DDECL_END(),
678 }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
680 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
681 D3DDECL_END(),
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},
689 D3DDECL_END(),
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},
700 D3DDECL_END(),
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},
710 D3DDECL_END(),
711 }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
712 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
714 unsigned int i;
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},
727 D3DDECL_END(),
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},
735 D3DDECL_END(),
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},
745 D3DDECL_END(),
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},
753 D3DDECL_END(),
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},
764 D3DDECL_END(),
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},
774 D3DDECL_END(),
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},
784 D3DDECL_END(),
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},
795 D3DDECL_END(),
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},
811 D3DDECL_END(),
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},
821 D3DDECL_END(),
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},
832 D3DDECL_END(),
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},
841 D3DDECL_END(),
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},
850 D3DDECL_END(),
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},
862 D3DDECL_END(),
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},
873 D3DDECL_END(),
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)
883 UINT got;
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 (
896 D3DFVF_XYZ |
897 D3DFVF_TEX1 |
898 D3DFVF_TEXCOORDSIZE1(0), 16);
899 compare_vertex_sizes (
900 D3DFVF_XYZ |
901 D3DFVF_TEX2 |
902 D3DFVF_TEXCOORDSIZE1(0) |
903 D3DFVF_TEXCOORDSIZE1(1), 20);
905 compare_vertex_sizes (
906 D3DFVF_XYZ |
907 D3DFVF_TEX1 |
908 D3DFVF_TEXCOORDSIZE2(0), 20);
910 compare_vertex_sizes (
911 D3DFVF_XYZ |
912 D3DFVF_TEX2 |
913 D3DFVF_TEXCOORDSIZE2(0) |
914 D3DFVF_TEXCOORDSIZE2(1), 28);
916 compare_vertex_sizes (
917 D3DFVF_XYZ |
918 D3DFVF_TEX6 |
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 (
927 D3DFVF_XYZ |
928 D3DFVF_TEX8 |
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 (
939 D3DFVF_XYZ |
940 D3DFVF_TEX1 |
941 D3DFVF_TEXCOORDSIZE3(0), 24);
943 compare_vertex_sizes (
944 D3DFVF_XYZ |
945 D3DFVF_TEX4 |
946 D3DFVF_TEXCOORDSIZE3(0) |
947 D3DFVF_TEXCOORDSIZE3(1) |
948 D3DFVF_TEXCOORDSIZE3(2) |
949 D3DFVF_TEXCOORDSIZE3(3), 60);
951 compare_vertex_sizes (
952 D3DFVF_XYZ |
953 D3DFVF_TEX1 |
954 D3DFVF_TEXCOORDSIZE4(0), 28);
956 compare_vertex_sizes (
957 D3DFVF_XYZ |
958 D3DFVF_TEX2 |
959 D3DFVF_TEXCOORDSIZE4(0) |
960 D3DFVF_TEXCOORDSIZE4(1), 44);
962 compare_vertex_sizes (
963 D3DFVF_XYZ |
964 D3DFVF_TEX3 |
965 D3DFVF_TEXCOORDSIZE4(0) |
966 D3DFVF_TEXCOORDSIZE4(1) |
967 D3DFVF_TEXCOORDSIZE4(2), 60);
969 compare_vertex_sizes (
970 D3DFVF_XYZB5 |
971 D3DFVF_NORMAL |
972 D3DFVF_DIFFUSE |
973 D3DFVF_SPECULAR |
974 D3DFVF_TEX8 |
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;
1017 exp_res = FALSE;
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;
1032 exp_res = FALSE;
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)
1040 HRESULT hr;
1041 HWND wnd;
1042 IDirect3D9 *d3d;
1043 IDirect3DDevice9 *device, *test_device;
1044 D3DPRESENT_PARAMETERS d3dpp;
1045 ID3DXMesh *d3dxmesh;
1046 int i, size;
1047 D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1048 DWORD options;
1049 struct mesh mesh;
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},
1054 D3DDECL_END(), };
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},
1064 D3DDECL_END(),
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},
1070 D3DDECL_END(),
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);
1080 if (!wnd)
1082 skip("Couldn't create application window\n");
1083 return;
1085 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1086 if (!d3d)
1088 skip("Couldn't create IDirect3D9 object\n");
1089 DestroyWindow(wnd);
1090 return;
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);
1097 if (FAILED(hr))
1099 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1100 IDirect3D9_Release(d3d);
1101 DestroyWindow(wnd);
1102 return;
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);
1114 if (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);
1128 if (hr == D3D_OK)
1130 /* device */
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);
1138 if (hr == D3D_OK)
1140 IDirect3DDevice9_Release(device);
1143 /* declaration */
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);
1150 if (hr == D3D_OK)
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 */
1165 /* options */
1166 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1167 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1169 /* rest */
1170 if (!new_mesh(&mesh, 3, 1))
1172 skip("Couldn't create mesh\n");
1174 else
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);
1182 free_mesh(&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);
1192 if (hr == D3D_OK)
1194 /* device */
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);
1202 if (hr == D3D_OK)
1204 IDirect3DDevice9_Release(device);
1207 /* declaration */
1208 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1209 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1211 if (hr == D3D_OK)
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 */
1226 /* options */
1227 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1228 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1230 /* rest */
1231 if (!new_mesh(&mesh, 3, 1))
1233 skip("Couldn't create mesh\n");
1235 else
1237 memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1238 memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1239 mesh.fvf = 0;
1240 mesh.vertex_size = 60;
1242 compare_mesh("createmesh2", d3dxmesh, &mesh);
1244 free_mesh(&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);
1259 DestroyWindow(wnd);
1262 static void D3DXCreateMeshFVFTest(void)
1264 HRESULT hr;
1265 HWND wnd;
1266 IDirect3D9 *d3d;
1267 IDirect3DDevice9 *device, *test_device;
1268 D3DPRESENT_PARAMETERS d3dpp;
1269 ID3DXMesh *d3dxmesh;
1270 int i, size;
1271 D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1272 DWORD options;
1273 struct mesh mesh;
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},
1278 D3DDECL_END(), };
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);
1287 if (!wnd)
1289 skip("Couldn't create application window\n");
1290 return;
1292 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1293 if (!d3d)
1295 skip("Couldn't create IDirect3D9 object\n");
1296 DestroyWindow(wnd);
1297 return;
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);
1304 if (FAILED(hr))
1306 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1307 IDirect3D9_Release(d3d);
1308 DestroyWindow(wnd);
1309 return;
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);
1321 if (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);
1335 if (hr == D3D_OK)
1337 /* device */
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);
1345 if (hr == D3D_OK)
1347 IDirect3DDevice9_Release(device);
1350 /* declaration */
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);
1357 if (hr == D3D_OK)
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 */
1373 /* options */
1374 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1375 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1377 /* rest */
1378 if (!new_mesh(&mesh, 3, 1))
1380 skip("Couldn't create mesh\n");
1382 else
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);
1390 free_mesh(&mesh);
1393 d3dxmesh->lpVtbl->Release(d3dxmesh);
1396 IDirect3DDevice9_Release(device);
1397 IDirect3D9_Release(d3d);
1398 DestroyWindow(wnd);
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;
1408 HRESULT hr;
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);
1416 if (FAILED(hr))
1417 return;
1419 if (mesh_fvf == fvf) {
1420 DWORD vertex_size = D3DXGetFVFVertexSize(fvf);
1421 int i;
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;
1426 DWORD texcount;
1427 DWORD pos_dim = 0;
1428 int j;
1429 BOOL last_beta_dword = FALSE;
1430 char prefix[128];
1432 switch (fvf & D3DFVF_POSITION_MASK) {
1433 case D3DFVF_XYZ: pos_dim = 3; break;
1434 case D3DFVF_XYZRHW: pos_dim = 4; break;
1435 case D3DFVF_XYZB1:
1436 case D3DFVF_XYZB2:
1437 case D3DFVF_XYZB3:
1438 case D3DFVF_XYZB4:
1439 case D3DFVF_XYZB5:
1440 pos_dim = (fvf & D3DFVF_POSITION_MASK) - D3DFVF_XYZB1 + 1;
1441 if (fvf & (D3DFVF_LASTBETA_UBYTE4 | D3DFVF_LASTBETA_D3DCOLOR))
1443 pos_dim--;
1444 last_beta_dword = TRUE;
1446 break;
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);
1457 exp_float++;
1458 got_float++;
1461 if (fvf & D3DFVF_NORMAL) {
1462 sprintf(prefix, "vertex[%u] normal, ", i);
1463 check_floats_(line, prefix, got_float, exp_float, 3);
1464 exp_float += 3;
1465 got_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);
1470 exp_float++;
1471 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);
1476 exp_float++;
1477 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);
1482 exp_float++;
1483 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);
1491 exp_float += dim;
1492 got_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;
1510 HRESULT hr;
1511 DWORD i;
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);
1520 if (FAILED(hr))
1521 return;
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);
1529 else
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)
1542 int i, j;
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)
1563 int i;
1564 ok_(__FILE__,line)(expected_count == got_count, "Expected %u materials, got %u\n", expected_count, got_count);
1565 if (!expected) {
1566 ok_(__FILE__,line)(got == NULL, "Expected NULL material ptr, got %p\n", got);
1567 return;
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);
1574 else
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)
1589 DWORD *expected;
1590 DWORD num_faces = mesh->lpVtbl->GetNumFaces(mesh);
1591 HRESULT hr;
1593 expected = HeapAlloc(GetProcessHeap(), 0, num_faces * sizeof(DWORD) * 3);
1594 if (!expected) {
1595 skip_(__FILE__, line)("Out of memory\n");
1596 return;
1598 hr = mesh->lpVtbl->GenerateAdjacency(mesh, epsilon, expected);
1599 ok_(__FILE__, line)(hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
1600 if (SUCCEEDED(hr))
1602 int i;
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)
1620 int i;
1621 static const struct {
1622 const char *name;
1623 DWORD name_size;
1624 DWORD num_bytes;
1625 DWORD value_offset;
1626 } params[] = {
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);
1639 return;
1641 for (i = 0; i < num_materials; i++)
1643 int j;
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++)
1651 int k;
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)
1694 LPSTR ret;
1695 if (!p) return NULL;
1696 ret = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
1697 if (ret) strcpy(ret, p);
1698 return ret;
1701 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_DestroyFrame(ID3DXAllocateHierarchy *iface, LPD3DXFRAME frame)
1703 TRACECALLBACK("ID3DXAllocateHierarchyImpl_DestroyFrame(%p, %p)\n", iface, frame);
1704 if (frame) {
1705 HeapFree(GetProcessHeap(), 0, frame->Name);
1706 HeapFree(GetProcessHeap(), 0, frame);
1708 return D3D_OK;
1711 static CALLBACK HRESULT ID3DXAllocateHierarchyImpl_CreateFrame(ID3DXAllocateHierarchy *iface, LPCSTR name, LPD3DXFRAME *new_frame)
1713 LPD3DXFRAME frame;
1715 TRACECALLBACK("ID3DXAllocateHierarchyImpl_CreateFrame(%p, '%s', %p)\n", iface, name, new_frame);
1716 frame = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*frame));
1717 if (!frame)
1718 return E_OUTOFMEMORY;
1719 if (name) {
1720 frame->Name = strdupA(name);
1721 if (!frame->Name) {
1722 HeapFree(GetProcessHeap(), 0, frame);
1723 return E_OUTOFMEMORY;
1726 *new_frame = frame;
1727 return D3D_OK;
1730 static HRESULT destroy_mesh_container(LPD3DXMESHCONTAINER mesh_container)
1732 int i;
1734 if (!mesh_container)
1735 return D3D_OK;
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) {
1748 int j;
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);
1762 return D3D_OK;
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;
1777 int i;
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;
1787 if (name) {
1788 mesh_container->Name = strdupA(name);
1789 if (!mesh_container->Name)
1790 goto error;
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)
1797 goto error;
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)
1806 goto error;
1810 mesh_container->pEffects = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_materials * sizeof(*effects));
1811 if (!mesh_container->pEffects)
1812 goto error;
1813 for (i = 0; i < num_materials; i++) {
1814 int j;
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)
1821 goto error;
1823 effect_dest->pDefaults = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1824 effect_src->NumDefaults * sizeof(*effect_src->pDefaults));
1825 if (!effect_dest->pDefaults)
1826 goto error;
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)
1835 goto error;
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");
1846 if (adjacency) {
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)
1853 goto error;
1854 memcpy(mesh_container->pAdjacency, adjacency, size);
1855 } else {
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);
1865 if (skin_info) {
1866 mesh_container->pSkinInfo = skin_info;
1867 skin_info->lpVtbl->AddRef(skin_info);
1869 *new_mesh_container = mesh_container;
1871 return S_OK;
1872 error:
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[] =
1890 "xof 0303txt 0032"
1891 "Mesh {"
1892 "3;"
1893 "0.0; 0.0; 0.0;,"
1894 "0.0; 1.0; 0.0;,"
1895 "1.0; 1.0; 0.0;;"
1896 "1;"
1897 "3; 0, 1, 2;;"
1898 "}";
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[] =
1905 "xof 0303txt 0032"
1906 "Frame {"
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;; }"
1922 "}";
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[] =
1932 "xof 0303txt 0032"
1933 "Mesh {"
1934 "8;" /* DWORD nVertices; */
1935 /* array Vector vertices[nVertices]; */
1936 "0.0; 0.0; 0.0;,"
1937 "0.0; 0.0; 1.0;,"
1938 "0.0; 1.0; 0.0;,"
1939 "0.0; 1.0; 1.0;,"
1940 "1.0; 0.0; 0.0;,"
1941 "1.0; 0.0; 1.0;,"
1942 "1.0; 1.0; 0.0;,"
1943 "1.0; 1.0; 1.0;;"
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) */
1952 "MeshNormals {"
1953 "6;" /* DWORD nNormals; */
1954 /* array Vector normals[nNormals]; */
1955 "-1.0; 0.0; 0.0;,"
1956 "0.0; 1.0; 0.0;,"
1957 "1.0; 0.0; 0.0;,"
1958 "0.0; -1.0; 0.0;,"
1959 "0.0; 0.0; 1.0;,"
1960 "0.0; 0.0; -1.0;;"
1961 "6;" /* DWORD nFaceNormals; */
1962 /* array MeshFace faceNormals[nFaceNormals]; */
1963 "4; 0, 0, 0, 0;,"
1964 "4; 1, 1, 1, 1;,"
1965 "4; 2, 2, 2, 2;,"
1966 "4; 3, 3, 3, 3;,"
1967 "4; 4, 4, 4, 4;,"
1968 "4; 5, 5, 5, 5;;"
1970 "MeshMaterialList materials {"
1971 "2;" /* DWORD nMaterials; */
1972 "6;" /* DWORD nFaceIndexes; */
1973 /* array DWORD faceIndexes[nFaceIndexes]; */
1974 "0, 0, 0, 1, 1, 1;;"
1975 "Material {"
1976 /* ColorRGBA faceColor; */
1977 "0.0; 0.0; 1.0; 1.0;;"
1978 /* FLOAT power; */
1979 "0.5;"
1980 /* ColorRGB specularColor; */
1981 "1.0; 1.0; 1.0;;"
1982 /* ColorRGB emissiveColor; */
1983 "0.0; 0.0; 0.0;;"
1985 "Material {"
1986 /* ColorRGBA faceColor; */
1987 "1.0; 1.0; 1.0; 1.0;;"
1988 /* FLOAT power; */
1989 "1.0;"
1990 /* ColorRGB specularColor; */
1991 "1.0; 1.0; 1.0;;"
1992 /* ColorRGB emissiveColor; */
1993 "0.0; 0.0; 0.0;;"
1994 "TextureFilename { \"texture.jpg\"; }"
1997 "}";
1998 static const WORD box_index_buffer[] = {
1999 0, 1, 3,
2000 0, 3, 2,
2001 8, 9, 7,
2002 8, 7, 6,
2003 10, 11, 5,
2004 10, 5, 4,
2005 12, 13, 14,
2006 12, 14, 15,
2007 16, 17, 18,
2008 16, 18, 19,
2009 20, 21, 22,
2010 20, 22, 23,
2012 static const struct {
2013 D3DXVECTOR3 position;
2014 D3DXVECTOR3 normal;
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 */
2048 0.5, /* Power */
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 */
2058 1.0, /* Power */
2060 (char *)"texture.jpg", /* pTextureFilename */
2063 const DWORD box_fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2064 /*________________________*/
2065 HRESULT hr;
2066 HWND wnd = NULL;
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);
2075 if (!wnd)
2077 skip("Couldn't create application window\n");
2078 return;
2080 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2081 if (!d3d)
2083 skip("Couldn't create IDirect3D9 object\n");
2084 goto cleanup;
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);
2091 if (FAILED(hr))
2093 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2094 goto cleanup;
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);
2142 frame_hier = NULL;
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);
2166 frame_hier = NULL;
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;
2174 int i;
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);
2197 frame_hier = NULL;
2200 cleanup:
2201 if (device) IDirect3DDevice9_Release(device);
2202 if (d3d) IDirect3D9_Release(d3d);
2203 if (wnd) DestroyWindow(wnd);
2206 static void D3DXCreateBoxTest(void)
2208 HRESULT hr;
2209 HWND wnd;
2210 WNDCLASS wc={0};
2211 IDirect3D9* d3d;
2212 IDirect3DDevice9* device;
2213 D3DPRESENT_PARAMETERS d3dpp;
2214 ID3DXMesh* box;
2215 ID3DXBuffer* ppBuffer;
2216 DWORD *buffer;
2217 static const DWORD adjacency[36]=
2218 {6, 9, 1, 2, 10, 0,
2219 1, 9, 3, 4, 10, 2,
2220 3, 8, 5, 7, 11, 4,
2221 0, 11, 7, 5, 8, 6,
2222 7, 4, 9, 2, 0, 8,
2223 1, 3, 11, 5, 6, 10};
2224 unsigned int i;
2226 wc.lpfnWndProc = DefWindowProcA;
2227 wc.lpszClassName = "d3dx9_test_wc";
2228 if (!RegisterClass(&wc))
2230 skip("RegisterClass failed\n");
2231 return;
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");
2237 if (!wnd)
2239 skip("Couldn't create application window\n");
2240 return;
2243 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2244 if (!d3d)
2246 skip("Couldn't create IDirect3D9 object\n");
2247 DestroyWindow(wnd);
2248 return;
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);
2255 if (FAILED(hr))
2257 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2258 IDirect3D9_Release(d3d);
2259 DestroyWindow(wnd);
2260 return;
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);
2285 if (FAILED(hr))
2287 skip("D3DXCreateBox failed\n");
2288 goto end;
2291 buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
2292 for(i=0; i<36; i++)
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);
2297 end:
2298 IDirect3DDevice9_Release(device);
2299 IDirect3D9_Release(d3d);
2300 ID3DXBuffer_Release(ppBuffer);
2301 DestroyWindow(wnd);
2304 struct sincos_table
2306 float *sin;
2307 float *cos;
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)
2319 float angle;
2320 int i;
2322 sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
2323 if (!sincos_table->sin)
2325 return FALSE;
2327 sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
2328 if (!sincos_table->cos)
2330 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
2331 return FALSE;
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;
2342 return TRUE;
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;
2358 DWORD vertex, face;
2359 int slice, stack;
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))
2371 return FALSE;
2373 if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
2375 free_sincos_table(&theta);
2376 return FALSE;
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);
2386 return FALSE;
2389 vertex = 0;
2390 face = 0;
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;
2398 vertex++;
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];
2410 vertex++;
2412 if (slice > 0)
2414 if (stack == 0)
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;
2420 face++;
2422 else
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);
2428 face++;
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);
2433 face++;
2438 if (stack == 0)
2440 mesh->faces[face][0] = 0;
2441 mesh->faces[face][1] = 1;
2442 mesh->faces[face][2] = slice;
2443 face++;
2445 else
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);
2450 face++;
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);
2455 face++;
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;
2472 face++;
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);
2482 return TRUE;
2485 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
2487 HRESULT hr;
2488 ID3DXMesh *sphere;
2489 struct mesh mesh;
2490 char name[256];
2492 hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
2493 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2494 if (hr != D3D_OK)
2496 skip("Couldn't create sphere\n");
2497 return;
2500 if (!compute_sphere(&mesh, radius, slices, stacks))
2502 skip("Couldn't create mesh\n");
2503 sphere->lpVtbl->Release(sphere);
2504 return;
2507 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2509 sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
2510 compare_mesh(name, sphere, &mesh);
2512 free_mesh(&mesh);
2514 sphere->lpVtbl->Release(sphere);
2517 static void D3DXCreateSphereTest(void)
2519 HRESULT hr;
2520 HWND wnd;
2521 IDirect3D9* d3d;
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);
2540 if (!wnd)
2542 skip("Couldn't create application window\n");
2543 return;
2545 if (!d3d)
2547 skip("Couldn't create IDirect3D9 object\n");
2548 DestroyWindow(wnd);
2549 return;
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);
2556 if (FAILED(hr))
2558 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2559 IDirect3D9_Release(d3d);
2560 DestroyWindow(wnd);
2561 return;
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);
2586 DestroyWindow(wnd);
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;
2596 DWORD vertex, face;
2597 int slice, stack;
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))
2605 return FALSE;
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);
2614 return FALSE;
2617 vertex = 0;
2618 face = 0;
2620 delta_radius = radius1 - radius2;
2621 radius = radius1;
2622 radius_step = delta_radius / stacks;
2624 z = -length / 2;
2625 z_step = length / stacks;
2626 z_normal = delta_radius / length;
2627 if (isnan(z_normal))
2629 z_normal = 0.0f;
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;
2648 if (slice > 0)
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);
2684 if (stack > 1)
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)
2697 z += z_step;
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;
2711 if (slice > 0)
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);
2732 return TRUE;
2735 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
2737 HRESULT hr;
2738 ID3DXMesh *cylinder;
2739 struct mesh mesh;
2740 char name[256];
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);
2744 if (hr != D3D_OK)
2746 skip("Couldn't create cylinder\n");
2747 return;
2750 if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
2752 skip("Couldn't create mesh\n");
2753 cylinder->lpVtbl->Release(cylinder);
2754 return;
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);
2762 free_mesh(&mesh);
2764 cylinder->lpVtbl->Release(cylinder);
2767 static void D3DXCreateCylinderTest(void)
2769 HRESULT hr;
2770 HWND wnd;
2771 IDirect3D9* d3d;
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);
2784 if (!wnd)
2786 skip("Couldn't create application window\n");
2787 return;
2789 if (!d3d)
2791 skip("Couldn't create IDirect3D9 object\n");
2792 DestroyWindow(wnd);
2793 return;
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);
2800 if (FAILED(hr))
2802 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2803 IDirect3D9_Release(d3d);
2804 DestroyWindow(wnd);
2805 return;
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);
2860 DestroyWindow(wnd);
2863 struct dynamic_array
2865 int count, capacity;
2866 void *items;
2869 enum pointtype {
2870 POINTTYPE_CURVE = 0,
2871 POINTTYPE_CORNER,
2872 POINTTYPE_CURVE_START,
2873 POINTTYPE_CURVE_END,
2874 POINTTYPE_CURVE_MIDDLE,
2877 struct point2d
2879 D3DXVECTOR2 pos;
2880 enum pointtype corner;
2883 /* is a dynamic_array */
2884 struct outline
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;
2897 struct glyphinfo
2899 struct outline_array outlines;
2900 float offset_x;
2903 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
2905 if (count > array->capacity) {
2906 void *new_buffer;
2907 int new_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);
2911 } else {
2912 new_capacity = max(16, count);
2913 new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
2915 if (!new_buffer)
2916 return FALSE;
2917 array->items = new_buffer;
2918 array->capacity = new_capacity;
2920 return TRUE;
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])))
2928 return NULL;
2930 item = &array->items[array->count++];
2931 ZeroMemory(item, sizeof(*item));
2932 return 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])))
2940 return NULL;
2942 item = &array->items[array->count++];
2943 ZeroMemory(item, sizeof(*item));
2944 return item;
2947 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
2949 D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
2950 while (count--) {
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;
2954 pt++;
2956 return ret;
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;
2964 float deviation;
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;
2974 pt->pos = *p2;
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. */
2979 } else {
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;
2986 return S_OK;
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,
3001 int pt_index,
3002 const D3DXVECTOR2 *nextpt,
3003 BOOL to_curve)
3005 D3DXVECTOR2 curdir, lastdir;
3006 struct point2d *prevpt, *pt;
3007 BOOL ret = FALSE;
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];
3014 if (to_curve)
3015 pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
3017 if (outline->count < 2)
3018 return FALSE;
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))
3025 outline->count--;
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;
3030 pt = prevpt;
3032 ret = TRUE;
3033 if (outline->count < 2)
3034 return ret;
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);
3041 return ret;
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;
3057 int j;
3058 struct outline *outline = add_outline(&glyph->outlines);
3060 if (!outline)
3061 return E_OUTOFMEMORY;
3063 pt = add_point(outline);
3064 if (!pt)
3065 return E_OUTOFMEMORY;
3066 pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
3067 pt->pos = *pt_flt;
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;
3078 if (!curve->cpfx) {
3079 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
3080 continue;
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);
3087 if (to_curve)
3089 HRESULT hr;
3090 int count = curve->cpfx;
3091 j = 0;
3093 while (count > 2)
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);
3099 if (hr != S_OK)
3100 return hr;
3101 bezier_start = bezier_end;
3102 count--;
3103 j++;
3105 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
3106 if (hr != S_OK)
3107 return hr;
3109 pt = add_point(outline);
3110 if (!pt)
3111 return E_OUTOFMEMORY;
3112 j++;
3113 pt->pos = pt_flt[j];
3114 pt->corner = POINTTYPE_CURVE_END;
3115 } else {
3116 for (j = 0; j < curve->cpfx; j++)
3118 pt = add_point(outline);
3119 if (!pt)
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) {
3131 BOOL to_curve;
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;
3140 else
3141 pt->corner = POINTTYPE_CURVE_END;
3143 outline->count--;
3144 lastpt = &outline->items[outline->count - 1];
3145 } else {
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++)
3163 D3DXVECTOR2 curdir;
3165 lastpt = pt;
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;
3175 break;
3176 case POINTTYPE_CURVE_MIDDLE:
3177 if (!is_direction_similar(&lastdir, &curdir, cos_90))
3178 lastpt->corner = POINTTYPE_CORNER;
3179 else
3180 lastpt->corner = POINTTYPE_CURVE;
3181 break;
3182 default:
3183 break;
3185 lastdir = curdir;
3188 header = (TTPOLYGONHEADER *)((char *)header + header->cb);
3190 return S_OK;
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;
3198 int textlen = 0;
3199 float offset_x;
3200 char *raw_outline = NULL;
3201 struct glyphinfo *glyphs = NULL;
3202 GLYPHMETRICS gm;
3203 int i;
3204 struct vertex *vertex_ptr;
3205 face *face_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));
3212 if (!glyphs) {
3213 hr = E_OUTOFMEMORY;
3214 goto error;
3217 offset_x = 0.0f;
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}};
3222 int datasize;
3224 glyphs[i].offset_x = offset_x;
3226 datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
3227 if (datasize < 0) {
3228 hr = E_FAIL;
3229 goto error;
3231 HeapFree(GetProcessHeap(), 0, raw_outline);
3232 raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
3233 if (!glyphs) {
3234 hr = E_OUTOFMEMORY;
3235 goto error;
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 */
3245 nb_corners = 0;
3246 nb_outline_points = 0;
3247 for (i = 0; i < textlen; i++)
3249 int j;
3250 for (j = 0; j < glyphs[i].outlines.count; j++)
3252 int k;
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)
3258 nb_corners++;
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))
3266 goto error;
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++)
3273 int j;
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];
3280 int k;
3281 struct point2d *prevpt = &outline->items[outline->count - 1];
3282 struct point2d *pt = &outline->items[0];
3284 for (k = 1; k <= outline->count; k++)
3286 struct vertex vtx;
3287 struct point2d *nextpt = &outline->items[k % outline->count];
3288 WORD vtx_idx = vertex_ptr - mesh->vertices;
3289 D3DXVECTOR2 vec;
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);
3295 else
3296 D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
3297 D3DXVec2Normalize(&vec, &vec);
3298 vtx.normal.x = -vec.y;
3299 vtx.normal.y = vec.x;
3300 vtx.normal.z = 0;
3302 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
3303 vtx.position.y = pt->pos.y;
3304 vtx.position.z = 0;
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;
3315 vtx.position.z = 0;
3316 *vertex_ptr++ = vtx;
3318 (*face_ptr)[0] = vtx_idx;
3319 (*face_ptr)[1] = vtx_idx + 2;
3320 (*face_ptr)[2] = vtx_idx + 1;
3321 face_ptr++;
3323 (*face_ptr)[0] = vtx_idx;
3324 (*face_ptr)[1] = vtx_idx + 3;
3325 (*face_ptr)[2] = vtx_idx + 2;
3326 face_ptr++;
3327 } else {
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);
3332 } else {
3333 D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
3335 D3DXVec2Normalize(&vec, &vec);
3336 vtx.normal.x = -vec.y;
3337 vtx.normal.y = vec.x;
3339 vtx.position.z = 0;
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;
3348 face_ptr++;
3350 (*face_ptr)[0] = vtx_idx;
3351 (*face_ptr)[1] = vtx_idx + 2;
3352 (*face_ptr)[2] = vtx_idx + 3;
3353 face_ptr++;
3356 prevpt = pt;
3357 pt = nextpt;
3359 if (!pt->corner) {
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;
3373 vertex_ptr++;
3376 hr = D3D_OK;
3377 error:
3378 if (glyphs) {
3379 for (i = 0; i < textlen; i++)
3381 int j;
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)
3395 HRESULT hr;
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;
3402 face *faces = NULL;
3403 int expected, i;
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);
3409 /* vertex buffer */
3410 hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
3411 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
3412 if (hr != D3D_OK)
3414 skip("Couldn't get vertex buffers\n");
3415 goto error;
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);
3421 if (hr != D3D_OK)
3423 skip("Couldn't get vertex buffer description\n");
3425 else
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);
3436 if (mesh->fvf == 0)
3438 expected = number_of_vertices * mesh->vertex_size;
3440 else
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);
3450 if (hr != D3D_OK)
3452 skip("Couldn't get index buffer\n");
3453 goto error;
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);
3459 if (hr != D3D_OK)
3461 skip("Couldn't get index buffer description\n");
3463 else
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);
3481 if (hr != D3D_OK)
3483 skip("Couldn't lock vertex buffer\n");
3484 goto error;
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);
3489 if (hr != D3D_OK)
3491 skip("Couldn't lock index buffer\n");
3492 goto error;
3495 face_idx1 = 0;
3496 vtx_idx2 = 0;
3497 face_idx2 = 0;
3498 vtx_idx1 = 0;
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;
3506 int j;
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)
3512 break;
3514 for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
3515 if (mesh->vertices[vtx_idx2].normal.z != 0)
3516 break;
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)
3547 break;
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)
3554 break;
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++) {
3581 struct vertex vtx;
3583 if (vertices[vtx_idx1].normal.z != 1.0f)
3584 break;
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;
3603 D3DXVECTOR3 normal;
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)
3611 break;
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;
3631 nb_back_faces /= 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);
3650 vtx_idx1++;
3651 first_vtx1++;
3653 for (j = 0; j < nb_back_faces; j++)
3655 int f1, f2;
3656 if (extrusion == 0.0f) {
3657 f1 = 1;
3658 f2 = 2;
3659 } else {
3660 f1 = 2;
3661 f2 = 1;
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);
3671 first_face1++;
3672 face_idx1++;
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)
3678 break;
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;
3688 error:
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)
3697 HRESULT hr;
3698 ID3DXMesh *d3dxmesh;
3699 struct mesh mesh;
3700 char name[256];
3701 OUTLINETEXTMETRIC otm;
3702 GLYPHMETRICS gm;
3703 GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
3704 int i;
3705 LOGFONT lf;
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);
3712 if (hr != D3D_OK)
3714 skip("Couldn't create text with D3DXCreateText\n");
3715 return;
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");
3725 return;
3727 lf.lfHeight = otm.otmEMSquare;
3728 lf.lfWidth = 0;
3729 font = CreateFontIndirect(&lf);
3730 if (!font) {
3731 d3dxmesh->lpVtbl->Release(d3dxmesh);
3732 skip("Couldn't create the modified font\n");
3733 return;
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);
3754 return;
3756 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
3758 compare_text_outline_mesh(name, d3dxmesh, &mesh, strlen(text), extrusion);
3760 free_mesh(&mesh);
3762 d3dxmesh->lpVtbl->Release(d3dxmesh);
3763 SelectObject(hdc, oldfont);
3764 HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
3767 static void D3DXCreateTextTest(void)
3769 HRESULT hr;
3770 HWND wnd;
3771 HDC hdc;
3772 IDirect3D9* d3d;
3773 IDirect3DDevice9* device;
3774 D3DPRESENT_PARAMETERS d3dpp;
3775 ID3DXMesh* d3dxmesh = NULL;
3776 HFONT hFont;
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);
3783 if (!wnd)
3785 skip("Couldn't create application window\n");
3786 return;
3788 if (!d3d)
3790 skip("Couldn't create IDirect3D9 object\n");
3791 DestroyWindow(wnd);
3792 return;
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);
3799 if (FAILED(hr))
3801 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
3802 IDirect3D9_Release(d3d);
3803 DestroyWindow(wnd);
3804 return;
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,
3811 "Arial");
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);
3858 #if 0
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");
3865 #endif
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);
3877 DeleteDC(hdc);
3879 IDirect3DDevice9_Release(device);
3880 IDirect3D9_Release(d3d);
3881 DestroyWindow(wnd);
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},
3903 D3DDECL_END(),
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},
3923 D3DDECL_END(),
3925 UINT size;
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},
3953 D3DDECL_END(),
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},
3973 D3DDECL_END(),
3975 static const UINT sizes1[] =
3977 4, 8, 12, 16,
3978 4, 4, 4, 8,
3979 4, 4, 8, 4,
3980 4, 4, 8, 0,
3982 static const UINT sizes2[] =
3984 12, 16, 20, 24,
3985 12, 12, 16, 16,
3987 unsigned int i;
3988 UINT size;
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)
4008 HRESULT hr;
4009 HWND wnd;
4010 IDirect3D9 *d3d;
4011 IDirect3DDevice9 *device;
4012 D3DPRESENT_PARAMETERS d3dpp;
4013 ID3DXMesh *d3dxmesh = NULL;
4014 D3DXVECTOR3 *vertices = NULL;
4015 WORD *indices = NULL;
4016 int i;
4017 struct {
4018 DWORD num_vertices;
4019 D3DXVECTOR3 vertices[6];
4020 DWORD num_faces;
4021 WORD indices[3 * 3];
4022 FLOAT epsilon;
4023 DWORD adjacency[3 * 3];
4024 } test_data[] = {
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},
4028 -1.0,
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},
4034 -1.0,
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},
4040 0.0,
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},
4046 0.25,
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},
4052 0.250001,
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},
4070 0.0,
4071 {-1, -1, -1, -1, -1, -1},
4075 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
4076 if (!wnd)
4078 skip("Couldn't create application window\n");
4079 return;
4081 d3d = Direct3DCreate9(D3D_SDK_VERSION);
4082 if (!d3d)
4084 skip("Couldn't create IDirect3D9 object\n");
4085 DestroyWindow(wnd);
4086 return;
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);
4093 if (FAILED(hr))
4095 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
4096 IDirect3D9_Release(d3d);
4097 DestroyWindow(wnd);
4098 return;
4101 for (i = 0; i < ARRAY_SIZE(test_data); i++)
4103 DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
4104 int j;
4106 if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
4107 d3dxmesh = NULL;
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);
4124 if (i == 0) {
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);
4141 START_TEST(mesh)
4143 D3DXBoundProbeTest();
4144 D3DXComputeBoundingBoxTest();
4145 D3DXComputeBoundingSphereTest();
4146 D3DXGetFVFVertexSizeTest();
4147 D3DXIntersectTriTest();
4148 D3DXCreateMeshTest();
4149 D3DXCreateMeshFVFTest();
4150 D3DXLoadMeshTest();
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();