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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
29 #define NONAMELESSUNION
38 #include "wine/debug.h"
39 #include "wine/unicode.h"
40 #include "wine/list.h"
41 #include "d3dx9_36_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
45 typedef struct ID3DXMeshImpl
47 ID3DXMesh ID3DXMesh_iface
;
54 IDirect3DDevice9
*device
;
55 IDirect3DVertexDeclaration9
*vertex_declaration
;
56 IDirect3DVertexBuffer9
*vertex_buffer
;
57 IDirect3DIndexBuffer9
*index_buffer
;
59 int attrib_buffer_lock_count
;
60 DWORD attrib_table_size
;
61 D3DXATTRIBUTERANGE
*attrib_table
;
64 static inline ID3DXMeshImpl
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
66 return CONTAINING_RECORD(iface
, ID3DXMeshImpl
, ID3DXMesh_iface
);
69 static HRESULT WINAPI
ID3DXMeshImpl_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, LPVOID
*object
)
71 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
73 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), object
);
75 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
76 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
77 IsEqualGUID(riid
, &IID_ID3DXMesh
))
79 iface
->lpVtbl
->AddRef(iface
);
84 WARN("Interface %s not found.\n", debugstr_guid(riid
));
89 static ULONG WINAPI
ID3DXMeshImpl_AddRef(ID3DXMesh
*iface
)
91 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
93 TRACE("(%p)->(): AddRef from %d\n", This
, This
->ref
);
95 return InterlockedIncrement(&This
->ref
);
98 static ULONG WINAPI
ID3DXMeshImpl_Release(ID3DXMesh
*iface
)
100 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
101 ULONG ref
= InterlockedDecrement(&This
->ref
);
103 TRACE("(%p)->(): Release from %d\n", This
, ref
+ 1);
107 IDirect3DIndexBuffer9_Release(This
->index_buffer
);
108 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
109 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
110 IDirect3DDevice9_Release(This
->device
);
111 HeapFree(GetProcessHeap(), 0, This
->attrib_buffer
);
112 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
113 HeapFree(GetProcessHeap(), 0, This
);
119 /*** ID3DXBaseMesh ***/
120 static HRESULT WINAPI
ID3DXMeshImpl_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
122 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
128 TRACE("(%p)->(%u)\n", This
, attrib_id
);
130 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
132 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
133 if (FAILED(hr
)) return hr
;
134 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
135 if (FAILED(hr
)) return hr
;
136 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
137 if (FAILED(hr
)) return hr
;
139 while (face_end
< This
->numfaces
)
141 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
143 if (This
->attrib_buffer
[face_start
] == attrib_id
)
146 if (face_start
>= This
->numfaces
)
148 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
150 if (This
->attrib_buffer
[face_end
] != attrib_id
)
154 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
155 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
156 if (FAILED(hr
)) return hr
;
162 static DWORD WINAPI
ID3DXMeshImpl_GetNumFaces(ID3DXMesh
*iface
)
164 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
166 TRACE("(%p)\n", This
);
168 return This
->numfaces
;
171 static DWORD WINAPI
ID3DXMeshImpl_GetNumVertices(ID3DXMesh
*iface
)
173 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
175 TRACE("(%p)\n", This
);
177 return This
->numvertices
;
180 static DWORD WINAPI
ID3DXMeshImpl_GetFVF(ID3DXMesh
*iface
)
182 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
184 TRACE("(%p)\n", This
);
189 static HRESULT WINAPI
ID3DXMeshImpl_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
191 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
194 TRACE("(%p)\n", This
);
196 if (declaration
== NULL
) return D3DERR_INVALIDCALL
;
198 return IDirect3DVertexDeclaration9_GetDeclaration(This
->vertex_declaration
,
203 static DWORD WINAPI
ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh
*iface
)
205 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
207 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
209 TRACE("iface (%p)\n", This
);
211 IDirect3DVertexDeclaration9_GetDeclaration(This
->vertex_declaration
,
214 return D3DXGetDeclVertexSize(declaration
, 0);
217 static DWORD WINAPI
ID3DXMeshImpl_GetOptions(ID3DXMesh
*iface
)
219 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
221 TRACE("(%p)\n", This
);
223 return This
->options
;
226 static HRESULT WINAPI
ID3DXMeshImpl_GetDevice(ID3DXMesh
*iface
, LPDIRECT3DDEVICE9
*device
)
228 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
230 TRACE("(%p)->(%p)\n", This
, device
);
232 if (device
== NULL
) return D3DERR_INVALIDCALL
;
233 *device
= This
->device
;
234 IDirect3DDevice9_AddRef(This
->device
);
239 static HRESULT WINAPI
ID3DXMeshImpl_CloneMeshFVF(ID3DXMesh
*iface
, DWORD options
, DWORD fvf
, LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*clone_mesh
)
241 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
243 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
245 TRACE("(%p)->(%x,%x,%p,%p)\n", This
, options
, fvf
, device
, clone_mesh
);
247 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
248 if (FAILED(hr
)) return hr
;
250 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
253 static HRESULT WINAPI
ID3DXMeshImpl_CloneMesh(ID3DXMesh
*iface
, DWORD options
, CONST D3DVERTEXELEMENT9
*declaration
, LPDIRECT3DDEVICE9 device
,
254 LPD3DXMESH
*clone_mesh_out
)
256 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
257 ID3DXMeshImpl
*cloned_this
;
258 ID3DXMesh
*clone_mesh
;
259 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
260 void *data_in
, *data_out
;
265 TRACE("(%p)->(%x,%p,%p,%p)\n", This
, options
, declaration
, device
, clone_mesh_out
);
268 return D3DERR_INVALIDCALL
;
270 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
271 if (FAILED(hr
)) return hr
;
273 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++) {
274 if (memcmp(&orig_declaration
[i
], &declaration
[i
], sizeof(*declaration
)))
276 FIXME("Vertex buffer conversion not implemented.\n");
281 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
282 declaration
, device
, &clone_mesh
);
283 if (FAILED(hr
)) return hr
;
285 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
286 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
288 if (options
& D3DXMESH_VB_SHARE
) {
289 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
290 /* FIXME: refactor to avoid creating a new vertex buffer */
291 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
292 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
294 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
295 if (FAILED(hr
)) goto error
;
296 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, D3DLOCK_DISCARD
, &data_out
);
298 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
301 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
302 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
303 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
306 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
307 if (FAILED(hr
)) goto error
;
308 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, D3DLOCK_DISCARD
, &data_out
);
310 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
313 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
314 if (options
& D3DXMESH_32BIT
) {
315 for (i
= 0; i
< This
->numfaces
* 3; i
++)
316 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
318 for (i
= 0; i
< This
->numfaces
* 3; i
++)
319 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
322 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
324 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
325 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
327 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
329 if (This
->attrib_table_size
)
331 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
332 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
333 if (!cloned_this
->attrib_table
) {
337 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
340 *clone_mesh_out
= clone_mesh
;
344 IUnknown_Release(clone_mesh
);
348 static HRESULT WINAPI
ID3DXMeshImpl_GetVertexBuffer(ID3DXMesh
*iface
, LPDIRECT3DVERTEXBUFFER9
*vertex_buffer
)
350 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
352 TRACE("(%p)->(%p)\n", This
, vertex_buffer
);
354 if (vertex_buffer
== NULL
) return D3DERR_INVALIDCALL
;
355 *vertex_buffer
= This
->vertex_buffer
;
356 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
361 static HRESULT WINAPI
ID3DXMeshImpl_GetIndexBuffer(ID3DXMesh
*iface
, LPDIRECT3DINDEXBUFFER9
*index_buffer
)
363 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
365 TRACE("(%p)->(%p)\n", This
, index_buffer
);
367 if (index_buffer
== NULL
) return D3DERR_INVALIDCALL
;
368 *index_buffer
= This
->index_buffer
;
369 IDirect3DIndexBuffer9_AddRef(This
->index_buffer
);
374 static HRESULT WINAPI
ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
376 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
378 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
380 return IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, data
, flags
);
383 static HRESULT WINAPI
ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh
*iface
)
385 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
387 TRACE("(%p)\n", This
);
389 return IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
392 static HRESULT WINAPI
ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
394 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
396 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
398 return IDirect3DIndexBuffer9_Lock(This
->index_buffer
, 0, 0, data
, flags
);
401 static HRESULT WINAPI
ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh
*iface
)
403 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
405 TRACE("(%p)\n", This
);
407 return IDirect3DIndexBuffer9_Unlock(This
->index_buffer
);
410 static HRESULT WINAPI
ID3DXMeshImpl_GetAttributeTable(ID3DXMesh
*iface
, D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
412 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
414 TRACE("(%p)->(%p,%p)\n", This
, attrib_table
, attrib_table_size
);
416 if (attrib_table_size
)
417 *attrib_table_size
= This
->attrib_table_size
;
420 CopyMemory(attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*attrib_table
));
425 static HRESULT WINAPI
ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
, CONST DWORD
*point_reps
, DWORD
*adjacency
)
427 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
429 FIXME("(%p)->(%p,%p): stub\n", This
, point_reps
, adjacency
);
434 static HRESULT WINAPI
ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
, CONST DWORD
*adjacency
, DWORD
*point_reps
)
436 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
438 FIXME("(%p)->(%p,%p): stub\n", This
, adjacency
, point_reps
);
443 struct vertex_metadata
{
446 DWORD first_shared_index
;
449 static int compare_vertex_keys(const void *a
, const void *b
)
451 const struct vertex_metadata
*left
= a
;
452 const struct vertex_metadata
*right
= b
;
453 if (left
->key
== right
->key
)
455 return left
->key
< right
->key
? -1 : 1;
458 static HRESULT WINAPI
ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh
*iface
, FLOAT epsilon
, DWORD
*adjacency
)
460 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
462 BYTE
*vertices
= NULL
;
463 const DWORD
*indices
= NULL
;
466 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
467 struct vertex_metadata
*sorted_vertices
;
468 /* shared_indices links together identical indices in the index buffer so
469 * that adjacency checks can be limited to faces sharing a vertex */
470 DWORD
*shared_indices
= NULL
;
471 const FLOAT epsilon_sq
= epsilon
* epsilon
;
474 TRACE("(%p)->(%f,%p)\n", This
, epsilon
, adjacency
);
477 return D3DERR_INVALIDCALL
;
479 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
480 if (!(This
->options
& D3DXMESH_32BIT
))
481 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
482 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
484 return E_OUTOFMEMORY
;
485 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
487 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
488 if (FAILED(hr
)) goto cleanup
;
489 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
490 if (FAILED(hr
)) goto cleanup
;
492 if (!(This
->options
& D3DXMESH_32BIT
)) {
493 const WORD
*word_indices
= (const WORD
*)indices
;
494 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
495 indices
= dword_indices
;
496 for (i
= 0; i
< This
->numfaces
* 3; i
++)
497 *dword_indices
++ = *word_indices
++;
500 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
501 for (i
= 0; i
< This
->numvertices
; i
++) {
502 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
503 sorted_vertices
[i
].first_shared_index
= -1;
504 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
505 sorted_vertices
[i
].vertex_index
= i
;
507 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
508 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
509 shared_indices
[i
] = *first_shared_index
;
510 *first_shared_index
= i
;
513 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
515 for (i
= 0; i
< This
->numvertices
; i
++) {
516 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
517 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
518 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
520 while (shared_index_a
!= -1) {
522 DWORD shared_index_b
= shared_indices
[shared_index_a
];
523 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
526 while (shared_index_b
!= -1) {
527 /* faces are adjacent if they have another coincident vertex */
528 DWORD base_a
= (shared_index_a
/ 3) * 3;
529 DWORD base_b
= (shared_index_b
/ 3) * 3;
530 BOOL adjacent
= FALSE
;
533 for (k
= 0; k
< 3; k
++) {
534 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
540 for (k
= 1; k
<= 2; k
++) {
541 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
542 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
543 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
544 if (!adjacent
&& epsilon
>= 0.0f
) {
545 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
548 D3DXVec3Subtract(&delta
,
549 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
550 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
551 length_sq
= D3DXVec3LengthSq(&delta
);
552 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
555 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
556 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
557 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
558 adjacency
[adj_a
] = base_b
/ 3;
559 adjacency
[adj_b
] = base_a
/ 3;
566 shared_index_b
= shared_indices
[shared_index_b
];
568 while (++j
< This
->numvertices
) {
569 D3DXVECTOR3
*vertex_b
;
572 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
573 /* no more coincident vertices to try */
574 j
= This
->numvertices
;
577 /* check for coincidence */
578 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
579 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
580 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
581 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
586 if (j
>= This
->numvertices
)
588 shared_index_b
= sorted_vertex_b
->first_shared_index
;
591 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
592 shared_index_a
= sorted_vertex_a
->first_shared_index
;
598 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
599 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
600 HeapFree(GetProcessHeap(), 0, shared_indices
);
604 static HRESULT WINAPI
ID3DXMeshImpl_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
606 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
608 FIXME("(%p)->(%p): stub\n", This
, declaration
);
614 static HRESULT WINAPI
ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
616 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
618 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
620 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
622 if (!(flags
& D3DLOCK_READONLY
)) {
623 D3DXATTRIBUTERANGE
*attrib_table
= This
->attrib_table
;
624 This
->attrib_table_size
= 0;
625 This
->attrib_table
= NULL
;
626 HeapFree(GetProcessHeap(), 0, attrib_table
);
629 *data
= This
->attrib_buffer
;
634 static HRESULT WINAPI
ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh
*iface
)
636 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
639 TRACE("(%p)\n", This
);
641 lock_count
= InterlockedDecrement(&This
->attrib_buffer_lock_count
);
643 if (lock_count
< 0) {
644 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
645 return D3DERR_INVALIDCALL
;
651 static HRESULT WINAPI
ID3DXMeshImpl_Optimize(ID3DXMesh
*iface
, DWORD flags
, CONST DWORD
*adjacency_in
, DWORD
*adjacency_out
,
652 DWORD
*face_remap
, LPD3DXBUFFER
*vertex_remap
, LPD3DXMESH
*opt_mesh
)
654 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
656 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
657 ID3DXMesh
*optimized_mesh
;
659 TRACE("(%p)->(%x,%p,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
662 return D3DERR_INVALIDCALL
;
664 hr
= iface
->lpVtbl
->GetDeclaration(iface
, declaration
);
665 if (FAILED(hr
)) return hr
;
667 hr
= iface
->lpVtbl
->CloneMesh(iface
, This
->options
, declaration
, This
->device
, &optimized_mesh
);
668 if (FAILED(hr
)) return hr
;
670 hr
= optimized_mesh
->lpVtbl
->OptimizeInplace(optimized_mesh
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
);
672 *opt_mesh
= optimized_mesh
;
674 IUnknown_Release(optimized_mesh
);
678 /* Creates a vertex_remap that removes unused vertices.
679 * Indices are updated according to the vertex_remap. */
680 static HRESULT
compact_mesh(ID3DXMeshImpl
*This
, DWORD
*indices
, DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
683 DWORD
*vertex_remap_ptr
;
684 DWORD num_used_vertices
;
687 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
688 if (FAILED(hr
)) return hr
;
689 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
691 for (i
= 0; i
< This
->numfaces
* 3; i
++)
692 vertex_remap_ptr
[indices
[i
]] = 1;
694 /* create old->new vertex mapping */
695 num_used_vertices
= 0;
696 for (i
= 0; i
< This
->numvertices
; i
++) {
697 if (vertex_remap_ptr
[i
])
698 vertex_remap_ptr
[i
] = num_used_vertices
++;
700 vertex_remap_ptr
[i
] = -1;
702 /* convert indices */
703 for (i
= 0; i
< This
->numfaces
* 3; i
++)
704 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
706 /* create new->old vertex mapping */
707 num_used_vertices
= 0;
708 for (i
= 0; i
< This
->numvertices
; i
++) {
709 if (vertex_remap_ptr
[i
] != -1)
710 vertex_remap_ptr
[num_used_vertices
++] = i
;
712 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
713 vertex_remap_ptr
[i
] = -1;
715 *new_num_vertices
= num_used_vertices
;
720 /* count the number of unique attribute values in a sorted attribute buffer */
721 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
723 DWORD last_attribute
= attrib_buffer
[0];
724 DWORD attrib_table_size
= 1;
726 for (i
= 1; i
< numfaces
; i
++) {
727 if (attrib_buffer
[i
] != last_attribute
) {
728 last_attribute
= attrib_buffer
[i
];
732 return attrib_table_size
;
735 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
736 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
738 DWORD attrib_table_size
= 0;
739 DWORD last_attribute
= attrib_buffer
[0];
740 DWORD min_vertex
, max_vertex
;
743 attrib_table
[0].AttribId
= last_attribute
;
744 attrib_table
[0].FaceStart
= 0;
745 min_vertex
= (DWORD
)-1;
747 for (i
= 0; i
< numfaces
; i
++) {
750 if (attrib_buffer
[i
] != last_attribute
) {
751 last_attribute
= attrib_buffer
[i
];
752 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
753 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
754 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
756 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
757 attrib_table
[attrib_table_size
].FaceStart
= i
;
758 min_vertex
= (DWORD
)-1;
761 for (j
= 0; j
< 3; j
++) {
762 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
763 if (vertex_index
< min_vertex
)
764 min_vertex
= vertex_index
;
765 if (vertex_index
> max_vertex
)
766 max_vertex
= vertex_index
;
769 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
770 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
771 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
775 static int attrib_entry_compare(const DWORD
**a
, const DWORD
**b
)
777 const DWORD
*ptr_a
= *a
;
778 const DWORD
*ptr_b
= *b
;
779 int delta
= *ptr_a
- *ptr_b
;
784 delta
= ptr_a
- ptr_b
; /* for stable sort */
788 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
789 static HRESULT
remap_faces_for_attrsort(ID3DXMeshImpl
*This
, const DWORD
*indices
,
790 const DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
792 const DWORD
**sorted_attrib_ptr_buffer
= NULL
;
795 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
796 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
797 if (!*face_remap
|| !sorted_attrib_ptr_buffer
) {
798 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
799 return E_OUTOFMEMORY
;
801 for (i
= 0; i
< This
->numfaces
; i
++)
802 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
803 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
),
804 (int(*)(const void *, const void *))attrib_entry_compare
);
806 for (i
= 0; i
< This
->numfaces
; i
++)
808 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
809 (*face_remap
)[old_face
] = i
;
812 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
813 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
814 for (i
= 0; i
< This
->numfaces
; i
++)
815 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
820 static HRESULT WINAPI
ID3DXMeshImpl_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, CONST DWORD
*adjacency_in
, DWORD
*adjacency_out
,
821 DWORD
*face_remap_out
, LPD3DXBUFFER
*vertex_remap_out
)
823 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
824 void *indices
= NULL
;
825 DWORD
*attrib_buffer
= NULL
;
827 ID3DXBuffer
*vertex_remap
= NULL
;
828 DWORD
*face_remap
= NULL
; /* old -> new mapping */
829 DWORD
*dword_indices
= NULL
;
830 DWORD new_num_vertices
= 0;
831 DWORD new_num_alloc_vertices
= 0;
832 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
833 DWORD
*sorted_attrib_buffer
= NULL
;
836 TRACE("(%p)->(%x,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
839 return D3DERR_INVALIDCALL
;
840 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
841 return D3DERR_INVALIDCALL
;
842 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
843 return D3DERR_INVALIDCALL
;
845 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
847 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
848 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
849 if (flags
& D3DXMESHOPT_STRIPREORDER
)
850 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
854 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, (void**)&indices
);
855 if (FAILED(hr
)) goto cleanup
;
857 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
858 if (!dword_indices
) return E_OUTOFMEMORY
;
859 if (This
->options
& D3DXMESH_32BIT
) {
860 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
862 WORD
*word_indices
= indices
;
863 for (i
= 0; i
< This
->numfaces
* 3; i
++)
864 dword_indices
[i
] = *word_indices
++;
867 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
869 new_num_alloc_vertices
= This
->numvertices
;
870 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
871 if (FAILED(hr
)) goto cleanup
;
872 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
873 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
875 FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
880 hr
= iface
->lpVtbl
->LockAttributeBuffer(iface
, 0, &attrib_buffer
);
881 if (FAILED(hr
)) goto cleanup
;
883 hr
= remap_faces_for_attrsort(This
, dword_indices
, attrib_buffer
, &sorted_attrib_buffer
, &face_remap
);
884 if (FAILED(hr
)) goto cleanup
;
889 /* reorder the vertices using vertex_remap */
890 D3DVERTEXBUFFER_DESC vertex_desc
;
891 DWORD
*vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
892 DWORD vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
896 hr
= IDirect3DVertexBuffer9_GetDesc(This
->vertex_buffer
, &vertex_desc
);
897 if (FAILED(hr
)) goto cleanup
;
899 hr
= IDirect3DDevice9_CreateVertexBuffer(This
->device
, new_num_alloc_vertices
* vertex_size
,
900 vertex_desc
.Usage
, This
->fvf
, vertex_desc
.Pool
, &vertex_buffer
, NULL
);
901 if (FAILED(hr
)) goto cleanup
;
903 hr
= IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, (void**)&orig_vertices
, D3DLOCK_READONLY
);
904 if (FAILED(hr
)) goto cleanup
;
906 hr
= IDirect3DVertexBuffer9_Lock(vertex_buffer
, 0, 0, (void**)&new_vertices
, D3DLOCK_DISCARD
);
908 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
912 for (i
= 0; i
< new_num_vertices
; i
++)
913 memcpy(new_vertices
+ i
* vertex_size
, orig_vertices
+ vertex_remap_ptr
[i
] * vertex_size
, vertex_size
);
915 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
916 IDirect3DVertexBuffer9_Unlock(vertex_buffer
);
917 } else if (vertex_remap_out
) {
918 DWORD
*vertex_remap_ptr
;
920 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), &vertex_remap
);
921 if (FAILED(hr
)) goto cleanup
;
922 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
923 for (i
= 0; i
< This
->numvertices
; i
++)
924 *vertex_remap_ptr
++ = i
;
927 if (flags
& D3DXMESHOPT_ATTRSORT
)
929 D3DXATTRIBUTERANGE
*attrib_table
;
930 DWORD attrib_table_size
;
932 attrib_table_size
= count_attributes(sorted_attrib_buffer
, This
->numfaces
);
933 attrib_table
= HeapAlloc(GetProcessHeap(), 0, attrib_table_size
* sizeof(*attrib_table
));
939 memcpy(attrib_buffer
, sorted_attrib_buffer
, This
->numfaces
* sizeof(*attrib_buffer
));
941 /* reorder the indices using face_remap */
942 if (This
->options
& D3DXMESH_32BIT
) {
943 for (i
= 0; i
< This
->numfaces
; i
++)
944 memcpy((DWORD
*)indices
+ face_remap
[i
] * 3, dword_indices
+ i
* 3, 3 * sizeof(DWORD
));
946 WORD
*word_indices
= indices
;
947 for (i
= 0; i
< This
->numfaces
; i
++) {
948 DWORD new_pos
= face_remap
[i
] * 3;
949 DWORD old_pos
= i
* 3;
950 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
951 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
952 word_indices
[new_pos
] = dword_indices
[old_pos
];
956 fill_attribute_table(attrib_buffer
, This
->numfaces
, indices
,
957 This
->options
& D3DXMESH_32BIT
, attrib_table
);
959 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
960 This
->attrib_table
= attrib_table
;
961 This
->attrib_table_size
= attrib_table_size
;
963 if (This
->options
& D3DXMESH_32BIT
) {
964 memcpy(indices
, dword_indices
, This
->numfaces
* 3 * sizeof(DWORD
));
966 WORD
*word_indices
= indices
;
967 for (i
= 0; i
< This
->numfaces
* 3; i
++)
968 *word_indices
++ = dword_indices
[i
];
974 for (i
= 0; i
< This
->numfaces
; i
++) {
975 DWORD old_pos
= i
* 3;
976 DWORD new_pos
= face_remap
[i
] * 3;
977 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
978 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
979 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
982 memcpy(adjacency_out
, adjacency_in
, This
->numfaces
* 3 * sizeof(*adjacency_out
));
985 if (face_remap_out
) {
987 for (i
= 0; i
< This
->numfaces
; i
++)
988 face_remap_out
[face_remap
[i
]] = i
;
990 for (i
= 0; i
< This
->numfaces
; i
++)
991 face_remap_out
[i
] = i
;
994 if (vertex_remap_out
)
995 *vertex_remap_out
= vertex_remap
;
999 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
1000 This
->vertex_buffer
= vertex_buffer
;
1001 vertex_buffer
= NULL
;
1002 This
->numvertices
= new_num_vertices
;
1007 HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer
);
1008 HeapFree(GetProcessHeap(), 0, face_remap
);
1009 HeapFree(GetProcessHeap(), 0, dword_indices
);
1010 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
1011 if (vertex_buffer
) IDirect3DVertexBuffer9_Release(vertex_buffer
);
1012 if (attrib_buffer
) iface
->lpVtbl
->UnlockAttributeBuffer(iface
);
1013 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1017 static HRESULT WINAPI
ID3DXMeshImpl_SetAttributeTable(ID3DXMesh
*iface
, CONST D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
1019 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1020 D3DXATTRIBUTERANGE
*new_table
= NULL
;
1022 TRACE("(%p)->(%p,%u)\n", This
, attrib_table
, attrib_table_size
);
1024 if (attrib_table_size
) {
1025 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
1027 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
1029 return E_OUTOFMEMORY
;
1031 CopyMemory(new_table
, attrib_table
, size
);
1032 } else if (attrib_table
) {
1033 return D3DERR_INVALIDCALL
;
1035 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1036 This
->attrib_table
= new_table
;
1037 This
->attrib_table_size
= attrib_table_size
;
1042 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
1044 /*** IUnknown methods ***/
1045 ID3DXMeshImpl_QueryInterface
,
1046 ID3DXMeshImpl_AddRef
,
1047 ID3DXMeshImpl_Release
,
1048 /*** ID3DXBaseMesh ***/
1049 ID3DXMeshImpl_DrawSubset
,
1050 ID3DXMeshImpl_GetNumFaces
,
1051 ID3DXMeshImpl_GetNumVertices
,
1052 ID3DXMeshImpl_GetFVF
,
1053 ID3DXMeshImpl_GetDeclaration
,
1054 ID3DXMeshImpl_GetNumBytesPerVertex
,
1055 ID3DXMeshImpl_GetOptions
,
1056 ID3DXMeshImpl_GetDevice
,
1057 ID3DXMeshImpl_CloneMeshFVF
,
1058 ID3DXMeshImpl_CloneMesh
,
1059 ID3DXMeshImpl_GetVertexBuffer
,
1060 ID3DXMeshImpl_GetIndexBuffer
,
1061 ID3DXMeshImpl_LockVertexBuffer
,
1062 ID3DXMeshImpl_UnlockVertexBuffer
,
1063 ID3DXMeshImpl_LockIndexBuffer
,
1064 ID3DXMeshImpl_UnlockIndexBuffer
,
1065 ID3DXMeshImpl_GetAttributeTable
,
1066 ID3DXMeshImpl_ConvertPointRepsToAdjacency
,
1067 ID3DXMeshImpl_ConvertAdjacencyToPointReps
,
1068 ID3DXMeshImpl_GenerateAdjacency
,
1069 ID3DXMeshImpl_UpdateSemantics
,
1071 ID3DXMeshImpl_LockAttributeBuffer
,
1072 ID3DXMeshImpl_UnlockAttributeBuffer
,
1073 ID3DXMeshImpl_Optimize
,
1074 ID3DXMeshImpl_OptimizeInplace
,
1075 ID3DXMeshImpl_SetAttributeTable
1078 /*************************************************************************
1081 BOOL WINAPI
D3DXBoxBoundProbe(CONST D3DXVECTOR3
*pmin
, CONST D3DXVECTOR3
*pmax
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
1083 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algoritm
1084 Amy Williams University of Utah
1085 Steve Barrus University of Utah
1086 R. Keith Morley University of Utah
1087 Peter Shirley University of Utah
1089 International Conference on Computer Graphics and Interactive Techniques archive
1090 ACM SIGGRAPH 2005 Courses
1091 Los Angeles, California
1093 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1095 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1096 against each slab, if there's anything left of the ray after we're
1097 done we've got an intersection of the ray with the box.
1101 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
1103 div
= 1.0f
/ praydirection
->x
;
1106 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
1107 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
1111 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
1112 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
1115 if ( tmax
< 0.0f
) return FALSE
;
1117 div
= 1.0f
/ praydirection
->y
;
1120 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
1121 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
1125 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
1126 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
1129 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
1131 if ( tymin
> tmin
) tmin
= tymin
;
1132 if ( tymax
< tmax
) tmax
= tymax
;
1134 div
= 1.0f
/ praydirection
->z
;
1137 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
1138 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
1142 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
1143 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
1146 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
1151 /*************************************************************************
1152 * D3DXComputeBoundingBox
1154 HRESULT WINAPI
D3DXComputeBoundingBox(CONST D3DXVECTOR3
*pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
1159 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
1161 *pmin
= *pfirstposition
;
1164 for(i
=0; i
<numvertices
; i
++)
1166 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
1168 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
1169 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
1171 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
1172 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
1174 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
1175 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
1181 /*************************************************************************
1182 * D3DXComputeBoundingSphere
1184 HRESULT WINAPI
D3DXComputeBoundingSphere(CONST D3DXVECTOR3
* pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, FLOAT
*pradius
)
1186 D3DXVECTOR3 temp
, temp1
;
1190 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
1198 for(i
=0; i
<numvertices
; i
++)
1200 D3DXVec3Add(&temp1
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
1204 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/((FLOAT
)numvertices
));
1206 for(i
=0; i
<numvertices
; i
++)
1208 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
1209 if ( d
> *pradius
) *pradius
= d
;
1214 static const UINT d3dx_decltype_size
[D3DDECLTYPE_UNUSED
] =
1216 /* D3DDECLTYPE_FLOAT1 */ 1 * 4,
1217 /* D3DDECLTYPE_FLOAT2 */ 2 * 4,
1218 /* D3DDECLTYPE_FLOAT3 */ 3 * 4,
1219 /* D3DDECLTYPE_FLOAT4 */ 4 * 4,
1220 /* D3DDECLTYPE_D3DCOLOR */ 4 * 1,
1221 /* D3DDECLTYPE_UBYTE4 */ 4 * 1,
1222 /* D3DDECLTYPE_SHORT2 */ 2 * 2,
1223 /* D3DDECLTYPE_SHORT4 */ 4 * 2,
1224 /* D3DDECLTYPE_UBYTE4N */ 4 * 1,
1225 /* D3DDECLTYPE_SHORT2N */ 2 * 2,
1226 /* D3DDECLTYPE_SHORT4N */ 4 * 2,
1227 /* D3DDECLTYPE_USHORT2N */ 2 * 2,
1228 /* D3DDECLTYPE_USHORT4N */ 4 * 2,
1229 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
1230 /* D3DDECLTYPE_DEC3N */ 4,
1231 /* D3DDECLTYPE_FLOAT16_2 */ 2 * 2,
1232 /* D3DDECLTYPE_FLOAT16_4 */ 4 * 2,
1235 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
1236 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
1238 declaration
[*idx
].Stream
= 0;
1239 declaration
[*idx
].Offset
= *offset
;
1240 declaration
[*idx
].Type
= type
;
1241 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
1242 declaration
[*idx
].Usage
= usage
;
1243 declaration
[*idx
].UsageIndex
= usage_idx
;
1245 *offset
+= d3dx_decltype_size
[type
];
1249 /*************************************************************************
1250 * D3DXDeclaratorFromFVF
1252 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1254 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
1255 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
1256 unsigned int offset
= 0;
1257 unsigned int idx
= 0;
1260 TRACE("fvf %#x, declaration %p.\n", fvf
, declaration
);
1262 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
1264 if (fvf
& D3DFVF_POSITION_MASK
)
1266 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
1267 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
1268 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
1270 if (has_blend_idx
) --blend_count
;
1272 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
1273 || (has_blend
&& blend_count
> 4))
1274 return D3DERR_INVALIDCALL
;
1276 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
1277 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
1279 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
1283 switch (blend_count
)
1288 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1291 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1294 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1297 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1300 ERR("Invalid blend count %u.\n", blend_count
);
1306 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
1307 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
1308 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
1309 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
1314 if (fvf
& D3DFVF_NORMAL
)
1315 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
1316 if (fvf
& D3DFVF_PSIZE
)
1317 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
1318 if (fvf
& D3DFVF_DIFFUSE
)
1319 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
1320 if (fvf
& D3DFVF_SPECULAR
)
1321 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
1323 for (i
= 0; i
< tex_count
; ++i
)
1325 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
1327 case D3DFVF_TEXTUREFORMAT1
:
1328 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
1330 case D3DFVF_TEXTUREFORMAT2
:
1331 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
1333 case D3DFVF_TEXTUREFORMAT3
:
1334 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
1336 case D3DFVF_TEXTUREFORMAT4
:
1337 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
1342 declaration
[idx
] = end_element
;
1347 /*************************************************************************
1348 * D3DXFVFFromDeclarator
1350 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
1352 unsigned int i
= 0, texture
, offset
;
1354 TRACE("(%p, %p)\n", declaration
, fvf
);
1357 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
1359 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
1360 declaration
[1].UsageIndex
== 0) &&
1361 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
1362 declaration
[2].UsageIndex
== 0))
1364 return D3DERR_INVALIDCALL
;
1366 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
1367 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
1369 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
1371 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
1375 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
1379 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
1380 declaration
[1].UsageIndex
== 0)
1382 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
1383 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
1385 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
1387 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
1391 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
1393 switch (declaration
[1].Type
)
1395 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
1396 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
1397 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
1398 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
1404 switch (declaration
[1].Type
)
1406 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
1407 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
1408 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
1409 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
1420 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
1421 declaration
[0].UsageIndex
== 0)
1423 *fvf
|= D3DFVF_XYZRHW
;
1427 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
1429 *fvf
|= D3DFVF_NORMAL
;
1432 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
1433 declaration
[i
].UsageIndex
== 0)
1435 *fvf
|= D3DFVF_PSIZE
;
1438 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
1439 declaration
[i
].UsageIndex
== 0)
1441 *fvf
|= D3DFVF_DIFFUSE
;
1444 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
1445 declaration
[i
].UsageIndex
== 1)
1447 *fvf
|= D3DFVF_SPECULAR
;
1451 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
1453 if (declaration
[i
].Stream
== 0xFF)
1457 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1458 declaration
[i
].UsageIndex
== texture
)
1460 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
1462 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1463 declaration
[i
].UsageIndex
== texture
)
1465 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
1467 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1468 declaration
[i
].UsageIndex
== texture
)
1470 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
1472 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1473 declaration
[i
].UsageIndex
== texture
)
1475 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
1479 return D3DERR_INVALIDCALL
;
1483 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
1485 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
1486 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
1488 if (declaration
[i
].Offset
!= offset
)
1490 return D3DERR_INVALIDCALL
;
1497 /*************************************************************************
1498 * D3DXGetFVFVertexSize
1500 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
1502 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
1505 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
1509 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
1511 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
1512 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
1513 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
1514 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
1516 switch (FVF
& D3DFVF_POSITION_MASK
)
1518 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
1519 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
1520 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
1521 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
1522 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
1523 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
1524 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
1525 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
1528 for (i
= 0; i
< numTextures
; i
++)
1530 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
1536 /*************************************************************************
1537 * D3DXGetDeclVertexSize
1539 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
1541 const D3DVERTEXELEMENT9
*element
;
1544 TRACE("decl %p, stream_idx %u\n", decl
, stream_idx
);
1546 if (!decl
) return 0;
1548 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
1552 if (element
->Stream
!= stream_idx
) continue;
1554 if (element
->Type
>= sizeof(d3dx_decltype_size
) / sizeof(*d3dx_decltype_size
))
1556 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
1560 type_size
= d3dx_decltype_size
[element
->Type
];
1561 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
1567 /*************************************************************************
1570 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
1572 const D3DVERTEXELEMENT9
*element
;
1574 TRACE("decl %p\n", decl
);
1576 /* null decl results in exception on Windows XP */
1578 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
1580 return element
- decl
;
1583 /*************************************************************************
1586 BOOL WINAPI
D3DXIntersectTri(CONST D3DXVECTOR3
*p0
, CONST D3DXVECTOR3
*p1
, CONST D3DXVECTOR3
*p2
, CONST D3DXVECTOR3
*praypos
, CONST D3DXVECTOR3
*praydir
, FLOAT
*pu
, FLOAT
*pv
, FLOAT
*pdist
)
1591 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
1592 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
1593 m
.u
.m
[2][0] = -praydir
->x
;
1595 m
.u
.m
[0][1] = p1
->y
- p0
->z
;
1596 m
.u
.m
[1][1] = p2
->y
- p0
->z
;
1597 m
.u
.m
[2][1] = -praydir
->y
;
1599 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
1600 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
1601 m
.u
.m
[2][2] = -praydir
->z
;
1608 vec
.x
= praypos
->x
- p0
->x
;
1609 vec
.y
= praypos
->y
- p0
->y
;
1610 vec
.z
= praypos
->z
- p0
->z
;
1613 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
1615 D3DXVec4Transform(&vec
, &vec
, &m
);
1616 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
1620 *pdist
= fabs( vec
.z
);
1628 /*************************************************************************
1629 * D3DXSphereBoundProbe
1631 BOOL WINAPI
D3DXSphereBoundProbe(CONST D3DXVECTOR3
*pcenter
, FLOAT radius
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
1633 D3DXVECTOR3 difference
;
1636 a
= D3DXVec3LengthSq(praydirection
);
1637 if (!D3DXVec3Subtract(&difference
, prayposition
, pcenter
)) return FALSE
;
1638 b
= D3DXVec3Dot(&difference
, praydirection
);
1639 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
1642 if ( ( d
<= 0.0f
) || ( sqrt(d
) <= b
) ) return FALSE
;
1646 /*************************************************************************
1649 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
, CONST D3DVERTEXELEMENT9
*declaration
,
1650 LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
)
1654 IDirect3DVertexDeclaration9
*vertex_declaration
;
1655 IDirect3DVertexBuffer9
*vertex_buffer
;
1656 IDirect3DIndexBuffer9
*index_buffer
;
1657 DWORD
*attrib_buffer
;
1658 ID3DXMeshImpl
*object
;
1659 DWORD index_usage
= 0;
1660 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
1661 D3DFORMAT index_format
= D3DFMT_INDEX16
;
1662 DWORD vertex_usage
= 0;
1663 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
1666 TRACE("(%d, %d, %x, %p, %p, %p)\n", numfaces
, numvertices
, options
, declaration
, device
, mesh
);
1668 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
1669 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
1670 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
1672 return D3DERR_INVALIDCALL
;
1674 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1675 if (declaration
[i
].Stream
!= 0)
1676 return D3DERR_INVALIDCALL
;
1678 if (options
& D3DXMESH_32BIT
)
1679 index_format
= D3DFMT_INDEX32
;
1681 if (options
& D3DXMESH_DONOTCLIP
) {
1682 index_usage
|= D3DUSAGE_DONOTCLIP
;
1683 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
1685 if (options
& D3DXMESH_POINTS
) {
1686 index_usage
|= D3DUSAGE_POINTS
;
1687 vertex_usage
|= D3DUSAGE_POINTS
;
1689 if (options
& D3DXMESH_RTPATCHES
) {
1690 index_usage
|= D3DUSAGE_RTPATCHES
;
1691 vertex_usage
|= D3DUSAGE_RTPATCHES
;
1693 if (options
& D3DXMESH_NPATCHES
) {
1694 index_usage
|= D3DUSAGE_NPATCHES
;
1695 vertex_usage
|= D3DUSAGE_NPATCHES
;
1698 if (options
& D3DXMESH_VB_SYSTEMMEM
)
1699 vertex_pool
= D3DPOOL_SYSTEMMEM
;
1700 else if (options
& D3DXMESH_VB_MANAGED
)
1701 vertex_pool
= D3DPOOL_MANAGED
;
1703 if (options
& D3DXMESH_VB_WRITEONLY
)
1704 vertex_usage
|= D3DUSAGE_WRITEONLY
;
1705 if (options
& D3DXMESH_VB_DYNAMIC
)
1706 vertex_usage
|= D3DUSAGE_DYNAMIC
;
1707 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
1708 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
1710 if (options
& D3DXMESH_IB_SYSTEMMEM
)
1711 index_pool
= D3DPOOL_SYSTEMMEM
;
1712 else if (options
& D3DXMESH_IB_MANAGED
)
1713 index_pool
= D3DPOOL_MANAGED
;
1715 if (options
& D3DXMESH_IB_WRITEONLY
)
1716 index_usage
|= D3DUSAGE_WRITEONLY
;
1717 if (options
& D3DXMESH_IB_DYNAMIC
)
1718 index_usage
|= D3DUSAGE_DYNAMIC
;
1719 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
1720 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
1722 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
1728 /* Create vertex declaration */
1729 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
1731 &vertex_declaration
);
1734 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
1738 /* Create vertex buffer */
1739 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
1740 numvertices
* D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
),
1748 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
1749 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1753 /* Create index buffer */
1754 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
1755 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
1763 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
1764 IDirect3DVertexBuffer9_Release(vertex_buffer
);
1765 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1769 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
1770 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ID3DXMeshImpl
));
1771 if (object
== NULL
|| attrib_buffer
== NULL
)
1773 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
1774 IDirect3DIndexBuffer9_Release(index_buffer
);
1775 IDirect3DVertexBuffer9_Release(vertex_buffer
);
1776 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1778 return E_OUTOFMEMORY
;
1780 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
1783 object
->numfaces
= numfaces
;
1784 object
->numvertices
= numvertices
;
1785 object
->options
= options
;
1787 object
->device
= device
;
1788 IDirect3DDevice9_AddRef(device
);
1790 object
->vertex_declaration
= vertex_declaration
;
1791 object
->vertex_buffer
= vertex_buffer
;
1792 object
->index_buffer
= index_buffer
;
1793 object
->attrib_buffer
= attrib_buffer
;
1795 *mesh
= &object
->ID3DXMesh_iface
;
1800 /*************************************************************************
1803 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
, DWORD fvf
,
1804 LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
)
1807 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
1809 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
1811 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
1812 if (FAILED(hr
)) return hr
;
1814 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
1820 DWORD num_poly_faces
;
1821 DWORD num_tri_faces
;
1822 D3DXVECTOR3
*vertices
;
1823 DWORD
*num_tri_per_face
;
1828 /* optional mesh data */
1831 D3DXVECTOR3
*normals
;
1832 DWORD
*normal_indices
;
1834 D3DXVECTOR2
*tex_coords
;
1836 DWORD
*vertex_colors
;
1838 DWORD num_materials
;
1839 D3DXMATERIAL
*materials
;
1840 DWORD
*material_indices
;
1843 static HRESULT
get_next_child(IDirectXFileData
*filedata
, IDirectXFileData
**child
, const GUID
**type
)
1846 IDirectXFileDataReference
*child_ref
= NULL
;
1847 IDirectXFileObject
*child_obj
= NULL
;
1848 IDirectXFileData
*child_data
= NULL
;
1850 hr
= IDirectXFileData_GetNextObject(filedata
, &child_obj
);
1851 if (FAILED(hr
)) return hr
;
1853 hr
= IDirectXFileObject_QueryInterface(child_obj
, &IID_IDirectXFileDataReference
, (void**)&child_ref
);
1854 if (SUCCEEDED(hr
)) {
1855 hr
= IDirectXFileDataReference_Resolve(child_ref
, &child_data
);
1856 IDirectXFileDataReference_Release(child_ref
);
1858 hr
= IDirectXFileObject_QueryInterface(child_obj
, &IID_IDirectXFileData
, (void**)&child_data
);
1860 IDirectXFileObject_Release(child_obj
);
1864 hr
= IDirectXFileData_GetType(child_data
, type
);
1866 IDirectXFileData_Release(child_data
);
1868 *child
= child_data
;
1874 static HRESULT
parse_texture_filename(IDirectXFileData
*filedata
, LPSTR
*filename_out
)
1880 char *filename
= NULL
;
1882 /* template TextureFilename {
1887 HeapFree(GetProcessHeap(), 0, *filename_out
);
1888 *filename_out
= NULL
;
1890 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
1891 if (FAILED(hr
)) return hr
;
1893 if (data_size
< sizeof(LPSTR
)) {
1894 WARN("truncated data (%u bytes)\n", data_size
);
1897 filename_in
= *(LPSTR
*)data
;
1899 filename
= HeapAlloc(GetProcessHeap(), 0, strlen(filename_in
) + 1);
1900 if (!filename
) return E_OUTOFMEMORY
;
1902 strcpy(filename
, filename_in
);
1903 *filename_out
= filename
;
1908 static HRESULT
parse_material(IDirectXFileData
*filedata
, D3DXMATERIAL
*material
)
1914 IDirectXFileData
*child
;
1916 material
->pTextureFilename
= NULL
;
1918 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
1919 if (FAILED(hr
)) return hr
;
1922 * template ColorRGBA {
1928 * template ColorRGB {
1933 * template Material {
1934 * ColorRGBA faceColor;
1936 * ColorRGB specularColor;
1937 * ColorRGB emissiveColor;
1941 if (data_size
!= sizeof(FLOAT
) * 11) {
1942 WARN("incorrect data size (%u bytes)\n", data_size
);
1946 memcpy(&material
->MatD3D
.Diffuse
, data
, sizeof(D3DCOLORVALUE
));
1947 data
+= sizeof(D3DCOLORVALUE
);
1948 material
->MatD3D
.Power
= *(FLOAT
*)data
;
1949 data
+= sizeof(FLOAT
);
1950 memcpy(&material
->MatD3D
.Specular
, data
, sizeof(FLOAT
) * 3);
1951 material
->MatD3D
.Specular
.a
= 1.0f
;
1952 data
+= 3 * sizeof(FLOAT
);
1953 memcpy(&material
->MatD3D
.Emissive
, data
, sizeof(FLOAT
) * 3);
1954 material
->MatD3D
.Emissive
.a
= 1.0f
;
1955 material
->MatD3D
.Ambient
.r
= 0.0f
;
1956 material
->MatD3D
.Ambient
.g
= 0.0f
;
1957 material
->MatD3D
.Ambient
.b
= 0.0f
;
1958 material
->MatD3D
.Ambient
.a
= 1.0f
;
1960 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
1962 if (IsEqualGUID(type
, &TID_D3DRMTextureFilename
)) {
1963 hr
= parse_texture_filename(child
, &material
->pTextureFilename
);
1964 if (FAILED(hr
)) break;
1967 return hr
== DXFILEERR_NOMOREOBJECTS
? D3D_OK
: hr
;
1970 static void destroy_materials(struct mesh_data
*mesh
)
1973 for (i
= 0; i
< mesh
->num_materials
; i
++)
1974 HeapFree(GetProcessHeap(), 0, mesh
->materials
[i
].pTextureFilename
);
1975 HeapFree(GetProcessHeap(), 0, mesh
->materials
);
1976 HeapFree(GetProcessHeap(), 0, mesh
->material_indices
);
1977 mesh
->num_materials
= 0;
1978 mesh
->materials
= NULL
;
1979 mesh
->material_indices
= NULL
;
1982 static HRESULT
parse_material_list(IDirectXFileData
*filedata
, struct mesh_data
*mesh
)
1986 DWORD
*data
, *in_ptr
;
1988 IDirectXFileData
*child
;
1989 DWORD num_materials
;
1992 destroy_materials(mesh
);
1994 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
1995 if (FAILED(hr
)) return hr
;
1997 /* template MeshMaterialList {
1999 * DWORD nFaceIndexes;
2000 * array DWORD faceIndexes[nFaceIndexes];
2007 if (data_size
< sizeof(DWORD
))
2008 goto truncated_data_error
;
2009 num_materials
= *in_ptr
++;
2013 if (data_size
< 2 * sizeof(DWORD
))
2014 goto truncated_data_error
;
2015 if (*in_ptr
++ != mesh
->num_poly_faces
) {
2016 WARN("number of material face indices (%u) doesn't match number of faces (%u)\n",
2017 *(in_ptr
- 1), mesh
->num_poly_faces
);
2020 if (data_size
< 2 * sizeof(DWORD
) + mesh
->num_poly_faces
* sizeof(DWORD
))
2021 goto truncated_data_error
;
2022 for (i
= 0; i
< mesh
->num_poly_faces
; i
++) {
2023 if (*in_ptr
++ >= num_materials
) {
2024 WARN("face %u: reference to undefined material %u (only %u materials)\n",
2025 i
, *(in_ptr
- 1), num_materials
);
2030 mesh
->materials
= HeapAlloc(GetProcessHeap(), 0, num_materials
* sizeof(*mesh
->materials
));
2031 mesh
->material_indices
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_poly_faces
* sizeof(*mesh
->material_indices
));
2032 if (!mesh
->materials
|| !mesh
->material_indices
)
2033 return E_OUTOFMEMORY
;
2034 memcpy(mesh
->material_indices
, data
+ 2, mesh
->num_poly_faces
* sizeof(DWORD
));
2036 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
2038 if (IsEqualGUID(type
, &TID_D3DRMMaterial
)) {
2039 if (mesh
->num_materials
>= num_materials
) {
2040 WARN("more materials defined than declared\n");
2043 hr
= parse_material(child
, &mesh
->materials
[mesh
->num_materials
++]);
2044 if (FAILED(hr
)) break;
2047 if (hr
!= DXFILEERR_NOMOREOBJECTS
)
2049 if (num_materials
!= mesh
->num_materials
) {
2050 WARN("only %u of %u materials defined\n", num_materials
, mesh
->num_materials
);
2055 truncated_data_error
:
2056 WARN("truncated data (%u bytes)\n", data_size
);
2060 static HRESULT
parse_texture_coords(IDirectXFileData
*filedata
, struct mesh_data
*mesh
)
2066 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2067 mesh
->tex_coords
= NULL
;
2069 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2070 if (FAILED(hr
)) return hr
;
2072 /* template Coords2d {
2076 * template MeshTextureCoords {
2077 * DWORD nTextureCoords;
2078 * array Coords2d textureCoords[nTextureCoords];
2082 if (data_size
< sizeof(DWORD
))
2083 goto truncated_data_error
;
2084 if (*(DWORD
*)data
!= mesh
->num_vertices
) {
2085 WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2086 *(DWORD
*)data
, mesh
->num_vertices
);
2089 data
+= sizeof(DWORD
);
2090 if (data_size
< sizeof(DWORD
) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
))
2091 goto truncated_data_error
;
2093 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2094 if (!mesh
->tex_coords
) return E_OUTOFMEMORY
;
2095 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2097 mesh
->fvf
|= D3DFVF_TEX1
;
2100 truncated_data_error
:
2101 WARN("truncated data (%u bytes)\n", data_size
);
2105 static HRESULT
parse_vertex_colors(IDirectXFileData
*filedata
, struct mesh_data
*mesh
)
2113 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2114 mesh
->vertex_colors
= NULL
;
2116 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2117 if (FAILED(hr
)) return hr
;
2119 /* template IndexedColor {
2121 * ColorRGBA indexColor;
2123 * template MeshVertexColors {
2124 * DWORD nVertexColors;
2125 * array IndexedColor vertexColors[nVertexColors];
2129 if (data_size
< sizeof(DWORD
))
2130 goto truncated_data_error
;
2131 num_colors
= *(DWORD
*)data
;
2132 data
+= sizeof(DWORD
);
2133 if (data_size
< sizeof(DWORD
) + num_colors
* (sizeof(DWORD
) + sizeof(D3DCOLORVALUE
)))
2134 goto truncated_data_error
;
2136 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(DWORD
));
2137 if (!mesh
->vertex_colors
)
2138 return E_OUTOFMEMORY
;
2140 for (i
= 0; i
< mesh
->num_vertices
; i
++)
2141 mesh
->vertex_colors
[i
] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2142 for (i
= 0; i
< num_colors
; i
++)
2144 D3DCOLORVALUE color
;
2145 DWORD index
= *(DWORD
*)data
;
2146 data
+= sizeof(DWORD
);
2147 if (index
>= mesh
->num_vertices
) {
2148 WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2149 i
, index
, mesh
->num_vertices
);
2152 memcpy(&color
, data
, sizeof(color
));
2153 data
+= sizeof(color
);
2154 color
.r
= fminf(1.0f
, fmaxf(0.0f
, color
.r
));
2155 color
.g
= fminf(1.0f
, fmaxf(0.0f
, color
.g
));
2156 color
.b
= fminf(1.0f
, fmaxf(0.0f
, color
.b
));
2157 color
.a
= fminf(1.0f
, fmaxf(0.0f
, color
.a
));
2158 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
2159 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
2160 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
2161 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
2164 mesh
->fvf
|= D3DFVF_DIFFUSE
;
2167 truncated_data_error
:
2168 WARN("truncated data (%u bytes)\n", data_size
);
2172 static HRESULT
parse_normals(IDirectXFileData
*filedata
, struct mesh_data
*mesh
)
2177 DWORD
*index_out_ptr
;
2179 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
2181 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
2182 mesh
->num_normals
= 0;
2183 mesh
->normals
= NULL
;
2184 mesh
->normal_indices
= NULL
;
2185 mesh
->fvf
|= D3DFVF_NORMAL
;
2187 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2188 if (FAILED(hr
)) return hr
;
2190 /* template Vector {
2195 * template MeshFace {
2196 * DWORD nFaceVertexIndices;
2197 * array DWORD faceVertexIndices[nFaceVertexIndices];
2199 * template MeshNormals {
2201 * array Vector normals[nNormals];
2202 * DWORD nFaceNormals;
2203 * array MeshFace faceNormals[nFaceNormals];
2207 if (data_size
< sizeof(DWORD
) * 2)
2208 goto truncated_data_error
;
2209 mesh
->num_normals
= *(DWORD
*)data
;
2210 data
+= sizeof(DWORD
);
2211 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
2212 num_face_indices
* sizeof(DWORD
))
2213 goto truncated_data_error
;
2215 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
2216 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
2217 if (!mesh
->normals
|| !mesh
->normal_indices
)
2218 return E_OUTOFMEMORY
;
2220 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
2221 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
2222 for (i
= 0; i
< mesh
->num_normals
; i
++)
2223 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
2225 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
2226 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
2227 *(DWORD
*)data
, mesh
->num_poly_faces
);
2230 data
+= sizeof(DWORD
);
2231 index_out_ptr
= mesh
->normal_indices
;
2232 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
2235 DWORD count
= *(DWORD
*)data
;
2236 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
2237 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
2238 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
2241 data
+= sizeof(DWORD
);
2243 for (j
= 0; j
< count
; j
++) {
2244 DWORD normal_index
= *(DWORD
*)data
;
2245 if (normal_index
>= mesh
->num_normals
) {
2246 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
2247 i
, j
, normal_index
, mesh
->num_normals
);
2250 *index_out_ptr
++ = normal_index
;
2251 data
+= sizeof(DWORD
);
2256 truncated_data_error
:
2257 WARN("truncated data (%u bytes)\n", data_size
);
2261 /* for provide_flags parameters */
2262 #define PROVIDE_MATERIALS 0x1
2263 #define PROVIDE_SKININFO 0x2
2264 #define PROVIDE_ADJACENCY 0x4
2266 static HRESULT
parse_mesh(IDirectXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
2270 BYTE
*data
, *in_ptr
;
2271 DWORD
*index_out_ptr
;
2273 IDirectXFileData
*child
;
2279 * array Vector vertices[nVertices];
2281 * array MeshFace faces[nFaces];
2286 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2287 if (FAILED(hr
)) return hr
;
2290 if (data_size
< sizeof(DWORD
) * 2)
2291 goto truncated_data_error
;
2292 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
2293 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
))
2294 goto truncated_data_error
;
2295 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
2297 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
2298 in_ptr
+= sizeof(DWORD
);
2300 mesh_data
->num_tri_faces
= 0;
2301 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
2303 DWORD num_poly_vertices
;
2306 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
))
2307 goto truncated_data_error
;
2308 num_poly_vertices
= *(DWORD
*)in_ptr
;
2309 in_ptr
+= sizeof(DWORD
);
2310 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
))
2311 goto truncated_data_error
;
2312 if (num_poly_vertices
< 3) {
2313 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
2316 for (j
= 0; j
< num_poly_vertices
; j
++) {
2317 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
2318 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
2319 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
2322 in_ptr
+= sizeof(DWORD
);
2324 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
2327 mesh_data
->fvf
= D3DFVF_XYZ
;
2329 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
2330 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
2331 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
2332 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
2333 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
2334 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
2335 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
)
2336 return E_OUTOFMEMORY
;
2338 in_ptr
= data
+ sizeof(DWORD
);
2339 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
2340 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
2342 index_out_ptr
= mesh_data
->indices
;
2343 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
2347 count
= *(DWORD
*)in_ptr
;
2348 in_ptr
+= sizeof(DWORD
);
2349 mesh_data
->num_tri_per_face
[i
] = count
- 2;
2352 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
2353 in_ptr
+= sizeof(DWORD
);
2357 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
2359 if (IsEqualGUID(type
, &TID_D3DRMMeshNormals
)) {
2360 hr
= parse_normals(child
, mesh_data
);
2361 } else if (IsEqualGUID(type
, &TID_D3DRMMeshVertexColors
)) {
2362 hr
= parse_vertex_colors(child
, mesh_data
);
2363 } else if (IsEqualGUID(type
, &TID_D3DRMMeshTextureCoords
)) {
2364 hr
= parse_texture_coords(child
, mesh_data
);
2365 } else if (IsEqualGUID(type
, &TID_D3DRMMeshMaterialList
) &&
2366 (provide_flags
& PROVIDE_MATERIALS
))
2368 hr
= parse_material_list(child
, mesh_data
);
2369 } else if (provide_flags
& PROVIDE_SKININFO
) {
2370 if (IsEqualGUID(type
, &DXFILEOBJ_XSkinMeshHeader
)) {
2371 FIXME("Skin mesh loading not implemented.\n");
2373 } else if (IsEqualGUID(type
, &DXFILEOBJ_SkinWeights
)) {
2374 /* ignored without XSkinMeshHeader */
2380 return hr
== DXFILEERR_NOMOREOBJECTS
? D3D_OK
: hr
;
2381 truncated_data_error
:
2382 WARN("truncated data (%u bytes)\n", data_size
);
2386 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
2387 ID3DXBuffer
**effects
)
2390 D3DXEFFECTINSTANCE
*effect_ptr
;
2392 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
2393 static const struct {
2394 const char *param_name
;
2398 } material_effects
[] = {
2399 #define EFFECT_TABLE_ENTRY(str, field) \
2400 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
2401 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
2402 EFFECT_TABLE_ENTRY("Power", Power
),
2403 EFFECT_TABLE_ENTRY("Specular", Specular
),
2404 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
2405 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
2406 #undef EFFECT_TABLE_ENTRY
2408 static const char texture_paramname
[] = "Texture0@Name";
2412 /* effects buffer layout:
2414 * D3DXEFFECTINSTANCE effects[num_materials];
2415 * for (effect in effects)
2417 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
2418 * for (default in defaults)
2420 * *default.pParamName;
2425 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
2426 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
2427 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
2428 buffer_size
+= material_effects
[i
].name_size
;
2429 buffer_size
+= material_effects
[i
].num_bytes
;
2431 buffer_size
*= num_materials
;
2432 for (i
= 0; i
< num_materials
; i
++) {
2433 if (material_ptr
[i
].pTextureFilename
) {
2434 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
2435 buffer_size
+= sizeof(texture_paramname
);
2436 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
2440 hr
= D3DXCreateBuffer(buffer_size
, effects
);
2441 if (FAILED(hr
)) return hr
;
2442 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
2443 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
2445 for (i
= 0; i
< num_materials
; i
++)
2448 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
2450 effect_ptr
->pDefaults
= defaults
;
2451 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
2452 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
2454 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
2456 defaults
->pParamName
= (LPSTR
)out_ptr
;
2457 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
2458 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
2459 defaults
->Type
= D3DXEDT_FLOATS
;
2460 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
2461 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
2462 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
2466 if (material_ptr
->pTextureFilename
) {
2467 defaults
->pParamName
= (LPSTR
)out_ptr
;
2468 strcpy(defaults
->pParamName
, texture_paramname
);
2469 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
2470 defaults
->Type
= D3DXEDT_STRING
;
2471 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
2472 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
2473 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
2478 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
2483 /* change to D3DXLoadSkinMeshFromXof when ID3DXFileData is implemented */
2484 static HRESULT
load_skin_mesh_from_xof(IDirectXFileData
*filedata
,
2486 LPDIRECT3DDEVICE9 device
,
2487 LPD3DXBUFFER
*adjacency_out
,
2488 LPD3DXBUFFER
*materials_out
,
2489 LPD3DXBUFFER
*effects_out
,
2490 DWORD
*num_materials_out
,
2491 LPD3DXSKININFO
*skin_info_out
,
2492 LPD3DXMESH
*mesh_out
)
2495 DWORD
*index_in_ptr
;
2496 struct mesh_data mesh_data
;
2497 DWORD total_vertices
;
2498 ID3DXMesh
*d3dxmesh
= NULL
;
2499 ID3DXBuffer
*adjacency
= NULL
;
2500 ID3DXBuffer
*materials
= NULL
;
2501 ID3DXBuffer
*effects
= NULL
;
2502 struct vertex_duplication
{
2505 } *duplications
= NULL
;
2507 void *vertices
= NULL
;
2508 void *indices
= NULL
;
2510 DWORD provide_flags
= 0;
2512 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
2514 if (num_materials_out
|| materials_out
|| effects_out
)
2515 provide_flags
|= PROVIDE_MATERIALS
;
2517 provide_flags
|= PROVIDE_SKININFO
;
2519 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
2520 if (FAILED(hr
)) goto cleanup
;
2522 total_vertices
= mesh_data
.num_vertices
;
2523 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
2524 /* duplicate vertices with multiple normals */
2525 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
2526 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
2527 if (!duplications
) {
2531 for (i
= 0; i
< total_vertices
; i
++)
2533 duplications
[i
].normal_index
= -1;
2534 list_init(&duplications
[i
].entry
);
2536 for (i
= 0; i
< num_face_indices
; i
++) {
2537 DWORD vertex_index
= mesh_data
.indices
[i
];
2538 DWORD normal_index
= mesh_data
.normal_indices
[i
];
2539 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
2541 if (dup_ptr
->normal_index
== -1) {
2542 dup_ptr
->normal_index
= normal_index
;
2544 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
2545 struct list
*dup_list
= &dup_ptr
->entry
;
2547 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
2548 if (new_normal
->x
== cur_normal
->x
&&
2549 new_normal
->y
== cur_normal
->y
&&
2550 new_normal
->z
== cur_normal
->z
)
2552 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
2554 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
2555 dup_ptr
= &duplications
[total_vertices
++];
2556 dup_ptr
->normal_index
= normal_index
;
2557 list_add_tail(dup_list
, &dup_ptr
->entry
);
2558 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
2561 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
2562 struct vertex_duplication
, entry
);
2569 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
2570 if (FAILED(hr
)) goto cleanup
;
2572 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, D3DLOCK_DISCARD
, &vertices
);
2573 if (FAILED(hr
)) goto cleanup
;
2576 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
2577 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
2578 out_ptr
+= sizeof(D3DXVECTOR3
);
2579 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
2580 if (duplications
[i
].normal_index
== -1)
2581 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
2583 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
2584 out_ptr
+= sizeof(D3DXVECTOR3
);
2586 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
2587 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
2588 out_ptr
+= sizeof(DWORD
);
2590 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
2591 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
2592 out_ptr
+= sizeof(D3DXVECTOR2
);
2595 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
2596 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
2598 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
2599 struct vertex_duplication
*dup_ptr
;
2600 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
2602 int j
= dup_ptr
- duplications
;
2603 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
2605 memcpy(dest_vertex
, out_ptr
, vertex_size
);
2606 dest_vertex
+= sizeof(D3DXVECTOR3
);
2607 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
2609 out_ptr
+= vertex_size
;
2612 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
2614 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, D3DLOCK_DISCARD
, (void**)&indices
);
2615 if (FAILED(hr
)) goto cleanup
;
2617 index_in_ptr
= mesh_data
.indices
;
2618 #define FILL_INDEX_BUFFER(indices_var) \
2619 for (i = 0; i < mesh_data.num_poly_faces; i++) \
2621 DWORD count = mesh_data.num_tri_per_face[i]; \
2622 WORD first_index = *index_in_ptr++; \
2624 *indices_var++ = first_index; \
2625 *indices_var++ = *index_in_ptr; \
2627 *indices_var++ = *index_in_ptr; \
2631 if (options
& D3DXMESH_32BIT
) {
2632 DWORD
*dword_indices
= indices
;
2633 FILL_INDEX_BUFFER(dword_indices
)
2635 WORD
*word_indices
= indices
;
2636 FILL_INDEX_BUFFER(word_indices
)
2638 #undef FILL_INDEX_BUFFER
2639 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
2641 if (mesh_data
.material_indices
) {
2642 DWORD
*attrib_buffer
= NULL
;
2643 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, D3DLOCK_DISCARD
, &attrib_buffer
);
2644 if (FAILED(hr
)) goto cleanup
;
2645 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
2647 DWORD count
= mesh_data
.num_tri_per_face
[i
];
2649 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
2651 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
2653 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
2654 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
2655 NULL
, NULL
, NULL
, NULL
);
2656 if (FAILED(hr
)) goto cleanup
;
2659 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
2660 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
2661 char *strings_out_ptr
;
2662 D3DXMATERIAL
*materials_ptr
;
2664 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
2665 if (mesh_data
.materials
[i
].pTextureFilename
)
2666 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
2669 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
2670 if (FAILED(hr
)) goto cleanup
;
2672 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
2673 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
2674 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
2675 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
2676 if (materials_ptr
[i
].pTextureFilename
) {
2677 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
2678 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
2679 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
2684 if (mesh_data
.num_materials
&& effects_out
) {
2685 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
2686 if (FAILED(hr
)) goto cleanup
;
2688 if (!materials_out
) {
2689 ID3DXBuffer_Release(materials
);
2694 if (adjacency_out
) {
2695 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
2696 if (FAILED(hr
)) goto cleanup
;
2697 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
2698 if (FAILED(hr
)) goto cleanup
;
2701 *mesh_out
= d3dxmesh
;
2702 if (adjacency_out
) *adjacency_out
= adjacency
;
2703 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
2704 if (materials_out
) *materials_out
= materials
;
2705 if (effects_out
) *effects_out
= effects
;
2706 if (skin_info_out
) *skin_info_out
= NULL
;
2711 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
2712 if (adjacency
) ID3DXBuffer_Release(adjacency
);
2713 if (materials
) ID3DXBuffer_Release(materials
);
2714 if (effects
) ID3DXBuffer_Release(effects
);
2716 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
2717 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
2718 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
2719 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
2720 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
2721 destroy_materials(&mesh_data
);
2722 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
2723 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
2724 HeapFree(GetProcessHeap(), 0, duplications
);
2728 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(LPCSTR filename
,
2730 LPDIRECT3DDEVICE9 device
,
2731 LPD3DXALLOCATEHIERARCHY alloc_hier
,
2732 LPD3DXLOADUSERDATA load_user_data
,
2733 LPD3DXFRAME
*frame_hierarchy
,
2734 LPD3DXANIMATIONCONTROLLER
*anim_controller
)
2740 TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_a(filename
), options
,
2741 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
2744 return D3DERR_INVALIDCALL
;
2746 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
2747 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2748 if (!filenameW
) return E_OUTOFMEMORY
;
2749 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
2751 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
2752 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
2753 HeapFree(GetProcessHeap(), 0, filenameW
);
2758 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(LPCWSTR filename
,
2760 LPDIRECT3DDEVICE9 device
,
2761 LPD3DXALLOCATEHIERARCHY alloc_hier
,
2762 LPD3DXLOADUSERDATA load_user_data
,
2763 LPD3DXFRAME
*frame_hierarchy
,
2764 LPD3DXANIMATIONCONTROLLER
*anim_controller
)
2770 TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_w(filename
), options
,
2771 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
2774 return D3DERR_INVALIDCALL
;
2776 hr
= map_view_of_file(filename
, &buffer
, &size
);
2778 return D3DXERR_INVALIDDATA
;
2780 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
2781 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
2783 UnmapViewOfFile(buffer
);
2788 static HRESULT
filedata_get_name(IDirectXFileData
*filedata
, char **name
)
2793 hr
= IDirectXFileData_GetName(filedata
, NULL
, &name_len
);
2794 if (FAILED(hr
)) return hr
;
2798 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
2799 if (!*name
) return E_OUTOFMEMORY
;
2801 hr
= IDirectXFileObject_GetName(filedata
, *name
, &name_len
);
2803 HeapFree(GetProcessHeap(), 0, name
);
2810 static HRESULT
load_mesh_container(IDirectXFileData
*filedata
,
2812 LPDIRECT3DDEVICE9 device
,
2813 LPD3DXALLOCATEHIERARCHY alloc_hier
,
2814 D3DXMESHCONTAINER
**mesh_container
)
2817 ID3DXBuffer
*adjacency
= NULL
;
2818 ID3DXBuffer
*materials
= NULL
;
2819 ID3DXBuffer
*effects
= NULL
;
2820 ID3DXSkinInfo
*skin_info
= NULL
;
2821 D3DXMESHDATA mesh_data
;
2822 DWORD num_materials
= 0;
2825 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
2826 mesh_data
.u
.pMesh
= NULL
;
2828 hr
= load_skin_mesh_from_xof(filedata
, options
, device
,
2829 &adjacency
, &materials
, &effects
, &num_materials
,
2830 &skin_info
, &mesh_data
.u
.pMesh
);
2831 if (FAILED(hr
)) return hr
;
2833 hr
= filedata_get_name(filedata
, &name
);
2834 if (FAILED(hr
)) goto cleanup
;
2836 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
2837 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
2838 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
2840 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
2841 skin_info
, mesh_container
);
2844 if (materials
) ID3DXBuffer_Release(materials
);
2845 if (effects
) ID3DXBuffer_Release(effects
);
2846 if (adjacency
) ID3DXBuffer_Release(adjacency
);
2847 if (skin_info
) IUnknown_Release(skin_info
);
2848 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
2849 HeapFree(GetProcessHeap(), 0, name
);
2853 static HRESULT
parse_transform_matrix(IDirectXFileData
*filedata
, D3DXMATRIX
*transform
)
2859 /* template Matrix4x4 {
2860 * array FLOAT matrix[16];
2862 * template FrameTransformMatrix {
2863 * Matrix4x4 frameMatrix;
2867 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2868 if (FAILED(hr
)) return hr
;
2870 if (data_size
!= sizeof(D3DXMATRIX
)) {
2871 WARN("incorrect data size (%u bytes)\n", data_size
);
2875 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
2880 static HRESULT
load_frame(IDirectXFileData
*filedata
,
2882 LPDIRECT3DDEVICE9 device
,
2883 LPD3DXALLOCATEHIERARCHY alloc_hier
,
2884 D3DXFRAME
**frame_out
)
2888 IDirectXFileData
*child
;
2890 D3DXFRAME
*frame
= NULL
;
2891 D3DXMESHCONTAINER
**next_container
;
2892 D3DXFRAME
**next_child
;
2894 hr
= filedata_get_name(filedata
, &name
);
2895 if (FAILED(hr
)) return hr
;
2897 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
2898 HeapFree(GetProcessHeap(), 0, name
);
2899 if (FAILED(hr
)) return E_FAIL
;
2902 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
2903 next_child
= &frame
->pFrameFirstChild
;
2904 next_container
= &frame
->pMeshContainer
;
2906 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
2908 if (IsEqualGUID(type
, &TID_D3DRMMesh
)) {
2909 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
2911 next_container
= &(*next_container
)->pNextMeshContainer
;
2912 } else if (IsEqualGUID(type
, &TID_D3DRMFrameTransformMatrix
)) {
2913 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
2914 } else if (IsEqualGUID(type
, &TID_D3DRMFrame
)) {
2915 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
2917 next_child
= &(*next_child
)->pFrameSibling
;
2919 if (FAILED(hr
)) break;
2921 if (hr
== DXFILEERR_NOMOREOBJECTS
)
2927 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(LPCVOID memory
,
2930 LPDIRECT3DDEVICE9 device
,
2931 LPD3DXALLOCATEHIERARCHY alloc_hier
,
2932 LPD3DXLOADUSERDATA load_user_data
,
2933 LPD3DXFRAME
*frame_hierarchy
,
2934 LPD3DXANIMATIONCONTROLLER
*anim_controller
)
2937 IDirectXFile
*dxfile
= NULL
;
2938 IDirectXFileEnumObject
*enumobj
= NULL
;
2939 IDirectXFileData
*filedata
= NULL
;
2940 DXFILELOADMEMORY source
;
2941 D3DXFRAME
*first_frame
= NULL
;
2942 D3DXFRAME
**next_frame
= &first_frame
;
2944 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
2945 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
2947 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
2948 return D3DERR_INVALIDCALL
;
2949 if (load_user_data
|| anim_controller
) {
2951 FIXME("Loading user data not implemented\n");
2952 if (anim_controller
)
2953 FIXME("Animation controller creation not implemented\n");
2957 hr
= DirectXFileCreate(&dxfile
);
2958 if (FAILED(hr
)) goto cleanup
;
2960 hr
= IDirectXFile_RegisterTemplates(dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
2961 if (FAILED(hr
)) goto cleanup
;
2963 source
.lpMemory
= (void*)memory
;
2964 source
.dSize
= memory_size
;
2965 hr
= IDirectXFile_CreateEnumObject(dxfile
, &source
, DXFILELOAD_FROMMEMORY
, &enumobj
);
2966 if (FAILED(hr
)) goto cleanup
;
2968 while (SUCCEEDED(hr
= IDirectXFileEnumObject_GetNextDataObject(enumobj
, &filedata
)))
2970 const GUID
*guid
= NULL
;
2972 hr
= IDirectXFileData_GetType(filedata
, &guid
);
2973 if (SUCCEEDED(hr
)) {
2974 if (IsEqualGUID(guid
, &TID_D3DRMMesh
)) {
2975 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
2981 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
2983 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
2984 if (FAILED(hr
)) goto cleanup
;
2985 } else if (IsEqualGUID(guid
, &TID_D3DRMFrame
)) {
2986 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
2987 if (FAILED(hr
)) goto cleanup
;
2990 next_frame
= &(*next_frame
)->pFrameSibling
;
2993 IDirectXFileData_Release(filedata
);
2998 if (hr
!= DXFILEERR_NOMOREOBJECTS
)
3003 } else if (first_frame
->pFrameSibling
) {
3004 D3DXFRAME
*root_frame
= NULL
;
3005 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
3010 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
3011 root_frame
->pFrameFirstChild
= first_frame
;
3012 *frame_hierarchy
= root_frame
;
3015 *frame_hierarchy
= first_frame
;
3020 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
3021 if (filedata
) IDirectXFileData_Release(filedata
);
3022 if (enumobj
) IDirectXFileEnumObject_Release(enumobj
);
3023 if (dxfile
) IDirectXFile_Release(dxfile
);
3027 HRESULT WINAPI
D3DXFrameDestroy(LPD3DXFRAME frame
, LPD3DXALLOCATEHIERARCHY alloc_hier
)
3032 TRACE("(%p, %p)\n", frame
, alloc_hier
);
3034 if (!frame
|| !alloc_hier
)
3035 return D3DERR_INVALIDCALL
;
3038 D3DXMESHCONTAINER
*container
;
3039 D3DXFRAME
*current_frame
;
3041 if (frame
->pFrameSibling
) {
3042 current_frame
= frame
->pFrameSibling
;
3043 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
3044 current_frame
->pFrameSibling
= NULL
;
3046 current_frame
= frame
;
3050 if (current_frame
->pFrameFirstChild
) {
3051 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
3052 if (FAILED(hr
)) return hr
;
3053 current_frame
->pFrameFirstChild
= NULL
;
3056 container
= current_frame
->pMeshContainer
;
3058 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
3059 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
3060 if (FAILED(hr
)) return hr
;
3061 container
= next_container
;
3063 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
3064 if (FAILED(hr
)) return hr
;
3069 HRESULT WINAPI
D3DXLoadMeshFromXA(LPCSTR filename
,
3071 LPDIRECT3DDEVICE9 device
,
3072 LPD3DXBUFFER
*adjacency
,
3073 LPD3DXBUFFER
*materials
,
3074 LPD3DXBUFFER
*effect_instances
,
3075 DWORD
*num_materials
,
3082 TRACE("(%s, %x, %p, %p, %p, %p, %p, %p)\n", debugstr_a(filename
), options
,
3083 device
, adjacency
, materials
, effect_instances
, num_materials
, mesh
);
3086 return D3DERR_INVALIDCALL
;
3088 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3089 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3090 if (!filenameW
) return E_OUTOFMEMORY
;
3091 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3093 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
3094 effect_instances
, num_materials
, mesh
);
3095 HeapFree(GetProcessHeap(), 0, filenameW
);
3100 HRESULT WINAPI
D3DXLoadMeshFromXW(LPCWSTR filename
,
3102 LPDIRECT3DDEVICE9 device
,
3103 LPD3DXBUFFER
*adjacency
,
3104 LPD3DXBUFFER
*materials
,
3105 LPD3DXBUFFER
*effect_instances
,
3106 DWORD
*num_materials
,
3113 TRACE("(%s, %x, %p, %p, %p, %p, %p, %p)\n", debugstr_w(filename
), options
,
3114 device
, adjacency
, materials
, effect_instances
, num_materials
, mesh
);
3117 return D3DERR_INVALIDCALL
;
3119 hr
= map_view_of_file(filename
, &buffer
, &size
);
3121 return D3DXERR_INVALIDDATA
;
3123 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
3124 materials
, effect_instances
, num_materials
, mesh
);
3126 UnmapViewOfFile(buffer
);
3131 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
,
3135 LPDIRECT3DDEVICE9 device
,
3136 LPD3DXBUFFER
*adjacency
,
3137 LPD3DXBUFFER
*materials
,
3138 LPD3DXBUFFER
*effect_instances
,
3139 DWORD
*num_materials
,
3147 TRACE("(%p, %s, %s, %x, %p, %p, %p, %p, %p, %p)\n",
3148 module
, debugstr_a(name
), debugstr_a(type
), options
, device
,
3149 adjacency
, materials
, effect_instances
, num_materials
, mesh
);
3151 resinfo
= FindResourceA(module
, name
, type
);
3152 if (!resinfo
) return D3DXERR_INVALIDDATA
;
3154 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
3155 if (!FAILED(hr
)) return D3DXERR_INVALIDDATA
;
3157 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
3158 materials
, effect_instances
, num_materials
, mesh
);
3161 struct mesh_container
3165 ID3DXBuffer
*adjacency
;
3166 ID3DXBuffer
*materials
;
3167 ID3DXBuffer
*effects
;
3168 DWORD num_materials
;
3169 D3DXMATRIX transform
;
3172 static HRESULT
parse_frame(IDirectXFileData
*filedata
,
3174 LPDIRECT3DDEVICE9 device
,
3175 const D3DXMATRIX
*parent_transform
,
3176 struct list
*container_list
,
3177 DWORD provide_flags
)
3180 D3DXMATRIX transform
= *parent_transform
;
3181 IDirectXFileData
*child
;
3184 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
3186 if (IsEqualGUID(type
, &TID_D3DRMMesh
)) {
3187 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
3192 list_add_tail(container_list
, &container
->entry
);
3193 container
->transform
= transform
;
3195 hr
= load_skin_mesh_from_xof(child
, options
, device
,
3196 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
3197 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
3198 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
3199 } else if (IsEqualGUID(type
, &TID_D3DRMFrameTransformMatrix
)) {
3200 D3DXMATRIX new_transform
;
3201 hr
= parse_transform_matrix(child
, &new_transform
);
3202 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
3203 } else if (IsEqualGUID(type
, &TID_D3DRMFrame
)) {
3204 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
3206 if (FAILED(hr
)) break;
3208 return hr
== DXFILEERR_NOMOREOBJECTS
? D3D_OK
: hr
;
3211 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(LPCVOID memory
,
3214 LPDIRECT3DDEVICE9 device
,
3215 LPD3DXBUFFER
*adjacency_out
,
3216 LPD3DXBUFFER
*materials_out
,
3217 LPD3DXBUFFER
*effects_out
,
3218 DWORD
*num_materials_out
,
3219 LPD3DXMESH
*mesh_out
)
3222 IDirectXFile
*dxfile
= NULL
;
3223 IDirectXFileEnumObject
*enumobj
= NULL
;
3224 IDirectXFileData
*filedata
= NULL
;
3225 DXFILELOADMEMORY source
;
3226 ID3DXBuffer
*materials
= NULL
;
3227 ID3DXBuffer
*effects
= NULL
;
3228 ID3DXBuffer
*adjacency
= NULL
;
3229 struct list container_list
= LIST_INIT(container_list
);
3230 struct mesh_container
*container_ptr
, *next_container_ptr
;
3231 DWORD num_materials
;
3232 DWORD num_faces
, num_vertices
;
3233 D3DXMATRIX identity
;
3235 DWORD provide_flags
= 0;
3237 ID3DXMesh
*concat_mesh
= NULL
;
3238 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
3239 BYTE
*concat_vertices
= NULL
;
3240 void *concat_indices
= NULL
;
3242 DWORD concat_vertex_size
;
3244 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3245 device
, adjacency_out
, materials_out
, effects_out
, num_materials_out
, mesh_out
);
3247 if (!memory
|| !memory_size
|| !device
|| !mesh_out
)
3248 return D3DERR_INVALIDCALL
;
3250 hr
= DirectXFileCreate(&dxfile
);
3251 if (FAILED(hr
)) goto cleanup
;
3253 hr
= IDirectXFile_RegisterTemplates(dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3254 if (FAILED(hr
)) goto cleanup
;
3256 source
.lpMemory
= (void*)memory
;
3257 source
.dSize
= memory_size
;
3258 hr
= IDirectXFile_CreateEnumObject(dxfile
, &source
, DXFILELOAD_FROMMEMORY
, &enumobj
);
3259 if (FAILED(hr
)) goto cleanup
;
3261 D3DXMatrixIdentity(&identity
);
3262 if (adjacency_out
) provide_flags
|= PROVIDE_ADJACENCY
;
3263 if (materials_out
|| effects_out
) provide_flags
|= PROVIDE_MATERIALS
;
3265 while (SUCCEEDED(hr
= IDirectXFileEnumObject_GetNextDataObject(enumobj
, &filedata
)))
3267 const GUID
*guid
= NULL
;
3269 hr
= IDirectXFileData_GetType(filedata
, &guid
);
3270 if (SUCCEEDED(hr
)) {
3271 if (IsEqualGUID(guid
, &TID_D3DRMMesh
)) {
3272 container_ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container_ptr
));
3273 if (!container_ptr
) {
3277 list_add_tail(&container_list
, &container_ptr
->entry
);
3278 D3DXMatrixIdentity(&container_ptr
->transform
);
3280 hr
= load_skin_mesh_from_xof(filedata
, options
, device
,
3281 (provide_flags
& PROVIDE_ADJACENCY
) ? &container_ptr
->adjacency
: NULL
,
3282 (provide_flags
& PROVIDE_MATERIALS
) ? &container_ptr
->materials
: NULL
,
3283 NULL
, &container_ptr
->num_materials
, NULL
, &container_ptr
->mesh
);
3284 } else if (IsEqualGUID(guid
, &TID_D3DRMFrame
)) {
3285 hr
= parse_frame(filedata
, options
, device
, &identity
, &container_list
, provide_flags
);
3287 if (FAILED(hr
)) goto cleanup
;
3289 IDirectXFileData_Release(filedata
);
3294 if (hr
!= DXFILEERR_NOMOREOBJECTS
)
3297 IDirectXFileEnumObject_Release(enumobj
);
3299 IDirectXFile_Release(dxfile
);
3302 if (list_empty(&container_list
)) {
3311 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3313 ID3DXMesh
*mesh
= container_ptr
->mesh
;
3314 fvf
|= mesh
->lpVtbl
->GetFVF(mesh
);
3315 num_faces
+= mesh
->lpVtbl
->GetNumFaces(mesh
);
3316 num_vertices
+= mesh
->lpVtbl
->GetNumVertices(mesh
);
3317 num_materials
+= container_ptr
->num_materials
;
3320 hr
= D3DXCreateMeshFVF(num_faces
, num_vertices
, options
, fvf
, device
, &concat_mesh
);
3321 if (FAILED(hr
)) goto cleanup
;
3323 hr
= concat_mesh
->lpVtbl
->GetDeclaration(concat_mesh
, concat_decl
);
3324 if (FAILED(hr
)) goto cleanup
;
3326 concat_vertex_size
= D3DXGetDeclVertexSize(concat_decl
, 0);
3328 hr
= concat_mesh
->lpVtbl
->LockVertexBuffer(concat_mesh
, D3DLOCK_DISCARD
, (void**)&concat_vertices
);
3329 if (FAILED(hr
)) goto cleanup
;
3331 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3333 D3DVERTEXELEMENT9 mesh_decl
[MAX_FVF_DECL_SIZE
];
3334 ID3DXMesh
*mesh
= container_ptr
->mesh
;
3335 DWORD num_mesh_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
3336 DWORD mesh_vertex_size
;
3337 const BYTE
*mesh_vertices
;
3339 hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, mesh_decl
);
3340 if (FAILED(hr
)) goto cleanup
;
3342 mesh_vertex_size
= D3DXGetDeclVertexSize(mesh_decl
, 0);
3344 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_vertices
);
3345 if (FAILED(hr
)) goto cleanup
;
3347 for (i
= 0; i
< num_mesh_vertices
; i
++) {
3351 D3DXVec3TransformCoord((D3DXVECTOR3
*)concat_vertices
,
3352 (D3DXVECTOR3
*)mesh_vertices
,
3353 &container_ptr
->transform
);
3354 for (j
= 1; concat_decl
[j
].Stream
!= 0xff; j
++)
3356 if (concat_decl
[j
].Usage
== mesh_decl
[k
].Usage
&&
3357 concat_decl
[j
].UsageIndex
== mesh_decl
[k
].UsageIndex
)
3359 if (concat_decl
[j
].Usage
== D3DDECLUSAGE_NORMAL
) {
3360 D3DXVec3TransformCoord((D3DXVECTOR3
*)(concat_vertices
+ concat_decl
[j
].Offset
),
3361 (D3DXVECTOR3
*)(mesh_vertices
+ mesh_decl
[k
].Offset
),
3362 &container_ptr
->transform
);
3364 memcpy(concat_vertices
+ concat_decl
[j
].Offset
,
3365 mesh_vertices
+ mesh_decl
[k
].Offset
,
3366 d3dx_decltype_size
[mesh_decl
[k
].Type
]);
3371 mesh_vertices
+= mesh_vertex_size
;
3372 concat_vertices
+= concat_vertex_size
;
3375 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
3378 concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
3379 concat_vertices
= NULL
;
3381 hr
= concat_mesh
->lpVtbl
->LockIndexBuffer(concat_mesh
, D3DLOCK_DISCARD
, &concat_indices
);
3382 if (FAILED(hr
)) goto cleanup
;
3385 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3387 ID3DXMesh
*mesh
= container_ptr
->mesh
;
3388 const void *mesh_indices
;
3389 DWORD num_mesh_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
3392 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_indices
);
3393 if (FAILED(hr
)) goto cleanup
;
3395 if (options
& D3DXMESH_32BIT
) {
3396 DWORD
*dest
= concat_indices
;
3397 const DWORD
*src
= mesh_indices
;
3398 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
3399 *dest
++ = index_offset
+ *src
++;
3400 concat_indices
= dest
;
3402 WORD
*dest
= concat_indices
;
3403 const WORD
*src
= mesh_indices
;
3404 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
3405 *dest
++ = index_offset
+ *src
++;
3406 concat_indices
= dest
;
3408 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
3410 index_offset
+= num_mesh_faces
* 3;
3413 concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
3414 concat_indices
= NULL
;
3416 if (num_materials
) {
3417 DWORD
*concat_attrib_buffer
= NULL
;
3420 hr
= concat_mesh
->lpVtbl
->LockAttributeBuffer(concat_mesh
, D3DLOCK_DISCARD
, &concat_attrib_buffer
);
3421 if (FAILED(hr
)) goto cleanup
;
3423 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3425 ID3DXMesh
*mesh
= container_ptr
->mesh
;
3426 const DWORD
*mesh_attrib_buffer
= NULL
;
3427 DWORD count
= mesh
->lpVtbl
->GetNumFaces(mesh
);
3429 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, D3DLOCK_READONLY
, (DWORD
**)&mesh_attrib_buffer
);
3431 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
3436 *concat_attrib_buffer
++ = offset
+ *mesh_attrib_buffer
++;
3438 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
3439 offset
+= container_ptr
->num_materials
;
3441 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
3444 if (materials_out
|| effects_out
) {
3445 D3DXMATERIAL
*out_ptr
;
3446 if (!num_materials
) {
3447 /* create default material */
3448 hr
= D3DXCreateBuffer(sizeof(D3DXMATERIAL
), &materials
);
3449 if (FAILED(hr
)) goto cleanup
;
3451 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3452 out_ptr
->MatD3D
.Diffuse
.r
= 0.5f
;
3453 out_ptr
->MatD3D
.Diffuse
.g
= 0.5f
;
3454 out_ptr
->MatD3D
.Diffuse
.b
= 0.5f
;
3455 out_ptr
->MatD3D
.Specular
.r
= 0.5f
;
3456 out_ptr
->MatD3D
.Specular
.g
= 0.5f
;
3457 out_ptr
->MatD3D
.Specular
.b
= 0.5f
;
3458 /* D3DXCreateBuffer initializes the rest to zero */
3460 DWORD buffer_size
= num_materials
* sizeof(D3DXMATERIAL
);
3461 char *strings_out_ptr
;
3463 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3465 if (container_ptr
->materials
) {
3466 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
3467 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
3469 if (in_ptr
->pTextureFilename
)
3470 buffer_size
+= strlen(in_ptr
->pTextureFilename
) + 1;
3476 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3477 if (FAILED(hr
)) goto cleanup
;
3478 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3479 strings_out_ptr
= (char*)(out_ptr
+ num_materials
);
3481 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3483 if (container_ptr
->materials
) {
3484 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
3485 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
3487 out_ptr
->MatD3D
= in_ptr
->MatD3D
;
3488 if (in_ptr
->pTextureFilename
) {
3489 out_ptr
->pTextureFilename
= strings_out_ptr
;
3490 strcpy(out_ptr
->pTextureFilename
, in_ptr
->pTextureFilename
);
3491 strings_out_ptr
+= strlen(in_ptr
->pTextureFilename
) + 1;
3504 generate_effects(materials
, num_materials
, &effects
);
3505 if (!materials_out
) {
3506 ID3DXBuffer_Release(materials
);
3511 if (adjacency_out
) {
3512 if (!list_next(&container_list
, list_head(&container_list
))) {
3513 container_ptr
= LIST_ENTRY(list_head(&container_list
), struct mesh_container
, entry
);
3514 adjacency
= container_ptr
->adjacency
;
3515 container_ptr
->adjacency
= NULL
;
3520 hr
= D3DXCreateBuffer(num_faces
* 3 * sizeof(DWORD
), &adjacency
);
3521 if (FAILED(hr
)) goto cleanup
;
3523 out_ptr
= ID3DXBuffer_GetBufferPointer(adjacency
);
3524 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
3526 DWORD
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->adjacency
);
3527 int count
= 3 * container_ptr
->mesh
->lpVtbl
->GetNumFaces(container_ptr
->mesh
);
3529 for (i
= 0; i
< count
; i
++)
3530 *out_ptr
++ = offset
+ *in_ptr
++;
3537 *mesh_out
= concat_mesh
;
3538 if (adjacency_out
) *adjacency_out
= adjacency
;
3539 if (materials_out
) *materials_out
= materials
;
3540 if (effects_out
) *effects_out
= effects
;
3541 if (num_materials_out
) *num_materials_out
= num_materials
;
3545 if (concat_indices
) concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
3546 if (concat_vertices
) concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
3547 if (filedata
) IDirectXFileData_Release(filedata
);
3548 if (enumobj
) IDirectXFileEnumObject_Release(enumobj
);
3549 if (dxfile
) IDirectXFile_Release(dxfile
);
3551 if (concat_mesh
) IUnknown_Release(concat_mesh
);
3552 if (materials
) ID3DXBuffer_Release(materials
);
3553 if (effects
) ID3DXBuffer_Release(effects
);
3554 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3556 LIST_FOR_EACH_ENTRY_SAFE(container_ptr
, next_container_ptr
, &container_list
, struct mesh_container
, entry
)
3558 if (container_ptr
->mesh
) IUnknown_Release(container_ptr
->mesh
);
3559 if (container_ptr
->adjacency
) ID3DXBuffer_Release(container_ptr
->adjacency
);
3560 if (container_ptr
->materials
) ID3DXBuffer_Release(container_ptr
->materials
);
3561 if (container_ptr
->effects
) ID3DXBuffer_Release(container_ptr
->effects
);
3562 HeapFree(GetProcessHeap(), 0, container_ptr
);
3567 HRESULT WINAPI
D3DXCreateBox(LPDIRECT3DDEVICE9 device
, FLOAT width
, FLOAT height
,
3568 FLOAT depth
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
3570 FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device
, width
, height
, depth
, mesh
, adjacency
);
3577 D3DXVECTOR3 position
;
3581 typedef WORD face
[3];
3589 static void free_sincos_table(struct sincos_table
*sincos_table
)
3591 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
3592 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
3595 /* pre compute sine and cosine tables; caller must free */
3596 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
3601 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
3602 if (!sincos_table
->sin
)
3606 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
3607 if (!sincos_table
->cos
)
3609 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
3613 angle
= angle_start
;
3614 for (i
= 0; i
< n
; i
++)
3616 sincos_table
->sin
[i
] = sin(angle
);
3617 sincos_table
->cos
[i
] = cos(angle
);
3618 angle
+= angle_step
;
3624 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
3626 return stack
*slices
+slice
+1;
3629 HRESULT WINAPI
D3DXCreateSphere(LPDIRECT3DDEVICE9 device
, FLOAT radius
, UINT slices
,
3630 UINT stacks
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
3632 DWORD number_of_vertices
, number_of_faces
;
3635 struct vertex
*vertices
;
3637 float phi_step
, phi_start
;
3638 struct sincos_table phi
;
3639 float theta_step
, theta
, sin_theta
, cos_theta
;
3643 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
3645 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
3647 return D3DERR_INVALIDCALL
;
3652 FIXME("Case of adjacency != NULL not implemented.\n");
3656 number_of_vertices
= 2 + slices
* (stacks
-1);
3657 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
3659 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
3660 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
3666 hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
3669 sphere
->lpVtbl
->Release(sphere
);
3673 hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
3676 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
3677 sphere
->lpVtbl
->Release(sphere
);
3681 /* phi = angle on xz plane wrt z axis */
3682 phi_step
= -2 * M_PI
/ slices
;
3683 phi_start
= M_PI
/ 2;
3685 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
3687 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
3688 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
3689 sphere
->lpVtbl
->Release(sphere
);
3690 return E_OUTOFMEMORY
;
3693 /* theta = angle on xy plane wrt x axis */
3694 theta_step
= M_PI
/ stacks
;
3701 vertices
[vertex
].normal
.x
= 0.0f
;
3702 vertices
[vertex
].normal
.y
= 0.0f
;
3703 vertices
[vertex
].normal
.z
= 1.0f
;
3704 vertices
[vertex
].position
.x
= 0.0f
;
3705 vertices
[vertex
].position
.y
= 0.0f
;
3706 vertices
[vertex
].position
.z
= radius
;
3709 for (stack
= 0; stack
< stacks
- 1; stack
++)
3711 sin_theta
= sin(theta
);
3712 cos_theta
= cos(theta
);
3714 for (slice
= 0; slice
< slices
; slice
++)
3716 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
3717 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
3718 vertices
[vertex
].normal
.z
= cos_theta
;
3719 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
3720 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
3721 vertices
[vertex
].position
.z
= radius
* cos_theta
;
3728 /* top stack is triangle fan */
3730 faces
[face
][1] = slice
+ 1;
3731 faces
[face
][2] = slice
;
3736 /* stacks in between top and bottom are quad strips */
3737 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
3738 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
3739 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
3742 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
3743 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
3744 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
3750 theta
+= theta_step
;
3756 faces
[face
][2] = slice
;
3761 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
3762 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
3763 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
3766 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
3767 faces
[face
][1] = vertex_index(slices
, 0, stack
);
3768 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
3773 vertices
[vertex
].position
.x
= 0.0f
;
3774 vertices
[vertex
].position
.y
= 0.0f
;
3775 vertices
[vertex
].position
.z
= -radius
;
3776 vertices
[vertex
].normal
.x
= 0.0f
;
3777 vertices
[vertex
].normal
.y
= 0.0f
;
3778 vertices
[vertex
].normal
.z
= -1.0f
;
3780 /* bottom stack is triangle fan */
3781 for (slice
= 1; slice
< slices
; slice
++)
3783 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
3784 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
3785 faces
[face
][2] = vertex
;
3789 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
3790 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
3791 faces
[face
][2] = vertex
;
3793 free_sincos_table(&phi
);
3794 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
3795 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
3801 HRESULT WINAPI
D3DXCreateCylinder(LPDIRECT3DDEVICE9 device
, FLOAT radius1
, FLOAT radius2
, FLOAT length
, UINT slices
,
3802 UINT stacks
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
3804 DWORD number_of_vertices
, number_of_faces
;
3806 ID3DXMesh
*cylinder
;
3807 struct vertex
*vertices
;
3809 float theta_step
, theta_start
;
3810 struct sincos_table theta
;
3811 float delta_radius
, radius
, radius_step
;
3812 float z
, z_step
, z_normal
;
3816 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
3818 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
3820 return D3DERR_INVALIDCALL
;
3825 FIXME("Case of adjacency != NULL not implemented.\n");
3829 number_of_vertices
= 2 + (slices
* (3 + stacks
));
3830 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
3832 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
3833 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
3839 hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
3842 cylinder
->lpVtbl
->Release(cylinder
);
3846 hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
3849 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
3850 cylinder
->lpVtbl
->Release(cylinder
);
3854 /* theta = angle on xy plane wrt x axis */
3855 theta_step
= -2 * M_PI
/ slices
;
3856 theta_start
= M_PI
/ 2;
3858 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
3860 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
3861 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
3862 cylinder
->lpVtbl
->Release(cylinder
);
3863 return E_OUTOFMEMORY
;
3869 delta_radius
= radius1
- radius2
;
3871 radius_step
= delta_radius
/ stacks
;
3874 z_step
= length
/ stacks
;
3875 z_normal
= delta_radius
/ length
;
3876 if (isnan(z_normal
))
3881 vertices
[vertex
].normal
.x
= 0.0f
;
3882 vertices
[vertex
].normal
.y
= 0.0f
;
3883 vertices
[vertex
].normal
.z
= -1.0f
;
3884 vertices
[vertex
].position
.x
= 0.0f
;
3885 vertices
[vertex
].position
.y
= 0.0f
;
3886 vertices
[vertex
++].position
.z
= z
;
3888 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
3890 vertices
[vertex
].normal
.x
= 0.0f
;
3891 vertices
[vertex
].normal
.y
= 0.0f
;
3892 vertices
[vertex
].normal
.z
= -1.0f
;
3893 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
3894 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
3895 vertices
[vertex
].position
.z
= z
;
3900 faces
[face
][1] = slice
;
3901 faces
[face
++][2] = slice
+ 1;
3906 faces
[face
][1] = slice
;
3907 faces
[face
++][2] = 1;
3909 for (stack
= 1; stack
<= stacks
+1; stack
++)
3911 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
3913 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
3914 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
3915 vertices
[vertex
].normal
.z
= z_normal
;
3916 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
3917 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
3918 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
3919 vertices
[vertex
].position
.z
= z
;
3921 if (stack
> 1 && slice
> 0)
3923 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
3924 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
3925 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
3927 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
3928 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
3929 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
3935 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
3936 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
3937 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
3939 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
3940 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
3941 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
3944 if (stack
< stacks
+ 1)
3947 radius
-= radius_step
;
3951 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
3953 vertices
[vertex
].normal
.x
= 0.0f
;
3954 vertices
[vertex
].normal
.y
= 0.0f
;
3955 vertices
[vertex
].normal
.z
= 1.0f
;
3956 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
3957 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
3958 vertices
[vertex
].position
.z
= z
;
3962 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
3963 faces
[face
][1] = number_of_vertices
- 1;
3964 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
3968 vertices
[vertex
].position
.x
= 0.0f
;
3969 vertices
[vertex
].position
.y
= 0.0f
;
3970 vertices
[vertex
].position
.z
= z
;
3971 vertices
[vertex
].normal
.x
= 0.0f
;
3972 vertices
[vertex
].normal
.y
= 0.0f
;
3973 vertices
[vertex
].normal
.z
= 1.0f
;
3975 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
3976 faces
[face
][1] = number_of_vertices
- 1;
3977 faces
[face
][2] = vertex_index(slices
, 0, stack
);
3979 free_sincos_table(&theta
);
3980 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
3981 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
3987 HRESULT WINAPI
D3DXCreateTeapot(LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
, LPD3DXBUFFER
* adjacency
)
3989 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
3994 HRESULT WINAPI
D3DXCreateTextA(LPDIRECT3DDEVICE9 device
,
3995 HDC hdc
, LPCSTR text
,
3996 FLOAT deviation
, FLOAT extrusion
,
3997 LPD3DXMESH
*mesh
, LPD3DXBUFFER
*adjacency
,
3998 LPGLYPHMETRICSFLOAT glyphmetrics
)
4004 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
4005 debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
4008 return D3DERR_INVALIDCALL
;
4010 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
4011 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4012 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
4014 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
4015 mesh
, adjacency
, glyphmetrics
);
4016 HeapFree(GetProcessHeap(), 0, textW
);
4022 POINTTYPE_CURVE
= 0,
4024 POINTTYPE_CURVE_START
,
4025 POINTTYPE_CURVE_END
,
4026 POINTTYPE_CURVE_MIDDLE
,
4032 enum pointtype corner
;
4035 struct dynamic_array
4037 int count
, capacity
;
4041 /* is a dynamic_array */
4044 int count
, capacity
;
4045 struct point2d
*items
;
4048 /* is a dynamic_array */
4049 struct outline_array
4051 int count
, capacity
;
4052 struct outline
*items
;
4061 struct point2d_index
4063 struct outline
*outline
;
4067 struct point2d_index_array
4070 struct point2d_index
*items
;
4075 struct outline_array outlines
;
4076 struct face_array faces
;
4077 struct point2d_index_array ordered_vertices
;
4081 /* is an dynamic_array */
4084 int count
, capacity
;
4088 /* complex polygons are split into monotone polygons, which have
4089 * at most 2 intersections with the vertical sweep line */
4090 struct triangulation
4092 struct word_array vertex_stack
;
4093 BOOL last_on_top
, merging
;
4096 /* is an dynamic_array */
4097 struct triangulation_array
4099 int count
, capacity
;
4100 struct triangulation
*items
;
4102 struct glyphinfo
*glyph
;
4105 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
4107 if (count
> array
->capacity
) {
4110 if (array
->items
&& array
->capacity
) {
4111 new_capacity
= max(array
->capacity
* 2, count
);
4112 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
4114 new_capacity
= max(16, count
);
4115 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
4119 array
->items
= new_buffer
;
4120 array
->capacity
= new_capacity
;
4125 static struct point2d
*add_points(struct outline
*array
, int num
)
4127 struct point2d
*item
;
4129 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
4132 item
= &array
->items
[array
->count
];
4133 array
->count
+= num
;
4137 static struct outline
*add_outline(struct outline_array
*array
)
4139 struct outline
*item
;
4141 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
4144 item
= &array
->items
[array
->count
++];
4145 ZeroMemory(item
, sizeof(*item
));
4149 static inline face
*add_face(struct face_array
*array
)
4151 return &array
->items
[array
->count
++];
4154 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
4156 struct triangulation
*item
;
4158 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
4161 item
= &array
->items
[array
->count
++];
4162 ZeroMemory(item
, sizeof(*item
));
4166 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
4168 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
4169 return E_OUTOFMEMORY
;
4171 array
->items
[array
->count
++] = vertex_index
;
4175 /* assume fixed point numbers can be converted to float point in place */
4176 C_ASSERT(sizeof(FIXED
) == sizeof(float));
4177 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
4179 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, float emsquare
)
4181 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
4183 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
4184 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
4185 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
4191 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
4192 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
4193 float max_deviation_sq
)
4195 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
4198 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
4199 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
4200 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
4202 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
4203 if (deviation_sq
< max_deviation_sq
) {
4204 struct point2d
*pt
= add_points(outline
, 1);
4205 if (!pt
) return E_OUTOFMEMORY
;
4207 pt
->corner
= POINTTYPE_CURVE
;
4208 /* the end point is omitted because the end line merges into the next segment of
4209 * the split bezier curve, and the end of the split bezier curve is added outside
4210 * this recursive function. */
4212 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
4213 if (hr
!= S_OK
) return hr
;
4214 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
4215 if (hr
!= S_OK
) return hr
;
4221 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
4223 /* dot product = cos(theta) */
4224 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
4227 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
4229 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
4239 static BOOL
attempt_line_merge(struct outline
*outline
,
4241 const D3DXVECTOR2
*nextpt
,
4243 const struct cos_table
*table
)
4245 D3DXVECTOR2 curdir
, lastdir
;
4246 struct point2d
*prevpt
, *pt
;
4249 pt
= &outline
->items
[pt_index
];
4250 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
4251 prevpt
= &outline
->items
[pt_index
];
4254 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
4256 if (outline
->count
< 2)
4259 /* remove last point if the next line continues the last line */
4260 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
4261 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
4262 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
4265 if (pt
->corner
== POINTTYPE_CURVE_END
)
4266 prevpt
->corner
= pt
->corner
;
4267 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
4268 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
4272 if (outline
->count
< 2)
4275 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
4276 prevpt
= &outline
->items
[pt_index
];
4277 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
4278 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
4283 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
4284 float max_deviation_sq
, float emsquare
, const struct cos_table
*cos_table
)
4286 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
4288 while ((char *)header
< (char *)raw_outline
+ datasize
)
4290 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
4291 struct point2d
*lastpt
, *pt
;
4292 D3DXVECTOR2 lastdir
;
4293 D3DXVECTOR2
*pt_flt
;
4295 struct outline
*outline
= add_outline(&glyph
->outlines
);
4298 return E_OUTOFMEMORY
;
4300 pt
= add_points(outline
, 1);
4302 return E_OUTOFMEMORY
;
4303 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
4305 pt
->corner
= POINTTYPE_CORNER
;
4307 if (header
->dwType
!= TT_POLYGON_TYPE
)
4308 FIXME("Unknown header type %d\n", header
->dwType
);
4310 while ((char *)curve
< (char *)header
+ header
->cb
)
4312 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
4313 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
4316 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
4320 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
4322 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
4327 int count
= curve
->cpfx
;
4332 D3DXVECTOR2 bezier_end
;
4334 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j
], &pt_flt
[j
+1]), 0.5f
);
4335 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j
], &bezier_end
, max_deviation_sq
);
4338 bezier_start
= bezier_end
;
4342 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j
], &pt_flt
[j
+1], max_deviation_sq
);
4346 pt
= add_points(outline
, 1);
4348 return E_OUTOFMEMORY
;
4350 pt
->pos
= pt_flt
[j
];
4351 pt
->corner
= POINTTYPE_CURVE_END
;
4353 pt
= add_points(outline
, curve
->cpfx
);
4355 return E_OUTOFMEMORY
;
4356 for (j
= 0; j
< curve
->cpfx
; j
++)
4358 pt
->pos
= pt_flt
[j
];
4359 pt
->corner
= POINTTYPE_CORNER
;
4364 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
4367 /* remove last point if the next line continues the last line */
4368 if (outline
->count
>= 3) {
4371 lastpt
= &outline
->items
[outline
->count
- 1];
4372 pt
= &outline
->items
[0];
4373 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
4374 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
4376 if (pt
->corner
== POINTTYPE_CURVE_START
)
4377 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
4379 pt
->corner
= POINTTYPE_CURVE_END
;
4382 lastpt
= &outline
->items
[outline
->count
- 1];
4384 /* outline closed with a line from end to start point */
4385 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
4387 lastpt
= &outline
->items
[0];
4388 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
4389 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
4390 lastpt
->corner
= POINTTYPE_CORNER
;
4391 pt
= &outline
->items
[1];
4392 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
4393 *lastpt
= outline
->items
[outline
->count
];
4396 lastpt
= &outline
->items
[outline
->count
- 1];
4397 pt
= &outline
->items
[0];
4398 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
4399 for (j
= 0; j
< outline
->count
; j
++)
4404 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
4405 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
4407 switch (lastpt
->corner
)
4409 case POINTTYPE_CURVE_START
:
4410 case POINTTYPE_CURVE_END
:
4411 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
4412 lastpt
->corner
= POINTTYPE_CORNER
;
4414 case POINTTYPE_CURVE_MIDDLE
:
4415 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
4416 lastpt
->corner
= POINTTYPE_CORNER
;
4418 lastpt
->corner
= POINTTYPE_CURVE
;
4426 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
4431 /* Get the y-distance from a line to a point */
4432 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
4433 D3DXVECTOR2
*line_pt2
,
4436 D3DXVECTOR2 line_vec
= {0, 0};
4440 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
4441 line_pt_dx
= point
->x
- line_pt1
->x
;
4442 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
4443 return point
->y
- line_y
;
4446 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
4448 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
4451 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
4453 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
4456 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
4458 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
4459 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
4463 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
4464 struct triangulation_array
*triangulations
,
4468 struct glyphinfo
*glyph
= triangulations
->glyph
;
4469 struct triangulation
*t
= *t_ptr
;
4474 if (t
->last_on_top
) {
4482 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
4483 /* consume all vertices on the stack */
4484 WORD last_pt
= t
->vertex_stack
.items
[0];
4486 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
4488 face
= add_face(&glyph
->faces
);
4489 if (!face
) return E_OUTOFMEMORY
;
4490 (*face
)[0] = vtx_idx
;
4491 (*face
)[f1
] = last_pt
;
4492 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
4494 t
->vertex_stack
.items
[0] = last_pt
;
4495 t
->vertex_stack
.count
= 1;
4496 } else if (t
->vertex_stack
.count
> 1) {
4497 int i
= t
->vertex_stack
.count
- 1;
4498 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
4499 WORD top_idx
= t
->vertex_stack
.items
[i
--];
4500 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
4504 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
4505 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
4507 if (prev_pt
->x
!= top_pt
->x
&&
4508 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
4509 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
4512 face
= add_face(&glyph
->faces
);
4513 if (!face
) return E_OUTOFMEMORY
;
4514 (*face
)[0] = vtx_idx
;
4515 (*face
)[f1
] = prev_idx
;
4516 (*face
)[f2
] = top_idx
;
4520 t
->vertex_stack
.count
--;
4523 t
->last_on_top
= to_top
;
4525 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
4527 if (hr
== S_OK
&& t
->merging
) {
4528 struct triangulation
*t2
;
4530 t2
= to_top
? t
- 1 : t
+ 1;
4531 t2
->merging
= FALSE
;
4532 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
4533 if (hr
!= S_OK
) return hr
;
4534 remove_triangulation(triangulations
, t
);
4542 /* check if the point is next on the outline for either the top or bottom */
4543 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
4545 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
4546 WORD idx
= t
->vertex_stack
.items
[i
];
4547 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
4548 struct outline
*outline
= pt_idx
->outline
;
4551 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
4553 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
4555 return &outline
->items
[i
].pos
;
4558 static int compare_vertex_indices(const void *a
, const void *b
)
4560 const struct point2d_index
*idx1
= a
, *idx2
= b
;
4561 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
4562 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
4563 float diff
= p1
->x
- p2
->x
;
4566 diff
= p1
->y
- p2
->y
;
4568 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
4571 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
4575 struct glyphinfo
*glyph
= triangulations
->glyph
;
4576 int nb_vertices
= 0;
4578 struct point2d_index
*idx_ptr
;
4580 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
4581 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
4583 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
4584 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
4585 if (!glyph
->ordered_vertices
.items
)
4586 return E_OUTOFMEMORY
;
4588 idx_ptr
= glyph
->ordered_vertices
.items
;
4589 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
4591 struct outline
*outline
= &glyph
->outlines
.items
[i
];
4594 idx_ptr
->outline
= outline
;
4595 idx_ptr
->vertex
= 0;
4597 for (j
= outline
->count
- 1; j
> 0; j
--)
4599 idx_ptr
->outline
= outline
;
4600 idx_ptr
->vertex
= j
;
4604 glyph
->ordered_vertices
.count
= nb_vertices
;
4606 /* Native implementation seems to try to create a triangle fan from
4607 * the first outline point if the glyph only has one outline. */
4608 if (glyph
->outlines
.count
== 1)
4610 struct outline
*outline
= glyph
->outlines
.items
;
4611 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
4612 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
4615 for (i
= 2; i
< outline
->count
; i
++)
4617 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
4618 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
4619 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
4621 D3DXVec2Subtract(&v1
, base
, last
);
4622 D3DXVec2Subtract(&v2
, last
, next
);
4623 ccw
= D3DXVec2CCW(&v1
, &v2
);
4631 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
4632 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
4633 if (!glyph
->faces
.items
)
4634 return E_OUTOFMEMORY
;
4636 glyph
->faces
.count
= outline
->count
- 2;
4637 for (i
= 0; i
< glyph
->faces
.count
; i
++)
4639 glyph
->faces
.items
[i
][0] = 0;
4640 glyph
->faces
.items
[i
][1] = i
+ 1;
4641 glyph
->faces
.items
[i
][2] = i
+ 2;
4647 /* Perform 2D polygon triangulation for complex glyphs.
4648 * Triangulation is performed using a sweep line concept, from right to left,
4649 * by processing vertices in sorted order. Complex polygons are split into
4650 * monotone polygons which are triangulated separately. */
4651 /* FIXME: The order of the faces is not consistent with the native implementation. */
4653 /* Reserve space for maximum possible faces from triangulation.
4654 * # faces for outer outlines = outline->count - 2
4655 * # faces for inner outlines = outline->count + 2
4656 * There must be at least 1 outer outline. */
4657 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
4658 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
4659 if (!glyph
->faces
.items
)
4660 return E_OUTOFMEMORY
;
4662 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
4663 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
4664 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
4667 int end
= triangulations
->count
;
4671 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
4672 int current
= (start
+ end
) / 2;
4673 struct triangulation
*t
= &triangulations
->items
[current
];
4674 BOOL on_top_outline
= FALSE
;
4675 D3DXVECTOR2
*top_next
, *bottom_next
;
4676 WORD top_idx
, bottom_idx
;
4678 if (t
->merging
&& t
->last_on_top
)
4679 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
4681 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
4682 if (sweep_vtx
== top_next
)
4684 if (t
->merging
&& t
->last_on_top
)
4686 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
4687 if (hr
!= S_OK
) return hr
;
4689 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
4690 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
4692 /* point also on bottom outline of higher triangulation */
4693 struct triangulation
*t2
= t
+ 1;
4694 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
4695 if (hr
!= S_OK
) return hr
;
4700 on_top_outline
= TRUE
;
4703 if (t
->merging
&& !t
->last_on_top
)
4704 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
4706 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
4707 if (sweep_vtx
== bottom_next
)
4709 if (t
->merging
&& !t
->last_on_top
)
4711 if (on_top_outline
) {
4712 /* outline finished */
4713 remove_triangulation(triangulations
, t
);
4717 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
4718 if (hr
!= S_OK
) return hr
;
4720 if (t
> triangulations
->items
&&
4721 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
4723 struct triangulation
*t2
= t
- 1;
4724 /* point also on top outline of lower triangulation */
4725 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
4726 if (hr
!= S_OK
) return hr
;
4727 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
4737 if (t
->last_on_top
) {
4738 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
4739 bottom_idx
= t
->vertex_stack
.items
[0];
4741 top_idx
= t
->vertex_stack
.items
[0];
4742 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
4745 /* check if the point is inside or outside this polygon */
4746 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
4747 top_next
, sweep_vtx
) > 0)
4749 start
= current
+ 1;
4750 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
4751 bottom_next
, sweep_vtx
) < 0)
4754 } else if (t
->merging
) {
4755 /* inside, so cancel merging */
4756 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
4758 t2
->merging
= FALSE
;
4759 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
4760 if (hr
!= S_OK
) return hr
;
4761 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
4762 if (hr
!= S_OK
) return hr
;
4765 /* inside, so split polygon into two monotone parts */
4766 struct triangulation
*t2
= add_triangulation(triangulations
);
4767 if (!t2
) return E_OUTOFMEMORY
;
4768 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
4769 if (t
->last_on_top
) {
4776 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
4777 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
4778 if (hr
!= S_OK
) return hr
;
4779 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
4780 if (hr
!= S_OK
) return hr
;
4781 t2
->last_on_top
= !t
->last_on_top
;
4783 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
4784 if (hr
!= S_OK
) return hr
;
4790 struct triangulation
*t
;
4791 struct triangulation
*t2
= add_triangulation(triangulations
);
4792 if (!t2
) return E_OUTOFMEMORY
;
4793 t
= &triangulations
->items
[start
];
4794 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
4795 ZeroMemory(t
, sizeof(*t
));
4796 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
4797 if (hr
!= S_OK
) return hr
;
4803 HRESULT WINAPI
D3DXCreateTextW(LPDIRECT3DDEVICE9 device
,
4804 HDC hdc
, LPCWSTR text
,
4805 FLOAT deviation
, FLOAT extrusion
,
4806 LPD3DXMESH
*mesh_ptr
, LPD3DXBUFFER
*adjacency
,
4807 LPGLYPHMETRICSFLOAT glyphmetrics
)
4810 ID3DXMesh
*mesh
= NULL
;
4811 DWORD nb_vertices
, nb_faces
;
4812 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
4813 struct vertex
*vertices
= NULL
;
4818 OUTLINETEXTMETRICW otm
;
4819 HFONT font
= NULL
, oldfont
= NULL
;
4820 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
4821 void *raw_outline
= NULL
;
4823 struct glyphinfo
*glyphs
= NULL
;
4825 struct triangulation_array triangulations
= {0, 0, NULL
};
4827 struct vertex
*vertex_ptr
;
4829 float max_deviation_sq
;
4830 const struct cos_table cos_table
= {
4831 cos(D3DXToRadian(0.5f
)),
4832 cos(D3DXToRadian(45.0f
)),
4833 cos(D3DXToRadian(90.0f
)),
4837 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
4838 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
4840 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
4841 return D3DERR_INVALIDCALL
;
4845 FIXME("Case of adjacency != NULL not implemented.\n");
4849 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
4850 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
4852 return D3DERR_INVALIDCALL
;
4855 if (deviation
== 0.0f
)
4856 deviation
= 1.0f
/ otm
.otmEMSquare
;
4857 max_deviation_sq
= deviation
* deviation
;
4859 lf
.lfHeight
= otm
.otmEMSquare
;
4861 font
= CreateFontIndirectW(&lf
);
4866 oldfont
= SelectObject(hdc
, font
);
4868 textlen
= strlenW(text
);
4869 for (i
= 0; i
< textlen
; i
++)
4871 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
4873 return D3DERR_INVALIDCALL
;
4874 if (bufsize
< datasize
)
4877 if (!bufsize
) { /* e.g. text == " " */
4878 hr
= D3DERR_INVALIDCALL
;
4882 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
4883 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
4884 if (!glyphs
|| !raw_outline
) {
4890 for (i
= 0; i
< textlen
; i
++)
4892 /* get outline points from data returned from GetGlyphOutline */
4895 glyphs
[i
].offset_x
= offset_x
;
4897 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
4898 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
4899 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
4900 if (hr
!= S_OK
) goto error
;
4902 triangulations
.glyph
= &glyphs
[i
];
4903 hr
= triangulate(&triangulations
);
4904 if (hr
!= S_OK
) goto error
;
4905 if (triangulations
.count
) {
4906 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
4907 triangulations
.count
= 0;
4912 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
4913 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
4914 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
4915 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
4916 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
4917 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
4919 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
4922 /* corner points need an extra vertex for the different side faces normals */
4924 nb_outline_points
= 0;
4926 for (i
= 0; i
< textlen
; i
++)
4929 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
4930 nb_front_faces
+= glyphs
[i
].faces
.count
;
4931 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
4934 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
4935 nb_corners
++; /* first outline point always repeated as a corner */
4936 for (k
= 1; k
< outline
->count
; k
++)
4937 if (outline
->items
[k
].corner
)
4942 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
4943 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
4946 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
4947 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
4951 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
4955 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
4959 /* convert 2D vertices and faces into 3D mesh */
4960 vertex_ptr
= vertices
;
4962 if (extrusion
== 0.0f
) {
4969 for (i
= 0; i
< textlen
; i
++)
4973 struct vertex
*back_vertices
;
4976 /* side vertices and faces */
4977 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
4979 struct vertex
*outline_vertices
= vertex_ptr
;
4980 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
4982 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
4983 struct point2d
*pt
= &outline
->items
[0];
4985 for (k
= 1; k
<= outline
->count
; k
++)
4988 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
4989 WORD vtx_idx
= vertex_ptr
- vertices
;
4992 if (pt
->corner
== POINTTYPE_CURVE_START
)
4993 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
4994 else if (pt
->corner
)
4995 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
4997 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
4998 D3DXVec2Normalize(&vec
, &vec
);
4999 vtx
.normal
.x
= -vec
.y
;
5000 vtx
.normal
.y
= vec
.x
;
5003 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
5004 vtx
.position
.y
= pt
->pos
.y
;
5006 *vertex_ptr
++ = vtx
;
5008 vtx
.position
.z
= -extrusion
;
5009 *vertex_ptr
++ = vtx
;
5011 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
5012 vtx
.position
.y
= nextpt
->pos
.y
;
5013 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
5014 vtx
.position
.z
= -extrusion
;
5015 *vertex_ptr
++ = vtx
;
5017 *vertex_ptr
++ = vtx
;
5019 (*face_ptr
)[0] = vtx_idx
;
5020 (*face_ptr
)[1] = vtx_idx
+ 2;
5021 (*face_ptr
)[2] = vtx_idx
+ 1;
5024 (*face_ptr
)[0] = vtx_idx
;
5025 (*face_ptr
)[1] = vtx_idx
+ 3;
5026 (*face_ptr
)[2] = vtx_idx
+ 2;
5029 if (nextpt
->corner
) {
5030 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
5031 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
5032 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
5034 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
5036 D3DXVec2Normalize(&vec
, &vec
);
5037 vtx
.normal
.x
= -vec
.y
;
5038 vtx
.normal
.y
= vec
.x
;
5041 *vertex_ptr
++ = vtx
;
5042 vtx
.position
.z
= -extrusion
;
5043 *vertex_ptr
++ = vtx
;
5046 (*face_ptr
)[0] = vtx_idx
;
5047 (*face_ptr
)[1] = vtx_idx
+ 3;
5048 (*face_ptr
)[2] = vtx_idx
+ 1;
5051 (*face_ptr
)[0] = vtx_idx
;
5052 (*face_ptr
)[1] = vtx_idx
+ 2;
5053 (*face_ptr
)[2] = vtx_idx
+ 3;
5061 *vertex_ptr
++ = *outline_vertices
++;
5062 *vertex_ptr
++ = *outline_vertices
++;
5066 /* back vertices and faces */
5067 back_faces
= face_ptr
;
5068 back_vertices
= vertex_ptr
;
5069 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
5071 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
5072 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
5073 vertex_ptr
->position
.y
= pt
->y
;
5074 vertex_ptr
->position
.z
= 0;
5075 vertex_ptr
->normal
.x
= 0;
5076 vertex_ptr
->normal
.y
= 0;
5077 vertex_ptr
->normal
.z
= 1;
5080 count
= back_vertices
- vertices
;
5081 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
5083 face
*f
= &glyphs
[i
].faces
.items
[j
];
5084 (*face_ptr
)[0] = (*f
)[0] + count
;
5085 (*face_ptr
)[1] = (*f
)[1] + count
;
5086 (*face_ptr
)[2] = (*f
)[2] + count
;
5090 /* front vertices and faces */
5091 j
= count
= vertex_ptr
- back_vertices
;
5094 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
5095 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
5096 vertex_ptr
->position
.z
= -extrusion
;
5097 vertex_ptr
->normal
.x
= 0;
5098 vertex_ptr
->normal
.y
= 0;
5099 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
5103 j
= face_ptr
- back_faces
;
5106 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
5107 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
5108 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
5118 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
5119 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
5120 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
5123 for (i
= 0; i
< textlen
; i
++)
5126 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
5127 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
5128 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
5129 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
5130 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
5132 HeapFree(GetProcessHeap(), 0, glyphs
);
5134 if (triangulations
.items
) {
5136 for (i
= 0; i
< triangulations
.count
; i
++)
5137 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
5138 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
5140 HeapFree(GetProcessHeap(), 0, raw_outline
);
5141 if (oldfont
) SelectObject(hdc
, oldfont
);
5142 if (font
) DeleteObject(font
);