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