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