xref: /reactos/dll/directx/wine/d3dx9_36/mesh.c (revision 71c6a60a)
1  /*
2  * Mesh operations specific to D3DX9.
3  *
4  * Copyright (C) 2005 Henri Verbeet
5  * Copyright (C) 2006 Ivan Gyurdiev
6  * Copyright (C) 2009 David Adam
7  * Copyright (C) 2010 Tony Wasserka
8  * Copyright (C) 2011 Dylan Smith
9  * Copyright (C) 2011 Michael Mc Donnell
10  * Copyright (C) 2013 Christian Costa
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include "config.h"
28 #include "wine/port.h"
29 
30 #include <assert.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 
35 #include "d3dx9_private.h"
36 #undef MAKE_DDHRESULT
37 #include "dxfile.h"
38 #include "rmxfguid.h"
39 #include "rmxftmpl.h"
40 #include "wine/unicode.h"
41 #include "wine/list.h"
42 
43 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
44 
45 struct d3dx9_mesh
46 {
47     ID3DXMesh ID3DXMesh_iface;
48     LONG ref;
49 
50     DWORD numfaces;
51     DWORD numvertices;
52     DWORD options;
53     DWORD fvf;
54     IDirect3DDevice9 *device;
55     D3DVERTEXELEMENT9 cached_declaration[MAX_FVF_DECL_SIZE];
56     IDirect3DVertexDeclaration9 *vertex_declaration;
57     UINT vertex_declaration_size;
58     UINT num_elem;
59     IDirect3DVertexBuffer9 *vertex_buffer;
60     IDirect3DIndexBuffer9 *index_buffer;
61     DWORD *attrib_buffer;
62     int attrib_buffer_lock_count;
63     DWORD attrib_table_size;
64     D3DXATTRIBUTERANGE *attrib_table;
65 };
66 
67 static const UINT d3dx_decltype_size[] =
68 {
69    /* D3DDECLTYPE_FLOAT1    */ sizeof(FLOAT),
70    /* D3DDECLTYPE_FLOAT2    */ sizeof(D3DXVECTOR2),
71    /* D3DDECLTYPE_FLOAT3    */ sizeof(D3DXVECTOR3),
72    /* D3DDECLTYPE_FLOAT4    */ sizeof(D3DXVECTOR4),
73    /* D3DDECLTYPE_D3DCOLOR  */ sizeof(D3DCOLOR),
74    /* D3DDECLTYPE_UBYTE4    */ 4 * sizeof(BYTE),
75    /* D3DDECLTYPE_SHORT2    */ 2 * sizeof(SHORT),
76    /* D3DDECLTYPE_SHORT4    */ 4 * sizeof(SHORT),
77    /* D3DDECLTYPE_UBYTE4N   */ 4 * sizeof(BYTE),
78    /* D3DDECLTYPE_SHORT2N   */ 2 * sizeof(SHORT),
79    /* D3DDECLTYPE_SHORT4N   */ 4 * sizeof(SHORT),
80    /* D3DDECLTYPE_USHORT2N  */ 2 * sizeof(USHORT),
81    /* D3DDECLTYPE_USHORT4N  */ 4 * sizeof(USHORT),
82    /* D3DDECLTYPE_UDEC3     */ 4, /* 3 * 10 bits + 2 padding */
83    /* D3DDECLTYPE_DEC3N     */ 4,
84    /* D3DDECLTYPE_FLOAT16_2 */ 2 * sizeof(D3DXFLOAT16),
85    /* D3DDECLTYPE_FLOAT16_4 */ 4 * sizeof(D3DXFLOAT16),
86 };
87 
88 static inline struct d3dx9_mesh *impl_from_ID3DXMesh(ID3DXMesh *iface)
89 {
90     return CONTAINING_RECORD(iface, struct d3dx9_mesh, ID3DXMesh_iface);
91 }
92 
93 static HRESULT WINAPI d3dx9_mesh_QueryInterface(ID3DXMesh *iface, REFIID riid, void **out)
94 {
95     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
96 
97     if (IsEqualGUID(riid, &IID_IUnknown) ||
98         IsEqualGUID(riid, &IID_ID3DXBaseMesh) ||
99         IsEqualGUID(riid, &IID_ID3DXMesh))
100     {
101         iface->lpVtbl->AddRef(iface);
102         *out = iface;
103         return S_OK;
104     }
105 
106     WARN("Interface %s not found.\n", debugstr_guid(riid));
107 
108     return E_NOINTERFACE;
109 }
110 
111 static ULONG WINAPI d3dx9_mesh_AddRef(ID3DXMesh *iface)
112 {
113     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
114     ULONG refcount = InterlockedIncrement(&mesh->ref);
115 
116     TRACE("%p increasing refcount to %u.\n", mesh, refcount);
117 
118     return refcount;
119 }
120 
121 static ULONG WINAPI d3dx9_mesh_Release(ID3DXMesh *iface)
122 {
123     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
124     ULONG refcount = InterlockedDecrement(&mesh->ref);
125 
126     TRACE("%p decreasing refcount to %u.\n", mesh, refcount);
127 
128     if (!refcount)
129     {
130         IDirect3DIndexBuffer9_Release(mesh->index_buffer);
131         IDirect3DVertexBuffer9_Release(mesh->vertex_buffer);
132         if (mesh->vertex_declaration)
133             IDirect3DVertexDeclaration9_Release(mesh->vertex_declaration);
134         IDirect3DDevice9_Release(mesh->device);
135         HeapFree(GetProcessHeap(), 0, mesh->attrib_buffer);
136         HeapFree(GetProcessHeap(), 0, mesh->attrib_table);
137         HeapFree(GetProcessHeap(), 0, mesh);
138     }
139 
140     return refcount;
141 }
142 
143 static HRESULT WINAPI d3dx9_mesh_DrawSubset(ID3DXMesh *iface, DWORD attrib_id)
144 {
145     struct d3dx9_mesh *This = impl_from_ID3DXMesh(iface);
146     HRESULT hr;
147     DWORD face_start;
148     DWORD face_end = 0;
149     DWORD vertex_size;
150 
151     TRACE("iface %p, attrib_id %u.\n", iface, attrib_id);
152 
153     if (!This->vertex_declaration)
154     {
155         WARN("Can't draw a mesh with an invalid vertex declaration.\n");
156         return E_FAIL;
157     }
158 
159     vertex_size = iface->lpVtbl->GetNumBytesPerVertex(iface);
160 
161     hr = IDirect3DDevice9_SetVertexDeclaration(This->device, This->vertex_declaration);
162     if (FAILED(hr)) return hr;
163     hr = IDirect3DDevice9_SetStreamSource(This->device, 0, This->vertex_buffer, 0, vertex_size);
164     if (FAILED(hr)) return hr;
165     hr = IDirect3DDevice9_SetIndices(This->device, This->index_buffer);
166     if (FAILED(hr)) return hr;
167 
168     while (face_end < This->numfaces)
169     {
170         for (face_start = face_end; face_start < This->numfaces; face_start++)
171         {
172             if (This->attrib_buffer[face_start] == attrib_id)
173                 break;
174         }
175         if (face_start >= This->numfaces)
176             break;
177         for (face_end = face_start + 1; face_end < This->numfaces; face_end++)
178         {
179             if (This->attrib_buffer[face_end] != attrib_id)
180                 break;
181         }
182 
183         hr = IDirect3DDevice9_DrawIndexedPrimitive(This->device, D3DPT_TRIANGLELIST,
184                 0, 0, This->numvertices, face_start * 3, face_end - face_start);
185         if (FAILED(hr)) return hr;
186     }
187 
188     return D3D_OK;
189 }
190 
191 static DWORD WINAPI d3dx9_mesh_GetNumFaces(ID3DXMesh *iface)
192 {
193     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
194 
195     TRACE("iface %p.\n", iface);
196 
197     return mesh->numfaces;
198 }
199 
200 static DWORD WINAPI d3dx9_mesh_GetNumVertices(ID3DXMesh *iface)
201 {
202     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
203 
204     TRACE("iface %p.\n", iface);
205 
206     return mesh->numvertices;
207 }
208 
209 static DWORD WINAPI d3dx9_mesh_GetFVF(ID3DXMesh *iface)
210 {
211     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
212 
213     TRACE("iface %p.\n", iface);
214 
215     return mesh->fvf;
216 }
217 
218 static void copy_declaration(D3DVERTEXELEMENT9 *dst, const D3DVERTEXELEMENT9 *src, UINT num_elem)
219 {
220     memcpy(dst, src, num_elem * sizeof(*src));
221 }
222 
223 static HRESULT WINAPI d3dx9_mesh_GetDeclaration(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
224 {
225     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
226 
227     TRACE("iface %p, declaration %p.\n", iface, declaration);
228 
229     if (!declaration)
230         return D3DERR_INVALIDCALL;
231 
232     copy_declaration(declaration, mesh->cached_declaration, mesh->num_elem);
233 
234     return D3D_OK;
235 }
236 
237 static DWORD WINAPI d3dx9_mesh_GetNumBytesPerVertex(ID3DXMesh *iface)
238 {
239     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
240 
241     TRACE("iface %p.\n", iface);
242 
243     return mesh->vertex_declaration_size;
244 }
245 
246 static DWORD WINAPI d3dx9_mesh_GetOptions(ID3DXMesh *iface)
247 {
248     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
249 
250     TRACE("iface %p.\n", iface);
251 
252     return mesh->options;
253 }
254 
255 static HRESULT WINAPI d3dx9_mesh_GetDevice(struct ID3DXMesh *iface, struct IDirect3DDevice9 **device)
256 {
257     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
258 
259     TRACE("iface %p, device %p.\n", iface, device);
260 
261     if (!device)
262         return D3DERR_INVALIDCALL;
263     *device = mesh->device;
264     IDirect3DDevice9_AddRef(mesh->device);
265 
266     return D3D_OK;
267 }
268 
269 static HRESULT WINAPI d3dx9_mesh_CloneMeshFVF(struct ID3DXMesh *iface, DWORD options, DWORD fvf,
270         struct IDirect3DDevice9 *device, struct ID3DXMesh **clone_mesh)
271 {
272     HRESULT hr;
273     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
274 
275     TRACE("iface %p, options %#x, fvf %#x, device %p, clone_mesh %p.\n",
276             iface, options, fvf, device, clone_mesh);
277 
278     if (FAILED(hr = D3DXDeclaratorFromFVF(fvf, declaration)))
279         return hr;
280 
281     return iface->lpVtbl->CloneMesh(iface, options, declaration, device, clone_mesh);
282 }
283 
284 static FLOAT scale_clamp_ubyten(FLOAT value)
285 {
286     value = value * UCHAR_MAX;
287 
288     if (value < 0.0f)
289     {
290         return 0.0f;
291     }
292     else
293     {
294         if (value > UCHAR_MAX) /* Clamp at 255 */
295             return UCHAR_MAX;
296         else
297             return value;
298     }
299 }
300 
301 static FLOAT scale_clamp_shortn(FLOAT value)
302 {
303     value = value * SHRT_MAX;
304 
305     /* The tests show that the range is SHRT_MIN + 1 to SHRT_MAX. */
306     if (value <= SHRT_MIN)
307     {
308         return SHRT_MIN + 1;
309     }
310     else if (value > SHRT_MAX)
311     {
312          return SHRT_MAX;
313     }
314     else
315     {
316         return value;
317     }
318 }
319 
320 static FLOAT scale_clamp_ushortn(FLOAT value)
321 {
322     value = value * USHRT_MAX;
323 
324     if (value < 0.0f)
325     {
326         return 0.0f;
327     }
328     else
329     {
330         if (value > USHRT_MAX) /* Clamp at 65535 */
331             return USHRT_MAX;
332         else
333             return value;
334     }
335 }
336 
337 static INT simple_round(FLOAT value)
338 {
339     int res = (INT)(value + 0.5f);
340 
341     return res;
342 }
343 
344 static void convert_float4(BYTE *dst, const D3DXVECTOR4 *src, D3DDECLTYPE type_dst)
345 {
346     BOOL fixme_once = FALSE;
347 
348     switch (type_dst)
349     {
350         case D3DDECLTYPE_FLOAT1:
351         {
352             FLOAT *dst_ptr = (FLOAT*)dst;
353             *dst_ptr = src->x;
354             break;
355         }
356         case D3DDECLTYPE_FLOAT2:
357         {
358             D3DXVECTOR2 *dst_ptr = (D3DXVECTOR2*)dst;
359             dst_ptr->x = src->x;
360             dst_ptr->y = src->y;
361             break;
362         }
363         case D3DDECLTYPE_FLOAT3:
364         {
365             D3DXVECTOR3 *dst_ptr = (D3DXVECTOR3*)dst;
366             dst_ptr->x = src->x;
367             dst_ptr->y = src->y;
368             dst_ptr->z = src->z;
369             break;
370         }
371         case D3DDECLTYPE_FLOAT4:
372         {
373             D3DXVECTOR4 *dst_ptr = (D3DXVECTOR4*)dst;
374             dst_ptr->x = src->x;
375             dst_ptr->y = src->y;
376             dst_ptr->z = src->z;
377             dst_ptr->w = src->w;
378             break;
379         }
380         case D3DDECLTYPE_D3DCOLOR:
381         {
382             dst[0] = (BYTE)simple_round(scale_clamp_ubyten(src->z));
383             dst[1] = (BYTE)simple_round(scale_clamp_ubyten(src->y));
384             dst[2] = (BYTE)simple_round(scale_clamp_ubyten(src->x));
385             dst[3] = (BYTE)simple_round(scale_clamp_ubyten(src->w));
386             break;
387         }
388         case D3DDECLTYPE_UBYTE4:
389         {
390             dst[0] = src->x < 0.0f ? 0 : (BYTE)simple_round(src->x);
391             dst[1] = src->y < 0.0f ? 0 : (BYTE)simple_round(src->y);
392             dst[2] = src->z < 0.0f ? 0 : (BYTE)simple_round(src->z);
393             dst[3] = src->w < 0.0f ? 0 : (BYTE)simple_round(src->w);
394             break;
395         }
396         case D3DDECLTYPE_SHORT2:
397         {
398             SHORT *dst_ptr = (SHORT*)dst;
399             dst_ptr[0] = (SHORT)simple_round(src->x);
400             dst_ptr[1] = (SHORT)simple_round(src->y);
401             break;
402         }
403         case D3DDECLTYPE_SHORT4:
404         {
405             SHORT *dst_ptr = (SHORT*)dst;
406             dst_ptr[0] = (SHORT)simple_round(src->x);
407             dst_ptr[1] = (SHORT)simple_round(src->y);
408             dst_ptr[2] = (SHORT)simple_round(src->z);
409             dst_ptr[3] = (SHORT)simple_round(src->w);
410             break;
411         }
412         case D3DDECLTYPE_UBYTE4N:
413         {
414             dst[0] = (BYTE)simple_round(scale_clamp_ubyten(src->x));
415             dst[1] = (BYTE)simple_round(scale_clamp_ubyten(src->y));
416             dst[2] = (BYTE)simple_round(scale_clamp_ubyten(src->z));
417             dst[3] = (BYTE)simple_round(scale_clamp_ubyten(src->w));
418             break;
419         }
420         case D3DDECLTYPE_SHORT2N:
421         {
422             SHORT *dst_ptr = (SHORT*)dst;
423             dst_ptr[0] = (SHORT)simple_round(scale_clamp_shortn(src->x));
424             dst_ptr[1] = (SHORT)simple_round(scale_clamp_shortn(src->y));
425             break;
426         }
427         case D3DDECLTYPE_SHORT4N:
428         {
429             SHORT *dst_ptr = (SHORT*)dst;
430             dst_ptr[0] = (SHORT)simple_round(scale_clamp_shortn(src->x));
431             dst_ptr[1] = (SHORT)simple_round(scale_clamp_shortn(src->y));
432             dst_ptr[2] = (SHORT)simple_round(scale_clamp_shortn(src->z));
433             dst_ptr[3] = (SHORT)simple_round(scale_clamp_shortn(src->w));
434             break;
435         }
436         case D3DDECLTYPE_USHORT2N:
437         {
438             USHORT *dst_ptr = (USHORT*)dst;
439             dst_ptr[0] = (USHORT)simple_round(scale_clamp_ushortn(src->x));
440             dst_ptr[1] = (USHORT)simple_round(scale_clamp_ushortn(src->y));
441             break;
442         }
443         case D3DDECLTYPE_USHORT4N:
444         {
445             USHORT *dst_ptr = (USHORT*)dst;
446             dst_ptr[0] = (USHORT)simple_round(scale_clamp_ushortn(src->x));
447             dst_ptr[1] = (USHORT)simple_round(scale_clamp_ushortn(src->y));
448             dst_ptr[2] = (USHORT)simple_round(scale_clamp_ushortn(src->z));
449             dst_ptr[3] = (USHORT)simple_round(scale_clamp_ushortn(src->w));
450             break;
451         }
452         case D3DDECLTYPE_FLOAT16_2:
453         {
454             D3DXFloat32To16Array((D3DXFLOAT16*)dst, (FLOAT*)src, 2);
455             break;
456         }
457         case D3DDECLTYPE_FLOAT16_4:
458         {
459             D3DXFloat32To16Array((D3DXFLOAT16*)dst, (FLOAT*)src, 4);
460             break;
461         }
462         default:
463             if (!fixme_once++)
464                 FIXME("Conversion from D3DDECLTYPE_FLOAT4 to %d not implemented.\n", type_dst);
465             break;
466     }
467 }
468 
469 static void convert_component(BYTE *dst, BYTE *src, D3DDECLTYPE type_dst, D3DDECLTYPE type_src)
470 {
471     BOOL fixme_once = FALSE;
472 
473     switch (type_src)
474     {
475         case D3DDECLTYPE_FLOAT1:
476         {
477             FLOAT *src_ptr = (FLOAT*)src;
478             D3DXVECTOR4 src_float4 = {*src_ptr, 0.0f, 0.0f, 1.0f};
479             convert_float4(dst, &src_float4, type_dst);
480             break;
481         }
482         case D3DDECLTYPE_FLOAT2:
483         {
484             D3DXVECTOR2 *src_ptr = (D3DXVECTOR2*)src;
485             D3DXVECTOR4 src_float4 = {src_ptr->x, src_ptr->y, 0.0f, 1.0f};
486             convert_float4(dst, &src_float4, type_dst);
487             break;
488         }
489         case D3DDECLTYPE_FLOAT3:
490         {
491             D3DXVECTOR3 *src_ptr = (D3DXVECTOR3*)src;
492             D3DXVECTOR4 src_float4 = {src_ptr->x, src_ptr->y, src_ptr->z, 1.0f};
493             convert_float4(dst, &src_float4, type_dst);
494             break;
495         }
496         case D3DDECLTYPE_FLOAT4:
497         {
498             D3DXVECTOR4 *src_ptr = (D3DXVECTOR4*)src;
499             D3DXVECTOR4 src_float4 = {src_ptr->x, src_ptr->y, src_ptr->z, src_ptr->w};
500             convert_float4(dst, &src_float4, type_dst);
501             break;
502         }
503         case D3DDECLTYPE_D3DCOLOR:
504         {
505             D3DXVECTOR4 src_float4 =
506             {
507                 (FLOAT)src[2]/UCHAR_MAX,
508                 (FLOAT)src[1]/UCHAR_MAX,
509                 (FLOAT)src[0]/UCHAR_MAX,
510                 (FLOAT)src[3]/UCHAR_MAX
511             };
512             convert_float4(dst, &src_float4, type_dst);
513             break;
514         }
515         case D3DDECLTYPE_UBYTE4:
516         {
517             D3DXVECTOR4 src_float4 = {src[0], src[1], src[2], src[3]};
518             convert_float4(dst, &src_float4, type_dst);
519             break;
520         }
521         case D3DDECLTYPE_SHORT2:
522         {
523             SHORT *src_ptr = (SHORT*)src;
524             D3DXVECTOR4 src_float4 = {src_ptr[0], src_ptr[1], 0.0f, 1.0f};
525             convert_float4(dst, &src_float4, type_dst);
526             break;
527         }
528         case D3DDECLTYPE_SHORT4:
529         {
530             SHORT *src_ptr = (SHORT*)src;
531             D3DXVECTOR4 src_float4 = {src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3]};
532             convert_float4(dst, &src_float4, type_dst);
533             break;
534         }
535         case D3DDECLTYPE_UBYTE4N:
536         {
537             D3DXVECTOR4 src_float4 =
538             {
539                 (FLOAT)src[0]/UCHAR_MAX,
540                 (FLOAT)src[1]/UCHAR_MAX,
541                 (FLOAT)src[2]/UCHAR_MAX,
542                 (FLOAT)src[3]/UCHAR_MAX
543             };
544             convert_float4(dst, &src_float4, type_dst);
545             break;
546         }
547         case D3DDECLTYPE_SHORT2N:
548         {
549             SHORT *src_ptr = (SHORT*)src;
550             D3DXVECTOR4 src_float4 = {(FLOAT)src_ptr[0]/SHRT_MAX, (FLOAT)src_ptr[1]/SHRT_MAX, 0.0f, 1.0f};
551             convert_float4(dst, &src_float4, type_dst);
552             break;
553         }
554         case D3DDECLTYPE_SHORT4N:
555         {
556             SHORT *src_ptr = (SHORT*)src;
557             D3DXVECTOR4 src_float4 =
558             {
559                 (FLOAT)src_ptr[0]/SHRT_MAX,
560                 (FLOAT)src_ptr[1]/SHRT_MAX,
561                 (FLOAT)src_ptr[2]/SHRT_MAX,
562                 (FLOAT)src_ptr[3]/SHRT_MAX
563             };
564             convert_float4(dst, &src_float4, type_dst);
565             break;
566         }
567         case D3DDECLTYPE_FLOAT16_2:
568         {
569             D3DXVECTOR4 src_float4 = {0.0f, 0.0f, 0.0f, 1.0f};
570             D3DXFloat16To32Array((FLOAT*)&src_float4, (D3DXFLOAT16*)src, 2);
571             convert_float4(dst, &src_float4, type_dst);
572             break;
573         }
574         case D3DDECLTYPE_FLOAT16_4:
575         {
576             D3DXVECTOR4 src_float4;
577             D3DXFloat16To32Array((FLOAT*)&src_float4, (D3DXFLOAT16*)src, 4);
578             convert_float4(dst, &src_float4, type_dst);
579             break;
580         }
581         default:
582             if (!fixme_once++)
583                 FIXME("Conversion of D3DDECLTYPE %d to %d not implemented.\n", type_src, type_dst);
584             break;
585     }
586 }
587 
588 static INT get_equivalent_declaration_index(D3DVERTEXELEMENT9 orig_declaration, D3DVERTEXELEMENT9 *declaration)
589 {
590     INT i;
591 
592     for (i = 0; declaration[i].Stream != 0xff; i++)
593     {
594         if (orig_declaration.Usage == declaration[i].Usage
595             && orig_declaration.UsageIndex == declaration[i].UsageIndex)
596         {
597             return i;
598         }
599     }
600 
601     return -1;
602 }
603 
604 static HRESULT convert_vertex_buffer(ID3DXMesh *mesh_dst, ID3DXMesh *mesh_src)
605 {
606     HRESULT hr;
607     D3DVERTEXELEMENT9 orig_declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
608     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
609     BYTE *vb_dst = NULL;
610     BYTE *vb_src = NULL;
611     UINT i;
612     UINT num_vertices = mesh_src->lpVtbl->GetNumVertices(mesh_src);
613     UINT dst_vertex_size = mesh_dst->lpVtbl->GetNumBytesPerVertex(mesh_dst);
614     UINT src_vertex_size = mesh_src->lpVtbl->GetNumBytesPerVertex(mesh_src);
615 
616     hr = mesh_src->lpVtbl->GetDeclaration(mesh_src, orig_declaration);
617     if (FAILED(hr)) return hr;
618     hr = mesh_dst->lpVtbl->GetDeclaration(mesh_dst, declaration);
619     if (FAILED(hr)) return hr;
620 
621     hr = mesh_src->lpVtbl->LockVertexBuffer(mesh_src, D3DLOCK_READONLY, (void**)&vb_src);
622     if (FAILED(hr)) goto cleanup;
623     hr = mesh_dst->lpVtbl->LockVertexBuffer(mesh_dst, 0, (void**)&vb_dst);
624     if (FAILED(hr)) goto cleanup;
625 
626     /* Clear all new fields by clearing the entire vertex buffer. */
627     memset(vb_dst, 0, num_vertices * dst_vertex_size);
628 
629     for (i = 0; orig_declaration[i].Stream != 0xff; i++)
630     {
631         INT eq_idx = get_equivalent_declaration_index(orig_declaration[i], declaration);
632 
633         if (eq_idx >= 0)
634         {
635             UINT j;
636             for (j = 0; j < num_vertices; j++)
637             {
638                 UINT idx_dst = dst_vertex_size * j + declaration[eq_idx].Offset;
639                 UINT idx_src = src_vertex_size * j + orig_declaration[i].Offset;
640                 UINT type_size = d3dx_decltype_size[orig_declaration[i].Type];
641 
642                 if (orig_declaration[i].Type == declaration[eq_idx].Type)
643                     memcpy(&vb_dst[idx_dst], &vb_src[idx_src], type_size);
644                 else
645                    convert_component(&vb_dst[idx_dst], &vb_src[idx_src], declaration[eq_idx].Type, orig_declaration[i].Type);
646             }
647         }
648     }
649 
650     hr = D3D_OK;
651 cleanup:
652     if (vb_dst) mesh_dst->lpVtbl->UnlockVertexBuffer(mesh_dst);
653     if (vb_src) mesh_src->lpVtbl->UnlockVertexBuffer(mesh_src);
654 
655     return hr;
656 }
657 
658 static BOOL declaration_equals(const D3DVERTEXELEMENT9 *declaration1, const D3DVERTEXELEMENT9 *declaration2)
659 {
660     UINT size1 = 0, size2 = 0;
661 
662     /* Find the size of each declaration */
663     while (declaration1[size1].Stream != 0xff) size1++;
664     while (declaration2[size2].Stream != 0xff) size2++;
665 
666     /* If not same size then they are definitely not equal */
667     if (size1 != size2)
668         return FALSE;
669 
670     /* Check that all components are the same */
671     if (memcmp(declaration1, declaration2, size1*sizeof(*declaration1)) == 0)
672         return TRUE;
673 
674     return FALSE;
675 }
676 
677 static HRESULT WINAPI d3dx9_mesh_CloneMesh(struct ID3DXMesh *iface, DWORD options,
678         const D3DVERTEXELEMENT9 *declaration, struct IDirect3DDevice9 *device, struct ID3DXMesh **clone_mesh_out)
679 {
680     struct d3dx9_mesh *This = impl_from_ID3DXMesh(iface);
681     struct d3dx9_mesh *cloned_this;
682     ID3DXMesh *clone_mesh;
683     D3DVERTEXELEMENT9 orig_declaration[MAX_FVF_DECL_SIZE] = { D3DDECL_END() };
684     void *data_in, *data_out;
685     DWORD vertex_size;
686     HRESULT hr;
687     BOOL same_declaration;
688 
689     TRACE("iface %p, options %#x, declaration %p, device %p, clone_mesh_out %p.\n",
690             iface, options, declaration, device, clone_mesh_out);
691 
692     if (!clone_mesh_out)
693         return D3DERR_INVALIDCALL;
694 
695     hr = iface->lpVtbl->GetDeclaration(iface, orig_declaration);
696     if (FAILED(hr)) return hr;
697 
698     hr = D3DXCreateMesh(This->numfaces, This->numvertices, options & ~D3DXMESH_VB_SHARE,
699                         declaration, device, &clone_mesh);
700     if (FAILED(hr)) return hr;
701 
702     cloned_this = impl_from_ID3DXMesh(clone_mesh);
703     vertex_size = clone_mesh->lpVtbl->GetNumBytesPerVertex(clone_mesh);
704     same_declaration = declaration_equals(declaration, orig_declaration);
705 
706     if (options & D3DXMESH_VB_SHARE) {
707         if (!same_declaration) {
708             hr = D3DERR_INVALIDCALL;
709             goto error;
710         }
711         IDirect3DVertexBuffer9_AddRef(This->vertex_buffer);
712         /* FIXME: refactor to avoid creating a new vertex buffer */
713         IDirect3DVertexBuffer9_Release(cloned_this->vertex_buffer);
714         cloned_this->vertex_buffer = This->vertex_buffer;
715     } else if (same_declaration) {
716         hr = iface->lpVtbl->LockVertexBuffer(iface, D3DLOCK_READONLY, &data_in);
717         if (FAILED(hr)) goto error;
718         hr = clone_mesh->lpVtbl->LockVertexBuffer(clone_mesh, 0, &data_out);
719         if (FAILED(hr)) {
720             iface->lpVtbl->UnlockVertexBuffer(iface);
721             goto error;
722         }
723         memcpy(data_out, data_in, This->numvertices * vertex_size);
724         clone_mesh->lpVtbl->UnlockVertexBuffer(clone_mesh);
725         iface->lpVtbl->UnlockVertexBuffer(iface);
726     } else {
727         hr = convert_vertex_buffer(clone_mesh, iface);
728         if (FAILED(hr)) goto error;
729     }
730 
731     hr = iface->lpVtbl->LockIndexBuffer(iface, D3DLOCK_READONLY, &data_in);
732     if (FAILED(hr)) goto error;
733     hr = clone_mesh->lpVtbl->LockIndexBuffer(clone_mesh, 0, &data_out);
734     if (FAILED(hr)) {
735         iface->lpVtbl->UnlockIndexBuffer(iface);
736         goto error;
737     }
738     if ((options ^ This->options) & D3DXMESH_32BIT) {
739         DWORD i;
740         if (options & D3DXMESH_32BIT) {
741             for (i = 0; i < This->numfaces * 3; i++)
742                 ((DWORD*)data_out)[i] = ((WORD*)data_in)[i];
743         } else {
744             for (i = 0; i < This->numfaces * 3; i++)
745                 ((WORD*)data_out)[i] = ((DWORD*)data_in)[i];
746         }
747     } else {
748         memcpy(data_out, data_in, This->numfaces * 3 * (options & D3DXMESH_32BIT ? 4 : 2));
749     }
750     clone_mesh->lpVtbl->UnlockIndexBuffer(clone_mesh);
751     iface->lpVtbl->UnlockIndexBuffer(iface);
752 
753     memcpy(cloned_this->attrib_buffer, This->attrib_buffer, This->numfaces * sizeof(*This->attrib_buffer));
754 
755     if (This->attrib_table_size)
756     {
757         cloned_this->attrib_table_size = This->attrib_table_size;
758         cloned_this->attrib_table = HeapAlloc(GetProcessHeap(), 0, This->attrib_table_size * sizeof(*This->attrib_table));
759         if (!cloned_this->attrib_table) {
760             hr = E_OUTOFMEMORY;
761             goto error;
762         }
763         memcpy(cloned_this->attrib_table, This->attrib_table, This->attrib_table_size * sizeof(*This->attrib_table));
764     }
765 
766     *clone_mesh_out = clone_mesh;
767 
768     return D3D_OK;
769 error:
770     IUnknown_Release(clone_mesh);
771     return hr;
772 }
773 
774 static HRESULT WINAPI d3dx9_mesh_GetVertexBuffer(struct ID3DXMesh *iface,
775         struct IDirect3DVertexBuffer9 **vertex_buffer)
776 {
777     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
778 
779     TRACE("iface %p, vertex_buffer %p.\n", iface, vertex_buffer);
780 
781     if (!vertex_buffer)
782         return D3DERR_INVALIDCALL;
783     *vertex_buffer = mesh->vertex_buffer;
784     IDirect3DVertexBuffer9_AddRef(mesh->vertex_buffer);
785 
786     return D3D_OK;
787 }
788 
789 static HRESULT WINAPI d3dx9_mesh_GetIndexBuffer(struct ID3DXMesh *iface,
790         struct IDirect3DIndexBuffer9 **index_buffer)
791 {
792     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
793 
794     TRACE("iface %p, index_buffer %p.\n", iface, index_buffer);
795 
796     if (!index_buffer)
797         return D3DERR_INVALIDCALL;
798     *index_buffer = mesh->index_buffer;
799     IDirect3DIndexBuffer9_AddRef(mesh->index_buffer);
800 
801     return D3D_OK;
802 }
803 
804 static HRESULT WINAPI d3dx9_mesh_LockVertexBuffer(ID3DXMesh *iface, DWORD flags, void **data)
805 {
806     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
807 
808     TRACE("iface %p, flags %#x, data %p.\n", iface, flags, data);
809 
810     return IDirect3DVertexBuffer9_Lock(mesh->vertex_buffer, 0, 0, data, flags);
811 }
812 
813 static HRESULT WINAPI d3dx9_mesh_UnlockVertexBuffer(ID3DXMesh *iface)
814 {
815     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
816 
817     TRACE("iface %p.\n", iface);
818 
819     return IDirect3DVertexBuffer9_Unlock(mesh->vertex_buffer);
820 }
821 
822 static HRESULT WINAPI d3dx9_mesh_LockIndexBuffer(ID3DXMesh *iface, DWORD flags, void **data)
823 {
824     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
825 
826     TRACE("iface %p, flags %#x, data %p.\n", iface, flags, data);
827 
828     return IDirect3DIndexBuffer9_Lock(mesh->index_buffer, 0, 0, data, flags);
829 }
830 
831 static HRESULT WINAPI d3dx9_mesh_UnlockIndexBuffer(ID3DXMesh *iface)
832 {
833     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
834 
835     TRACE("iface %p.\n", iface);
836 
837     return IDirect3DIndexBuffer9_Unlock(mesh->index_buffer);
838 }
839 
840 /* FIXME: This looks just wrong, we never check *attrib_table_size before
841  * copying the data. */
842 static HRESULT WINAPI d3dx9_mesh_GetAttributeTable(ID3DXMesh *iface,
843         D3DXATTRIBUTERANGE *attrib_table, DWORD *attrib_table_size)
844 {
845     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
846 
847     TRACE("iface %p, attrib_table %p, attrib_table_size %p.\n",
848             iface, attrib_table, attrib_table_size);
849 
850     if (attrib_table_size)
851         *attrib_table_size = mesh->attrib_table_size;
852 
853     if (attrib_table)
854         memcpy(attrib_table, mesh->attrib_table, mesh->attrib_table_size * sizeof(*attrib_table));
855 
856     return D3D_OK;
857 }
858 
859 struct edge_face
860 {
861     struct list entry;
862     DWORD v2;
863     DWORD face;
864 };
865 
866 struct edge_face_map
867 {
868     struct list *lists;
869     struct edge_face *entries;
870 };
871 
872 /* Builds up a map of which face a new edge belongs to. That way the adjacency
873  * of another edge can be looked up. An edge has an adjacent face if there
874  * is an edge going in the opposite direction in the map. For example if the
875  * edge (v1, v2) belongs to face 4, and there is a mapping (v2, v1)->7, then
876  * face 4 and 7 are adjacent.
877  *
878  * Each edge might have been replaced with another edge, or none at all. There
879  * is at most one edge to face mapping, i.e. an edge can only belong to one
880  * face.
881  */
882 static HRESULT init_edge_face_map(struct edge_face_map *edge_face_map, const DWORD *index_buffer,
883         const DWORD *point_reps, DWORD num_faces)
884 {
885     DWORD face, edge;
886     DWORD i;
887 
888     edge_face_map->lists = HeapAlloc(GetProcessHeap(), 0, 3 * num_faces * sizeof(*edge_face_map->lists));
889     if (!edge_face_map->lists) return E_OUTOFMEMORY;
890 
891     edge_face_map->entries = HeapAlloc(GetProcessHeap(), 0, 3 * num_faces * sizeof(*edge_face_map->entries));
892     if (!edge_face_map->entries) return E_OUTOFMEMORY;
893 
894 
895     /* Initialize all lists */
896     for (i = 0; i < 3 * num_faces; i++)
897     {
898         list_init(&edge_face_map->lists[i]);
899     }
900     /* Build edge face mapping */
901     for (face = 0; face < num_faces; face++)
902     {
903         for (edge = 0; edge < 3; edge++)
904         {
905             DWORD v1 = index_buffer[3*face + edge];
906             DWORD v2 = index_buffer[3*face + (edge+1)%3];
907             DWORD new_v1 = point_reps[v1]; /* What v1 has been replaced with */
908             DWORD new_v2 = point_reps[v2];
909 
910             if (v1 != v2) /* Only map non-collapsed edges */
911             {
912                 i = 3*face + edge;
913                 edge_face_map->entries[i].v2 = new_v2;
914                 edge_face_map->entries[i].face = face;
915                 list_add_head(&edge_face_map->lists[new_v1], &edge_face_map->entries[i].entry);
916             }
917         }
918     }
919 
920     return D3D_OK;
921 }
922 
923 static DWORD find_adjacent_face(struct edge_face_map *edge_face_map, DWORD vertex1, DWORD vertex2, DWORD num_faces)
924 {
925     struct edge_face *edge_face_ptr;
926 
927     LIST_FOR_EACH_ENTRY(edge_face_ptr, &edge_face_map->lists[vertex2], struct edge_face, entry)
928     {
929         if (edge_face_ptr->v2 == vertex1)
930             return edge_face_ptr->face;
931     }
932 
933     return -1;
934 }
935 
936 static DWORD *generate_identity_point_reps(DWORD num_vertices)
937 {
938         DWORD *id_point_reps;
939         DWORD i;
940 
941         id_point_reps = HeapAlloc(GetProcessHeap(), 0, num_vertices * sizeof(*id_point_reps));
942         if (!id_point_reps)
943             return NULL;
944 
945         for (i = 0; i < num_vertices; i++)
946         {
947             id_point_reps[i] = i;
948         }
949 
950         return id_point_reps;
951 }
952 
953 static HRESULT WINAPI d3dx9_mesh_ConvertPointRepsToAdjacency(ID3DXMesh *iface,
954         const DWORD *point_reps, DWORD *adjacency)
955 {
956     HRESULT hr;
957     DWORD num_faces = iface->lpVtbl->GetNumFaces(iface);
958     DWORD num_vertices = iface->lpVtbl->GetNumVertices(iface);
959     DWORD options = iface->lpVtbl->GetOptions(iface);
960     BOOL indices_are_16_bit = !(options & D3DXMESH_32BIT);
961     DWORD *ib = NULL;
962     void *ib_ptr = NULL;
963     DWORD face;
964     DWORD edge;
965     struct edge_face_map edge_face_map = {0};
966     const DWORD *point_reps_ptr = NULL;
967     DWORD *id_point_reps = NULL;
968 
969     TRACE("iface %p, point_reps %p, adjacency %p.\n", iface, point_reps, adjacency);
970 
971     if (!adjacency) return D3DERR_INVALIDCALL;
972 
973     if (!point_reps) /* Identity point reps */
974     {
975         id_point_reps = generate_identity_point_reps(num_vertices);
976         if (!id_point_reps)
977         {
978             hr = E_OUTOFMEMORY;
979             goto cleanup;
980         }
981 
982         point_reps_ptr = id_point_reps;
983     }
984     else
985     {
986         point_reps_ptr = point_reps;
987     }
988 
989     hr = iface->lpVtbl->LockIndexBuffer(iface, D3DLOCK_READONLY, &ib_ptr);
990     if (FAILED(hr)) goto cleanup;
991 
992     if (indices_are_16_bit)
993     {
994         /* Widen 16 bit to 32 bit */
995         DWORD i;
996         WORD *ib_16bit = ib_ptr;
997         ib = HeapAlloc(GetProcessHeap(), 0, 3 * num_faces * sizeof(DWORD));
998         if (!ib)
999         {
1000             hr = E_OUTOFMEMORY;
1001             goto cleanup;
1002         }
1003         for (i = 0; i < 3 * num_faces; i++)
1004         {
1005             ib[i] = ib_16bit[i];
1006         }
1007     }
1008     else
1009     {
1010         ib = ib_ptr;
1011     }
1012 
1013     hr = init_edge_face_map(&edge_face_map, ib, point_reps_ptr, num_faces);
1014     if (FAILED(hr)) goto cleanup;
1015 
1016     /* Create adjacency */
1017     for (face = 0; face < num_faces; face++)
1018     {
1019         for (edge = 0; edge < 3; edge++)
1020         {
1021             DWORD v1 = ib[3*face + edge];
1022             DWORD v2 = ib[3*face + (edge+1)%3];
1023             DWORD new_v1 = point_reps_ptr[v1];
1024             DWORD new_v2 = point_reps_ptr[v2];
1025             DWORD adj_face;
1026 
1027             adj_face = find_adjacent_face(&edge_face_map, new_v1, new_v2, num_faces);
1028             adjacency[3*face + edge] = adj_face;
1029         }
1030     }
1031 
1032     hr = D3D_OK;
1033 cleanup:
1034     HeapFree(GetProcessHeap(), 0, id_point_reps);
1035     if (indices_are_16_bit) HeapFree(GetProcessHeap(), 0, ib);
1036     HeapFree(GetProcessHeap(), 0, edge_face_map.lists);
1037     HeapFree(GetProcessHeap(), 0, edge_face_map.entries);
1038     if(ib_ptr) iface->lpVtbl->UnlockIndexBuffer(iface);
1039     return hr;
1040 }
1041 
1042 /* ConvertAdjacencyToPointReps helper function.
1043  *
1044  * Goes around the edges of each face and replaces the vertices in any adjacent
1045  * face's edge with its own vertices(if its vertices have a lower index). This
1046  * way as few as possible low index vertices are shared among the faces. The
1047  * re-ordered index buffer is stored in new_indices.
1048  *
1049  * The vertices in a point representation must be ordered sequentially, e.g.
1050  * index 5 holds the index of the vertex that replaces vertex 5, i.e. if
1051  * vertex 5 is replaced by vertex 3 then index 5 would contain 3. If no vertex
1052  * replaces it, then it contains the same number as the index itself, e.g.
1053  * index 5 would contain 5. */
1054 static HRESULT propagate_face_vertices(const DWORD *adjacency, DWORD *point_reps,
1055         const DWORD *indices, DWORD *new_indices, DWORD face, DWORD numfaces)
1056 {
1057     const unsigned int VERTS_PER_FACE = 3;
1058     DWORD edge, opp_edge;
1059     DWORD face_base = VERTS_PER_FACE * face;
1060 
1061     for (edge = 0; edge < VERTS_PER_FACE; edge++)
1062     {
1063         DWORD adj_face = adjacency[face_base + edge];
1064         DWORD adj_face_base;
1065         DWORD i;
1066         if (adj_face == -1) /* No adjacent face. */
1067             continue;
1068         else if (adj_face >= numfaces)
1069         {
1070             /* This throws exception on Windows */
1071             WARN("Index out of bounds. Got %d expected less than %d.\n",
1072                 adj_face, numfaces);
1073             return D3DERR_INVALIDCALL;
1074         }
1075         adj_face_base = 3 * adj_face;
1076 
1077         /* Find opposite edge in adjacent face. */
1078         for (opp_edge = 0; opp_edge < VERTS_PER_FACE; opp_edge++)
1079         {
1080             DWORD opp_edge_index = adj_face_base + opp_edge;
1081             if (adjacency[opp_edge_index] == face)
1082                 break; /* Found opposite edge. */
1083         }
1084 
1085         /* Replaces vertices in opposite edge with vertices from current edge. */
1086         for (i = 0; i < 2; i++)
1087         {
1088             DWORD from = face_base + (edge + (1 - i)) % VERTS_PER_FACE;
1089             DWORD to = adj_face_base + (opp_edge + i) % VERTS_PER_FACE;
1090 
1091             /* Propagate lowest index. */
1092             if (new_indices[to] > new_indices[from])
1093             {
1094                 new_indices[to] = new_indices[from];
1095                 point_reps[indices[to]] = new_indices[from];
1096             }
1097         }
1098     }
1099 
1100     return D3D_OK;
1101 }
1102 
1103 static HRESULT WINAPI d3dx9_mesh_ConvertAdjacencyToPointReps(ID3DXMesh *iface,
1104         const DWORD *adjacency, DWORD *point_reps)
1105 {
1106     struct d3dx9_mesh *This = impl_from_ID3DXMesh(iface);
1107     HRESULT hr;
1108     DWORD face;
1109     DWORD i;
1110     DWORD *indices = NULL;
1111     WORD *indices_16bit = NULL;
1112     DWORD *new_indices = NULL;
1113     const unsigned int VERTS_PER_FACE = 3;
1114 
1115     TRACE("iface %p, adjacency %p, point_reps %p.\n", iface, adjacency, point_reps);
1116 
1117     if (!adjacency)
1118     {
1119         WARN("NULL adjacency.\n");
1120         hr = D3DERR_INVALIDCALL;
1121         goto cleanup;
1122     }
1123 
1124     if (!point_reps)
1125     {
1126         WARN("NULL point_reps.\n");
1127         hr = D3DERR_INVALIDCALL;
1128         goto cleanup;
1129     }
1130 
1131     /* Should never happen as CreateMesh does not allow meshes with 0 faces */
1132     if (This->numfaces == 0)
1133     {
1134         ERR("Number of faces was zero.\n");
1135         hr = D3DERR_INVALIDCALL;
1136         goto cleanup;
1137     }
1138 
1139     new_indices = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * This->numfaces * sizeof(*indices));
1140     if (!new_indices)
1141     {
1142         hr = E_OUTOFMEMORY;
1143         goto cleanup;
1144     }
1145 
1146     if (This->options & D3DXMESH_32BIT)
1147     {
1148         hr = iface->lpVtbl->LockIndexBuffer(iface, D3DLOCK_READONLY, (void**)&indices);
1149         if (FAILED(hr)) goto cleanup;
1150         memcpy(new_indices, indices, VERTS_PER_FACE * This->numfaces * sizeof(*indices));
1151     }
1152     else
1153     {
1154         /* Make a widening copy of indices_16bit into indices and new_indices
1155          * in order to re-use the helper function */
1156         hr = iface->lpVtbl->LockIndexBuffer(iface, D3DLOCK_READONLY, (void**)&indices_16bit);
1157         if (FAILED(hr)) goto cleanup;
1158         indices = HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE * This->numfaces * sizeof(*indices));
1159         if (!indices)
1160         {
1161             hr = E_OUTOFMEMORY;
1162             goto cleanup;
1163         }
1164         for (i = 0; i < VERTS_PER_FACE * This->numfaces; i++)
1165         {
1166             new_indices[i] = indices_16bit[i];
1167             indices[i] = indices_16bit[i];
1168         }
1169     }
1170 
1171     /* Vertices are ordered sequentially in the point representation. */
1172     for (i = 0; i < This->numvertices; i++)
1173     {
1174         point_reps[i] = i;
1175     }
1176 
1177     /* Propagate vertices with low indices so as few vertices as possible
1178      * are used in the mesh.
1179      */
1180     for (face = 0; face < This->numfaces; face++)
1181     {
1182         hr = propagate_face_vertices(adjacency, point_reps, indices, new_indices, face, This->numfaces);
1183         if (FAILED(hr)) goto cleanup;
1184     }
1185     /* Go in opposite direction to catch all face orderings */
1186     for (face = 0; face < This->numfaces; face++)
1187     {
1188         hr = propagate_face_vertices(adjacency, point_reps,
1189                                      indices, new_indices,
1190                                      (This->numfaces - 1) - face, This->numfaces);
1191         if (FAILED(hr)) goto cleanup;
1192     }
1193 
1194     hr = D3D_OK;
1195 cleanup:
1196     if (This->options & D3DXMESH_32BIT)
1197     {
1198         if (indices) iface->lpVtbl->UnlockIndexBuffer(iface);
1199     }
1200     else
1201     {
1202         if (indices_16bit) iface->lpVtbl->UnlockIndexBuffer(iface);
1203         HeapFree(GetProcessHeap(), 0, indices);
1204     }
1205     HeapFree(GetProcessHeap(), 0, new_indices);
1206     return hr;
1207 }
1208 
1209 struct vertex_metadata {
1210   float key;
1211   DWORD vertex_index;
1212   DWORD first_shared_index;
1213 };
1214 
1215 static int compare_vertex_keys(const void *a, const void *b)
1216 {
1217     const struct vertex_metadata *left = a;
1218     const struct vertex_metadata *right = b;
1219     if (left->key == right->key)
1220         return 0;
1221     return left->key < right->key ? -1 : 1;
1222 }
1223 
1224 static HRESULT WINAPI d3dx9_mesh_GenerateAdjacency(ID3DXMesh *iface, float epsilon, DWORD *adjacency)
1225 {
1226     struct d3dx9_mesh *This = impl_from_ID3DXMesh(iface);
1227     HRESULT hr;
1228     BYTE *vertices = NULL;
1229     const DWORD *indices = NULL;
1230     DWORD vertex_size;
1231     DWORD buffer_size;
1232     /* sort the vertices by (x + y + z) to quickly find coincident vertices */
1233     struct vertex_metadata *sorted_vertices;
1234     /* shared_indices links together identical indices in the index buffer so
1235      * that adjacency checks can be limited to faces sharing a vertex */
1236     DWORD *shared_indices = NULL;
1237     const FLOAT epsilon_sq = epsilon * epsilon;
1238     DWORD i;
1239 
1240     TRACE("iface %p, epsilon %.8e, adjacency %p.\n", iface, epsilon, adjacency);
1241 
1242     if (!adjacency)
1243         return D3DERR_INVALIDCALL;
1244 
1245     buffer_size = This->numfaces * 3 * sizeof(*shared_indices) + This->numvertices * sizeof(*sorted_vertices);
1246     if (!(This->options & D3DXMESH_32BIT))
1247         buffer_size += This->numfaces * 3 * sizeof(*indices);
1248     shared_indices = HeapAlloc(GetProcessHeap(), 0, buffer_size);
1249     if (!shared_indices)
1250         return E_OUTOFMEMORY;
1251     sorted_vertices = (struct vertex_metadata*)(shared_indices + This->numfaces * 3);
1252 
1253     hr = iface->lpVtbl->LockVertexBuffer(iface, D3DLOCK_READONLY, (void**)&vertices);
1254     if (FAILED(hr)) goto cleanup;
1255     hr = iface->lpVtbl->LockIndexBuffer(iface, D3DLOCK_READONLY, (void**)&indices);
1256     if (FAILED(hr)) goto cleanup;
1257 
1258     if (!(This->options & D3DXMESH_32BIT)) {
1259         const WORD *word_indices = (const WORD*)indices;
1260         DWORD *dword_indices = (DWORD*)(sorted_vertices + This->numvertices);
1261         indices = dword_indices;
1262         for (i = 0; i < This->numfaces * 3; i++)
1263             *dword_indices++ = *word_indices++;
1264     }
1265 
1266     vertex_size = iface->lpVtbl->GetNumBytesPerVertex(iface);
1267     for (i = 0; i < This->numvertices; i++) {
1268         D3DXVECTOR3 *vertex = (D3DXVECTOR3*)(vertices + vertex_size * i);
1269         sorted_vertices[i].first_shared_index = -1;
1270         sorted_vertices[i].key = vertex->x + vertex->y + vertex->z;
1271         sorted_vertices[i].vertex_index = i;
1272     }
1273     for (i = 0; i < This->numfaces * 3; i++) {
1274         DWORD *first_shared_index = &sorted_vertices[indices[i]].first_shared_index;
1275         shared_indices[i] = *first_shared_index;
1276         *first_shared_index = i;
1277         adjacency[i] = -1;
1278     }
1279     qsort(sorted_vertices, This->numvertices, sizeof(*sorted_vertices), compare_vertex_keys);
1280 
1281     for (i = 0; i < This->numvertices; i++) {
1282         struct vertex_metadata *sorted_vertex_a = &sorted_vertices[i];
1283         D3DXVECTOR3 *vertex_a = (D3DXVECTOR3*)(vertices + sorted_vertex_a->vertex_index * vertex_size);
1284         DWORD shared_index_a = sorted_vertex_a->first_shared_index;
1285 
1286         while (shared_index_a != -1) {
1287             DWORD j = i;
1288             DWORD shared_index_b = shared_indices[shared_index_a];
1289             struct vertex_metadata *sorted_vertex_b = sorted_vertex_a;
1290 
1291             while (TRUE) {
1292                 while (shared_index_b != -1) {
1293                     /* faces are adjacent if they have another coincident vertex */
1294                     DWORD base_a = (shared_index_a / 3) * 3;
1295                     DWORD base_b = (shared_index_b / 3) * 3;
1296                     BOOL adjacent = FALSE;
1297                     int k;
1298 
1299                     for (k = 0; k < 3; k++) {
1300                         if (adjacency[base_b + k] == shared_index_a / 3) {
1301                             adjacent = TRUE;
1302                             break;
1303                         }
1304                     }
1305                     if (!adjacent) {
1306                         for (k = 1; k <= 2; k++) {
1307                             DWORD vertex_index_a = base_a + (shared_index_a + k) % 3;
1308                             DWORD vertex_index_b = base_b + (shared_index_b + (3 - k)) % 3;
1309                             adjacent = indices[vertex_index_a] == indices[vertex_index_b];
1310                             if (!adjacent && epsilon >= 0.0f) {
1311                                 D3DXVECTOR3 delta = {0.0f, 0.0f, 0.0f};
1312                                 FLOAT length_sq;
1313 
1314                                 D3DXVec3Subtract(&delta,
1315                                                  (D3DXVECTOR3*)(vertices + indices[vertex_index_a] * vertex_size),
1316                                                  (D3DXVECTOR3*)(vertices + indices[vertex_index_b] * vertex_size));
1317                                 length_sq = D3DXVec3LengthSq(&delta);
1318                                 adjacent = epsilon == 0.0f ? length_sq == 0.0f : length_sq < epsilon_sq;
1319                             }
1320                             if (adjacent) {
1321                                 DWORD adj_a = base_a + 2 - (vertex_index_a + shared_index_a + 1) % 3;
1322                                 DWORD adj_b = base_b + 2 - (vertex_index_b + shared_index_b + 1) % 3;
1323                                 if (adjacency[adj_a] == -1 && adjacency[adj_b] == -1) {
1324                                     adjacency[adj_a] = base_b / 3;
1325                                     adjacency[adj_b] = base_a / 3;
1326                                     break;
1327                                 }
1328                             }
1329                         }
1330                     }
1331 
1332                     shared_index_b = shared_indices[shared_index_b];
1333                 }
1334                 while (++j < This->numvertices) {
1335                     D3DXVECTOR3 *vertex_b;
1336 
1337                     sorted_vertex_b++;
1338                     if (sorted_vertex_b->key - sorted_vertex_a->key > epsilon * 3.0f) {
1339                         /* no more coincident vertices to try */
1340                         j = This->numvertices;
1341                         break;
1342                     }
1343                     /* check for coincidence */
1344                     vertex_b = (D3DXVECTOR3*)(vertices + sorted_vertex_b->vertex_index * vertex_size);
1345                     if (fabsf(vertex_a->x - vertex_b->x) <= epsilon &&
1346                         fabsf(vertex_a->y - vertex_b->y) <= epsilon &&
1347                         fabsf(vertex_a->z - vertex_b->z) <= epsilon)
1348                     {
1349                         break;
1350                     }
1351                 }
1352                 if (j >= This->numvertices)
1353                     break;
1354                 shared_index_b = sorted_vertex_b->first_shared_index;
1355             }
1356 
1357             sorted_vertex_a->first_shared_index = shared_indices[sorted_vertex_a->first_shared_index];
1358             shared_index_a = sorted_vertex_a->first_shared_index;
1359         }
1360     }
1361 
1362     hr = D3D_OK;
1363 cleanup:
1364     if (indices) iface->lpVtbl->UnlockIndexBuffer(iface);
1365     if (vertices) iface->lpVtbl->UnlockVertexBuffer(iface);
1366     HeapFree(GetProcessHeap(), 0, shared_indices);
1367     return hr;
1368 }
1369 
1370 static HRESULT WINAPI d3dx9_mesh_UpdateSemantics(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
1371 {
1372     struct d3dx9_mesh *This = impl_from_ID3DXMesh(iface);
1373     HRESULT hr;
1374     UINT vertex_declaration_size;
1375     int i;
1376 
1377     TRACE("iface %p, declaration %p.\n", iface, declaration);
1378 
1379     if (!declaration)
1380     {
1381         WARN("Invalid declaration. Can't use NULL declaration.\n");
1382         return D3DERR_INVALIDCALL;
1383     }
1384 
1385     /* New declaration must be same size as original */
1386     vertex_declaration_size = D3DXGetDeclVertexSize(declaration, declaration[0].Stream);
1387     if (vertex_declaration_size != This->vertex_declaration_size)
1388     {
1389         WARN("Invalid declaration. New vertex size does not match the original vertex size.\n");
1390         return D3DERR_INVALIDCALL;
1391     }
1392 
1393     /* New declaration must not contain non-zero Stream value  */
1394     for (i = 0; declaration[i].Stream != 0xff; i++)
1395     {
1396         if (declaration[i].Stream != 0)
1397         {
1398             WARN("Invalid declaration. New declaration contains non-zero Stream value.\n");
1399             return D3DERR_INVALIDCALL;
1400         }
1401     }
1402 
1403     This->num_elem = i + 1;
1404     copy_declaration(This->cached_declaration, declaration, This->num_elem);
1405 
1406     if (This->vertex_declaration)
1407         IDirect3DVertexDeclaration9_Release(This->vertex_declaration);
1408 
1409     /* An application can pass an invalid declaration to UpdateSemantics and
1410      * still expect D3D_OK (see tests). If the declaration is invalid, then
1411      * subsequent calls to DrawSubset will fail. This is handled by setting the
1412      * vertex declaration to NULL.
1413      *     GetDeclaration, GetNumBytesPerVertex must, however, use the new
1414      * invalid declaration. This is handled by them using the cached vertex
1415      * declaration instead of the actual vertex declaration.
1416      */
1417     hr = IDirect3DDevice9_CreateVertexDeclaration(This->device,
1418                                                   declaration,
1419                                                   &This->vertex_declaration);
1420     if (FAILED(hr))
1421     {
1422         WARN("Using invalid declaration. Calls to DrawSubset will fail.\n");
1423         This->vertex_declaration = NULL;
1424     }
1425 
1426     return D3D_OK;
1427 }
1428 
1429 static HRESULT WINAPI d3dx9_mesh_LockAttributeBuffer(ID3DXMesh *iface, DWORD flags, DWORD **data)
1430 {
1431     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
1432 
1433     TRACE("iface %p, flags %#x, data %p.\n", iface, flags, data);
1434 
1435     InterlockedIncrement(&mesh->attrib_buffer_lock_count);
1436 
1437     if (!(flags & D3DLOCK_READONLY))
1438     {
1439         D3DXATTRIBUTERANGE *attrib_table = mesh->attrib_table;
1440         mesh->attrib_table_size = 0;
1441         mesh->attrib_table = NULL;
1442         HeapFree(GetProcessHeap(), 0, attrib_table);
1443     }
1444 
1445     *data = mesh->attrib_buffer;
1446 
1447     return D3D_OK;
1448 }
1449 
1450 static HRESULT WINAPI d3dx9_mesh_UnlockAttributeBuffer(ID3DXMesh *iface)
1451 {
1452     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
1453     int lock_count;
1454 
1455     TRACE("iface %p.\n", iface);
1456 
1457     lock_count = InterlockedDecrement(&mesh->attrib_buffer_lock_count);
1458     if (lock_count < 0)
1459     {
1460         InterlockedIncrement(&mesh->attrib_buffer_lock_count);
1461         return D3DERR_INVALIDCALL;
1462     }
1463 
1464     return D3D_OK;
1465 }
1466 
1467 static HRESULT WINAPI d3dx9_mesh_Optimize(ID3DXMesh *iface, DWORD flags, const DWORD *adjacency_in,
1468         DWORD *adjacency_out, DWORD *face_remap, ID3DXBuffer **vertex_remap, ID3DXMesh **opt_mesh)
1469 {
1470     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
1471     HRESULT hr;
1472     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = { D3DDECL_END() };
1473     ID3DXMesh *optimized_mesh;
1474 
1475     TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap %p, vertex_remap %p, opt_mesh %p.\n",
1476             iface, flags, adjacency_in, adjacency_out, face_remap, vertex_remap, opt_mesh);
1477 
1478     if (!opt_mesh)
1479         return D3DERR_INVALIDCALL;
1480 
1481     hr = iface->lpVtbl->GetDeclaration(iface, declaration);
1482     if (FAILED(hr)) return hr;
1483 
1484     if (FAILED(hr = iface->lpVtbl->CloneMesh(iface, mesh->options, declaration, mesh->device, &optimized_mesh)))
1485         return hr;
1486 
1487     hr = optimized_mesh->lpVtbl->OptimizeInplace(optimized_mesh, flags, adjacency_in, adjacency_out, face_remap, vertex_remap);
1488     if (SUCCEEDED(hr))
1489         *opt_mesh = optimized_mesh;
1490     else
1491         IUnknown_Release(optimized_mesh);
1492     return hr;
1493 }
1494 
1495 /* Creates a vertex_remap that removes unused vertices.
1496  * Indices are updated according to the vertex_remap. */
1497 static HRESULT compact_mesh(struct d3dx9_mesh *This, DWORD *indices,
1498         DWORD *new_num_vertices, ID3DXBuffer **vertex_remap)
1499 {
1500     HRESULT hr;
1501     DWORD *vertex_remap_ptr;
1502     DWORD num_used_vertices;
1503     DWORD i;
1504 
1505     hr = D3DXCreateBuffer(This->numvertices * sizeof(DWORD), vertex_remap);
1506     if (FAILED(hr)) return hr;
1507     vertex_remap_ptr = ID3DXBuffer_GetBufferPointer(*vertex_remap);
1508 
1509     for (i = 0; i < This->numfaces * 3; i++)
1510         vertex_remap_ptr[indices[i]] = 1;
1511 
1512     /* create old->new vertex mapping */
1513     num_used_vertices = 0;
1514     for (i = 0; i < This->numvertices; i++) {
1515         if (vertex_remap_ptr[i])
1516             vertex_remap_ptr[i] = num_used_vertices++;
1517         else
1518             vertex_remap_ptr[i] = -1;
1519     }
1520     /* convert indices */
1521     for (i = 0; i < This->numfaces * 3; i++)
1522         indices[i] = vertex_remap_ptr[indices[i]];
1523 
1524     /* create new->old vertex mapping */
1525     num_used_vertices = 0;
1526     for (i = 0; i < This->numvertices; i++) {
1527         if (vertex_remap_ptr[i] != -1)
1528             vertex_remap_ptr[num_used_vertices++] = i;
1529     }
1530     for (i = num_used_vertices; i < This->numvertices; i++)
1531         vertex_remap_ptr[i] = -1;
1532 
1533     *new_num_vertices = num_used_vertices;
1534 
1535     return D3D_OK;
1536 }
1537 
1538 /* count the number of unique attribute values in a sorted attribute buffer */
1539 static DWORD count_attributes(const DWORD *attrib_buffer, DWORD numfaces)
1540 {
1541     DWORD last_attribute = attrib_buffer[0];
1542     DWORD attrib_table_size = 1;
1543     DWORD i;
1544     for (i = 1; i < numfaces; i++) {
1545         if (attrib_buffer[i] != last_attribute) {
1546             last_attribute = attrib_buffer[i];
1547             attrib_table_size++;
1548         }
1549     }
1550     return attrib_table_size;
1551 }
1552 
1553 static void fill_attribute_table(DWORD *attrib_buffer, DWORD numfaces, void *indices,
1554                                  BOOL is_32bit_indices, D3DXATTRIBUTERANGE *attrib_table)
1555 {
1556     DWORD attrib_table_size = 0;
1557     DWORD last_attribute = attrib_buffer[0];
1558     DWORD min_vertex, max_vertex;
1559     DWORD i;
1560 
1561     attrib_table[0].AttribId = last_attribute;
1562     attrib_table[0].FaceStart = 0;
1563     min_vertex = (DWORD)-1;
1564     max_vertex = 0;
1565     for (i = 0; i < numfaces; i++) {
1566         DWORD j;
1567 
1568         if (attrib_buffer[i] != last_attribute) {
1569             last_attribute = attrib_buffer[i];
1570             attrib_table[attrib_table_size].FaceCount = i - attrib_table[attrib_table_size].FaceStart;
1571             attrib_table[attrib_table_size].VertexStart = min_vertex;
1572             attrib_table[attrib_table_size].VertexCount = max_vertex - min_vertex + 1;
1573             attrib_table_size++;
1574             attrib_table[attrib_table_size].AttribId = attrib_buffer[i];
1575             attrib_table[attrib_table_size].FaceStart = i;
1576             min_vertex = (DWORD)-1;
1577             max_vertex = 0;
1578         }
1579         for (j = 0; j < 3; j++) {
1580             DWORD vertex_index = is_32bit_indices ? ((DWORD*)indices)[i * 3 + j] : ((WORD*)indices)[i * 3 + j];
1581             if (vertex_index < min_vertex)
1582                 min_vertex = vertex_index;
1583             if (vertex_index > max_vertex)
1584                 max_vertex = vertex_index;
1585         }
1586     }
1587     attrib_table[attrib_table_size].FaceCount = i - attrib_table[attrib_table_size].FaceStart;
1588     attrib_table[attrib_table_size].VertexStart = min_vertex;
1589     attrib_table[attrib_table_size].VertexCount = max_vertex - min_vertex + 1;
1590     attrib_table_size++;
1591 }
1592 
1593 static int attrib_entry_compare(const DWORD **a, const DWORD **b)
1594 {
1595     const DWORD *ptr_a = *a;
1596     const DWORD *ptr_b = *b;
1597     int delta = *ptr_a - *ptr_b;
1598 
1599     if (delta)
1600         return delta;
1601 
1602     delta = ptr_a - ptr_b; /* for stable sort */
1603     return delta;
1604 }
1605 
1606 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
1607 static HRESULT remap_faces_for_attrsort(struct d3dx9_mesh *This, const DWORD *indices,
1608         DWORD *attrib_buffer, DWORD **sorted_attrib_buffer, DWORD **face_remap)
1609 {
1610     DWORD **sorted_attrib_ptr_buffer = NULL;
1611     DWORD i;
1612 
1613     sorted_attrib_ptr_buffer = HeapAlloc(GetProcessHeap(), 0, This->numfaces * sizeof(*sorted_attrib_ptr_buffer));
1614     if (!sorted_attrib_ptr_buffer)
1615         return E_OUTOFMEMORY;
1616 
1617     *face_remap = HeapAlloc(GetProcessHeap(), 0, This->numfaces * sizeof(**face_remap));
1618     if (!*face_remap)
1619     {
1620         HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer);
1621         return E_OUTOFMEMORY;
1622     }
1623 
1624     for (i = 0; i < This->numfaces; i++)
1625         sorted_attrib_ptr_buffer[i] = &attrib_buffer[i];
1626     qsort(sorted_attrib_ptr_buffer, This->numfaces, sizeof(*sorted_attrib_ptr_buffer),
1627          (int(*)(const void *, const void *))attrib_entry_compare);
1628 
1629     for (i = 0; i < This->numfaces; i++)
1630     {
1631         DWORD old_face = sorted_attrib_ptr_buffer[i] - attrib_buffer;
1632         (*face_remap)[old_face] = i;
1633     }
1634 
1635     /* overwrite sorted_attrib_ptr_buffer with the values themselves */
1636     *sorted_attrib_buffer = (DWORD*)sorted_attrib_ptr_buffer;
1637     for (i = 0; i < This->numfaces; i++)
1638         (*sorted_attrib_buffer)[(*face_remap)[i]] = attrib_buffer[i];
1639 
1640     return D3D_OK;
1641 }
1642 
1643 static HRESULT WINAPI d3dx9_mesh_OptimizeInplace(ID3DXMesh *iface, DWORD flags, const DWORD *adjacency_in,
1644         DWORD *adjacency_out, DWORD *face_remap_out, ID3DXBuffer **vertex_remap_out)
1645 {
1646     struct d3dx9_mesh *This = impl_from_ID3DXMesh(iface);
1647     void *indices = NULL;
1648     DWORD *attrib_buffer = NULL;
1649     HRESULT hr;
1650     ID3DXBuffer *vertex_remap = NULL;
1651     DWORD *face_remap = NULL; /* old -> new mapping */
1652     DWORD *dword_indices = NULL;
1653     DWORD new_num_vertices = 0;
1654     DWORD new_num_alloc_vertices = 0;
1655     IDirect3DVertexBuffer9 *vertex_buffer = NULL;
1656     DWORD *sorted_attrib_buffer = NULL;
1657     DWORD i;
1658 
1659     TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
1660             iface, flags, adjacency_in, adjacency_out, face_remap_out, vertex_remap_out);
1661 
1662     if (!flags)
1663         return D3DERR_INVALIDCALL;
1664     if (!adjacency_in && (flags & (D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_STRIPREORDER)))
1665         return D3DERR_INVALIDCALL;
1666     if ((flags & (D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_STRIPREORDER)) == (D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_STRIPREORDER))
1667         return D3DERR_INVALIDCALL;
1668 
1669     if (flags & (D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_STRIPREORDER))
1670     {
1671         if (flags & D3DXMESHOPT_VERTEXCACHE)
1672             FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
1673         if (flags & D3DXMESHOPT_STRIPREORDER)
1674             FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
1675         return E_NOTIMPL;
1676     }
1677 
1678     hr = iface->lpVtbl->LockIndexBuffer(iface, 0, &indices);
1679     if (FAILED(hr)) goto cleanup;
1680 
1681     dword_indices = HeapAlloc(GetProcessHeap(), 0, This->numfaces * 3 * sizeof(DWORD));
1682     if (!dword_indices) return E_OUTOFMEMORY;
1683     if (This->options & D3DXMESH_32BIT) {
1684         memcpy(dword_indices, indices, This->numfaces * 3 * sizeof(DWORD));
1685     } else {
1686         WORD *word_indices = indices;
1687         for (i = 0; i < This->numfaces * 3; i++)
1688             dword_indices[i] = *word_indices++;
1689     }
1690 
1691     if ((flags & (D3DXMESHOPT_COMPACT | D3DXMESHOPT_IGNOREVERTS | D3DXMESHOPT_ATTRSORT)) == D3DXMESHOPT_COMPACT)
1692     {
1693         new_num_alloc_vertices = This->numvertices;
1694         hr = compact_mesh(This, dword_indices, &new_num_vertices, &vertex_remap);
1695         if (FAILED(hr)) goto cleanup;
1696     } else if (flags & D3DXMESHOPT_ATTRSORT) {
1697         if (!(flags & D3DXMESHOPT_IGNOREVERTS))
1698         {
1699             FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
1700             hr = E_NOTIMPL;
1701             goto cleanup;
1702         }
1703 
1704         hr = iface->lpVtbl->LockAttributeBuffer(iface, 0, &attrib_buffer);
1705         if (FAILED(hr)) goto cleanup;
1706 
1707         hr = remap_faces_for_attrsort(This, dword_indices, attrib_buffer, &sorted_attrib_buffer, &face_remap);
1708         if (FAILED(hr)) goto cleanup;
1709     }
1710 
1711     if (vertex_remap)
1712     {
1713         /* reorder the vertices using vertex_remap */
1714         D3DVERTEXBUFFER_DESC vertex_desc;
1715         DWORD *vertex_remap_ptr = ID3DXBuffer_GetBufferPointer(vertex_remap);
1716         DWORD vertex_size = iface->lpVtbl->GetNumBytesPerVertex(iface);
1717         BYTE *orig_vertices;
1718         BYTE *new_vertices;
1719 
1720         hr = IDirect3DVertexBuffer9_GetDesc(This->vertex_buffer, &vertex_desc);
1721         if (FAILED(hr)) goto cleanup;
1722 
1723         hr = IDirect3DDevice9_CreateVertexBuffer(This->device, new_num_alloc_vertices * vertex_size,
1724                 vertex_desc.Usage, This->fvf, vertex_desc.Pool, &vertex_buffer, NULL);
1725         if (FAILED(hr)) goto cleanup;
1726 
1727         hr = IDirect3DVertexBuffer9_Lock(This->vertex_buffer, 0, 0, (void**)&orig_vertices, D3DLOCK_READONLY);
1728         if (FAILED(hr)) goto cleanup;
1729 
1730         hr = IDirect3DVertexBuffer9_Lock(vertex_buffer, 0, 0, (void**)&new_vertices, 0);
1731         if (FAILED(hr)) {
1732             IDirect3DVertexBuffer9_Unlock(This->vertex_buffer);
1733             goto cleanup;
1734         }
1735 
1736         for (i = 0; i < new_num_vertices; i++)
1737             memcpy(new_vertices + i * vertex_size, orig_vertices + vertex_remap_ptr[i] * vertex_size, vertex_size);
1738 
1739         IDirect3DVertexBuffer9_Unlock(This->vertex_buffer);
1740         IDirect3DVertexBuffer9_Unlock(vertex_buffer);
1741     } else if (vertex_remap_out) {
1742         DWORD *vertex_remap_ptr;
1743 
1744         hr = D3DXCreateBuffer(This->numvertices * sizeof(DWORD), &vertex_remap);
1745         if (FAILED(hr)) goto cleanup;
1746         vertex_remap_ptr = ID3DXBuffer_GetBufferPointer(vertex_remap);
1747         for (i = 0; i < This->numvertices; i++)
1748             *vertex_remap_ptr++ = i;
1749     }
1750 
1751     if (flags & D3DXMESHOPT_ATTRSORT)
1752     {
1753         D3DXATTRIBUTERANGE *attrib_table;
1754         DWORD attrib_table_size;
1755 
1756         attrib_table_size = count_attributes(sorted_attrib_buffer, This->numfaces);
1757         attrib_table = HeapAlloc(GetProcessHeap(), 0, attrib_table_size * sizeof(*attrib_table));
1758         if (!attrib_table) {
1759             hr = E_OUTOFMEMORY;
1760             goto cleanup;
1761         }
1762 
1763         memcpy(attrib_buffer, sorted_attrib_buffer, This->numfaces * sizeof(*attrib_buffer));
1764 
1765         /* reorder the indices using face_remap */
1766         if (This->options & D3DXMESH_32BIT) {
1767             for (i = 0; i < This->numfaces; i++)
1768                 memcpy((DWORD*)indices + face_remap[i] * 3, dword_indices + i * 3, 3 * sizeof(DWORD));
1769         } else {
1770             WORD *word_indices = indices;
1771             for (i = 0; i < This->numfaces; i++) {
1772                 DWORD new_pos = face_remap[i] * 3;
1773                 DWORD old_pos = i * 3;
1774                 word_indices[new_pos++] = dword_indices[old_pos++];
1775                 word_indices[new_pos++] = dword_indices[old_pos++];
1776                 word_indices[new_pos] = dword_indices[old_pos];
1777             }
1778         }
1779 
1780         fill_attribute_table(attrib_buffer, This->numfaces, indices,
1781                              This->options & D3DXMESH_32BIT, attrib_table);
1782 
1783         HeapFree(GetProcessHeap(), 0, This->attrib_table);
1784         This->attrib_table = attrib_table;
1785         This->attrib_table_size = attrib_table_size;
1786     } else {
1787         if (This->options & D3DXMESH_32BIT) {
1788             memcpy(indices, dword_indices, This->numfaces * 3 * sizeof(DWORD));
1789         } else {
1790             WORD *word_indices = indices;
1791             for (i = 0; i < This->numfaces * 3; i++)
1792                 *word_indices++ = dword_indices[i];
1793         }
1794     }
1795 
1796     if (adjacency_out) {
1797         if (face_remap) {
1798             for (i = 0; i < This->numfaces; i++) {
1799                 DWORD old_pos = i * 3;
1800                 DWORD new_pos = face_remap[i] * 3;
1801                 adjacency_out[new_pos++] = face_remap[adjacency_in[old_pos++]];
1802                 adjacency_out[new_pos++] = face_remap[adjacency_in[old_pos++]];
1803                 adjacency_out[new_pos++] = face_remap[adjacency_in[old_pos++]];
1804             }
1805         } else {
1806             memcpy(adjacency_out, adjacency_in, This->numfaces * 3 * sizeof(*adjacency_out));
1807         }
1808     }
1809     if (face_remap_out) {
1810         if (face_remap) {
1811             for (i = 0; i < This->numfaces; i++)
1812                 face_remap_out[face_remap[i]] = i;
1813         } else {
1814             for (i = 0; i < This->numfaces; i++)
1815                 face_remap_out[i] = i;
1816         }
1817     }
1818     if (vertex_remap_out)
1819         *vertex_remap_out = vertex_remap;
1820     vertex_remap = NULL;
1821 
1822     if (vertex_buffer) {
1823         IDirect3DVertexBuffer9_Release(This->vertex_buffer);
1824         This->vertex_buffer = vertex_buffer;
1825         vertex_buffer = NULL;
1826         This->numvertices = new_num_vertices;
1827     }
1828 
1829     hr = D3D_OK;
1830 cleanup:
1831     HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer);
1832     HeapFree(GetProcessHeap(), 0, face_remap);
1833     HeapFree(GetProcessHeap(), 0, dword_indices);
1834     if (vertex_remap) ID3DXBuffer_Release(vertex_remap);
1835     if (vertex_buffer) IDirect3DVertexBuffer9_Release(vertex_buffer);
1836     if (attrib_buffer) iface->lpVtbl->UnlockAttributeBuffer(iface);
1837     if (indices) iface->lpVtbl->UnlockIndexBuffer(iface);
1838     return hr;
1839 }
1840 
1841 static HRESULT WINAPI d3dx9_mesh_SetAttributeTable(ID3DXMesh *iface,
1842         const D3DXATTRIBUTERANGE *attrib_table, DWORD attrib_table_size)
1843 {
1844     struct d3dx9_mesh *mesh = impl_from_ID3DXMesh(iface);
1845     D3DXATTRIBUTERANGE *new_table = NULL;
1846 
1847     TRACE("iface %p, attrib_table %p, attrib_table_size %u.\n", iface, attrib_table, attrib_table_size);
1848 
1849     if (attrib_table_size) {
1850         size_t size = attrib_table_size * sizeof(*attrib_table);
1851 
1852         new_table = HeapAlloc(GetProcessHeap(), 0, size);
1853         if (!new_table)
1854             return E_OUTOFMEMORY;
1855 
1856         CopyMemory(new_table, attrib_table, size);
1857     } else if (attrib_table) {
1858         return D3DERR_INVALIDCALL;
1859     }
1860     HeapFree(GetProcessHeap(), 0, mesh->attrib_table);
1861     mesh->attrib_table = new_table;
1862     mesh->attrib_table_size = attrib_table_size;
1863 
1864     return D3D_OK;
1865 }
1866 
1867 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl =
1868 {
1869     d3dx9_mesh_QueryInterface,
1870     d3dx9_mesh_AddRef,
1871     d3dx9_mesh_Release,
1872     d3dx9_mesh_DrawSubset,
1873     d3dx9_mesh_GetNumFaces,
1874     d3dx9_mesh_GetNumVertices,
1875     d3dx9_mesh_GetFVF,
1876     d3dx9_mesh_GetDeclaration,
1877     d3dx9_mesh_GetNumBytesPerVertex,
1878     d3dx9_mesh_GetOptions,
1879     d3dx9_mesh_GetDevice,
1880     d3dx9_mesh_CloneMeshFVF,
1881     d3dx9_mesh_CloneMesh,
1882     d3dx9_mesh_GetVertexBuffer,
1883     d3dx9_mesh_GetIndexBuffer,
1884     d3dx9_mesh_LockVertexBuffer,
1885     d3dx9_mesh_UnlockVertexBuffer,
1886     d3dx9_mesh_LockIndexBuffer,
1887     d3dx9_mesh_UnlockIndexBuffer,
1888     d3dx9_mesh_GetAttributeTable,
1889     d3dx9_mesh_ConvertPointRepsToAdjacency,
1890     d3dx9_mesh_ConvertAdjacencyToPointReps,
1891     d3dx9_mesh_GenerateAdjacency,
1892     d3dx9_mesh_UpdateSemantics,
1893     d3dx9_mesh_LockAttributeBuffer,
1894     d3dx9_mesh_UnlockAttributeBuffer,
1895     d3dx9_mesh_Optimize,
1896     d3dx9_mesh_OptimizeInplace,
1897     d3dx9_mesh_SetAttributeTable,
1898 };
1899 
1900 
1901 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algorithm
1902 Amy Williams             University of Utah
1903 Steve Barrus             University of Utah
1904 R. Keith Morley          University of Utah
1905 Peter Shirley            University of Utah
1906 
1907 International Conference on Computer Graphics and Interactive Techniques  archive
1908 ACM SIGGRAPH 2005 Courses
1909 Los Angeles, California
1910 
1911 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1912 
1913 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1914 against each slab, if there's anything left of the ray after we're
1915 done we've got an intersection of the ray with the box. */
1916 BOOL WINAPI D3DXBoxBoundProbe(const D3DXVECTOR3 *pmin, const D3DXVECTOR3 *pmax,
1917         const D3DXVECTOR3 *prayposition, const D3DXVECTOR3 *praydirection)
1918 {
1919     FLOAT div, tmin, tmax, tymin, tymax, tzmin, tzmax;
1920 
1921     div = 1.0f / praydirection->x;
1922     if ( div >= 0.0f )
1923     {
1924         tmin = ( pmin->x - prayposition->x ) * div;
1925         tmax = ( pmax->x - prayposition->x ) * div;
1926     }
1927     else
1928     {
1929         tmin = ( pmax->x - prayposition->x ) * div;
1930         tmax = ( pmin->x - prayposition->x ) * div;
1931     }
1932 
1933     if ( tmax < 0.0f ) return FALSE;
1934 
1935     div = 1.0f / praydirection->y;
1936     if ( div >= 0.0f )
1937     {
1938         tymin = ( pmin->y - prayposition->y ) * div;
1939         tymax = ( pmax->y - prayposition->y ) * div;
1940     }
1941     else
1942     {
1943         tymin = ( pmax->y - prayposition->y ) * div;
1944         tymax = ( pmin->y - prayposition->y ) * div;
1945     }
1946 
1947     if ( ( tymax < 0.0f ) || ( tmin > tymax ) || ( tymin > tmax ) ) return FALSE;
1948 
1949     if ( tymin > tmin ) tmin = tymin;
1950     if ( tymax < tmax ) tmax = tymax;
1951 
1952     div = 1.0f / praydirection->z;
1953     if ( div >= 0.0f )
1954     {
1955         tzmin = ( pmin->z - prayposition->z ) * div;
1956         tzmax = ( pmax->z - prayposition->z ) * div;
1957     }
1958     else
1959     {
1960         tzmin = ( pmax->z - prayposition->z ) * div;
1961         tzmax = ( pmin->z - prayposition->z ) * div;
1962     }
1963 
1964     if ( (tzmax < 0.0f ) || ( tmin > tzmax ) || ( tzmin > tmax ) ) return FALSE;
1965 
1966     return TRUE;
1967 }
1968 
1969 HRESULT WINAPI D3DXComputeBoundingBox(const D3DXVECTOR3 *pfirstposition,
1970         DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pmin, D3DXVECTOR3 *pmax)
1971 {
1972     D3DXVECTOR3 vec;
1973     unsigned int i;
1974 
1975     if( !pfirstposition || !pmin || !pmax ) return D3DERR_INVALIDCALL;
1976 
1977     *pmin = *pfirstposition;
1978     *pmax = *pmin;
1979 
1980     for(i=0; i<numvertices; i++)
1981     {
1982         vec = *( (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i) );
1983 
1984         if ( vec.x < pmin->x ) pmin->x = vec.x;
1985         if ( vec.x > pmax->x ) pmax->x = vec.x;
1986 
1987         if ( vec.y < pmin->y ) pmin->y = vec.y;
1988         if ( vec.y > pmax->y ) pmax->y = vec.y;
1989 
1990         if ( vec.z < pmin->z ) pmin->z = vec.z;
1991         if ( vec.z > pmax->z ) pmax->z = vec.z;
1992     }
1993 
1994     return D3D_OK;
1995 }
1996 
1997 HRESULT WINAPI D3DXComputeBoundingSphere(const D3DXVECTOR3 *pfirstposition,
1998         DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pcenter, float *pradius)
1999 {
2000     D3DXVECTOR3 temp;
2001     FLOAT d;
2002     unsigned int i;
2003 
2004     if( !pfirstposition || !pcenter || !pradius ) return D3DERR_INVALIDCALL;
2005 
2006     temp.x = 0.0f;
2007     temp.y = 0.0f;
2008     temp.z = 0.0f;
2009     *pradius = 0.0f;
2010 
2011     for(i=0; i<numvertices; i++)
2012         D3DXVec3Add(&temp, &temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i));
2013 
2014     D3DXVec3Scale(pcenter, &temp, 1.0f / numvertices);
2015 
2016     for(i=0; i<numvertices; i++)
2017     {
2018         d = D3DXVec3Length(D3DXVec3Subtract(&temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i), pcenter));
2019         if ( d > *pradius ) *pradius = d;
2020     }
2021     return D3D_OK;
2022 }
2023 
2024 static void append_decl_element(D3DVERTEXELEMENT9 *declaration, UINT *idx, UINT *offset,
2025         D3DDECLTYPE type, D3DDECLUSAGE usage, UINT usage_idx)
2026 {
2027     declaration[*idx].Stream = 0;
2028     declaration[*idx].Offset = *offset;
2029     declaration[*idx].Type = type;
2030     declaration[*idx].Method = D3DDECLMETHOD_DEFAULT;
2031     declaration[*idx].Usage = usage;
2032     declaration[*idx].UsageIndex = usage_idx;
2033 
2034     *offset += d3dx_decltype_size[type];
2035     ++(*idx);
2036 }
2037 
2038 /*************************************************************************
2039  * D3DXDeclaratorFromFVF
2040  */
2041 HRESULT WINAPI D3DXDeclaratorFromFVF(DWORD fvf, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
2042 {
2043     static const D3DVERTEXELEMENT9 end_element = D3DDECL_END();
2044     DWORD tex_count = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
2045     unsigned int offset = 0;
2046     unsigned int idx = 0;
2047     unsigned int i;
2048 
2049     TRACE("fvf %#x, declaration %p.\n", fvf, declaration);
2050 
2051     if (fvf & (D3DFVF_RESERVED0 | D3DFVF_RESERVED2)) return D3DERR_INVALIDCALL;
2052 
2053     if (fvf & D3DFVF_POSITION_MASK)
2054     {
2055         BOOL has_blend = (fvf & D3DFVF_XYZB5) >= D3DFVF_XYZB1;
2056         DWORD blend_count = 1 + (((fvf & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1);
2057         BOOL has_blend_idx = (fvf & D3DFVF_LASTBETA_D3DCOLOR) || (fvf & D3DFVF_LASTBETA_UBYTE4);
2058 
2059         if (has_blend_idx) --blend_count;
2060 
2061         if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZW
2062                 || (has_blend && blend_count > 4))
2063             return D3DERR_INVALIDCALL;
2064 
2065         if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
2066             append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_POSITIONT, 0);
2067         else
2068             append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_POSITION, 0);
2069 
2070         if (has_blend)
2071         {
2072             switch (blend_count)
2073             {
2074                  case 0:
2075                     break;
2076                  case 1:
2077                     append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_BLENDWEIGHT, 0);
2078                     break;
2079                  case 2:
2080                     append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT2, D3DDECLUSAGE_BLENDWEIGHT, 0);
2081                     break;
2082                  case 3:
2083                     append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_BLENDWEIGHT, 0);
2084                     break;
2085                  case 4:
2086                     append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_BLENDWEIGHT, 0);
2087                     break;
2088                  default:
2089                      ERR("Invalid blend count %u.\n", blend_count);
2090                      break;
2091             }
2092 
2093             if (has_blend_idx)
2094             {
2095                 if (fvf & D3DFVF_LASTBETA_UBYTE4)
2096                     append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_UBYTE4, D3DDECLUSAGE_BLENDINDICES, 0);
2097                 else if (fvf & D3DFVF_LASTBETA_D3DCOLOR)
2098                     append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_BLENDINDICES, 0);
2099             }
2100         }
2101     }
2102 
2103     if (fvf & D3DFVF_NORMAL)
2104         append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_NORMAL, 0);
2105     if (fvf & D3DFVF_PSIZE)
2106         append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_PSIZE, 0);
2107     if (fvf & D3DFVF_DIFFUSE)
2108         append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_COLOR, 0);
2109     if (fvf & D3DFVF_SPECULAR)
2110         append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_COLOR, 1);
2111 
2112     for (i = 0; i < tex_count; ++i)
2113     {
2114         switch ((fvf >> (16 + 2 * i)) & 0x03)
2115         {
2116             case D3DFVF_TEXTUREFORMAT1:
2117                 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_TEXCOORD, i);
2118                 break;
2119             case D3DFVF_TEXTUREFORMAT2:
2120                 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT2, D3DDECLUSAGE_TEXCOORD, i);
2121                 break;
2122             case D3DFVF_TEXTUREFORMAT3:
2123                 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_TEXCOORD, i);
2124                 break;
2125             case D3DFVF_TEXTUREFORMAT4:
2126                 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_TEXCOORD, i);
2127                 break;
2128         }
2129     }
2130 
2131     declaration[idx] = end_element;
2132 
2133     return D3D_OK;
2134 }
2135 
2136 /*************************************************************************
2137  * D3DXFVFFromDeclarator
2138  */
2139 HRESULT WINAPI D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9 *declaration, DWORD *fvf)
2140 {
2141     unsigned int i = 0, texture, offset;
2142 
2143     TRACE("(%p, %p)\n", declaration, fvf);
2144 
2145     *fvf = 0;
2146     if (declaration[0].Type == D3DDECLTYPE_FLOAT3 && declaration[0].Usage == D3DDECLUSAGE_POSITION)
2147     {
2148         if ((declaration[1].Type == D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
2149              declaration[1].UsageIndex == 0) &&
2150             (declaration[2].Type == D3DDECLTYPE_FLOAT1 && declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES &&
2151              declaration[2].UsageIndex == 0))
2152         {
2153             return D3DERR_INVALIDCALL;
2154         }
2155         else if ((declaration[1].Type == D3DDECLTYPE_UBYTE4 || declaration[1].Type == D3DDECLTYPE_D3DCOLOR) &&
2156                  declaration[1].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[1].UsageIndex == 0)
2157         {
2158             if (declaration[1].Type == D3DDECLTYPE_UBYTE4)
2159             {
2160                 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4;
2161             }
2162             else
2163             {
2164                 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR;
2165             }
2166             i = 2;
2167         }
2168         else if (declaration[1].Type <= D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
2169                  declaration[1].UsageIndex == 0)
2170         {
2171             if ((declaration[2].Type == D3DDECLTYPE_UBYTE4 || declaration[2].Type == D3DDECLTYPE_D3DCOLOR) &&
2172                 declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[2].UsageIndex == 0)
2173             {
2174                 if (declaration[2].Type == D3DDECLTYPE_UBYTE4)
2175                 {
2176                     *fvf |= D3DFVF_LASTBETA_UBYTE4;
2177                 }
2178                 else
2179                 {
2180                     *fvf |= D3DFVF_LASTBETA_D3DCOLOR;
2181                 }
2182                 switch (declaration[1].Type)
2183                 {
2184                     case D3DDECLTYPE_FLOAT1: *fvf |= D3DFVF_XYZB2; break;
2185                     case D3DDECLTYPE_FLOAT2: *fvf |= D3DFVF_XYZB3; break;
2186                     case D3DDECLTYPE_FLOAT3: *fvf |= D3DFVF_XYZB4; break;
2187                     case D3DDECLTYPE_FLOAT4: *fvf |= D3DFVF_XYZB5; break;
2188                 }
2189                 i = 3;
2190             }
2191             else
2192             {
2193                 switch (declaration[1].Type)
2194                 {
2195                     case D3DDECLTYPE_FLOAT1: *fvf |= D3DFVF_XYZB1; break;
2196                     case D3DDECLTYPE_FLOAT2: *fvf |= D3DFVF_XYZB2; break;
2197                     case D3DDECLTYPE_FLOAT3: *fvf |= D3DFVF_XYZB3; break;
2198                     case D3DDECLTYPE_FLOAT4: *fvf |= D3DFVF_XYZB4; break;
2199                 }
2200                 i = 2;
2201             }
2202         }
2203         else
2204         {
2205             *fvf |= D3DFVF_XYZ;
2206             i = 1;
2207         }
2208     }
2209     else if (declaration[0].Type == D3DDECLTYPE_FLOAT4 && declaration[0].Usage == D3DDECLUSAGE_POSITIONT &&
2210              declaration[0].UsageIndex == 0)
2211     {
2212         *fvf |= D3DFVF_XYZRHW;
2213         i = 1;
2214     }
2215 
2216     if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_NORMAL)
2217     {
2218         *fvf |= D3DFVF_NORMAL;
2219         i++;
2220     }
2221     if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_PSIZE &&
2222         declaration[i].UsageIndex == 0)
2223     {
2224         *fvf |= D3DFVF_PSIZE;
2225         i++;
2226     }
2227     if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
2228         declaration[i].UsageIndex == 0)
2229     {
2230         *fvf |= D3DFVF_DIFFUSE;
2231         i++;
2232     }
2233     if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
2234         declaration[i].UsageIndex == 1)
2235     {
2236         *fvf |= D3DFVF_SPECULAR;
2237         i++;
2238     }
2239 
2240     for (texture = 0; texture < D3DDP_MAXTEXCOORD; i++, texture++)
2241     {
2242         if (declaration[i].Stream == 0xFF)
2243         {
2244             break;
2245         }
2246         else if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
2247                  declaration[i].UsageIndex == texture)
2248         {
2249             *fvf |= D3DFVF_TEXCOORDSIZE1(declaration[i].UsageIndex);
2250         }
2251         else if (declaration[i].Type == D3DDECLTYPE_FLOAT2 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
2252                  declaration[i].UsageIndex == texture)
2253         {
2254             *fvf |= D3DFVF_TEXCOORDSIZE2(declaration[i].UsageIndex);
2255         }
2256         else if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
2257                  declaration[i].UsageIndex == texture)
2258         {
2259             *fvf |= D3DFVF_TEXCOORDSIZE3(declaration[i].UsageIndex);
2260         }
2261         else if (declaration[i].Type == D3DDECLTYPE_FLOAT4 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
2262                  declaration[i].UsageIndex == texture)
2263         {
2264             *fvf |= D3DFVF_TEXCOORDSIZE4(declaration[i].UsageIndex);
2265         }
2266         else
2267         {
2268             return D3DERR_INVALIDCALL;
2269         }
2270     }
2271 
2272     *fvf |= (texture << D3DFVF_TEXCOUNT_SHIFT);
2273 
2274     for (offset = 0, i = 0; declaration[i].Stream != 0xFF;
2275          offset += d3dx_decltype_size[declaration[i].Type], i++)
2276     {
2277         if (declaration[i].Offset != offset)
2278         {
2279             return D3DERR_INVALIDCALL;
2280         }
2281     }
2282 
2283     return D3D_OK;
2284 }
2285 
2286 /*************************************************************************
2287  * D3DXGetFVFVertexSize
2288  */
2289 static UINT Get_TexCoord_Size_From_FVF(DWORD FVF, int tex_num)
2290 {
2291     return (((((FVF) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1);
2292 }
2293 
2294 UINT WINAPI D3DXGetFVFVertexSize(DWORD FVF)
2295 {
2296     DWORD size = 0;
2297     UINT i;
2298     UINT numTextures = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
2299 
2300     if (FVF & D3DFVF_NORMAL) size += sizeof(D3DXVECTOR3);
2301     if (FVF & D3DFVF_DIFFUSE) size += sizeof(DWORD);
2302     if (FVF & D3DFVF_SPECULAR) size += sizeof(DWORD);
2303     if (FVF & D3DFVF_PSIZE) size += sizeof(DWORD);
2304 
2305     switch (FVF & D3DFVF_POSITION_MASK)
2306     {
2307         case D3DFVF_XYZ:    size += sizeof(D3DXVECTOR3); break;
2308         case D3DFVF_XYZRHW: size += 4 * sizeof(FLOAT); break;
2309         case D3DFVF_XYZB1:  size += 4 * sizeof(FLOAT); break;
2310         case D3DFVF_XYZB2:  size += 5 * sizeof(FLOAT); break;
2311         case D3DFVF_XYZB3:  size += 6 * sizeof(FLOAT); break;
2312         case D3DFVF_XYZB4:  size += 7 * sizeof(FLOAT); break;
2313         case D3DFVF_XYZB5:  size += 8 * sizeof(FLOAT); break;
2314         case D3DFVF_XYZW:   size += 4 * sizeof(FLOAT); break;
2315     }
2316 
2317     for (i = 0; i < numTextures; i++)
2318     {
2319         size += Get_TexCoord_Size_From_FVF(FVF, i) * sizeof(FLOAT);
2320     }
2321 
2322     return size;
2323 }
2324 
2325 /*************************************************************************
2326  * D3DXGetDeclVertexSize
2327  */
2328 UINT WINAPI D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9 *decl, DWORD stream_idx)
2329 {
2330     const D3DVERTEXELEMENT9 *element;
2331     UINT size = 0;
2332 
2333     TRACE("decl %p, stream_idx %u\n", decl, stream_idx);
2334 
2335     if (!decl) return 0;
2336 
2337     for (element = decl; element->Stream != 0xff; ++element)
2338     {
2339         UINT type_size;
2340 
2341         if (element->Stream != stream_idx) continue;
2342 
2343         if (element->Type >= ARRAY_SIZE(d3dx_decltype_size))
2344         {
2345             FIXME("Unhandled element type %#x, size will be incorrect.\n", element->Type);
2346             continue;
2347         }
2348 
2349         type_size = d3dx_decltype_size[element->Type];
2350         if (element->Offset + type_size > size) size = element->Offset + type_size;
2351     }
2352 
2353     return size;
2354 }
2355 
2356 /*************************************************************************
2357  * D3DXGetDeclLength
2358  */
2359 UINT WINAPI D3DXGetDeclLength(const D3DVERTEXELEMENT9 *decl)
2360 {
2361     const D3DVERTEXELEMENT9 *element;
2362 
2363     TRACE("decl %p\n", decl);
2364 
2365     /* null decl results in exception on Windows XP */
2366 
2367     for (element = decl; element->Stream != 0xff; ++element);
2368 
2369     return element - decl;
2370 }
2371 
2372 BOOL WINAPI D3DXIntersectTri(const D3DXVECTOR3 *p0, const D3DXVECTOR3 *p1, const D3DXVECTOR3 *p2,
2373         const D3DXVECTOR3 *praypos, const D3DXVECTOR3 *praydir, float *pu, float *pv, float *pdist)
2374 {
2375     D3DXMATRIX m;
2376     D3DXVECTOR4 vec;
2377 
2378     TRACE("p0 %p, p1 %p, p2 %p, praypos %p, praydir %p, pu %p, pv %p, pdist %p.\n",
2379             p0, p1, p2, praypos, praydir, pu, pv, pdist);
2380 
2381     m.u.m[0][0] = p1->x - p0->x;
2382     m.u.m[1][0] = p2->x - p0->x;
2383     m.u.m[2][0] = -praydir->x;
2384     m.u.m[3][0] = 0.0f;
2385     m.u.m[0][1] = p1->y - p0->y;
2386     m.u.m[1][1] = p2->y - p0->y;
2387     m.u.m[2][1] = -praydir->y;
2388     m.u.m[3][1] = 0.0f;
2389     m.u.m[0][2] = p1->z - p0->z;
2390     m.u.m[1][2] = p2->z - p0->z;
2391     m.u.m[2][2] = -praydir->z;
2392     m.u.m[3][2] = 0.0f;
2393     m.u.m[0][3] = 0.0f;
2394     m.u.m[1][3] = 0.0f;
2395     m.u.m[2][3] = 0.0f;
2396     m.u.m[3][3] = 1.0f;
2397 
2398     vec.x = praypos->x - p0->x;
2399     vec.y = praypos->y - p0->y;
2400     vec.z = praypos->z - p0->z;
2401     vec.w = 0.0f;
2402 
2403     if ( D3DXMatrixInverse(&m, NULL, &m) )
2404     {
2405         D3DXVec4Transform(&vec, &vec, &m);
2406         if ( (vec.x >= 0.0f) && (vec.y >= 0.0f) && (vec.x + vec.y <= 1.0f) && (vec.z >= 0.0f) )
2407         {
2408             if (pu) *pu = vec.x;
2409             if (pv) *pv = vec.y;
2410             if (pdist) *pdist = fabsf( vec.z );
2411             return TRUE;
2412         }
2413     }
2414 
2415     return FALSE;
2416 }
2417 
2418 BOOL WINAPI D3DXSphereBoundProbe(const D3DXVECTOR3 *pcenter, float radius,
2419         const D3DXVECTOR3 *prayposition, const D3DXVECTOR3 *praydirection)
2420 {
2421     D3DXVECTOR3 difference;
2422     FLOAT a, b, c, d;
2423 
2424     a = D3DXVec3LengthSq(praydirection);
2425     if (!D3DXVec3Subtract(&difference, prayposition, pcenter)) return FALSE;
2426     b = D3DXVec3Dot(&difference, praydirection);
2427     c = D3DXVec3LengthSq(&difference) - radius * radius;
2428     d = b * b - a * c;
2429 
2430     if ( ( d <= 0.0f ) || ( sqrt(d) <= b ) ) return FALSE;
2431     return TRUE;
2432 }
2433 
2434 /*************************************************************************
2435  * D3DXCreateMesh
2436  */
2437 HRESULT WINAPI D3DXCreateMesh(DWORD numfaces, DWORD numvertices, DWORD options,
2438         const D3DVERTEXELEMENT9 *declaration, struct IDirect3DDevice9 *device, struct ID3DXMesh **mesh)
2439 {
2440     HRESULT hr;
2441     DWORD fvf;
2442     IDirect3DVertexDeclaration9 *vertex_declaration;
2443     UINT vertex_declaration_size;
2444     UINT num_elem;
2445     IDirect3DVertexBuffer9 *vertex_buffer;
2446     IDirect3DIndexBuffer9 *index_buffer;
2447     DWORD *attrib_buffer;
2448     struct d3dx9_mesh *object;
2449     DWORD index_usage = 0;
2450     D3DPOOL index_pool = D3DPOOL_DEFAULT;
2451     D3DFORMAT index_format = D3DFMT_INDEX16;
2452     DWORD vertex_usage = 0;
2453     D3DPOOL vertex_pool = D3DPOOL_DEFAULT;
2454     int i;
2455 
2456     TRACE("numfaces %u, numvertices %u, options %#x, declaration %p, device %p, mesh %p.\n",
2457             numfaces, numvertices, options, declaration, device, mesh);
2458 
2459     if (numfaces == 0 || numvertices == 0 || declaration == NULL || device == NULL || mesh == NULL ||
2460         /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
2461         (options & (D3DXMESH_VB_SHARE | D3DXMESH_USEHWONLY | 0xfffe0000)))
2462     {
2463         return D3DERR_INVALIDCALL;
2464     }
2465     for (i = 0; declaration[i].Stream != 0xff; i++)
2466         if (declaration[i].Stream != 0)
2467             return D3DERR_INVALIDCALL;
2468     num_elem = i + 1;
2469 
2470     if (options & D3DXMESH_32BIT)
2471         index_format = D3DFMT_INDEX32;
2472 
2473     if (options & D3DXMESH_DONOTCLIP) {
2474         index_usage |= D3DUSAGE_DONOTCLIP;
2475         vertex_usage |= D3DUSAGE_DONOTCLIP;
2476     }
2477     if (options & D3DXMESH_POINTS) {
2478         index_usage |= D3DUSAGE_POINTS;
2479         vertex_usage |= D3DUSAGE_POINTS;
2480     }
2481     if (options & D3DXMESH_RTPATCHES) {
2482         index_usage |= D3DUSAGE_RTPATCHES;
2483         vertex_usage |= D3DUSAGE_RTPATCHES;
2484     }
2485     if (options & D3DXMESH_NPATCHES) {
2486         index_usage |= D3DUSAGE_NPATCHES;
2487         vertex_usage |= D3DUSAGE_NPATCHES;
2488     }
2489 
2490     if (options & D3DXMESH_VB_SYSTEMMEM)
2491         vertex_pool = D3DPOOL_SYSTEMMEM;
2492     else if (options & D3DXMESH_VB_MANAGED)
2493         vertex_pool = D3DPOOL_MANAGED;
2494 
2495     if (options & D3DXMESH_VB_WRITEONLY)
2496         vertex_usage |= D3DUSAGE_WRITEONLY;
2497     if (options & D3DXMESH_VB_DYNAMIC)
2498         vertex_usage |= D3DUSAGE_DYNAMIC;
2499     if (options & D3DXMESH_VB_SOFTWAREPROCESSING)
2500         vertex_usage |= D3DUSAGE_SOFTWAREPROCESSING;
2501 
2502     if (options & D3DXMESH_IB_SYSTEMMEM)
2503         index_pool = D3DPOOL_SYSTEMMEM;
2504     else if (options & D3DXMESH_IB_MANAGED)
2505         index_pool = D3DPOOL_MANAGED;
2506 
2507     if (options & D3DXMESH_IB_WRITEONLY)
2508         index_usage |= D3DUSAGE_WRITEONLY;
2509     if (options & D3DXMESH_IB_DYNAMIC)
2510         index_usage |= D3DUSAGE_DYNAMIC;
2511     if (options & D3DXMESH_IB_SOFTWAREPROCESSING)
2512         index_usage |= D3DUSAGE_SOFTWAREPROCESSING;
2513 
2514     hr = D3DXFVFFromDeclarator(declaration, &fvf);
2515     if (hr != D3D_OK)
2516     {
2517         fvf = 0;
2518     }
2519 
2520     /* Create vertex declaration */
2521     hr = IDirect3DDevice9_CreateVertexDeclaration(device,
2522                                                   declaration,
2523                                                   &vertex_declaration);
2524     if (FAILED(hr))
2525     {
2526         WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr);
2527         return hr;
2528     }
2529     vertex_declaration_size = D3DXGetDeclVertexSize(declaration, declaration[0].Stream);
2530 
2531     /* Create vertex buffer */
2532     hr = IDirect3DDevice9_CreateVertexBuffer(device,
2533                                              numvertices * vertex_declaration_size,
2534                                              vertex_usage,
2535                                              fvf,
2536                                              vertex_pool,
2537                                              &vertex_buffer,
2538                                              NULL);
2539     if (FAILED(hr))
2540     {
2541         WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
2542         IDirect3DVertexDeclaration9_Release(vertex_declaration);
2543         return hr;
2544     }
2545 
2546     /* Create index buffer */
2547     hr = IDirect3DDevice9_CreateIndexBuffer(device,
2548                                             numfaces * 3 * ((index_format == D3DFMT_INDEX16) ? 2 : 4),
2549                                             index_usage,
2550                                             index_format,
2551                                             index_pool,
2552                                             &index_buffer,
2553                                             NULL);
2554     if (FAILED(hr))
2555     {
2556         WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
2557         IDirect3DVertexBuffer9_Release(vertex_buffer);
2558         IDirect3DVertexDeclaration9_Release(vertex_declaration);
2559         return hr;
2560     }
2561 
2562     attrib_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, numfaces * sizeof(*attrib_buffer));
2563     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2564     if (object == NULL || attrib_buffer == NULL)
2565     {
2566         HeapFree(GetProcessHeap(), 0, object);
2567         HeapFree(GetProcessHeap(), 0, attrib_buffer);
2568         IDirect3DIndexBuffer9_Release(index_buffer);
2569         IDirect3DVertexBuffer9_Release(vertex_buffer);
2570         IDirect3DVertexDeclaration9_Release(vertex_declaration);
2571         *mesh = NULL;
2572         return E_OUTOFMEMORY;
2573     }
2574     object->ID3DXMesh_iface.lpVtbl = &D3DXMesh_Vtbl;
2575     object->ref = 1;
2576 
2577     object->numfaces = numfaces;
2578     object->numvertices = numvertices;
2579     object->options = options;
2580     object->fvf = fvf;
2581     object->device = device;
2582     IDirect3DDevice9_AddRef(device);
2583 
2584     copy_declaration(object->cached_declaration, declaration, num_elem);
2585     object->vertex_declaration = vertex_declaration;
2586     object->vertex_declaration_size = vertex_declaration_size;
2587     object->num_elem = num_elem;
2588     object->vertex_buffer = vertex_buffer;
2589     object->index_buffer = index_buffer;
2590     object->attrib_buffer = attrib_buffer;
2591 
2592     *mesh = &object->ID3DXMesh_iface;
2593 
2594     return D3D_OK;
2595 }
2596 
2597 /*************************************************************************
2598  * D3DXCreateMeshFVF
2599  */
2600 HRESULT WINAPI D3DXCreateMeshFVF(DWORD numfaces, DWORD numvertices, DWORD options,
2601         DWORD fvf, struct IDirect3DDevice9 *device, struct ID3DXMesh **mesh)
2602 {
2603     HRESULT hr;
2604     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
2605 
2606     TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces, numvertices, options, fvf, device, mesh);
2607 
2608     hr = D3DXDeclaratorFromFVF(fvf, declaration);
2609     if (FAILED(hr)) return hr;
2610 
2611     return D3DXCreateMesh(numfaces, numvertices, options, declaration, device, mesh);
2612 }
2613 
2614 
2615 struct mesh_data {
2616     DWORD num_vertices;
2617     DWORD num_poly_faces;
2618     DWORD num_tri_faces;
2619     D3DXVECTOR3 *vertices;
2620     DWORD *num_tri_per_face;
2621     DWORD *indices;
2622 
2623     DWORD fvf;
2624 
2625     /* optional mesh data */
2626 
2627     DWORD num_normals;
2628     D3DXVECTOR3 *normals;
2629     DWORD *normal_indices;
2630 
2631     D3DXVECTOR2 *tex_coords;
2632 
2633     DWORD *vertex_colors;
2634 
2635     DWORD num_materials;
2636     D3DXMATERIAL *materials;
2637     DWORD *material_indices;
2638 
2639     struct ID3DXSkinInfo *skin_info;
2640     DWORD nb_bones;
2641 };
2642 
2643 static HRESULT parse_texture_filename(ID3DXFileData *filedata, char **filename_out)
2644 {
2645     HRESULT hr;
2646     SIZE_T data_size;
2647     BYTE *data;
2648     char *filename_in;
2649     char *filename = NULL;
2650 
2651     /* template TextureFilename {
2652      *     STRING filename;
2653      * }
2654      */
2655 
2656     HeapFree(GetProcessHeap(), 0, *filename_out);
2657     *filename_out = NULL;
2658 
2659     hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void**)&data);
2660     if (FAILED(hr)) return hr;
2661 
2662     /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
2663     if (data_size < sizeof(filename_in))
2664     {
2665         WARN("truncated data (%lu bytes)\n", data_size);
2666         filedata->lpVtbl->Unlock(filedata);
2667         return E_FAIL;
2668     }
2669     filename_in = *(char **)data;
2670 
2671     filename = HeapAlloc(GetProcessHeap(), 0, strlen(filename_in) + 1);
2672     if (!filename) {
2673         filedata->lpVtbl->Unlock(filedata);
2674         return E_OUTOFMEMORY;
2675     }
2676 
2677     strcpy(filename, filename_in);
2678     *filename_out = filename;
2679 
2680     filedata->lpVtbl->Unlock(filedata);
2681 
2682     return D3D_OK;
2683 }
2684 
2685 static HRESULT parse_material(ID3DXFileData *filedata, D3DXMATERIAL *material)
2686 {
2687     HRESULT hr;
2688     SIZE_T data_size;
2689     const BYTE *data;
2690     GUID type;
2691     ID3DXFileData *child;
2692     SIZE_T i, nb_children;
2693 
2694     material->pTextureFilename = NULL;
2695 
2696     hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void**)&data);
2697     if (FAILED(hr)) return hr;
2698 
2699     /*
2700      * template ColorRGBA {
2701      *     FLOAT red;
2702      *     FLOAT green;
2703      *     FLOAT blue;
2704      *     FLOAT alpha;
2705      * }
2706      * template ColorRGB {
2707      *     FLOAT red;
2708      *     FLOAT green;
2709      *     FLOAT blue;
2710      * }
2711      * template Material {
2712      *     ColorRGBA faceColor;
2713      *     FLOAT power;
2714      *     ColorRGB specularColor;
2715      *     ColorRGB emissiveColor;
2716      *     [ ... ]
2717      * }
2718      */
2719     if (data_size != sizeof(FLOAT) * 11) {
2720         WARN("incorrect data size (%ld bytes)\n", data_size);
2721         filedata->lpVtbl->Unlock(filedata);
2722         return E_FAIL;
2723     }
2724 
2725     memcpy(&material->MatD3D.Diffuse, data, sizeof(D3DCOLORVALUE));
2726     data += sizeof(D3DCOLORVALUE);
2727     material->MatD3D.Power = *(FLOAT*)data;
2728     data += sizeof(FLOAT);
2729     memcpy(&material->MatD3D.Specular, data, sizeof(FLOAT) * 3);
2730     material->MatD3D.Specular.a = 1.0f;
2731     data += 3 * sizeof(FLOAT);
2732     memcpy(&material->MatD3D.Emissive, data, sizeof(FLOAT) * 3);
2733     material->MatD3D.Emissive.a = 1.0f;
2734     material->MatD3D.Ambient.r = 0.0f;
2735     material->MatD3D.Ambient.g = 0.0f;
2736     material->MatD3D.Ambient.b = 0.0f;
2737     material->MatD3D.Ambient.a = 1.0f;
2738 
2739     filedata->lpVtbl->Unlock(filedata);
2740 
2741     hr = filedata->lpVtbl->GetChildren(filedata, &nb_children);
2742     if (FAILED(hr))
2743         return hr;
2744 
2745     for (i = 0; i < nb_children; i++)
2746     {
2747         hr = filedata->lpVtbl->GetChild(filedata, i, &child);
2748         if (FAILED(hr))
2749             return hr;
2750         hr = child->lpVtbl->GetType(child, &type);
2751         if (FAILED(hr))
2752             goto err;
2753 
2754         if (IsEqualGUID(&type, &TID_D3DRMTextureFilename)) {
2755             hr = parse_texture_filename(child, &material->pTextureFilename);
2756             if (FAILED(hr))
2757                 goto err;
2758         }
2759         IUnknown_Release(child);
2760     }
2761     return D3D_OK;
2762 
2763 err:
2764     IUnknown_Release(child);
2765     return hr;
2766 }
2767 
2768 static void destroy_materials(struct mesh_data *mesh)
2769 {
2770     DWORD i;
2771     for (i = 0; i < mesh->num_materials; i++)
2772         HeapFree(GetProcessHeap(), 0, mesh->materials[i].pTextureFilename);
2773     HeapFree(GetProcessHeap(), 0, mesh->materials);
2774     HeapFree(GetProcessHeap(), 0, mesh->material_indices);
2775     mesh->num_materials = 0;
2776     mesh->materials = NULL;
2777     mesh->material_indices = NULL;
2778 }
2779 
2780 static HRESULT parse_material_list(ID3DXFileData *filedata, struct mesh_data *mesh)
2781 {
2782     HRESULT hr;
2783     SIZE_T data_size;
2784     const DWORD *data, *in_ptr;
2785     GUID type;
2786     ID3DXFileData *child = NULL;
2787     DWORD num_materials;
2788     DWORD i;
2789     SIZE_T nb_children;
2790 
2791     destroy_materials(mesh);
2792 
2793     hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void**)&data);
2794     if (FAILED(hr)) return hr;
2795 
2796     /* template MeshMaterialList {
2797      *     DWORD nMaterials;
2798      *     DWORD nFaceIndexes;
2799      *     array DWORD faceIndexes[nFaceIndexes];
2800      *     [ Material ]
2801      * }
2802      */
2803 
2804     in_ptr = data;
2805     hr = E_FAIL;
2806 
2807     if (data_size < sizeof(DWORD)) {
2808         WARN("truncated data (%ld bytes)\n", data_size);
2809         goto end;
2810     }
2811     num_materials = *in_ptr++;
2812     if (!num_materials) {
2813         hr = D3D_OK;
2814         goto end;
2815     }
2816 
2817     if (data_size < 2 * sizeof(DWORD)) {
2818         WARN("truncated data (%ld bytes)\n", data_size);
2819         goto end;
2820     }
2821     if (*in_ptr++ != mesh->num_poly_faces) {
2822         WARN("number of material face indices (%u) doesn't match number of faces (%u)\n",
2823              *(in_ptr - 1), mesh->num_poly_faces);
2824         goto end;
2825     }
2826     if (data_size < 2 * sizeof(DWORD) + mesh->num_poly_faces * sizeof(DWORD)) {
2827         WARN("truncated data (%ld bytes)\n", data_size);
2828         goto end;
2829     }
2830     for (i = 0; i < mesh->num_poly_faces; i++) {
2831         if (*in_ptr++ >= num_materials) {
2832             WARN("face %u: reference to undefined material %u (only %u materials)\n",
2833                  i, *(in_ptr - 1), num_materials);
2834             goto end;
2835         }
2836     }
2837 
2838     mesh->materials = HeapAlloc(GetProcessHeap(), 0, num_materials * sizeof(*mesh->materials));
2839     mesh->material_indices = HeapAlloc(GetProcessHeap(), 0, mesh->num_poly_faces * sizeof(*mesh->material_indices));
2840     if (!mesh->materials || !mesh->material_indices) {
2841         hr = E_OUTOFMEMORY;
2842         goto end;
2843     }
2844     memcpy(mesh->material_indices, data + 2, mesh->num_poly_faces * sizeof(DWORD));
2845 
2846     hr = filedata->lpVtbl->GetChildren(filedata, &nb_children);
2847     if (FAILED(hr))
2848         goto end;
2849 
2850     for (i = 0; i < nb_children; i++)
2851     {
2852         hr = filedata->lpVtbl->GetChild(filedata, i, &child);
2853         if (FAILED(hr))
2854             goto end;
2855         hr = child->lpVtbl->GetType(child, &type);
2856         if (FAILED(hr))
2857             goto end;
2858 
2859         if (IsEqualGUID(&type, &TID_D3DRMMaterial)) {
2860             if (mesh->num_materials >= num_materials) {
2861                 WARN("more materials defined than declared\n");
2862                 hr = E_FAIL;
2863                 goto end;
2864             }
2865             hr = parse_material(child, &mesh->materials[mesh->num_materials++]);
2866             if (FAILED(hr))
2867                 goto end;
2868         }
2869 
2870         IUnknown_Release(child);
2871         child = NULL;
2872     }
2873     if (num_materials != mesh->num_materials) {
2874         WARN("only %u of %u materials defined\n", num_materials, mesh->num_materials);
2875         hr = E_FAIL;
2876     }
2877 
2878 end:
2879     if (child)
2880         IUnknown_Release(child);
2881     filedata->lpVtbl->Unlock(filedata);
2882     return hr;
2883 }
2884 
2885 static HRESULT parse_texture_coords(ID3DXFileData *filedata, struct mesh_data *mesh)
2886 {
2887     HRESULT hr;
2888     SIZE_T data_size;
2889     const BYTE *data;
2890 
2891     HeapFree(GetProcessHeap(), 0, mesh->tex_coords);
2892     mesh->tex_coords = NULL;
2893 
2894     hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void**)&data);
2895     if (FAILED(hr)) return hr;
2896 
2897     /* template Coords2d {
2898      *     FLOAT u;
2899      *     FLOAT v;
2900      * }
2901      * template MeshTextureCoords {
2902      *     DWORD nTextureCoords;
2903      *     array Coords2d textureCoords[nTextureCoords];
2904      * }
2905      */
2906 
2907     hr = E_FAIL;
2908 
2909     if (data_size < sizeof(DWORD)) {
2910         WARN("truncated data (%ld bytes)\n", data_size);
2911         goto end;
2912     }
2913     if (*(DWORD*)data != mesh->num_vertices) {
2914         WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2915              *(DWORD*)data, mesh->num_vertices);
2916         goto end;
2917     }
2918     data += sizeof(DWORD);
2919     if (data_size < sizeof(DWORD) + mesh->num_vertices * sizeof(*mesh->tex_coords)) {
2920         WARN("truncated data (%ld bytes)\n", data_size);
2921         goto end;
2922     }
2923 
2924     mesh->tex_coords = HeapAlloc(GetProcessHeap(), 0, mesh->num_vertices * sizeof(*mesh->tex_coords));
2925     if (!mesh->tex_coords) {
2926         hr = E_OUTOFMEMORY;
2927         goto end;
2928     }
2929     memcpy(mesh->tex_coords, data, mesh->num_vertices * sizeof(*mesh->tex_coords));
2930 
2931     mesh->fvf |= D3DFVF_TEX1;
2932 
2933     hr = D3D_OK;
2934 
2935 end:
2936     filedata->lpVtbl->Unlock(filedata);
2937     return hr;
2938 }
2939 
2940 static HRESULT parse_vertex_colors(ID3DXFileData *filedata, struct mesh_data *mesh)
2941 {
2942     HRESULT hr;
2943     SIZE_T data_size;
2944     const BYTE *data;
2945     DWORD num_colors;
2946     DWORD i;
2947 
2948     HeapFree(GetProcessHeap(), 0, mesh->vertex_colors);
2949     mesh->vertex_colors = NULL;
2950 
2951     hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void**)&data);
2952     if (FAILED(hr)) return hr;
2953 
2954     /* template IndexedColor {
2955      *     DWORD index;
2956      *     ColorRGBA indexColor;
2957      * }
2958      * template MeshVertexColors {
2959      *     DWORD nVertexColors;
2960      *     array IndexedColor vertexColors[nVertexColors];
2961      * }
2962      */
2963 
2964     hr = E_FAIL;
2965 
2966     if (data_size < sizeof(DWORD)) {
2967         WARN("truncated data (%ld bytes)\n", data_size);
2968         goto end;
2969     }
2970     num_colors = *(DWORD*)data;
2971     data += sizeof(DWORD);
2972     if (data_size < sizeof(DWORD) + num_colors * (sizeof(DWORD) + sizeof(D3DCOLORVALUE))) {
2973         WARN("truncated data (%ld bytes)\n", data_size);
2974         goto end;
2975     }
2976 
2977     mesh->vertex_colors = HeapAlloc(GetProcessHeap(), 0, mesh->num_vertices * sizeof(DWORD));
2978     if (!mesh->vertex_colors) {
2979         hr = E_OUTOFMEMORY;
2980         goto end;
2981     }
2982 
2983     for (i = 0; i < mesh->num_vertices; i++)
2984         mesh->vertex_colors[i] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2985     for (i = 0; i < num_colors; i++)
2986     {
2987         D3DCOLORVALUE color;
2988         DWORD index = *(DWORD*)data;
2989         data += sizeof(DWORD);
2990         if (index >= mesh->num_vertices) {
2991             WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2992                  i, index, mesh->num_vertices);
2993             goto end;
2994         }
2995         memcpy(&color, data, sizeof(color));
2996         data += sizeof(color);
2997         color.r = min(1.0f, max(0.0f, color.r));
2998         color.g = min(1.0f, max(0.0f, color.g));
2999         color.b = min(1.0f, max(0.0f, color.b));
3000         color.a = min(1.0f, max(0.0f, color.a));
3001         mesh->vertex_colors[index] = D3DCOLOR_ARGB((BYTE)(color.a * 255.0f + 0.5f),
3002                                                    (BYTE)(color.r * 255.0f + 0.5f),
3003                                                    (BYTE)(color.g * 255.0f + 0.5f),
3004                                                    (BYTE)(color.b * 255.0f + 0.5f));
3005     }
3006 
3007     mesh->fvf |= D3DFVF_DIFFUSE;
3008 
3009     hr = D3D_OK;
3010 
3011 end:
3012     filedata->lpVtbl->Unlock(filedata);
3013     return hr;
3014 }
3015 
3016 static HRESULT parse_normals(ID3DXFileData *filedata, struct mesh_data *mesh)
3017 {
3018     HRESULT hr;
3019     SIZE_T data_size;
3020     const BYTE *data;
3021     DWORD *index_out_ptr;
3022     DWORD i;
3023     DWORD num_face_indices = mesh->num_poly_faces * 2 + mesh->num_tri_faces;
3024 
3025     HeapFree(GetProcessHeap(), 0, mesh->normals);
3026     mesh->num_normals = 0;
3027     mesh->normals = NULL;
3028     mesh->normal_indices = NULL;
3029     mesh->fvf |= D3DFVF_NORMAL;
3030 
3031     hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void**)&data);
3032     if (FAILED(hr)) return hr;
3033 
3034     /* template Vector {
3035      *     FLOAT x;
3036      *     FLOAT y;
3037      *     FLOAT z;
3038      * }
3039      * template MeshFace {
3040      *     DWORD nFaceVertexIndices;
3041      *     array DWORD faceVertexIndices[nFaceVertexIndices];
3042      * }
3043      * template MeshNormals {
3044      *     DWORD nNormals;
3045      *     array Vector normals[nNormals];
3046      *     DWORD nFaceNormals;
3047      *     array MeshFace faceNormals[nFaceNormals];
3048      * }
3049      */
3050 
3051     hr = E_FAIL;
3052 
3053     if (data_size < sizeof(DWORD) * 2) {
3054         WARN("truncated data (%ld bytes)\n", data_size);
3055         goto end;
3056     }
3057     mesh->num_normals = *(DWORD*)data;
3058     data += sizeof(DWORD);
3059     if (data_size < sizeof(DWORD) * 2 + mesh->num_normals * sizeof(D3DXVECTOR3) +
3060                     num_face_indices * sizeof(DWORD)) {
3061         WARN("truncated data (%ld bytes)\n", data_size);
3062         goto end;
3063     }
3064 
3065     mesh->normals = HeapAlloc(GetProcessHeap(), 0, mesh->num_normals * sizeof(D3DXVECTOR3));
3066     mesh->normal_indices = HeapAlloc(GetProcessHeap(), 0, num_face_indices * sizeof(DWORD));
3067     if (!mesh->normals || !mesh->normal_indices) {
3068         hr = E_OUTOFMEMORY;
3069         goto end;
3070     }
3071 
3072     memcpy(mesh->normals, data, mesh->num_normals * sizeof(D3DXVECTOR3));
3073     data += mesh->num_normals * sizeof(D3DXVECTOR3);
3074     for (i = 0; i < mesh->num_normals; i++)
3075         D3DXVec3Normalize(&mesh->normals[i], &mesh->normals[i]);
3076 
3077     if (*(DWORD*)data != mesh->num_poly_faces) {
3078         WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
3079              *(DWORD*)data, mesh->num_poly_faces);
3080         goto end;
3081     }
3082     data += sizeof(DWORD);
3083     index_out_ptr = mesh->normal_indices;
3084     for (i = 0; i < mesh->num_poly_faces; i++)
3085     {
3086         DWORD j;
3087         DWORD count = *(DWORD*)data;
3088         if (count != mesh->num_tri_per_face[i] + 2) {
3089             WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
3090                  i, count, mesh->num_tri_per_face[i] + 2);
3091             goto end;
3092         }
3093         data += sizeof(DWORD);
3094 
3095         for (j = 0; j < count; j++) {
3096             DWORD normal_index = *(DWORD*)data;
3097             if (normal_index >= mesh->num_normals) {
3098                 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
3099                      i, j, normal_index, mesh->num_normals);
3100                 goto end;
3101             }
3102             *index_out_ptr++ = normal_index;
3103             data += sizeof(DWORD);
3104         }
3105     }
3106 
3107     hr =  D3D_OK;
3108 
3109 end:
3110     filedata->lpVtbl->Unlock(filedata);
3111     return hr;
3112 }
3113 
3114 static HRESULT parse_skin_mesh_info(ID3DXFileData *filedata, struct mesh_data *mesh_data, DWORD index)
3115 {
3116     HRESULT hr;
3117     SIZE_T data_size;
3118     const BYTE *data;
3119 
3120     TRACE("(%p, %p, %u)\n", filedata, mesh_data, index);
3121 
3122     hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void**)&data);
3123     if (FAILED(hr)) return hr;
3124 
3125     hr = E_FAIL;
3126 
3127     if (!mesh_data->skin_info) {
3128         if (data_size < sizeof(WORD) * 3) {
3129             WARN("truncated data (%ld bytes)\n", data_size);
3130             goto end;
3131         }
3132         /* Skip nMaxSkinWeightsPerVertex and nMaxSkinWeightsPerFace */
3133         data += 2 * sizeof(WORD);
3134         mesh_data->nb_bones = *(WORD*)data;
3135         hr = D3DXCreateSkinInfoFVF(mesh_data->num_vertices, mesh_data->fvf, mesh_data->nb_bones, &mesh_data->skin_info);
3136     } else {
3137         const char *name;
3138         DWORD nb_influences;
3139 
3140         /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
3141         name = *(const char**)data;
3142         data += sizeof(char*);
3143 
3144         nb_influences = *(DWORD*)data;
3145         data += sizeof(DWORD);
3146 
3147         if (data_size < (sizeof(char*) + sizeof(DWORD) + nb_influences * (sizeof(DWORD) + sizeof(FLOAT)) + 16 * sizeof(FLOAT))) {
3148             WARN("truncated data (%ld bytes)\n", data_size);
3149             goto end;
3150         }
3151 
3152         hr = mesh_data->skin_info->lpVtbl->SetBoneName(mesh_data->skin_info, index, name);
3153         if (SUCCEEDED(hr))
3154             hr = mesh_data->skin_info->lpVtbl->SetBoneInfluence(mesh_data->skin_info, index, nb_influences,
3155                      (const DWORD*)data, (const FLOAT*)(data + nb_influences * sizeof(DWORD)));
3156         if (SUCCEEDED(hr))
3157             hr = mesh_data->skin_info->lpVtbl->SetBoneOffsetMatrix(mesh_data->skin_info, index,
3158                      (const D3DMATRIX*)(data + nb_influences * (sizeof(DWORD) + sizeof(FLOAT))));
3159     }
3160 
3161 end:
3162     filedata->lpVtbl->Unlock(filedata);
3163     return hr;
3164 }
3165 
3166 /* for provide_flags parameters */
3167 #define PROVIDE_MATERIALS 0x1
3168 #define PROVIDE_SKININFO  0x2
3169 #define PROVIDE_ADJACENCY 0x4
3170 
3171 static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, DWORD provide_flags)
3172 {
3173     HRESULT hr;
3174     SIZE_T data_size;
3175     const BYTE *data, *in_ptr;
3176     DWORD *index_out_ptr;
3177     GUID type;
3178     ID3DXFileData *child = NULL;
3179     DWORD i;
3180     SIZE_T nb_children;
3181     DWORD nb_skin_weights_info = 0;
3182 
3183     /*
3184      * template Mesh {
3185      *     DWORD nVertices;
3186      *     array Vector vertices[nVertices];
3187      *     DWORD nFaces;
3188      *     array MeshFace faces[nFaces];
3189      *     [ ... ]
3190      * }
3191      */
3192 
3193     hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void**)&data);
3194     if (FAILED(hr)) return hr;
3195 
3196     in_ptr = data;
3197     hr = E_FAIL;
3198 
3199     if (data_size < sizeof(DWORD) * 2) {
3200         WARN("truncated data (%ld bytes)\n", data_size);
3201         goto end;
3202     }
3203     mesh_data->num_vertices = *(DWORD*)in_ptr;
3204     if (data_size < sizeof(DWORD) * 2 + mesh_data->num_vertices * sizeof(D3DXVECTOR3)) {
3205         WARN("truncated data (%ld bytes)\n", data_size);
3206         goto end;
3207     }
3208     in_ptr += sizeof(DWORD) + mesh_data->num_vertices * sizeof(D3DXVECTOR3);
3209 
3210     mesh_data->num_poly_faces = *(DWORD*)in_ptr;
3211     in_ptr += sizeof(DWORD);
3212 
3213     mesh_data->num_tri_faces = 0;
3214     for (i = 0; i < mesh_data->num_poly_faces; i++)
3215     {
3216         DWORD num_poly_vertices;
3217         DWORD j;
3218 
3219         if (data_size - (in_ptr - data) < sizeof(DWORD)) {
3220             WARN("truncated data (%ld bytes)\n", data_size);
3221             goto end;
3222         }
3223         num_poly_vertices = *(DWORD*)in_ptr;
3224         in_ptr += sizeof(DWORD);
3225         if (data_size - (in_ptr - data) < num_poly_vertices * sizeof(DWORD)) {
3226             WARN("truncated data (%ld bytes)\n", data_size);
3227             goto end;
3228         }
3229         if (num_poly_vertices < 3) {
3230             WARN("face %u has only %u vertices\n", i, num_poly_vertices);
3231             goto end;
3232         }
3233         for (j = 0; j < num_poly_vertices; j++) {
3234             if (*(DWORD*)in_ptr >= mesh_data->num_vertices) {
3235                 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
3236                      i, j, *(DWORD*)in_ptr, mesh_data->num_vertices);
3237                 goto end;
3238             }
3239             in_ptr += sizeof(DWORD);
3240         }
3241         mesh_data->num_tri_faces += num_poly_vertices - 2;
3242     }
3243 
3244     mesh_data->fvf = D3DFVF_XYZ;
3245 
3246     mesh_data->vertices = HeapAlloc(GetProcessHeap(), 0,
3247             mesh_data->num_vertices * sizeof(*mesh_data->vertices));
3248     mesh_data->num_tri_per_face = HeapAlloc(GetProcessHeap(), 0,
3249             mesh_data->num_poly_faces * sizeof(*mesh_data->num_tri_per_face));
3250     mesh_data->indices = HeapAlloc(GetProcessHeap(), 0,
3251             (mesh_data->num_tri_faces + mesh_data->num_poly_faces * 2) * sizeof(*mesh_data->indices));
3252     if (!mesh_data->vertices || !mesh_data->num_tri_per_face || !mesh_data->indices) {
3253         hr = E_OUTOFMEMORY;
3254         goto end;
3255     }
3256 
3257     in_ptr = data + sizeof(DWORD);
3258     memcpy(mesh_data->vertices, in_ptr, mesh_data->num_vertices * sizeof(D3DXVECTOR3));
3259     in_ptr += mesh_data->num_vertices * sizeof(D3DXVECTOR3) + sizeof(DWORD);
3260 
3261     index_out_ptr = mesh_data->indices;
3262     for (i = 0; i < mesh_data->num_poly_faces; i++)
3263     {
3264         DWORD count;
3265 
3266         count = *(DWORD*)in_ptr;
3267         in_ptr += sizeof(DWORD);
3268         mesh_data->num_tri_per_face[i] = count - 2;
3269 
3270         while (count--) {
3271             *index_out_ptr++ = *(DWORD*)in_ptr;
3272             in_ptr += sizeof(DWORD);
3273         }
3274     }
3275 
3276     hr = filedata->lpVtbl->GetChildren(filedata, &nb_children);
3277     if (FAILED(hr))
3278         goto end;
3279 
3280     for (i = 0; i < nb_children; i++)
3281     {
3282         hr = filedata->lpVtbl->GetChild(filedata, i, &child);
3283         if (FAILED(hr))
3284             goto end;
3285         hr = child->lpVtbl->GetType(child, &type);
3286         if (FAILED(hr))
3287             goto end;
3288 
3289         if (IsEqualGUID(&type, &TID_D3DRMMeshNormals)) {
3290             hr = parse_normals(child, mesh_data);
3291         } else if (IsEqualGUID(&type, &TID_D3DRMMeshVertexColors)) {
3292             hr = parse_vertex_colors(child, mesh_data);
3293         } else if (IsEqualGUID(&type, &TID_D3DRMMeshTextureCoords)) {
3294             hr = parse_texture_coords(child, mesh_data);
3295         } else if (IsEqualGUID(&type, &TID_D3DRMMeshMaterialList) &&
3296                    (provide_flags & PROVIDE_MATERIALS))
3297         {
3298             hr = parse_material_list(child, mesh_data);
3299         } else if (provide_flags & PROVIDE_SKININFO) {
3300             if (IsEqualGUID(&type, &DXFILEOBJ_XSkinMeshHeader)) {
3301                 if (mesh_data->skin_info) {
3302                     WARN("Skin mesh header already encountered\n");
3303                     hr = E_FAIL;
3304                     goto end;
3305                 }
3306                 hr = parse_skin_mesh_info(child, mesh_data, 0);
3307                 if (FAILED(hr))
3308                     goto end;
3309             } else if (IsEqualGUID(&type, &DXFILEOBJ_SkinWeights)) {
3310                 if (!mesh_data->skin_info) {
3311                     WARN("Skin weights found but skin mesh header not encountered yet\n");
3312                     hr = E_FAIL;
3313                     goto end;
3314                 }
3315                 hr = parse_skin_mesh_info(child, mesh_data, nb_skin_weights_info);
3316                 if (FAILED(hr))
3317                     goto end;
3318                 nb_skin_weights_info++;
3319             }
3320         }
3321         if (FAILED(hr))
3322             goto end;
3323 
3324         IUnknown_Release(child);
3325         child = NULL;
3326     }
3327 
3328     if (mesh_data->skin_info && (nb_skin_weights_info != mesh_data->nb_bones)) {
3329         WARN("Mismatch between nb skin weights info %u encountered and nb bones %u from skin mesh header\n",
3330              nb_skin_weights_info, mesh_data->nb_bones);
3331         hr = E_FAIL;
3332         goto end;
3333     }
3334 
3335     hr = D3D_OK;
3336 
3337 end:
3338     if (child)
3339         IUnknown_Release(child);
3340     filedata->lpVtbl->Unlock(filedata);
3341     return hr;
3342 }
3343 
3344 static HRESULT generate_effects(ID3DXBuffer *materials, DWORD num_materials,
3345                                 ID3DXBuffer **effects)
3346 {
3347     HRESULT hr;
3348     D3DXEFFECTINSTANCE *effect_ptr;
3349     BYTE *out_ptr;
3350     const D3DXMATERIAL *material_ptr = ID3DXBuffer_GetBufferPointer(materials);
3351     static const struct {
3352         const char *param_name;
3353         DWORD name_size;
3354         DWORD num_bytes;
3355         DWORD value_offset;
3356     } material_effects[] = {
3357 #define EFFECT_TABLE_ENTRY(str, field) \
3358     {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
3359         EFFECT_TABLE_ENTRY("Diffuse", Diffuse),
3360         EFFECT_TABLE_ENTRY("Power", Power),
3361         EFFECT_TABLE_ENTRY("Specular", Specular),
3362         EFFECT_TABLE_ENTRY("Emissive", Emissive),
3363         EFFECT_TABLE_ENTRY("Ambient", Ambient),
3364 #undef EFFECT_TABLE_ENTRY
3365     };
3366     static const char texture_paramname[] = "Texture0@Name";
3367     DWORD buffer_size;
3368     DWORD i;
3369 
3370     /* effects buffer layout:
3371      *
3372      * D3DXEFFECTINSTANCE effects[num_materials];
3373      * for (effect in effects)
3374      * {
3375      *     D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
3376      *     for (default in defaults)
3377      *     {
3378      *         *default.pParamName;
3379      *         *default.pValue;
3380      *     }
3381      * }
3382      */
3383     buffer_size = sizeof(D3DXEFFECTINSTANCE);
3384     buffer_size += sizeof(D3DXEFFECTDEFAULT) * ARRAY_SIZE(material_effects);
3385     for (i = 0; i < ARRAY_SIZE(material_effects); i++) {
3386         buffer_size += material_effects[i].name_size;
3387         buffer_size += material_effects[i].num_bytes;
3388     }
3389     buffer_size *= num_materials;
3390     for (i = 0; i < num_materials; i++) {
3391         if (material_ptr[i].pTextureFilename) {
3392             buffer_size += sizeof(D3DXEFFECTDEFAULT);
3393             buffer_size += sizeof(texture_paramname);
3394             buffer_size += strlen(material_ptr[i].pTextureFilename) + 1;
3395         }
3396     }
3397 
3398     hr = D3DXCreateBuffer(buffer_size, effects);
3399     if (FAILED(hr)) return hr;
3400     effect_ptr = ID3DXBuffer_GetBufferPointer(*effects);
3401     out_ptr = (BYTE*)(effect_ptr + num_materials);
3402 
3403     for (i = 0; i < num_materials; i++)
3404     {
3405         DWORD j;
3406         D3DXEFFECTDEFAULT *defaults = (D3DXEFFECTDEFAULT*)out_ptr;
3407 
3408         effect_ptr->pDefaults = defaults;
3409         effect_ptr->NumDefaults = material_ptr->pTextureFilename ? 6 : 5;
3410         out_ptr = (BYTE*)(effect_ptr->pDefaults + effect_ptr->NumDefaults);
3411 
3412         for (j = 0; j < ARRAY_SIZE(material_effects); j++)
3413         {
3414             defaults->pParamName = (char *)out_ptr;
3415             strcpy(defaults->pParamName, material_effects[j].param_name);
3416             defaults->pValue = defaults->pParamName + material_effects[j].name_size;
3417             defaults->Type = D3DXEDT_FLOATS;
3418             defaults->NumBytes = material_effects[j].num_bytes;
3419             memcpy(defaults->pValue, (BYTE*)material_ptr + material_effects[j].value_offset, defaults->NumBytes);
3420             out_ptr = (BYTE*)defaults->pValue + defaults->NumBytes;
3421             defaults++;
3422         }
3423 
3424         if (material_ptr->pTextureFilename)
3425         {
3426             defaults->pParamName = (char *)out_ptr;
3427             strcpy(defaults->pParamName, texture_paramname);
3428             defaults->pValue = defaults->pParamName + sizeof(texture_paramname);
3429             defaults->Type = D3DXEDT_STRING;
3430             defaults->NumBytes = strlen(material_ptr->pTextureFilename) + 1;
3431             strcpy(defaults->pValue, material_ptr->pTextureFilename);
3432             out_ptr = (BYTE*)defaults->pValue + defaults->NumBytes;
3433         }
3434         material_ptr++;
3435         effect_ptr++;
3436     }
3437     assert(out_ptr - (BYTE*)ID3DXBuffer_GetBufferPointer(*effects) == buffer_size);
3438 
3439     return D3D_OK;
3440 }
3441 
3442 HRESULT WINAPI D3DXLoadSkinMeshFromXof(struct ID3DXFileData *filedata, DWORD options,
3443         struct IDirect3DDevice9 *device, struct ID3DXBuffer **adjacency_out, struct ID3DXBuffer **materials_out,
3444         struct ID3DXBuffer **effects_out, DWORD *num_materials_out, struct ID3DXSkinInfo **skin_info_out,
3445         struct ID3DXMesh **mesh_out)
3446 {
3447     HRESULT hr;
3448     DWORD *index_in_ptr;
3449     struct mesh_data mesh_data;
3450     DWORD total_vertices;
3451     ID3DXMesh *d3dxmesh = NULL;
3452     ID3DXBuffer *adjacency = NULL;
3453     ID3DXBuffer *materials = NULL;
3454     ID3DXBuffer *effects = NULL;
3455     struct vertex_duplication {
3456         DWORD normal_index;
3457         struct list entry;
3458     } *duplications = NULL;
3459     DWORD i;
3460     void *vertices = NULL;
3461     void *indices = NULL;
3462     BYTE *out_ptr;
3463     DWORD provide_flags = 0;
3464 
3465     TRACE("(%p, %x, %p, %p, %p, %p, %p, %p, %p)\n", filedata, options, device, adjacency_out, materials_out,
3466           effects_out, num_materials_out, skin_info_out, mesh_out);
3467 
3468     ZeroMemory(&mesh_data, sizeof(mesh_data));
3469 
3470     if (num_materials_out || materials_out || effects_out)
3471         provide_flags |= PROVIDE_MATERIALS;
3472     if (skin_info_out)
3473         provide_flags |= PROVIDE_SKININFO;
3474 
3475     hr = parse_mesh(filedata, &mesh_data, provide_flags);
3476     if (FAILED(hr)) goto cleanup;
3477 
3478     total_vertices = mesh_data.num_vertices;
3479     if (mesh_data.fvf & D3DFVF_NORMAL) {
3480         /* duplicate vertices with multiple normals */
3481         DWORD num_face_indices = mesh_data.num_poly_faces * 2 + mesh_data.num_tri_faces;
3482         duplications = HeapAlloc(GetProcessHeap(), 0, (mesh_data.num_vertices + num_face_indices) * sizeof(*duplications));
3483         if (!duplications) {
3484             hr = E_OUTOFMEMORY;
3485             goto cleanup;
3486         }
3487         for (i = 0; i < total_vertices; i++)
3488         {
3489             duplications[i].normal_index = -1;
3490             list_init(&duplications[i].entry);
3491         }
3492         for (i = 0; i < num_face_indices; i++) {
3493             DWORD vertex_index = mesh_data.indices[i];
3494             DWORD normal_index = mesh_data.normal_indices[i];
3495             struct vertex_duplication *dup_ptr = &duplications[vertex_index];
3496 
3497             if (dup_ptr->normal_index == -1) {
3498                 dup_ptr->normal_index = normal_index;
3499             } else {
3500                 D3DXVECTOR3 *new_normal = &mesh_data.normals[normal_index];
3501                 struct list *dup_list = &dup_ptr->entry;
3502                 while (TRUE) {
3503                     D3DXVECTOR3 *cur_normal = &mesh_data.normals[dup_ptr->normal_index];
3504                     if (new_normal->x == cur_normal->x &&
3505                         new_normal->y == cur_normal->y &&
3506                         new_normal->z == cur_normal->z)
3507                     {
3508                         mesh_data.indices[i] = dup_ptr - duplications;
3509                         break;
3510                     } else if (!list_next(dup_list, &dup_ptr->entry)) {
3511                         dup_ptr = &duplications[total_vertices++];
3512                         dup_ptr->normal_index = normal_index;
3513                         list_add_tail(dup_list, &dup_ptr->entry);
3514                         mesh_data.indices[i] = dup_ptr - duplications;
3515                         break;
3516                     } else {
3517                         dup_ptr = LIST_ENTRY(list_next(dup_list, &dup_ptr->entry),
3518                                              struct vertex_duplication, entry);
3519                     }
3520                 }
3521             }
3522         }
3523     }
3524 
3525     hr = D3DXCreateMeshFVF(mesh_data.num_tri_faces, total_vertices, options, mesh_data.fvf, device, &d3dxmesh);
3526     if (FAILED(hr)) goto cleanup;
3527 
3528     hr = d3dxmesh->lpVtbl->LockVertexBuffer(d3dxmesh, 0, &vertices);
3529     if (FAILED(hr)) goto cleanup;
3530 
3531     out_ptr = vertices;
3532     for (i = 0; i < mesh_data.num_vertices; i++) {
3533         *(D3DXVECTOR3*)out_ptr = mesh_data.vertices[i];
3534         out_ptr += sizeof(D3DXVECTOR3);
3535         if (mesh_data.fvf & D3DFVF_NORMAL) {
3536             if (duplications[i].normal_index == -1)
3537                 ZeroMemory(out_ptr, sizeof(D3DXVECTOR3));
3538             else
3539                 *(D3DXVECTOR3*)out_ptr = mesh_data.normals[duplications[i].normal_index];
3540             out_ptr += sizeof(D3DXVECTOR3);
3541         }
3542         if (mesh_data.fvf & D3DFVF_DIFFUSE) {
3543             *(DWORD*)out_ptr = mesh_data.vertex_colors[i];
3544             out_ptr += sizeof(DWORD);
3545         }
3546         if (mesh_data.fvf & D3DFVF_TEX1) {
3547             *(D3DXVECTOR2*)out_ptr = mesh_data.tex_coords[i];
3548             out_ptr += sizeof(D3DXVECTOR2);
3549         }
3550     }
3551     if (mesh_data.fvf & D3DFVF_NORMAL) {
3552         DWORD vertex_size = D3DXGetFVFVertexSize(mesh_data.fvf);
3553         out_ptr = vertices;
3554         for (i = 0; i < mesh_data.num_vertices; i++) {
3555             struct vertex_duplication *dup_ptr;
3556             LIST_FOR_EACH_ENTRY(dup_ptr, &duplications[i].entry, struct vertex_duplication, entry)
3557             {
3558                 int j = dup_ptr - duplications;
3559                 BYTE *dest_vertex = (BYTE*)vertices + j * vertex_size;
3560 
3561                 memcpy(dest_vertex, out_ptr, vertex_size);
3562                 dest_vertex += sizeof(D3DXVECTOR3);
3563                 *(D3DXVECTOR3*)dest_vertex = mesh_data.normals[dup_ptr->normal_index];
3564             }
3565             out_ptr += vertex_size;
3566         }
3567     }
3568     d3dxmesh->lpVtbl->UnlockVertexBuffer(d3dxmesh);
3569 
3570     hr = d3dxmesh->lpVtbl->LockIndexBuffer(d3dxmesh, 0, &indices);
3571     if (FAILED(hr)) goto cleanup;
3572 
3573     index_in_ptr = mesh_data.indices;
3574 #define FILL_INDEX_BUFFER(indices_var) \
3575         for (i = 0; i < mesh_data.num_poly_faces; i++) \
3576         { \
3577             DWORD count = mesh_data.num_tri_per_face[i]; \
3578             WORD first_index = *index_in_ptr++; \
3579             while (count--) { \
3580                 *indices_var++ = first_index; \
3581                 *indices_var++ = *index_in_ptr; \
3582                 index_in_ptr++; \
3583                 *indices_var++ = *index_in_ptr; \
3584             } \
3585             index_in_ptr++; \
3586         }
3587     if (options & D3DXMESH_32BIT) {
3588         DWORD *dword_indices = indices;
3589         FILL_INDEX_BUFFER(dword_indices)
3590     } else {
3591         WORD *word_indices = indices;
3592         FILL_INDEX_BUFFER(word_indices)
3593     }
3594 #undef FILL_INDEX_BUFFER
3595     d3dxmesh->lpVtbl->UnlockIndexBuffer(d3dxmesh);
3596 
3597     if (mesh_data.material_indices) {
3598         DWORD *attrib_buffer = NULL;
3599         hr = d3dxmesh->lpVtbl->LockAttributeBuffer(d3dxmesh, 0, &attrib_buffer);
3600         if (FAILED(hr)) goto cleanup;
3601         for (i = 0; i < mesh_data.num_poly_faces; i++)
3602         {
3603             DWORD count = mesh_data.num_tri_per_face[i];
3604             while (count--)
3605                 *attrib_buffer++ = mesh_data.material_indices[i];
3606         }
3607         d3dxmesh->lpVtbl->UnlockAttributeBuffer(d3dxmesh);
3608 
3609         hr = d3dxmesh->lpVtbl->OptimizeInplace(d3dxmesh,
3610                 D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_IGNOREVERTS | D3DXMESHOPT_DONOTSPLIT,
3611                 NULL, NULL, NULL, NULL);
3612         if (FAILED(hr)) goto cleanup;
3613     }
3614 
3615     if (mesh_data.num_materials && (materials_out || effects_out)) {
3616         DWORD buffer_size = mesh_data.num_materials * sizeof(D3DXMATERIAL);
3617         char *strings_out_ptr;
3618         D3DXMATERIAL *materials_ptr;
3619 
3620         for (i = 0; i < mesh_data.num_materials; i++) {
3621             if (mesh_data.materials[i].pTextureFilename)
3622                 buffer_size += strlen(mesh_data.materials[i].pTextureFilename) + 1;
3623         }
3624 
3625         hr = D3DXCreateBuffer(buffer_size, &materials);
3626         if (FAILED(hr)) goto cleanup;
3627 
3628         materials_ptr = ID3DXBuffer_GetBufferPointer(materials);
3629         memcpy(materials_ptr, mesh_data.materials, mesh_data.num_materials * sizeof(D3DXMATERIAL));
3630         strings_out_ptr = (char*)(materials_ptr + mesh_data.num_materials);
3631         for (i = 0; i < mesh_data.num_materials; i++) {
3632             if (materials_ptr[i].pTextureFilename) {
3633                 strcpy(strings_out_ptr, mesh_data.materials[i].pTextureFilename);
3634                 materials_ptr[i].pTextureFilename = strings_out_ptr;
3635                 strings_out_ptr += strlen(mesh_data.materials[i].pTextureFilename) + 1;
3636             }
3637         }
3638     }
3639 
3640     if (mesh_data.num_materials && effects_out) {
3641         hr = generate_effects(materials, mesh_data.num_materials, &effects);
3642         if (FAILED(hr)) goto cleanup;
3643 
3644         if (!materials_out) {
3645             ID3DXBuffer_Release(materials);
3646             materials = NULL;
3647         }
3648     }
3649 
3650     if (adjacency_out) {
3651         hr = D3DXCreateBuffer(mesh_data.num_tri_faces * 3 * sizeof(DWORD), &adjacency);
3652         if (FAILED(hr)) goto cleanup;
3653         hr = d3dxmesh->lpVtbl->GenerateAdjacency(d3dxmesh, 0.0f, ID3DXBuffer_GetBufferPointer(adjacency));
3654         if (FAILED(hr)) goto cleanup;
3655     }
3656 
3657     *mesh_out = d3dxmesh;
3658     if (adjacency_out) *adjacency_out = adjacency;
3659     if (num_materials_out) *num_materials_out = mesh_data.num_materials;
3660     if (materials_out) *materials_out = materials;
3661     if (effects_out) *effects_out = effects;
3662     if (skin_info_out) *skin_info_out = mesh_data.skin_info;
3663 
3664     hr = D3D_OK;
3665 cleanup:
3666     if (FAILED(hr)) {
3667         if (d3dxmesh) IUnknown_Release(d3dxmesh);
3668         if (adjacency) ID3DXBuffer_Release(adjacency);
3669         if (materials) ID3DXBuffer_Release(materials);
3670         if (effects) ID3DXBuffer_Release(effects);
3671         if (mesh_data.skin_info) mesh_data.skin_info->lpVtbl->Release(mesh_data.skin_info);
3672         if (skin_info_out) *skin_info_out = NULL;
3673     }
3674     HeapFree(GetProcessHeap(), 0, mesh_data.vertices);
3675     HeapFree(GetProcessHeap(), 0, mesh_data.num_tri_per_face);
3676     HeapFree(GetProcessHeap(), 0, mesh_data.indices);
3677     HeapFree(GetProcessHeap(), 0, mesh_data.normals);
3678     HeapFree(GetProcessHeap(), 0, mesh_data.normal_indices);
3679     destroy_materials(&mesh_data);
3680     HeapFree(GetProcessHeap(), 0, mesh_data.tex_coords);
3681     HeapFree(GetProcessHeap(), 0, mesh_data.vertex_colors);
3682     HeapFree(GetProcessHeap(), 0, duplications);
3683     return hr;
3684 }
3685 
3686 HRESULT WINAPI D3DXLoadMeshHierarchyFromXA(const char *filename, DWORD options, struct IDirect3DDevice9 *device,
3687         struct ID3DXAllocateHierarchy *alloc_hier, struct ID3DXLoadUserData *load_user_data,
3688         D3DXFRAME **frame_hierarchy, struct ID3DXAnimationController **anim_controller)
3689 {
3690     WCHAR *filenameW;
3691     HRESULT hr;
3692     int len;
3693 
3694     TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3695             "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3696             debugstr_a(filename), options, device, alloc_hier,
3697             load_user_data, frame_hierarchy, anim_controller);
3698 
3699     if (!filename)
3700         return D3DERR_INVALIDCALL;
3701 
3702     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
3703     filenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3704     if (!filenameW) return E_OUTOFMEMORY;
3705     MultiByteToWideChar(CP_ACP, 0, filename, -1, filenameW, len);
3706 
3707     hr = D3DXLoadMeshHierarchyFromXW(filenameW, options, device,
3708             alloc_hier, load_user_data, frame_hierarchy, anim_controller);
3709     HeapFree(GetProcessHeap(), 0, filenameW);
3710 
3711     return hr;
3712 }
3713 
3714 HRESULT WINAPI D3DXLoadMeshHierarchyFromXW(const WCHAR *filename, DWORD options, struct IDirect3DDevice9 *device,
3715         struct ID3DXAllocateHierarchy *alloc_hier, struct ID3DXLoadUserData *load_user_data,
3716         D3DXFRAME **frame_hierarchy, struct ID3DXAnimationController **anim_controller)
3717 {
3718     void *buffer;
3719     HRESULT hr;
3720     DWORD size;
3721 
3722     TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3723             "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3724             debugstr_w(filename), options, device, alloc_hier,
3725             load_user_data, frame_hierarchy, anim_controller);
3726 
3727     if (!filename)
3728         return D3DERR_INVALIDCALL;
3729 
3730     hr = map_view_of_file(filename, &buffer, &size);
3731     if (FAILED(hr))
3732         return D3DXERR_INVALIDDATA;
3733 
3734     hr = D3DXLoadMeshHierarchyFromXInMemory(buffer, size, options, device,
3735             alloc_hier, load_user_data, frame_hierarchy, anim_controller);
3736 
3737     UnmapViewOfFile(buffer);
3738 
3739     return hr;
3740 }
3741 
3742 static HRESULT filedata_get_name(ID3DXFileData *filedata, char **name)
3743 {
3744     HRESULT hr;
3745     SIZE_T name_len;
3746 
3747     hr = filedata->lpVtbl->GetName(filedata, NULL, &name_len);
3748     if (FAILED(hr)) return hr;
3749 
3750     if (!name_len)
3751         name_len++;
3752     *name = HeapAlloc(GetProcessHeap(), 0, name_len);
3753     if (!*name) return E_OUTOFMEMORY;
3754 
3755     hr = filedata->lpVtbl->GetName(filedata, *name, &name_len);
3756     if (FAILED(hr))
3757         HeapFree(GetProcessHeap(), 0, *name);
3758     else if (!name_len)
3759         (*name)[0] = 0;
3760 
3761     return hr;
3762 }
3763 
3764 static HRESULT load_mesh_container(struct ID3DXFileData *filedata, DWORD options, struct IDirect3DDevice9 *device,
3765         struct ID3DXAllocateHierarchy *alloc_hier, D3DXMESHCONTAINER **mesh_container)
3766 {
3767     HRESULT hr;
3768     ID3DXBuffer *adjacency = NULL;
3769     ID3DXBuffer *materials = NULL;
3770     ID3DXBuffer *effects = NULL;
3771     ID3DXSkinInfo *skin_info = NULL;
3772     D3DXMESHDATA mesh_data;
3773     DWORD num_materials = 0;
3774     char *name = NULL;
3775 
3776     mesh_data.Type = D3DXMESHTYPE_MESH;
3777     mesh_data.u.pMesh = NULL;
3778 
3779     hr = D3DXLoadSkinMeshFromXof(filedata, options, device,
3780             &adjacency, &materials, &effects, &num_materials,
3781             &skin_info, &mesh_data.u.pMesh);
3782     if (FAILED(hr)) return hr;
3783 
3784     hr = filedata_get_name(filedata, &name);
3785     if (FAILED(hr)) goto cleanup;
3786 
3787     hr = alloc_hier->lpVtbl->CreateMeshContainer(alloc_hier, name, &mesh_data,
3788             materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL,
3789             effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL,
3790             num_materials,
3791             adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL,
3792             skin_info, mesh_container);
3793 
3794 cleanup:
3795     if (materials) ID3DXBuffer_Release(materials);
3796     if (effects) ID3DXBuffer_Release(effects);
3797     if (adjacency) ID3DXBuffer_Release(adjacency);
3798     if (skin_info) IUnknown_Release(skin_info);
3799     if (mesh_data.u.pMesh) IUnknown_Release(mesh_data.u.pMesh);
3800     HeapFree(GetProcessHeap(), 0, name);
3801     return hr;
3802 }
3803 
3804 static HRESULT parse_transform_matrix(ID3DXFileData *filedata, D3DXMATRIX *transform)
3805 {
3806     HRESULT hr;
3807     SIZE_T data_size;
3808     const BYTE *data;
3809 
3810     /* template Matrix4x4 {
3811      *     array FLOAT matrix[16];
3812      * }
3813      * template FrameTransformMatrix {
3814      *     Matrix4x4 frameMatrix;
3815      * }
3816      */
3817 
3818     hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void**)&data);
3819     if (FAILED(hr)) return hr;
3820 
3821     if (data_size != sizeof(D3DXMATRIX)) {
3822         WARN("incorrect data size (%ld bytes)\n", data_size);
3823         filedata->lpVtbl->Unlock(filedata);
3824         return E_FAIL;
3825     }
3826 
3827     memcpy(transform, data, sizeof(D3DXMATRIX));
3828 
3829     filedata->lpVtbl->Unlock(filedata);
3830     return D3D_OK;
3831 }
3832 
3833 static HRESULT load_frame(struct ID3DXFileData *filedata, DWORD options, struct IDirect3DDevice9 *device,
3834         struct ID3DXAllocateHierarchy *alloc_hier, D3DXFRAME **frame_out)
3835 {
3836     HRESULT hr;
3837     GUID type;
3838     ID3DXFileData *child;
3839     char *name = NULL;
3840     D3DXFRAME *frame = NULL;
3841     D3DXMESHCONTAINER **next_container;
3842     D3DXFRAME **next_child;
3843     SIZE_T i, nb_children;
3844 
3845     hr = filedata_get_name(filedata, &name);
3846     if (FAILED(hr)) return hr;
3847 
3848     hr = alloc_hier->lpVtbl->CreateFrame(alloc_hier, name, frame_out);
3849     HeapFree(GetProcessHeap(), 0, name);
3850     if (FAILED(hr)) return E_FAIL;
3851 
3852     frame = *frame_out;
3853     D3DXMatrixIdentity(&frame->TransformationMatrix);
3854     next_child = &frame->pFrameFirstChild;
3855     next_container = &frame->pMeshContainer;
3856 
3857     hr = filedata->lpVtbl->GetChildren(filedata, &nb_children);
3858     if (FAILED(hr))
3859         return hr;
3860 
3861     for (i = 0; i < nb_children; i++)
3862     {
3863         hr = filedata->lpVtbl->GetChild(filedata, i, &child);
3864         if (FAILED(hr))
3865             return hr;
3866         hr = child->lpVtbl->GetType(child, &type);
3867         if (FAILED(hr))
3868             goto err;
3869 
3870         if (IsEqualGUID(&type, &TID_D3DRMMesh)) {
3871             hr = load_mesh_container(child, options, device, alloc_hier, next_container);
3872             if (SUCCEEDED(hr))
3873                 next_container = &(*next_container)->pNextMeshContainer;
3874         } else if (IsEqualGUID(&type, &TID_D3DRMFrameTransformMatrix)) {
3875             hr = parse_transform_matrix(child, &frame->TransformationMatrix);
3876         } else if (IsEqualGUID(&type, &TID_D3DRMFrame)) {
3877             hr = load_frame(child, options, device, alloc_hier, next_child);
3878             if (SUCCEEDED(hr))
3879                 next_child = &(*next_child)->pFrameSibling;
3880         }
3881         if (FAILED(hr))
3882             goto err;
3883 
3884         IUnknown_Release(child);
3885     }
3886     return D3D_OK;
3887 
3888 err:
3889     IUnknown_Release(child);
3890     return hr;
3891 }
3892 
3893 HRESULT WINAPI D3DXLoadMeshHierarchyFromXInMemory(const void *memory, DWORD memory_size, DWORD options,
3894         struct IDirect3DDevice9 *device, struct ID3DXAllocateHierarchy *alloc_hier,
3895         struct ID3DXLoadUserData *load_user_data, D3DXFRAME **frame_hierarchy,
3896         struct ID3DXAnimationController **anim_controller)
3897 {
3898     HRESULT hr;
3899     ID3DXFile *d3dxfile = NULL;
3900     ID3DXFileEnumObject *enumobj = NULL;
3901     ID3DXFileData *filedata = NULL;
3902     D3DXF_FILELOADMEMORY source;
3903     D3DXFRAME *first_frame = NULL;
3904     D3DXFRAME **next_frame = &first_frame;
3905     SIZE_T i, nb_children;
3906     GUID guid;
3907 
3908     TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory, memory_size, options,
3909           device, alloc_hier, load_user_data, frame_hierarchy, anim_controller);
3910 
3911     if (!memory || !memory_size || !device || !frame_hierarchy || !alloc_hier)
3912         return D3DERR_INVALIDCALL;
3913     if (load_user_data)
3914     {
3915         FIXME("Loading user data not implemented.\n");
3916         return E_NOTIMPL;
3917     }
3918 
3919     hr = D3DXFileCreate(&d3dxfile);
3920     if (FAILED(hr)) goto cleanup;
3921 
3922     hr = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES);
3923     if (FAILED(hr)) goto cleanup;
3924 
3925     source.lpMemory = (void*)memory;
3926     source.dSize = memory_size;
3927     hr = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &source, D3DXF_FILELOAD_FROMMEMORY, &enumobj);
3928     if (FAILED(hr)) goto cleanup;
3929 
3930     hr = enumobj->lpVtbl->GetChildren(enumobj, &nb_children);
3931     if (FAILED(hr))
3932         goto cleanup;
3933 
3934     for (i = 0; i < nb_children; i++)
3935     {
3936         hr = enumobj->lpVtbl->GetChild(enumobj, i, &filedata);
3937         if (FAILED(hr))
3938             goto cleanup;
3939 
3940         hr = filedata->lpVtbl->GetType(filedata, &guid);
3941         if (SUCCEEDED(hr)) {
3942             if (IsEqualGUID(&guid, &TID_D3DRMMesh)) {
3943                 hr = alloc_hier->lpVtbl->CreateFrame(alloc_hier, NULL, next_frame);
3944                 if (FAILED(hr)) {
3945                     hr = E_FAIL;
3946                     goto cleanup;
3947                 }
3948 
3949                 D3DXMatrixIdentity(&(*next_frame)->TransformationMatrix);
3950 
3951                 hr = load_mesh_container(filedata, options, device, alloc_hier, &(*next_frame)->pMeshContainer);
3952                 if (FAILED(hr)) goto cleanup;
3953             } else if (IsEqualGUID(&guid, &TID_D3DRMFrame)) {
3954                 hr = load_frame(filedata, options, device, alloc_hier, next_frame);
3955                 if (FAILED(hr)) goto cleanup;
3956             }
3957             while (*next_frame)
3958                 next_frame = &(*next_frame)->pFrameSibling;
3959         }
3960 
3961         filedata->lpVtbl->Release(filedata);
3962         filedata = NULL;
3963         if (FAILED(hr))
3964             goto cleanup;
3965     }
3966 
3967     if (!first_frame) {
3968         hr = E_FAIL;
3969     } else if (first_frame->pFrameSibling) {
3970         D3DXFRAME *root_frame = NULL;
3971         hr = alloc_hier->lpVtbl->CreateFrame(alloc_hier, NULL, &root_frame);
3972         if (FAILED(hr)) {
3973             hr = E_FAIL;
3974             goto cleanup;
3975         }
3976         D3DXMatrixIdentity(&root_frame->TransformationMatrix);
3977         root_frame->pFrameFirstChild = first_frame;
3978         *frame_hierarchy = root_frame;
3979         hr = D3D_OK;
3980     } else {
3981         *frame_hierarchy = first_frame;
3982         hr = D3D_OK;
3983     }
3984 
3985     if (anim_controller)
3986     {
3987         *anim_controller = NULL;
3988         FIXME("Animation controller creation not implemented.\n");
3989     }
3990 
3991 cleanup:
3992     if (FAILED(hr) && first_frame) D3DXFrameDestroy(first_frame, alloc_hier);
3993     if (filedata) filedata->lpVtbl->Release(filedata);
3994     if (enumobj) enumobj->lpVtbl->Release(enumobj);
3995     if (d3dxfile) d3dxfile->lpVtbl->Release(d3dxfile);
3996     return hr;
3997 }
3998 
3999 HRESULT WINAPI D3DXCleanMesh(D3DXCLEANTYPE clean_type, ID3DXMesh *mesh_in, const DWORD *adjacency_in,
4000         ID3DXMesh **mesh_out, DWORD *adjacency_out, ID3DXBuffer **errors_and_warnings)
4001 {
4002     FIXME("(%u, %p, %p, %p, %p, %p)\n", clean_type, mesh_in, adjacency_in, mesh_out, adjacency_out, errors_and_warnings);
4003 
4004     return E_NOTIMPL;
4005 }
4006 
4007 HRESULT WINAPI D3DXFrameDestroy(D3DXFRAME *frame, ID3DXAllocateHierarchy *alloc_hier)
4008 {
4009     HRESULT hr;
4010     BOOL last = FALSE;
4011 
4012     TRACE("(%p, %p)\n", frame, alloc_hier);
4013 
4014     if (!frame || !alloc_hier)
4015         return D3DERR_INVALIDCALL;
4016 
4017     while (!last) {
4018         D3DXMESHCONTAINER *container;
4019         D3DXFRAME *current_frame;
4020 
4021         if (frame->pFrameSibling) {
4022             current_frame = frame->pFrameSibling;
4023             frame->pFrameSibling = current_frame->pFrameSibling;
4024             current_frame->pFrameSibling = NULL;
4025         } else {
4026             current_frame = frame;
4027             last = TRUE;
4028         }
4029 
4030         if (current_frame->pFrameFirstChild) {
4031             hr = D3DXFrameDestroy(current_frame->pFrameFirstChild, alloc_hier);
4032             if (FAILED(hr)) return hr;
4033             current_frame->pFrameFirstChild = NULL;
4034         }
4035 
4036         container = current_frame->pMeshContainer;
4037         while (container) {
4038             D3DXMESHCONTAINER *next_container = container->pNextMeshContainer;
4039             hr = alloc_hier->lpVtbl->DestroyMeshContainer(alloc_hier, container);
4040             if (FAILED(hr)) return hr;
4041             container = next_container;
4042         }
4043         hr = alloc_hier->lpVtbl->DestroyFrame(alloc_hier, current_frame);
4044         if (FAILED(hr)) return hr;
4045     }
4046     return D3D_OK;
4047 }
4048 
4049 HRESULT WINAPI D3DXLoadMeshFromXA(const char *filename, DWORD options, struct IDirect3DDevice9 *device,
4050         struct ID3DXBuffer **adjacency, struct ID3DXBuffer **materials, struct ID3DXBuffer **effect_instances,
4051         DWORD *num_materials, struct ID3DXMesh **mesh)
4052 {
4053     WCHAR *filenameW;
4054     HRESULT hr;
4055     int len;
4056 
4057     TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4058             "effect_instances %p, num_materials %p, mesh %p.\n",
4059             debugstr_a(filename), options, device, adjacency, materials,
4060             effect_instances, num_materials, mesh);
4061 
4062     if (!filename)
4063         return D3DERR_INVALIDCALL;
4064 
4065     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
4066     filenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4067     if (!filenameW) return E_OUTOFMEMORY;
4068     MultiByteToWideChar(CP_ACP, 0, filename, -1, filenameW, len);
4069 
4070     hr = D3DXLoadMeshFromXW(filenameW, options, device, adjacency, materials,
4071                             effect_instances, num_materials, mesh);
4072     HeapFree(GetProcessHeap(), 0, filenameW);
4073 
4074     return hr;
4075 }
4076 
4077 HRESULT WINAPI D3DXLoadMeshFromXW(const WCHAR *filename, DWORD options, struct IDirect3DDevice9 *device,
4078         struct ID3DXBuffer **adjacency, struct ID3DXBuffer **materials, struct ID3DXBuffer **effect_instances,
4079         DWORD *num_materials, struct ID3DXMesh **mesh)
4080 {
4081     void *buffer;
4082     HRESULT hr;
4083     DWORD size;
4084 
4085     TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4086             "effect_instances %p, num_materials %p, mesh %p.\n",
4087             debugstr_w(filename), options, device, adjacency, materials,
4088             effect_instances, num_materials, mesh);
4089 
4090     if (!filename)
4091         return D3DERR_INVALIDCALL;
4092 
4093     hr = map_view_of_file(filename, &buffer, &size);
4094     if (FAILED(hr))
4095         return D3DXERR_INVALIDDATA;
4096 
4097     hr = D3DXLoadMeshFromXInMemory(buffer, size, options, device, adjacency,
4098             materials, effect_instances, num_materials, mesh);
4099 
4100     UnmapViewOfFile(buffer);
4101 
4102     return hr;
4103 }
4104 
4105 HRESULT WINAPI D3DXLoadMeshFromXResource(HMODULE module, const char *name, const char *type, DWORD options,
4106         struct IDirect3DDevice9 *device, struct ID3DXBuffer **adjacency, struct ID3DXBuffer **materials,
4107         struct ID3DXBuffer **effect_instances, DWORD *num_materials, struct ID3DXMesh **mesh)
4108 {
4109     HRESULT hr;
4110     HRSRC resinfo;
4111     void *buffer;
4112     DWORD size;
4113 
4114     TRACE("module %p, name %s, type %s, options %#x, device %p, adjacency %p, "
4115             "materials %p, effect_instances %p, num_materials %p, mesh %p.\n",
4116             module, debugstr_a(name), debugstr_a(type), options, device, adjacency,
4117             materials, effect_instances, num_materials, mesh);
4118 
4119     resinfo = FindResourceA(module, name, type);
4120     if (!resinfo) return D3DXERR_INVALIDDATA;
4121 
4122     hr = load_resource_into_memory(module, resinfo, &buffer, &size);
4123     if (FAILED(hr)) return D3DXERR_INVALIDDATA;
4124 
4125     return D3DXLoadMeshFromXInMemory(buffer, size, options, device, adjacency,
4126             materials, effect_instances, num_materials, mesh);
4127 }
4128 
4129 struct mesh_container
4130 {
4131     struct list entry;
4132     ID3DXMesh *mesh;
4133     ID3DXBuffer *adjacency;
4134     ID3DXBuffer *materials;
4135     ID3DXBuffer *effects;
4136     DWORD num_materials;
4137     D3DXMATRIX transform;
4138 };
4139 
4140 static HRESULT parse_frame(struct ID3DXFileData *filedata, DWORD options, struct IDirect3DDevice9 *device,
4141         const D3DXMATRIX *parent_transform, struct list *container_list, DWORD provide_flags)
4142 {
4143     HRESULT hr;
4144     D3DXMATRIX transform = *parent_transform;
4145     ID3DXFileData *child;
4146     GUID type;
4147     SIZE_T i, nb_children;
4148 
4149     hr = filedata->lpVtbl->GetChildren(filedata, &nb_children);
4150     if (FAILED(hr))
4151         return hr;
4152 
4153     for (i = 0; i < nb_children; i++)
4154     {
4155         hr = filedata->lpVtbl->GetChild(filedata, i, &child);
4156         if (FAILED(hr))
4157             return hr;
4158         hr = child->lpVtbl->GetType(child, &type);
4159         if (FAILED(hr))
4160             goto err;
4161 
4162         if (IsEqualGUID(&type, &TID_D3DRMMesh)) {
4163             struct mesh_container *container = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*container));
4164             if (!container)
4165             {
4166                 hr = E_OUTOFMEMORY;
4167                 goto err;
4168             }
4169             list_add_tail(container_list, &container->entry);
4170             container->transform = transform;
4171 
4172             hr = D3DXLoadSkinMeshFromXof(child, options, device,
4173                     (provide_flags & PROVIDE_ADJACENCY) ? &container->adjacency : NULL,
4174                     (provide_flags & PROVIDE_MATERIALS) ? &container->materials : NULL,
4175                     NULL, &container->num_materials, NULL, &container->mesh);
4176         } else if (IsEqualGUID(&type, &TID_D3DRMFrameTransformMatrix)) {
4177             D3DXMATRIX new_transform;
4178             hr = parse_transform_matrix(child, &new_transform);
4179             D3DXMatrixMultiply(&transform, &transform, &new_transform);
4180         } else if (IsEqualGUID(&type, &TID_D3DRMFrame)) {
4181             hr = parse_frame(child, options, device, &transform, container_list, provide_flags);
4182         }
4183         if (FAILED(hr))
4184             goto err;
4185 
4186         IUnknown_Release(child);
4187     }
4188     return D3D_OK;
4189 
4190 err:
4191     IUnknown_Release(child);
4192     return hr;
4193 }
4194 
4195 HRESULT WINAPI D3DXLoadMeshFromXInMemory(const void *memory, DWORD memory_size, DWORD options,
4196         struct IDirect3DDevice9 *device, struct ID3DXBuffer **adjacency_out, struct ID3DXBuffer **materials_out,
4197         struct ID3DXBuffer **effects_out, DWORD *num_materials_out, struct ID3DXMesh **mesh_out)
4198 {
4199     HRESULT hr;
4200     ID3DXFile *d3dxfile = NULL;
4201     ID3DXFileEnumObject *enumobj = NULL;
4202     ID3DXFileData *filedata = NULL;
4203     D3DXF_FILELOADMEMORY source;
4204     ID3DXBuffer *materials = NULL;
4205     ID3DXBuffer *effects = NULL;
4206     ID3DXBuffer *adjacency = NULL;
4207     struct list container_list = LIST_INIT(container_list);
4208     struct mesh_container *container_ptr, *next_container_ptr;
4209     DWORD num_materials;
4210     DWORD num_faces, num_vertices;
4211     D3DXMATRIX identity;
4212     DWORD provide_flags = 0;
4213     DWORD fvf;
4214     ID3DXMesh *concat_mesh = NULL;
4215     D3DVERTEXELEMENT9 concat_decl[MAX_FVF_DECL_SIZE];
4216     BYTE *concat_vertices = NULL;
4217     void *concat_indices = NULL;
4218     DWORD index_offset;
4219     DWORD concat_vertex_size;
4220     SIZE_T i, nb_children;
4221     GUID guid;
4222 
4223     TRACE("(%p, %u, %x, %p, %p, %p, %p, %p, %p)\n", memory, memory_size, options,
4224           device, adjacency_out, materials_out, effects_out, num_materials_out, mesh_out);
4225 
4226     if (!memory || !memory_size || !device || !mesh_out)
4227         return D3DERR_INVALIDCALL;
4228 
4229     hr = D3DXFileCreate(&d3dxfile);
4230     if (FAILED(hr)) goto cleanup;
4231 
4232     hr = d3dxfile->lpVtbl->RegisterTemplates(d3dxfile, D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES);
4233     if (FAILED(hr)) goto cleanup;
4234 
4235     source.lpMemory = (void*)memory;
4236     source.dSize = memory_size;
4237     hr = d3dxfile->lpVtbl->CreateEnumObject(d3dxfile, &source, D3DXF_FILELOAD_FROMMEMORY, &enumobj);
4238     if (FAILED(hr)) goto cleanup;
4239 
4240     D3DXMatrixIdentity(&identity);
4241     if (adjacency_out) provide_flags |= PROVIDE_ADJACENCY;
4242     if (materials_out || effects_out) provide_flags |= PROVIDE_MATERIALS;
4243 
4244     hr = enumobj->lpVtbl->GetChildren(enumobj, &nb_children);
4245     if (FAILED(hr))
4246         goto cleanup;
4247 
4248     for (i = 0; i < nb_children; i++)
4249     {
4250         hr = enumobj->lpVtbl->GetChild(enumobj, i, &filedata);
4251         if (FAILED(hr))
4252             goto cleanup;
4253 
4254         hr = filedata->lpVtbl->GetType(filedata, &guid);
4255         if (SUCCEEDED(hr)) {
4256             if (IsEqualGUID(&guid, &TID_D3DRMMesh)) {
4257                 container_ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*container_ptr));
4258                 if (!container_ptr) {
4259                     hr = E_OUTOFMEMORY;
4260                     goto cleanup;
4261                 }
4262                 list_add_tail(&container_list, &container_ptr->entry);
4263                 D3DXMatrixIdentity(&container_ptr->transform);
4264 
4265                 hr = D3DXLoadSkinMeshFromXof(filedata, options, device,
4266                         (provide_flags & PROVIDE_ADJACENCY) ? &container_ptr->adjacency : NULL,
4267                         (provide_flags & PROVIDE_MATERIALS) ? &container_ptr->materials : NULL,
4268                         NULL, &container_ptr->num_materials, NULL, &container_ptr->mesh);
4269             } else if (IsEqualGUID(&guid, &TID_D3DRMFrame)) {
4270                 hr = parse_frame(filedata, options, device, &identity, &container_list, provide_flags);
4271             }
4272             if (FAILED(hr)) goto cleanup;
4273         }
4274         filedata->lpVtbl->Release(filedata);
4275         filedata = NULL;
4276         if (FAILED(hr))
4277             goto cleanup;
4278     }
4279 
4280     enumobj->lpVtbl->Release(enumobj);
4281     enumobj = NULL;
4282     d3dxfile->lpVtbl->Release(d3dxfile);
4283     d3dxfile = NULL;
4284 
4285     if (list_empty(&container_list)) {
4286         hr = E_FAIL;
4287         goto cleanup;
4288     }
4289 
4290     fvf = D3DFVF_XYZ;
4291     num_faces = 0;
4292     num_vertices = 0;
4293     num_materials = 0;
4294     LIST_FOR_EACH_ENTRY(container_ptr, &container_list, struct mesh_container, entry)
4295     {
4296         ID3DXMesh *mesh = container_ptr->mesh;
4297         fvf |= mesh->lpVtbl->GetFVF(mesh);
4298         num_faces += mesh->lpVtbl->GetNumFaces(mesh);
4299         num_vertices += mesh->lpVtbl->GetNumVertices(mesh);
4300         num_materials += container_ptr->num_materials;
4301     }
4302 
4303     hr = D3DXCreateMeshFVF(num_faces, num_vertices, options, fvf, device, &concat_mesh);
4304     if (FAILED(hr)) goto cleanup;
4305 
4306     hr = concat_mesh->lpVtbl->GetDeclaration(concat_mesh, concat_decl);
4307     if (FAILED(hr)) goto cleanup;
4308 
4309     concat_vertex_size = D3DXGetDeclVertexSize(concat_decl, 0);
4310 
4311     hr = concat_mesh->lpVtbl->LockVertexBuffer(concat_mesh, 0, (void**)&concat_vertices);
4312     if (FAILED(hr)) goto cleanup;
4313 
4314     LIST_FOR_EACH_ENTRY(container_ptr, &container_list, struct mesh_container, entry)
4315     {
4316         D3DVERTEXELEMENT9 mesh_decl[MAX_FVF_DECL_SIZE];
4317         ID3DXMesh *mesh = container_ptr->mesh;
4318         DWORD num_mesh_vertices = mesh->lpVtbl->GetNumVertices(mesh);
4319         DWORD mesh_vertex_size;
4320         const BYTE *mesh_vertices;
4321         DWORD i;
4322 
4323         hr = mesh->lpVtbl->GetDeclaration(mesh, mesh_decl);
4324         if (FAILED(hr)) goto cleanup;
4325 
4326         mesh_vertex_size = D3DXGetDeclVertexSize(mesh_decl, 0);
4327 
4328         hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_vertices);
4329         if (FAILED(hr)) goto cleanup;
4330 
4331         for (i = 0; i < num_mesh_vertices; i++) {
4332             int j;
4333             int k = 1;
4334 
4335             D3DXVec3TransformCoord((D3DXVECTOR3*)concat_vertices,
4336                                    (D3DXVECTOR3*)mesh_vertices,
4337                                    &container_ptr->transform);
4338             for (j = 1; concat_decl[j].Stream != 0xff; j++)
4339             {
4340                 if (concat_decl[j].Usage == mesh_decl[k].Usage &&
4341                     concat_decl[j].UsageIndex == mesh_decl[k].UsageIndex)
4342                 {
4343                     if (concat_decl[j].Usage == D3DDECLUSAGE_NORMAL) {
4344                         D3DXVec3TransformCoord((D3DXVECTOR3*)(concat_vertices + concat_decl[j].Offset),
4345                                                (D3DXVECTOR3*)(mesh_vertices + mesh_decl[k].Offset),
4346                                                &container_ptr->transform);
4347                     } else {
4348                         memcpy(concat_vertices + concat_decl[j].Offset,
4349                                mesh_vertices + mesh_decl[k].Offset,
4350                                d3dx_decltype_size[mesh_decl[k].Type]);
4351                     }
4352                     k++;
4353                 }
4354             }
4355             mesh_vertices += mesh_vertex_size;
4356             concat_vertices += concat_vertex_size;
4357         }
4358 
4359         mesh->lpVtbl->UnlockVertexBuffer(mesh);
4360     }
4361 
4362     concat_mesh->lpVtbl->UnlockVertexBuffer(concat_mesh);
4363     concat_vertices = NULL;
4364 
4365     hr = concat_mesh->lpVtbl->LockIndexBuffer(concat_mesh, 0, &concat_indices);
4366     if (FAILED(hr)) goto cleanup;
4367 
4368     index_offset = 0;
4369     LIST_FOR_EACH_ENTRY(container_ptr, &container_list, struct mesh_container, entry)
4370     {
4371         ID3DXMesh *mesh = container_ptr->mesh;
4372         const void *mesh_indices;
4373         DWORD num_mesh_faces = mesh->lpVtbl->GetNumFaces(mesh);
4374         DWORD i;
4375 
4376         hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_READONLY, (void**)&mesh_indices);
4377         if (FAILED(hr)) goto cleanup;
4378 
4379         if (options & D3DXMESH_32BIT) {
4380             DWORD *dest = concat_indices;
4381             const DWORD *src = mesh_indices;
4382             for (i = 0; i < num_mesh_faces * 3; i++)
4383                 *dest++ = index_offset + *src++;
4384             concat_indices = dest;
4385         } else {
4386             WORD *dest = concat_indices;
4387             const WORD *src = mesh_indices;
4388             for (i = 0; i < num_mesh_faces * 3; i++)
4389                 *dest++ = index_offset + *src++;
4390             concat_indices = dest;
4391         }
4392         mesh->lpVtbl->UnlockIndexBuffer(mesh);
4393 
4394         index_offset += num_mesh_faces * 3;
4395     }
4396 
4397     concat_mesh->lpVtbl->UnlockIndexBuffer(concat_mesh);
4398     concat_indices = NULL;
4399 
4400     if (num_materials) {
4401         DWORD *concat_attrib_buffer = NULL;
4402         DWORD offset = 0;
4403 
4404         hr = concat_mesh->lpVtbl->LockAttributeBuffer(concat_mesh, 0, &concat_attrib_buffer);
4405         if (FAILED(hr)) goto cleanup;
4406 
4407         LIST_FOR_EACH_ENTRY(container_ptr, &container_list, struct mesh_container, entry)
4408         {
4409             ID3DXMesh *mesh = container_ptr->mesh;
4410             const DWORD *mesh_attrib_buffer = NULL;
4411             DWORD count = mesh->lpVtbl->GetNumFaces(mesh);
4412 
4413             hr = mesh->lpVtbl->LockAttributeBuffer(mesh, D3DLOCK_READONLY, (DWORD**)&mesh_attrib_buffer);
4414             if (FAILED(hr)) {
4415                 concat_mesh->lpVtbl->UnlockAttributeBuffer(concat_mesh);
4416                 goto cleanup;
4417             }
4418 
4419             while (count--)
4420                 *concat_attrib_buffer++ = offset + *mesh_attrib_buffer++;
4421 
4422             mesh->lpVtbl->UnlockAttributeBuffer(mesh);
4423             offset += container_ptr->num_materials;
4424         }
4425         concat_mesh->lpVtbl->UnlockAttributeBuffer(concat_mesh);
4426     }
4427 
4428     if (materials_out || effects_out) {
4429         D3DXMATERIAL *out_ptr;
4430         if (!num_materials) {
4431             /* create default material */
4432             hr = D3DXCreateBuffer(sizeof(D3DXMATERIAL), &materials);
4433             if (FAILED(hr)) goto cleanup;
4434 
4435             out_ptr = ID3DXBuffer_GetBufferPointer(materials);
4436             out_ptr->MatD3D.Diffuse.r = 0.5f;
4437             out_ptr->MatD3D.Diffuse.g = 0.5f;
4438             out_ptr->MatD3D.Diffuse.b = 0.5f;
4439             out_ptr->MatD3D.Specular.r = 0.5f;
4440             out_ptr->MatD3D.Specular.g = 0.5f;
4441             out_ptr->MatD3D.Specular.b = 0.5f;
4442             /* D3DXCreateBuffer initializes the rest to zero */
4443         } else {
4444             DWORD buffer_size = num_materials * sizeof(D3DXMATERIAL);
4445             char *strings_out_ptr;
4446 
4447             LIST_FOR_EACH_ENTRY(container_ptr, &container_list, struct mesh_container, entry)
4448             {
4449                 if (container_ptr->materials) {
4450                     DWORD i;
4451                     const D3DXMATERIAL *in_ptr = ID3DXBuffer_GetBufferPointer(container_ptr->materials);
4452                     for (i = 0; i < container_ptr->num_materials; i++)
4453                     {
4454                         if (in_ptr->pTextureFilename)
4455                             buffer_size += strlen(in_ptr->pTextureFilename) + 1;
4456                         in_ptr++;
4457                     }
4458                 }
4459             }
4460 
4461             hr = D3DXCreateBuffer(buffer_size, &materials);
4462             if (FAILED(hr)) goto cleanup;
4463             out_ptr = ID3DXBuffer_GetBufferPointer(materials);
4464             strings_out_ptr = (char*)(out_ptr + num_materials);
4465 
4466             LIST_FOR_EACH_ENTRY(container_ptr, &container_list, struct mesh_container, entry)
4467             {
4468                 if (container_ptr->materials) {
4469                     DWORD i;
4470                     const D3DXMATERIAL *in_ptr = ID3DXBuffer_GetBufferPointer(container_ptr->materials);
4471                     for (i = 0; i < container_ptr->num_materials; i++)
4472                     {
4473                         out_ptr->MatD3D = in_ptr->MatD3D;
4474                         if (in_ptr->pTextureFilename) {
4475                             out_ptr->pTextureFilename = strings_out_ptr;
4476                             strcpy(out_ptr->pTextureFilename, in_ptr->pTextureFilename);
4477                             strings_out_ptr += strlen(in_ptr->pTextureFilename) + 1;
4478                         }
4479                         in_ptr++;
4480                         out_ptr++;
4481                     }
4482                 }
4483             }
4484         }
4485     }
4486     if (!num_materials)
4487         num_materials = 1;
4488 
4489     if (effects_out) {
4490         generate_effects(materials, num_materials, &effects);
4491         if (!materials_out) {
4492             ID3DXBuffer_Release(materials);
4493             materials = NULL;
4494         }
4495     }
4496 
4497     if (adjacency_out) {
4498         if (!list_next(&container_list, list_head(&container_list))) {
4499             container_ptr = LIST_ENTRY(list_head(&container_list), struct mesh_container, entry);
4500             adjacency = container_ptr->adjacency;
4501             container_ptr->adjacency = NULL;
4502         } else {
4503             DWORD offset = 0;
4504             DWORD *out_ptr;
4505 
4506             hr = D3DXCreateBuffer(num_faces * 3 * sizeof(DWORD), &adjacency);
4507             if (FAILED(hr)) goto cleanup;
4508 
4509             out_ptr = ID3DXBuffer_GetBufferPointer(adjacency);
4510             LIST_FOR_EACH_ENTRY(container_ptr, &container_list, struct mesh_container, entry)
4511             {
4512                 DWORD i;
4513                 DWORD count = 3 * container_ptr->mesh->lpVtbl->GetNumFaces(container_ptr->mesh);
4514                 DWORD *in_ptr = ID3DXBuffer_GetBufferPointer(container_ptr->adjacency);
4515 
4516                 for (i = 0; i < count; i++)
4517                     *out_ptr++ = offset + *in_ptr++;
4518 
4519                 offset += count;
4520             }
4521         }
4522     }
4523 
4524     *mesh_out = concat_mesh;
4525     if (adjacency_out) *adjacency_out = adjacency;
4526     if (materials_out) *materials_out = materials;
4527     if (effects_out) *effects_out = effects;
4528     if (num_materials_out) *num_materials_out = num_materials;
4529 
4530     hr = D3D_OK;
4531 cleanup:
4532     if (concat_indices) concat_mesh->lpVtbl->UnlockIndexBuffer(concat_mesh);
4533     if (concat_vertices) concat_mesh->lpVtbl->UnlockVertexBuffer(concat_mesh);
4534     if (filedata) filedata->lpVtbl->Release(filedata);
4535     if (enumobj) enumobj->lpVtbl->Release(enumobj);
4536     if (d3dxfile) d3dxfile->lpVtbl->Release(d3dxfile);
4537     if (FAILED(hr)) {
4538         if (concat_mesh) IUnknown_Release(concat_mesh);
4539         if (materials) ID3DXBuffer_Release(materials);
4540         if (effects) ID3DXBuffer_Release(effects);
4541         if (adjacency) ID3DXBuffer_Release(adjacency);
4542     }
4543     LIST_FOR_EACH_ENTRY_SAFE(container_ptr, next_container_ptr, &container_list, struct mesh_container, entry)
4544     {
4545         if (container_ptr->mesh) IUnknown_Release(container_ptr->mesh);
4546         if (container_ptr->adjacency) ID3DXBuffer_Release(container_ptr->adjacency);
4547         if (container_ptr->materials) ID3DXBuffer_Release(container_ptr->materials);
4548         if (container_ptr->effects) ID3DXBuffer_Release(container_ptr->effects);
4549         HeapFree(GetProcessHeap(), 0, container_ptr);
4550     }
4551     return hr;
4552 }
4553 
4554 struct vertex
4555 {
4556     D3DXVECTOR3 position;
4557     D3DXVECTOR3 normal;
4558 };
4559 
4560 HRESULT WINAPI D3DXCreatePolygon(struct IDirect3DDevice9 *device, float length, UINT sides,
4561         struct ID3DXMesh **mesh, struct ID3DXBuffer **adjacency)
4562 {
4563     HRESULT hr;
4564     ID3DXMesh *polygon;
4565     struct vertex *vertices;
4566     WORD (*faces)[3];
4567     DWORD (*adjacency_buf)[3];
4568     float angle, scale;
4569     unsigned int i;
4570 
4571     TRACE("device %p, length %f, sides %u, mesh %p, adjacency %p.\n",
4572             device, length, sides, mesh, adjacency);
4573 
4574     if (!device || length < 0.0f || sides < 3 || !mesh)
4575         return D3DERR_INVALIDCALL;
4576 
4577     if (FAILED(hr = D3DXCreateMeshFVF(sides, sides + 1, D3DXMESH_MANAGED,
4578             D3DFVF_XYZ | D3DFVF_NORMAL, device, &polygon)))
4579     {
4580         return hr;
4581     }
4582 
4583     if (FAILED(hr = polygon->lpVtbl->LockVertexBuffer(polygon, 0, (void **)&vertices)))
4584     {
4585         polygon->lpVtbl->Release(polygon);
4586         return hr;
4587     }
4588 
4589     if (FAILED(hr = polygon->lpVtbl->LockIndexBuffer(polygon, 0, (void **)&faces)))
4590     {
4591         polygon->lpVtbl->UnlockVertexBuffer(polygon);
4592         polygon->lpVtbl->Release(polygon);
4593         return hr;
4594     }
4595 
4596     angle = D3DX_PI / sides;
4597     scale = 0.5f * length / sinf(angle);
4598     angle *= 2.0f;
4599 
4600     vertices[0].position.x = 0.0f;
4601     vertices[0].position.y = 0.0f;
4602     vertices[0].position.z = 0.0f;
4603     vertices[0].normal.x = 0.0f;
4604     vertices[0].normal.y = 0.0f;
4605     vertices[0].normal.z = 1.0f;
4606 
4607     for (i = 0; i < sides; ++i)
4608     {
4609         vertices[i + 1].position.x = cosf(angle * i) * scale;
4610         vertices[i + 1].position.y = sinf(angle * i) * scale;
4611         vertices[i + 1].position.z = 0.0f;
4612         vertices[i + 1].normal.x = 0.0f;
4613         vertices[i + 1].normal.y = 0.0f;
4614         vertices[i + 1].normal.z = 1.0f;
4615 
4616         faces[i][0] = 0;
4617         faces[i][1] = i + 1;
4618         faces[i][2] = i + 2;
4619     }
4620 
4621     faces[sides - 1][2] = 1;
4622 
4623     polygon->lpVtbl->UnlockVertexBuffer(polygon);
4624     polygon->lpVtbl->UnlockIndexBuffer(polygon);
4625 
4626     if (adjacency)
4627     {
4628         if (FAILED(hr = D3DXCreateBuffer(sides * sizeof(DWORD) * 3, adjacency)))
4629         {
4630             polygon->lpVtbl->Release(polygon);
4631             return hr;
4632         }
4633 
4634         adjacency_buf = ID3DXBuffer_GetBufferPointer(*adjacency);
4635         for (i = 0; i < sides; ++i)
4636         {
4637             adjacency_buf[i][0] = i - 1;
4638             adjacency_buf[i][1] = ~0U;
4639             adjacency_buf[i][2] = i + 1;
4640         }
4641         adjacency_buf[0][0] = sides - 1;
4642         adjacency_buf[sides - 1][2] = 0;
4643     }
4644 
4645     *mesh = polygon;
4646 
4647     return D3D_OK;
4648 }
4649 
4650 HRESULT WINAPI D3DXCreateBox(struct IDirect3DDevice9 *device, float width, float height,
4651         float depth, struct ID3DXMesh **mesh, struct ID3DXBuffer **adjacency)
4652 {
4653     HRESULT hr;
4654     ID3DXMesh *box;
4655     struct vertex *vertices;
4656     WORD (*faces)[3];
4657     DWORD *adjacency_buf;
4658     unsigned int i, face;
4659     static const D3DXVECTOR3 unit_box[] =
4660     {
4661         {-0.5f, -0.5f, -0.5f}, {-0.5f, -0.5f,  0.5f}, {-0.5f,  0.5f,  0.5f}, {-0.5f,  0.5f, -0.5f},
4662         {-0.5f,  0.5f, -0.5f}, {-0.5f,  0.5f,  0.5f}, { 0.5f,  0.5f,  0.5f}, { 0.5f,  0.5f, -0.5f},
4663         { 0.5f,  0.5f, -0.5f}, { 0.5f,  0.5f,  0.5f}, { 0.5f, -0.5f,  0.5f}, { 0.5f, -0.5f, -0.5f},
4664         {-0.5f, -0.5f,  0.5f}, {-0.5f, -0.5f, -0.5f}, { 0.5f, -0.5f, -0.5f}, { 0.5f, -0.5f,  0.5f},
4665         {-0.5f, -0.5f,  0.5f}, { 0.5f, -0.5f,  0.5f}, { 0.5f,  0.5f,  0.5f}, {-0.5f,  0.5f,  0.5f},
4666         {-0.5f, -0.5f, -0.5f}, {-0.5f,  0.5f, -0.5f}, { 0.5f,  0.5f, -0.5f}, { 0.5f, -0.5f, -0.5f}
4667     };
4668     static const D3DXVECTOR3 normals[] =
4669     {
4670         {-1.0f,  0.0f, 0.0f}, { 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f,  0.0f},
4671         { 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, -1.0f}
4672     };
4673     static const DWORD adjacency_table[] =
4674     {
4675         6, 9, 1, 2, 10, 0, 1,  9,  3, 4, 10,  2,
4676         3, 8, 5, 7, 11, 4, 0, 11,  7, 5,  8,  6,
4677         7, 4, 9, 2,  0, 8, 1,  3, 11, 5,  6, 10
4678     };
4679 
4680     TRACE("device %p, width %f, height %f, depth %f, mesh %p, adjacency %p\n",
4681                     device, width, height, depth, mesh, adjacency);
4682 
4683     if (!device || width < 0.0f || height < 0.0f || depth < 0.0f || !mesh)
4684     {
4685         return D3DERR_INVALIDCALL;
4686     }
4687 
4688     if (FAILED(hr = D3DXCreateMeshFVF(12, 24, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &box)))
4689     {
4690         return hr;
4691     }
4692 
4693     if (FAILED(hr = box->lpVtbl->LockVertexBuffer(box, 0, (void **)&vertices)))
4694     {
4695         box->lpVtbl->Release(box);
4696         return hr;
4697     }
4698 
4699     if (FAILED(hr = box->lpVtbl->LockIndexBuffer(box, 0, (void **)&faces)))
4700     {
4701         box->lpVtbl->UnlockVertexBuffer(box);
4702         box->lpVtbl->Release(box);
4703         return hr;
4704     }
4705 
4706     for (i = 0; i < 24; i++)
4707     {
4708         vertices[i].position.x = width * unit_box[i].x;
4709         vertices[i].position.y = height * unit_box[i].y;
4710         vertices[i].position.z = depth * unit_box[i].z;
4711         vertices[i].normal.x = normals[i / 4].x;
4712         vertices[i].normal.y = normals[i / 4].y;
4713         vertices[i].normal.z = normals[i / 4].z;
4714     }
4715 
4716     face = 0;
4717     for (i = 0; i < 12; i++)
4718     {
4719         faces[i][0] = face++;
4720         faces[i][1] = face++;
4721         faces[i][2] = (i % 2) ? face - 4 : face;
4722     }
4723 
4724     box->lpVtbl->UnlockIndexBuffer(box);
4725     box->lpVtbl->UnlockVertexBuffer(box);
4726 
4727     if (adjacency)
4728     {
4729         if (FAILED(hr = D3DXCreateBuffer(sizeof(adjacency_table), adjacency)))
4730         {
4731             box->lpVtbl->Release(box);
4732             return hr;
4733         }
4734 
4735         adjacency_buf = ID3DXBuffer_GetBufferPointer(*adjacency);
4736         memcpy(adjacency_buf, adjacency_table, sizeof(adjacency_table));
4737     }
4738 
4739     *mesh = box;
4740 
4741     return D3D_OK;
4742 }
4743 
4744 typedef WORD face[3];
4745 
4746 struct sincos_table
4747 {
4748     float *sin;
4749     float *cos;
4750 };
4751 
4752 static void free_sincos_table(struct sincos_table *sincos_table)
4753 {
4754     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
4755     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
4756 }
4757 
4758 /* pre compute sine and cosine tables; caller must free */
4759 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
4760 {
4761     float angle;
4762     int i;
4763 
4764     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
4765     if (!sincos_table->sin)
4766     {
4767         return FALSE;
4768     }
4769     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
4770     if (!sincos_table->cos)
4771     {
4772         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
4773         return FALSE;
4774     }
4775 
4776     angle = angle_start;
4777     for (i = 0; i < n; i++)
4778     {
4779         sincos_table->sin[i] = sinf(angle);
4780         sincos_table->cos[i] = cosf(angle);
4781         angle += angle_step;
4782     }
4783 
4784     return TRUE;
4785 }
4786 
4787 static WORD vertex_index(UINT slices, int slice, int stack)
4788 {
4789     return stack*slices+slice+1;
4790 }
4791 
4792 HRESULT WINAPI D3DXCreateSphere(struct IDirect3DDevice9 *device, float radius, UINT slices,
4793         UINT stacks, struct ID3DXMesh **mesh, struct ID3DXBuffer **adjacency)
4794 {
4795     DWORD number_of_vertices, number_of_faces;
4796     HRESULT hr;
4797     ID3DXMesh *sphere;
4798     struct vertex *vertices;
4799     face *faces;
4800     float phi_step, phi_start;
4801     struct sincos_table phi;
4802     float theta_step, theta, sin_theta, cos_theta;
4803     DWORD vertex, face, stack, slice;
4804 
4805     TRACE("(%p, %f, %u, %u, %p, %p)\n", device, radius, slices, stacks, mesh, adjacency);
4806 
4807     if (!device || radius < 0.0f || slices < 2 || stacks < 2 || !mesh)
4808     {
4809         return D3DERR_INVALIDCALL;
4810     }
4811 
4812     number_of_vertices = 2 + slices * (stacks-1);
4813     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
4814 
4815     hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
4816                            D3DFVF_XYZ | D3DFVF_NORMAL, device, &sphere);
4817     if (FAILED(hr))
4818     {
4819         return hr;
4820     }
4821 
4822     if (FAILED(hr = sphere->lpVtbl->LockVertexBuffer(sphere, 0, (void **)&vertices)))
4823     {
4824         sphere->lpVtbl->Release(sphere);
4825         return hr;
4826     }
4827 
4828     if (FAILED(hr = sphere->lpVtbl->LockIndexBuffer(sphere, 0, (void **)&faces)))
4829     {
4830         sphere->lpVtbl->UnlockVertexBuffer(sphere);
4831         sphere->lpVtbl->Release(sphere);
4832         return hr;
4833     }
4834 
4835     /* phi = angle on xz plane wrt z axis */
4836     phi_step = -2.0f * D3DX_PI / slices;
4837     phi_start = D3DX_PI / 2.0f;
4838 
4839     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
4840     {
4841         sphere->lpVtbl->UnlockIndexBuffer(sphere);
4842         sphere->lpVtbl->UnlockVertexBuffer(sphere);
4843         sphere->lpVtbl->Release(sphere);
4844         return E_OUTOFMEMORY;
4845     }
4846 
4847     /* theta = angle on xy plane wrt x axis */
4848     theta_step = D3DX_PI / stacks;
4849     theta = theta_step;
4850 
4851     vertex = 0;
4852     face = 0;
4853 
4854     vertices[vertex].normal.x = 0.0f;
4855     vertices[vertex].normal.y = 0.0f;
4856     vertices[vertex].normal.z = 1.0f;
4857     vertices[vertex].position.x = 0.0f;
4858     vertices[vertex].position.y = 0.0f;
4859     vertices[vertex].position.z = radius;
4860     vertex++;
4861 
4862     for (stack = 0; stack < stacks - 1; stack++)
4863     {
4864         sin_theta = sinf(theta);
4865         cos_theta = cosf(theta);
4866 
4867         for (slice = 0; slice < slices; slice++)
4868         {
4869             vertices[vertex].normal.x = sin_theta * phi.cos[slice];
4870             vertices[vertex].normal.y = sin_theta * phi.sin[slice];
4871             vertices[vertex].normal.z = cos_theta;
4872             vertices[vertex].position.x = radius * sin_theta * phi.cos[slice];
4873             vertices[vertex].position.y = radius * sin_theta * phi.sin[slice];
4874             vertices[vertex].position.z = radius * cos_theta;
4875             vertex++;
4876 
4877             if (slice > 0)
4878             {
4879                 if (stack == 0)
4880                 {
4881                     /* top stack is triangle fan */
4882                     faces[face][0] = 0;
4883                     faces[face][1] = slice + 1;
4884                     faces[face][2] = slice;
4885                     face++;
4886                 }
4887                 else
4888                 {
4889                     /* stacks in between top and bottom are quad strips */
4890                     faces[face][0] = vertex_index(slices, slice-1, stack-1);
4891                     faces[face][1] = vertex_index(slices, slice, stack-1);
4892                     faces[face][2] = vertex_index(slices, slice-1, stack);
4893                     face++;
4894 
4895                     faces[face][0] = vertex_index(slices, slice, stack-1);
4896                     faces[face][1] = vertex_index(slices, slice, stack);
4897                     faces[face][2] = vertex_index(slices, slice-1, stack);
4898                     face++;
4899                 }
4900             }
4901         }
4902 
4903         theta += theta_step;
4904 
4905         if (stack == 0)
4906         {
4907             faces[face][0] = 0;
4908             faces[face][1] = 1;
4909             faces[face][2] = slice;
4910             face++;
4911         }
4912         else
4913         {
4914             faces[face][0] = vertex_index(slices, slice-1, stack-1);
4915             faces[face][1] = vertex_index(slices, 0, stack-1);
4916             faces[face][2] = vertex_index(slices, slice-1, stack);
4917             face++;
4918 
4919             faces[face][0] = vertex_index(slices, 0, stack-1);
4920             faces[face][1] = vertex_index(slices, 0, stack);
4921             faces[face][2] = vertex_index(slices, slice-1, stack);
4922             face++;
4923         }
4924     }
4925 
4926     vertices[vertex].position.x = 0.0f;
4927     vertices[vertex].position.y = 0.0f;
4928     vertices[vertex].position.z = -radius;
4929     vertices[vertex].normal.x = 0.0f;
4930     vertices[vertex].normal.y = 0.0f;
4931     vertices[vertex].normal.z = -1.0f;
4932 
4933     /* bottom stack is triangle fan */
4934     for (slice = 1; slice < slices; slice++)
4935     {
4936         faces[face][0] = vertex_index(slices, slice-1, stack-1);
4937         faces[face][1] = vertex_index(slices, slice, stack-1);
4938         faces[face][2] = vertex;
4939         face++;
4940     }
4941 
4942     faces[face][0] = vertex_index(slices, slice-1, stack-1);
4943     faces[face][1] = vertex_index(slices, 0, stack-1);
4944     faces[face][2] = vertex;
4945 
4946     free_sincos_table(&phi);
4947     sphere->lpVtbl->UnlockIndexBuffer(sphere);
4948     sphere->lpVtbl->UnlockVertexBuffer(sphere);
4949 
4950 
4951     if (adjacency)
4952     {
4953         if (FAILED(hr = D3DXCreateBuffer(number_of_faces * sizeof(DWORD) * 3, adjacency)))
4954         {
4955             sphere->lpVtbl->Release(sphere);
4956             return hr;
4957         }
4958 
4959         if (FAILED(hr = sphere->lpVtbl->GenerateAdjacency(sphere, 0.0f, (*adjacency)->lpVtbl->GetBufferPointer(*adjacency))))
4960         {
4961             (*adjacency)->lpVtbl->Release(*adjacency);
4962             sphere->lpVtbl->Release(sphere);
4963             return hr;
4964         }
4965     }
4966 
4967     *mesh = sphere;
4968 
4969     return D3D_OK;
4970 }
4971 
4972 HRESULT WINAPI D3DXCreateCylinder(struct IDirect3DDevice9 *device, float radius1, float radius2,
4973         float length, UINT slices, UINT stacks, struct ID3DXMesh **mesh, struct ID3DXBuffer **adjacency)
4974 {
4975     DWORD number_of_vertices, number_of_faces;
4976     HRESULT hr;
4977     ID3DXMesh *cylinder;
4978     struct vertex *vertices;
4979     face *faces;
4980     float theta_step, theta_start;
4981     struct sincos_table theta;
4982     float delta_radius, radius, radius_step;
4983     float z, z_step, z_normal;
4984     DWORD vertex, face, slice, stack;
4985 
4986     TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device, radius1, radius2, length, slices, stacks, mesh, adjacency);
4987 
4988     if (device == NULL || radius1 < 0.0f || radius2 < 0.0f || length < 0.0f || slices < 2 || stacks < 1 || mesh == NULL)
4989     {
4990         return D3DERR_INVALIDCALL;
4991     }
4992 
4993     number_of_vertices = 2 + (slices * (3 + stacks));
4994     number_of_faces = 2 * slices + stacks * (2 * slices);
4995 
4996     hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
4997                            D3DFVF_XYZ | D3DFVF_NORMAL, device, &cylinder);
4998     if (FAILED(hr))
4999     {
5000         return hr;
5001     }
5002 
5003     if (FAILED(hr = cylinder->lpVtbl->LockVertexBuffer(cylinder, 0, (void **)&vertices)))
5004     {
5005         cylinder->lpVtbl->Release(cylinder);
5006         return hr;
5007     }
5008 
5009     if (FAILED(hr = cylinder->lpVtbl->LockIndexBuffer(cylinder, 0, (void **)&faces)))
5010     {
5011         cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
5012         cylinder->lpVtbl->Release(cylinder);
5013         return hr;
5014     }
5015 
5016     /* theta = angle on xy plane wrt x axis */
5017     theta_step = -2.0f * D3DX_PI / slices;
5018     theta_start = D3DX_PI / 2.0f;
5019 
5020     if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
5021     {
5022         cylinder->lpVtbl->UnlockIndexBuffer(cylinder);
5023         cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
5024         cylinder->lpVtbl->Release(cylinder);
5025         return E_OUTOFMEMORY;
5026     }
5027 
5028     vertex = 0;
5029     face = 0;
5030 
5031     delta_radius = radius1 - radius2;
5032     radius = radius1;
5033     radius_step = delta_radius / stacks;
5034 
5035     z = -length / 2;
5036     z_step = length / stacks;
5037     z_normal = delta_radius / length;
5038     if (isnan(z_normal))
5039     {
5040         z_normal = 0.0f;
5041     }
5042 
5043     vertices[vertex].normal.x = 0.0f;
5044     vertices[vertex].normal.y = 0.0f;
5045     vertices[vertex].normal.z = -1.0f;
5046     vertices[vertex].position.x = 0.0f;
5047     vertices[vertex].position.y = 0.0f;
5048     vertices[vertex++].position.z = z;
5049 
5050     for (slice = 0; slice < slices; slice++, vertex++)
5051     {
5052         vertices[vertex].normal.x = 0.0f;
5053         vertices[vertex].normal.y = 0.0f;
5054         vertices[vertex].normal.z = -1.0f;
5055         vertices[vertex].position.x = radius * theta.cos[slice];
5056         vertices[vertex].position.y = radius * theta.sin[slice];
5057         vertices[vertex].position.z = z;
5058 
5059         if (slice > 0)
5060         {
5061             faces[face][0] = 0;
5062             faces[face][1] = slice;
5063             faces[face++][2] = slice + 1;
5064         }
5065     }
5066 
5067     faces[face][0] = 0;
5068     faces[face][1] = slice;
5069     faces[face++][2] = 1;
5070 
5071     for (stack = 1; stack <= stacks+1; stack++)
5072     {
5073         for (slice = 0; slice < slices; slice++, vertex++)
5074         {
5075             vertices[vertex].normal.x = theta.cos[slice];
5076             vertices[vertex].normal.y = theta.sin[slice];
5077             vertices[vertex].normal.z = z_normal;
5078             D3DXVec3Normalize(&vertices[vertex].normal, &vertices[vertex].normal);
5079             vertices[vertex].position.x = radius * theta.cos[slice];
5080             vertices[vertex].position.y = radius * theta.sin[slice];
5081             vertices[vertex].position.z = z;
5082 
5083             if (stack > 1 && slice > 0)
5084             {
5085                 faces[face][0] = vertex_index(slices, slice-1, stack-1);
5086                 faces[face][1] = vertex_index(slices, slice-1, stack);
5087                 faces[face++][2] = vertex_index(slices, slice, stack-1);
5088 
5089                 faces[face][0] = vertex_index(slices, slice, stack-1);
5090                 faces[face][1] = vertex_index(slices, slice-1, stack);
5091                 faces[face++][2] = vertex_index(slices, slice, stack);
5092             }
5093         }
5094 
5095         if (stack > 1)
5096         {
5097             faces[face][0] = vertex_index(slices, slice-1, stack-1);
5098             faces[face][1] = vertex_index(slices, slice-1, stack);
5099             faces[face++][2] = vertex_index(slices, 0, stack-1);
5100 
5101             faces[face][0] = vertex_index(slices, 0, stack-1);
5102             faces[face][1] = vertex_index(slices, slice-1, stack);
5103             faces[face++][2] = vertex_index(slices, 0, stack);
5104         }
5105 
5106         if (stack < stacks + 1)
5107         {
5108             z += z_step;
5109             radius -= radius_step;
5110         }
5111     }
5112 
5113     for (slice = 0; slice < slices; slice++, vertex++)
5114     {
5115         vertices[vertex].normal.x = 0.0f;
5116         vertices[vertex].normal.y = 0.0f;
5117         vertices[vertex].normal.z = 1.0f;
5118         vertices[vertex].position.x = radius * theta.cos[slice];
5119         vertices[vertex].position.y = radius * theta.sin[slice];
5120         vertices[vertex].position.z = z;
5121 
5122         if (slice > 0)
5123         {
5124             faces[face][0] = vertex_index(slices, slice-1, stack);
5125             faces[face][1] = number_of_vertices - 1;
5126             faces[face++][2] = vertex_index(slices, slice, stack);
5127         }
5128     }
5129 
5130     vertices[vertex].position.x = 0.0f;
5131     vertices[vertex].position.y = 0.0f;
5132     vertices[vertex].position.z = z;
5133     vertices[vertex].normal.x = 0.0f;
5134     vertices[vertex].normal.y = 0.0f;
5135     vertices[vertex].normal.z = 1.0f;
5136 
5137     faces[face][0] = vertex_index(slices, slice-1, stack);
5138     faces[face][1] = number_of_vertices - 1;
5139     faces[face][2] = vertex_index(slices, 0, stack);
5140 
5141     free_sincos_table(&theta);
5142     cylinder->lpVtbl->UnlockIndexBuffer(cylinder);
5143     cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
5144 
5145     if (adjacency)
5146     {
5147         if (FAILED(hr = D3DXCreateBuffer(number_of_faces * sizeof(DWORD) * 3, adjacency)))
5148         {
5149             cylinder->lpVtbl->Release(cylinder);
5150             return hr;
5151         }
5152 
5153         if (FAILED(hr = cylinder->lpVtbl->GenerateAdjacency(cylinder, 0.0f, (*adjacency)->lpVtbl->GetBufferPointer(*adjacency))))
5154         {
5155             (*adjacency)->lpVtbl->Release(*adjacency);
5156             cylinder->lpVtbl->Release(cylinder);
5157             return hr;
5158         }
5159     }
5160 
5161     *mesh = cylinder;
5162 
5163     return D3D_OK;
5164 }
5165 
5166 HRESULT WINAPI D3DXCreateTeapot(struct IDirect3DDevice9 *device,
5167         struct ID3DXMesh **mesh, struct ID3DXBuffer **adjacency)
5168 {
5169     FIXME("device %p, mesh %p, adjacency %p semi-stub.\n", device, mesh, adjacency);
5170 
5171     return D3DXCreateSphere(device, 1.0f, 4, 4, mesh, adjacency);
5172 }
5173 
5174 HRESULT WINAPI D3DXCreateTextA(struct IDirect3DDevice9 *device, HDC hdc, const char *text, float deviation,
5175         float extrusion, struct ID3DXMesh **mesh, struct ID3DXBuffer **adjacency, GLYPHMETRICSFLOAT *glyphmetrics)
5176 {
5177     WCHAR *textW;
5178     HRESULT hr;
5179     int len;
5180 
5181     TRACE("device %p, hdc %p, text %s, deviation %.8e, extrusion %.8e, mesh %p, adjacency %p, glyphmetrics %p.\n",
5182             device, hdc, debugstr_a(text), deviation, extrusion, mesh, adjacency, glyphmetrics);
5183 
5184     if (!text)
5185         return D3DERR_INVALIDCALL;
5186 
5187     len = MultiByteToWideChar(CP_ACP, 0, text, -1, NULL, 0);
5188     textW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5189     MultiByteToWideChar(CP_ACP, 0, text, -1, textW, len);
5190 
5191     hr = D3DXCreateTextW(device, hdc, textW, deviation, extrusion,
5192                          mesh, adjacency, glyphmetrics);
5193     HeapFree(GetProcessHeap(), 0, textW);
5194 
5195     return hr;
5196 }
5197 
5198 HRESULT WINAPI D3DXCreateTorus(struct IDirect3DDevice9 *device,
5199         float innerradius, float outerradius, UINT sides, UINT rings, struct ID3DXMesh **mesh, ID3DXBuffer **adjacency)
5200 {
5201     HRESULT hr;
5202     ID3DXMesh *torus;
5203     WORD (*faces)[3];
5204     struct vertex *vertices;
5205     float phi, phi_step, sin_phi, cos_phi;
5206     float theta, theta_step, sin_theta, cos_theta;
5207     unsigned int i, j, numvert, numfaces;
5208 
5209     TRACE("device %p, innerradius %.8e, outerradius %.8e, sides %u, rings %u, mesh %p, adjacency %p.\n",
5210             device, innerradius, outerradius, sides, rings, mesh, adjacency);
5211 
5212     numvert = sides * rings;
5213     numfaces = numvert * 2;
5214 
5215     if (!device || innerradius < 0.0f || outerradius < 0.0f || sides < 3 || rings < 3 || !mesh)
5216     {
5217         WARN("Invalid arguments.\n");
5218         return D3DERR_INVALIDCALL;
5219     }
5220 
5221     if (FAILED(hr = D3DXCreateMeshFVF(numfaces, numvert, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL, device, &torus)))
5222         return hr;
5223 
5224     if (FAILED(hr = torus->lpVtbl->LockVertexBuffer(torus, 0, (void **)&vertices)))
5225     {
5226         torus->lpVtbl->Release(torus);
5227         return hr;
5228     }
5229 
5230     if (FAILED(hr = torus->lpVtbl->LockIndexBuffer(torus, 0, (void **)&faces)))
5231     {
5232         torus->lpVtbl->UnlockVertexBuffer(torus);
5233         torus->lpVtbl->Release(torus);
5234         return hr;
5235     }
5236 
5237     phi_step = D3DX_PI / sides * 2.0f;
5238     theta_step = D3DX_PI / rings * -2.0f;
5239 
5240     theta = 0.0f;
5241 
5242     for (i = 0; i < rings; ++i)
5243     {
5244         phi = 0.0f;
5245 
5246         sin_theta = sinf(theta);
5247         cos_theta = cosf(theta);
5248 
5249         for (j = 0; j < sides; ++j)
5250         {
5251             sin_phi = sinf(phi);
5252             cos_phi = cosf(phi);
5253 
5254             vertices[i * sides + j].position.x = (innerradius * cos_phi + outerradius) * cos_theta;
5255             vertices[i * sides + j].position.y = (innerradius * cos_phi + outerradius) * sin_theta;
5256             vertices[i * sides + j].position.z = innerradius * sin_phi;
5257             vertices[i * sides + j].normal.x = cos_phi * cos_theta;
5258             vertices[i * sides + j].normal.y = cos_phi * sin_theta;
5259             vertices[i * sides + j].normal.z = sin_phi;
5260 
5261             phi += phi_step;
5262         }
5263 
5264         theta += theta_step;
5265     }
5266 
5267     for (i = 0; i < numfaces - sides * 2; ++i)
5268     {
5269         faces[i][0] = i % 2 ? i / 2 + sides : i / 2;
5270         faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
5271         faces[i][2] = (i + 1) % (sides * 2) ? (i + 1) / 2 + sides : (i + 1) / 2;
5272     }
5273 
5274     for (j = 0; i < numfaces; ++i, ++j)
5275     {
5276         faces[i][0] = i % 2 ? j / 2 : i / 2;
5277         faces[i][1] = (i / 2 + 1) % sides ? i / 2 + 1 : i / 2 + 1 - sides;
5278         faces[i][2] = i == numfaces - 1 ? 0 : (j + 1) / 2;
5279     }
5280 
5281     torus->lpVtbl->UnlockIndexBuffer(torus);
5282     torus->lpVtbl->UnlockVertexBuffer(torus);
5283 
5284     if (adjacency)
5285     {
5286         if (FAILED(hr = D3DXCreateBuffer(numfaces * sizeof(DWORD) * 3, adjacency)))
5287         {
5288             torus->lpVtbl->Release(torus);
5289             return hr;
5290         }
5291 
5292         if (FAILED(hr = torus->lpVtbl->GenerateAdjacency(torus, 0.0f, (*adjacency)->lpVtbl->GetBufferPointer(*adjacency))))
5293         {
5294             (*adjacency)->lpVtbl->Release(*adjacency);
5295             torus->lpVtbl->Release(torus);
5296             return hr;
5297         }
5298     }
5299 
5300     *mesh = torus;
5301 
5302     return D3D_OK;
5303 }
5304 
5305 enum pointtype {
5306     POINTTYPE_CURVE = 0,
5307     POINTTYPE_CORNER,
5308     POINTTYPE_CURVE_START,
5309     POINTTYPE_CURVE_END,
5310     POINTTYPE_CURVE_MIDDLE,
5311 };
5312 
5313 struct point2d
5314 {
5315     D3DXVECTOR2 pos;
5316     enum pointtype corner;
5317 };
5318 
5319 struct dynamic_array
5320 {
5321     int count, capacity;
5322     void *items;
5323 };
5324 
5325 /* is a dynamic_array */
5326 struct outline
5327 {
5328     int count, capacity;
5329     struct point2d *items;
5330 };
5331 
5332 /* is a dynamic_array */
5333 struct outline_array
5334 {
5335     int count, capacity;
5336     struct outline *items;
5337 };
5338 
5339 struct face_array
5340 {
5341     int count;
5342     face *items;
5343 };
5344 
5345 struct point2d_index
5346 {
5347     struct outline *outline;
5348     int vertex;
5349 };
5350 
5351 struct point2d_index_array
5352 {
5353     int count;
5354     struct point2d_index *items;
5355 };
5356 
5357 struct glyphinfo
5358 {
5359     struct outline_array outlines;
5360     struct face_array faces;
5361     struct point2d_index_array ordered_vertices;
5362     float offset_x;
5363 };
5364 
5365 /* is an dynamic_array */
5366 struct word_array
5367 {
5368     int count, capacity;
5369     WORD *items;
5370 };
5371 
5372 /* complex polygons are split into monotone polygons, which have
5373  * at most 2 intersections with the vertical sweep line */
5374 struct triangulation
5375 {
5376     struct word_array vertex_stack;
5377     BOOL last_on_top, merging;
5378 };
5379 
5380 /* is an dynamic_array */
5381 struct triangulation_array
5382 {
5383     int count, capacity;
5384     struct triangulation *items;
5385 
5386     struct glyphinfo *glyph;
5387 };
5388 
5389 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
5390 {
5391     if (count > array->capacity) {
5392         void *new_buffer;
5393         int new_capacity;
5394         if (array->items && array->capacity) {
5395             new_capacity = max(array->capacity * 2, count);
5396             new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
5397         } else {
5398             new_capacity = max(16, count);
5399             new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
5400         }
5401         if (!new_buffer)
5402             return FALSE;
5403         array->items = new_buffer;
5404         array->capacity = new_capacity;
5405     }
5406     return TRUE;
5407 }
5408 
5409 static struct point2d *add_points(struct outline *array, int num)
5410 {
5411     struct point2d *item;
5412 
5413     if (!reserve((struct dynamic_array *)array, array->count + num, sizeof(array->items[0])))
5414         return NULL;
5415 
5416     item = &array->items[array->count];
5417     array->count += num;
5418     return item;
5419 }
5420 
5421 static struct outline *add_outline(struct outline_array *array)
5422 {
5423     struct outline *item;
5424 
5425     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
5426         return NULL;
5427 
5428     item = &array->items[array->count++];
5429     ZeroMemory(item, sizeof(*item));
5430     return item;
5431 }
5432 
5433 static inline face *add_face(struct face_array *array)
5434 {
5435     return &array->items[array->count++];
5436 }
5437 
5438 static struct triangulation *add_triangulation(struct triangulation_array *array)
5439 {
5440     struct triangulation *item;
5441 
5442     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
5443         return NULL;
5444 
5445     item = &array->items[array->count++];
5446     ZeroMemory(item, sizeof(*item));
5447     return item;
5448 }
5449 
5450 static HRESULT add_vertex_index(struct word_array *array, WORD vertex_index)
5451 {
5452     if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
5453         return E_OUTOFMEMORY;
5454 
5455     array->items[array->count++] = vertex_index;
5456     return S_OK;
5457 }
5458 
5459 /* assume fixed point numbers can be converted to float point in place */
5460 C_ASSERT(sizeof(FIXED) == sizeof(float));
5461 C_ASSERT(sizeof(POINTFX) == sizeof(D3DXVECTOR2));
5462 
5463 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, unsigned int emsquare)
5464 {
5465     D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
5466     while (count--) {
5467         D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
5468         pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
5469         pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
5470         pt++;
5471     }
5472     return ret;
5473 }
5474 
5475 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
5476                                  const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
5477                                  float max_deviation_sq)
5478 {
5479     D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
5480     float deviation_sq;
5481 
5482     D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
5483     D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
5484     D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
5485 
5486     deviation_sq = D3DXVec2LengthSq(D3DXVec2Subtract(&vec, &middle, p2));
5487     if (deviation_sq < max_deviation_sq) {
5488         struct point2d *pt = add_points(outline, 1);
5489         if (!pt) return E_OUTOFMEMORY;
5490         pt->pos = *p2;
5491         pt->corner = POINTTYPE_CURVE;
5492         /* the end point is omitted because the end line merges into the next segment of
5493          * the split bezier curve, and the end of the split bezier curve is added outside
5494          * this recursive function. */
5495     } else {
5496         HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation_sq);
5497         if (hr != S_OK) return hr;
5498         hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation_sq);
5499         if (hr != S_OK) return hr;
5500     }
5501 
5502     return S_OK;
5503 }
5504 
5505 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
5506 {
5507     /* dot product = cos(theta) */
5508     return D3DXVec2Dot(dir1, dir2) > cos_theta;
5509 }
5510 
5511 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
5512 {
5513     return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
5514 }
5515 
5516 struct cos_table
5517 {
5518     float cos_half;
5519     float cos_45;
5520     float cos_90;
5521 };
5522 
5523 static BOOL attempt_line_merge(struct outline *outline,
5524                                int pt_index,
5525                                const D3DXVECTOR2 *nextpt,
5526                                BOOL to_curve,
5527                                const struct cos_table *table)
5528 {
5529     D3DXVECTOR2 curdir, lastdir;
5530     struct point2d *prevpt, *pt;
5531     BOOL ret = FALSE;
5532 
5533     pt = &outline->items[pt_index];
5534     pt_index = (pt_index - 1 + outline->count) % outline->count;
5535     prevpt = &outline->items[pt_index];
5536 
5537     if (to_curve)
5538         pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
5539 
5540     if (outline->count < 2)
5541         return FALSE;
5542 
5543     /* remove last point if the next line continues the last line */
5544     unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
5545     unit_vec2(&curdir, &pt->pos, nextpt);
5546     if (is_direction_similar(&lastdir, &curdir, table->cos_half))
5547     {
5548         outline->count--;
5549         if (pt->corner == POINTTYPE_CURVE_END)
5550             prevpt->corner = pt->corner;
5551         if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
5552             prevpt->corner = POINTTYPE_CURVE_MIDDLE;
5553         pt = prevpt;
5554 
5555         ret = TRUE;
5556         if (outline->count < 2)
5557             return ret;
5558 
5559         pt_index = (pt_index - 1 + outline->count) % outline->count;
5560         prevpt = &outline->items[pt_index];
5561         unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
5562         unit_vec2(&curdir, &pt->pos, nextpt);
5563     }
5564     return ret;
5565 }
5566 
5567 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
5568                               float max_deviation_sq, unsigned int emsquare,
5569                               const struct cos_table *cos_table)
5570 {
5571     TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
5572 
5573     while ((char *)header < (char *)raw_outline + datasize)
5574     {
5575         TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
5576         struct point2d *lastpt, *pt;
5577         D3DXVECTOR2 lastdir;
5578         D3DXVECTOR2 *pt_flt;
5579         int j;
5580         struct outline *outline = add_outline(&glyph->outlines);
5581 
5582         if (!outline)
5583             return E_OUTOFMEMORY;
5584 
5585         pt = add_points(outline, 1);
5586         if (!pt)
5587             return E_OUTOFMEMORY;
5588         pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
5589         pt->pos = *pt_flt;
5590         pt->corner = POINTTYPE_CORNER;
5591 
5592         if (header->dwType != TT_POLYGON_TYPE)
5593             FIXME("Unknown header type %d\n", header->dwType);
5594 
5595         while ((char *)curve < (char *)header + header->cb)
5596         {
5597             D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
5598             BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
5599             unsigned int j2 = 0;
5600 
5601             if (!curve->cpfx) {
5602                 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
5603                 continue;
5604             }
5605 
5606             pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
5607 
5608             attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve, cos_table);
5609 
5610             if (to_curve)
5611             {
5612                 HRESULT hr;
5613                 int count = curve->cpfx;
5614 
5615                 while (count > 2)
5616                 {
5617                     D3DXVECTOR2 bezier_end;
5618 
5619                     D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j2], &pt_flt[j2+1]), 0.5f);
5620                     hr = add_bezier_points(outline, &bezier_start, &pt_flt[j2], &bezier_end, max_deviation_sq);
5621                     if (hr != S_OK)
5622                         return hr;
5623                     bezier_start = bezier_end;
5624                     count--;
5625                     j2++;
5626                 }
5627                 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j2], &pt_flt[j2+1], max_deviation_sq);
5628                 if (hr != S_OK)
5629                     return hr;
5630 
5631                 pt = add_points(outline, 1);
5632                 if (!pt)
5633                     return E_OUTOFMEMORY;
5634                 j2++;
5635                 pt->pos = pt_flt[j2];
5636                 pt->corner = POINTTYPE_CURVE_END;
5637             } else {
5638                 pt = add_points(outline, curve->cpfx);
5639                 if (!pt)
5640                     return E_OUTOFMEMORY;
5641                 for (j2 = 0; j2 < curve->cpfx; j2++)
5642                 {
5643                     pt->pos = pt_flt[j2];
5644                     pt->corner = POINTTYPE_CORNER;
5645                     pt++;
5646                 }
5647             }
5648 
5649             curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
5650         }
5651 
5652         /* remove last point if the next line continues the last line */
5653         if (outline->count >= 3) {
5654             BOOL to_curve;
5655 
5656             lastpt = &outline->items[outline->count - 1];
5657             pt = &outline->items[0];
5658             if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
5659                 if (lastpt->corner == POINTTYPE_CURVE_END)
5660                 {
5661                     if (pt->corner == POINTTYPE_CURVE_START)
5662                         pt->corner = POINTTYPE_CURVE_MIDDLE;
5663                     else
5664                         pt->corner = POINTTYPE_CURVE_END;
5665                 }
5666                 outline->count--;
5667             } else {
5668                 /* outline closed with a line from end to start point */
5669                 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE, cos_table);
5670             }
5671             lastpt = &outline->items[0];
5672             to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
5673             if (lastpt->corner == POINTTYPE_CURVE_START)
5674                 lastpt->corner = POINTTYPE_CORNER;
5675             pt = &outline->items[1];
5676             if (attempt_line_merge(outline, 0, &pt->pos, to_curve, cos_table))
5677                 *lastpt = outline->items[outline->count];
5678         }
5679 
5680         lastpt = &outline->items[outline->count - 1];
5681         pt = &outline->items[0];
5682         unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
5683         for (j = 0; j < outline->count; j++)
5684         {
5685             D3DXVECTOR2 curdir;
5686 
5687             lastpt = pt;
5688             pt = &outline->items[(j + 1) % outline->count];
5689             unit_vec2(&curdir, &lastpt->pos, &pt->pos);
5690 
5691             switch (lastpt->corner)
5692             {
5693                 case POINTTYPE_CURVE_START:
5694                 case POINTTYPE_CURVE_END:
5695                     if (!is_direction_similar(&lastdir, &curdir, cos_table->cos_45))
5696                         lastpt->corner = POINTTYPE_CORNER;
5697                     break;
5698                 case POINTTYPE_CURVE_MIDDLE:
5699                     if (!is_direction_similar(&lastdir, &curdir, cos_table->cos_90))
5700                         lastpt->corner = POINTTYPE_CORNER;
5701                     else
5702                         lastpt->corner = POINTTYPE_CURVE;
5703                     break;
5704                 default:
5705                     break;
5706             }
5707             lastdir = curdir;
5708         }
5709 
5710         header = (TTPOLYGONHEADER *)((char *)header + header->cb);
5711     }
5712     return S_OK;
5713 }
5714 
5715 /* Get the y-distance from a line to a point */
5716 static float get_line_to_point_y_distance(D3DXVECTOR2 *line_pt1,
5717                                           D3DXVECTOR2 *line_pt2,
5718                                           D3DXVECTOR2 *point)
5719 {
5720     D3DXVECTOR2 line_vec = {0, 0};
5721     float line_pt_dx;
5722     float line_y;
5723 
5724     D3DXVec2Subtract(&line_vec, line_pt2, line_pt1);
5725     line_pt_dx = point->x - line_pt1->x;
5726     line_y = line_pt1->y + (line_vec.y * line_pt_dx) / line_vec.x;
5727     return point->y - line_y;
5728 }
5729 
5730 static D3DXVECTOR2 *get_indexed_point(struct point2d_index *pt_idx)
5731 {
5732     return &pt_idx->outline->items[pt_idx->vertex].pos;
5733 }
5734 
5735 static D3DXVECTOR2 *get_ordered_vertex(struct glyphinfo *glyph, WORD index)
5736 {
5737     return get_indexed_point(&glyph->ordered_vertices.items[index]);
5738 }
5739 
5740 static void remove_triangulation(struct triangulation_array *array, struct triangulation *item)
5741 {
5742     HeapFree(GetProcessHeap(), 0, item->vertex_stack.items);
5743     MoveMemory(item, item + 1, (char*)&array->items[array->count] - (char*)(item + 1));
5744     array->count--;
5745 }
5746 
5747 static HRESULT triangulation_add_point(struct triangulation **t_ptr,
5748                                        struct triangulation_array *triangulations,
5749                                        WORD vtx_idx,
5750                                        BOOL to_top)
5751 {
5752     struct glyphinfo *glyph = triangulations->glyph;
5753     struct triangulation *t = *t_ptr;
5754     HRESULT hr;
5755     face *face;
5756     int f1, f2;
5757 
5758     if (t->last_on_top) {
5759         f1 = 1;
5760         f2 = 2;
5761     } else {
5762         f1 = 2;
5763         f2 = 1;
5764     }
5765 
5766     if (t->last_on_top != to_top && t->vertex_stack.count > 1) {
5767         /* consume all vertices on the stack */
5768         WORD last_pt = t->vertex_stack.items[0];
5769         int i;
5770         for (i = 1; i < t->vertex_stack.count; i++)
5771         {
5772             face = add_face(&glyph->faces);
5773             if (!face) return E_OUTOFMEMORY;
5774             (*face)[0] = vtx_idx;
5775             (*face)[f1] = last_pt;
5776             (*face)[f2] = last_pt = t->vertex_stack.items[i];
5777         }
5778         t->vertex_stack.items[0] = last_pt;
5779         t->vertex_stack.count = 1;
5780     } else if (t->vertex_stack.count > 1) {
5781         int i = t->vertex_stack.count - 1;
5782         D3DXVECTOR2 *point = get_ordered_vertex(glyph, vtx_idx);
5783         WORD top_idx = t->vertex_stack.items[i--];
5784         D3DXVECTOR2 *top_pt = get_ordered_vertex(glyph, top_idx);
5785 
5786         while (i >= 0)
5787         {
5788             WORD prev_idx = t->vertex_stack.items[i--];
5789             D3DXVECTOR2 *prev_pt = get_ordered_vertex(glyph, prev_idx);
5790 
5791             if (prev_pt->x != top_pt->x &&
5792                 ((to_top && get_line_to_point_y_distance(prev_pt, top_pt, point) > 0) ||
5793                  (!to_top && get_line_to_point_y_distance(prev_pt, top_pt, point) < 0)))
5794                 break;
5795 
5796             face = add_face(&glyph->faces);
5797             if (!face) return E_OUTOFMEMORY;
5798             (*face)[0] = vtx_idx;
5799             (*face)[f1] = prev_idx;
5800             (*face)[f2] = top_idx;
5801 
5802             top_pt = prev_pt;
5803             top_idx = prev_idx;
5804             t->vertex_stack.count--;
5805         }
5806     }
5807     t->last_on_top = to_top;
5808 
5809     hr = add_vertex_index(&t->vertex_stack, vtx_idx);
5810 
5811     if (hr == S_OK && t->merging) {
5812         struct triangulation *t2;
5813 
5814         t2 = to_top ? t - 1 : t + 1;
5815         t2->merging = FALSE;
5816         hr = triangulation_add_point(&t2, triangulations, vtx_idx, to_top);
5817         if (hr != S_OK) return hr;
5818         remove_triangulation(triangulations, t);
5819         if (t2 > t)
5820             t2--;
5821         *t_ptr = t2;
5822     }
5823     return hr;
5824 }
5825 
5826 /* check if the point is next on the outline for either the top or bottom */
5827 static D3DXVECTOR2 *triangulation_get_next_point(struct triangulation *t, struct glyphinfo *glyph, BOOL on_top)
5828 {
5829     int i = t->last_on_top == on_top ? t->vertex_stack.count - 1 : 0;
5830     WORD idx = t->vertex_stack.items[i];
5831     struct point2d_index *pt_idx = &glyph->ordered_vertices.items[idx];
5832     struct outline *outline = pt_idx->outline;
5833 
5834     if (on_top)
5835         i = (pt_idx->vertex + outline->count - 1) % outline->count;
5836     else
5837         i = (pt_idx->vertex + 1) % outline->count;
5838 
5839     return &outline->items[i].pos;
5840 }
5841 
5842 static int compare_vertex_indices(const void *a, const void *b)
5843 {
5844     const struct point2d_index *idx1 = a, *idx2 = b;
5845     const D3DXVECTOR2 *p1 = &idx1->outline->items[idx1->vertex].pos;
5846     const D3DXVECTOR2 *p2 = &idx2->outline->items[idx2->vertex].pos;
5847     float diff = p1->x - p2->x;
5848 
5849     if (diff == 0.0f)
5850         diff = p1->y - p2->y;
5851 
5852     return diff == 0.0f ? 0 : (diff > 0.0f ? -1 : 1);
5853 }
5854 
5855 static HRESULT triangulate(struct triangulation_array *triangulations)
5856 {
5857     int sweep_idx;
5858     HRESULT hr;
5859     struct glyphinfo *glyph = triangulations->glyph;
5860     int nb_vertices = 0;
5861     int i;
5862     struct point2d_index *idx_ptr;
5863 
5864     /* Glyphs without outlines do not generate any vertices. */
5865     if (!glyph->outlines.count)
5866         return D3D_OK;
5867 
5868     for (i = 0; i < glyph->outlines.count; i++)
5869         nb_vertices += glyph->outlines.items[i].count;
5870 
5871     glyph->ordered_vertices.items = HeapAlloc(GetProcessHeap(), 0,
5872             nb_vertices * sizeof(*glyph->ordered_vertices.items));
5873     if (!glyph->ordered_vertices.items)
5874         return E_OUTOFMEMORY;
5875 
5876     idx_ptr = glyph->ordered_vertices.items;
5877     for (i = 0; i < glyph->outlines.count; i++)
5878     {
5879         struct outline *outline = &glyph->outlines.items[i];
5880         int j;
5881 
5882         idx_ptr->outline = outline;
5883         idx_ptr->vertex = 0;
5884         idx_ptr++;
5885         for (j = outline->count - 1; j > 0; j--)
5886         {
5887             idx_ptr->outline = outline;
5888             idx_ptr->vertex = j;
5889             idx_ptr++;
5890         }
5891     }
5892     glyph->ordered_vertices.count = nb_vertices;
5893 
5894     /* Native implementation seems to try to create a triangle fan from
5895      * the first outline point if the glyph only has one outline. */
5896     if (glyph->outlines.count == 1)
5897     {
5898         struct outline *outline = glyph->outlines.items;
5899         D3DXVECTOR2 *base = &outline->items[0].pos;
5900         D3DXVECTOR2 *last = &outline->items[1].pos;
5901         float ccw = 0;
5902 
5903         for (i = 2; i < outline->count; i++)
5904         {
5905             D3DXVECTOR2 *next = &outline->items[i].pos;
5906             D3DXVECTOR2 v1 = {0.0f, 0.0f};
5907             D3DXVECTOR2 v2 = {0.0f, 0.0f};
5908 
5909             D3DXVec2Subtract(&v1, base, last);
5910             D3DXVec2Subtract(&v2, last, next);
5911             ccw = D3DXVec2CCW(&v1, &v2);
5912             if (ccw > 0.0f)
5913                 break;
5914 
5915             last = next;
5916         }
5917         if (ccw <= 0)
5918         {
5919             glyph->faces.items = HeapAlloc(GetProcessHeap(), 0,
5920                     (outline->count - 2) * sizeof(glyph->faces.items[0]));
5921             if (!glyph->faces.items)
5922                 return E_OUTOFMEMORY;
5923 
5924             glyph->faces.count = outline->count - 2;
5925             for (i = 0; i < glyph->faces.count; i++)
5926             {
5927                 glyph->faces.items[i][0] = 0;
5928                 glyph->faces.items[i][1] = i + 1;
5929                 glyph->faces.items[i][2] = i + 2;
5930             }
5931             return S_OK;
5932         }
5933     }
5934 
5935     /* Perform 2D polygon triangulation for complex glyphs.
5936      * Triangulation is performed using a sweep line concept, from right to left,
5937      * by processing vertices in sorted order. Complex polygons are split into
5938      * monotone polygons which are triangulated separately. */
5939     /* FIXME: The order of the faces is not consistent with the native implementation. */
5940 
5941     /* Reserve space for maximum possible faces from triangulation.
5942      * # faces for outer outlines = outline->count - 2
5943      * # faces for inner outlines = outline->count + 2
5944      * There must be at least 1 outer outline. */
5945     glyph->faces.items = HeapAlloc(GetProcessHeap(), 0,
5946             (nb_vertices + glyph->outlines.count * 2 - 4) * sizeof(glyph->faces.items[0]));
5947     if (!glyph->faces.items)
5948         return E_OUTOFMEMORY;
5949 
5950     qsort(glyph->ordered_vertices.items, nb_vertices,
5951           sizeof(glyph->ordered_vertices.items[0]), compare_vertex_indices);
5952     for (sweep_idx = 0; sweep_idx < glyph->ordered_vertices.count; sweep_idx++)
5953     {
5954         int start = 0;
5955         int end = triangulations->count;
5956 
5957         while (start < end)
5958         {
5959             D3DXVECTOR2 *sweep_vtx = get_ordered_vertex(glyph, sweep_idx);
5960             int current = (start + end) / 2;
5961             struct triangulation *t = &triangulations->items[current];
5962             BOOL on_top_outline = FALSE;
5963             D3DXVECTOR2 *top_next, *bottom_next;
5964             WORD top_idx, bottom_idx;
5965 
5966             if (t->merging && t->last_on_top)
5967                 top_next = triangulation_get_next_point(t + 1, glyph, TRUE);
5968             else
5969                 top_next = triangulation_get_next_point(t, glyph, TRUE);
5970             if (sweep_vtx == top_next)
5971             {
5972                 if (t->merging && t->last_on_top)
5973                     t++;
5974                 hr = triangulation_add_point(&t, triangulations, sweep_idx, TRUE);
5975                 if (hr != S_OK) return hr;
5976 
5977                 if (t + 1 < &triangulations->items[triangulations->count] &&
5978                     triangulation_get_next_point(t + 1, glyph, FALSE) == sweep_vtx)
5979                 {
5980                     /* point also on bottom outline of higher triangulation */
5981                     struct triangulation *t2 = t + 1;
5982                     hr = triangulation_add_point(&t2, triangulations, sweep_idx, FALSE);
5983                     if (hr != S_OK) return hr;
5984 
5985                     t->merging = TRUE;
5986                     t2->merging = TRUE;
5987                 }
5988                 on_top_outline = TRUE;
5989             }
5990 
5991             if (t->merging && !t->last_on_top)
5992                 bottom_next = triangulation_get_next_point(t - 1, glyph, FALSE);
5993             else
5994                 bottom_next = triangulation_get_next_point(t, glyph, FALSE);
5995             if (sweep_vtx == bottom_next)
5996             {
5997                 if (t->merging && !t->last_on_top)
5998                     t--;
5999                 if (on_top_outline) {
6000                     /* outline finished */
6001                     remove_triangulation(triangulations, t);
6002                     break;
6003                 }
6004 
6005                 hr = triangulation_add_point(&t, triangulations, sweep_idx, FALSE);
6006                 if (hr != S_OK) return hr;
6007 
6008                 if (t > triangulations->items &&
6009                     triangulation_get_next_point(t - 1, glyph, TRUE) == sweep_vtx)
6010                 {
6011                     struct triangulation *t2 = t - 1;
6012                     /* point also on top outline of lower triangulation */
6013                     hr = triangulation_add_point(&t2, triangulations, sweep_idx, TRUE);
6014                     if (hr != S_OK) return hr;
6015                     t = t2 + 1; /* t may be invalidated by triangulation merging */
6016 
6017                     t->merging = TRUE;
6018                     t2->merging = TRUE;
6019                 }
6020                 break;
6021             }
6022             if (on_top_outline)
6023                 break;
6024 
6025             if (t->last_on_top) {
6026                 top_idx = t->vertex_stack.items[t->vertex_stack.count - 1];
6027                 bottom_idx = t->vertex_stack.items[0];
6028             } else {
6029                 top_idx = t->vertex_stack.items[0];
6030                 bottom_idx = t->vertex_stack.items[t->vertex_stack.count - 1];
6031             }
6032 
6033             /* check if the point is inside or outside this polygon */
6034             if (get_line_to_point_y_distance(get_ordered_vertex(glyph, top_idx),
6035                                              top_next, sweep_vtx) > 0)
6036             { /* above */
6037                 start = current + 1;
6038             } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph, bottom_idx),
6039                                                     bottom_next, sweep_vtx) < 0)
6040             { /* below */
6041                 end = current;
6042             } else if (t->merging) {
6043                 /* inside, so cancel merging */
6044                 struct triangulation *t2 = t->last_on_top ? t + 1 : t - 1;
6045                 t->merging = FALSE;
6046                 t2->merging = FALSE;
6047                 hr = triangulation_add_point(&t, triangulations, sweep_idx, t->last_on_top);
6048                 if (hr != S_OK) return hr;
6049                 hr = triangulation_add_point(&t2, triangulations, sweep_idx, t2->last_on_top);
6050                 if (hr != S_OK) return hr;
6051                 break;
6052             } else {
6053                 /* inside, so split polygon into two monotone parts */
6054                 struct triangulation *t2 = add_triangulation(triangulations);
6055                 if (!t2) return E_OUTOFMEMORY;
6056                 MoveMemory(t + 1, t, (char*)(t2 + 1) - (char*)t);
6057                 if (t->last_on_top) {
6058                     t2 = t + 1;
6059                 } else {
6060                     t2 = t;
6061                     t++;
6062                 }
6063 
6064                 ZeroMemory(&t2->vertex_stack, sizeof(t2->vertex_stack));
6065                 hr = add_vertex_index(&t2->vertex_stack, t->vertex_stack.items[t->vertex_stack.count - 1]);
6066                 if (hr != S_OK) return hr;
6067                 hr = add_vertex_index(&t2->vertex_stack, sweep_idx);
6068                 if (hr != S_OK) return hr;
6069                 t2->last_on_top = !t->last_on_top;
6070 
6071                 hr = triangulation_add_point(&t, triangulations, sweep_idx, t->last_on_top);
6072                 if (hr != S_OK) return hr;
6073                 break;
6074             }
6075         }
6076         if (start >= end)
6077         {
6078             struct triangulation *t;
6079             struct triangulation *t2 = add_triangulation(triangulations);
6080             if (!t2) return E_OUTOFMEMORY;
6081             t = &triangulations->items[start];
6082             MoveMemory(t + 1, t, (char*)(t2 + 1) - (char*)t);
6083             ZeroMemory(t, sizeof(*t));
6084             hr = add_vertex_index(&t->vertex_stack, sweep_idx);
6085             if (hr != S_OK) return hr;
6086         }
6087     }
6088     return S_OK;
6089 }
6090 
6091 HRESULT WINAPI D3DXCreateTextW(struct IDirect3DDevice9 *device, HDC hdc, const WCHAR *text, float deviation,
6092         float extrusion, struct ID3DXMesh **mesh_ptr, struct ID3DXBuffer **adjacency, GLYPHMETRICSFLOAT *glyphmetrics)
6093 {
6094     HRESULT hr;
6095     ID3DXMesh *mesh = NULL;
6096     DWORD nb_vertices, nb_faces;
6097     DWORD nb_front_faces, nb_corners, nb_outline_points;
6098     struct vertex *vertices = NULL;
6099     face *faces = NULL;
6100     int textlen = 0;
6101     float offset_x;
6102     LOGFONTW lf;
6103     OUTLINETEXTMETRICW otm;
6104     HFONT font = NULL, oldfont = NULL;
6105     const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
6106     void *raw_outline = NULL;
6107     int bufsize = 0;
6108     struct glyphinfo *glyphs = NULL;
6109     GLYPHMETRICS gm;
6110     struct triangulation_array triangulations = {0, 0, NULL};
6111     int i;
6112     struct vertex *vertex_ptr;
6113     face *face_ptr;
6114     float max_deviation_sq;
6115     const struct cos_table cos_table = {
6116         cosf(D3DXToRadian(0.5f)),
6117         cosf(D3DXToRadian(45.0f)),
6118         cosf(D3DXToRadian(90.0f)),
6119     };
6120     int f1, f2;
6121 
6122     TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device, hdc,
6123           debugstr_w(text), deviation, extrusion, mesh_ptr, adjacency, glyphmetrics);
6124 
6125     if (!device || !hdc || !text || !*text || deviation < 0.0f || extrusion < 0.0f || !mesh_ptr)
6126         return D3DERR_INVALIDCALL;
6127 
6128     if (adjacency)
6129     {
6130         FIXME("Case of adjacency != NULL not implemented.\n");
6131         return E_NOTIMPL;
6132     }
6133 
6134     if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf) ||
6135         !GetOutlineTextMetricsW(hdc, sizeof(otm), &otm))
6136     {
6137         return D3DERR_INVALIDCALL;
6138     }
6139 
6140     if (deviation == 0.0f)
6141         deviation = 1.0f / otm.otmEMSquare;
6142     max_deviation_sq = deviation * deviation;
6143 
6144     lf.lfHeight = otm.otmEMSquare;
6145     lf.lfWidth = 0;
6146     font = CreateFontIndirectW(&lf);
6147     if (!font) {
6148         hr = E_OUTOFMEMORY;
6149         goto error;
6150     }
6151     oldfont = SelectObject(hdc, font);
6152 
6153     textlen = strlenW(text);
6154     for (i = 0; i < textlen; i++)
6155     {
6156         int datasize = GetGlyphOutlineW(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
6157         if (datasize < 0)
6158             return D3DERR_INVALIDCALL;
6159         if (bufsize < datasize)
6160             bufsize = datasize;
6161     }
6162     if (!bufsize) { /* e.g. text == " " */
6163         hr = D3DERR_INVALIDCALL;
6164         goto error;
6165     }
6166 
6167     glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
6168     raw_outline = HeapAlloc(GetProcessHeap(), 0, bufsize);
6169     if (!glyphs || !raw_outline) {
6170         hr = E_OUTOFMEMORY;
6171         goto error;
6172     }
6173 
6174     offset_x = 0.0f;
6175     for (i = 0; i < textlen; i++)
6176     {
6177         /* get outline points from data returned from GetGlyphOutline */
6178         int datasize;
6179 
6180         glyphs[i].offset_x = offset_x;
6181 
6182         datasize = GetGlyphOutlineW(hdc, text[i], GGO_NATIVE, &gm, bufsize, raw_outline, &identity);
6183         hr = create_outline(&glyphs[i], raw_outline, datasize,
6184                             max_deviation_sq, otm.otmEMSquare, &cos_table);
6185         if (hr != S_OK) goto error;
6186 
6187         triangulations.glyph = &glyphs[i];
6188         hr = triangulate(&triangulations);
6189         if (hr != S_OK) goto error;
6190         if (triangulations.count) {
6191             ERR("%d incomplete triangulations of glyph (%u).\n", triangulations.count, text[i]);
6192             triangulations.count = 0;
6193         }
6194 
6195         if (glyphmetrics)
6196         {
6197             glyphmetrics[i].gmfBlackBoxX = gm.gmBlackBoxX / (float)otm.otmEMSquare;
6198             glyphmetrics[i].gmfBlackBoxY = gm.gmBlackBoxY / (float)otm.otmEMSquare;
6199             glyphmetrics[i].gmfptGlyphOrigin.x = gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare;
6200             glyphmetrics[i].gmfptGlyphOrigin.y = gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare;
6201             glyphmetrics[i].gmfCellIncX = gm.gmCellIncX / (float)otm.otmEMSquare;
6202             glyphmetrics[i].gmfCellIncY = gm.gmCellIncY / (float)otm.otmEMSquare;
6203         }
6204         offset_x += gm.gmCellIncX / (float)otm.otmEMSquare;
6205     }
6206 
6207     /* corner points need an extra vertex for the different side faces normals */
6208     nb_corners = 0;
6209     nb_outline_points = 0;
6210     nb_front_faces = 0;
6211     for (i = 0; i < textlen; i++)
6212     {
6213         int j;
6214         nb_outline_points += glyphs[i].ordered_vertices.count;
6215         nb_front_faces += glyphs[i].faces.count;
6216         for (j = 0; j < glyphs[i].outlines.count; j++)
6217         {
6218             int k;
6219             struct outline *outline = &glyphs[i].outlines.items[j];
6220             nb_corners++; /* first outline point always repeated as a corner */
6221             for (k = 1; k < outline->count; k++)
6222                 if (outline->items[k].corner)
6223                     nb_corners++;
6224         }
6225     }
6226 
6227     nb_vertices = (nb_outline_points + nb_corners) * 2 + nb_outline_points * 2;
6228     nb_faces = nb_outline_points * 2 + nb_front_faces * 2;
6229 
6230 
6231     hr = D3DXCreateMeshFVF(nb_faces, nb_vertices, D3DXMESH_MANAGED,
6232                            D3DFVF_XYZ | D3DFVF_NORMAL, device, &mesh);
6233     if (FAILED(hr))
6234         goto error;
6235 
6236     if (FAILED(hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
6237         goto error;
6238 
6239     if (FAILED(hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, (void **)&faces)))
6240         goto error;
6241 
6242     /* convert 2D vertices and faces into 3D mesh */
6243     vertex_ptr = vertices;
6244     face_ptr = faces;
6245     if (extrusion == 0.0f) {
6246         f1 = 1;
6247         f2 = 2;
6248     } else {
6249         f1 = 2;
6250         f2 = 1;
6251     }
6252     for (i = 0; i < textlen; i++)
6253     {
6254         int j;
6255         int count;
6256         struct vertex *back_vertices;
6257         face *back_faces;
6258 
6259         /* side vertices and faces */
6260         for (j = 0; j < glyphs[i].outlines.count; j++)
6261         {
6262             struct vertex *outline_vertices = vertex_ptr;
6263             struct outline *outline = &glyphs[i].outlines.items[j];
6264             int k;
6265             struct point2d *prevpt = &outline->items[outline->count - 1];
6266             struct point2d *pt = &outline->items[0];
6267 
6268             for (k = 1; k <= outline->count; k++)
6269             {
6270                 struct vertex vtx;
6271                 struct point2d *nextpt = &outline->items[k % outline->count];
6272                 WORD vtx_idx = vertex_ptr - vertices;
6273                 D3DXVECTOR2 vec;
6274 
6275                 if (pt->corner == POINTTYPE_CURVE_START)
6276                     D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
6277                 else if (pt->corner)
6278                     D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
6279                 else
6280                     D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
6281                 D3DXVec2Normalize(&vec, &vec);
6282                 vtx.normal.x = -vec.y;
6283                 vtx.normal.y = vec.x;
6284                 vtx.normal.z = 0;
6285 
6286                 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
6287                 vtx.position.y = pt->pos.y;
6288                 vtx.position.z = 0;
6289                 *vertex_ptr++ = vtx;
6290 
6291                 vtx.position.z = -extrusion;
6292                 *vertex_ptr++ = vtx;
6293 
6294                 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
6295                 vtx.position.y = nextpt->pos.y;
6296                 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
6297                     vtx.position.z = -extrusion;
6298                     *vertex_ptr++ = vtx;
6299                     vtx.position.z = 0;
6300                     *vertex_ptr++ = vtx;
6301 
6302                     (*face_ptr)[0] = vtx_idx;
6303                     (*face_ptr)[1] = vtx_idx + 2;
6304                     (*face_ptr)[2] = vtx_idx + 1;
6305                     face_ptr++;
6306 
6307                     (*face_ptr)[0] = vtx_idx;
6308                     (*face_ptr)[1] = vtx_idx + 3;
6309                     (*face_ptr)[2] = vtx_idx + 2;
6310                     face_ptr++;
6311                 } else {
6312                     if (nextpt->corner) {
6313                         if (nextpt->corner == POINTTYPE_CURVE_END) {
6314                             D3DXVECTOR2 *nextpt2 = &outline->items[(k + 1) % outline->count].pos;
6315                             D3DXVec2Subtract(&vec, nextpt2, &nextpt->pos);
6316                         } else {
6317                             D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
6318                         }
6319                         D3DXVec2Normalize(&vec, &vec);
6320                         vtx.normal.x = -vec.y;
6321                         vtx.normal.y = vec.x;
6322 
6323                         vtx.position.z = 0;
6324                         *vertex_ptr++ = vtx;
6325                         vtx.position.z = -extrusion;
6326                         *vertex_ptr++ = vtx;
6327                     }
6328 
6329                     (*face_ptr)[0] = vtx_idx;
6330                     (*face_ptr)[1] = vtx_idx + 3;
6331                     (*face_ptr)[2] = vtx_idx + 1;
6332                     face_ptr++;
6333 
6334                     (*face_ptr)[0] = vtx_idx;
6335                     (*face_ptr)[1] = vtx_idx + 2;
6336                     (*face_ptr)[2] = vtx_idx + 3;
6337                     face_ptr++;
6338                 }
6339 
6340                 prevpt = pt;
6341                 pt = nextpt;
6342             }
6343             if (!pt->corner) {
6344                 *vertex_ptr++ = *outline_vertices++;
6345                 *vertex_ptr++ = *outline_vertices++;
6346             }
6347         }
6348 
6349         /* back vertices and faces */
6350         back_faces = face_ptr;
6351         back_vertices = vertex_ptr;
6352         for (j = 0; j < glyphs[i].ordered_vertices.count; j++)
6353         {
6354             D3DXVECTOR2 *pt = get_ordered_vertex(&glyphs[i], j);
6355             vertex_ptr->position.x = pt->x + glyphs[i].offset_x;
6356             vertex_ptr->position.y = pt->y;
6357             vertex_ptr->position.z = 0;
6358             vertex_ptr->normal.x = 0;
6359             vertex_ptr->normal.y = 0;
6360             vertex_ptr->normal.z = 1;
6361             vertex_ptr++;
6362         }
6363         count = back_vertices - vertices;
6364         for (j = 0; j < glyphs[i].faces.count; j++)
6365         {
6366             face *f = &glyphs[i].faces.items[j];
6367             (*face_ptr)[0] = (*f)[0] + count;
6368             (*face_ptr)[1] = (*f)[1] + count;
6369             (*face_ptr)[2] = (*f)[2] + count;
6370             face_ptr++;
6371         }
6372 
6373         /* front vertices and faces */
6374         j = count = vertex_ptr - back_vertices;
6375         while (j--)
6376         {
6377             vertex_ptr->position.x = back_vertices->position.x;
6378             vertex_ptr->position.y = back_vertices->position.y;
6379             vertex_ptr->position.z = -extrusion;
6380             vertex_ptr->normal.x = 0;
6381             vertex_ptr->normal.y = 0;
6382             vertex_ptr->normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
6383             vertex_ptr++;
6384             back_vertices++;
6385         }
6386         j = face_ptr - back_faces;
6387         while (j--)
6388         {
6389             (*face_ptr)[0] = (*back_faces)[0] + count;
6390             (*face_ptr)[1] = (*back_faces)[f1] + count;
6391             (*face_ptr)[2] = (*back_faces)[f2] + count;
6392             face_ptr++;
6393             back_faces++;
6394         }
6395     }
6396 
6397     *mesh_ptr = mesh;
6398     hr = D3D_OK;
6399 error:
6400     if (mesh) {
6401         if (faces) mesh->lpVtbl->UnlockIndexBuffer(mesh);
6402         if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
6403         if (hr != D3D_OK) mesh->lpVtbl->Release(mesh);
6404     }
6405     if (glyphs) {
6406         for (i = 0; i < textlen; i++)
6407         {
6408             int j;
6409             for (j = 0; j < glyphs[i].outlines.count; j++)
6410                 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items[j].items);
6411             HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items);
6412             HeapFree(GetProcessHeap(), 0, glyphs[i].faces.items);
6413             HeapFree(GetProcessHeap(), 0, glyphs[i].ordered_vertices.items);
6414         }
6415         HeapFree(GetProcessHeap(), 0, glyphs);
6416     }
6417     if (triangulations.items) {
6418         int i;
6419         for (i = 0; i < triangulations.count; i++)
6420             HeapFree(GetProcessHeap(), 0, triangulations.items[i].vertex_stack.items);
6421         HeapFree(GetProcessHeap(), 0, triangulations.items);
6422     }
6423     HeapFree(GetProcessHeap(), 0, raw_outline);
6424     if (oldfont) SelectObject(hdc, oldfont);
6425     if (font) DeleteObject(font);
6426 
6427     return hr;
6428 }
6429 
6430 HRESULT WINAPI D3DXValidMesh(ID3DXMesh *mesh, const DWORD *adjacency, ID3DXBuffer **errors_and_warnings)
6431 {
6432     FIXME("(%p, %p, %p): stub\n", mesh, adjacency, *errors_and_warnings);
6433 
6434     return E_NOTIMPL;
6435 }
6436 
6437 static BOOL weld_float1(void *to, void *from, FLOAT epsilon)
6438 {
6439     FLOAT *v1 = to;
6440     FLOAT *v2 = from;
6441 
6442     if (fabsf(*v1 - *v2) <= epsilon)
6443     {
6444         *v1 = *v2;
6445 
6446         return TRUE;
6447     }
6448 
6449     return FALSE;
6450 }
6451 
6452 static BOOL weld_float2(void *to, void *from, FLOAT epsilon)
6453 {
6454     D3DXVECTOR2 *v1 = to;
6455     D3DXVECTOR2 *v2 = from;
6456     FLOAT diff_x = fabsf(v1->x - v2->x);
6457     FLOAT diff_y = fabsf(v1->y - v2->y);
6458     FLOAT max_abs_diff = max(diff_x, diff_y);
6459 
6460     if (max_abs_diff <= epsilon)
6461     {
6462         memcpy(to, from, sizeof(D3DXVECTOR2));
6463 
6464         return TRUE;
6465     }
6466 
6467     return FALSE;
6468 }
6469 
6470 static BOOL weld_float3(void *to, void *from, FLOAT epsilon)
6471 {
6472     D3DXVECTOR3 *v1 = to;
6473     D3DXVECTOR3 *v2 = from;
6474     FLOAT diff_x = fabsf(v1->x - v2->x);
6475     FLOAT diff_y = fabsf(v1->y - v2->y);
6476     FLOAT diff_z = fabsf(v1->z - v2->z);
6477     FLOAT max_abs_diff = max(diff_x, diff_y);
6478     max_abs_diff = max(diff_z, max_abs_diff);
6479 
6480     if (max_abs_diff <= epsilon)
6481     {
6482         memcpy(to, from, sizeof(D3DXVECTOR3));
6483 
6484         return TRUE;
6485     }
6486 
6487     return FALSE;
6488 }
6489 
6490 static BOOL weld_float4(void *to, void *from, FLOAT epsilon)
6491 {
6492     D3DXVECTOR4 *v1 = to;
6493     D3DXVECTOR4 *v2 = from;
6494     FLOAT diff_x = fabsf(v1->x - v2->x);
6495     FLOAT diff_y = fabsf(v1->y - v2->y);
6496     FLOAT diff_z = fabsf(v1->z - v2->z);
6497     FLOAT diff_w = fabsf(v1->w - v2->w);
6498     FLOAT max_abs_diff = max(diff_x, diff_y);
6499     max_abs_diff = max(diff_z, max_abs_diff);
6500     max_abs_diff = max(diff_w, max_abs_diff);
6501 
6502     if (max_abs_diff <= epsilon)
6503     {
6504         memcpy(to, from, sizeof(D3DXVECTOR4));
6505 
6506         return TRUE;
6507     }
6508 
6509     return FALSE;
6510 }
6511 
6512 static BOOL weld_ubyte4(void *to, void *from, FLOAT epsilon)
6513 {
6514     BYTE *b1 = to;
6515     BYTE *b2 = from;
6516     BYTE truncated_epsilon = (BYTE)epsilon;
6517     BYTE diff_x = b1[0] > b2[0] ? b1[0] - b2[0] : b2[0] - b1[0];
6518     BYTE diff_y = b1[1] > b2[1] ? b1[1] - b2[1] : b2[1] - b1[1];
6519     BYTE diff_z = b1[2] > b2[2] ? b1[2] - b2[2] : b2[2] - b1[2];
6520     BYTE diff_w = b1[3] > b2[3] ? b1[3] - b2[3] : b2[3] - b1[3];
6521     BYTE max_diff = max(diff_x, diff_y);
6522     max_diff = max(diff_z, max_diff);
6523     max_diff = max(diff_w, max_diff);
6524 
6525     if (max_diff <= truncated_epsilon)
6526     {
6527         memcpy(to, from, 4 * sizeof(BYTE));
6528 
6529         return TRUE;
6530     }
6531 
6532     return FALSE;
6533 }
6534 
6535 static BOOL weld_ubyte4n(void *to, void *from, FLOAT epsilon)
6536 {
6537     return weld_ubyte4(to, from, epsilon * UCHAR_MAX);
6538 }
6539 
6540 static BOOL weld_d3dcolor(void *to, void *from, FLOAT epsilon)
6541 {
6542     return weld_ubyte4n(to, from, epsilon);
6543 }
6544 
6545 static BOOL weld_short2(void *to, void *from, FLOAT epsilon)
6546 {
6547     SHORT *s1 = to;
6548     SHORT *s2 = from;
6549     SHORT truncated_epsilon = (SHORT)epsilon;
6550     SHORT diff_x = abs(s1[0] - s2[0]);
6551     SHORT diff_y = abs(s1[1] - s2[1]);
6552     SHORT max_abs_diff = max(diff_x, diff_y);
6553 
6554     if (max_abs_diff <= truncated_epsilon)
6555     {
6556         memcpy(to, from, 2 * sizeof(SHORT));
6557 
6558         return TRUE;
6559     }
6560 
6561     return FALSE;
6562 }
6563 
6564 static BOOL weld_short2n(void *to, void *from, FLOAT epsilon)
6565 {
6566     return weld_short2(to, from, epsilon * SHRT_MAX);
6567 }
6568 
6569 static BOOL weld_short4(void *to, void *from, FLOAT epsilon)
6570 {
6571     SHORT *s1 = to;
6572     SHORT *s2 = from;
6573     SHORT truncated_epsilon = (SHORT)epsilon;
6574     SHORT diff_x = abs(s1[0] - s2[0]);
6575     SHORT diff_y = abs(s1[1] - s2[1]);
6576     SHORT diff_z = abs(s1[2] - s2[2]);
6577     SHORT diff_w = abs(s1[3] - s2[3]);
6578     SHORT max_abs_diff = max(diff_x, diff_y);
6579     max_abs_diff = max(diff_z, max_abs_diff);
6580     max_abs_diff = max(diff_w, max_abs_diff);
6581 
6582     if (max_abs_diff <= truncated_epsilon)
6583     {
6584         memcpy(to, from, 4 * sizeof(SHORT));
6585 
6586         return TRUE;
6587     }
6588 
6589     return FALSE;
6590 }
6591 
6592 static BOOL weld_short4n(void *to, void *from, FLOAT epsilon)
6593 {
6594     return weld_short4(to, from, epsilon * SHRT_MAX);
6595 }
6596 
6597 static BOOL weld_ushort2n(void *to, void *from, FLOAT epsilon)
6598 {
6599     USHORT *s1 = to;
6600     USHORT *s2 = from;
6601     USHORT scaled_epsilon = (USHORT)(epsilon * USHRT_MAX);
6602     USHORT diff_x = s1[0] > s2[0] ? s1[0] - s2[0] : s2[0] - s1[0];
6603     USHORT diff_y = s1[1] > s2[1] ? s1[1] - s2[1] : s2[1] - s1[1];
6604     USHORT max_diff = max(diff_x, diff_y);
6605 
6606     if (max_diff <= scaled_epsilon)
6607     {
6608         memcpy(to, from, 2 * sizeof(USHORT));
6609 
6610         return TRUE;
6611     }
6612 
6613     return FALSE;
6614 }
6615 
6616 static BOOL weld_ushort4n(void *to, void *from, FLOAT epsilon)
6617 {
6618     USHORT *s1 = to;
6619     USHORT *s2 = from;
6620     USHORT scaled_epsilon = (USHORT)(epsilon * USHRT_MAX);
6621     USHORT diff_x = s1[0] > s2[0] ? s1[0] - s2[0] : s2[0] - s1[0];
6622     USHORT diff_y = s1[1] > s2[1] ? s1[1] - s2[1] : s2[1] - s1[1];
6623     USHORT diff_z = s1[2] > s2[2] ? s1[2] - s2[2] : s2[2] - s1[2];
6624     USHORT diff_w = s1[3] > s2[3] ? s1[3] - s2[3] : s2[3] - s1[3];
6625     USHORT max_diff = max(diff_x, diff_y);
6626     max_diff = max(diff_z, max_diff);
6627     max_diff = max(diff_w, max_diff);
6628 
6629     if (max_diff <= scaled_epsilon)
6630     {
6631         memcpy(to, from, 4 * sizeof(USHORT));
6632 
6633         return TRUE;
6634     }
6635 
6636     return FALSE;
6637 }
6638 
6639 struct udec3
6640 {
6641     UINT x;
6642     UINT y;
6643     UINT z;
6644     UINT w;
6645 };
6646 
6647 static struct udec3 dword_to_udec3(DWORD d)
6648 {
6649     struct udec3 v;
6650 
6651     v.x = d & 0x3ff;
6652     v.y = (d & 0xffc00) >> 10;
6653     v.z = (d & 0x3ff00000) >> 20;
6654     v.w = (d & 0xc0000000) >> 30;
6655 
6656     return v;
6657 }
6658 
6659 static BOOL weld_udec3(void *to, void *from, FLOAT epsilon)
6660 {
6661     DWORD *d1 = to;
6662     DWORD *d2 = from;
6663     struct udec3 v1 = dword_to_udec3(*d1);
6664     struct udec3 v2 = dword_to_udec3(*d2);
6665     UINT truncated_epsilon = (UINT)epsilon;
6666     UINT diff_x = v1.x > v2.x ? v1.x - v2.x : v2.x - v1.x;
6667     UINT diff_y = v1.y > v2.y ? v1.y - v2.y : v2.y - v1.y;
6668     UINT diff_z = v1.z > v2.z ? v1.z - v2.z : v2.z - v1.z;
6669     UINT diff_w = v1.w > v2.w ? v1.w - v2.w : v2.w - v1.w;
6670     UINT max_diff = max(diff_x, diff_y);
6671     max_diff = max(diff_z, max_diff);
6672     max_diff = max(diff_w, max_diff);
6673 
6674     if (max_diff <= truncated_epsilon)
6675     {
6676         memcpy(to, from, sizeof(DWORD));
6677 
6678         return TRUE;
6679     }
6680 
6681     return FALSE;
6682 }
6683 
6684 struct dec3n
6685 {
6686     INT x;
6687     INT y;
6688     INT z;
6689     INT w;
6690 };
6691 
6692 static struct dec3n dword_to_dec3n(DWORD d)
6693 {
6694     struct dec3n v;
6695 
6696     v.x = d & 0x3ff;
6697     v.y = (d & 0xffc00) >> 10;
6698     v.z = (d & 0x3ff00000) >> 20;
6699     v.w = (d & 0xc0000000) >> 30;
6700 
6701     return v;
6702 }
6703 
6704 static BOOL weld_dec3n(void *to, void *from, FLOAT epsilon)
6705 {
6706     const UINT MAX_DEC3N = 511;
6707     DWORD *d1 = to;
6708     DWORD *d2 = from;
6709     struct dec3n v1 = dword_to_dec3n(*d1);
6710     struct dec3n v2 = dword_to_dec3n(*d2);
6711     INT scaled_epsilon = (INT)(epsilon * MAX_DEC3N);
6712     INT diff_x = abs(v1.x - v2.x);
6713     INT diff_y = abs(v1.y - v2.y);
6714     INT diff_z = abs(v1.z - v2.z);
6715     INT diff_w = abs(v1.w - v2.w);
6716     INT max_abs_diff = max(diff_x, diff_y);
6717     max_abs_diff = max(diff_z, max_abs_diff);
6718     max_abs_diff = max(diff_w, max_abs_diff);
6719 
6720     if (max_abs_diff <= scaled_epsilon)
6721     {
6722         memcpy(to, from, sizeof(DWORD));
6723 
6724         return TRUE;
6725     }
6726 
6727     return FALSE;
6728 }
6729 
6730 static BOOL weld_float16_2(void *to, void *from, FLOAT epsilon)
6731 {
6732     D3DXFLOAT16 *v1_float16 = to;
6733     D3DXFLOAT16 *v2_float16 = from;
6734     FLOAT diff_x;
6735     FLOAT diff_y;
6736     FLOAT max_abs_diff;
6737 #define NUM_ELEM 2
6738     FLOAT v1[NUM_ELEM];
6739     FLOAT v2[NUM_ELEM];
6740 
6741     D3DXFloat16To32Array(v1, v1_float16, NUM_ELEM);
6742     D3DXFloat16To32Array(v2, v2_float16, NUM_ELEM);
6743 
6744     diff_x = fabsf(v1[0] - v2[0]);
6745     diff_y = fabsf(v1[1] - v2[1]);
6746     max_abs_diff = max(diff_x, diff_y);
6747 
6748     if (max_abs_diff <= epsilon)
6749     {
6750         memcpy(to, from, NUM_ELEM * sizeof(D3DXFLOAT16));
6751 
6752         return TRUE;
6753     }
6754 
6755     return FALSE;
6756 #undef NUM_ELEM
6757 }
6758 
6759 static BOOL weld_float16_4(void *to, void *from, FLOAT epsilon)
6760 {
6761     D3DXFLOAT16 *v1_float16 = to;
6762     D3DXFLOAT16 *v2_float16 = from;
6763     FLOAT diff_x;
6764     FLOAT diff_y;
6765     FLOAT diff_z;
6766     FLOAT diff_w;
6767     FLOAT max_abs_diff;
6768 #define NUM_ELEM 4
6769     FLOAT v1[NUM_ELEM];
6770     FLOAT v2[NUM_ELEM];
6771 
6772     D3DXFloat16To32Array(v1, v1_float16, NUM_ELEM);
6773     D3DXFloat16To32Array(v2, v2_float16, NUM_ELEM);
6774 
6775     diff_x = fabsf(v1[0] - v2[0]);
6776     diff_y = fabsf(v1[1] - v2[1]);
6777     diff_z = fabsf(v1[2] - v2[2]);
6778     diff_w = fabsf(v1[3] - v2[3]);
6779     max_abs_diff = max(diff_x, diff_y);
6780     max_abs_diff = max(diff_z, max_abs_diff);
6781     max_abs_diff = max(diff_w, max_abs_diff);
6782 
6783     if (max_abs_diff <= epsilon)
6784     {
6785         memcpy(to, from, NUM_ELEM * sizeof(D3DXFLOAT16));
6786 
6787         return TRUE;
6788     }
6789 
6790     return FALSE;
6791 #undef NUM_ELEM
6792 }
6793 
6794 /* Sets the vertex components to the same value if they are within epsilon. */
6795 static BOOL weld_component(void *to, void *from, D3DDECLTYPE type, FLOAT epsilon)
6796 {
6797     /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6798     BOOL fixme_once_unused = FALSE;
6799     BOOL fixme_once_unknown = FALSE;
6800 
6801     switch (type)
6802     {
6803         case D3DDECLTYPE_FLOAT1:
6804             return weld_float1(to, from, epsilon);
6805 
6806         case D3DDECLTYPE_FLOAT2:
6807             return weld_float2(to, from, epsilon);
6808 
6809         case D3DDECLTYPE_FLOAT3:
6810             return weld_float3(to, from, epsilon);
6811 
6812         case D3DDECLTYPE_FLOAT4:
6813             return weld_float4(to, from, epsilon);
6814 
6815         case D3DDECLTYPE_D3DCOLOR:
6816             return weld_d3dcolor(to, from, epsilon);
6817 
6818         case D3DDECLTYPE_UBYTE4:
6819             return weld_ubyte4(to, from, epsilon);
6820 
6821         case D3DDECLTYPE_SHORT2:
6822             return weld_short2(to, from, epsilon);
6823 
6824         case D3DDECLTYPE_SHORT4:
6825             return weld_short4(to, from, epsilon);
6826 
6827         case D3DDECLTYPE_UBYTE4N:
6828             return weld_ubyte4n(to, from, epsilon);
6829 
6830         case D3DDECLTYPE_SHORT2N:
6831             return weld_short2n(to, from, epsilon);
6832 
6833         case D3DDECLTYPE_SHORT4N:
6834             return weld_short4n(to, from, epsilon);
6835 
6836         case D3DDECLTYPE_USHORT2N:
6837             return weld_ushort2n(to, from, epsilon);
6838 
6839         case D3DDECLTYPE_USHORT4N:
6840             return weld_ushort4n(to, from, epsilon);
6841 
6842         case D3DDECLTYPE_UDEC3:
6843             return weld_udec3(to, from, epsilon);
6844 
6845         case D3DDECLTYPE_DEC3N:
6846             return weld_dec3n(to, from, epsilon);
6847 
6848         case D3DDECLTYPE_FLOAT16_2:
6849             return weld_float16_2(to, from, epsilon);
6850 
6851         case D3DDECLTYPE_FLOAT16_4:
6852             return weld_float16_4(to, from, epsilon);
6853 
6854         case D3DDECLTYPE_UNUSED:
6855             if (!fixme_once_unused++)
6856                 FIXME("D3DDECLTYPE_UNUSED welding not implemented.\n");
6857             break;
6858 
6859         default:
6860             if (!fixme_once_unknown++)
6861                 FIXME("Welding of unknown declaration type %d is not implemented.\n", type);
6862             break;
6863     }
6864 
6865     return FALSE;
6866 }
6867 
6868 static FLOAT get_component_epsilon(const D3DVERTEXELEMENT9 *decl_ptr, const D3DXWELDEPSILONS *epsilons)
6869 {
6870     FLOAT epsilon = 0.0f;
6871     /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6872     static BOOL fixme_once_blendindices = FALSE;
6873     static BOOL fixme_once_positiont = FALSE;
6874     static BOOL fixme_once_fog = FALSE;
6875     static BOOL fixme_once_depth = FALSE;
6876     static BOOL fixme_once_sample = FALSE;
6877     static BOOL fixme_once_unknown = FALSE;
6878 
6879     switch (decl_ptr->Usage)
6880     {
6881         case D3DDECLUSAGE_POSITION:
6882             epsilon = epsilons->Position;
6883             break;
6884         case D3DDECLUSAGE_BLENDWEIGHT:
6885             epsilon = epsilons->BlendWeights;
6886             break;
6887         case D3DDECLUSAGE_NORMAL:
6888             epsilon = epsilons->Normals;
6889             break;
6890         case D3DDECLUSAGE_PSIZE:
6891             epsilon = epsilons->PSize;
6892             break;
6893         case D3DDECLUSAGE_TEXCOORD:
6894         {
6895             BYTE usage_index = decl_ptr->UsageIndex;
6896             if (usage_index > 7)
6897                 usage_index = 7;
6898             epsilon = epsilons->Texcoords[usage_index];
6899             break;
6900         }
6901         case D3DDECLUSAGE_TANGENT:
6902             epsilon = epsilons->Tangent;
6903             break;
6904         case D3DDECLUSAGE_BINORMAL:
6905             epsilon = epsilons->Binormal;
6906             break;
6907         case D3DDECLUSAGE_TESSFACTOR:
6908             epsilon = epsilons->TessFactor;
6909             break;
6910         case D3DDECLUSAGE_COLOR:
6911             if (decl_ptr->UsageIndex == 0)
6912                 epsilon = epsilons->Diffuse;
6913             else if (decl_ptr->UsageIndex == 1)
6914                 epsilon = epsilons->Specular;
6915             else
6916                 epsilon = 1e-6f;
6917             break;
6918         case D3DDECLUSAGE_BLENDINDICES:
6919             if (!fixme_once_blendindices++)
6920                 FIXME("D3DDECLUSAGE_BLENDINDICES welding not implemented.\n");
6921             break;
6922         case D3DDECLUSAGE_POSITIONT:
6923             if (!fixme_once_positiont++)
6924                 FIXME("D3DDECLUSAGE_POSITIONT welding not implemented.\n");
6925             break;
6926         case D3DDECLUSAGE_FOG:
6927             if (!fixme_once_fog++)
6928                 FIXME("D3DDECLUSAGE_FOG welding not implemented.\n");
6929             break;
6930         case D3DDECLUSAGE_DEPTH:
6931             if (!fixme_once_depth++)
6932                 FIXME("D3DDECLUSAGE_DEPTH welding not implemented.\n");
6933             break;
6934         case D3DDECLUSAGE_SAMPLE:
6935             if (!fixme_once_sample++)
6936                 FIXME("D3DDECLUSAGE_SAMPLE welding not implemented.\n");
6937             break;
6938         default:
6939             if (!fixme_once_unknown++)
6940                 FIXME("Unknown usage %x\n", decl_ptr->Usage);
6941             break;
6942     }
6943 
6944     return epsilon;
6945 }
6946 
6947 /* Helper function for reading a 32-bit index buffer. */
6948 static inline DWORD read_ib(void *index_buffer, BOOL indices_are_32bit,
6949                             DWORD index)
6950 {
6951     if (indices_are_32bit)
6952     {
6953         DWORD *indices = index_buffer;
6954         return indices[index];
6955     }
6956     else
6957     {
6958         WORD *indices = index_buffer;
6959         return indices[index];
6960     }
6961 }
6962 
6963 /* Helper function for writing to a 32-bit index buffer. */
6964 static inline void write_ib(void *index_buffer, BOOL indices_are_32bit,
6965                             DWORD index, DWORD value)
6966 {
6967     if (indices_are_32bit)
6968     {
6969         DWORD *indices = index_buffer;
6970         indices[index] = value;
6971     }
6972     else
6973     {
6974         WORD *indices = index_buffer;
6975         indices[index] = value;
6976     }
6977 }
6978 
6979 /*************************************************************************
6980  * D3DXWeldVertices    (D3DX9_36.@)
6981  *
6982  * Welds together similar vertices. The similarity between vert-
6983  * ices can be the position and other components such as
6984  * normal and color.
6985  *
6986  * PARAMS
6987  *   mesh             [I] Mesh which vertices will be welded together.
6988  *   flags            [I] D3DXWELDEPSILONSFLAGS specifying how to weld.
6989  *   epsilons         [I] How similar a component needs to be for welding.
6990  *   adjacency        [I] Which faces are adjacent to other faces.
6991  *   adjacency_out    [O] Updated adjacency after welding.
6992  *   face_remap_out   [O] Which faces the old faces have been mapped to.
6993  *   vertex_remap_out [O] Which vertices the old vertices have been mapped to.
6994  *
6995  * RETURNS
6996  *   Success: D3D_OK.
6997  *   Failure: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
6998  *
6999  * BUGS
7000  *   Attribute sorting not implemented.
7001  *
7002  */
7003 HRESULT WINAPI D3DXWeldVertices(ID3DXMesh *mesh, DWORD flags, const D3DXWELDEPSILONS *epsilons,
7004         const DWORD *adjacency, DWORD *adjacency_out, DWORD *face_remap_out, ID3DXBuffer **vertex_remap_out)
7005 {
7006     DWORD *adjacency_generated = NULL;
7007     const DWORD *adjacency_ptr;
7008     DWORD *attributes = NULL;
7009     const FLOAT DEFAULT_EPSILON = 1.0e-6f;
7010     HRESULT hr;
7011     DWORD i;
7012     void *indices = NULL;
7013     BOOL indices_are_32bit = mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT;
7014     DWORD optimize_flags;
7015     DWORD *point_reps = NULL;
7016     struct d3dx9_mesh *This = impl_from_ID3DXMesh(mesh);
7017     DWORD *vertex_face_map = NULL;
7018     BYTE *vertices = NULL;
7019 
7020     TRACE("mesh %p, flags %#x, epsilons %p, adjacency %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
7021             mesh, flags, epsilons, adjacency, adjacency_out, face_remap_out, vertex_remap_out);
7022 
7023     if (flags == 0)
7024     {
7025         WARN("No flags are undefined. Using D3DXWELDEPSILONS_WELDPARTIALMATCHES instead.\n");
7026         flags = D3DXWELDEPSILONS_WELDPARTIALMATCHES;
7027     }
7028 
7029     if (adjacency) /* Use supplied adjacency. */
7030     {
7031         adjacency_ptr = adjacency;
7032     }
7033     else /* Adjacency has to be generated. */
7034     {
7035         adjacency_generated = HeapAlloc(GetProcessHeap(), 0, 3 * This->numfaces * sizeof(*adjacency_generated));
7036         if (!adjacency_generated)
7037         {
7038             ERR("Couldn't allocate memory for adjacency_generated.\n");
7039             hr = E_OUTOFMEMORY;
7040             goto cleanup;
7041         }
7042         hr = mesh->lpVtbl->GenerateAdjacency(mesh, DEFAULT_EPSILON, adjacency_generated);
7043         if (FAILED(hr))
7044         {
7045             ERR("Couldn't generate adjacency.\n");
7046             goto cleanup;
7047         }
7048         adjacency_ptr = adjacency_generated;
7049     }
7050 
7051     /* Point representation says which vertices can be replaced. */
7052     point_reps = HeapAlloc(GetProcessHeap(), 0, This->numvertices * sizeof(*point_reps));
7053     if (!point_reps)
7054     {
7055         hr = E_OUTOFMEMORY;
7056         ERR("Couldn't allocate memory for point_reps.\n");
7057         goto cleanup;
7058     }
7059     hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, adjacency_ptr, point_reps);
7060     if (FAILED(hr))
7061     {
7062         ERR("ConvertAdjacencyToPointReps failed.\n");
7063         goto cleanup;
7064     }
7065 
7066     hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &indices);
7067     if (FAILED(hr))
7068     {
7069         ERR("Couldn't lock index buffer.\n");
7070         goto cleanup;
7071     }
7072 
7073     hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &attributes);
7074     if (FAILED(hr))
7075     {
7076         ERR("Couldn't lock attribute buffer.\n");
7077         goto cleanup;
7078     }
7079     vertex_face_map = HeapAlloc(GetProcessHeap(), 0, This->numvertices * sizeof(*vertex_face_map));
7080     if (!vertex_face_map)
7081     {
7082         hr = E_OUTOFMEMORY;
7083         ERR("Couldn't allocate memory for vertex_face_map.\n");
7084         goto cleanup;
7085     }
7086     /* Build vertex face map, so that a vertex's face can be looked up. */
7087     for (i = 0; i < This->numfaces; i++)
7088     {
7089         DWORD j;
7090         for (j = 0; j < 3; j++)
7091         {
7092             DWORD index = read_ib(indices, indices_are_32bit, 3*i + j);
7093             vertex_face_map[index] = i;
7094         }
7095     }
7096 
7097     if (flags & D3DXWELDEPSILONS_WELDPARTIALMATCHES)
7098     {
7099         hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void**)&vertices);
7100         if (FAILED(hr))
7101         {
7102             ERR("Couldn't lock vertex buffer.\n");
7103             goto cleanup;
7104         }
7105         /* For each vertex that can be removed, compare its vertex components
7106          * with the vertex components from the vertex that can replace it. A
7107          * vertex is only fully replaced if all the components match and the
7108          * flag D3DXWELDEPSILONS_DONOTREMOVEVERTICES is not set, and they
7109          * belong to the same attribute group. Otherwise the vertex components
7110          * that are within epsilon are set to the same value.
7111          */
7112         for (i = 0; i < 3 * This->numfaces; i++)
7113         {
7114             D3DVERTEXELEMENT9 *decl_ptr;
7115             DWORD vertex_size = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
7116             DWORD num_vertex_components;
7117             INT matches = 0;
7118             BOOL all_match;
7119             DWORD index = read_ib(indices, indices_are_32bit, i);
7120 
7121             for (decl_ptr = This->cached_declaration, num_vertex_components = 0; decl_ptr->Stream != 0xFF; decl_ptr++, num_vertex_components++)
7122             {
7123                 BYTE *to = &vertices[vertex_size*index + decl_ptr->Offset];
7124                 BYTE *from = &vertices[vertex_size*point_reps[index] + decl_ptr->Offset];
7125                 FLOAT epsilon = get_component_epsilon(decl_ptr, epsilons);
7126 
7127                 /* Don't weld self */
7128                 if (index == point_reps[index])
7129                 {
7130                     matches++;
7131                     continue;
7132                 }
7133 
7134                 if (weld_component(to, from, decl_ptr->Type, epsilon))
7135                     matches++;
7136             }
7137 
7138             all_match = (num_vertex_components == matches);
7139             if (all_match && !(flags & D3DXWELDEPSILONS_DONOTREMOVEVERTICES))
7140             {
7141                 DWORD to_face = vertex_face_map[index];
7142                 DWORD from_face = vertex_face_map[point_reps[index]];
7143                 if(attributes[to_face] != attributes[from_face] && !(flags & D3DXWELDEPSILONS_DONOTSPLIT))
7144                     continue;
7145                 write_ib(indices, indices_are_32bit, i, point_reps[index]);
7146             }
7147         }
7148         mesh->lpVtbl->UnlockVertexBuffer(mesh);
7149         vertices = NULL;
7150     }
7151     else if (flags & D3DXWELDEPSILONS_WELDALL)
7152     {
7153         for (i = 0; i < 3 * This->numfaces; i++)
7154         {
7155             DWORD index = read_ib(indices, indices_are_32bit, i);
7156             DWORD to_face = vertex_face_map[index];
7157             DWORD from_face = vertex_face_map[point_reps[index]];
7158             if(attributes[to_face] != attributes[from_face] && !(flags & D3DXWELDEPSILONS_DONOTSPLIT))
7159                 continue;
7160             write_ib(indices, indices_are_32bit, i, point_reps[index]);
7161         }
7162     }
7163     mesh->lpVtbl->UnlockAttributeBuffer(mesh);
7164     attributes = NULL;
7165     mesh->lpVtbl->UnlockIndexBuffer(mesh);
7166     indices = NULL;
7167 
7168     /* Compact mesh using OptimizeInplace */
7169     optimize_flags = D3DXMESHOPT_COMPACT;
7170     hr = mesh->lpVtbl->OptimizeInplace(mesh, optimize_flags, adjacency_ptr, adjacency_out, face_remap_out, vertex_remap_out);
7171     if (FAILED(hr))
7172     {
7173         ERR("Couldn't compact mesh.\n");
7174         goto cleanup;
7175     }
7176 
7177     hr = D3D_OK;
7178 cleanup:
7179     HeapFree(GetProcessHeap(), 0, adjacency_generated);
7180     HeapFree(GetProcessHeap(), 0, point_reps);
7181     HeapFree(GetProcessHeap(), 0, vertex_face_map);
7182     if (attributes) mesh->lpVtbl->UnlockAttributeBuffer(mesh);
7183     if (indices) mesh->lpVtbl->UnlockIndexBuffer(mesh);
7184     if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
7185 
7186     return hr;
7187 }
7188 
7189 
7190 /*************************************************************************
7191  * D3DXOptimizeVertices    (D3DX9_36.@)
7192  */
7193 HRESULT WINAPI D3DXOptimizeVertices(const void *indices, UINT num_faces,
7194         UINT num_vertices, BOOL indices_are_32bit, DWORD *vertex_remap)
7195 {
7196     UINT i;
7197 
7198     FIXME("indices %p, num_faces %u, num_vertices %u, indices_are_32bit %#x, vertex_remap %p semi-stub.\n",
7199             indices, num_faces, num_vertices, indices_are_32bit, vertex_remap);
7200 
7201     if (!vertex_remap)
7202     {
7203         WARN("vertex remap pointer is NULL.\n");
7204         return D3DERR_INVALIDCALL;
7205     }
7206 
7207     for (i = 0; i < num_vertices; i++)
7208     {
7209         vertex_remap[i] = i;
7210     }
7211 
7212     return D3D_OK;
7213 }
7214 
7215 
7216 /*************************************************************************
7217  * D3DXOptimizeFaces    (D3DX9_36.@)
7218  *
7219  * Re-orders the faces so the vertex cache is used optimally.
7220  *
7221  * PARAMS
7222  *   indices           [I] Pointer to an index buffer belonging to a mesh.
7223  *   num_faces         [I] Number of faces in the mesh.
7224  *   num_vertices      [I] Number of vertices in the mesh.
7225  *   indices_are_32bit [I] Specifies whether indices are 32- or 16-bit.
7226  *   face_remap        [I/O] The new order the faces should be drawn in.
7227  *
7228  * RETURNS
7229  *   Success: D3D_OK.
7230  *   Failure: D3DERR_INVALIDCALL.
7231  *
7232  * BUGS
7233  *   The face re-ordering does not use the vertex cache optimally.
7234  *
7235  */
7236 HRESULT WINAPI D3DXOptimizeFaces(const void *indices, UINT num_faces,
7237         UINT num_vertices, BOOL indices_are_32bit, DWORD *face_remap)
7238 {
7239     UINT i;
7240     UINT j = num_faces - 1;
7241     UINT limit_16_bit = 2 << 15; /* According to MSDN */
7242     HRESULT hr = D3D_OK;
7243 
7244     FIXME("indices %p, num_faces %u, num_vertices %u, indices_are_32bit %#x, face_remap %p semi-stub. "
7245             "Face order will not be optimal.\n",
7246             indices, num_faces, num_vertices, indices_are_32bit, face_remap);
7247 
7248     if (!indices_are_32bit && num_faces >= limit_16_bit)
7249     {
7250         WARN("Number of faces must be less than %d when using 16-bit indices.\n",
7251              limit_16_bit);
7252         hr = D3DERR_INVALIDCALL;
7253         goto error;
7254     }
7255 
7256     if (!face_remap)
7257     {
7258         WARN("Face remap pointer is NULL.\n");
7259         hr = D3DERR_INVALIDCALL;
7260         goto error;
7261     }
7262 
7263     /* The faces are drawn in reverse order for simple meshes. This ordering
7264      * is not optimal for complicated meshes, but will not break anything
7265      * either. The ordering should be changed to take advantage of the vertex
7266      * cache on the graphics card.
7267      *
7268      * TODO Re-order to take advantage of vertex cache.
7269      */
7270     for (i = 0; i < num_faces; i++)
7271     {
7272         face_remap[i] = j--;
7273     }
7274 
7275     return D3D_OK;
7276 
7277 error:
7278     return hr;
7279 }
7280 
7281 static D3DXVECTOR3 *vertex_element_vec3(BYTE *vertices, const D3DVERTEXELEMENT9 *declaration,
7282         DWORD vertex_stride, DWORD index)
7283 {
7284     return (D3DXVECTOR3 *)(vertices + declaration->Offset + index * vertex_stride);
7285 }
7286 
7287 static D3DXVECTOR3 read_vec3(BYTE *vertices, const D3DVERTEXELEMENT9 *declaration,
7288         DWORD vertex_stride, DWORD index)
7289 {
7290     D3DXVECTOR3 vec3 = {0};
7291     const D3DXVECTOR3 *src = vertex_element_vec3(vertices, declaration, vertex_stride, index);
7292 
7293     switch (declaration->Type)
7294     {
7295         case D3DDECLTYPE_FLOAT1:
7296             vec3.x = src->x;
7297             break;
7298         case D3DDECLTYPE_FLOAT2:
7299             vec3.x = src->x;
7300             vec3.y = src->y;
7301             break;
7302         case D3DDECLTYPE_FLOAT3:
7303         case D3DDECLTYPE_FLOAT4:
7304             vec3 = *src;
7305             break;
7306         default:
7307             ERR("Cannot read vec3\n");
7308             break;
7309     }
7310 
7311     return vec3;
7312 }
7313 
7314 /*************************************************************************
7315  * D3DXComputeTangentFrameEx    (D3DX9_36.@)
7316  */
7317 HRESULT WINAPI D3DXComputeTangentFrameEx(ID3DXMesh *mesh, DWORD texture_in_semantic, DWORD texture_in_index,
7318         DWORD u_partial_out_semantic, DWORD u_partial_out_index, DWORD v_partial_out_semantic,
7319         DWORD v_partial_out_index, DWORD normal_out_semantic, DWORD normal_out_index, DWORD options,
7320         const DWORD *adjacency, float partial_edge_threshold, float singular_point_threshold,
7321         float normal_edge_threshold, ID3DXMesh **mesh_out, ID3DXBuffer **vertex_mapping)
7322 {
7323     HRESULT hr;
7324     void *indices = NULL;
7325     BYTE *vertices = NULL;
7326     DWORD *point_reps = NULL;
7327     size_t normal_size;
7328     BOOL indices_are_32bit;
7329     DWORD i, j, num_faces, num_vertices, vertex_stride;
7330     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE] = {D3DDECL_END()};
7331     D3DVERTEXELEMENT9 *position_declaration = NULL, *normal_declaration = NULL;
7332     DWORD weighting_method = options & (D3DXTANGENT_WEIGHT_EQUAL | D3DXTANGENT_WEIGHT_BY_AREA);
7333 
7334     TRACE("mesh %p, texture_in_semantic %u, texture_in_index %u, u_partial_out_semantic %u, u_partial_out_index %u, "
7335             "v_partial_out_semantic %u, v_partial_out_index %u, normal_out_semantic %u, normal_out_index %u, "
7336             "options %#x, adjacency %p, partial_edge_threshold %f, singular_point_threshold %f, "
7337             "normal_edge_threshold %f, mesh_out %p, vertex_mapping %p\n",
7338             mesh, texture_in_semantic, texture_in_index, u_partial_out_semantic, u_partial_out_index,
7339             v_partial_out_semantic, v_partial_out_index, normal_out_semantic, normal_out_index, options, adjacency,
7340             partial_edge_threshold, singular_point_threshold, normal_edge_threshold, mesh_out, vertex_mapping);
7341 
7342     if (!mesh)
7343     {
7344         WARN("mesh is NULL\n");
7345         return D3DERR_INVALIDCALL;
7346     }
7347 
7348     if (weighting_method == (D3DXTANGENT_WEIGHT_EQUAL | D3DXTANGENT_WEIGHT_BY_AREA))
7349     {
7350         WARN("D3DXTANGENT_WEIGHT_BY_AREA and D3DXTANGENT_WEIGHT_EQUAL are mutally exclusive\n");
7351         return D3DERR_INVALIDCALL;
7352     }
7353 
7354     if (u_partial_out_semantic != D3DX_DEFAULT)
7355     {
7356         FIXME("tangent vectors computation is not supported\n");
7357         return E_NOTIMPL;
7358     }
7359 
7360     if (v_partial_out_semantic != D3DX_DEFAULT)
7361     {
7362         FIXME("binormal vectors computation is not supported\n");
7363         return E_NOTIMPL;
7364     }
7365 
7366     if (options & ~(D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_WEIGHT_EQUAL | D3DXTANGENT_WEIGHT_BY_AREA))
7367     {
7368         FIXME("unsupported options %#x\n", options);
7369         return E_NOTIMPL;
7370     }
7371 
7372     if (!(options & D3DXTANGENT_CALCULATE_NORMALS))
7373     {
7374         FIXME("only normals computation is supported\n");
7375         return E_NOTIMPL;
7376     }
7377 
7378     if (!(options & D3DXTANGENT_GENERATE_IN_PLACE) || mesh_out || vertex_mapping)
7379     {
7380         FIXME("only D3DXTANGENT_GENERATE_IN_PLACE is supported\n");
7381         return E_NOTIMPL;
7382     }
7383 
7384     if (FAILED(hr = mesh->lpVtbl->GetDeclaration(mesh, declaration)))
7385         return hr;
7386 
7387     for (i = 0; declaration[i].Stream != 0xff; i++)
7388     {
7389         if (declaration[i].Usage == D3DDECLUSAGE_POSITION && !declaration[i].UsageIndex)
7390             position_declaration = &declaration[i];
7391         if (declaration[i].Usage == normal_out_semantic && declaration[i].UsageIndex == normal_out_index)
7392             normal_declaration = &declaration[i];
7393     }
7394 
7395     if (!position_declaration || !normal_declaration)
7396         return D3DERR_INVALIDCALL;
7397 
7398     if (normal_declaration->Type == D3DDECLTYPE_FLOAT3)
7399     {
7400         normal_size = sizeof(D3DXVECTOR3);
7401     }
7402     else if (normal_declaration->Type == D3DDECLTYPE_FLOAT4)
7403     {
7404         normal_size = sizeof(D3DXVECTOR4);
7405     }
7406     else
7407     {
7408         WARN("unsupported normals type %u\n", normal_declaration->Type);
7409         return D3DERR_INVALIDCALL;
7410     }
7411 
7412     num_faces = mesh->lpVtbl->GetNumFaces(mesh);
7413     num_vertices = mesh->lpVtbl->GetNumVertices(mesh);
7414     vertex_stride = mesh->lpVtbl->GetNumBytesPerVertex(mesh);
7415     indices_are_32bit = mesh->lpVtbl->GetOptions(mesh) & D3DXMESH_32BIT;
7416 
7417     point_reps = HeapAlloc(GetProcessHeap(), 0, num_vertices * sizeof(*point_reps));
7418     if (!point_reps)
7419     {
7420         hr = E_OUTOFMEMORY;
7421         goto done;
7422     }
7423 
7424     if (adjacency)
7425     {
7426         if (FAILED(hr = mesh->lpVtbl->ConvertAdjacencyToPointReps(mesh, adjacency, point_reps)))
7427             goto done;
7428     }
7429     else
7430     {
7431         for (i = 0; i < num_vertices; i++)
7432             point_reps[i] = i;
7433     }
7434 
7435     if (FAILED(hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &indices)))
7436         goto done;
7437 
7438     if (FAILED(hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, (void **)&vertices)))
7439         goto done;
7440 
7441     for (i = 0; i < num_vertices; i++)
7442     {
7443         static const D3DXVECTOR4 default_vector = {0.0f, 0.0f, 0.0f, 1.0f};
7444         void *normal = vertices + normal_declaration->Offset + i * vertex_stride;
7445 
7446         memcpy(normal, &default_vector, normal_size);
7447     }
7448 
7449     for (i = 0; i < num_faces; i++)
7450     {
7451         float denominator, weights[3];
7452         D3DXVECTOR3 a, b, cross, face_normal;
7453         const DWORD face_indices[3] =
7454         {
7455             read_ib(indices, indices_are_32bit, 3 * i + 0),
7456             read_ib(indices, indices_are_32bit, 3 * i + 1),
7457             read_ib(indices, indices_are_32bit, 3 * i + 2)
7458         };
7459         const D3DXVECTOR3 v0 = read_vec3(vertices, position_declaration, vertex_stride, face_indices[0]);
7460         const D3DXVECTOR3 v1 = read_vec3(vertices, position_declaration, vertex_stride, face_indices[1]);
7461         const D3DXVECTOR3 v2 = read_vec3(vertices, position_declaration, vertex_stride, face_indices[2]);
7462 
7463         D3DXVec3Cross(&cross, D3DXVec3Subtract(&a, &v0, &v1), D3DXVec3Subtract(&b, &v0, &v2));
7464 
7465         switch (weighting_method)
7466         {
7467             case D3DXTANGENT_WEIGHT_EQUAL:
7468                 weights[0] = weights[1] = weights[2] = 1.0f;
7469                 break;
7470             case D3DXTANGENT_WEIGHT_BY_AREA:
7471                 weights[0] = weights[1] = weights[2] = D3DXVec3Length(&cross);
7472                 break;
7473             default:
7474                 /* weight by angle */
7475                 denominator = D3DXVec3Length(&a) * D3DXVec3Length(&b);
7476                 if (!denominator)
7477                     weights[0] = 0.0f;
7478                 else
7479                     weights[0] = acosf(D3DXVec3Dot(&a, &b) / denominator);
7480 
7481                 D3DXVec3Subtract(&a, &v1, &v0);
7482                 D3DXVec3Subtract(&b, &v1, &v2);
7483                 denominator = D3DXVec3Length(&a) * D3DXVec3Length(&b);
7484                 if (!denominator)
7485                     weights[1] = 0.0f;
7486                 else
7487                     weights[1] = acosf(D3DXVec3Dot(&a, &b) / denominator);
7488 
7489                 D3DXVec3Subtract(&a, &v2, &v0);
7490                 D3DXVec3Subtract(&b, &v2, &v1);
7491                 denominator = D3DXVec3Length(&a) * D3DXVec3Length(&b);
7492                 if (!denominator)
7493                     weights[2] = 0.0f;
7494                 else
7495                     weights[2] = acosf(D3DXVec3Dot(&a, &b) / denominator);
7496 
7497                 break;
7498         }
7499 
7500         D3DXVec3Normalize(&face_normal, &cross);
7501 
7502         for (j = 0; j < 3; j++)
7503         {
7504             D3DXVECTOR3 normal;
7505             DWORD rep_index = point_reps[face_indices[j]];
7506             D3DXVECTOR3 *rep_normal = vertex_element_vec3(vertices, normal_declaration, vertex_stride, rep_index);
7507 
7508             D3DXVec3Scale(&normal, &face_normal, weights[j]);
7509             D3DXVec3Add(rep_normal, rep_normal, &normal);
7510         }
7511     }
7512 
7513     for (i = 0; i < num_vertices; i++)
7514     {
7515         DWORD rep_index = point_reps[i];
7516         D3DXVECTOR3 *normal = vertex_element_vec3(vertices, normal_declaration, vertex_stride, i);
7517         D3DXVECTOR3 *rep_normal = vertex_element_vec3(vertices, normal_declaration, vertex_stride, rep_index);
7518 
7519         if (i == rep_index)
7520             D3DXVec3Normalize(rep_normal, rep_normal);
7521         else
7522             *normal = *rep_normal;
7523     }
7524 
7525     hr = D3D_OK;
7526 
7527 done:
7528     if (vertices)
7529         mesh->lpVtbl->UnlockVertexBuffer(mesh);
7530 
7531     if (indices)
7532         mesh->lpVtbl->UnlockIndexBuffer(mesh);
7533 
7534     HeapFree(GetProcessHeap(), 0, point_reps);
7535 
7536     return hr;
7537 }
7538 
7539 /*************************************************************************
7540  * D3DXComputeTangent    (D3DX9_36.@)
7541  */
7542 HRESULT WINAPI D3DXComputeTangent(ID3DXMesh *mesh, DWORD stage_idx, DWORD tangent_idx,
7543         DWORD binorm_idx, DWORD wrap, const DWORD *adjacency)
7544 {
7545     TRACE("mesh %p, stage_idx %d, tangent_idx %d, binorm_idx %d, wrap %d, adjacency %p.\n",
7546            mesh, stage_idx, tangent_idx, binorm_idx, wrap, adjacency);
7547 
7548     return D3DXComputeTangentFrameEx( mesh, D3DDECLUSAGE_TEXCOORD, stage_idx,
7549             ( binorm_idx == D3DX_DEFAULT ) ? D3DX_DEFAULT : D3DDECLUSAGE_BINORMAL,
7550             binorm_idx,
7551             ( tangent_idx == D3DX_DEFAULT ) ? D3DX_DEFAULT : D3DDECLUSAGE_TANGENT,
7552             tangent_idx, D3DX_DEFAULT, 0,
7553             ( wrap ? D3DXTANGENT_WRAP_UV : 0 ) | D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_ORTHOGONALIZE_FROM_U,
7554             adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL);
7555 }
7556 
7557 /*************************************************************************
7558  * D3DXComputeNormals    (D3DX9_36.@)
7559  */
7560 HRESULT WINAPI D3DXComputeNormals(struct ID3DXBaseMesh *mesh, const DWORD *adjacency)
7561 {
7562     TRACE("mesh %p, adjacency %p\n", mesh, adjacency);
7563 
7564     if (mesh && (ID3DXMeshVtbl *)mesh->lpVtbl != &D3DXMesh_Vtbl)
7565     {
7566         ERR("Invalid virtual table\n");
7567         return D3DERR_INVALIDCALL;
7568     }
7569 
7570     return D3DXComputeTangentFrameEx((ID3DXMesh *)mesh, D3DX_DEFAULT, 0,
7571             D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DDECLUSAGE_NORMAL, 0,
7572             D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
7573             adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL);
7574 }
7575 
7576 /*************************************************************************
7577  * D3DXIntersect    (D3DX9_36.@)
7578  */
7579 HRESULT WINAPI D3DXIntersect(ID3DXBaseMesh *mesh, const D3DXVECTOR3 *ray_pos, const D3DXVECTOR3 *ray_dir,
7580         BOOL *hit, DWORD *face_index, float *u, float *v, float *distance, ID3DXBuffer **all_hits, DWORD *count_of_hits)
7581 {
7582     FIXME("mesh %p, ray_pos %p, ray_dir %p, hit %p, face_index %p, u %p, v %p, distance %p, all_hits %p, "
7583             "count_of_hits %p stub!\n", mesh, ray_pos, ray_dir, hit, face_index, u, v, distance, all_hits, count_of_hits);
7584 
7585     return E_NOTIMPL;
7586 }
7587 
7588 HRESULT WINAPI D3DXTessellateNPatches(ID3DXMesh *mesh, const DWORD *adjacency_in, float num_segs,
7589         BOOL quadratic_normals, ID3DXMesh **mesh_out, ID3DXBuffer **adjacency_out)
7590 {
7591     FIXME("mesh %p, adjacency_in %p, num_segs %f, quadratic_normals %d, mesh_out %p, adjacency_out %p stub.\n",
7592             mesh, adjacency_in, num_segs, quadratic_normals, mesh_out, adjacency_out);
7593 
7594     return E_NOTIMPL;
7595 }
7596 
7597 HRESULT WINAPI D3DXConvertMeshSubsetToSingleStrip(struct ID3DXBaseMesh *mesh_in, DWORD attribute_id,
7598         DWORD ib_flags, struct IDirect3DIndexBuffer9 **index_buffer, DWORD *index_count)
7599 {
7600     FIXME("mesh_in %p, attribute_id %u, ib_flags %u, index_buffer %p, index_count %p stub.\n",
7601             mesh_in, attribute_id, ib_flags, index_buffer, index_count);
7602 
7603     return E_NOTIMPL;
7604 }
7605 
7606 struct frame_node
7607 {
7608     struct list entry;
7609     D3DXFRAME *frame;
7610 };
7611 
7612 static BOOL queue_frame_node(struct list *queue, D3DXFRAME *frame)
7613 {
7614     struct frame_node *node;
7615 
7616     if (!frame->pFrameFirstChild)
7617         return TRUE;
7618 
7619     node = HeapAlloc(GetProcessHeap(), 0, sizeof(*node));
7620     if (!node)
7621         return FALSE;
7622 
7623     node->frame = frame;
7624     list_add_tail(queue, &node->entry);
7625 
7626     return TRUE;
7627 }
7628 
7629 static void empty_frame_queue(struct list *queue)
7630 {
7631     struct frame_node *cur, *cur2;
7632     LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, queue, struct frame_node, entry)
7633     {
7634         list_remove(&cur->entry);
7635         HeapFree(GetProcessHeap(), 0, cur);
7636     }
7637 }
7638 
7639 D3DXFRAME * WINAPI D3DXFrameFind(const D3DXFRAME *root, const char *name)
7640 {
7641     D3DXFRAME *found = NULL, *frame;
7642     struct list queue;
7643 
7644     TRACE("root frame %p, name %s.\n", root, debugstr_a(name));
7645 
7646     if (!root)
7647         return NULL;
7648 
7649     list_init(&queue);
7650 
7651     frame = (D3DXFRAME *)root;
7652 
7653     for (;;)
7654     {
7655         struct frame_node *node;
7656 
7657         while (frame)
7658         {
7659             if ((name && frame->Name && !strcmp(frame->Name, name)) || (!name && !frame->Name))
7660             {
7661                 found = frame;
7662                 goto cleanup;
7663             }
7664 
7665             if (!queue_frame_node(&queue, frame))
7666                 goto cleanup;
7667 
7668             frame = frame->pFrameSibling;
7669         }
7670 
7671         if (list_empty(&queue))
7672             break;
7673 
7674         node = LIST_ENTRY(list_head(&queue), struct frame_node, entry);
7675         list_remove(&node->entry);
7676         frame = node->frame->pFrameFirstChild;
7677         HeapFree(GetProcessHeap(), 0, node);
7678     }
7679 
7680 cleanup:
7681     empty_frame_queue(&queue);
7682 
7683     return found;
7684 }
7685