d3dx9: D3DXCreateMesh rejects declarations with non-zero streams.
[wine/multimedia.git] / dlls / d3dx9_36 / tests / mesh.c
blob88ac59cc978b4065e566ac37c8c40da06398838a
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 #include <stdio.h>
22 #include <float.h>
23 #include "wine/test.h"
24 #include "d3dx9.h"
26 #define admitted_error 0.0001f
28 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
30 #define compare_vertex_sizes(type, exp) \
31 got=D3DXGetFVFVertexSize(type); \
32 ok(got==exp, "Expected: %d, Got: %d\n", exp, got);
34 #define compare_float(got, exp) \
35 do { \
36 float _got = (got); \
37 float _exp = (exp); \
38 ok(_got == _exp, "Expected: %g, Got: %g\n", _exp, _got); \
39 } while (0)
41 static BOOL compare(FLOAT u, FLOAT v)
43 return (fabs(u-v) < admitted_error);
46 static BOOL compare_vec3(D3DXVECTOR3 u, D3DXVECTOR3 v)
48 return ( compare(u.x, v.x) && compare(u.y, v.y) && compare(u.z, v.z) );
51 struct vertex
53 D3DXVECTOR3 position;
54 D3DXVECTOR3 normal;
57 typedef WORD face[3];
59 static BOOL compare_face(face a, face b)
61 return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
64 struct mesh
66 DWORD number_of_vertices;
67 struct vertex *vertices;
69 DWORD number_of_faces;
70 face *faces;
72 DWORD fvf;
73 UINT vertex_size;
76 static void free_mesh(struct mesh *mesh)
78 HeapFree(GetProcessHeap(), 0, mesh->faces);
79 HeapFree(GetProcessHeap(), 0, mesh->vertices);
82 static BOOL new_mesh(struct mesh *mesh, DWORD number_of_vertices, DWORD number_of_faces)
84 mesh->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_vertices * sizeof(*mesh->vertices));
85 if (!mesh->vertices)
87 return FALSE;
89 mesh->number_of_vertices = number_of_vertices;
91 mesh->faces = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, number_of_faces * sizeof(*mesh->faces));
92 if (!mesh->faces)
94 HeapFree(GetProcessHeap(), 0, mesh->vertices);
95 return FALSE;
97 mesh->number_of_faces = number_of_faces;
99 return TRUE;
102 static void compare_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh)
104 HRESULT hr;
105 DWORD number_of_vertices, number_of_faces;
106 IDirect3DVertexBuffer9 *vertex_buffer;
107 IDirect3DIndexBuffer9 *index_buffer;
108 D3DVERTEXBUFFER_DESC vertex_buffer_description;
109 D3DINDEXBUFFER_DESC index_buffer_description;
110 struct vertex *vertices;
111 face *faces;
112 int expected, i;
114 number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
115 ok(number_of_vertices == mesh->number_of_vertices, "Test %s, result %u, expected %d\n",
116 name, number_of_vertices, mesh->number_of_vertices);
118 number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
119 ok(number_of_faces == mesh->number_of_faces, "Test %s, result %u, expected %d\n",
120 name, number_of_faces, mesh->number_of_faces);
122 /* vertex buffer */
123 hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
124 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
126 if (hr != D3D_OK)
128 skip("Couldn't get vertex buffer\n");
130 else
132 hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
133 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
135 if (hr != D3D_OK)
137 skip("Couldn't get vertex buffer description\n");
139 else
141 ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
142 name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
143 ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
144 name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
145 ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
146 ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_DEFAULT)\n",
147 name, vertex_buffer_description.Pool, D3DPOOL_DEFAULT);
148 ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
149 name, vertex_buffer_description.FVF, mesh->fvf);
150 if (mesh->fvf == 0)
152 expected = number_of_vertices * mesh->vertex_size;
154 else
156 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
158 ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
159 name, vertex_buffer_description.Size, expected);
162 /* specify offset and size to avoid potential overruns */
163 hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
164 (LPVOID *)&vertices, D3DLOCK_DISCARD);
165 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
167 if (hr != D3D_OK)
169 skip("Couldn't lock vertex buffer\n");
171 else
173 for (i = 0; i < number_of_vertices; i++)
175 ok(compare_vec3(vertices[i].position, mesh->vertices[i].position),
176 "Test %s, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
177 vertices[i].position.x, vertices[i].position.y, vertices[i].position.z,
178 mesh->vertices[i].position.x, mesh->vertices[i].position.y, mesh->vertices[i].position.z);
179 ok(compare_vec3(vertices[i].normal, mesh->vertices[i].normal),
180 "Test %s, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i,
181 vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z,
182 mesh->vertices[i].normal.x, mesh->vertices[i].normal.y, mesh->vertices[i].normal.z);
185 IDirect3DVertexBuffer9_Unlock(vertex_buffer);
188 IDirect3DVertexBuffer9_Release(vertex_buffer);
191 /* index buffer */
192 hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
193 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
195 if (!index_buffer)
197 skip("Couldn't get index buffer\n");
199 else
201 hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
202 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
204 if (hr != D3D_OK)
206 skip("Couldn't get index buffer description\n");
208 else
210 ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
211 name, index_buffer_description.Format, D3DFMT_INDEX16);
212 ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
213 name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
214 todo_wine ok(index_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, index_buffer_description.Usage, 0);
215 ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_DEFAULT)\n",
216 name, index_buffer_description.Pool, D3DPOOL_DEFAULT);
217 expected = number_of_faces * sizeof(WORD) * 3;
218 ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
219 name, index_buffer_description.Size, expected);
222 /* specify offset and size to avoid potential overruns */
223 hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
224 (LPVOID *)&faces, D3DLOCK_DISCARD);
225 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
227 if (hr != D3D_OK)
229 skip("Couldn't lock index buffer\n");
231 else
233 for (i = 0; i < number_of_faces; i++)
235 ok(compare_face(faces[i], mesh->faces[i]),
236 "Test %s, face %d, result (%u, %u, %u), expected (%u, %u, %u)\n", name, i,
237 faces[i][0], faces[i][1], faces[i][2],
238 mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2]);
241 IDirect3DIndexBuffer9_Unlock(index_buffer);
244 IDirect3DIndexBuffer9_Release(index_buffer);
248 static void D3DXBoundProbeTest(void)
250 BOOL result;
251 D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition;
252 FLOAT radius;
254 /*____________Test the Box case___________________________*/
255 bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f;
256 top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f;
258 raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f;
259 rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
260 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
261 ok(result == TRUE, "expected TRUE, received FALSE\n");
263 raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f;
264 rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f;
265 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
266 ok(result == FALSE, "expected FALSE, received TRUE\n");
268 rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f;
269 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
270 ok(result == TRUE, "expected TRUE, received FALSE\n");
272 bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
273 top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f;
274 rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f;
275 raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f;
276 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
277 ok(result == FALSE, "expected FALSE, received TRUE\n");
279 bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f;
280 top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f;
282 raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f;
283 rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f;
284 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
285 ok(result == TRUE, "expected TRUE, received FALSE\n");
287 bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f;
288 top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f;
290 raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f;
291 rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
292 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
293 ok(result == FALSE, "expected FALSE, received TRUE\n");
295 raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f;
296 rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f;
297 result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection);
298 ok(result == TRUE, "expected TRUE, received FALSE\n");
300 /*____________Test the Sphere case________________________*/
301 radius = sqrt(77.0f);
302 center.x = 1.0f; center.y = 2.0f; center.z = 3.0f;
303 raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f;
305 rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 9.0f;
306 result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
307 ok(result == TRUE, "expected TRUE, received FALSE\n");
309 rayposition.x = 45.0f; rayposition.y = -75.0f; rayposition.z = 49.0f;
310 result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
311 ok(result == FALSE, "expected FALSE, received TRUE\n");
313 rayposition.x = 5.0f; rayposition.y = 11.0f; rayposition.z = 9.0f;
314 result = D3DXSphereBoundProbe(&center, radius, &rayposition, &raydirection);
315 ok(result == FALSE, "expected FALSE, received TRUE\n");
318 static void D3DXComputeBoundingBoxTest(void)
320 D3DXVECTOR3 exp_max, exp_min, got_max, got_min, vertex[5];
321 HRESULT hr;
323 vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
324 vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
325 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
326 vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
327 vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
329 exp_min.x = 1.0f; exp_min.y = 1.0f; exp_min.z = 1.0f;
330 exp_max.x = 9.0f; exp_max.y = 9.0f; exp_max.z = 9.0f;
332 hr = D3DXComputeBoundingBox(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
334 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
335 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);
336 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);
338 /*________________________*/
340 vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
341 vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
342 vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
343 vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
344 vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
346 exp_min.x = -6.92f; exp_min.y = -8.1f; exp_min.z = -3.80f;
347 exp_max.x = 11.4f; exp_max.y = 7.90f; exp_max.z = 11.9f;
349 hr = D3DXComputeBoundingBox(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
351 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
352 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);
353 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);
355 /*________________________*/
357 vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
358 vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
359 vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
360 vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
361 vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
363 exp_min.x = -6.92f; exp_min.y = -0.9f; exp_min.z = -3.8f;
364 exp_max.x = 7.43f; exp_max.y = 7.90f; exp_max.z = 11.9f;
366 hr = D3DXComputeBoundingBox(&vertex[0],4,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
368 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
369 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);
370 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);
372 /*________________________*/
373 hr = D3DXComputeBoundingBox(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,&got_max);
374 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
376 /*________________________*/
377 hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_max);
378 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
380 /*________________________*/
381 hr = D3DXComputeBoundingBox(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_min,NULL);
382 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
385 static void D3DXComputeBoundingSphereTest(void)
387 D3DXVECTOR3 exp_cen, got_cen, vertex[5];
388 FLOAT exp_rad, got_rad;
389 HRESULT hr;
391 vertex[0].x = 1.0f; vertex[0].y = 1.0f; vertex[0].z = 1.0f;
392 vertex[1].x = 1.0f; vertex[1].y = 1.0f; vertex[1].z = 1.0f;
393 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 1.0f;
394 vertex[3].x = 1.0f; vertex[3].y = 1.0f; vertex[3].z = 1.0f;
395 vertex[4].x = 9.0f; vertex[4].y = 9.0f; vertex[4].z = 9.0f;
397 exp_rad = 6.928203f;
398 exp_cen.x = 5.0; exp_cen.y = 5.0; exp_cen.z = 5.0;
400 hr = D3DXComputeBoundingSphere(&vertex[3],2,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
402 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
403 ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
404 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);
406 /*________________________*/
408 vertex[0].x = 2.0f; vertex[0].y = 5.9f; vertex[0].z = -1.2f;
409 vertex[1].x = -1.87f; vertex[1].y = 7.9f; vertex[1].z = 7.4f;
410 vertex[2].x = 7.43f; vertex[2].y = -0.9f; vertex[2].z = 11.9f;
411 vertex[3].x = -6.92f; vertex[3].y = 6.3f; vertex[3].z = -3.8f;
412 vertex[4].x = 11.4f; vertex[4].y = -8.1f; vertex[4].z = 4.5f;
414 exp_rad = 13.707883f;
415 exp_cen.x = 2.408f; exp_cen.y = 2.22f; exp_cen.z = 3.76f;
417 hr = D3DXComputeBoundingSphere(&vertex[0],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
419 ok( hr == D3D_OK, "Expected D3D_OK, got %#x\n", hr);
420 ok( compare(exp_rad, got_rad), "Expected radius: %f, got radius: %f\n", exp_rad, got_rad);
421 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);
423 /*________________________*/
424 hr = D3DXComputeBoundingSphere(NULL,5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,&got_rad);
425 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
427 /*________________________*/
428 hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),NULL,&got_rad);
429 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
431 /*________________________*/
432 hr = D3DXComputeBoundingSphere(&vertex[3],5,D3DXGetFVFVertexSize(D3DFVF_XYZ),&got_cen,NULL);
433 ok( hr == D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, got %#x\n", hr);
436 static void print_elements(const D3DVERTEXELEMENT9 *elements)
438 D3DVERTEXELEMENT9 last = D3DDECL_END();
439 const D3DVERTEXELEMENT9 *ptr = elements;
440 int count = 0;
442 while (memcmp(ptr, &last, sizeof(D3DVERTEXELEMENT9)))
444 trace(
445 "[Element %d] Stream = %d, Offset = %d, Type = %d, Method = %d, Usage = %d, UsageIndex = %d\n",
446 count, ptr->Stream, ptr->Offset, ptr->Type, ptr->Method, ptr->Usage, ptr->UsageIndex);
447 ptr++;
448 count++;
452 static void compare_elements(const D3DVERTEXELEMENT9 *elements, const D3DVERTEXELEMENT9 *expected_elements,
453 unsigned int line, unsigned int test_id)
455 D3DVERTEXELEMENT9 last = D3DDECL_END();
456 unsigned int i;
458 for (i = 0; i < MAX_FVF_DECL_SIZE; i++)
460 int end1 = memcmp(&elements[i], &last, sizeof(last));
461 int end2 = memcmp(&expected_elements[i], &last, sizeof(last));
462 int status;
464 if (!end1 && !end2) break;
466 status = !end1 ^ !end2;
467 ok(!status, "Line %u, test %u: Mismatch in size, test declaration is %s than expected.\n",
468 line, test_id, end1 ? "shorter" : "longer");
469 if (status)
471 print_elements(elements);
472 break;
475 status = memcmp(&elements[i], &expected_elements[i], sizeof(D3DVERTEXELEMENT9));
476 ok(!status, "Line %u, test %u: Mismatch in element %u.\n", line, test_id, i);
477 if (status)
479 print_elements(elements);
480 break;
485 static void test_fvf_to_decl(DWORD test_fvf, const D3DVERTEXELEMENT9 expected_elements[],
486 HRESULT expected_hr, unsigned int line, unsigned int test_id)
488 HRESULT hr;
489 D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
491 hr = D3DXDeclaratorFromFVF(test_fvf, decl);
492 ok(hr == expected_hr,
493 "Line %u, test %u: D3DXDeclaratorFromFVF returned %#x, expected %#x.\n",
494 line, test_id, hr, expected_hr);
495 if (SUCCEEDED(hr)) compare_elements(decl, expected_elements, line, test_id);
498 static void test_decl_to_fvf(const D3DVERTEXELEMENT9 *decl, DWORD expected_fvf,
499 HRESULT expected_hr, unsigned int line, unsigned int test_id)
501 HRESULT hr;
502 DWORD result_fvf = 0xdeadbeef;
504 hr = D3DXFVFFromDeclarator(decl, &result_fvf);
505 ok(hr == expected_hr,
506 "Line %u, test %u: D3DXFVFFromDeclarator returned %#x, expected %#x.\n",
507 line, test_id, hr, expected_hr);
508 if (SUCCEEDED(hr))
510 ok(expected_fvf == result_fvf, "Line %u, test %u: Got FVF %#x, expected %#x.\n",
511 line, test_id, result_fvf, expected_fvf);
515 static void test_fvf_decl_conversion(void)
517 static const struct
519 D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH + 1];
520 DWORD fvf;
522 test_data[] =
525 D3DDECL_END(),
526 }, 0},
528 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
529 D3DDECL_END(),
530 }, D3DFVF_XYZ},
532 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
533 D3DDECL_END(),
534 }, D3DFVF_XYZRHW},
536 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0},
537 D3DDECL_END(),
538 }, D3DFVF_XYZRHW},
540 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
541 {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
542 D3DDECL_END(),
543 }, D3DFVF_XYZB1},
545 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
546 {0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
547 D3DDECL_END(),
548 }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4},
550 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
551 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
552 D3DDECL_END(),
553 }, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR},
555 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
556 {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
557 D3DDECL_END(),
558 }, D3DFVF_XYZB2},
560 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
561 {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
562 {0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
563 D3DDECL_END(),
564 }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4},
566 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
567 {0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
568 {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
569 D3DDECL_END(),
570 }, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR},
572 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
573 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
574 D3DDECL_END(),
575 }, D3DFVF_XYZB3},
577 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
578 {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
579 {0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
580 D3DDECL_END(),
581 }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4},
583 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
584 {0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
585 {0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
586 D3DDECL_END(),
587 }, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR},
589 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
590 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
591 D3DDECL_END(),
592 }, D3DFVF_XYZB4},
594 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
595 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
596 {0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
597 D3DDECL_END(),
598 }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4},
600 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
601 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
602 {0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
603 D3DDECL_END(),
604 }, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR},
606 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
607 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
608 {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
609 D3DDECL_END(),
610 }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4},
612 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
613 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
614 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0},
615 D3DDECL_END(),
616 }, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR},
618 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
619 D3DDECL_END(),
620 }, D3DFVF_NORMAL},
622 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
623 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
624 D3DDECL_END(),
625 }, D3DFVF_NORMAL | D3DFVF_DIFFUSE},
627 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
628 D3DDECL_END(),
629 }, D3DFVF_PSIZE},
631 {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
632 D3DDECL_END(),
633 }, D3DFVF_DIFFUSE},
635 {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
636 D3DDECL_END(),
637 }, D3DFVF_SPECULAR},
638 /* Make sure textures of different sizes work. */
640 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
641 D3DDECL_END(),
642 }, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1},
644 {0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
645 D3DDECL_END(),
646 }, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1},
648 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0},
649 D3DDECL_END(),
650 }, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1},
652 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0},
653 D3DDECL_END(),
654 }, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1},
655 /* Make sure the TEXCOORD index works correctly - try several textures. */
657 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
658 {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
659 {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2},
660 {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
661 D3DDECL_END(),
662 }, D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1)
663 | D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE4(3)},
664 /* Now try some combination tests. */
666 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
667 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
668 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
669 {0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
670 {0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0},
671 {0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1},
672 D3DDECL_END(),
673 }, D3DFVF_XYZB4 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2
674 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1)},
676 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
677 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
678 {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
679 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
680 {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
681 {0, 36, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
682 D3DDECL_END(),
683 }, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_PSIZE | D3DFVF_SPECULAR | D3DFVF_TEX2
684 | D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE4(1)},
686 unsigned int i;
688 for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
690 test_decl_to_fvf(test_data[i].decl, test_data[i].fvf, D3D_OK, __LINE__, i);
691 test_fvf_to_decl(test_data[i].fvf, test_data[i].decl, D3D_OK, __LINE__, i);
694 /* Usage indices for position and normal are apparently ignored. */
696 const D3DVERTEXELEMENT9 decl[] =
698 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1},
699 D3DDECL_END(),
701 test_decl_to_fvf(decl, D3DFVF_XYZ, D3D_OK, __LINE__, 0);
704 const D3DVERTEXELEMENT9 decl[] =
706 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1},
707 D3DDECL_END(),
709 test_decl_to_fvf(decl, D3DFVF_NORMAL, D3D_OK, __LINE__, 0);
711 /* D3DFVF_LASTBETA_UBYTE4 and D3DFVF_LASTBETA_D3DCOLOR are ignored if
712 * there are no blend matrices. */
714 const D3DVERTEXELEMENT9 decl[] =
716 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
717 D3DDECL_END(),
719 test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_UBYTE4, decl, D3D_OK, __LINE__, 0);
722 const D3DVERTEXELEMENT9 decl[] =
724 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
725 D3DDECL_END(),
727 test_fvf_to_decl(D3DFVF_XYZ | D3DFVF_LASTBETA_D3DCOLOR, decl, D3D_OK, __LINE__, 0);
729 /* D3DFVF_LASTBETA_UBYTE4 takes precedence over D3DFVF_LASTBETA_D3DCOLOR. */
731 const D3DVERTEXELEMENT9 decl[] =
733 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
734 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
735 {0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0},
736 D3DDECL_END(),
738 test_fvf_to_decl(D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | D3DFVF_LASTBETA_UBYTE4,
739 decl, D3D_OK, __LINE__, 0);
741 /* These are supposed to fail, both ways. */
743 const D3DVERTEXELEMENT9 decl[] =
745 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
746 D3DDECL_END(),
748 test_decl_to_fvf(decl, D3DFVF_XYZW, D3DERR_INVALIDCALL, __LINE__, 0);
749 test_fvf_to_decl(D3DFVF_XYZW, decl, D3DERR_INVALIDCALL, __LINE__, 0);
752 const D3DVERTEXELEMENT9 decl[] =
754 {0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0},
755 {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
756 D3DDECL_END(),
758 test_decl_to_fvf(decl, D3DFVF_XYZW | D3DFVF_NORMAL, D3DERR_INVALIDCALL, __LINE__, 0);
759 test_fvf_to_decl(D3DFVF_XYZW | D3DFVF_NORMAL, decl, D3DERR_INVALIDCALL, __LINE__, 0);
762 const D3DVERTEXELEMENT9 decl[] =
764 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
765 {0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0},
766 {0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0},
767 D3DDECL_END(),
769 test_decl_to_fvf(decl, D3DFVF_XYZB5, D3DERR_INVALIDCALL, __LINE__, 0);
770 test_fvf_to_decl(D3DFVF_XYZB5, decl, D3DERR_INVALIDCALL, __LINE__, 0);
772 /* Test a declaration that can't be converted to an FVF. */
774 const D3DVERTEXELEMENT9 decl[] =
776 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
777 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
778 {0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0},
779 {0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1},
780 {0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
781 /* 8 bytes padding */
782 {0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1},
783 D3DDECL_END(),
785 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
787 /* Elements must be ordered by offset. */
789 const D3DVERTEXELEMENT9 decl[] =
791 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
792 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
793 D3DDECL_END(),
795 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
797 /* Basic tests for element order. */
799 const D3DVERTEXELEMENT9 decl[] =
801 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
802 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
803 {0, 16, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
804 D3DDECL_END(),
806 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
809 const D3DVERTEXELEMENT9 decl[] =
811 {0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
812 {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
813 D3DDECL_END(),
815 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
818 const D3DVERTEXELEMENT9 decl[] =
820 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0},
821 {0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
822 D3DDECL_END(),
824 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
826 /* Textures must be ordered by texcoords. */
828 const D3DVERTEXELEMENT9 decl[] =
830 {0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0},
831 {0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 2},
832 {0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 1},
833 {0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3},
834 D3DDECL_END(),
836 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
838 /* Duplicate elements are not allowed. */
840 const D3DVERTEXELEMENT9 decl[] =
842 {0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0},
843 {0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
844 {0, 16, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0},
845 D3DDECL_END(),
847 test_decl_to_fvf(decl, 0, D3DERR_INVALIDCALL, __LINE__, 0);
849 /* Invalid FVFs cannot be converted to a declarator. */
850 test_fvf_to_decl(0xdeadbeef, NULL, D3DERR_INVALIDCALL, __LINE__, 0);
853 static void D3DXGetFVFVertexSizeTest(void)
855 UINT got;
857 compare_vertex_sizes (D3DFVF_XYZ, 12);
859 compare_vertex_sizes (D3DFVF_XYZB3, 24);
861 compare_vertex_sizes (D3DFVF_XYZB5, 32);
863 compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_NORMAL, 24);
865 compare_vertex_sizes (D3DFVF_XYZ | D3DFVF_DIFFUSE, 16);
867 compare_vertex_sizes (
868 D3DFVF_XYZ |
869 D3DFVF_TEX1 |
870 D3DFVF_TEXCOORDSIZE1(0), 16);
871 compare_vertex_sizes (
872 D3DFVF_XYZ |
873 D3DFVF_TEX2 |
874 D3DFVF_TEXCOORDSIZE1(0) |
875 D3DFVF_TEXCOORDSIZE1(1), 20);
877 compare_vertex_sizes (
878 D3DFVF_XYZ |
879 D3DFVF_TEX1 |
880 D3DFVF_TEXCOORDSIZE2(0), 20);
882 compare_vertex_sizes (
883 D3DFVF_XYZ |
884 D3DFVF_TEX2 |
885 D3DFVF_TEXCOORDSIZE2(0) |
886 D3DFVF_TEXCOORDSIZE2(1), 28);
888 compare_vertex_sizes (
889 D3DFVF_XYZ |
890 D3DFVF_TEX6 |
891 D3DFVF_TEXCOORDSIZE2(0) |
892 D3DFVF_TEXCOORDSIZE2(1) |
893 D3DFVF_TEXCOORDSIZE2(2) |
894 D3DFVF_TEXCOORDSIZE2(3) |
895 D3DFVF_TEXCOORDSIZE2(4) |
896 D3DFVF_TEXCOORDSIZE2(5), 60);
898 compare_vertex_sizes (
899 D3DFVF_XYZ |
900 D3DFVF_TEX8 |
901 D3DFVF_TEXCOORDSIZE2(0) |
902 D3DFVF_TEXCOORDSIZE2(1) |
903 D3DFVF_TEXCOORDSIZE2(2) |
904 D3DFVF_TEXCOORDSIZE2(3) |
905 D3DFVF_TEXCOORDSIZE2(4) |
906 D3DFVF_TEXCOORDSIZE2(5) |
907 D3DFVF_TEXCOORDSIZE2(6) |
908 D3DFVF_TEXCOORDSIZE2(7), 76);
910 compare_vertex_sizes (
911 D3DFVF_XYZ |
912 D3DFVF_TEX1 |
913 D3DFVF_TEXCOORDSIZE3(0), 24);
915 compare_vertex_sizes (
916 D3DFVF_XYZ |
917 D3DFVF_TEX4 |
918 D3DFVF_TEXCOORDSIZE3(0) |
919 D3DFVF_TEXCOORDSIZE3(1) |
920 D3DFVF_TEXCOORDSIZE3(2) |
921 D3DFVF_TEXCOORDSIZE3(3), 60);
923 compare_vertex_sizes (
924 D3DFVF_XYZ |
925 D3DFVF_TEX1 |
926 D3DFVF_TEXCOORDSIZE4(0), 28);
928 compare_vertex_sizes (
929 D3DFVF_XYZ |
930 D3DFVF_TEX2 |
931 D3DFVF_TEXCOORDSIZE4(0) |
932 D3DFVF_TEXCOORDSIZE4(1), 44);
934 compare_vertex_sizes (
935 D3DFVF_XYZ |
936 D3DFVF_TEX3 |
937 D3DFVF_TEXCOORDSIZE4(0) |
938 D3DFVF_TEXCOORDSIZE4(1) |
939 D3DFVF_TEXCOORDSIZE4(2), 60);
941 compare_vertex_sizes (
942 D3DFVF_XYZB5 |
943 D3DFVF_NORMAL |
944 D3DFVF_DIFFUSE |
945 D3DFVF_SPECULAR |
946 D3DFVF_TEX8 |
947 D3DFVF_TEXCOORDSIZE4(0) |
948 D3DFVF_TEXCOORDSIZE4(1) |
949 D3DFVF_TEXCOORDSIZE4(2) |
950 D3DFVF_TEXCOORDSIZE4(3) |
951 D3DFVF_TEXCOORDSIZE4(4) |
952 D3DFVF_TEXCOORDSIZE4(5) |
953 D3DFVF_TEXCOORDSIZE4(6) |
954 D3DFVF_TEXCOORDSIZE4(7), 180);
957 static void D3DXIntersectTriTest(void)
959 BOOL exp_res, got_res;
960 D3DXVECTOR3 position, ray, vertex[3];
961 FLOAT exp_dist, got_dist, exp_u, got_u, exp_v, got_v;
963 vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
964 vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
965 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
967 position.x = -14.5f; position.y = -23.75f; position.z = -32.0f;
969 ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
971 exp_res = TRUE; exp_u = 0.5f; exp_v = 0.25f; exp_dist = 8.0f;
973 got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
974 ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
975 ok( compare(exp_u,got_u), "Expected u = %f, got %f\n",exp_u,got_u);
976 ok( compare(exp_v,got_v), "Expected v = %f, got %f\n",exp_v,got_v);
977 ok( compare(exp_dist,got_dist), "Expected distance = %f, got %f\n",exp_dist,got_dist);
979 /*Only positive ray is taken in account*/
981 vertex[0].x = 1.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
982 vertex[1].x = 2.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
983 vertex[2].x = 1.0f; vertex[2].y = 1.0f; vertex[2].z = 0.0f;
985 position.x = 17.5f; position.y = 24.25f; position.z = 32.0f;
987 ray.x = 2.0f; ray.y = 3.0f; ray.z = 4.0f;
989 exp_res = FALSE;
991 got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
992 ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
994 /*Intersection between ray and triangle in a same plane is considered as empty*/
996 vertex[0].x = 4.0f; vertex[0].y = 0.0f; vertex[0].z = 0.0f;
997 vertex[1].x = 6.0f; vertex[1].y = 0.0f; vertex[1].z = 0.0f;
998 vertex[2].x = 4.0f; vertex[2].y = 2.0f; vertex[2].z = 0.0f;
1000 position.x = 1.0f; position.y = 1.0f; position.z = 0.0f;
1002 ray.x = 1.0f; ray.y = 0.0f; ray.z = 0.0f;
1004 exp_res = FALSE;
1006 got_res = D3DXIntersectTri(&vertex[0],&vertex[1],&vertex[2],&position,&ray,&got_u,&got_v,&got_dist);
1007 ok( got_res == exp_res, "Expected result = %d, got %d\n",exp_res,got_res);
1010 static void D3DXCreateMeshTest(void)
1012 HRESULT hr;
1013 HWND wnd;
1014 IDirect3D9 *d3d;
1015 IDirect3DDevice9 *device, *test_device;
1016 D3DPRESENT_PARAMETERS d3dpp;
1017 ID3DXMesh *d3dxmesh;
1018 int i, size;
1019 D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1020 DWORD options;
1021 struct mesh mesh;
1023 static const D3DVERTEXELEMENT9 decl1[3] = {
1024 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1025 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1026 D3DDECL_END(), };
1028 static const D3DVERTEXELEMENT9 decl2[] = {
1029 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1030 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1031 {0, 24, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
1032 {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
1033 {0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
1034 /* 8 bytes padding */
1035 {0, 44, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
1036 D3DDECL_END(),
1039 static const D3DVERTEXELEMENT9 decl3[] = {
1040 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1041 {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1042 D3DDECL_END(),
1045 hr = D3DXCreateMesh(0, 0, 0, NULL, NULL, NULL);
1046 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1048 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, NULL, &d3dxmesh);
1049 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1051 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1052 if (!wnd)
1054 skip("Couldn't create application window\n");
1055 return;
1057 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1058 if (!d3d)
1060 skip("Couldn't create IDirect3D9 object\n");
1061 DestroyWindow(wnd);
1062 return;
1065 ZeroMemory(&d3dpp, sizeof(d3dpp));
1066 d3dpp.Windowed = TRUE;
1067 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1068 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1069 if (FAILED(hr))
1071 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1072 IDirect3D9_Release(d3d);
1073 DestroyWindow(wnd);
1074 return;
1077 hr = D3DXCreateMesh(0, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1078 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1080 hr = D3DXCreateMesh(1, 0, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1081 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1083 hr = D3DXCreateMesh(1, 3, 0, decl1, device, &d3dxmesh);
1084 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1086 if (hr == D3D_OK)
1088 d3dxmesh->lpVtbl->Release(d3dxmesh);
1091 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, 0, device, &d3dxmesh);
1092 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1094 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, NULL);
1095 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1097 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl1, device, &d3dxmesh);
1098 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1100 if (hr == D3D_OK)
1102 /* device */
1103 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1104 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1106 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1107 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1108 ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1110 if (hr == D3D_OK)
1112 IDirect3DDevice9_Release(device);
1115 /* declaration */
1116 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1117 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1119 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1120 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1122 if (hr == D3D_OK)
1124 size = sizeof(decl1) / sizeof(decl1[0]);
1125 for (i = 0; i < size - 1; i++)
1127 ok(test_decl[i].Stream == decl1[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl1[i].Stream);
1128 ok(test_decl[i].Type == decl1[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl1[i].Type);
1129 ok(test_decl[i].Method == decl1[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl1[i].Method);
1130 ok(test_decl[i].Usage == decl1[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl1[i].Usage);
1131 ok(test_decl[i].UsageIndex == decl1[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl1[i].UsageIndex);
1132 ok(test_decl[i].Offset == decl1[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl1[i].Offset);
1134 ok(decl1[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1137 /* options */
1138 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1139 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1141 /* rest */
1142 if (!new_mesh(&mesh, 3, 1))
1144 skip("Couldn't create mesh\n");
1146 else
1148 memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1149 memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1150 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1152 compare_mesh("createmesh1", d3dxmesh, &mesh);
1154 free_mesh(&mesh);
1157 d3dxmesh->lpVtbl->Release(d3dxmesh);
1160 /* Test a declaration that can't be converted to an FVF. */
1161 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl2, device, &d3dxmesh);
1162 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1164 if (hr == D3D_OK)
1166 /* device */
1167 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1168 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1170 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1171 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1172 ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1174 if (hr == D3D_OK)
1176 IDirect3DDevice9_Release(device);
1179 /* declaration */
1180 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1181 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1183 if (hr == D3D_OK)
1185 size = sizeof(decl2) / sizeof(decl2[0]);
1186 for (i = 0; i < size - 1; i++)
1188 ok(test_decl[i].Stream == decl2[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl2[i].Stream);
1189 ok(test_decl[i].Type == decl2[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl2[i].Type);
1190 ok(test_decl[i].Method == decl2[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl2[i].Method);
1191 ok(test_decl[i].Usage == decl2[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl2[i].Usage);
1192 ok(test_decl[i].UsageIndex == decl2[i].UsageIndex, "Returned usage index %d, expected %d\n", test_decl[i].UsageIndex, decl2[i].UsageIndex);
1193 ok(test_decl[i].Offset == decl2[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl2[i].Offset);
1195 ok(decl2[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1198 /* options */
1199 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1200 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1202 /* rest */
1203 if (!new_mesh(&mesh, 3, 1))
1205 skip("Couldn't create mesh\n");
1207 else
1209 memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1210 memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1211 mesh.fvf = 0;
1212 mesh.vertex_size = 60;
1214 compare_mesh("createmesh2", d3dxmesh, &mesh);
1216 free_mesh(&mesh);
1219 d3dxmesh->lpVtbl->Release(d3dxmesh);
1222 /* Test a declaration with multiple streams. */
1223 hr = D3DXCreateMesh(1, 3, D3DXMESH_MANAGED, decl3, device, &d3dxmesh);
1224 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1226 IDirect3DDevice9_Release(device);
1227 IDirect3D9_Release(d3d);
1228 DestroyWindow(wnd);
1231 static void D3DXCreateMeshFVFTest(void)
1233 HRESULT hr;
1234 HWND wnd;
1235 IDirect3D9 *d3d;
1236 IDirect3DDevice9 *device, *test_device;
1237 D3DPRESENT_PARAMETERS d3dpp;
1238 ID3DXMesh *d3dxmesh;
1239 int i, size;
1240 D3DVERTEXELEMENT9 test_decl[MAX_FVF_DECL_SIZE];
1241 DWORD options;
1242 struct mesh mesh;
1244 static const D3DVERTEXELEMENT9 decl[3] = {
1245 {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
1246 {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
1247 D3DDECL_END(), };
1249 hr = D3DXCreateMeshFVF(0, 0, 0, 0, NULL, NULL);
1250 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1252 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, NULL, &d3dxmesh);
1253 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1255 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1256 if (!wnd)
1258 skip("Couldn't create application window\n");
1259 return;
1261 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1262 if (!d3d)
1264 skip("Couldn't create IDirect3D9 object\n");
1265 DestroyWindow(wnd);
1266 return;
1269 ZeroMemory(&d3dpp, sizeof(d3dpp));
1270 d3dpp.Windowed = TRUE;
1271 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1272 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1273 if (FAILED(hr))
1275 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1276 IDirect3D9_Release(d3d);
1277 DestroyWindow(wnd);
1278 return;
1281 hr = D3DXCreateMeshFVF(0, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1282 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1284 hr = D3DXCreateMeshFVF(1, 0, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1285 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1287 hr = D3DXCreateMeshFVF(1, 3, 0, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1288 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1290 if (hr == D3D_OK)
1292 d3dxmesh->lpVtbl->Release(d3dxmesh);
1295 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, 0xdeadbeef, device, &d3dxmesh);
1296 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1298 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, NULL);
1299 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1301 hr = D3DXCreateMeshFVF(1, 3, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &d3dxmesh);
1302 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1304 if (hr == D3D_OK)
1306 /* device */
1307 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, NULL);
1308 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1310 hr = d3dxmesh->lpVtbl->GetDevice(d3dxmesh, &test_device);
1311 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
1312 ok(test_device == device, "Got result %p, expected %p\n", test_device, device);
1314 if (hr == D3D_OK)
1316 IDirect3DDevice9_Release(device);
1319 /* declaration */
1320 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, NULL);
1321 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1323 hr = d3dxmesh->lpVtbl->GetDeclaration(d3dxmesh, test_decl);
1324 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1326 if (hr == D3D_OK)
1328 size = sizeof(decl) / sizeof(decl[0]);
1329 for (i = 0; i < size - 1; i++)
1331 ok(test_decl[i].Stream == decl[i].Stream, "Returned stream %d, expected %d\n", test_decl[i].Stream, decl[i].Stream);
1332 ok(test_decl[i].Type == decl[i].Type, "Returned type %d, expected %d\n", test_decl[i].Type, decl[i].Type);
1333 ok(test_decl[i].Method == decl[i].Method, "Returned method %d, expected %d\n", test_decl[i].Method, decl[i].Method);
1334 ok(test_decl[i].Usage == decl[i].Usage, "Returned usage %d, expected %d\n", test_decl[i].Usage, decl[i].Usage);
1335 ok(test_decl[i].UsageIndex == decl[i].UsageIndex, "Returned usage index %d, expected %d\n",
1336 test_decl[i].UsageIndex, decl[i].UsageIndex);
1337 ok(test_decl[i].Offset == decl[i].Offset, "Returned offset %d, expected %d\n", test_decl[i].Offset, decl[i].Offset);
1339 ok(decl[size-1].Stream == 0xFF, "Returned too long vertex declaration\n"); /* end element */
1342 /* options */
1343 options = d3dxmesh->lpVtbl->GetOptions(d3dxmesh);
1344 ok(options == D3DXMESH_MANAGED, "Got result %x, expected %x (D3DXMESH_MANAGED)\n", options, D3DXMESH_MANAGED);
1346 /* rest */
1347 if (!new_mesh(&mesh, 3, 1))
1349 skip("Couldn't create mesh\n");
1351 else
1353 memset(mesh.vertices, 0, mesh.number_of_vertices * sizeof(*mesh.vertices));
1354 memset(mesh.faces, 0, mesh.number_of_faces * sizeof(*mesh.faces));
1355 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1357 compare_mesh("createmeshfvf", d3dxmesh, &mesh);
1359 free_mesh(&mesh);
1362 d3dxmesh->lpVtbl->Release(d3dxmesh);
1365 IDirect3DDevice9_Release(device);
1366 IDirect3D9_Release(d3d);
1367 DestroyWindow(wnd);
1370 static void D3DXCreateBoxTest(void)
1372 HRESULT hr;
1373 HWND wnd;
1374 WNDCLASS wc={0};
1375 IDirect3D9* d3d;
1376 IDirect3DDevice9* device;
1377 D3DPRESENT_PARAMETERS d3dpp;
1378 ID3DXMesh* box;
1379 ID3DXBuffer* ppBuffer;
1380 DWORD *buffer;
1381 static const DWORD adjacency[36]=
1382 {6, 9, 1, 2, 10, 0,
1383 1, 9, 3, 4, 10, 2,
1384 3, 8, 5, 7, 11, 4,
1385 0, 11, 7, 5, 8, 6,
1386 7, 4, 9, 2, 0, 8,
1387 1, 3, 11, 5, 6, 10};
1388 unsigned int i;
1390 wc.lpfnWndProc = DefWindowProcA;
1391 wc.lpszClassName = "d3dx9_test_wc";
1392 if (!RegisterClass(&wc))
1394 skip("RegisterClass failed\n");
1395 return;
1398 wnd = CreateWindow("d3dx9_test_wc", "d3dx9_test",
1399 WS_SYSMENU | WS_POPUP , 0, 0, 640, 480, 0, 0, 0, 0);
1400 ok(wnd != NULL, "Expected to have a window, received NULL\n");
1401 if (!wnd)
1403 skip("Couldn't create application window\n");
1404 return;
1407 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1408 if (!d3d)
1410 skip("Couldn't create IDirect3D9 object\n");
1411 DestroyWindow(wnd);
1412 return;
1415 memset(&d3dpp, 0, sizeof(d3dpp));
1416 d3dpp.Windowed = TRUE;
1417 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1418 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1419 if (FAILED(hr))
1421 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1422 IDirect3D9_Release(d3d);
1423 DestroyWindow(wnd);
1424 return;
1427 hr = D3DXCreateBuffer(36 * sizeof(DWORD), &ppBuffer);
1428 ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
1429 if (FAILED(hr)) goto end;
1431 hr = D3DXCreateBox(device,2.0f,20.0f,4.9f,NULL, &ppBuffer);
1432 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
1434 hr = D3DXCreateBox(NULL,22.0f,20.0f,4.9f,&box, &ppBuffer);
1435 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
1437 hr = D3DXCreateBox(device,-2.0f,20.0f,4.9f,&box, &ppBuffer);
1438 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
1440 hr = D3DXCreateBox(device,22.0f,-20.0f,4.9f,&box, &ppBuffer);
1441 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
1443 hr = D3DXCreateBox(device,22.0f,20.0f,-4.9f,&box, &ppBuffer);
1444 todo_wine ok(hr==D3DERR_INVALIDCALL, "Expected D3DERR_INVALIDCALL, received %#x\n", hr);
1446 hr = D3DXCreateBox(device,10.9f,20.0f,4.9f,&box, &ppBuffer);
1447 todo_wine ok(hr==D3D_OK, "Expected D3D_OK, received %#x\n", hr);
1449 if (FAILED(hr))
1451 skip("D3DXCreateBox failed\n");
1452 goto end;
1455 buffer = ID3DXBuffer_GetBufferPointer(ppBuffer);
1456 for(i=0; i<36; i++)
1457 todo_wine ok(adjacency[i]==buffer[i], "expected adjacency %d: %#x, received %#x\n",i,adjacency[i], buffer[i]);
1459 box->lpVtbl->Release(box);
1461 end:
1462 IDirect3DDevice9_Release(device);
1463 IDirect3D9_Release(d3d);
1464 ID3DXBuffer_Release(ppBuffer);
1465 DestroyWindow(wnd);
1468 struct sincos_table
1470 float *sin;
1471 float *cos;
1474 static void free_sincos_table(struct sincos_table *sincos_table)
1476 HeapFree(GetProcessHeap(), 0, sincos_table->cos);
1477 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1480 /* pre compute sine and cosine tables; caller must free */
1481 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
1483 float angle;
1484 int i;
1486 sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
1487 if (!sincos_table->sin)
1489 return FALSE;
1491 sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
1492 if (!sincos_table->cos)
1494 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1495 return FALSE;
1498 angle = angle_start;
1499 for (i = 0; i < n; i++)
1501 sincos_table->sin[i] = sin(angle);
1502 sincos_table->cos[i] = cos(angle);
1503 angle += angle_step;
1506 return TRUE;
1509 static WORD vertex_index(UINT slices, int slice, int stack)
1511 return stack*slices+slice+1;
1514 /* slices = subdivisions along xy plane, stacks = subdivisions along z axis */
1515 static BOOL compute_sphere(struct mesh *mesh, FLOAT radius, UINT slices, UINT stacks)
1517 float theta_step, theta_start;
1518 struct sincos_table theta;
1519 float phi_step, phi_start;
1520 struct sincos_table phi;
1521 DWORD number_of_vertices, number_of_faces;
1522 DWORD vertex, face;
1523 int slice, stack;
1525 /* theta = angle on xy plane wrt x axis */
1526 theta_step = M_PI / stacks;
1527 theta_start = theta_step;
1529 /* phi = angle on xz plane wrt z axis */
1530 phi_step = -2 * M_PI / slices;
1531 phi_start = M_PI / 2;
1533 if (!compute_sincos_table(&theta, theta_start, theta_step, stacks))
1535 return FALSE;
1537 if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
1539 free_sincos_table(&theta);
1540 return FALSE;
1543 number_of_vertices = 2 + slices * (stacks-1);
1544 number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
1546 if (!new_mesh(mesh, number_of_vertices, number_of_faces))
1548 free_sincos_table(&phi);
1549 free_sincos_table(&theta);
1550 return FALSE;
1553 vertex = 0;
1554 face = 0;
1556 mesh->vertices[vertex].normal.x = 0.0f;
1557 mesh->vertices[vertex].normal.y = 0.0f;
1558 mesh->vertices[vertex].normal.z = 1.0f;
1559 mesh->vertices[vertex].position.x = 0.0f;
1560 mesh->vertices[vertex].position.y = 0.0f;
1561 mesh->vertices[vertex].position.z = radius;
1562 vertex++;
1564 for (stack = 0; stack < stacks - 1; stack++)
1566 for (slice = 0; slice < slices; slice++)
1568 mesh->vertices[vertex].normal.x = theta.sin[stack] * phi.cos[slice];
1569 mesh->vertices[vertex].normal.y = theta.sin[stack] * phi.sin[slice];
1570 mesh->vertices[vertex].normal.z = theta.cos[stack];
1571 mesh->vertices[vertex].position.x = radius * theta.sin[stack] * phi.cos[slice];
1572 mesh->vertices[vertex].position.y = radius * theta.sin[stack] * phi.sin[slice];
1573 mesh->vertices[vertex].position.z = radius * theta.cos[stack];
1574 vertex++;
1576 if (slice > 0)
1578 if (stack == 0)
1580 /* top stack is triangle fan */
1581 mesh->faces[face][0] = 0;
1582 mesh->faces[face][1] = slice + 1;
1583 mesh->faces[face][2] = slice;
1584 face++;
1586 else
1588 /* stacks in between top and bottom are quad strips */
1589 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1590 mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
1591 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
1592 face++;
1594 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
1595 mesh->faces[face][1] = vertex_index(slices, slice, stack);
1596 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
1597 face++;
1602 if (stack == 0)
1604 mesh->faces[face][0] = 0;
1605 mesh->faces[face][1] = 1;
1606 mesh->faces[face][2] = slice;
1607 face++;
1609 else
1611 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1612 mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
1613 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
1614 face++;
1616 mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
1617 mesh->faces[face][1] = vertex_index(slices, 0, stack);
1618 mesh->faces[face][2] = vertex_index(slices, slice-1, stack);
1619 face++;
1623 mesh->vertices[vertex].position.x = 0.0f;
1624 mesh->vertices[vertex].position.y = 0.0f;
1625 mesh->vertices[vertex].position.z = -radius;
1626 mesh->vertices[vertex].normal.x = 0.0f;
1627 mesh->vertices[vertex].normal.y = 0.0f;
1628 mesh->vertices[vertex].normal.z = -1.0f;
1630 /* bottom stack is triangle fan */
1631 for (slice = 1; slice < slices; slice++)
1633 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1634 mesh->faces[face][1] = vertex_index(slices, slice, stack-1);
1635 mesh->faces[face][2] = vertex;
1636 face++;
1639 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1640 mesh->faces[face][1] = vertex_index(slices, 0, stack-1);
1641 mesh->faces[face][2] = vertex;
1643 free_sincos_table(&phi);
1644 free_sincos_table(&theta);
1646 return TRUE;
1649 static void test_sphere(IDirect3DDevice9 *device, FLOAT radius, UINT slices, UINT stacks)
1651 HRESULT hr;
1652 ID3DXMesh *sphere;
1653 struct mesh mesh;
1654 char name[256];
1656 hr = D3DXCreateSphere(device, radius, slices, stacks, &sphere, NULL);
1657 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1658 if (hr != D3D_OK)
1660 skip("Couldn't create sphere\n");
1661 return;
1664 if (!compute_sphere(&mesh, radius, slices, stacks))
1666 skip("Couldn't create mesh\n");
1667 sphere->lpVtbl->Release(sphere);
1668 return;
1671 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1673 sprintf(name, "sphere (%g, %u, %u)", radius, slices, stacks);
1674 compare_mesh(name, sphere, &mesh);
1676 free_mesh(&mesh);
1678 sphere->lpVtbl->Release(sphere);
1681 static void D3DXCreateSphereTest(void)
1683 HRESULT hr;
1684 HWND wnd;
1685 IDirect3D9* d3d;
1686 IDirect3DDevice9* device;
1687 D3DPRESENT_PARAMETERS d3dpp;
1688 ID3DXMesh* sphere = NULL;
1690 hr = D3DXCreateSphere(NULL, 0.0f, 0, 0, NULL, NULL);
1691 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1693 hr = D3DXCreateSphere(NULL, 0.1f, 0, 0, NULL, NULL);
1694 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1696 hr = D3DXCreateSphere(NULL, 0.0f, 1, 0, NULL, NULL);
1697 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1699 hr = D3DXCreateSphere(NULL, 0.0f, 0, 1, NULL, NULL);
1700 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1702 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1703 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1704 if (!wnd)
1706 skip("Couldn't create application window\n");
1707 return;
1709 if (!d3d)
1711 skip("Couldn't create IDirect3D9 object\n");
1712 DestroyWindow(wnd);
1713 return;
1716 ZeroMemory(&d3dpp, sizeof(d3dpp));
1717 d3dpp.Windowed = TRUE;
1718 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1719 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1720 if (FAILED(hr))
1722 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1723 IDirect3D9_Release(d3d);
1724 DestroyWindow(wnd);
1725 return;
1728 hr = D3DXCreateSphere(device, 1.0f, 1, 1, &sphere, NULL);
1729 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1731 hr = D3DXCreateSphere(device, 1.0f, 2, 1, &sphere, NULL);
1732 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1734 hr = D3DXCreateSphere(device, 1.0f, 1, 2, &sphere, NULL);
1735 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1737 hr = D3DXCreateSphere(device, -0.1f, 1, 2, &sphere, NULL);
1738 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
1740 test_sphere(device, 0.0f, 2, 2);
1741 test_sphere(device, 1.0f, 2, 2);
1742 test_sphere(device, 1.0f, 3, 2);
1743 test_sphere(device, 1.0f, 4, 4);
1744 test_sphere(device, 1.0f, 3, 4);
1745 test_sphere(device, 5.0f, 6, 7);
1746 test_sphere(device, 10.0f, 11, 12);
1748 IDirect3DDevice9_Release(device);
1749 IDirect3D9_Release(d3d);
1750 DestroyWindow(wnd);
1753 static BOOL compute_cylinder(struct mesh *mesh, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
1755 float theta_step, theta_start;
1756 struct sincos_table theta;
1757 FLOAT delta_radius, radius, radius_step;
1758 FLOAT z, z_step, z_normal;
1759 DWORD number_of_vertices, number_of_faces;
1760 DWORD vertex, face;
1761 int slice, stack;
1763 /* theta = angle on xy plane wrt x axis */
1764 theta_step = -2 * M_PI / slices;
1765 theta_start = M_PI / 2;
1767 if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
1769 return FALSE;
1772 number_of_vertices = 2 + (slices * (3 + stacks));
1773 number_of_faces = 2 * slices + stacks * (2 * slices);
1775 if (!new_mesh(mesh, number_of_vertices, number_of_faces))
1777 free_sincos_table(&theta);
1778 return FALSE;
1781 vertex = 0;
1782 face = 0;
1784 delta_radius = radius1 - radius2;
1785 radius = radius1;
1786 radius_step = delta_radius / stacks;
1788 z = -length / 2;
1789 z_step = length / stacks;
1790 z_normal = delta_radius / length;
1791 if (isnan(z_normal))
1793 z_normal = 0.0f;
1796 mesh->vertices[vertex].normal.x = 0.0f;
1797 mesh->vertices[vertex].normal.y = 0.0f;
1798 mesh->vertices[vertex].normal.z = -1.0f;
1799 mesh->vertices[vertex].position.x = 0.0f;
1800 mesh->vertices[vertex].position.y = 0.0f;
1801 mesh->vertices[vertex++].position.z = z;
1803 for (slice = 0; slice < slices; slice++, vertex++)
1805 mesh->vertices[vertex].normal.x = 0.0f;
1806 mesh->vertices[vertex].normal.y = 0.0f;
1807 mesh->vertices[vertex].normal.z = -1.0f;
1808 mesh->vertices[vertex].position.x = radius * theta.cos[slice];
1809 mesh->vertices[vertex].position.y = radius * theta.sin[slice];
1810 mesh->vertices[vertex].position.z = z;
1812 if (slice > 0)
1814 mesh->faces[face][0] = 0;
1815 mesh->faces[face][1] = slice;
1816 mesh->faces[face++][2] = slice + 1;
1820 mesh->faces[face][0] = 0;
1821 mesh->faces[face][1] = slice;
1822 mesh->faces[face++][2] = 1;
1824 for (stack = 1; stack <= stacks+1; stack++)
1826 for (slice = 0; slice < slices; slice++, vertex++)
1828 mesh->vertices[vertex].normal.x = theta.cos[slice];
1829 mesh->vertices[vertex].normal.y = theta.sin[slice];
1830 mesh->vertices[vertex].normal.z = z_normal;
1831 D3DXVec3Normalize(&mesh->vertices[vertex].normal, &mesh->vertices[vertex].normal);
1832 mesh->vertices[vertex].position.x = radius * theta.cos[slice];
1833 mesh->vertices[vertex].position.y = radius * theta.sin[slice];
1834 mesh->vertices[vertex].position.z = z;
1836 if (stack > 1 && slice > 0)
1838 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1839 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
1840 mesh->faces[face++][2] = vertex_index(slices, slice, stack-1);
1842 mesh->faces[face][0] = vertex_index(slices, slice, stack-1);
1843 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
1844 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
1848 if (stack > 1)
1850 mesh->faces[face][0] = vertex_index(slices, slice-1, stack-1);
1851 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
1852 mesh->faces[face++][2] = vertex_index(slices, 0, stack-1);
1854 mesh->faces[face][0] = vertex_index(slices, 0, stack-1);
1855 mesh->faces[face][1] = vertex_index(slices, slice-1, stack);
1856 mesh->faces[face++][2] = vertex_index(slices, 0, stack);
1859 if (stack < stacks + 1)
1861 z += z_step;
1862 radius -= radius_step;
1866 for (slice = 0; slice < slices; slice++, vertex++)
1868 mesh->vertices[vertex].normal.x = 0.0f;
1869 mesh->vertices[vertex].normal.y = 0.0f;
1870 mesh->vertices[vertex].normal.z = 1.0f;
1871 mesh->vertices[vertex].position.x = radius * theta.cos[slice];
1872 mesh->vertices[vertex].position.y = radius * theta.sin[slice];
1873 mesh->vertices[vertex].position.z = z;
1875 if (slice > 0)
1877 mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
1878 mesh->faces[face][1] = number_of_vertices - 1;
1879 mesh->faces[face++][2] = vertex_index(slices, slice, stack);
1883 mesh->vertices[vertex].position.x = 0.0f;
1884 mesh->vertices[vertex].position.y = 0.0f;
1885 mesh->vertices[vertex].position.z = z;
1886 mesh->vertices[vertex].normal.x = 0.0f;
1887 mesh->vertices[vertex].normal.y = 0.0f;
1888 mesh->vertices[vertex].normal.z = 1.0f;
1890 mesh->faces[face][0] = vertex_index(slices, slice-1, stack);
1891 mesh->faces[face][1] = number_of_vertices - 1;
1892 mesh->faces[face][2] = vertex_index(slices, 0, stack);
1894 free_sincos_table(&theta);
1896 return TRUE;
1899 static void test_cylinder(IDirect3DDevice9 *device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices, UINT stacks)
1901 HRESULT hr;
1902 ID3DXMesh *cylinder;
1903 struct mesh mesh;
1904 char name[256];
1906 hr = D3DXCreateCylinder(device, radius1, radius2, length, slices, stacks, &cylinder, NULL);
1907 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
1908 if (hr != D3D_OK)
1910 skip("Couldn't create cylinder\n");
1911 return;
1914 if (!compute_cylinder(&mesh, radius1, radius2, length, slices, stacks))
1916 skip("Couldn't create mesh\n");
1917 cylinder->lpVtbl->Release(cylinder);
1918 return;
1921 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
1923 sprintf(name, "cylinder (%g, %g, %g, %u, %u)", radius1, radius2, length, slices, stacks);
1924 compare_mesh(name, cylinder, &mesh);
1926 free_mesh(&mesh);
1928 cylinder->lpVtbl->Release(cylinder);
1931 static void D3DXCreateCylinderTest(void)
1933 HRESULT hr;
1934 HWND wnd;
1935 IDirect3D9* d3d;
1936 IDirect3DDevice9* device;
1937 D3DPRESENT_PARAMETERS d3dpp;
1938 ID3DXMesh* cylinder = NULL;
1940 hr = D3DXCreateCylinder(NULL, 0.0f, 0.0f, 0.0f, 0, 0, NULL, NULL);
1941 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1943 hr = D3DXCreateCylinder(NULL, 1.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
1944 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1946 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
1947 d3d = Direct3DCreate9(D3D_SDK_VERSION);
1948 if (!wnd)
1950 skip("Couldn't create application window\n");
1951 return;
1953 if (!d3d)
1955 skip("Couldn't create IDirect3D9 object\n");
1956 DestroyWindow(wnd);
1957 return;
1960 ZeroMemory(&d3dpp, sizeof(d3dpp));
1961 d3dpp.Windowed = TRUE;
1962 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1963 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
1964 if (FAILED(hr))
1966 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
1967 IDirect3D9_Release(d3d);
1968 DestroyWindow(wnd);
1969 return;
1972 hr = D3DXCreateCylinder(device, -0.1f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
1973 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1975 hr = D3DXCreateCylinder(device, 0.0f, 1.0f, 1.0f, 2, 1, &cylinder, NULL);
1976 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
1978 if (SUCCEEDED(hr) && cylinder)
1980 cylinder->lpVtbl->Release(cylinder);
1983 hr = D3DXCreateCylinder(device, 1.0f, -0.1f, 1.0f, 2, 1, &cylinder, NULL);
1984 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1986 hr = D3DXCreateCylinder(device, 1.0f, 0.0f, 1.0f, 2, 1, &cylinder, NULL);
1987 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
1989 if (SUCCEEDED(hr) && cylinder)
1991 cylinder->lpVtbl->Release(cylinder);
1994 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, -0.1f, 2, 1, &cylinder, NULL);
1995 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
1997 /* Test with length == 0.0f succeeds */
1998 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 0.0f, 2, 1, &cylinder, NULL);
1999 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n",hr);
2001 if (SUCCEEDED(hr) && cylinder)
2003 cylinder->lpVtbl->Release(cylinder);
2006 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 1, 1, &cylinder, NULL);
2007 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2009 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 0, &cylinder, NULL);
2010 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2012 hr = D3DXCreateCylinder(device, 1.0f, 1.0f, 1.0f, 2, 1, NULL, NULL);
2013 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n",hr,D3DERR_INVALIDCALL);
2015 test_cylinder(device, 0.0f, 0.0f, 0.0f, 2, 1);
2016 test_cylinder(device, 1.0f, 1.0f, 1.0f, 2, 1);
2017 test_cylinder(device, 1.0f, 1.0f, 2.0f, 3, 4);
2018 test_cylinder(device, 3.0f, 2.0f, 4.0f, 3, 4);
2019 test_cylinder(device, 2.0f, 3.0f, 4.0f, 3, 4);
2020 test_cylinder(device, 3.0f, 4.0f, 5.0f, 11, 20);
2022 IDirect3DDevice9_Release(device);
2023 IDirect3D9_Release(d3d);
2024 DestroyWindow(wnd);
2027 struct dynamic_array
2029 int count, capacity;
2030 void *items;
2033 enum pointtype {
2034 POINTTYPE_CURVE = 0,
2035 POINTTYPE_CORNER,
2036 POINTTYPE_CURVE_START,
2037 POINTTYPE_CURVE_END,
2038 POINTTYPE_CURVE_MIDDLE,
2041 struct point2d
2043 D3DXVECTOR2 pos;
2044 enum pointtype corner;
2047 /* is a dynamic_array */
2048 struct outline
2050 int count, capacity;
2051 struct point2d *items;
2054 /* is a dynamic_array */
2055 struct outline_array
2057 int count, capacity;
2058 struct outline *items;
2061 struct glyphinfo
2063 struct outline_array outlines;
2064 float offset_x;
2067 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
2069 if (count > array->capacity) {
2070 void *new_buffer;
2071 int new_capacity;
2072 if (array->items && array->capacity) {
2073 new_capacity = max(array->capacity * 2, count);
2074 new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
2075 } else {
2076 new_capacity = max(16, count);
2077 new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
2079 if (!new_buffer)
2080 return FALSE;
2081 array->items = new_buffer;
2082 array->capacity = new_capacity;
2084 return TRUE;
2087 static struct point2d *add_point(struct outline *array)
2089 struct point2d *item;
2091 if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
2092 return NULL;
2094 item = &array->items[array->count++];
2095 ZeroMemory(item, sizeof(*item));
2096 return item;
2099 static struct outline *add_outline(struct outline_array *array)
2101 struct outline *item;
2103 if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
2104 return NULL;
2106 item = &array->items[array->count++];
2107 ZeroMemory(item, sizeof(*item));
2108 return item;
2111 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
2113 D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
2114 while (count--) {
2115 D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
2116 pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
2117 pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
2118 pt++;
2120 return ret;
2123 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
2124 const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
2125 float max_deviation)
2127 D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
2128 float deviation;
2130 D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
2131 D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
2132 D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
2134 deviation = D3DXVec2Length(D3DXVec2Subtract(&vec, &middle, p2));
2135 if (deviation < max_deviation) {
2136 struct point2d *pt = add_point(outline);
2137 if (!pt) return E_OUTOFMEMORY;
2138 pt->pos = *p2;
2139 pt->corner = POINTTYPE_CURVE;
2140 /* the end point is omitted because the end line merges into the next segment of
2141 * the split bezier curve, and the end of the split bezier curve is added outside
2142 * this recursive function. */
2143 } else {
2144 HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation);
2145 if (hr != S_OK) return hr;
2146 hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation);
2147 if (hr != S_OK) return hr;
2150 return S_OK;
2153 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
2155 /* dot product = cos(theta) */
2156 return D3DXVec2Dot(dir1, dir2) > cos_theta;
2159 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
2161 return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
2164 static BOOL attempt_line_merge(struct outline *outline,
2165 int pt_index,
2166 const D3DXVECTOR2 *nextpt,
2167 BOOL to_curve)
2169 D3DXVECTOR2 curdir, lastdir;
2170 struct point2d *prevpt, *pt;
2171 BOOL ret = FALSE;
2172 const float cos_half = cos(D3DXToRadian(0.5f));
2174 pt = &outline->items[pt_index];
2175 pt_index = (pt_index - 1 + outline->count) % outline->count;
2176 prevpt = &outline->items[pt_index];
2178 if (to_curve)
2179 pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
2181 if (outline->count < 2)
2182 return FALSE;
2184 /* remove last point if the next line continues the last line */
2185 unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
2186 unit_vec2(&curdir, &pt->pos, nextpt);
2187 if (is_direction_similar(&lastdir, &curdir, cos_half))
2189 outline->count--;
2190 if (pt->corner == POINTTYPE_CURVE_END)
2191 prevpt->corner = pt->corner;
2192 if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
2193 prevpt->corner = POINTTYPE_CURVE_MIDDLE;
2194 pt = prevpt;
2196 ret = TRUE;
2197 if (outline->count < 2)
2198 return ret;
2200 pt_index = (pt_index - 1 + outline->count) % outline->count;
2201 prevpt = &outline->items[pt_index];
2202 unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
2203 unit_vec2(&curdir, &pt->pos, nextpt);
2205 return ret;
2208 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
2209 float max_deviation, float emsquare)
2211 const float cos_45 = cos(D3DXToRadian(45.0f));
2212 const float cos_90 = cos(D3DXToRadian(90.0f));
2213 TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
2215 while ((char *)header < (char *)raw_outline + datasize)
2217 TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
2218 struct point2d *lastpt, *pt;
2219 D3DXVECTOR2 lastdir;
2220 D3DXVECTOR2 *pt_flt;
2221 int j;
2222 struct outline *outline = add_outline(&glyph->outlines);
2224 if (!outline)
2225 return E_OUTOFMEMORY;
2227 pt = add_point(outline);
2228 if (!pt)
2229 return E_OUTOFMEMORY;
2230 pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
2231 pt->pos = *pt_flt;
2232 pt->corner = POINTTYPE_CORNER;
2234 if (header->dwType != TT_POLYGON_TYPE)
2235 trace("Unknown header type %d\n", header->dwType);
2237 while ((char *)curve < (char *)header + header->cb)
2239 D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
2240 BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
2242 if (!curve->cpfx) {
2243 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
2244 continue;
2247 pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
2249 attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve);
2251 if (to_curve)
2253 HRESULT hr;
2254 int count = curve->cpfx;
2255 j = 0;
2257 while (count > 2)
2259 D3DXVECTOR2 bezier_end;
2261 D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
2262 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation);
2263 if (hr != S_OK)
2264 return hr;
2265 bezier_start = bezier_end;
2266 count--;
2267 j++;
2269 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation);
2270 if (hr != S_OK)
2271 return hr;
2273 pt = add_point(outline);
2274 if (!pt)
2275 return E_OUTOFMEMORY;
2276 j++;
2277 pt->pos = pt_flt[j];
2278 pt->corner = POINTTYPE_CURVE_END;
2279 } else {
2280 for (j = 0; j < curve->cpfx; j++)
2282 pt = add_point(outline);
2283 if (!pt)
2284 return E_OUTOFMEMORY;
2285 pt->pos = pt_flt[j];
2286 pt->corner = POINTTYPE_CORNER;
2290 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
2293 /* remove last point if the next line continues the last line */
2294 if (outline->count >= 3) {
2295 BOOL to_curve;
2297 lastpt = &outline->items[outline->count - 1];
2298 pt = &outline->items[0];
2299 if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
2300 if (lastpt->corner == POINTTYPE_CURVE_END)
2302 if (pt->corner == POINTTYPE_CURVE_START)
2303 pt->corner = POINTTYPE_CURVE_MIDDLE;
2304 else
2305 pt->corner = POINTTYPE_CURVE_END;
2307 outline->count--;
2308 lastpt = &outline->items[outline->count - 1];
2309 } else {
2310 /* outline closed with a line from end to start point */
2311 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE);
2313 lastpt = &outline->items[0];
2314 to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
2315 if (lastpt->corner == POINTTYPE_CURVE_START)
2316 lastpt->corner = POINTTYPE_CORNER;
2317 pt = &outline->items[1];
2318 if (attempt_line_merge(outline, 0, &pt->pos, to_curve))
2319 *lastpt = outline->items[outline->count];
2322 lastpt = &outline->items[outline->count - 1];
2323 pt = &outline->items[0];
2324 unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
2325 for (j = 0; j < outline->count; j++)
2327 D3DXVECTOR2 curdir;
2329 lastpt = pt;
2330 pt = &outline->items[(j + 1) % outline->count];
2331 unit_vec2(&curdir, &lastpt->pos, &pt->pos);
2333 switch (lastpt->corner)
2335 case POINTTYPE_CURVE_START:
2336 case POINTTYPE_CURVE_END:
2337 if (!is_direction_similar(&lastdir, &curdir, cos_45))
2338 lastpt->corner = POINTTYPE_CORNER;
2339 break;
2340 case POINTTYPE_CURVE_MIDDLE:
2341 if (!is_direction_similar(&lastdir, &curdir, cos_90))
2342 lastpt->corner = POINTTYPE_CORNER;
2343 else
2344 lastpt->corner = POINTTYPE_CURVE;
2345 break;
2346 default:
2347 break;
2349 lastdir = curdir;
2352 header = (TTPOLYGONHEADER *)((char *)header + header->cb);
2354 return S_OK;
2357 static BOOL compute_text_mesh(struct mesh *mesh, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion, FLOAT otmEMSquare)
2359 HRESULT hr = E_FAIL;
2360 DWORD nb_vertices, nb_faces;
2361 DWORD nb_corners, nb_outline_points;
2362 int textlen = 0;
2363 float offset_x;
2364 char *raw_outline = NULL;
2365 struct glyphinfo *glyphs = NULL;
2366 GLYPHMETRICS gm;
2367 int i;
2368 struct vertex *vertex_ptr;
2369 face *face_ptr;
2371 if (deviation == 0.0f)
2372 deviation = 1.0f / otmEMSquare;
2374 textlen = strlen(text);
2375 glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
2376 if (!glyphs) {
2377 hr = E_OUTOFMEMORY;
2378 goto error;
2381 offset_x = 0.0f;
2382 for (i = 0; i < textlen; i++)
2384 /* get outline points from data returned from GetGlyphOutline */
2385 const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
2386 int datasize;
2388 glyphs[i].offset_x = offset_x;
2390 datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
2391 if (datasize < 0) {
2392 hr = E_FAIL;
2393 goto error;
2395 HeapFree(GetProcessHeap(), 0, raw_outline);
2396 raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize);
2397 if (!glyphs) {
2398 hr = E_OUTOFMEMORY;
2399 goto error;
2401 datasize = GetGlyphOutline(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity);
2403 create_outline(&glyphs[i], raw_outline, datasize, deviation, otmEMSquare);
2405 offset_x += gm.gmCellIncX / (float)otmEMSquare;
2408 /* corner points need an extra vertex for the different side faces normals */
2409 nb_corners = 0;
2410 nb_outline_points = 0;
2411 for (i = 0; i < textlen; i++)
2413 int j;
2414 for (j = 0; j < glyphs[i].outlines.count; j++)
2416 int k;
2417 struct outline *outline = &glyphs[i].outlines.items[j];
2418 nb_outline_points += outline->count;
2419 nb_corners++; /* first outline point always repeated as a corner */
2420 for (k = 1; k < outline->count; k++)
2421 if (outline->items[k].corner)
2422 nb_corners++;
2426 nb_vertices = (nb_outline_points + nb_corners) * 2 + textlen;
2427 nb_faces = nb_outline_points * 2;
2429 if (!new_mesh(mesh, nb_vertices, nb_faces))
2430 goto error;
2432 /* convert 2D vertices and faces into 3D mesh */
2433 vertex_ptr = mesh->vertices;
2434 face_ptr = mesh->faces;
2435 for (i = 0; i < textlen; i++)
2437 int j;
2439 /* side vertices and faces */
2440 for (j = 0; j < glyphs[i].outlines.count; j++)
2442 struct vertex *outline_vertices = vertex_ptr;
2443 struct outline *outline = &glyphs[i].outlines.items[j];
2444 int k;
2445 struct point2d *prevpt = &outline->items[outline->count - 1];
2446 struct point2d *pt = &outline->items[0];
2448 for (k = 1; k <= outline->count; k++)
2450 struct vertex vtx;
2451 struct point2d *nextpt = &outline->items[k % outline->count];
2452 WORD vtx_idx = vertex_ptr - mesh->vertices;
2453 D3DXVECTOR2 vec;
2455 if (pt->corner == POINTTYPE_CURVE_START)
2456 D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
2457 else if (pt->corner)
2458 D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
2459 else
2460 D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
2461 D3DXVec2Normalize(&vec, &vec);
2462 vtx.normal.x = -vec.y;
2463 vtx.normal.y = vec.x;
2464 vtx.normal.z = 0;
2466 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
2467 vtx.position.y = pt->pos.y;
2468 vtx.position.z = 0;
2469 *vertex_ptr++ = vtx;
2471 vtx.position.z = -extrusion;
2472 *vertex_ptr++ = vtx;
2474 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
2475 vtx.position.y = nextpt->pos.y;
2476 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
2477 vtx.position.z = -extrusion;
2478 *vertex_ptr++ = vtx;
2479 vtx.position.z = 0;
2480 *vertex_ptr++ = vtx;
2482 (*face_ptr)[0] = vtx_idx;
2483 (*face_ptr)[1] = vtx_idx + 2;
2484 (*face_ptr)[2] = vtx_idx + 1;
2485 face_ptr++;
2487 (*face_ptr)[0] = vtx_idx;
2488 (*face_ptr)[1] = vtx_idx + 3;
2489 (*face_ptr)[2] = vtx_idx + 2;
2490 face_ptr++;
2491 } else {
2492 if (nextpt->corner) {
2493 if (nextpt->corner == POINTTYPE_CURVE_END) {
2494 struct point2d *nextpt2 = &outline->items[(k + 1) % outline->count];
2495 D3DXVec2Subtract(&vec, &nextpt2->pos, &nextpt->pos);
2496 } else {
2497 D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
2499 D3DXVec2Normalize(&vec, &vec);
2500 vtx.normal.x = -vec.y;
2501 vtx.normal.y = vec.x;
2503 vtx.position.z = 0;
2504 *vertex_ptr++ = vtx;
2505 vtx.position.z = -extrusion;
2506 *vertex_ptr++ = vtx;
2509 (*face_ptr)[0] = vtx_idx;
2510 (*face_ptr)[1] = vtx_idx + 3;
2511 (*face_ptr)[2] = vtx_idx + 1;
2512 face_ptr++;
2514 (*face_ptr)[0] = vtx_idx;
2515 (*face_ptr)[1] = vtx_idx + 2;
2516 (*face_ptr)[2] = vtx_idx + 3;
2517 face_ptr++;
2520 prevpt = pt;
2521 pt = nextpt;
2523 if (!pt->corner) {
2524 *vertex_ptr++ = *outline_vertices++;
2525 *vertex_ptr++ = *outline_vertices++;
2529 /* FIXME: compute expected faces */
2530 /* Add placeholder to seperate glyph outlines */
2531 vertex_ptr->position.x = 0;
2532 vertex_ptr->position.y = 0;
2533 vertex_ptr->position.z = 0;
2534 vertex_ptr->normal.x = 0;
2535 vertex_ptr->normal.y = 0;
2536 vertex_ptr->normal.z = 1;
2537 vertex_ptr++;
2540 hr = D3D_OK;
2541 error:
2542 if (glyphs) {
2543 for (i = 0; i < textlen; i++)
2545 int j;
2546 for (j = 0; j < glyphs[i].outlines.count; j++)
2547 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items[j].items);
2548 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items);
2550 HeapFree(GetProcessHeap(), 0, glyphs);
2552 HeapFree(GetProcessHeap(), 0, raw_outline);
2554 return hr == D3D_OK;
2557 static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh, int textlen, float extrusion)
2559 HRESULT hr;
2560 DWORD number_of_vertices, number_of_faces;
2561 IDirect3DVertexBuffer9 *vertex_buffer = NULL;
2562 IDirect3DIndexBuffer9 *index_buffer = NULL;
2563 D3DVERTEXBUFFER_DESC vertex_buffer_description;
2564 D3DINDEXBUFFER_DESC index_buffer_description;
2565 struct vertex *vertices = NULL;
2566 face *faces = NULL;
2567 int expected, i;
2568 int vtx_idx1, face_idx1, vtx_idx2, face_idx2;
2570 number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
2571 number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
2573 /* vertex buffer */
2574 hr = d3dxmesh->lpVtbl->GetVertexBuffer(d3dxmesh, &vertex_buffer);
2575 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
2576 if (hr != D3D_OK)
2578 skip("Couldn't get vertex buffers\n");
2579 goto error;
2582 hr = IDirect3DVertexBuffer9_GetDesc(vertex_buffer, &vertex_buffer_description);
2583 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
2585 if (hr != D3D_OK)
2587 skip("Couldn't get vertex buffer description\n");
2589 else
2591 ok(vertex_buffer_description.Format == D3DFMT_VERTEXDATA, "Test %s, result %x, expected %x (D3DFMT_VERTEXDATA)\n",
2592 name, vertex_buffer_description.Format, D3DFMT_VERTEXDATA);
2593 ok(vertex_buffer_description.Type == D3DRTYPE_VERTEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_VERTEXBUFFER)\n",
2594 name, vertex_buffer_description.Type, D3DRTYPE_VERTEXBUFFER);
2595 ok(vertex_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, vertex_buffer_description.Usage, 0);
2596 ok(vertex_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_DEFAULT)\n",
2597 name, vertex_buffer_description.Pool, D3DPOOL_DEFAULT);
2598 ok(vertex_buffer_description.FVF == mesh->fvf, "Test %s, result %x, expected %x\n",
2599 name, vertex_buffer_description.FVF, mesh->fvf);
2600 if (mesh->fvf == 0)
2602 expected = number_of_vertices * mesh->vertex_size;
2604 else
2606 expected = number_of_vertices * D3DXGetFVFVertexSize(mesh->fvf);
2608 ok(vertex_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
2609 name, vertex_buffer_description.Size, expected);
2612 hr = d3dxmesh->lpVtbl->GetIndexBuffer(d3dxmesh, &index_buffer);
2613 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
2614 if (hr != D3D_OK)
2616 skip("Couldn't get index buffer\n");
2617 goto error;
2620 hr = IDirect3DIndexBuffer9_GetDesc(index_buffer, &index_buffer_description);
2621 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
2623 if (hr != D3D_OK)
2625 skip("Couldn't get index buffer description\n");
2627 else
2629 ok(index_buffer_description.Format == D3DFMT_INDEX16, "Test %s, result %x, expected %x (D3DFMT_INDEX16)\n",
2630 name, index_buffer_description.Format, D3DFMT_INDEX16);
2631 ok(index_buffer_description.Type == D3DRTYPE_INDEXBUFFER, "Test %s, result %x, expected %x (D3DRTYPE_INDEXBUFFER)\n",
2632 name, index_buffer_description.Type, D3DRTYPE_INDEXBUFFER);
2633 todo_wine ok(index_buffer_description.Usage == 0, "Test %s, result %x, expected %x\n", name, index_buffer_description.Usage, 0);
2634 ok(index_buffer_description.Pool == D3DPOOL_MANAGED, "Test %s, result %x, expected %x (D3DPOOL_DEFAULT)\n",
2635 name, index_buffer_description.Pool, D3DPOOL_DEFAULT);
2636 expected = number_of_faces * sizeof(WORD) * 3;
2637 ok(index_buffer_description.Size == expected, "Test %s, result %x, expected %x\n",
2638 name, index_buffer_description.Size, expected);
2641 /* specify offset and size to avoid potential overruns */
2642 hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, number_of_vertices * sizeof(D3DXVECTOR3) * 2,
2643 (LPVOID *)&vertices, D3DLOCK_DISCARD);
2644 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
2645 if (hr != D3D_OK)
2647 skip("Couldn't lock vertex buffer\n");
2648 goto error;
2650 hr = IDirect3DIndexBuffer9_Lock(index_buffer, 0, number_of_faces * sizeof(WORD) * 3,
2651 (LPVOID *)&faces, D3DLOCK_DISCARD);
2652 ok(hr == D3D_OK, "Test %s, result %x, expected 0 (D3D_OK)\n", name, hr);
2653 if (hr != D3D_OK)
2655 skip("Couldn't lock index buffer\n");
2656 goto error;
2659 face_idx1 = 0;
2660 vtx_idx2 = 0;
2661 face_idx2 = 0;
2662 vtx_idx1 = 0;
2663 for (i = 0; i < textlen; i++)
2665 int nb_outline_vertices1, nb_outline_faces1;
2666 int nb_outline_vertices2, nb_outline_faces2;
2667 int nb_back_vertices, nb_back_faces;
2668 int first_vtx1, first_vtx2;
2669 int first_face1, first_face2;
2670 int j;
2672 first_vtx1 = vtx_idx1;
2673 first_vtx2 = vtx_idx2;
2674 for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
2675 if (vertices[vtx_idx1].normal.z != 0)
2676 break;
2678 for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
2679 if (mesh->vertices[vtx_idx2].normal.z != 0)
2680 break;
2682 nb_outline_vertices1 = vtx_idx1 - first_vtx1;
2683 nb_outline_vertices2 = vtx_idx2 - first_vtx2;
2684 ok(nb_outline_vertices1 == nb_outline_vertices2,
2685 "Test %s, glyph %d, outline vertex count result %d, expected %d\n", name, i,
2686 nb_outline_vertices1, nb_outline_vertices2);
2688 for (j = 0; j < min(nb_outline_vertices1, nb_outline_vertices2); j++)
2690 vtx_idx1 = first_vtx1 + j;
2691 vtx_idx2 = first_vtx2 + j;
2692 ok(compare_vec3(vertices[vtx_idx1].position, mesh->vertices[vtx_idx2].position),
2693 "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
2694 vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
2695 mesh->vertices[vtx_idx2].position.x, mesh->vertices[vtx_idx2].position.y, mesh->vertices[vtx_idx2].position.z);
2696 ok(compare_vec3(vertices[vtx_idx1].normal, mesh->vertices[first_vtx2 + j].normal),
2697 "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
2698 vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
2699 mesh->vertices[vtx_idx2].normal.x, mesh->vertices[vtx_idx2].normal.y, mesh->vertices[vtx_idx2].normal.z);
2701 vtx_idx1 = first_vtx1 + nb_outline_vertices1;
2702 vtx_idx2 = first_vtx2 + nb_outline_vertices2;
2704 first_face1 = face_idx1;
2705 first_face2 = face_idx2;
2706 for (; face_idx1 < number_of_faces; face_idx1++)
2708 if (faces[face_idx1][0] >= vtx_idx1 ||
2709 faces[face_idx1][1] >= vtx_idx1 ||
2710 faces[face_idx1][2] >= vtx_idx1)
2711 break;
2713 for (; face_idx2 < mesh->number_of_faces; face_idx2++)
2715 if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
2716 mesh->faces[face_idx2][1] >= vtx_idx2 ||
2717 mesh->faces[face_idx2][2] >= vtx_idx2)
2718 break;
2720 nb_outline_faces1 = face_idx1 - first_face1;
2721 nb_outline_faces2 = face_idx2 - first_face2;
2722 ok(nb_outline_faces1 == nb_outline_faces2,
2723 "Test %s, glyph %d, outline face count result %d, expected %d\n", name, i,
2724 nb_outline_faces1, nb_outline_faces2);
2726 for (j = 0; j < min(nb_outline_faces1, nb_outline_faces2); j++)
2728 face_idx1 = first_face1 + j;
2729 face_idx2 = first_face2 + j;
2730 ok(faces[face_idx1][0] - first_vtx1 == mesh->faces[face_idx2][0] - first_vtx2 &&
2731 faces[face_idx1][1] - first_vtx1 == mesh->faces[face_idx2][1] - first_vtx2 &&
2732 faces[face_idx1][2] - first_vtx1 == mesh->faces[face_idx2][2] - first_vtx2,
2733 "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
2734 faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
2735 mesh->faces[face_idx2][0] - first_vtx2 + first_vtx1,
2736 mesh->faces[face_idx2][1] - first_vtx2 + first_vtx1,
2737 mesh->faces[face_idx2][2] - first_vtx2 + first_vtx1);
2739 face_idx1 = first_face1 + nb_outline_faces1;
2740 face_idx2 = first_face2 + nb_outline_faces2;
2742 /* partial test on back vertices and faces */
2743 first_vtx1 = vtx_idx1;
2744 for (; vtx_idx1 < number_of_vertices; vtx_idx1++) {
2745 struct vertex vtx;
2747 if (vertices[vtx_idx1].normal.z != 1.0f)
2748 break;
2750 vtx.position.z = 0.0f;
2751 vtx.normal.x = 0.0f;
2752 vtx.normal.y = 0.0f;
2753 vtx.normal.z = 1.0f;
2754 ok(compare(vertices[vtx_idx1].position.z, vtx.position.z),
2755 "Test %s, glyph %d, vertex position.z %d, result %g, expected %g\n", name, i, vtx_idx1,
2756 vertices[vtx_idx1].position.z, vtx.position.z);
2757 ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
2758 "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
2759 vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
2760 vtx.normal.x, vtx.normal.y, vtx.normal.z);
2762 nb_back_vertices = vtx_idx1 - first_vtx1;
2763 first_face1 = face_idx1;
2764 for (; face_idx1 < number_of_faces; face_idx1++)
2766 const D3DXVECTOR3 *vtx1, *vtx2, *vtx3;
2767 D3DXVECTOR3 normal;
2768 D3DXVECTOR3 v1 = {0, 0, 0};
2769 D3DXVECTOR3 v2 = {0, 0, 0};
2770 D3DXVECTOR3 forward = {0.0f, 0.0f, 1.0f};
2772 if (faces[face_idx1][0] >= vtx_idx1 ||
2773 faces[face_idx1][1] >= vtx_idx1 ||
2774 faces[face_idx1][2] >= vtx_idx1)
2775 break;
2777 vtx1 = &vertices[faces[face_idx1][0]].position;
2778 vtx2 = &vertices[faces[face_idx1][1]].position;
2779 vtx3 = &vertices[faces[face_idx1][2]].position;
2781 D3DXVec3Subtract(&v1, vtx2, vtx1);
2782 D3DXVec3Subtract(&v2, vtx3, vtx2);
2783 D3DXVec3Cross(&normal, &v1, &v2);
2784 D3DXVec3Normalize(&normal, &normal);
2785 ok(compare_vec3(normal, forward),
2786 "Test %s, glyph %d, face %d normal, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, face_idx1,
2787 normal.x, normal.y, normal.z, forward.x, forward.y, forward.z);
2789 nb_back_faces = face_idx1 - first_face1;
2791 /* compare front and back faces & vertices */
2792 if (extrusion == 0.0f) {
2793 /* Oddly there are only back faces in this case */
2794 nb_back_vertices /= 2;
2795 nb_back_faces /= 2;
2796 face_idx1 -= nb_back_faces;
2797 vtx_idx1 -= nb_back_vertices;
2799 for (j = 0; j < nb_back_vertices; j++)
2801 struct vertex vtx = vertices[first_vtx1];
2802 vtx.position.z = -extrusion;
2803 vtx.normal.x = 0.0f;
2804 vtx.normal.y = 0.0f;
2805 vtx.normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
2806 ok(compare_vec3(vertices[vtx_idx1].position, vtx.position),
2807 "Test %s, glyph %d, vertex position %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
2808 vertices[vtx_idx1].position.x, vertices[vtx_idx1].position.y, vertices[vtx_idx1].position.z,
2809 vtx.position.x, vtx.position.y, vtx.position.z);
2810 ok(compare_vec3(vertices[vtx_idx1].normal, vtx.normal),
2811 "Test %s, glyph %d, vertex normal %d, result (%g, %g, %g), expected (%g, %g, %g)\n", name, i, vtx_idx1,
2812 vertices[vtx_idx1].normal.x, vertices[vtx_idx1].normal.y, vertices[vtx_idx1].normal.z,
2813 vtx.normal.x, vtx.normal.y, vtx.normal.z);
2814 vtx_idx1++;
2815 first_vtx1++;
2817 for (j = 0; j < nb_back_faces; j++)
2819 int f1, f2;
2820 if (extrusion == 0.0f) {
2821 f1 = 1;
2822 f2 = 2;
2823 } else {
2824 f1 = 2;
2825 f2 = 1;
2827 ok(faces[face_idx1][0] == faces[first_face1][0] + nb_back_vertices &&
2828 faces[face_idx1][1] == faces[first_face1][f1] + nb_back_vertices &&
2829 faces[face_idx1][2] == faces[first_face1][f2] + nb_back_vertices,
2830 "Test %s, glyph %d, face %d, result (%d, %d, %d), expected (%d, %d, %d)\n", name, i, face_idx1,
2831 faces[face_idx1][0], faces[face_idx1][1], faces[face_idx1][2],
2832 faces[first_face1][0] - nb_back_faces,
2833 faces[first_face1][f1] - nb_back_faces,
2834 faces[first_face1][f2] - nb_back_faces);
2835 first_face1++;
2836 face_idx1++;
2839 /* skip to the outline for the next glyph */
2840 for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) {
2841 if (mesh->vertices[vtx_idx2].normal.z == 0)
2842 break;
2844 for (; face_idx2 < mesh->number_of_faces; face_idx2++)
2846 if (mesh->faces[face_idx2][0] >= vtx_idx2 ||
2847 mesh->faces[face_idx2][1] >= vtx_idx2 ||
2848 mesh->faces[face_idx2][2] >= vtx_idx2) break;
2852 error:
2853 if (vertices) IDirect3DVertexBuffer9_Unlock(vertex_buffer);
2854 if (faces) IDirect3DIndexBuffer9_Unlock(index_buffer);
2855 if (index_buffer) IDirect3DIndexBuffer9_Release(index_buffer);
2856 if (vertex_buffer) IDirect3DVertexBuffer9_Release(vertex_buffer);
2859 static void test_createtext(IDirect3DDevice9 *device, HDC hdc, LPCSTR text, FLOAT deviation, FLOAT extrusion)
2861 HRESULT hr;
2862 ID3DXMesh *d3dxmesh;
2863 struct mesh mesh;
2864 char name[256];
2865 OUTLINETEXTMETRIC otm;
2866 GLYPHMETRICS gm;
2867 GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text));
2868 int i;
2869 LOGFONT lf;
2870 HFONT font = NULL, oldfont = NULL;
2872 sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion);
2874 hr = D3DXCreateText(device, hdc, text, deviation, extrusion, &d3dxmesh, NULL, glyphmetrics_float);
2875 ok(hr == D3D_OK, "Got result %x, expected 0 (D3D_OK)\n", hr);
2876 if (hr != D3D_OK)
2878 skip("Couldn't create text with D3DXCreateText\n");
2879 return;
2882 /* must select a modified font having lfHeight = otm.otmEMSquare before
2883 * calling GetGlyphOutline to get the expected values */
2884 if (!GetObject(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf) ||
2885 !GetOutlineTextMetrics(hdc, sizeof(otm), &otm))
2887 d3dxmesh->lpVtbl->Release(d3dxmesh);
2888 skip("Couldn't get text outline\n");
2889 return;
2891 lf.lfHeight = otm.otmEMSquare;
2892 lf.lfWidth = 0;
2893 font = CreateFontIndirect(&lf);
2894 if (!font) {
2895 d3dxmesh->lpVtbl->Release(d3dxmesh);
2896 skip("Couldn't create the modified font\n");
2897 return;
2899 oldfont = SelectObject(hdc, font);
2901 for (i = 0; i < strlen(text); i++)
2903 const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
2904 GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
2905 compare_float(glyphmetrics_float[i].gmfBlackBoxX, gm.gmBlackBoxX / (float)otm.otmEMSquare);
2906 compare_float(glyphmetrics_float[i].gmfBlackBoxY, gm.gmBlackBoxY / (float)otm.otmEMSquare);
2907 compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.x, gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare);
2908 compare_float(glyphmetrics_float[i].gmfptGlyphOrigin.y, gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare);
2909 compare_float(glyphmetrics_float[i].gmfCellIncX, gm.gmCellIncX / (float)otm.otmEMSquare);
2910 compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare);
2913 ZeroMemory(&mesh, sizeof(mesh));
2914 if (!compute_text_mesh(&mesh, hdc, text, deviation, extrusion, otm.otmEMSquare))
2916 skip("Couldn't create mesh\n");
2917 d3dxmesh->lpVtbl->Release(d3dxmesh);
2918 return;
2920 mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL;
2922 compare_text_outline_mesh(name, d3dxmesh, &mesh, strlen(text), extrusion);
2924 free_mesh(&mesh);
2926 d3dxmesh->lpVtbl->Release(d3dxmesh);
2927 SelectObject(hdc, oldfont);
2928 HeapFree(GetProcessHeap(), 0, glyphmetrics_float);
2931 static void D3DXCreateTextTest(void)
2933 HRESULT hr;
2934 HWND wnd;
2935 HDC hdc;
2936 IDirect3D9* d3d;
2937 IDirect3DDevice9* device;
2938 D3DPRESENT_PARAMETERS d3dpp;
2939 ID3DXMesh* d3dxmesh = NULL;
2940 HFONT hFont;
2941 OUTLINETEXTMETRIC otm;
2942 int number_of_vertices;
2943 int number_of_faces;
2945 wnd = CreateWindow("static", "d3dx9_test", WS_POPUP, 0, 0, 1000, 1000, NULL, NULL, NULL, NULL);
2946 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2947 if (!wnd)
2949 skip("Couldn't create application window\n");
2950 return;
2952 if (!d3d)
2954 skip("Couldn't create IDirect3D9 object\n");
2955 DestroyWindow(wnd);
2956 return;
2959 ZeroMemory(&d3dpp, sizeof(d3dpp));
2960 d3dpp.Windowed = TRUE;
2961 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2962 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
2963 if (FAILED(hr))
2965 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
2966 IDirect3D9_Release(d3d);
2967 DestroyWindow(wnd);
2968 return;
2971 hdc = CreateCompatibleDC(NULL);
2973 hFont = CreateFont(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
2974 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
2975 "Arial");
2976 SelectObject(hdc, hFont);
2977 GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
2979 hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, NULL, NULL, NULL);
2980 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2982 /* D3DXCreateTextA page faults from passing NULL text */
2984 hr = D3DXCreateTextW(device, hdc, NULL, 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
2985 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2987 hr = D3DXCreateText(device, hdc, "", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
2988 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2990 hr = D3DXCreateText(device, hdc, " ", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
2991 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2993 hr = D3DXCreateText(NULL, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
2994 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2996 hr = D3DXCreateText(device, NULL, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
2997 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
2999 hr = D3DXCreateText(device, hdc, "wine", -FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
3000 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3002 hr = D3DXCreateText(device, hdc, "wine", 0.001f, -FLT_MIN, &d3dxmesh, NULL, NULL);
3003 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3005 /* deviation = 0.0f treated as if deviation = 1.0f / otm.otmEMSquare */
3006 hr = D3DXCreateText(device, hdc, "wine", 1.0f / otm.otmEMSquare, 0.4f, &d3dxmesh, NULL, NULL);
3007 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
3008 number_of_vertices = d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh);
3009 number_of_faces = d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh);
3010 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
3012 hr = D3DXCreateText(device, hdc, "wine", 0.0f, 0.4f, &d3dxmesh, NULL, NULL);
3013 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
3014 ok(number_of_vertices == d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh),
3015 "Got %d vertices, expected %d\n",
3016 d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_vertices);
3017 ok(number_of_faces == d3dxmesh->lpVtbl->GetNumFaces(d3dxmesh),
3018 "Got %d faces, expected %d\n",
3019 d3dxmesh->lpVtbl->GetNumVertices(d3dxmesh), number_of_faces);
3020 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
3022 #if 0
3023 /* too much detail requested, so will appear to hang */
3024 trace("Waiting for D3DXCreateText to finish with deviation = FLT_MIN ...\n");
3025 hr = D3DXCreateText(device, hdc, "wine", FLT_MIN, 0.4f, &d3dxmesh, NULL, NULL);
3026 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
3027 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
3028 trace("D3DXCreateText finish with deviation = FLT_MIN\n");
3029 #endif
3031 hr = D3DXCreateText(device, hdc, "wine", 0.001f, 0.4f, &d3dxmesh, NULL, NULL);
3032 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
3033 if (SUCCEEDED(hr) && d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
3035 test_createtext(device, hdc, "wine", FLT_MAX, 0.4f);
3036 test_createtext(device, hdc, "wine", 0.001f, FLT_MIN);
3037 test_createtext(device, hdc, "wine", 0.001f, 0.0f);
3038 test_createtext(device, hdc, "wine", 0.001f, FLT_MAX);
3039 test_createtext(device, hdc, "wine", 0.0f, 1.0f);
3041 DeleteDC(hdc);
3043 IDirect3DDevice9_Release(device);
3044 IDirect3D9_Release(d3d);
3045 DestroyWindow(wnd);
3048 static void test_get_decl_length(void)
3050 static const D3DVERTEXELEMENT9 declaration1[] =
3052 {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3053 {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3054 {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3055 {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3056 {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3057 {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3058 {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3059 {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3060 {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3061 {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3062 {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3063 {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3064 {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3065 {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3066 {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3067 D3DDECL_END(),
3069 static const D3DVERTEXELEMENT9 declaration2[] =
3071 {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3072 {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3073 {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3074 {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3075 {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3076 {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3077 {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3078 {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3079 {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3080 {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3081 {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3082 {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3083 {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3084 {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3085 {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3086 {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3087 D3DDECL_END(),
3089 UINT size;
3091 size = D3DXGetDeclLength(declaration1);
3092 ok(size == 15, "Got size %u, expected 15.\n", size);
3094 size = D3DXGetDeclLength(declaration2);
3095 ok(size == 16, "Got size %u, expected 16.\n", size);
3098 static void test_get_decl_vertex_size(void)
3100 static const D3DVERTEXELEMENT9 declaration1[] =
3102 {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3103 {1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3104 {2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3105 {3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3106 {4, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3107 {5, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3108 {6, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3109 {7, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3110 {8, 0, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3111 {9, 0, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3112 {10, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3113 {11, 0, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3114 {12, 0, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3115 {13, 0, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3116 {14, 0, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3117 D3DDECL_END(),
3119 static const D3DVERTEXELEMENT9 declaration2[] =
3121 {0, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3122 {1, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3123 {2, 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3124 {3, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3125 {4, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3126 {5, 8, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3127 {6, 8, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3128 {7, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3129 {0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3130 {1, 8, D3DDECLTYPE_SHORT2N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3131 {2, 8, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3132 {3, 8, D3DDECLTYPE_UDEC3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3133 {4, 8, D3DDECLTYPE_DEC3N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3134 {5, 8, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3135 {6, 8, D3DDECLTYPE_FLOAT16_4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3136 {7, 8, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
3137 D3DDECL_END(),
3139 static const UINT sizes1[] =
3141 4, 8, 12, 16,
3142 4, 4, 4, 8,
3143 4, 4, 8, 4,
3144 4, 4, 8, 0,
3146 static const UINT sizes2[] =
3148 12, 16, 20, 24,
3149 12, 12, 16, 16,
3151 unsigned int i;
3152 UINT size;
3154 size = D3DXGetDeclVertexSize(NULL, 0);
3155 ok(size == 0, "Got size %#x, expected 0.\n", size);
3157 for (i = 0; i < 16; ++i)
3159 size = D3DXGetDeclVertexSize(declaration1, i);
3160 ok(size == sizes1[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes1[i]);
3163 for (i = 0; i < 8; ++i)
3165 size = D3DXGetDeclVertexSize(declaration2, i);
3166 ok(size == sizes2[i], "Got size %u for stream %u, expected %u.\n", size, i, sizes2[i]);
3170 static void D3DXGenerateAdjacencyTest(void)
3172 HRESULT hr;
3173 HWND wnd;
3174 IDirect3D9 *d3d;
3175 IDirect3DDevice9 *device;
3176 D3DPRESENT_PARAMETERS d3dpp;
3177 ID3DXMesh *d3dxmesh = NULL;
3178 D3DXVECTOR3 *vertices = NULL;
3179 WORD *indices = NULL;
3180 int i;
3181 struct {
3182 DWORD num_vertices;
3183 D3DXVECTOR3 vertices[6];
3184 DWORD num_faces;
3185 WORD indices[3 * 3];
3186 FLOAT epsilon;
3187 DWORD adjacency[3 * 3];
3188 } test_data[] = {
3189 { /* for epsilon < 0, indices must match for faces to be adjacent */
3190 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}},
3191 2, {0, 1, 2, 0, 2, 3},
3192 -1.0,
3193 {-1, -1, 1, 0, -1, -1},
3196 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}},
3197 2, {0, 1, 2, 3, 4, 5},
3198 -1.0,
3199 {-1, -1, -1, -1, -1, -1},
3201 { /* for epsilon == 0, indices or vertices must match for faces to be adjacent */
3202 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}},
3203 2, {0, 1, 2, 3, 4, 5},
3204 0.0,
3205 {-1, -1, 1, 0, -1, -1},
3207 { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
3208 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}},
3209 2, {0, 1, 2, 3, 4, 5},
3210 0.25,
3211 {-1, -1, -1, -1, -1, -1},
3213 { /* for epsilon > 0, vertices must be less than (but NOT equal to) epsilon distance away */
3214 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}},
3215 2, {0, 1, 2, 3, 4, 5},
3216 0.250001,
3217 {-1, -1, 1, 0, -1, -1},
3219 { /* length between vertices are compared to epsilon, not the individual dimension deltas */
3220 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}},
3221 2, {0, 1, 2, 3, 4, 5},
3222 0.353, /* < sqrt(0.25*0.25 + 0.25*0.25) */
3223 {-1, -1, -1, -1, -1, -1},
3226 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}},
3227 2, {0, 1, 2, 3, 4, 5},
3228 0.354, /* > sqrt(0.25*0.25 + 0.25*0.25) */
3229 {-1, -1, 1, 0, -1, -1},
3231 { /* adjacent faces must have opposite winding orders at the shared edge */
3232 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}},
3233 2, {0, 1, 2, 0, 3, 2},
3234 0.0,
3235 {-1, -1, -1, -1, -1, -1},
3239 wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
3240 if (!wnd)
3242 skip("Couldn't create application window\n");
3243 return;
3245 d3d = Direct3DCreate9(D3D_SDK_VERSION);
3246 if (!d3d)
3248 skip("Couldn't create IDirect3D9 object\n");
3249 DestroyWindow(wnd);
3250 return;
3253 ZeroMemory(&d3dpp, sizeof(d3dpp));
3254 d3dpp.Windowed = TRUE;
3255 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
3256 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
3257 if (FAILED(hr))
3259 skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
3260 IDirect3D9_Release(d3d);
3261 DestroyWindow(wnd);
3262 return;
3265 for (i = 0; i < ARRAY_SIZE(test_data); i++)
3267 DWORD adjacency[ARRAY_SIZE(test_data[0].adjacency)];
3268 int j;
3270 if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
3271 d3dxmesh = NULL;
3273 hr = D3DXCreateMeshFVF(test_data[i].num_faces, test_data[i].num_vertices, 0, D3DFVF_XYZ, device, &d3dxmesh);
3274 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
3276 hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&vertices);
3277 ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
3278 if (FAILED(hr)) continue;
3279 CopyMemory(vertices, test_data[i].vertices, test_data[i].num_vertices * sizeof(test_data[0].vertices[0]));
3280 d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
3282 hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, D3DLOCK_DISCARD, (void**)&indices);
3283 ok(hr == D3D_OK, "test %d: Got result %x, expected %x (D3D_OK)\n", i, hr, D3D_OK);
3284 if (FAILED(hr)) continue;
3285 CopyMemory(indices, test_data[i].indices, test_data[i].num_faces * 3 * sizeof(test_data[0].indices[0]));
3286 d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
3288 if (i == 0) {
3289 hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, NULL);
3290 ok(hr == D3DERR_INVALIDCALL, "Got result %x, expected %x (D3DERR_INVALIDCALL)\n", hr, D3DERR_INVALIDCALL);
3293 hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, test_data[i].epsilon, adjacency);
3294 ok(hr == D3D_OK, "Got result %x, expected %x (D3D_OK)\n", hr, D3D_OK);
3295 if (FAILED(hr)) continue;
3297 for (j = 0; j < test_data[i].num_faces * 3; j++)
3298 ok(adjacency[j] == test_data[i].adjacency[j],
3299 "Test %d adjacency %d: Got result %u, expected %u\n", i, j,
3300 adjacency[j], test_data[i].adjacency[j]);
3302 if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
3305 START_TEST(mesh)
3307 D3DXBoundProbeTest();
3308 D3DXComputeBoundingBoxTest();
3309 D3DXComputeBoundingSphereTest();
3310 D3DXGetFVFVertexSizeTest();
3311 D3DXIntersectTriTest();
3312 D3DXCreateMeshTest();
3313 D3DXCreateMeshFVFTest();
3314 D3DXCreateBoxTest();
3315 D3DXCreateSphereTest();
3316 D3DXCreateCylinderTest();
3317 D3DXCreateTextTest();
3318 test_get_decl_length();
3319 test_get_decl_vertex_size();
3320 test_fvf_decl_conversion();
3321 D3DXGenerateAdjacencyTest();