2 * Mesh operations specific to D3DX9.
4 * Copyright (C) 2005 Henri Verbeet
5 * Copyright (C) 2006 Ivan Gyurdiev
6 * Copyright (C) 2009 David Adam
7 * Copyright (C) 2010 Tony Wasserka
8 * Copyright (C) 2011 Dylan Smith
9 * Copyright (C) 2011 Michael Mc Donnell
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
30 #define NONAMELESSUNION
39 #include "wine/debug.h"
40 #include "wine/unicode.h"
41 #include "wine/list.h"
42 #include "d3dx9_36_private.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
46 typedef struct ID3DXMeshImpl
48 ID3DXMesh ID3DXMesh_iface
;
55 IDirect3DDevice9
*device
;
56 D3DVERTEXELEMENT9 cached_declaration
[MAX_FVF_DECL_SIZE
];
57 IDirect3DVertexDeclaration9
*vertex_declaration
;
58 UINT vertex_declaration_size
;
60 IDirect3DVertexBuffer9
*vertex_buffer
;
61 IDirect3DIndexBuffer9
*index_buffer
;
63 int attrib_buffer_lock_count
;
64 DWORD attrib_table_size
;
65 D3DXATTRIBUTERANGE
*attrib_table
;
68 static inline ID3DXMeshImpl
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
70 return CONTAINING_RECORD(iface
, ID3DXMeshImpl
, ID3DXMesh_iface
);
73 static HRESULT WINAPI
ID3DXMeshImpl_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, LPVOID
*object
)
75 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
77 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), object
);
79 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
80 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
81 IsEqualGUID(riid
, &IID_ID3DXMesh
))
83 iface
->lpVtbl
->AddRef(iface
);
88 WARN("Interface %s not found.\n", debugstr_guid(riid
));
93 static ULONG WINAPI
ID3DXMeshImpl_AddRef(ID3DXMesh
*iface
)
95 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
97 TRACE("(%p)->(): AddRef from %d\n", This
, This
->ref
);
99 return InterlockedIncrement(&This
->ref
);
102 static ULONG WINAPI
ID3DXMeshImpl_Release(ID3DXMesh
*iface
)
104 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
105 ULONG ref
= InterlockedDecrement(&This
->ref
);
107 TRACE("(%p)->(): Release from %d\n", This
, ref
+ 1);
111 IDirect3DIndexBuffer9_Release(This
->index_buffer
);
112 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
113 if (This
->vertex_declaration
)
114 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
115 IDirect3DDevice9_Release(This
->device
);
116 HeapFree(GetProcessHeap(), 0, This
->attrib_buffer
);
117 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
118 HeapFree(GetProcessHeap(), 0, This
);
124 /*** ID3DXBaseMesh ***/
125 static HRESULT WINAPI
ID3DXMeshImpl_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
127 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
133 TRACE("(%p)->(%u)\n", This
, attrib_id
);
135 if (!This
->vertex_declaration
)
137 WARN("Can't draw a mesh with an invalid vertex declaration.\n");
141 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
143 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
144 if (FAILED(hr
)) return hr
;
145 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
146 if (FAILED(hr
)) return hr
;
147 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
148 if (FAILED(hr
)) return hr
;
150 while (face_end
< This
->numfaces
)
152 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
154 if (This
->attrib_buffer
[face_start
] == attrib_id
)
157 if (face_start
>= This
->numfaces
)
159 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
161 if (This
->attrib_buffer
[face_end
] != attrib_id
)
165 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
166 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
167 if (FAILED(hr
)) return hr
;
173 static DWORD WINAPI
ID3DXMeshImpl_GetNumFaces(ID3DXMesh
*iface
)
175 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
177 TRACE("(%p)\n", This
);
179 return This
->numfaces
;
182 static DWORD WINAPI
ID3DXMeshImpl_GetNumVertices(ID3DXMesh
*iface
)
184 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
186 TRACE("(%p)\n", This
);
188 return This
->numvertices
;
191 static DWORD WINAPI
ID3DXMeshImpl_GetFVF(ID3DXMesh
*iface
)
193 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
195 TRACE("(%p)\n", This
);
200 static void copy_declaration(D3DVERTEXELEMENT9
*dst
, const D3DVERTEXELEMENT9
*src
, UINT num_elem
)
202 memcpy(dst
, src
, num_elem
* sizeof(*src
));
205 static HRESULT WINAPI
ID3DXMeshImpl_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
207 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
209 TRACE("(%p)\n", This
);
211 if (declaration
== NULL
) return D3DERR_INVALIDCALL
;
213 copy_declaration(declaration
, This
->cached_declaration
, This
->num_elem
);
218 static DWORD WINAPI
ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh
*iface
)
220 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
222 TRACE("iface (%p)\n", This
);
224 return This
->vertex_declaration_size
;
227 static DWORD WINAPI
ID3DXMeshImpl_GetOptions(ID3DXMesh
*iface
)
229 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
231 TRACE("(%p)\n", This
);
233 return This
->options
;
236 static HRESULT WINAPI
ID3DXMeshImpl_GetDevice(ID3DXMesh
*iface
, LPDIRECT3DDEVICE9
*device
)
238 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
240 TRACE("(%p)->(%p)\n", This
, device
);
242 if (device
== NULL
) return D3DERR_INVALIDCALL
;
243 *device
= This
->device
;
244 IDirect3DDevice9_AddRef(This
->device
);
249 static HRESULT WINAPI
ID3DXMeshImpl_CloneMeshFVF(ID3DXMesh
*iface
, DWORD options
, DWORD fvf
, LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*clone_mesh
)
251 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
253 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
255 TRACE("(%p)->(%x,%x,%p,%p)\n", This
, options
, fvf
, device
, clone_mesh
);
257 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
258 if (FAILED(hr
)) return hr
;
260 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
263 static HRESULT WINAPI
ID3DXMeshImpl_CloneMesh(ID3DXMesh
*iface
, DWORD options
, CONST D3DVERTEXELEMENT9
*declaration
, LPDIRECT3DDEVICE9 device
,
264 LPD3DXMESH
*clone_mesh_out
)
266 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
267 ID3DXMeshImpl
*cloned_this
;
268 ID3DXMesh
*clone_mesh
;
269 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
270 void *data_in
, *data_out
;
275 TRACE("(%p)->(%x,%p,%p,%p)\n", This
, options
, declaration
, device
, clone_mesh_out
);
278 return D3DERR_INVALIDCALL
;
280 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
281 if (FAILED(hr
)) return hr
;
283 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++) {
284 if (memcmp(&orig_declaration
[i
], &declaration
[i
], sizeof(*declaration
)))
286 FIXME("Vertex buffer conversion not implemented.\n");
291 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
292 declaration
, device
, &clone_mesh
);
293 if (FAILED(hr
)) return hr
;
295 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
296 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
298 if (options
& D3DXMESH_VB_SHARE
) {
299 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
300 /* FIXME: refactor to avoid creating a new vertex buffer */
301 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
302 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
304 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
305 if (FAILED(hr
)) goto error
;
306 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, D3DLOCK_DISCARD
, &data_out
);
308 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
311 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
312 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
313 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
316 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
317 if (FAILED(hr
)) goto error
;
318 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, D3DLOCK_DISCARD
, &data_out
);
320 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
323 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
324 if (options
& D3DXMESH_32BIT
) {
325 for (i
= 0; i
< This
->numfaces
* 3; i
++)
326 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
328 for (i
= 0; i
< This
->numfaces
* 3; i
++)
329 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
332 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
334 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
335 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
337 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
339 if (This
->attrib_table_size
)
341 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
342 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
343 if (!cloned_this
->attrib_table
) {
347 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
350 *clone_mesh_out
= clone_mesh
;
354 IUnknown_Release(clone_mesh
);
358 static HRESULT WINAPI
ID3DXMeshImpl_GetVertexBuffer(ID3DXMesh
*iface
, LPDIRECT3DVERTEXBUFFER9
*vertex_buffer
)
360 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
362 TRACE("(%p)->(%p)\n", This
, vertex_buffer
);
364 if (vertex_buffer
== NULL
) return D3DERR_INVALIDCALL
;
365 *vertex_buffer
= This
->vertex_buffer
;
366 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
371 static HRESULT WINAPI
ID3DXMeshImpl_GetIndexBuffer(ID3DXMesh
*iface
, LPDIRECT3DINDEXBUFFER9
*index_buffer
)
373 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
375 TRACE("(%p)->(%p)\n", This
, index_buffer
);
377 if (index_buffer
== NULL
) return D3DERR_INVALIDCALL
;
378 *index_buffer
= This
->index_buffer
;
379 IDirect3DIndexBuffer9_AddRef(This
->index_buffer
);
384 static HRESULT WINAPI
ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
386 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
388 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
390 return IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, data
, flags
);
393 static HRESULT WINAPI
ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh
*iface
)
395 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
397 TRACE("(%p)\n", This
);
399 return IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
402 static HRESULT WINAPI
ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
404 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
406 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
408 return IDirect3DIndexBuffer9_Lock(This
->index_buffer
, 0, 0, data
, flags
);
411 static HRESULT WINAPI
ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh
*iface
)
413 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
415 TRACE("(%p)\n", This
);
417 return IDirect3DIndexBuffer9_Unlock(This
->index_buffer
);
420 static HRESULT WINAPI
ID3DXMeshImpl_GetAttributeTable(ID3DXMesh
*iface
, D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
422 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
424 TRACE("(%p)->(%p,%p)\n", This
, attrib_table
, attrib_table_size
);
426 if (attrib_table_size
)
427 *attrib_table_size
= This
->attrib_table_size
;
430 CopyMemory(attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*attrib_table
));
435 static HRESULT WINAPI
ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
, CONST DWORD
*point_reps
, DWORD
*adjacency
)
437 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
439 FIXME("(%p)->(%p,%p): stub\n", This
, point_reps
, adjacency
);
444 /* ConvertAdjacencyToPointReps helper function.
446 * Goes around the edges of each face and replaces the vertices in any adjacent
447 * face's edge with its own vertices(if its vertices have a lower index). This
448 * way as few as possible low index vertices are shared among the faces. The
449 * re-ordered index buffer is stored in new_indices.
451 * The vertices in a point representation must be ordered sequentially, e.g.
452 * index 5 holds the index of the vertex that replaces vertex 5, i.e. if
453 * vertex 5 is replaced by vertex 3 then index 5 would contain 3. If no vertex
454 * replaces it, then it contains the same number as the index itself, e.g.
455 * index 5 would contain 5. */
456 static HRESULT
propagate_face_vertices(CONST DWORD
*adjacency
, DWORD
*point_reps
,
457 CONST DWORD
*indices
, DWORD
*new_indices
,
458 CONST DWORD face
, CONST DWORD numfaces
)
460 const unsigned int VERTS_PER_FACE
= 3;
461 DWORD edge
, opp_edge
;
462 DWORD face_base
= VERTS_PER_FACE
* face
;
464 for (edge
= 0; edge
< VERTS_PER_FACE
; edge
++)
466 DWORD adj_face
= adjacency
[face_base
+ edge
];
469 if (adj_face
== -1) /* No adjacent face. */
471 else if (adj_face
>= numfaces
)
473 /* This throws exception on Windows */
474 WARN("Index out of bounds. Got %d expected less than %d.\n",
476 return D3DERR_INVALIDCALL
;
478 adj_face_base
= 3 * adj_face
;
480 /* Find opposite edge in adjacent face. */
481 for (opp_edge
= 0; opp_edge
< VERTS_PER_FACE
; opp_edge
++)
483 DWORD opp_edge_index
= adj_face_base
+ opp_edge
;
484 if (adjacency
[opp_edge_index
] == face
)
485 break; /* Found opposite edge. */
488 /* Replaces vertices in opposite edge with vertices from current edge. */
489 for (i
= 0, j
= 1; i
< 2 && (j
+1) > 0; i
++, j
--)
491 DWORD from
= face_base
+ (edge
+ j
) % VERTS_PER_FACE
;
492 DWORD to
= adj_face_base
+ (opp_edge
+ i
) % VERTS_PER_FACE
;
494 /* Propagate lowest index. */
495 if (new_indices
[to
] > new_indices
[from
])
497 new_indices
[to
] = new_indices
[from
];
498 point_reps
[indices
[to
]] = new_indices
[from
];
506 static HRESULT WINAPI
ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
, CONST DWORD
*adjacency
, DWORD
*point_reps
)
511 DWORD
*indices
= NULL
;
512 WORD
*indices_16bit
= NULL
;
513 DWORD
*new_indices
= NULL
;
514 const unsigned int VERTS_PER_FACE
= 3;
516 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
518 TRACE("(%p)->(%p,%p)\n", This
, adjacency
, point_reps
);
522 WARN("NULL adjacency.\n");
523 hr
= D3DERR_INVALIDCALL
;
529 WARN("NULL point_reps.\n");
530 hr
= D3DERR_INVALIDCALL
;
534 /* Should never happen as CreateMesh does not allow meshes with 0 faces */
535 if (This
->numfaces
== 0)
537 ERR("Number of faces was zero.\n");
538 hr
= D3DERR_INVALIDCALL
;
542 new_indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
549 if (This
->options
& D3DXMESH_32BIT
)
551 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
552 if (FAILED(hr
)) goto cleanup
;
553 memcpy(new_indices
, indices
, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
557 /* Make a widening copy of indices_16bit into indices and new_indices
558 * in order to re-use the helper function */
559 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices_16bit
);
560 if (FAILED(hr
)) goto cleanup
;
561 indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
567 for (i
= 0; i
< VERTS_PER_FACE
* This
->numfaces
; i
++)
569 new_indices
[i
] = indices_16bit
[i
];
570 indices
[i
] = indices_16bit
[i
];
574 /* Vertices are ordered sequentially in the point representation. */
575 for (i
= 0; i
< This
->numvertices
; i
++)
580 /* Propagate vertices with low indices so as few vertices as possible
581 * are used in the mesh.
583 for (face
= 0; face
< This
->numfaces
; face
++)
585 hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
, face
, This
->numfaces
);
586 if (FAILED(hr
)) goto cleanup
;
588 /* Go in opposite direction to catch all face orderings */
589 for (face
= This
->numfaces
- 1; face
+ 1 > 0; face
--)
591 hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
, face
, This
->numfaces
);
592 if (FAILED(hr
)) goto cleanup
;
597 if (This
->options
& D3DXMESH_32BIT
)
599 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
603 if (indices_16bit
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
604 HeapFree(GetProcessHeap(), 0, indices
);
606 HeapFree(GetProcessHeap(), 0, new_indices
);
610 struct vertex_metadata
{
613 DWORD first_shared_index
;
616 static int compare_vertex_keys(const void *a
, const void *b
)
618 const struct vertex_metadata
*left
= a
;
619 const struct vertex_metadata
*right
= b
;
620 if (left
->key
== right
->key
)
622 return left
->key
< right
->key
? -1 : 1;
625 static HRESULT WINAPI
ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh
*iface
, FLOAT epsilon
, DWORD
*adjacency
)
627 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
629 BYTE
*vertices
= NULL
;
630 const DWORD
*indices
= NULL
;
633 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
634 struct vertex_metadata
*sorted_vertices
;
635 /* shared_indices links together identical indices in the index buffer so
636 * that adjacency checks can be limited to faces sharing a vertex */
637 DWORD
*shared_indices
= NULL
;
638 const FLOAT epsilon_sq
= epsilon
* epsilon
;
641 TRACE("(%p)->(%f,%p)\n", This
, epsilon
, adjacency
);
644 return D3DERR_INVALIDCALL
;
646 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
647 if (!(This
->options
& D3DXMESH_32BIT
))
648 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
649 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
651 return E_OUTOFMEMORY
;
652 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
654 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
655 if (FAILED(hr
)) goto cleanup
;
656 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
657 if (FAILED(hr
)) goto cleanup
;
659 if (!(This
->options
& D3DXMESH_32BIT
)) {
660 const WORD
*word_indices
= (const WORD
*)indices
;
661 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
662 indices
= dword_indices
;
663 for (i
= 0; i
< This
->numfaces
* 3; i
++)
664 *dword_indices
++ = *word_indices
++;
667 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
668 for (i
= 0; i
< This
->numvertices
; i
++) {
669 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
670 sorted_vertices
[i
].first_shared_index
= -1;
671 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
672 sorted_vertices
[i
].vertex_index
= i
;
674 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
675 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
676 shared_indices
[i
] = *first_shared_index
;
677 *first_shared_index
= i
;
680 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
682 for (i
= 0; i
< This
->numvertices
; i
++) {
683 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
684 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
685 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
687 while (shared_index_a
!= -1) {
689 DWORD shared_index_b
= shared_indices
[shared_index_a
];
690 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
693 while (shared_index_b
!= -1) {
694 /* faces are adjacent if they have another coincident vertex */
695 DWORD base_a
= (shared_index_a
/ 3) * 3;
696 DWORD base_b
= (shared_index_b
/ 3) * 3;
697 BOOL adjacent
= FALSE
;
700 for (k
= 0; k
< 3; k
++) {
701 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
707 for (k
= 1; k
<= 2; k
++) {
708 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
709 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
710 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
711 if (!adjacent
&& epsilon
>= 0.0f
) {
712 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
715 D3DXVec3Subtract(&delta
,
716 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
717 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
718 length_sq
= D3DXVec3LengthSq(&delta
);
719 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
722 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
723 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
724 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
725 adjacency
[adj_a
] = base_b
/ 3;
726 adjacency
[adj_b
] = base_a
/ 3;
733 shared_index_b
= shared_indices
[shared_index_b
];
735 while (++j
< This
->numvertices
) {
736 D3DXVECTOR3
*vertex_b
;
739 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
740 /* no more coincident vertices to try */
741 j
= This
->numvertices
;
744 /* check for coincidence */
745 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
746 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
747 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
748 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
753 if (j
>= This
->numvertices
)
755 shared_index_b
= sorted_vertex_b
->first_shared_index
;
758 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
759 shared_index_a
= sorted_vertex_a
->first_shared_index
;
765 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
766 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
767 HeapFree(GetProcessHeap(), 0, shared_indices
);
771 static HRESULT WINAPI
ID3DXMeshImpl_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
774 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
775 UINT vertex_declaration_size
;
778 TRACE("(%p)->(%p)\n", This
, declaration
);
782 WARN("Invalid declaration. Can't use NULL declaration.\n");
783 return D3DERR_INVALIDCALL
;
786 /* New declaration must be same size as original */
787 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
788 if (vertex_declaration_size
!= This
->vertex_declaration_size
)
790 WARN("Invalid declaration. New vertex size does not match the original vertex size.\n");
791 return D3DERR_INVALIDCALL
;
794 /* New declaration must not contain non-zero Stream value */
795 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
797 if (declaration
[i
].Stream
!= 0)
799 WARN("Invalid declaration. New declaration contains non-zero Stream value.\n");
800 return D3DERR_INVALIDCALL
;
804 This
->num_elem
= i
+ 1;
805 copy_declaration(This
->cached_declaration
, declaration
, This
->num_elem
);
807 if (This
->vertex_declaration
)
808 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
810 /* An application can pass an invalid declaration to UpdateSemantics and
811 * still expect D3D_OK (see tests). If the declaration is invalid, then
812 * subsequent calls to DrawSubset will fail. This is handled by setting the
813 * vertex declaration to NULL.
814 * GetDeclaration, GetNumBytesPerVertex must, however, use the new
815 * invalid declaration. This is handled by them using the cached vertex
816 * declaration instead of the actual vertex declaration.
818 hr
= IDirect3DDevice9_CreateVertexDeclaration(This
->device
,
820 &This
->vertex_declaration
);
823 WARN("Using invalid declaration. Calls to DrawSubset will fail.\n");
824 This
->vertex_declaration
= NULL
;
831 static HRESULT WINAPI
ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
833 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
835 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
837 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
839 if (!(flags
& D3DLOCK_READONLY
)) {
840 D3DXATTRIBUTERANGE
*attrib_table
= This
->attrib_table
;
841 This
->attrib_table_size
= 0;
842 This
->attrib_table
= NULL
;
843 HeapFree(GetProcessHeap(), 0, attrib_table
);
846 *data
= This
->attrib_buffer
;
851 static HRESULT WINAPI
ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh
*iface
)
853 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
856 TRACE("(%p)\n", This
);
858 lock_count
= InterlockedDecrement(&This
->attrib_buffer_lock_count
);
860 if (lock_count
< 0) {
861 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
862 return D3DERR_INVALIDCALL
;
868 static HRESULT WINAPI
ID3DXMeshImpl_Optimize(ID3DXMesh
*iface
, DWORD flags
, CONST DWORD
*adjacency_in
, DWORD
*adjacency_out
,
869 DWORD
*face_remap
, LPD3DXBUFFER
*vertex_remap
, LPD3DXMESH
*opt_mesh
)
871 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
873 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
874 ID3DXMesh
*optimized_mesh
;
876 TRACE("(%p)->(%x,%p,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
879 return D3DERR_INVALIDCALL
;
881 hr
= iface
->lpVtbl
->GetDeclaration(iface
, declaration
);
882 if (FAILED(hr
)) return hr
;
884 hr
= iface
->lpVtbl
->CloneMesh(iface
, This
->options
, declaration
, This
->device
, &optimized_mesh
);
885 if (FAILED(hr
)) return hr
;
887 hr
= optimized_mesh
->lpVtbl
->OptimizeInplace(optimized_mesh
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
);
889 *opt_mesh
= optimized_mesh
;
891 IUnknown_Release(optimized_mesh
);
895 /* Creates a vertex_remap that removes unused vertices.
896 * Indices are updated according to the vertex_remap. */
897 static HRESULT
compact_mesh(ID3DXMeshImpl
*This
, DWORD
*indices
, DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
900 DWORD
*vertex_remap_ptr
;
901 DWORD num_used_vertices
;
904 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
905 if (FAILED(hr
)) return hr
;
906 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
908 for (i
= 0; i
< This
->numfaces
* 3; i
++)
909 vertex_remap_ptr
[indices
[i
]] = 1;
911 /* create old->new vertex mapping */
912 num_used_vertices
= 0;
913 for (i
= 0; i
< This
->numvertices
; i
++) {
914 if (vertex_remap_ptr
[i
])
915 vertex_remap_ptr
[i
] = num_used_vertices
++;
917 vertex_remap_ptr
[i
] = -1;
919 /* convert indices */
920 for (i
= 0; i
< This
->numfaces
* 3; i
++)
921 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
923 /* create new->old vertex mapping */
924 num_used_vertices
= 0;
925 for (i
= 0; i
< This
->numvertices
; i
++) {
926 if (vertex_remap_ptr
[i
] != -1)
927 vertex_remap_ptr
[num_used_vertices
++] = i
;
929 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
930 vertex_remap_ptr
[i
] = -1;
932 *new_num_vertices
= num_used_vertices
;
937 /* count the number of unique attribute values in a sorted attribute buffer */
938 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
940 DWORD last_attribute
= attrib_buffer
[0];
941 DWORD attrib_table_size
= 1;
943 for (i
= 1; i
< numfaces
; i
++) {
944 if (attrib_buffer
[i
] != last_attribute
) {
945 last_attribute
= attrib_buffer
[i
];
949 return attrib_table_size
;
952 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
953 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
955 DWORD attrib_table_size
= 0;
956 DWORD last_attribute
= attrib_buffer
[0];
957 DWORD min_vertex
, max_vertex
;
960 attrib_table
[0].AttribId
= last_attribute
;
961 attrib_table
[0].FaceStart
= 0;
962 min_vertex
= (DWORD
)-1;
964 for (i
= 0; i
< numfaces
; i
++) {
967 if (attrib_buffer
[i
] != last_attribute
) {
968 last_attribute
= attrib_buffer
[i
];
969 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
970 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
971 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
973 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
974 attrib_table
[attrib_table_size
].FaceStart
= i
;
975 min_vertex
= (DWORD
)-1;
978 for (j
= 0; j
< 3; j
++) {
979 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
980 if (vertex_index
< min_vertex
)
981 min_vertex
= vertex_index
;
982 if (vertex_index
> max_vertex
)
983 max_vertex
= vertex_index
;
986 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
987 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
988 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
992 static int attrib_entry_compare(const DWORD
**a
, const DWORD
**b
)
994 const DWORD
*ptr_a
= *a
;
995 const DWORD
*ptr_b
= *b
;
996 int delta
= *ptr_a
- *ptr_b
;
1001 delta
= ptr_a
- ptr_b
; /* for stable sort */
1005 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
1006 static HRESULT
remap_faces_for_attrsort(ID3DXMeshImpl
*This
, const DWORD
*indices
,
1007 const DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
1009 const DWORD
**sorted_attrib_ptr_buffer
= NULL
;
1012 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
1013 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
1014 if (!*face_remap
|| !sorted_attrib_ptr_buffer
) {
1015 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
1016 return E_OUTOFMEMORY
;
1018 for (i
= 0; i
< This
->numfaces
; i
++)
1019 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
1020 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
),
1021 (int(*)(const void *, const void *))attrib_entry_compare
);
1023 for (i
= 0; i
< This
->numfaces
; i
++)
1025 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
1026 (*face_remap
)[old_face
] = i
;
1029 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
1030 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
1031 for (i
= 0; i
< This
->numfaces
; i
++)
1032 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
1037 static HRESULT WINAPI
ID3DXMeshImpl_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, CONST DWORD
*adjacency_in
, DWORD
*adjacency_out
,
1038 DWORD
*face_remap_out
, LPD3DXBUFFER
*vertex_remap_out
)
1040 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1041 void *indices
= NULL
;
1042 DWORD
*attrib_buffer
= NULL
;
1044 ID3DXBuffer
*vertex_remap
= NULL
;
1045 DWORD
*face_remap
= NULL
; /* old -> new mapping */
1046 DWORD
*dword_indices
= NULL
;
1047 DWORD new_num_vertices
= 0;
1048 DWORD new_num_alloc_vertices
= 0;
1049 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
1050 DWORD
*sorted_attrib_buffer
= NULL
;
1053 TRACE("(%p)->(%x,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
1056 return D3DERR_INVALIDCALL
;
1057 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
1058 return D3DERR_INVALIDCALL
;
1059 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1060 return D3DERR_INVALIDCALL
;
1062 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1064 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
1065 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
1066 if (flags
& D3DXMESHOPT_STRIPREORDER
)
1067 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
1071 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, (void**)&indices
);
1072 if (FAILED(hr
)) goto cleanup
;
1074 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
1075 if (!dword_indices
) return E_OUTOFMEMORY
;
1076 if (This
->options
& D3DXMESH_32BIT
) {
1077 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1079 WORD
*word_indices
= indices
;
1080 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1081 dword_indices
[i
] = *word_indices
++;
1084 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
1086 new_num_alloc_vertices
= This
->numvertices
;
1087 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
1088 if (FAILED(hr
)) goto cleanup
;
1089 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
1090 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
1092 FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
1097 hr
= iface
->lpVtbl
->LockAttributeBuffer(iface
, 0, &attrib_buffer
);
1098 if (FAILED(hr
)) goto cleanup
;
1100 hr
= remap_faces_for_attrsort(This
, dword_indices
, attrib_buffer
, &sorted_attrib_buffer
, &face_remap
);
1101 if (FAILED(hr
)) goto cleanup
;
1106 /* reorder the vertices using vertex_remap */
1107 D3DVERTEXBUFFER_DESC vertex_desc
;
1108 DWORD
*vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1109 DWORD vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1110 BYTE
*orig_vertices
;
1113 hr
= IDirect3DVertexBuffer9_GetDesc(This
->vertex_buffer
, &vertex_desc
);
1114 if (FAILED(hr
)) goto cleanup
;
1116 hr
= IDirect3DDevice9_CreateVertexBuffer(This
->device
, new_num_alloc_vertices
* vertex_size
,
1117 vertex_desc
.Usage
, This
->fvf
, vertex_desc
.Pool
, &vertex_buffer
, NULL
);
1118 if (FAILED(hr
)) goto cleanup
;
1120 hr
= IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, (void**)&orig_vertices
, D3DLOCK_READONLY
);
1121 if (FAILED(hr
)) goto cleanup
;
1123 hr
= IDirect3DVertexBuffer9_Lock(vertex_buffer
, 0, 0, (void**)&new_vertices
, D3DLOCK_DISCARD
);
1125 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1129 for (i
= 0; i
< new_num_vertices
; i
++)
1130 memcpy(new_vertices
+ i
* vertex_size
, orig_vertices
+ vertex_remap_ptr
[i
] * vertex_size
, vertex_size
);
1132 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1133 IDirect3DVertexBuffer9_Unlock(vertex_buffer
);
1134 } else if (vertex_remap_out
) {
1135 DWORD
*vertex_remap_ptr
;
1137 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), &vertex_remap
);
1138 if (FAILED(hr
)) goto cleanup
;
1139 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1140 for (i
= 0; i
< This
->numvertices
; i
++)
1141 *vertex_remap_ptr
++ = i
;
1144 if (flags
& D3DXMESHOPT_ATTRSORT
)
1146 D3DXATTRIBUTERANGE
*attrib_table
;
1147 DWORD attrib_table_size
;
1149 attrib_table_size
= count_attributes(sorted_attrib_buffer
, This
->numfaces
);
1150 attrib_table
= HeapAlloc(GetProcessHeap(), 0, attrib_table_size
* sizeof(*attrib_table
));
1151 if (!attrib_table
) {
1156 memcpy(attrib_buffer
, sorted_attrib_buffer
, This
->numfaces
* sizeof(*attrib_buffer
));
1158 /* reorder the indices using face_remap */
1159 if (This
->options
& D3DXMESH_32BIT
) {
1160 for (i
= 0; i
< This
->numfaces
; i
++)
1161 memcpy((DWORD
*)indices
+ face_remap
[i
] * 3, dword_indices
+ i
* 3, 3 * sizeof(DWORD
));
1163 WORD
*word_indices
= indices
;
1164 for (i
= 0; i
< This
->numfaces
; i
++) {
1165 DWORD new_pos
= face_remap
[i
] * 3;
1166 DWORD old_pos
= i
* 3;
1167 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1168 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1169 word_indices
[new_pos
] = dword_indices
[old_pos
];
1173 fill_attribute_table(attrib_buffer
, This
->numfaces
, indices
,
1174 This
->options
& D3DXMESH_32BIT
, attrib_table
);
1176 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1177 This
->attrib_table
= attrib_table
;
1178 This
->attrib_table_size
= attrib_table_size
;
1180 if (This
->options
& D3DXMESH_32BIT
) {
1181 memcpy(indices
, dword_indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1183 WORD
*word_indices
= indices
;
1184 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1185 *word_indices
++ = dword_indices
[i
];
1189 if (adjacency_out
) {
1191 for (i
= 0; i
< This
->numfaces
; i
++) {
1192 DWORD old_pos
= i
* 3;
1193 DWORD new_pos
= face_remap
[i
] * 3;
1194 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1195 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1196 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1199 memcpy(adjacency_out
, adjacency_in
, This
->numfaces
* 3 * sizeof(*adjacency_out
));
1202 if (face_remap_out
) {
1204 for (i
= 0; i
< This
->numfaces
; i
++)
1205 face_remap_out
[face_remap
[i
]] = i
;
1207 for (i
= 0; i
< This
->numfaces
; i
++)
1208 face_remap_out
[i
] = i
;
1211 if (vertex_remap_out
)
1212 *vertex_remap_out
= vertex_remap
;
1213 vertex_remap
= NULL
;
1215 if (vertex_buffer
) {
1216 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
1217 This
->vertex_buffer
= vertex_buffer
;
1218 vertex_buffer
= NULL
;
1219 This
->numvertices
= new_num_vertices
;
1224 HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer
);
1225 HeapFree(GetProcessHeap(), 0, face_remap
);
1226 HeapFree(GetProcessHeap(), 0, dword_indices
);
1227 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
1228 if (vertex_buffer
) IDirect3DVertexBuffer9_Release(vertex_buffer
);
1229 if (attrib_buffer
) iface
->lpVtbl
->UnlockAttributeBuffer(iface
);
1230 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1234 static HRESULT WINAPI
ID3DXMeshImpl_SetAttributeTable(ID3DXMesh
*iface
, CONST D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
1236 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1237 D3DXATTRIBUTERANGE
*new_table
= NULL
;
1239 TRACE("(%p)->(%p,%u)\n", This
, attrib_table
, attrib_table_size
);
1241 if (attrib_table_size
) {
1242 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
1244 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
1246 return E_OUTOFMEMORY
;
1248 CopyMemory(new_table
, attrib_table
, size
);
1249 } else if (attrib_table
) {
1250 return D3DERR_INVALIDCALL
;
1252 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1253 This
->attrib_table
= new_table
;
1254 This
->attrib_table_size
= attrib_table_size
;
1259 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
1261 /*** IUnknown methods ***/
1262 ID3DXMeshImpl_QueryInterface
,
1263 ID3DXMeshImpl_AddRef
,
1264 ID3DXMeshImpl_Release
,
1265 /*** ID3DXBaseMesh ***/
1266 ID3DXMeshImpl_DrawSubset
,
1267 ID3DXMeshImpl_GetNumFaces
,
1268 ID3DXMeshImpl_GetNumVertices
,
1269 ID3DXMeshImpl_GetFVF
,
1270 ID3DXMeshImpl_GetDeclaration
,
1271 ID3DXMeshImpl_GetNumBytesPerVertex
,
1272 ID3DXMeshImpl_GetOptions
,
1273 ID3DXMeshImpl_GetDevice
,
1274 ID3DXMeshImpl_CloneMeshFVF
,
1275 ID3DXMeshImpl_CloneMesh
,
1276 ID3DXMeshImpl_GetVertexBuffer
,
1277 ID3DXMeshImpl_GetIndexBuffer
,
1278 ID3DXMeshImpl_LockVertexBuffer
,
1279 ID3DXMeshImpl_UnlockVertexBuffer
,
1280 ID3DXMeshImpl_LockIndexBuffer
,
1281 ID3DXMeshImpl_UnlockIndexBuffer
,
1282 ID3DXMeshImpl_GetAttributeTable
,
1283 ID3DXMeshImpl_ConvertPointRepsToAdjacency
,
1284 ID3DXMeshImpl_ConvertAdjacencyToPointReps
,
1285 ID3DXMeshImpl_GenerateAdjacency
,
1286 ID3DXMeshImpl_UpdateSemantics
,
1288 ID3DXMeshImpl_LockAttributeBuffer
,
1289 ID3DXMeshImpl_UnlockAttributeBuffer
,
1290 ID3DXMeshImpl_Optimize
,
1291 ID3DXMeshImpl_OptimizeInplace
,
1292 ID3DXMeshImpl_SetAttributeTable
1295 /*************************************************************************
1298 BOOL WINAPI
D3DXBoxBoundProbe(CONST D3DXVECTOR3
*pmin
, CONST D3DXVECTOR3
*pmax
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
1300 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algoritm
1301 Amy Williams University of Utah
1302 Steve Barrus University of Utah
1303 R. Keith Morley University of Utah
1304 Peter Shirley University of Utah
1306 International Conference on Computer Graphics and Interactive Techniques archive
1307 ACM SIGGRAPH 2005 Courses
1308 Los Angeles, California
1310 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1312 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1313 against each slab, if there's anything left of the ray after we're
1314 done we've got an intersection of the ray with the box.
1318 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
1320 div
= 1.0f
/ praydirection
->x
;
1323 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
1324 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
1328 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
1329 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
1332 if ( tmax
< 0.0f
) return FALSE
;
1334 div
= 1.0f
/ praydirection
->y
;
1337 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
1338 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
1342 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
1343 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
1346 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
1348 if ( tymin
> tmin
) tmin
= tymin
;
1349 if ( tymax
< tmax
) tmax
= tymax
;
1351 div
= 1.0f
/ praydirection
->z
;
1354 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
1355 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
1359 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
1360 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
1363 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
1368 /*************************************************************************
1369 * D3DXComputeBoundingBox
1371 HRESULT WINAPI
D3DXComputeBoundingBox(CONST D3DXVECTOR3
*pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
1376 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
1378 *pmin
= *pfirstposition
;
1381 for(i
=0; i
<numvertices
; i
++)
1383 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
1385 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
1386 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
1388 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
1389 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
1391 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
1392 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
1398 /*************************************************************************
1399 * D3DXComputeBoundingSphere
1401 HRESULT WINAPI
D3DXComputeBoundingSphere(CONST D3DXVECTOR3
* pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, FLOAT
*pradius
)
1403 D3DXVECTOR3 temp
, temp1
;
1407 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
1415 for(i
=0; i
<numvertices
; i
++)
1417 D3DXVec3Add(&temp1
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
1421 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/((FLOAT
)numvertices
));
1423 for(i
=0; i
<numvertices
; i
++)
1425 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
1426 if ( d
> *pradius
) *pradius
= d
;
1431 static const UINT d3dx_decltype_size
[D3DDECLTYPE_UNUSED
] =
1433 /* D3DDECLTYPE_FLOAT1 */ 1 * 4,
1434 /* D3DDECLTYPE_FLOAT2 */ 2 * 4,
1435 /* D3DDECLTYPE_FLOAT3 */ 3 * 4,
1436 /* D3DDECLTYPE_FLOAT4 */ 4 * 4,
1437 /* D3DDECLTYPE_D3DCOLOR */ 4 * 1,
1438 /* D3DDECLTYPE_UBYTE4 */ 4 * 1,
1439 /* D3DDECLTYPE_SHORT2 */ 2 * 2,
1440 /* D3DDECLTYPE_SHORT4 */ 4 * 2,
1441 /* D3DDECLTYPE_UBYTE4N */ 4 * 1,
1442 /* D3DDECLTYPE_SHORT2N */ 2 * 2,
1443 /* D3DDECLTYPE_SHORT4N */ 4 * 2,
1444 /* D3DDECLTYPE_USHORT2N */ 2 * 2,
1445 /* D3DDECLTYPE_USHORT4N */ 4 * 2,
1446 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
1447 /* D3DDECLTYPE_DEC3N */ 4,
1448 /* D3DDECLTYPE_FLOAT16_2 */ 2 * 2,
1449 /* D3DDECLTYPE_FLOAT16_4 */ 4 * 2,
1452 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
1453 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
1455 declaration
[*idx
].Stream
= 0;
1456 declaration
[*idx
].Offset
= *offset
;
1457 declaration
[*idx
].Type
= type
;
1458 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
1459 declaration
[*idx
].Usage
= usage
;
1460 declaration
[*idx
].UsageIndex
= usage_idx
;
1462 *offset
+= d3dx_decltype_size
[type
];
1466 /*************************************************************************
1467 * D3DXDeclaratorFromFVF
1469 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1471 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
1472 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
1473 unsigned int offset
= 0;
1474 unsigned int idx
= 0;
1477 TRACE("fvf %#x, declaration %p.\n", fvf
, declaration
);
1479 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
1481 if (fvf
& D3DFVF_POSITION_MASK
)
1483 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
1484 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
1485 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
1487 if (has_blend_idx
) --blend_count
;
1489 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
1490 || (has_blend
&& blend_count
> 4))
1491 return D3DERR_INVALIDCALL
;
1493 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
1494 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
1496 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
1500 switch (blend_count
)
1505 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1508 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1511 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1514 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1517 ERR("Invalid blend count %u.\n", blend_count
);
1523 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
1524 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
1525 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
1526 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
1531 if (fvf
& D3DFVF_NORMAL
)
1532 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
1533 if (fvf
& D3DFVF_PSIZE
)
1534 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
1535 if (fvf
& D3DFVF_DIFFUSE
)
1536 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
1537 if (fvf
& D3DFVF_SPECULAR
)
1538 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
1540 for (i
= 0; i
< tex_count
; ++i
)
1542 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
1544 case D3DFVF_TEXTUREFORMAT1
:
1545 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
1547 case D3DFVF_TEXTUREFORMAT2
:
1548 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
1550 case D3DFVF_TEXTUREFORMAT3
:
1551 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
1553 case D3DFVF_TEXTUREFORMAT4
:
1554 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
1559 declaration
[idx
] = end_element
;
1564 /*************************************************************************
1565 * D3DXFVFFromDeclarator
1567 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
1569 unsigned int i
= 0, texture
, offset
;
1571 TRACE("(%p, %p)\n", declaration
, fvf
);
1574 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
1576 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
1577 declaration
[1].UsageIndex
== 0) &&
1578 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
1579 declaration
[2].UsageIndex
== 0))
1581 return D3DERR_INVALIDCALL
;
1583 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
1584 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
1586 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
1588 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
1592 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
1596 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
1597 declaration
[1].UsageIndex
== 0)
1599 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
1600 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
1602 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
1604 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
1608 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
1610 switch (declaration
[1].Type
)
1612 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
1613 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
1614 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
1615 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
1621 switch (declaration
[1].Type
)
1623 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
1624 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
1625 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
1626 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
1637 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
1638 declaration
[0].UsageIndex
== 0)
1640 *fvf
|= D3DFVF_XYZRHW
;
1644 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
1646 *fvf
|= D3DFVF_NORMAL
;
1649 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
1650 declaration
[i
].UsageIndex
== 0)
1652 *fvf
|= D3DFVF_PSIZE
;
1655 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
1656 declaration
[i
].UsageIndex
== 0)
1658 *fvf
|= D3DFVF_DIFFUSE
;
1661 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
1662 declaration
[i
].UsageIndex
== 1)
1664 *fvf
|= D3DFVF_SPECULAR
;
1668 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
1670 if (declaration
[i
].Stream
== 0xFF)
1674 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1675 declaration
[i
].UsageIndex
== texture
)
1677 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
1679 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1680 declaration
[i
].UsageIndex
== texture
)
1682 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
1684 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1685 declaration
[i
].UsageIndex
== texture
)
1687 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
1689 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1690 declaration
[i
].UsageIndex
== texture
)
1692 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
1696 return D3DERR_INVALIDCALL
;
1700 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
1702 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
1703 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
1705 if (declaration
[i
].Offset
!= offset
)
1707 return D3DERR_INVALIDCALL
;
1714 /*************************************************************************
1715 * D3DXGetFVFVertexSize
1717 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
1719 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
1722 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
1726 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
1728 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
1729 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
1730 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
1731 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
1733 switch (FVF
& D3DFVF_POSITION_MASK
)
1735 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
1736 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
1737 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
1738 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
1739 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
1740 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
1741 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
1742 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
1745 for (i
= 0; i
< numTextures
; i
++)
1747 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
1753 /*************************************************************************
1754 * D3DXGetDeclVertexSize
1756 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
1758 const D3DVERTEXELEMENT9
*element
;
1761 TRACE("decl %p, stream_idx %u\n", decl
, stream_idx
);
1763 if (!decl
) return 0;
1765 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
1769 if (element
->Stream
!= stream_idx
) continue;
1771 if (element
->Type
>= sizeof(d3dx_decltype_size
) / sizeof(*d3dx_decltype_size
))
1773 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
1777 type_size
= d3dx_decltype_size
[element
->Type
];
1778 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
1784 /*************************************************************************
1787 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
1789 const D3DVERTEXELEMENT9
*element
;
1791 TRACE("decl %p\n", decl
);
1793 /* null decl results in exception on Windows XP */
1795 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
1797 return element
- decl
;
1800 /*************************************************************************
1803 BOOL WINAPI
D3DXIntersectTri(CONST D3DXVECTOR3
*p0
, CONST D3DXVECTOR3
*p1
, CONST D3DXVECTOR3
*p2
, CONST D3DXVECTOR3
*praypos
, CONST D3DXVECTOR3
*praydir
, FLOAT
*pu
, FLOAT
*pv
, FLOAT
*pdist
)
1808 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
1809 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
1810 m
.u
.m
[2][0] = -praydir
->x
;
1812 m
.u
.m
[0][1] = p1
->y
- p0
->z
;
1813 m
.u
.m
[1][1] = p2
->y
- p0
->z
;
1814 m
.u
.m
[2][1] = -praydir
->y
;
1816 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
1817 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
1818 m
.u
.m
[2][2] = -praydir
->z
;
1825 vec
.x
= praypos
->x
- p0
->x
;
1826 vec
.y
= praypos
->y
- p0
->y
;
1827 vec
.z
= praypos
->z
- p0
->z
;
1830 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
1832 D3DXVec4Transform(&vec
, &vec
, &m
);
1833 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
1837 *pdist
= fabs( vec
.z
);
1845 /*************************************************************************
1846 * D3DXSphereBoundProbe
1848 BOOL WINAPI
D3DXSphereBoundProbe(CONST D3DXVECTOR3
*pcenter
, FLOAT radius
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
1850 D3DXVECTOR3 difference
;
1853 a
= D3DXVec3LengthSq(praydirection
);
1854 if (!D3DXVec3Subtract(&difference
, prayposition
, pcenter
)) return FALSE
;
1855 b
= D3DXVec3Dot(&difference
, praydirection
);
1856 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
1859 if ( ( d
<= 0.0f
) || ( sqrt(d
) <= b
) ) return FALSE
;
1863 /*************************************************************************
1866 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
, CONST D3DVERTEXELEMENT9
*declaration
,
1867 LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
)
1871 IDirect3DVertexDeclaration9
*vertex_declaration
;
1872 UINT vertex_declaration_size
;
1874 IDirect3DVertexBuffer9
*vertex_buffer
;
1875 IDirect3DIndexBuffer9
*index_buffer
;
1876 DWORD
*attrib_buffer
;
1877 ID3DXMeshImpl
*object
;
1878 DWORD index_usage
= 0;
1879 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
1880 D3DFORMAT index_format
= D3DFMT_INDEX16
;
1881 DWORD vertex_usage
= 0;
1882 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
1885 TRACE("(%d, %d, %x, %p, %p, %p)\n", numfaces
, numvertices
, options
, declaration
, device
, mesh
);
1887 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
1888 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
1889 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
1891 return D3DERR_INVALIDCALL
;
1893 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1894 if (declaration
[i
].Stream
!= 0)
1895 return D3DERR_INVALIDCALL
;
1898 if (options
& D3DXMESH_32BIT
)
1899 index_format
= D3DFMT_INDEX32
;
1901 if (options
& D3DXMESH_DONOTCLIP
) {
1902 index_usage
|= D3DUSAGE_DONOTCLIP
;
1903 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
1905 if (options
& D3DXMESH_POINTS
) {
1906 index_usage
|= D3DUSAGE_POINTS
;
1907 vertex_usage
|= D3DUSAGE_POINTS
;
1909 if (options
& D3DXMESH_RTPATCHES
) {
1910 index_usage
|= D3DUSAGE_RTPATCHES
;
1911 vertex_usage
|= D3DUSAGE_RTPATCHES
;
1913 if (options
& D3DXMESH_NPATCHES
) {
1914 index_usage
|= D3DUSAGE_NPATCHES
;
1915 vertex_usage
|= D3DUSAGE_NPATCHES
;
1918 if (options
& D3DXMESH_VB_SYSTEMMEM
)
1919 vertex_pool
= D3DPOOL_SYSTEMMEM
;
1920 else if (options
& D3DXMESH_VB_MANAGED
)
1921 vertex_pool
= D3DPOOL_MANAGED
;
1923 if (options
& D3DXMESH_VB_WRITEONLY
)
1924 vertex_usage
|= D3DUSAGE_WRITEONLY
;
1925 if (options
& D3DXMESH_VB_DYNAMIC
)
1926 vertex_usage
|= D3DUSAGE_DYNAMIC
;
1927 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
1928 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
1930 if (options
& D3DXMESH_IB_SYSTEMMEM
)
1931 index_pool
= D3DPOOL_SYSTEMMEM
;
1932 else if (options
& D3DXMESH_IB_MANAGED
)
1933 index_pool
= D3DPOOL_MANAGED
;
1935 if (options
& D3DXMESH_IB_WRITEONLY
)
1936 index_usage
|= D3DUSAGE_WRITEONLY
;
1937 if (options
& D3DXMESH_IB_DYNAMIC
)
1938 index_usage
|= D3DUSAGE_DYNAMIC
;
1939 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
1940 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
1942 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
1948 /* Create vertex declaration */
1949 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
1951 &vertex_declaration
);
1954 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
1957 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
1959 /* Create vertex buffer */
1960 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
1961 numvertices
* vertex_declaration_size
,
1969 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
1970 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1974 /* Create index buffer */
1975 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
1976 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
1984 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
1985 IDirect3DVertexBuffer9_Release(vertex_buffer
);
1986 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1990 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
1991 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ID3DXMeshImpl
));
1992 if (object
== NULL
|| attrib_buffer
== NULL
)
1994 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
1995 IDirect3DIndexBuffer9_Release(index_buffer
);
1996 IDirect3DVertexBuffer9_Release(vertex_buffer
);
1997 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1999 return E_OUTOFMEMORY
;
2001 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
2004 object
->numfaces
= numfaces
;
2005 object
->numvertices
= numvertices
;
2006 object
->options
= options
;
2008 object
->device
= device
;
2009 IDirect3DDevice9_AddRef(device
);
2011 copy_declaration(object
->cached_declaration
, declaration
, num_elem
);
2012 object
->vertex_declaration
= vertex_declaration
;
2013 object
->vertex_declaration_size
= vertex_declaration_size
;
2014 object
->num_elem
= num_elem
;
2015 object
->vertex_buffer
= vertex_buffer
;
2016 object
->index_buffer
= index_buffer
;
2017 object
->attrib_buffer
= attrib_buffer
;
2019 *mesh
= &object
->ID3DXMesh_iface
;
2024 /*************************************************************************
2027 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
, DWORD fvf
,
2028 LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
)
2031 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
2033 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
2035 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
2036 if (FAILED(hr
)) return hr
;
2038 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2044 DWORD num_poly_faces
;
2045 DWORD num_tri_faces
;
2046 D3DXVECTOR3
*vertices
;
2047 DWORD
*num_tri_per_face
;
2052 /* optional mesh data */
2055 D3DXVECTOR3
*normals
;
2056 DWORD
*normal_indices
;
2058 D3DXVECTOR2
*tex_coords
;
2060 DWORD
*vertex_colors
;
2062 DWORD num_materials
;
2063 D3DXMATERIAL
*materials
;
2064 DWORD
*material_indices
;
2067 static HRESULT
get_next_child(IDirectXFileData
*filedata
, IDirectXFileData
**child
, const GUID
**type
)
2070 IDirectXFileDataReference
*child_ref
= NULL
;
2071 IDirectXFileObject
*child_obj
= NULL
;
2072 IDirectXFileData
*child_data
= NULL
;
2074 hr
= IDirectXFileData_GetNextObject(filedata
, &child_obj
);
2075 if (FAILED(hr
)) return hr
;
2077 hr
= IDirectXFileObject_QueryInterface(child_obj
, &IID_IDirectXFileDataReference
, (void**)&child_ref
);
2078 if (SUCCEEDED(hr
)) {
2079 hr
= IDirectXFileDataReference_Resolve(child_ref
, &child_data
);
2080 IDirectXFileDataReference_Release(child_ref
);
2082 hr
= IDirectXFileObject_QueryInterface(child_obj
, &IID_IDirectXFileData
, (void**)&child_data
);
2084 IDirectXFileObject_Release(child_obj
);
2088 hr
= IDirectXFileData_GetType(child_data
, type
);
2090 IDirectXFileData_Release(child_data
);
2092 *child
= child_data
;
2098 static HRESULT
parse_texture_filename(IDirectXFileData
*filedata
, LPSTR
*filename_out
)
2104 char *filename
= NULL
;
2106 /* template TextureFilename {
2111 HeapFree(GetProcessHeap(), 0, *filename_out
);
2112 *filename_out
= NULL
;
2114 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2115 if (FAILED(hr
)) return hr
;
2117 if (data_size
< sizeof(LPSTR
)) {
2118 WARN("truncated data (%u bytes)\n", data_size
);
2121 filename_in
= *(LPSTR
*)data
;
2123 filename
= HeapAlloc(GetProcessHeap(), 0, strlen(filename_in
) + 1);
2124 if (!filename
) return E_OUTOFMEMORY
;
2126 strcpy(filename
, filename_in
);
2127 *filename_out
= filename
;
2132 static HRESULT
parse_material(IDirectXFileData
*filedata
, D3DXMATERIAL
*material
)
2138 IDirectXFileData
*child
;
2140 material
->pTextureFilename
= NULL
;
2142 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2143 if (FAILED(hr
)) return hr
;
2146 * template ColorRGBA {
2152 * template ColorRGB {
2157 * template Material {
2158 * ColorRGBA faceColor;
2160 * ColorRGB specularColor;
2161 * ColorRGB emissiveColor;
2165 if (data_size
!= sizeof(FLOAT
) * 11) {
2166 WARN("incorrect data size (%u bytes)\n", data_size
);
2170 memcpy(&material
->MatD3D
.Diffuse
, data
, sizeof(D3DCOLORVALUE
));
2171 data
+= sizeof(D3DCOLORVALUE
);
2172 material
->MatD3D
.Power
= *(FLOAT
*)data
;
2173 data
+= sizeof(FLOAT
);
2174 memcpy(&material
->MatD3D
.Specular
, data
, sizeof(FLOAT
) * 3);
2175 material
->MatD3D
.Specular
.a
= 1.0f
;
2176 data
+= 3 * sizeof(FLOAT
);
2177 memcpy(&material
->MatD3D
.Emissive
, data
, sizeof(FLOAT
) * 3);
2178 material
->MatD3D
.Emissive
.a
= 1.0f
;
2179 material
->MatD3D
.Ambient
.r
= 0.0f
;
2180 material
->MatD3D
.Ambient
.g
= 0.0f
;
2181 material
->MatD3D
.Ambient
.b
= 0.0f
;
2182 material
->MatD3D
.Ambient
.a
= 1.0f
;
2184 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
2186 if (IsEqualGUID(type
, &TID_D3DRMTextureFilename
)) {
2187 hr
= parse_texture_filename(child
, &material
->pTextureFilename
);
2188 if (FAILED(hr
)) break;
2191 return hr
== DXFILEERR_NOMOREOBJECTS
? D3D_OK
: hr
;
2194 static void destroy_materials(struct mesh_data
*mesh
)
2197 for (i
= 0; i
< mesh
->num_materials
; i
++)
2198 HeapFree(GetProcessHeap(), 0, mesh
->materials
[i
].pTextureFilename
);
2199 HeapFree(GetProcessHeap(), 0, mesh
->materials
);
2200 HeapFree(GetProcessHeap(), 0, mesh
->material_indices
);
2201 mesh
->num_materials
= 0;
2202 mesh
->materials
= NULL
;
2203 mesh
->material_indices
= NULL
;
2206 static HRESULT
parse_material_list(IDirectXFileData
*filedata
, struct mesh_data
*mesh
)
2210 DWORD
*data
, *in_ptr
;
2212 IDirectXFileData
*child
;
2213 DWORD num_materials
;
2216 destroy_materials(mesh
);
2218 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2219 if (FAILED(hr
)) return hr
;
2221 /* template MeshMaterialList {
2223 * DWORD nFaceIndexes;
2224 * array DWORD faceIndexes[nFaceIndexes];
2231 if (data_size
< sizeof(DWORD
))
2232 goto truncated_data_error
;
2233 num_materials
= *in_ptr
++;
2237 if (data_size
< 2 * sizeof(DWORD
))
2238 goto truncated_data_error
;
2239 if (*in_ptr
++ != mesh
->num_poly_faces
) {
2240 WARN("number of material face indices (%u) doesn't match number of faces (%u)\n",
2241 *(in_ptr
- 1), mesh
->num_poly_faces
);
2244 if (data_size
< 2 * sizeof(DWORD
) + mesh
->num_poly_faces
* sizeof(DWORD
))
2245 goto truncated_data_error
;
2246 for (i
= 0; i
< mesh
->num_poly_faces
; i
++) {
2247 if (*in_ptr
++ >= num_materials
) {
2248 WARN("face %u: reference to undefined material %u (only %u materials)\n",
2249 i
, *(in_ptr
- 1), num_materials
);
2254 mesh
->materials
= HeapAlloc(GetProcessHeap(), 0, num_materials
* sizeof(*mesh
->materials
));
2255 mesh
->material_indices
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_poly_faces
* sizeof(*mesh
->material_indices
));
2256 if (!mesh
->materials
|| !mesh
->material_indices
)
2257 return E_OUTOFMEMORY
;
2258 memcpy(mesh
->material_indices
, data
+ 2, mesh
->num_poly_faces
* sizeof(DWORD
));
2260 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
2262 if (IsEqualGUID(type
, &TID_D3DRMMaterial
)) {
2263 if (mesh
->num_materials
>= num_materials
) {
2264 WARN("more materials defined than declared\n");
2267 hr
= parse_material(child
, &mesh
->materials
[mesh
->num_materials
++]);
2268 if (FAILED(hr
)) break;
2271 if (hr
!= DXFILEERR_NOMOREOBJECTS
)
2273 if (num_materials
!= mesh
->num_materials
) {
2274 WARN("only %u of %u materials defined\n", num_materials
, mesh
->num_materials
);
2279 truncated_data_error
:
2280 WARN("truncated data (%u bytes)\n", data_size
);
2284 static HRESULT
parse_texture_coords(IDirectXFileData
*filedata
, struct mesh_data
*mesh
)
2290 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2291 mesh
->tex_coords
= NULL
;
2293 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2294 if (FAILED(hr
)) return hr
;
2296 /* template Coords2d {
2300 * template MeshTextureCoords {
2301 * DWORD nTextureCoords;
2302 * array Coords2d textureCoords[nTextureCoords];
2306 if (data_size
< sizeof(DWORD
))
2307 goto truncated_data_error
;
2308 if (*(DWORD
*)data
!= mesh
->num_vertices
) {
2309 WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2310 *(DWORD
*)data
, mesh
->num_vertices
);
2313 data
+= sizeof(DWORD
);
2314 if (data_size
< sizeof(DWORD
) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
))
2315 goto truncated_data_error
;
2317 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2318 if (!mesh
->tex_coords
) return E_OUTOFMEMORY
;
2319 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2321 mesh
->fvf
|= D3DFVF_TEX1
;
2324 truncated_data_error
:
2325 WARN("truncated data (%u bytes)\n", data_size
);
2329 static HRESULT
parse_vertex_colors(IDirectXFileData
*filedata
, struct mesh_data
*mesh
)
2337 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2338 mesh
->vertex_colors
= NULL
;
2340 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2341 if (FAILED(hr
)) return hr
;
2343 /* template IndexedColor {
2345 * ColorRGBA indexColor;
2347 * template MeshVertexColors {
2348 * DWORD nVertexColors;
2349 * array IndexedColor vertexColors[nVertexColors];
2353 if (data_size
< sizeof(DWORD
))
2354 goto truncated_data_error
;
2355 num_colors
= *(DWORD
*)data
;
2356 data
+= sizeof(DWORD
);
2357 if (data_size
< sizeof(DWORD
) + num_colors
* (sizeof(DWORD
) + sizeof(D3DCOLORVALUE
)))
2358 goto truncated_data_error
;
2360 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(DWORD
));
2361 if (!mesh
->vertex_colors
)
2362 return E_OUTOFMEMORY
;
2364 for (i
= 0; i
< mesh
->num_vertices
; i
++)
2365 mesh
->vertex_colors
[i
] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2366 for (i
= 0; i
< num_colors
; i
++)
2368 D3DCOLORVALUE color
;
2369 DWORD index
= *(DWORD
*)data
;
2370 data
+= sizeof(DWORD
);
2371 if (index
>= mesh
->num_vertices
) {
2372 WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2373 i
, index
, mesh
->num_vertices
);
2376 memcpy(&color
, data
, sizeof(color
));
2377 data
+= sizeof(color
);
2378 color
.r
= fminf(1.0f
, fmaxf(0.0f
, color
.r
));
2379 color
.g
= fminf(1.0f
, fmaxf(0.0f
, color
.g
));
2380 color
.b
= fminf(1.0f
, fmaxf(0.0f
, color
.b
));
2381 color
.a
= fminf(1.0f
, fmaxf(0.0f
, color
.a
));
2382 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
2383 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
2384 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
2385 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
2388 mesh
->fvf
|= D3DFVF_DIFFUSE
;
2391 truncated_data_error
:
2392 WARN("truncated data (%u bytes)\n", data_size
);
2396 static HRESULT
parse_normals(IDirectXFileData
*filedata
, struct mesh_data
*mesh
)
2401 DWORD
*index_out_ptr
;
2403 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
2405 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
2406 mesh
->num_normals
= 0;
2407 mesh
->normals
= NULL
;
2408 mesh
->normal_indices
= NULL
;
2409 mesh
->fvf
|= D3DFVF_NORMAL
;
2411 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2412 if (FAILED(hr
)) return hr
;
2414 /* template Vector {
2419 * template MeshFace {
2420 * DWORD nFaceVertexIndices;
2421 * array DWORD faceVertexIndices[nFaceVertexIndices];
2423 * template MeshNormals {
2425 * array Vector normals[nNormals];
2426 * DWORD nFaceNormals;
2427 * array MeshFace faceNormals[nFaceNormals];
2431 if (data_size
< sizeof(DWORD
) * 2)
2432 goto truncated_data_error
;
2433 mesh
->num_normals
= *(DWORD
*)data
;
2434 data
+= sizeof(DWORD
);
2435 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
2436 num_face_indices
* sizeof(DWORD
))
2437 goto truncated_data_error
;
2439 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
2440 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
2441 if (!mesh
->normals
|| !mesh
->normal_indices
)
2442 return E_OUTOFMEMORY
;
2444 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
2445 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
2446 for (i
= 0; i
< mesh
->num_normals
; i
++)
2447 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
2449 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
2450 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
2451 *(DWORD
*)data
, mesh
->num_poly_faces
);
2454 data
+= sizeof(DWORD
);
2455 index_out_ptr
= mesh
->normal_indices
;
2456 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
2459 DWORD count
= *(DWORD
*)data
;
2460 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
2461 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
2462 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
2465 data
+= sizeof(DWORD
);
2467 for (j
= 0; j
< count
; j
++) {
2468 DWORD normal_index
= *(DWORD
*)data
;
2469 if (normal_index
>= mesh
->num_normals
) {
2470 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
2471 i
, j
, normal_index
, mesh
->num_normals
);
2474 *index_out_ptr
++ = normal_index
;
2475 data
+= sizeof(DWORD
);
2480 truncated_data_error
:
2481 WARN("truncated data (%u bytes)\n", data_size
);
2485 /* for provide_flags parameters */
2486 #define PROVIDE_MATERIALS 0x1
2487 #define PROVIDE_SKININFO 0x2
2488 #define PROVIDE_ADJACENCY 0x4
2490 static HRESULT
parse_mesh(IDirectXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
2494 BYTE
*data
, *in_ptr
;
2495 DWORD
*index_out_ptr
;
2497 IDirectXFileData
*child
;
2503 * array Vector vertices[nVertices];
2505 * array MeshFace faces[nFaces];
2510 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2511 if (FAILED(hr
)) return hr
;
2514 if (data_size
< sizeof(DWORD
) * 2)
2515 goto truncated_data_error
;
2516 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
2517 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
))
2518 goto truncated_data_error
;
2519 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
2521 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
2522 in_ptr
+= sizeof(DWORD
);
2524 mesh_data
->num_tri_faces
= 0;
2525 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
2527 DWORD num_poly_vertices
;
2530 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
))
2531 goto truncated_data_error
;
2532 num_poly_vertices
= *(DWORD
*)in_ptr
;
2533 in_ptr
+= sizeof(DWORD
);
2534 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
))
2535 goto truncated_data_error
;
2536 if (num_poly_vertices
< 3) {
2537 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
2540 for (j
= 0; j
< num_poly_vertices
; j
++) {
2541 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
2542 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
2543 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
2546 in_ptr
+= sizeof(DWORD
);
2548 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
2551 mesh_data
->fvf
= D3DFVF_XYZ
;
2553 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
2554 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
2555 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
2556 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
2557 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
2558 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
2559 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
)
2560 return E_OUTOFMEMORY
;
2562 in_ptr
= data
+ sizeof(DWORD
);
2563 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
2564 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
2566 index_out_ptr
= mesh_data
->indices
;
2567 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
2571 count
= *(DWORD
*)in_ptr
;
2572 in_ptr
+= sizeof(DWORD
);
2573 mesh_data
->num_tri_per_face
[i
] = count
- 2;
2576 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
2577 in_ptr
+= sizeof(DWORD
);
2581 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
2583 if (IsEqualGUID(type
, &TID_D3DRMMeshNormals
)) {
2584 hr
= parse_normals(child
, mesh_data
);
2585 } else if (IsEqualGUID(type
, &TID_D3DRMMeshVertexColors
)) {
2586 hr
= parse_vertex_colors(child
, mesh_data
);
2587 } else if (IsEqualGUID(type
, &TID_D3DRMMeshTextureCoords
)) {
2588 hr
= parse_texture_coords(child
, mesh_data
);
2589 } else if (IsEqualGUID(type
, &TID_D3DRMMeshMaterialList
) &&
2590 (provide_flags
& PROVIDE_MATERIALS
))
2592 hr
= parse_material_list(child
, mesh_data
);
2593 } else if (provide_flags
& PROVIDE_SKININFO
) {
2594 if (IsEqualGUID(type
, &DXFILEOBJ_XSkinMeshHeader
)) {
2595 FIXME("Skin mesh loading not implemented.\n");
2597 } else if (IsEqualGUID(type
, &DXFILEOBJ_SkinWeights
)) {
2598 /* ignored without XSkinMeshHeader */
2604 return hr
== DXFILEERR_NOMOREOBJECTS
? D3D_OK
: hr
;
2605 truncated_data_error
:
2606 WARN("truncated data (%u bytes)\n", data_size
);
2610 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
2611 ID3DXBuffer
**effects
)
2614 D3DXEFFECTINSTANCE
*effect_ptr
;
2616 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
2617 static const struct {
2618 const char *param_name
;
2622 } material_effects
[] = {
2623 #define EFFECT_TABLE_ENTRY(str, field) \
2624 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
2625 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
2626 EFFECT_TABLE_ENTRY("Power", Power
),
2627 EFFECT_TABLE_ENTRY("Specular", Specular
),
2628 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
2629 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
2630 #undef EFFECT_TABLE_ENTRY
2632 static const char texture_paramname
[] = "Texture0@Name";
2636 /* effects buffer layout:
2638 * D3DXEFFECTINSTANCE effects[num_materials];
2639 * for (effect in effects)
2641 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
2642 * for (default in defaults)
2644 * *default.pParamName;
2649 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
2650 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
2651 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
2652 buffer_size
+= material_effects
[i
].name_size
;
2653 buffer_size
+= material_effects
[i
].num_bytes
;
2655 buffer_size
*= num_materials
;
2656 for (i
= 0; i
< num_materials
; i
++) {
2657 if (material_ptr
[i
].pTextureFilename
) {
2658 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
2659 buffer_size
+= sizeof(texture_paramname
);
2660 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
2664 hr
= D3DXCreateBuffer(buffer_size
, effects
);
2665 if (FAILED(hr
)) return hr
;
2666 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
2667 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
2669 for (i
= 0; i
< num_materials
; i
++)
2672 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
2674 effect_ptr
->pDefaults
= defaults
;
2675 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
2676 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
2678 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
2680 defaults
->pParamName
= (LPSTR
)out_ptr
;
2681 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
2682 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
2683 defaults
->Type
= D3DXEDT_FLOATS
;
2684 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
2685 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
2686 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
2690 if (material_ptr
->pTextureFilename
) {
2691 defaults
->pParamName
= (LPSTR
)out_ptr
;
2692 strcpy(defaults
->pParamName
, texture_paramname
);
2693 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
2694 defaults
->Type
= D3DXEDT_STRING
;
2695 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
2696 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
2697 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
2702 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
2707 /* change to D3DXLoadSkinMeshFromXof when ID3DXFileData is implemented */
2708 static HRESULT
load_skin_mesh_from_xof(IDirectXFileData
*filedata
,
2710 LPDIRECT3DDEVICE9 device
,
2711 LPD3DXBUFFER
*adjacency_out
,
2712 LPD3DXBUFFER
*materials_out
,
2713 LPD3DXBUFFER
*effects_out
,
2714 DWORD
*num_materials_out
,
2715 LPD3DXSKININFO
*skin_info_out
,
2716 LPD3DXMESH
*mesh_out
)
2719 DWORD
*index_in_ptr
;
2720 struct mesh_data mesh_data
;
2721 DWORD total_vertices
;
2722 ID3DXMesh
*d3dxmesh
= NULL
;
2723 ID3DXBuffer
*adjacency
= NULL
;
2724 ID3DXBuffer
*materials
= NULL
;
2725 ID3DXBuffer
*effects
= NULL
;
2726 struct vertex_duplication
{
2729 } *duplications
= NULL
;
2731 void *vertices
= NULL
;
2732 void *indices
= NULL
;
2734 DWORD provide_flags
= 0;
2736 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
2738 if (num_materials_out
|| materials_out
|| effects_out
)
2739 provide_flags
|= PROVIDE_MATERIALS
;
2741 provide_flags
|= PROVIDE_SKININFO
;
2743 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
2744 if (FAILED(hr
)) goto cleanup
;
2746 total_vertices
= mesh_data
.num_vertices
;
2747 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
2748 /* duplicate vertices with multiple normals */
2749 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
2750 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
2751 if (!duplications
) {
2755 for (i
= 0; i
< total_vertices
; i
++)
2757 duplications
[i
].normal_index
= -1;
2758 list_init(&duplications
[i
].entry
);
2760 for (i
= 0; i
< num_face_indices
; i
++) {
2761 DWORD vertex_index
= mesh_data
.indices
[i
];
2762 DWORD normal_index
= mesh_data
.normal_indices
[i
];
2763 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
2765 if (dup_ptr
->normal_index
== -1) {
2766 dup_ptr
->normal_index
= normal_index
;
2768 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
2769 struct list
*dup_list
= &dup_ptr
->entry
;
2771 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
2772 if (new_normal
->x
== cur_normal
->x
&&
2773 new_normal
->y
== cur_normal
->y
&&
2774 new_normal
->z
== cur_normal
->z
)
2776 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
2778 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
2779 dup_ptr
= &duplications
[total_vertices
++];
2780 dup_ptr
->normal_index
= normal_index
;
2781 list_add_tail(dup_list
, &dup_ptr
->entry
);
2782 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
2785 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
2786 struct vertex_duplication
, entry
);
2793 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
2794 if (FAILED(hr
)) goto cleanup
;
2796 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, D3DLOCK_DISCARD
, &vertices
);
2797 if (FAILED(hr
)) goto cleanup
;
2800 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
2801 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
2802 out_ptr
+= sizeof(D3DXVECTOR3
);
2803 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
2804 if (duplications
[i
].normal_index
== -1)
2805 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
2807 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
2808 out_ptr
+= sizeof(D3DXVECTOR3
);
2810 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
2811 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
2812 out_ptr
+= sizeof(DWORD
);
2814 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
2815 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
2816 out_ptr
+= sizeof(D3DXVECTOR2
);
2819 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
2820 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
2822 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
2823 struct vertex_duplication
*dup_ptr
;
2824 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
2826 int j
= dup_ptr
- duplications
;
2827 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
2829 memcpy(dest_vertex
, out_ptr
, vertex_size
);
2830 dest_vertex
+= sizeof(D3DXVECTOR3
);
2831 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
2833 out_ptr
+= vertex_size
;
2836 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
2838 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, D3DLOCK_DISCARD
, (void**)&indices
);
2839 if (FAILED(hr
)) goto cleanup
;
2841 index_in_ptr
= mesh_data
.indices
;
2842 #define FILL_INDEX_BUFFER(indices_var) \
2843 for (i = 0; i < mesh_data.num_poly_faces; i++) \
2845 DWORD count = mesh_data.num_tri_per_face[i]; \
2846 WORD first_index = *index_in_ptr++; \
2848 *indices_var++ = first_index; \
2849 *indices_var++ = *index_in_ptr; \
2851 *indices_var++ = *index_in_ptr; \
2855 if (options
& D3DXMESH_32BIT
) {
2856 DWORD
*dword_indices
= indices
;
2857 FILL_INDEX_BUFFER(dword_indices
)
2859 WORD
*word_indices
= indices
;
2860 FILL_INDEX_BUFFER(word_indices
)
2862 #undef FILL_INDEX_BUFFER
2863 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
2865 if (mesh_data
.material_indices
) {
2866 DWORD
*attrib_buffer
= NULL
;
2867 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, D3DLOCK_DISCARD
, &attrib_buffer
);
2868 if (FAILED(hr
)) goto cleanup
;
2869 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
2871 DWORD count
= mesh_data
.num_tri_per_face
[i
];
2873 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
2875 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
2877 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
2878 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
2879 NULL
, NULL
, NULL
, NULL
);
2880 if (FAILED(hr
)) goto cleanup
;
2883 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
2884 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
2885 char *strings_out_ptr
;
2886 D3DXMATERIAL
*materials_ptr
;
2888 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
2889 if (mesh_data
.materials
[i
].pTextureFilename
)
2890 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
2893 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
2894 if (FAILED(hr
)) goto cleanup
;
2896 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
2897 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
2898 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
2899 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
2900 if (materials_ptr
[i
].pTextureFilename
) {
2901 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
2902 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
2903 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
2908 if (mesh_data
.num_materials
&& effects_out
) {
2909 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
2910 if (FAILED(hr
)) goto cleanup
;
2912 if (!materials_out
) {
2913 ID3DXBuffer_Release(materials
);
2918 if (adjacency_out
) {
2919 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
2920 if (FAILED(hr
)) goto cleanup
;
2921 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
2922 if (FAILED(hr
)) goto cleanup
;
2925 *mesh_out
= d3dxmesh
;
2926 if (adjacency_out
) *adjacency_out
= adjacency
;
2927 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
2928 if (materials_out
) *materials_out
= materials
;
2929 if (effects_out
) *effects_out
= effects
;
2930 if (skin_info_out
) *skin_info_out
= NULL
;
2935 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
2936 if (adjacency
) ID3DXBuffer_Release(adjacency
);
2937 if (materials
) ID3DXBuffer_Release(materials
);
2938 if (effects
) ID3DXBuffer_Release(effects
);
2940 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
2941 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
2942 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
2943 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
2944 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
2945 destroy_materials(&mesh_data
);
2946 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
2947 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
2948 HeapFree(GetProcessHeap(), 0, duplications
);
2952 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(LPCSTR filename
,
2954 LPDIRECT3DDEVICE9 device
,
2955 LPD3DXALLOCATEHIERARCHY alloc_hier
,
2956 LPD3DXLOADUSERDATA load_user_data
,
2957 LPD3DXFRAME
*frame_hierarchy
,
2958 LPD3DXANIMATIONCONTROLLER
*anim_controller
)
2964 TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_a(filename
), options
,
2965 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
2968 return D3DERR_INVALIDCALL
;
2970 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
2971 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2972 if (!filenameW
) return E_OUTOFMEMORY
;
2973 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
2975 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
2976 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
2977 HeapFree(GetProcessHeap(), 0, filenameW
);
2982 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(LPCWSTR filename
,
2984 LPDIRECT3DDEVICE9 device
,
2985 LPD3DXALLOCATEHIERARCHY alloc_hier
,
2986 LPD3DXLOADUSERDATA load_user_data
,
2987 LPD3DXFRAME
*frame_hierarchy
,
2988 LPD3DXANIMATIONCONTROLLER
*anim_controller
)
2994 TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_w(filename
), options
,
2995 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
2998 return D3DERR_INVALIDCALL
;
3000 hr
= map_view_of_file(filename
, &buffer
, &size
);
3002 return D3DXERR_INVALIDDATA
;
3004 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
3005 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3007 UnmapViewOfFile(buffer
);
3012 static HRESULT
filedata_get_name(IDirectXFileData
*filedata
, char **name
)
3017 hr
= IDirectXFileData_GetName(filedata
, NULL
, &name_len
);
3018 if (FAILED(hr
)) return hr
;
3022 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
3023 if (!*name
) return E_OUTOFMEMORY
;
3025 hr
= IDirectXFileObject_GetName(filedata
, *name
, &name_len
);
3027 HeapFree(GetProcessHeap(), 0, name
);
3034 static HRESULT
load_mesh_container(IDirectXFileData
*filedata
,
3036 LPDIRECT3DDEVICE9 device
,
3037 LPD3DXALLOCATEHIERARCHY alloc_hier
,
3038 D3DXMESHCONTAINER
**mesh_container
)
3041 ID3DXBuffer
*adjacency
= NULL
;
3042 ID3DXBuffer
*materials
= NULL
;
3043 ID3DXBuffer
*effects
= NULL
;
3044 ID3DXSkinInfo
*skin_info
= NULL
;
3045 D3DXMESHDATA mesh_data
;
3046 DWORD num_materials
= 0;
3049 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
3050 mesh_data
.u
.pMesh
= NULL
;
3052 hr
= load_skin_mesh_from_xof(filedata
, options
, device
,
3053 &adjacency
, &materials
, &effects
, &num_materials
,
3054 &skin_info
, &mesh_data
.u
.pMesh
);
3055 if (FAILED(hr
)) return hr
;
3057 hr
= filedata_get_name(filedata
, &name
);
3058 if (FAILED(hr
)) goto cleanup
;
3060 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
3061 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
3062 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
3064 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
3065 skin_info
, mesh_container
);
3068 if (materials
) ID3DXBuffer_Release(materials
);
3069 if (effects
) ID3DXBuffer_Release(effects
);
3070 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3071 if (skin_info
) IUnknown_Release(skin_info
);
3072 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
3073 HeapFree(GetProcessHeap(), 0, name
);
3077 static HRESULT
parse_transform_matrix(IDirectXFileData
*filedata
, D3DXMATRIX
*transform
)
3083 /* template Matrix4x4 {
3084 * array FLOAT matrix[16];
3086 * template FrameTransformMatrix {
3087 * Matrix4x4 frameMatrix;
3091 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
3092 if (FAILED(hr
)) return hr
;
3094 if (data_size
!= sizeof(D3DXMATRIX
)) {
3095 WARN("incorrect data size (%u bytes)\n", data_size
);
3099 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
3104 static HRESULT
load_frame(IDirectXFileData
*filedata
,
3106 LPDIRECT3DDEVICE9 device
,
3107 LPD3DXALLOCATEHIERARCHY alloc_hier
,
3108 D3DXFRAME
**frame_out
)
3112 IDirectXFileData
*child
;
3114 D3DXFRAME
*frame
= NULL
;
3115 D3DXMESHCONTAINER
**next_container
;
3116 D3DXFRAME
**next_child
;
3118 hr
= filedata_get_name(filedata
, &name
);
3119 if (FAILED(hr
)) return hr
;
3121 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
3122 HeapFree(GetProcessHeap(), 0, name
);
3123 if (FAILED(hr
)) return E_FAIL
;
3126 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
3127 next_child
= &frame
->pFrameFirstChild
;
3128 next_container
= &frame
->pMeshContainer
;
3130 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
3132 if (IsEqualGUID(type
, &TID_D3DRMMesh
)) {
3133 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
3135 next_container
= &(*next_container
)->pNextMeshContainer
;
3136 } else if (IsEqualGUID(type
, &TID_D3DRMFrameTransformMatrix
)) {
3137 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
3138 } else if (IsEqualGUID(type
, &TID_D3DRMFrame
)) {
3139 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
3141 next_child
= &(*next_child
)->pFrameSibling
;
3143 if (FAILED(hr
)) break;
3145 if (hr
== DXFILEERR_NOMOREOBJECTS
)
3151 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(LPCVOID memory
,
3154 LPDIRECT3DDEVICE9 device
,
3155 LPD3DXALLOCATEHIERARCHY alloc_hier
,
3156 LPD3DXLOADUSERDATA load_user_data
,
3157 LPD3DXFRAME
*frame_hierarchy
,
3158 LPD3DXANIMATIONCONTROLLER
*anim_controller
)
3161 IDirectXFile
*dxfile
= NULL
;
3162 IDirectXFileEnumObject
*enumobj
= NULL
;
3163 IDirectXFileData
*filedata
= NULL
;
3164 DXFILELOADMEMORY source
;
3165 D3DXFRAME
*first_frame
= NULL
;
3166 D3DXFRAME
**next_frame
= &first_frame
;
3168 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3169 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3171 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
3172 return D3DERR_INVALIDCALL
;
3173 if (load_user_data
|| anim_controller
) {
3175 FIXME("Loading user data not implemented\n");
3176 if (anim_controller
)
3177 FIXME("Animation controller creation not implemented\n");
3181 hr
= DirectXFileCreate(&dxfile
);
3182 if (FAILED(hr
)) goto cleanup
;
3184 hr
= IDirectXFile_RegisterTemplates(dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3185 if (FAILED(hr
)) goto cleanup
;
3187 source
.lpMemory
= (void*)memory
;
3188 source
.dSize
= memory_size
;
3189 hr
= IDirectXFile_CreateEnumObject(dxfile
, &source
, DXFILELOAD_FROMMEMORY
, &enumobj
);
3190 if (FAILED(hr
)) goto cleanup
;
3192 while (SUCCEEDED(hr
= IDirectXFileEnumObject_GetNextDataObject(enumobj
, &filedata
)))
3194 const GUID
*guid
= NULL
;
3196 hr
= IDirectXFileData_GetType(filedata
, &guid
);
3197 if (SUCCEEDED(hr
)) {
3198 if (IsEqualGUID(guid
, &TID_D3DRMMesh
)) {
3199 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
3205 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
3207 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
3208 if (FAILED(hr
)) goto cleanup
;
3209 } else if (IsEqualGUID(guid
, &TID_D3DRMFrame
)) {
3210 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
3211 if (FAILED(hr
)) goto cleanup
;
3214 next_frame
= &(*next_frame
)->pFrameSibling
;
3217 IDirectXFileData_Release(filedata
);
3222 if (hr
!= DXFILEERR_NOMOREOBJECTS
)
3227 } else if (first_frame
->pFrameSibling
) {
3228 D3DXFRAME
*root_frame
= NULL
;
3229 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
3234 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
3235 root_frame
->pFrameFirstChild
= first_frame
;
3236 *frame_hierarchy
= root_frame
;
3239 *frame_hierarchy
= first_frame
;
3244 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
3245 if (filedata
) IDirectXFileData_Release(filedata
);
3246 if (enumobj
) IDirectXFileEnumObject_Release(enumobj
);
3247 if (dxfile
) IDirectXFile_Release(dxfile
);
3251 HRESULT WINAPI
D3DXFrameDestroy(LPD3DXFRAME frame
, LPD3DXALLOCATEHIERARCHY alloc_hier
)
3256 TRACE("(%p, %p)\n", frame
, alloc_hier
);
3258 if (!frame
|| !alloc_hier
)
3259 return D3DERR_INVALIDCALL
;
3262 D3DXMESHCONTAINER
*container
;
3263 D3DXFRAME
*current_frame
;
3265 if (frame
->pFrameSibling
) {
3266 current_frame
= frame
->pFrameSibling
;
3267 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
3268 current_frame
->pFrameSibling
= NULL
;
3270 current_frame
= frame
;
3274 if (current_frame
->pFrameFirstChild
) {
3275 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
3276 if (FAILED(hr
)) return hr
;
3277 current_frame
->pFrameFirstChild
= NULL
;
3280 container
= current_frame
->pMeshContainer
;
3282 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
3283 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
3284 if (FAILED(hr
)) return hr
;
3285 container
= next_container
;
3287 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
3288 if (FAILED(hr
)) return hr
;
3293 HRESULT WINAPI
D3DXLoadMeshFromXA(LPCSTR filename
,
3295 LPDIRECT3DDEVICE9 device
,
3296 LPD3DXBUFFER
*adjacency
,
3297 LPD3DXBUFFER
*materials
,
3298 LPD3DXBUFFER
*effect_instances
,
3299 DWORD
*num_materials
,
3306 TRACE("(%s, %x, %p, %p, %p, %p, %p, %p)\n", debugstr_a(filename
), options
,
3307 device
, adjacency
, materials
, effect_instances
, num_materials
, mesh
);
3310 return D3DERR_INVALIDCALL
;
3312 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3313 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3314 if (!filenameW
) return E_OUTOFMEMORY
;
3315 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3317 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
3318 effect_instances
, num_materials
, mesh
);
3319 HeapFree(GetProcessHeap(), 0, filenameW
);
3324 HRESULT WINAPI
D3DXLoadMeshFromXW(LPCWSTR filename
,
3326 LPDIRECT3DDEVICE9 device
,
3327 LPD3DXBUFFER
*adjacency
,
3328 LPD3DXBUFFER
*materials
,
3329 LPD3DXBUFFER
*effect_instances
,
3330 DWORD
*num_materials
,
3337 TRACE("(%s, %x, %p, %p, %p, %p, %p, %p)\n", debugstr_w(filename
), options
,
3338 device
, adjacency
, materials
, effect_instances
, num_materials
, mesh
);
3341 return D3DERR_INVALIDCALL
;
3343 hr
= map_view_of_file(filename
, &buffer
, &size
);
3345 return D3DXERR_INVALIDDATA
;
3347 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
3348 materials
, effect_instances
, num_materials
, mesh
);
3350 UnmapViewOfFile(buffer
);
3355 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
,
3359 LPDIRECT3DDEVICE9 device
,
3360 LPD3DXBUFFER
*adjacency
,
3361 LPD3DXBUFFER
*materials
,
3362 LPD3DXBUFFER
*effect_instances
,
3363 DWORD
*num_materials
,
3371 TRACE("(%p, %s, %s, %x, %p, %p, %p, %p, %p, %p)\n",
3372 module
, debugstr_a(name
), debugstr_a(type
), options
, device
,
3373 adjacency
, materials
, effect_instances
, num_materials
, mesh
);
3375 resinfo
= FindResourceA(module
, name
, type
);
3376 if (!resinfo
) return D3DXERR_INVALIDDATA
;
3378 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
3379 if (FAILED(hr
)) return D3DXERR_INVALIDDATA
;
3381 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
3382 materials
, effect_instances
, num_materials
, mesh
);
3385 struct mesh_container
3389 ID3DXBuffer
*adjacency
;
3390 ID3DXBuffer
*materials
;
3391 ID3DXBuffer
*effects
;
3392 DWORD num_materials
;
3393 D3DXMATRIX transform
;
3396 static HRESULT
parse_frame(IDirectXFileData
*filedata
,
3398 LPDIRECT3DDEVICE9 device
,
3399 const D3DXMATRIX
*parent_transform
,
3400 struct list
*container_list
,
3401 DWORD provide_flags
)
3404 D3DXMATRIX transform
= *parent_transform
;
3405 IDirectXFileData
*child
;
3408 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
3410 if (IsEqualGUID(type
, &TID_D3DRMMesh
)) {
3411 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
3416 list_add_tail(container_list
, &container
->entry
);
3417 container
->transform
= transform
;
3419 hr
= load_skin_mesh_from_xof(child
, options
, device
,
3420 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
3421 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
3422 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
3423 } else if (IsEqualGUID(type
, &TID_D3DRMFrameTransformMatrix
)) {
3424 D3DXMATRIX new_transform
;
3425 hr
= parse_transform_matrix(child
, &new_transform
);
3426 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
3427 } else if (IsEqualGUID(type
, &TID_D3DRMFrame
)) {
3428 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
3430 if (FAILED(hr
)) break;
3432 return hr
== DXFILEERR_NOMOREOBJECTS
? D3D_OK
: hr
;
3435 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(LPCVOID memory
,
3438 LPDIRECT3DDEVICE9 device
,
3439 LPD3DXBUFFER
*adjacency_out
,
3440 LPD3DXBUFFER
*materials_out
,
3441 LPD3DXBUFFER
*effects_out
,
3442 DWORD
*num_materials_out
,
3443 LPD3DXMESH
*mesh_out
)
3446 IDirectXFile
*dxfile
= NULL
;
3447 IDirectXFileEnumObject
*enumobj
= NULL
;
3448 IDirectXFileData
*filedata
= NULL
;
3449 DXFILELOADMEMORY source
;
3450 ID3DXBuffer
*materials
= NULL
;
3451 ID3DXBuffer
*effects
= NULL
;
3452 ID3DXBuffer
*adjacency
= NULL
;
3453 struct list container_list
= LIST_INIT(container_list
);
3454 struct mesh_container
*container_ptr
, *next_container_ptr
;
3455 DWORD num_materials
;
3456 DWORD num_faces
, num_vertices
;
3457 D3DXMATRIX identity
;
3459 DWORD provide_flags
= 0;
3461 ID3DXMesh
*concat_mesh
= NULL
;
3462 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
3463 BYTE
*concat_vertices
= NULL
;
3464 void *concat_indices
= NULL
;
3466 DWORD concat_vertex_size
;
3468 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3469 device
, adjacency_out
, materials_out
, effects_out
, num_materials_out
, mesh_out
);
3471 if (!memory
|| !memory_size
|| !device
|| !mesh_out
)
3472 return D3DERR_INVALIDCALL
;
3474 hr
= DirectXFileCreate(&dxfile
);
3475 if (FAILED(hr
)) goto cleanup
;
3477 hr
= IDirectXFile_RegisterTemplates(dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3478 if (FAILED(hr
)) goto cleanup
;
3480 source
.lpMemory
= (void*)memory
;
3481 source
.dSize
= memory_size
;
3482 hr
= IDirectXFile_CreateEnumObject(dxfile
, &source
, DXFILELOAD_FROMMEMORY
, &enumobj
);
3483 if (FAILED(hr
)) goto cleanup
;
3485 D3DXMatrixIdentity(&identity
);
3486 if (adjacency_out
) provide_flags
|= PROVIDE_ADJACENCY
;
3487 if (materials_out
|| effects_out
) provide_flags
|= PROVIDE_MATERIALS
;
3489 while (SUCCEEDED(hr
= IDirectXFileEnumObject_GetNextDataObject(enumobj
, &filedata
)))
3491 const GUID
*guid
= NULL
;
3493 hr
= IDirectXFileData_GetType(filedata
, &guid
);
3494 if (SUCCEEDED(hr
)) {
3495 if (IsEqualGUID(guid
, &TID_D3DRMMesh
)) {
3496 container_ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container_ptr
));
3497 if (!container_ptr
) {
3501 list_add_tail(&container_list
, &container_ptr
->entry
);
3502 D3DXMatrixIdentity(&container_ptr
->transform
);
3504 hr
= load_skin_mesh_from_xof(filedata
, options
, device
,
3505 (provide_flags
& PROVIDE_ADJACENCY
) ? &container_ptr
->adjacency
: NULL
,
3506 (provide_flags
& PROVIDE_MATERIALS
) ? &container_ptr
->materials
: NULL
,
3507 NULL
, &container_ptr
->num_materials
, NULL
, &container_ptr
->mesh
);
3508 } else if (IsEqualGUID(guid
, &TID_D3DRMFrame
)) {
3509 hr
= parse_frame(filedata
, options
, device
, &identity
, &container_list
, provide_flags
);
3511 if (FAILED(hr
)) goto cleanup
;
3513 IDirectXFileData_Release(filedata
);
3518 if (hr
!= DXFILEERR_NOMOREOBJECTS
)
3521 IDirectXFileEnumObject_Release(enumobj
);
3523 IDirectXFile_Release(dxfile
);
3526 if (list_empty(&container_list
)) {
3535 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3537 ID3DXMesh
*mesh
= container_ptr
->mesh
;
3538 fvf
|= mesh
->lpVtbl
->GetFVF(mesh
);
3539 num_faces
+= mesh
->lpVtbl
->GetNumFaces(mesh
);
3540 num_vertices
+= mesh
->lpVtbl
->GetNumVertices(mesh
);
3541 num_materials
+= container_ptr
->num_materials
;
3544 hr
= D3DXCreateMeshFVF(num_faces
, num_vertices
, options
, fvf
, device
, &concat_mesh
);
3545 if (FAILED(hr
)) goto cleanup
;
3547 hr
= concat_mesh
->lpVtbl
->GetDeclaration(concat_mesh
, concat_decl
);
3548 if (FAILED(hr
)) goto cleanup
;
3550 concat_vertex_size
= D3DXGetDeclVertexSize(concat_decl
, 0);
3552 hr
= concat_mesh
->lpVtbl
->LockVertexBuffer(concat_mesh
, D3DLOCK_DISCARD
, (void**)&concat_vertices
);
3553 if (FAILED(hr
)) goto cleanup
;
3555 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3557 D3DVERTEXELEMENT9 mesh_decl
[MAX_FVF_DECL_SIZE
];
3558 ID3DXMesh
*mesh
= container_ptr
->mesh
;
3559 DWORD num_mesh_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
3560 DWORD mesh_vertex_size
;
3561 const BYTE
*mesh_vertices
;
3563 hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, mesh_decl
);
3564 if (FAILED(hr
)) goto cleanup
;
3566 mesh_vertex_size
= D3DXGetDeclVertexSize(mesh_decl
, 0);
3568 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_vertices
);
3569 if (FAILED(hr
)) goto cleanup
;
3571 for (i
= 0; i
< num_mesh_vertices
; i
++) {
3575 D3DXVec3TransformCoord((D3DXVECTOR3
*)concat_vertices
,
3576 (D3DXVECTOR3
*)mesh_vertices
,
3577 &container_ptr
->transform
);
3578 for (j
= 1; concat_decl
[j
].Stream
!= 0xff; j
++)
3580 if (concat_decl
[j
].Usage
== mesh_decl
[k
].Usage
&&
3581 concat_decl
[j
].UsageIndex
== mesh_decl
[k
].UsageIndex
)
3583 if (concat_decl
[j
].Usage
== D3DDECLUSAGE_NORMAL
) {
3584 D3DXVec3TransformCoord((D3DXVECTOR3
*)(concat_vertices
+ concat_decl
[j
].Offset
),
3585 (D3DXVECTOR3
*)(mesh_vertices
+ mesh_decl
[k
].Offset
),
3586 &container_ptr
->transform
);
3588 memcpy(concat_vertices
+ concat_decl
[j
].Offset
,
3589 mesh_vertices
+ mesh_decl
[k
].Offset
,
3590 d3dx_decltype_size
[mesh_decl
[k
].Type
]);
3595 mesh_vertices
+= mesh_vertex_size
;
3596 concat_vertices
+= concat_vertex_size
;
3599 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
3602 concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
3603 concat_vertices
= NULL
;
3605 hr
= concat_mesh
->lpVtbl
->LockIndexBuffer(concat_mesh
, D3DLOCK_DISCARD
, &concat_indices
);
3606 if (FAILED(hr
)) goto cleanup
;
3609 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3611 ID3DXMesh
*mesh
= container_ptr
->mesh
;
3612 const void *mesh_indices
;
3613 DWORD num_mesh_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
3616 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_indices
);
3617 if (FAILED(hr
)) goto cleanup
;
3619 if (options
& D3DXMESH_32BIT
) {
3620 DWORD
*dest
= concat_indices
;
3621 const DWORD
*src
= mesh_indices
;
3622 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
3623 *dest
++ = index_offset
+ *src
++;
3624 concat_indices
= dest
;
3626 WORD
*dest
= concat_indices
;
3627 const WORD
*src
= mesh_indices
;
3628 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
3629 *dest
++ = index_offset
+ *src
++;
3630 concat_indices
= dest
;
3632 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
3634 index_offset
+= num_mesh_faces
* 3;
3637 concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
3638 concat_indices
= NULL
;
3640 if (num_materials
) {
3641 DWORD
*concat_attrib_buffer
= NULL
;
3644 hr
= concat_mesh
->lpVtbl
->LockAttributeBuffer(concat_mesh
, D3DLOCK_DISCARD
, &concat_attrib_buffer
);
3645 if (FAILED(hr
)) goto cleanup
;
3647 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3649 ID3DXMesh
*mesh
= container_ptr
->mesh
;
3650 const DWORD
*mesh_attrib_buffer
= NULL
;
3651 DWORD count
= mesh
->lpVtbl
->GetNumFaces(mesh
);
3653 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, D3DLOCK_READONLY
, (DWORD
**)&mesh_attrib_buffer
);
3655 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
3660 *concat_attrib_buffer
++ = offset
+ *mesh_attrib_buffer
++;
3662 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
3663 offset
+= container_ptr
->num_materials
;
3665 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
3668 if (materials_out
|| effects_out
) {
3669 D3DXMATERIAL
*out_ptr
;
3670 if (!num_materials
) {
3671 /* create default material */
3672 hr
= D3DXCreateBuffer(sizeof(D3DXMATERIAL
), &materials
);
3673 if (FAILED(hr
)) goto cleanup
;
3675 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3676 out_ptr
->MatD3D
.Diffuse
.r
= 0.5f
;
3677 out_ptr
->MatD3D
.Diffuse
.g
= 0.5f
;
3678 out_ptr
->MatD3D
.Diffuse
.b
= 0.5f
;
3679 out_ptr
->MatD3D
.Specular
.r
= 0.5f
;
3680 out_ptr
->MatD3D
.Specular
.g
= 0.5f
;
3681 out_ptr
->MatD3D
.Specular
.b
= 0.5f
;
3682 /* D3DXCreateBuffer initializes the rest to zero */
3684 DWORD buffer_size
= num_materials
* sizeof(D3DXMATERIAL
);
3685 char *strings_out_ptr
;
3687 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3689 if (container_ptr
->materials
) {
3690 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
3691 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
3693 if (in_ptr
->pTextureFilename
)
3694 buffer_size
+= strlen(in_ptr
->pTextureFilename
) + 1;
3700 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3701 if (FAILED(hr
)) goto cleanup
;
3702 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3703 strings_out_ptr
= (char*)(out_ptr
+ num_materials
);
3705 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3707 if (container_ptr
->materials
) {
3708 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
3709 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
3711 out_ptr
->MatD3D
= in_ptr
->MatD3D
;
3712 if (in_ptr
->pTextureFilename
) {
3713 out_ptr
->pTextureFilename
= strings_out_ptr
;
3714 strcpy(out_ptr
->pTextureFilename
, in_ptr
->pTextureFilename
);
3715 strings_out_ptr
+= strlen(in_ptr
->pTextureFilename
) + 1;
3728 generate_effects(materials
, num_materials
, &effects
);
3729 if (!materials_out
) {
3730 ID3DXBuffer_Release(materials
);
3735 if (adjacency_out
) {
3736 if (!list_next(&container_list
, list_head(&container_list
))) {
3737 container_ptr
= LIST_ENTRY(list_head(&container_list
), struct mesh_container
, entry
);
3738 adjacency
= container_ptr
->adjacency
;
3739 container_ptr
->adjacency
= NULL
;
3744 hr
= D3DXCreateBuffer(num_faces
* 3 * sizeof(DWORD
), &adjacency
);
3745 if (FAILED(hr
)) goto cleanup
;
3747 out_ptr
= ID3DXBuffer_GetBufferPointer(adjacency
);
3748 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3750 DWORD
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->adjacency
);
3751 int count
= 3 * container_ptr
->mesh
->lpVtbl
->GetNumFaces(container_ptr
->mesh
);
3753 for (i
= 0; i
< count
; i
++)
3754 *out_ptr
++ = offset
+ *in_ptr
++;
3761 *mesh_out
= concat_mesh
;
3762 if (adjacency_out
) *adjacency_out
= adjacency
;
3763 if (materials_out
) *materials_out
= materials
;
3764 if (effects_out
) *effects_out
= effects
;
3765 if (num_materials_out
) *num_materials_out
= num_materials
;
3769 if (concat_indices
) concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
3770 if (concat_vertices
) concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
3771 if (filedata
) IDirectXFileData_Release(filedata
);
3772 if (enumobj
) IDirectXFileEnumObject_Release(enumobj
);
3773 if (dxfile
) IDirectXFile_Release(dxfile
);
3775 if (concat_mesh
) IUnknown_Release(concat_mesh
);
3776 if (materials
) ID3DXBuffer_Release(materials
);
3777 if (effects
) ID3DXBuffer_Release(effects
);
3778 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3780 LIST_FOR_EACH_ENTRY_SAFE(container_ptr
, next_container_ptr
, &container_list
, struct mesh_container
, entry
)
3782 if (container_ptr
->mesh
) IUnknown_Release(container_ptr
->mesh
);
3783 if (container_ptr
->adjacency
) ID3DXBuffer_Release(container_ptr
->adjacency
);
3784 if (container_ptr
->materials
) ID3DXBuffer_Release(container_ptr
->materials
);
3785 if (container_ptr
->effects
) ID3DXBuffer_Release(container_ptr
->effects
);
3786 HeapFree(GetProcessHeap(), 0, container_ptr
);
3791 HRESULT WINAPI
D3DXCreateBox(LPDIRECT3DDEVICE9 device
, FLOAT width
, FLOAT height
,
3792 FLOAT depth
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
3794 FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device
, width
, height
, depth
, mesh
, adjacency
);
3801 D3DXVECTOR3 position
;
3805 typedef WORD face
[3];
3813 static void free_sincos_table(struct sincos_table
*sincos_table
)
3815 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
3816 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
3819 /* pre compute sine and cosine tables; caller must free */
3820 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
3825 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
3826 if (!sincos_table
->sin
)
3830 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
3831 if (!sincos_table
->cos
)
3833 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
3837 angle
= angle_start
;
3838 for (i
= 0; i
< n
; i
++)
3840 sincos_table
->sin
[i
] = sin(angle
);
3841 sincos_table
->cos
[i
] = cos(angle
);
3842 angle
+= angle_step
;
3848 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
3850 return stack
*slices
+slice
+1;
3853 HRESULT WINAPI
D3DXCreateSphere(LPDIRECT3DDEVICE9 device
, FLOAT radius
, UINT slices
,
3854 UINT stacks
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
3856 DWORD number_of_vertices
, number_of_faces
;
3859 struct vertex
*vertices
;
3861 float phi_step
, phi_start
;
3862 struct sincos_table phi
;
3863 float theta_step
, theta
, sin_theta
, cos_theta
;
3867 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
3869 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
3871 return D3DERR_INVALIDCALL
;
3876 FIXME("Case of adjacency != NULL not implemented.\n");
3880 number_of_vertices
= 2 + slices
* (stacks
-1);
3881 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
3883 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
3884 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
3890 hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
3893 sphere
->lpVtbl
->Release(sphere
);
3897 hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
3900 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
3901 sphere
->lpVtbl
->Release(sphere
);
3905 /* phi = angle on xz plane wrt z axis */
3906 phi_step
= -2 * M_PI
/ slices
;
3907 phi_start
= M_PI
/ 2;
3909 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
3911 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
3912 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
3913 sphere
->lpVtbl
->Release(sphere
);
3914 return E_OUTOFMEMORY
;
3917 /* theta = angle on xy plane wrt x axis */
3918 theta_step
= M_PI
/ stacks
;
3924 vertices
[vertex
].normal
.x
= 0.0f
;
3925 vertices
[vertex
].normal
.y
= 0.0f
;
3926 vertices
[vertex
].normal
.z
= 1.0f
;
3927 vertices
[vertex
].position
.x
= 0.0f
;
3928 vertices
[vertex
].position
.y
= 0.0f
;
3929 vertices
[vertex
].position
.z
= radius
;
3932 for (stack
= 0; stack
< stacks
- 1; stack
++)
3934 sin_theta
= sin(theta
);
3935 cos_theta
= cos(theta
);
3937 for (slice
= 0; slice
< slices
; slice
++)
3939 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
3940 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
3941 vertices
[vertex
].normal
.z
= cos_theta
;
3942 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
3943 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
3944 vertices
[vertex
].position
.z
= radius
* cos_theta
;
3951 /* top stack is triangle fan */
3953 faces
[face
][1] = slice
+ 1;
3954 faces
[face
][2] = slice
;
3959 /* stacks in between top and bottom are quad strips */
3960 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
3961 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
3962 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
3965 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
3966 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
3967 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
3973 theta
+= theta_step
;
3979 faces
[face
][2] = slice
;
3984 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
3985 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
3986 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
3989 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
3990 faces
[face
][1] = vertex_index(slices
, 0, stack
);
3991 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
3996 vertices
[vertex
].position
.x
= 0.0f
;
3997 vertices
[vertex
].position
.y
= 0.0f
;
3998 vertices
[vertex
].position
.z
= -radius
;
3999 vertices
[vertex
].normal
.x
= 0.0f
;
4000 vertices
[vertex
].normal
.y
= 0.0f
;
4001 vertices
[vertex
].normal
.z
= -1.0f
;
4003 /* bottom stack is triangle fan */
4004 for (slice
= 1; slice
< slices
; slice
++)
4006 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4007 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4008 faces
[face
][2] = vertex
;
4012 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4013 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4014 faces
[face
][2] = vertex
;
4016 free_sincos_table(&phi
);
4017 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4018 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4024 HRESULT WINAPI
D3DXCreateCylinder(LPDIRECT3DDEVICE9 device
, FLOAT radius1
, FLOAT radius2
, FLOAT length
, UINT slices
,
4025 UINT stacks
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
4027 DWORD number_of_vertices
, number_of_faces
;
4029 ID3DXMesh
*cylinder
;
4030 struct vertex
*vertices
;
4032 float theta_step
, theta_start
;
4033 struct sincos_table theta
;
4034 float delta_radius
, radius
, radius_step
;
4035 float z
, z_step
, z_normal
;
4039 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
4041 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
4043 return D3DERR_INVALIDCALL
;
4048 FIXME("Case of adjacency != NULL not implemented.\n");
4052 number_of_vertices
= 2 + (slices
* (3 + stacks
));
4053 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
4055 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4056 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
4062 hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
4065 cylinder
->lpVtbl
->Release(cylinder
);
4069 hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
4072 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4073 cylinder
->lpVtbl
->Release(cylinder
);
4077 /* theta = angle on xy plane wrt x axis */
4078 theta_step
= -2 * M_PI
/ slices
;
4079 theta_start
= M_PI
/ 2;
4081 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
4083 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
4084 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4085 cylinder
->lpVtbl
->Release(cylinder
);
4086 return E_OUTOFMEMORY
;
4092 delta_radius
= radius1
- radius2
;
4094 radius_step
= delta_radius
/ stacks
;
4097 z_step
= length
/ stacks
;
4098 z_normal
= delta_radius
/ length
;
4099 if (isnan(z_normal
))
4104 vertices
[vertex
].normal
.x
= 0.0f
;
4105 vertices
[vertex
].normal
.y
= 0.0f
;
4106 vertices
[vertex
].normal
.z
= -1.0f
;
4107 vertices
[vertex
].position
.x
= 0.0f
;
4108 vertices
[vertex
].position
.y
= 0.0f
;
4109 vertices
[vertex
++].position
.z
= z
;
4111 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4113 vertices
[vertex
].normal
.x
= 0.0f
;
4114 vertices
[vertex
].normal
.y
= 0.0f
;
4115 vertices
[vertex
].normal
.z
= -1.0f
;
4116 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4117 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4118 vertices
[vertex
].position
.z
= z
;
4123 faces
[face
][1] = slice
;
4124 faces
[face
++][2] = slice
+ 1;
4129 faces
[face
][1] = slice
;
4130 faces
[face
++][2] = 1;
4132 for (stack
= 1; stack
<= stacks
+1; stack
++)
4134 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4136 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
4137 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
4138 vertices
[vertex
].normal
.z
= z_normal
;
4139 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
4140 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4141 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4142 vertices
[vertex
].position
.z
= z
;
4144 if (stack
> 1 && slice
> 0)
4146 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4147 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4148 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
4150 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4151 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4152 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
4158 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4159 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4160 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
4162 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4163 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4164 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
4167 if (stack
< stacks
+ 1)
4170 radius
-= radius_step
;
4174 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4176 vertices
[vertex
].normal
.x
= 0.0f
;
4177 vertices
[vertex
].normal
.y
= 0.0f
;
4178 vertices
[vertex
].normal
.z
= 1.0f
;
4179 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4180 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4181 vertices
[vertex
].position
.z
= z
;
4185 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
4186 faces
[face
][1] = number_of_vertices
- 1;
4187 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
4191 vertices
[vertex
].position
.x
= 0.0f
;
4192 vertices
[vertex
].position
.y
= 0.0f
;
4193 vertices
[vertex
].position
.z
= z
;
4194 vertices
[vertex
].normal
.x
= 0.0f
;
4195 vertices
[vertex
].normal
.y
= 0.0f
;
4196 vertices
[vertex
].normal
.z
= 1.0f
;
4198 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
4199 faces
[face
][1] = number_of_vertices
- 1;
4200 faces
[face
][2] = vertex_index(slices
, 0, stack
);
4202 free_sincos_table(&theta
);
4203 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
4204 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4210 HRESULT WINAPI
D3DXCreateTeapot(LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
, LPD3DXBUFFER
* adjacency
)
4212 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
4217 HRESULT WINAPI
D3DXCreateTextA(LPDIRECT3DDEVICE9 device
,
4218 HDC hdc
, LPCSTR text
,
4219 FLOAT deviation
, FLOAT extrusion
,
4220 LPD3DXMESH
*mesh
, LPD3DXBUFFER
*adjacency
,
4221 LPGLYPHMETRICSFLOAT glyphmetrics
)
4227 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
4228 debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
4231 return D3DERR_INVALIDCALL
;
4233 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
4234 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4235 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
4237 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
4238 mesh
, adjacency
, glyphmetrics
);
4239 HeapFree(GetProcessHeap(), 0, textW
);
4245 POINTTYPE_CURVE
= 0,
4247 POINTTYPE_CURVE_START
,
4248 POINTTYPE_CURVE_END
,
4249 POINTTYPE_CURVE_MIDDLE
,
4255 enum pointtype corner
;
4258 struct dynamic_array
4260 int count
, capacity
;
4264 /* is a dynamic_array */
4267 int count
, capacity
;
4268 struct point2d
*items
;
4271 /* is a dynamic_array */
4272 struct outline_array
4274 int count
, capacity
;
4275 struct outline
*items
;
4284 struct point2d_index
4286 struct outline
*outline
;
4290 struct point2d_index_array
4293 struct point2d_index
*items
;
4298 struct outline_array outlines
;
4299 struct face_array faces
;
4300 struct point2d_index_array ordered_vertices
;
4304 /* is an dynamic_array */
4307 int count
, capacity
;
4311 /* complex polygons are split into monotone polygons, which have
4312 * at most 2 intersections with the vertical sweep line */
4313 struct triangulation
4315 struct word_array vertex_stack
;
4316 BOOL last_on_top
, merging
;
4319 /* is an dynamic_array */
4320 struct triangulation_array
4322 int count
, capacity
;
4323 struct triangulation
*items
;
4325 struct glyphinfo
*glyph
;
4328 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
4330 if (count
> array
->capacity
) {
4333 if (array
->items
&& array
->capacity
) {
4334 new_capacity
= max(array
->capacity
* 2, count
);
4335 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
4337 new_capacity
= max(16, count
);
4338 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
4342 array
->items
= new_buffer
;
4343 array
->capacity
= new_capacity
;
4348 static struct point2d
*add_points(struct outline
*array
, int num
)
4350 struct point2d
*item
;
4352 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
4355 item
= &array
->items
[array
->count
];
4356 array
->count
+= num
;
4360 static struct outline
*add_outline(struct outline_array
*array
)
4362 struct outline
*item
;
4364 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
4367 item
= &array
->items
[array
->count
++];
4368 ZeroMemory(item
, sizeof(*item
));
4372 static inline face
*add_face(struct face_array
*array
)
4374 return &array
->items
[array
->count
++];
4377 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
4379 struct triangulation
*item
;
4381 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
4384 item
= &array
->items
[array
->count
++];
4385 ZeroMemory(item
, sizeof(*item
));
4389 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
4391 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
4392 return E_OUTOFMEMORY
;
4394 array
->items
[array
->count
++] = vertex_index
;
4398 /* assume fixed point numbers can be converted to float point in place */
4399 C_ASSERT(sizeof(FIXED
) == sizeof(float));
4400 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
4402 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, float emsquare
)
4404 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
4406 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
4407 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
4408 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
4414 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
4415 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
4416 float max_deviation_sq
)
4418 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
4421 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
4422 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
4423 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
4425 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
4426 if (deviation_sq
< max_deviation_sq
) {
4427 struct point2d
*pt
= add_points(outline
, 1);
4428 if (!pt
) return E_OUTOFMEMORY
;
4430 pt
->corner
= POINTTYPE_CURVE
;
4431 /* the end point is omitted because the end line merges into the next segment of
4432 * the split bezier curve, and the end of the split bezier curve is added outside
4433 * this recursive function. */
4435 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
4436 if (hr
!= S_OK
) return hr
;
4437 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
4438 if (hr
!= S_OK
) return hr
;
4444 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
4446 /* dot product = cos(theta) */
4447 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
4450 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
4452 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
4462 static BOOL
attempt_line_merge(struct outline
*outline
,
4464 const D3DXVECTOR2
*nextpt
,
4466 const struct cos_table
*table
)
4468 D3DXVECTOR2 curdir
, lastdir
;
4469 struct point2d
*prevpt
, *pt
;
4472 pt
= &outline
->items
[pt_index
];
4473 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
4474 prevpt
= &outline
->items
[pt_index
];
4477 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
4479 if (outline
->count
< 2)
4482 /* remove last point if the next line continues the last line */
4483 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
4484 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
4485 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
4488 if (pt
->corner
== POINTTYPE_CURVE_END
)
4489 prevpt
->corner
= pt
->corner
;
4490 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
4491 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
4495 if (outline
->count
< 2)
4498 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
4499 prevpt
= &outline
->items
[pt_index
];
4500 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
4501 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
4506 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
4507 float max_deviation_sq
, float emsquare
, const struct cos_table
*cos_table
)
4509 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
4511 while ((char *)header
< (char *)raw_outline
+ datasize
)
4513 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
4514 struct point2d
*lastpt
, *pt
;
4515 D3DXVECTOR2 lastdir
;
4516 D3DXVECTOR2
*pt_flt
;
4518 struct outline
*outline
= add_outline(&glyph
->outlines
);
4521 return E_OUTOFMEMORY
;
4523 pt
= add_points(outline
, 1);
4525 return E_OUTOFMEMORY
;
4526 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
4528 pt
->corner
= POINTTYPE_CORNER
;
4530 if (header
->dwType
!= TT_POLYGON_TYPE
)
4531 FIXME("Unknown header type %d\n", header
->dwType
);
4533 while ((char *)curve
< (char *)header
+ header
->cb
)
4535 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
4536 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
4539 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
4543 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
4545 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
4550 int count
= curve
->cpfx
;
4555 D3DXVECTOR2 bezier_end
;
4557 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j
], &pt_flt
[j
+1]), 0.5f
);
4558 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j
], &bezier_end
, max_deviation_sq
);
4561 bezier_start
= bezier_end
;
4565 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j
], &pt_flt
[j
+1], max_deviation_sq
);
4569 pt
= add_points(outline
, 1);
4571 return E_OUTOFMEMORY
;
4573 pt
->pos
= pt_flt
[j
];
4574 pt
->corner
= POINTTYPE_CURVE_END
;
4576 pt
= add_points(outline
, curve
->cpfx
);
4578 return E_OUTOFMEMORY
;
4579 for (j
= 0; j
< curve
->cpfx
; j
++)
4581 pt
->pos
= pt_flt
[j
];
4582 pt
->corner
= POINTTYPE_CORNER
;
4587 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
4590 /* remove last point if the next line continues the last line */
4591 if (outline
->count
>= 3) {
4594 lastpt
= &outline
->items
[outline
->count
- 1];
4595 pt
= &outline
->items
[0];
4596 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
4597 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
4599 if (pt
->corner
== POINTTYPE_CURVE_START
)
4600 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
4602 pt
->corner
= POINTTYPE_CURVE_END
;
4605 lastpt
= &outline
->items
[outline
->count
- 1];
4607 /* outline closed with a line from end to start point */
4608 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
4610 lastpt
= &outline
->items
[0];
4611 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
4612 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
4613 lastpt
->corner
= POINTTYPE_CORNER
;
4614 pt
= &outline
->items
[1];
4615 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
4616 *lastpt
= outline
->items
[outline
->count
];
4619 lastpt
= &outline
->items
[outline
->count
- 1];
4620 pt
= &outline
->items
[0];
4621 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
4622 for (j
= 0; j
< outline
->count
; j
++)
4627 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
4628 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
4630 switch (lastpt
->corner
)
4632 case POINTTYPE_CURVE_START
:
4633 case POINTTYPE_CURVE_END
:
4634 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
4635 lastpt
->corner
= POINTTYPE_CORNER
;
4637 case POINTTYPE_CURVE_MIDDLE
:
4638 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
4639 lastpt
->corner
= POINTTYPE_CORNER
;
4641 lastpt
->corner
= POINTTYPE_CURVE
;
4649 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
4654 /* Get the y-distance from a line to a point */
4655 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
4656 D3DXVECTOR2
*line_pt2
,
4659 D3DXVECTOR2 line_vec
= {0, 0};
4663 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
4664 line_pt_dx
= point
->x
- line_pt1
->x
;
4665 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
4666 return point
->y
- line_y
;
4669 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
4671 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
4674 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
4676 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
4679 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
4681 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
4682 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
4686 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
4687 struct triangulation_array
*triangulations
,
4691 struct glyphinfo
*glyph
= triangulations
->glyph
;
4692 struct triangulation
*t
= *t_ptr
;
4697 if (t
->last_on_top
) {
4705 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
4706 /* consume all vertices on the stack */
4707 WORD last_pt
= t
->vertex_stack
.items
[0];
4709 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
4711 face
= add_face(&glyph
->faces
);
4712 if (!face
) return E_OUTOFMEMORY
;
4713 (*face
)[0] = vtx_idx
;
4714 (*face
)[f1
] = last_pt
;
4715 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
4717 t
->vertex_stack
.items
[0] = last_pt
;
4718 t
->vertex_stack
.count
= 1;
4719 } else if (t
->vertex_stack
.count
> 1) {
4720 int i
= t
->vertex_stack
.count
- 1;
4721 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
4722 WORD top_idx
= t
->vertex_stack
.items
[i
--];
4723 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
4727 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
4728 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
4730 if (prev_pt
->x
!= top_pt
->x
&&
4731 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
4732 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
4735 face
= add_face(&glyph
->faces
);
4736 if (!face
) return E_OUTOFMEMORY
;
4737 (*face
)[0] = vtx_idx
;
4738 (*face
)[f1
] = prev_idx
;
4739 (*face
)[f2
] = top_idx
;
4743 t
->vertex_stack
.count
--;
4746 t
->last_on_top
= to_top
;
4748 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
4750 if (hr
== S_OK
&& t
->merging
) {
4751 struct triangulation
*t2
;
4753 t2
= to_top
? t
- 1 : t
+ 1;
4754 t2
->merging
= FALSE
;
4755 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
4756 if (hr
!= S_OK
) return hr
;
4757 remove_triangulation(triangulations
, t
);
4765 /* check if the point is next on the outline for either the top or bottom */
4766 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
4768 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
4769 WORD idx
= t
->vertex_stack
.items
[i
];
4770 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
4771 struct outline
*outline
= pt_idx
->outline
;
4774 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
4776 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
4778 return &outline
->items
[i
].pos
;
4781 static int compare_vertex_indices(const void *a
, const void *b
)
4783 const struct point2d_index
*idx1
= a
, *idx2
= b
;
4784 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
4785 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
4786 float diff
= p1
->x
- p2
->x
;
4789 diff
= p1
->y
- p2
->y
;
4791 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
4794 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
4798 struct glyphinfo
*glyph
= triangulations
->glyph
;
4799 int nb_vertices
= 0;
4801 struct point2d_index
*idx_ptr
;
4803 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
4804 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
4806 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
4807 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
4808 if (!glyph
->ordered_vertices
.items
)
4809 return E_OUTOFMEMORY
;
4811 idx_ptr
= glyph
->ordered_vertices
.items
;
4812 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
4814 struct outline
*outline
= &glyph
->outlines
.items
[i
];
4817 idx_ptr
->outline
= outline
;
4818 idx_ptr
->vertex
= 0;
4820 for (j
= outline
->count
- 1; j
> 0; j
--)
4822 idx_ptr
->outline
= outline
;
4823 idx_ptr
->vertex
= j
;
4827 glyph
->ordered_vertices
.count
= nb_vertices
;
4829 /* Native implementation seems to try to create a triangle fan from
4830 * the first outline point if the glyph only has one outline. */
4831 if (glyph
->outlines
.count
== 1)
4833 struct outline
*outline
= glyph
->outlines
.items
;
4834 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
4835 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
4838 for (i
= 2; i
< outline
->count
; i
++)
4840 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
4841 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
4842 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
4844 D3DXVec2Subtract(&v1
, base
, last
);
4845 D3DXVec2Subtract(&v2
, last
, next
);
4846 ccw
= D3DXVec2CCW(&v1
, &v2
);
4854 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
4855 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
4856 if (!glyph
->faces
.items
)
4857 return E_OUTOFMEMORY
;
4859 glyph
->faces
.count
= outline
->count
- 2;
4860 for (i
= 0; i
< glyph
->faces
.count
; i
++)
4862 glyph
->faces
.items
[i
][0] = 0;
4863 glyph
->faces
.items
[i
][1] = i
+ 1;
4864 glyph
->faces
.items
[i
][2] = i
+ 2;
4870 /* Perform 2D polygon triangulation for complex glyphs.
4871 * Triangulation is performed using a sweep line concept, from right to left,
4872 * by processing vertices in sorted order. Complex polygons are split into
4873 * monotone polygons which are triangulated separately. */
4874 /* FIXME: The order of the faces is not consistent with the native implementation. */
4876 /* Reserve space for maximum possible faces from triangulation.
4877 * # faces for outer outlines = outline->count - 2
4878 * # faces for inner outlines = outline->count + 2
4879 * There must be at least 1 outer outline. */
4880 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
4881 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
4882 if (!glyph
->faces
.items
)
4883 return E_OUTOFMEMORY
;
4885 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
4886 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
4887 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
4890 int end
= triangulations
->count
;
4894 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
4895 int current
= (start
+ end
) / 2;
4896 struct triangulation
*t
= &triangulations
->items
[current
];
4897 BOOL on_top_outline
= FALSE
;
4898 D3DXVECTOR2
*top_next
, *bottom_next
;
4899 WORD top_idx
, bottom_idx
;
4901 if (t
->merging
&& t
->last_on_top
)
4902 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
4904 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
4905 if (sweep_vtx
== top_next
)
4907 if (t
->merging
&& t
->last_on_top
)
4909 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
4910 if (hr
!= S_OK
) return hr
;
4912 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
4913 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
4915 /* point also on bottom outline of higher triangulation */
4916 struct triangulation
*t2
= t
+ 1;
4917 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
4918 if (hr
!= S_OK
) return hr
;
4923 on_top_outline
= TRUE
;
4926 if (t
->merging
&& !t
->last_on_top
)
4927 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
4929 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
4930 if (sweep_vtx
== bottom_next
)
4932 if (t
->merging
&& !t
->last_on_top
)
4934 if (on_top_outline
) {
4935 /* outline finished */
4936 remove_triangulation(triangulations
, t
);
4940 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
4941 if (hr
!= S_OK
) return hr
;
4943 if (t
> triangulations
->items
&&
4944 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
4946 struct triangulation
*t2
= t
- 1;
4947 /* point also on top outline of lower triangulation */
4948 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
4949 if (hr
!= S_OK
) return hr
;
4950 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
4960 if (t
->last_on_top
) {
4961 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
4962 bottom_idx
= t
->vertex_stack
.items
[0];
4964 top_idx
= t
->vertex_stack
.items
[0];
4965 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
4968 /* check if the point is inside or outside this polygon */
4969 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
4970 top_next
, sweep_vtx
) > 0)
4972 start
= current
+ 1;
4973 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
4974 bottom_next
, sweep_vtx
) < 0)
4977 } else if (t
->merging
) {
4978 /* inside, so cancel merging */
4979 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
4981 t2
->merging
= FALSE
;
4982 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
4983 if (hr
!= S_OK
) return hr
;
4984 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
4985 if (hr
!= S_OK
) return hr
;
4988 /* inside, so split polygon into two monotone parts */
4989 struct triangulation
*t2
= add_triangulation(triangulations
);
4990 if (!t2
) return E_OUTOFMEMORY
;
4991 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
4992 if (t
->last_on_top
) {
4999 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
5000 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
5001 if (hr
!= S_OK
) return hr
;
5002 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
5003 if (hr
!= S_OK
) return hr
;
5004 t2
->last_on_top
= !t
->last_on_top
;
5006 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
5007 if (hr
!= S_OK
) return hr
;
5013 struct triangulation
*t
;
5014 struct triangulation
*t2
= add_triangulation(triangulations
);
5015 if (!t2
) return E_OUTOFMEMORY
;
5016 t
= &triangulations
->items
[start
];
5017 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
5018 ZeroMemory(t
, sizeof(*t
));
5019 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
5020 if (hr
!= S_OK
) return hr
;
5026 HRESULT WINAPI
D3DXCreateTextW(LPDIRECT3DDEVICE9 device
,
5027 HDC hdc
, LPCWSTR text
,
5028 FLOAT deviation
, FLOAT extrusion
,
5029 LPD3DXMESH
*mesh_ptr
, LPD3DXBUFFER
*adjacency
,
5030 LPGLYPHMETRICSFLOAT glyphmetrics
)
5033 ID3DXMesh
*mesh
= NULL
;
5034 DWORD nb_vertices
, nb_faces
;
5035 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
5036 struct vertex
*vertices
= NULL
;
5041 OUTLINETEXTMETRICW otm
;
5042 HFONT font
= NULL
, oldfont
= NULL
;
5043 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
5044 void *raw_outline
= NULL
;
5046 struct glyphinfo
*glyphs
= NULL
;
5048 struct triangulation_array triangulations
= {0, 0, NULL
};
5050 struct vertex
*vertex_ptr
;
5052 float max_deviation_sq
;
5053 const struct cos_table cos_table
= {
5054 cos(D3DXToRadian(0.5f
)),
5055 cos(D3DXToRadian(45.0f
)),
5056 cos(D3DXToRadian(90.0f
)),
5060 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
5061 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
5063 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
5064 return D3DERR_INVALIDCALL
;
5068 FIXME("Case of adjacency != NULL not implemented.\n");
5072 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
5073 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
5075 return D3DERR_INVALIDCALL
;
5078 if (deviation
== 0.0f
)
5079 deviation
= 1.0f
/ otm
.otmEMSquare
;
5080 max_deviation_sq
= deviation
* deviation
;
5082 lf
.lfHeight
= otm
.otmEMSquare
;
5084 font
= CreateFontIndirectW(&lf
);
5089 oldfont
= SelectObject(hdc
, font
);
5091 textlen
= strlenW(text
);
5092 for (i
= 0; i
< textlen
; i
++)
5094 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
5096 return D3DERR_INVALIDCALL
;
5097 if (bufsize
< datasize
)
5100 if (!bufsize
) { /* e.g. text == " " */
5101 hr
= D3DERR_INVALIDCALL
;
5105 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
5106 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
5107 if (!glyphs
|| !raw_outline
) {
5113 for (i
= 0; i
< textlen
; i
++)
5115 /* get outline points from data returned from GetGlyphOutline */
5118 glyphs
[i
].offset_x
= offset_x
;
5120 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
5121 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
5122 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
5123 if (hr
!= S_OK
) goto error
;
5125 triangulations
.glyph
= &glyphs
[i
];
5126 hr
= triangulate(&triangulations
);
5127 if (hr
!= S_OK
) goto error
;
5128 if (triangulations
.count
) {
5129 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
5130 triangulations
.count
= 0;
5135 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
5136 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
5137 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
5138 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
5139 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
5140 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
5142 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
5145 /* corner points need an extra vertex for the different side faces normals */
5147 nb_outline_points
= 0;
5149 for (i
= 0; i
< textlen
; i
++)
5152 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
5153 nb_front_faces
+= glyphs
[i
].faces
.count
;
5154 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
5157 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
5158 nb_corners
++; /* first outline point always repeated as a corner */
5159 for (k
= 1; k
< outline
->count
; k
++)
5160 if (outline
->items
[k
].corner
)
5165 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
5166 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
5169 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
5170 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
5174 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
5178 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
5182 /* convert 2D vertices and faces into 3D mesh */
5183 vertex_ptr
= vertices
;
5185 if (extrusion
== 0.0f
) {
5192 for (i
= 0; i
< textlen
; i
++)
5196 struct vertex
*back_vertices
;
5199 /* side vertices and faces */
5200 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
5202 struct vertex
*outline_vertices
= vertex_ptr
;
5203 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
5205 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
5206 struct point2d
*pt
= &outline
->items
[0];
5208 for (k
= 1; k
<= outline
->count
; k
++)
5211 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
5212 WORD vtx_idx
= vertex_ptr
- vertices
;
5215 if (pt
->corner
== POINTTYPE_CURVE_START
)
5216 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
5217 else if (pt
->corner
)
5218 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
5220 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
5221 D3DXVec2Normalize(&vec
, &vec
);
5222 vtx
.normal
.x
= -vec
.y
;
5223 vtx
.normal
.y
= vec
.x
;
5226 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
5227 vtx
.position
.y
= pt
->pos
.y
;
5229 *vertex_ptr
++ = vtx
;
5231 vtx
.position
.z
= -extrusion
;
5232 *vertex_ptr
++ = vtx
;
5234 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
5235 vtx
.position
.y
= nextpt
->pos
.y
;
5236 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
5237 vtx
.position
.z
= -extrusion
;
5238 *vertex_ptr
++ = vtx
;
5240 *vertex_ptr
++ = vtx
;
5242 (*face_ptr
)[0] = vtx_idx
;
5243 (*face_ptr
)[1] = vtx_idx
+ 2;
5244 (*face_ptr
)[2] = vtx_idx
+ 1;
5247 (*face_ptr
)[0] = vtx_idx
;
5248 (*face_ptr
)[1] = vtx_idx
+ 3;
5249 (*face_ptr
)[2] = vtx_idx
+ 2;
5252 if (nextpt
->corner
) {
5253 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
5254 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
5255 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
5257 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
5259 D3DXVec2Normalize(&vec
, &vec
);
5260 vtx
.normal
.x
= -vec
.y
;
5261 vtx
.normal
.y
= vec
.x
;
5264 *vertex_ptr
++ = vtx
;
5265 vtx
.position
.z
= -extrusion
;
5266 *vertex_ptr
++ = vtx
;
5269 (*face_ptr
)[0] = vtx_idx
;
5270 (*face_ptr
)[1] = vtx_idx
+ 3;
5271 (*face_ptr
)[2] = vtx_idx
+ 1;
5274 (*face_ptr
)[0] = vtx_idx
;
5275 (*face_ptr
)[1] = vtx_idx
+ 2;
5276 (*face_ptr
)[2] = vtx_idx
+ 3;
5284 *vertex_ptr
++ = *outline_vertices
++;
5285 *vertex_ptr
++ = *outline_vertices
++;
5289 /* back vertices and faces */
5290 back_faces
= face_ptr
;
5291 back_vertices
= vertex_ptr
;
5292 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
5294 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
5295 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
5296 vertex_ptr
->position
.y
= pt
->y
;
5297 vertex_ptr
->position
.z
= 0;
5298 vertex_ptr
->normal
.x
= 0;
5299 vertex_ptr
->normal
.y
= 0;
5300 vertex_ptr
->normal
.z
= 1;
5303 count
= back_vertices
- vertices
;
5304 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
5306 face
*f
= &glyphs
[i
].faces
.items
[j
];
5307 (*face_ptr
)[0] = (*f
)[0] + count
;
5308 (*face_ptr
)[1] = (*f
)[1] + count
;
5309 (*face_ptr
)[2] = (*f
)[2] + count
;
5313 /* front vertices and faces */
5314 j
= count
= vertex_ptr
- back_vertices
;
5317 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
5318 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
5319 vertex_ptr
->position
.z
= -extrusion
;
5320 vertex_ptr
->normal
.x
= 0;
5321 vertex_ptr
->normal
.y
= 0;
5322 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
5326 j
= face_ptr
- back_faces
;
5329 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
5330 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
5331 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
5341 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
5342 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
5343 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
5346 for (i
= 0; i
< textlen
; i
++)
5349 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
5350 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
5351 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
5352 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
5353 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
5355 HeapFree(GetProcessHeap(), 0, glyphs
);
5357 if (triangulations
.items
) {
5359 for (i
= 0; i
< triangulations
.count
; i
++)
5360 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
5361 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
5363 HeapFree(GetProcessHeap(), 0, raw_outline
);
5364 if (oldfont
) SelectObject(hdc
, oldfont
);
5365 if (font
) DeleteObject(font
);