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
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
39 #include "wine/list.h"
40 #include "d3dx9_36_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
44 typedef struct ID3DXMeshImpl
46 ID3DXMesh ID3DXMesh_iface
;
53 IDirect3DDevice9
*device
;
54 IDirect3DVertexDeclaration9
*vertex_declaration
;
55 IDirect3DVertexBuffer9
*vertex_buffer
;
56 IDirect3DIndexBuffer9
*index_buffer
;
58 int attrib_buffer_lock_count
;
59 DWORD attrib_table_size
;
60 D3DXATTRIBUTERANGE
*attrib_table
;
63 static inline ID3DXMeshImpl
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
65 return CONTAINING_RECORD(iface
, ID3DXMeshImpl
, ID3DXMesh_iface
);
68 static HRESULT WINAPI
ID3DXMeshImpl_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, LPVOID
*object
)
70 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
72 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), object
);
74 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
75 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
76 IsEqualGUID(riid
, &IID_ID3DXMesh
))
78 iface
->lpVtbl
->AddRef(iface
);
83 WARN("Interface %s not found.\n", debugstr_guid(riid
));
88 static ULONG WINAPI
ID3DXMeshImpl_AddRef(ID3DXMesh
*iface
)
90 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
92 TRACE("(%p)->(): AddRef from %d\n", This
, This
->ref
);
94 return InterlockedIncrement(&This
->ref
);
97 static ULONG WINAPI
ID3DXMeshImpl_Release(ID3DXMesh
*iface
)
99 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
100 ULONG ref
= InterlockedDecrement(&This
->ref
);
102 TRACE("(%p)->(): Release from %d\n", This
, ref
+ 1);
106 IDirect3DIndexBuffer9_Release(This
->index_buffer
);
107 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
108 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
109 IDirect3DDevice9_Release(This
->device
);
110 HeapFree(GetProcessHeap(), 0, This
->attrib_buffer
);
111 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
112 HeapFree(GetProcessHeap(), 0, This
);
118 /*** ID3DXBaseMesh ***/
119 static HRESULT WINAPI
ID3DXMeshImpl_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
121 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
127 TRACE("(%p)->(%u)\n", This
, attrib_id
);
129 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
131 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
132 if (FAILED(hr
)) return hr
;
133 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
134 if (FAILED(hr
)) return hr
;
135 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
136 if (FAILED(hr
)) return hr
;
138 while (face_end
< This
->numfaces
)
140 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
142 if (This
->attrib_buffer
[face_start
] == attrib_id
)
145 if (face_start
>= This
->numfaces
)
147 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
149 if (This
->attrib_buffer
[face_end
] != attrib_id
)
153 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
154 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
155 if (FAILED(hr
)) return hr
;
161 static DWORD WINAPI
ID3DXMeshImpl_GetNumFaces(ID3DXMesh
*iface
)
163 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
165 TRACE("(%p)\n", This
);
167 return This
->numfaces
;
170 static DWORD WINAPI
ID3DXMeshImpl_GetNumVertices(ID3DXMesh
*iface
)
172 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
174 TRACE("(%p)\n", This
);
176 return This
->numvertices
;
179 static DWORD WINAPI
ID3DXMeshImpl_GetFVF(ID3DXMesh
*iface
)
181 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
183 TRACE("(%p)\n", This
);
188 static HRESULT WINAPI
ID3DXMeshImpl_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
190 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
193 TRACE("(%p)\n", This
);
195 if (declaration
== NULL
) return D3DERR_INVALIDCALL
;
197 return IDirect3DVertexDeclaration9_GetDeclaration(This
->vertex_declaration
,
202 static DWORD WINAPI
ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh
*iface
)
204 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
206 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
208 TRACE("iface (%p)\n", This
);
210 IDirect3DVertexDeclaration9_GetDeclaration(This
->vertex_declaration
,
213 return D3DXGetDeclVertexSize(declaration
, 0);
216 static DWORD WINAPI
ID3DXMeshImpl_GetOptions(ID3DXMesh
*iface
)
218 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
220 TRACE("(%p)\n", This
);
222 return This
->options
;
225 static HRESULT WINAPI
ID3DXMeshImpl_GetDevice(ID3DXMesh
*iface
, LPDIRECT3DDEVICE9
*device
)
227 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
229 TRACE("(%p)->(%p)\n", This
, device
);
231 if (device
== NULL
) return D3DERR_INVALIDCALL
;
232 *device
= This
->device
;
233 IDirect3DDevice9_AddRef(This
->device
);
238 static HRESULT WINAPI
ID3DXMeshImpl_CloneMeshFVF(ID3DXMesh
*iface
, DWORD options
, DWORD fvf
, LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*clone_mesh
)
240 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
242 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
244 TRACE("(%p)->(%x,%x,%p,%p)\n", This
, options
, fvf
, device
, clone_mesh
);
246 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
247 if (FAILED(hr
)) return hr
;
249 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
252 static HRESULT WINAPI
ID3DXMeshImpl_CloneMesh(ID3DXMesh
*iface
, DWORD options
, CONST D3DVERTEXELEMENT9
*declaration
, LPDIRECT3DDEVICE9 device
,
253 LPD3DXMESH
*clone_mesh_out
)
255 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
256 ID3DXMeshImpl
*cloned_this
;
257 ID3DXMesh
*clone_mesh
;
258 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
259 void *data_in
, *data_out
;
264 TRACE("(%p)->(%x,%p,%p,%p)\n", This
, options
, declaration
, device
, clone_mesh_out
);
267 return D3DERR_INVALIDCALL
;
269 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
270 if (FAILED(hr
)) return hr
;
272 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++) {
273 if (memcmp(&orig_declaration
[i
], &declaration
[i
], sizeof(*declaration
)))
275 FIXME("Vertex buffer conversion not implemented.\n");
280 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
281 declaration
, device
, &clone_mesh
);
282 if (FAILED(hr
)) return hr
;
284 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
285 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
287 if (options
& D3DXMESH_VB_SHARE
) {
288 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
289 /* FIXME: refactor to avoid creating a new vertex buffer */
290 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
291 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
293 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
294 if (FAILED(hr
)) goto error
;
295 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, D3DLOCK_DISCARD
, &data_out
);
297 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
300 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
301 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
302 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
305 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
306 if (FAILED(hr
)) goto error
;
307 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, D3DLOCK_DISCARD
, &data_out
);
309 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
312 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
313 if (options
& D3DXMESH_32BIT
) {
314 for (i
= 0; i
< This
->numfaces
* 3; i
++)
315 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
317 for (i
= 0; i
< This
->numfaces
* 3; i
++)
318 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
321 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
323 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
324 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
326 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
328 if (This
->attrib_table_size
)
330 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
331 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
332 if (!cloned_this
->attrib_table
) {
336 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
339 *clone_mesh_out
= clone_mesh
;
343 IUnknown_Release(clone_mesh
);
347 static HRESULT WINAPI
ID3DXMeshImpl_GetVertexBuffer(ID3DXMesh
*iface
, LPDIRECT3DVERTEXBUFFER9
*vertex_buffer
)
349 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
351 TRACE("(%p)->(%p)\n", This
, vertex_buffer
);
353 if (vertex_buffer
== NULL
) return D3DERR_INVALIDCALL
;
354 *vertex_buffer
= This
->vertex_buffer
;
355 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
360 static HRESULT WINAPI
ID3DXMeshImpl_GetIndexBuffer(ID3DXMesh
*iface
, LPDIRECT3DINDEXBUFFER9
*index_buffer
)
362 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
364 TRACE("(%p)->(%p)\n", This
, index_buffer
);
366 if (index_buffer
== NULL
) return D3DERR_INVALIDCALL
;
367 *index_buffer
= This
->index_buffer
;
368 IDirect3DIndexBuffer9_AddRef(This
->index_buffer
);
373 static HRESULT WINAPI
ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
375 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
377 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
379 return IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, data
, flags
);
382 static HRESULT WINAPI
ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh
*iface
)
384 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
386 TRACE("(%p)\n", This
);
388 return IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
391 static HRESULT WINAPI
ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
393 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
395 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
397 return IDirect3DIndexBuffer9_Lock(This
->index_buffer
, 0, 0, data
, flags
);
400 static HRESULT WINAPI
ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh
*iface
)
402 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
404 TRACE("(%p)\n", This
);
406 return IDirect3DIndexBuffer9_Unlock(This
->index_buffer
);
409 static HRESULT WINAPI
ID3DXMeshImpl_GetAttributeTable(ID3DXMesh
*iface
, D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
411 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
413 TRACE("(%p)->(%p,%p)\n", This
, attrib_table
, attrib_table_size
);
415 if (attrib_table_size
)
416 *attrib_table_size
= This
->attrib_table_size
;
419 CopyMemory(attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*attrib_table
));
424 static HRESULT WINAPI
ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
, CONST DWORD
*point_reps
, DWORD
*adjacency
)
426 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
428 FIXME("(%p)->(%p,%p): stub\n", This
, point_reps
, adjacency
);
433 static HRESULT WINAPI
ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
, CONST DWORD
*adjacency
, DWORD
*point_reps
)
435 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
437 FIXME("(%p)->(%p,%p): stub\n", This
, adjacency
, point_reps
);
442 struct vertex_metadata
{
445 DWORD first_shared_index
;
448 static int compare_vertex_keys(const void *a
, const void *b
)
450 const struct vertex_metadata
*left
= a
;
451 const struct vertex_metadata
*right
= b
;
452 if (left
->key
== right
->key
)
454 return left
->key
< right
->key
? -1 : 1;
457 static HRESULT WINAPI
ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh
*iface
, FLOAT epsilon
, DWORD
*adjacency
)
459 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
461 BYTE
*vertices
= NULL
;
462 const DWORD
*indices
= NULL
;
465 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
466 struct vertex_metadata
*sorted_vertices
;
467 /* shared_indices links together identical indices in the index buffer so
468 * that adjacency checks can be limited to faces sharing a vertex */
469 DWORD
*shared_indices
= NULL
;
470 const FLOAT epsilon_sq
= epsilon
* epsilon
;
473 TRACE("(%p)->(%f,%p)\n", This
, epsilon
, adjacency
);
476 return D3DERR_INVALIDCALL
;
478 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
479 if (!(This
->options
& D3DXMESH_32BIT
))
480 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
481 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
483 return E_OUTOFMEMORY
;
484 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
486 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
487 if (FAILED(hr
)) goto cleanup
;
488 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
489 if (FAILED(hr
)) goto cleanup
;
491 if (!(This
->options
& D3DXMESH_32BIT
)) {
492 const WORD
*word_indices
= (const WORD
*)indices
;
493 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
494 indices
= dword_indices
;
495 for (i
= 0; i
< This
->numfaces
* 3; i
++)
496 *dword_indices
++ = *word_indices
++;
499 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
500 for (i
= 0; i
< This
->numvertices
; i
++) {
501 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
502 sorted_vertices
[i
].first_shared_index
= -1;
503 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
504 sorted_vertices
[i
].vertex_index
= i
;
506 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
507 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
508 shared_indices
[i
] = *first_shared_index
;
509 *first_shared_index
= i
;
512 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
514 for (i
= 0; i
< This
->numvertices
; i
++) {
515 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
516 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
517 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
519 while (shared_index_a
!= -1) {
521 DWORD shared_index_b
= shared_indices
[shared_index_a
];
522 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
525 while (shared_index_b
!= -1) {
526 /* faces are adjacent if they have another coincident vertex */
527 DWORD base_a
= (shared_index_a
/ 3) * 3;
528 DWORD base_b
= (shared_index_b
/ 3) * 3;
529 BOOL adjacent
= FALSE
;
532 for (k
= 0; k
< 3; k
++) {
533 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
539 for (k
= 1; k
<= 2; k
++) {
540 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
541 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
542 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
543 if (!adjacent
&& epsilon
>= 0.0f
) {
544 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
547 D3DXVec3Subtract(&delta
,
548 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
549 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
550 length_sq
= D3DXVec3LengthSq(&delta
);
551 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
554 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
555 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
556 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
557 adjacency
[adj_a
] = base_b
/ 3;
558 adjacency
[adj_b
] = base_a
/ 3;
565 shared_index_b
= shared_indices
[shared_index_b
];
567 while (++j
< This
->numvertices
) {
568 D3DXVECTOR3
*vertex_b
;
571 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
572 /* no more coincident vertices to try */
573 j
= This
->numvertices
;
576 /* check for coincidence */
577 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
578 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
579 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
580 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
585 if (j
>= This
->numvertices
)
587 shared_index_b
= sorted_vertex_b
->first_shared_index
;
590 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
591 shared_index_a
= sorted_vertex_a
->first_shared_index
;
597 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
598 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
599 HeapFree(GetProcessHeap(), 0, shared_indices
);
603 static HRESULT WINAPI
ID3DXMeshImpl_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
605 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
607 FIXME("(%p)->(%p): stub\n", This
, declaration
);
613 static HRESULT WINAPI
ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
615 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
617 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
619 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
621 if (!(flags
& D3DLOCK_READONLY
)) {
622 D3DXATTRIBUTERANGE
*attrib_table
= This
->attrib_table
;
623 This
->attrib_table_size
= 0;
624 This
->attrib_table
= NULL
;
625 HeapFree(GetProcessHeap(), 0, attrib_table
);
628 *data
= This
->attrib_buffer
;
633 static HRESULT WINAPI
ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh
*iface
)
635 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
638 TRACE("(%p)\n", This
);
640 lock_count
= InterlockedDecrement(&This
->attrib_buffer_lock_count
);
642 if (lock_count
< 0) {
643 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
644 return D3DERR_INVALIDCALL
;
650 static HRESULT WINAPI
ID3DXMeshImpl_Optimize(ID3DXMesh
*iface
, DWORD flags
, CONST DWORD
*adjacency_in
, DWORD
*adjacency_out
,
651 DWORD
*face_remap
, LPD3DXBUFFER
*vertex_remap
, LPD3DXMESH
*opt_mesh
)
653 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
655 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
656 ID3DXMesh
*optimized_mesh
;
658 TRACE("(%p)->(%x,%p,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
661 return D3DERR_INVALIDCALL
;
663 hr
= iface
->lpVtbl
->GetDeclaration(iface
, declaration
);
664 if (FAILED(hr
)) return hr
;
666 hr
= iface
->lpVtbl
->CloneMesh(iface
, This
->options
, declaration
, This
->device
, &optimized_mesh
);
667 if (FAILED(hr
)) return hr
;
669 hr
= optimized_mesh
->lpVtbl
->OptimizeInplace(optimized_mesh
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
);
671 *opt_mesh
= optimized_mesh
;
673 IUnknown_Release(optimized_mesh
);
677 /* Creates a vertex_remap that removes unused vertices.
678 * Indices are updated according to the vertex_remap. */
679 static HRESULT
compact_mesh(ID3DXMeshImpl
*This
, DWORD
*indices
, DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
682 DWORD
*vertex_remap_ptr
;
683 DWORD num_used_vertices
;
686 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
687 if (FAILED(hr
)) return hr
;
688 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
690 for (i
= 0; i
< This
->numfaces
* 3; i
++)
691 vertex_remap_ptr
[indices
[i
]] = 1;
693 /* create old->new vertex mapping */
694 num_used_vertices
= 0;
695 for (i
= 0; i
< This
->numvertices
; i
++) {
696 if (vertex_remap_ptr
[i
])
697 vertex_remap_ptr
[i
] = num_used_vertices
++;
699 vertex_remap_ptr
[i
] = -1;
701 /* convert indices */
702 for (i
= 0; i
< This
->numfaces
* 3; i
++)
703 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
705 /* create new->old vertex mapping */
706 num_used_vertices
= 0;
707 for (i
= 0; i
< This
->numvertices
; i
++) {
708 if (vertex_remap_ptr
[i
] != -1)
709 vertex_remap_ptr
[num_used_vertices
++] = i
;
711 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
712 vertex_remap_ptr
[i
] = -1;
714 *new_num_vertices
= num_used_vertices
;
719 /* count the number of unique attribute values in a sorted attribute buffer */
720 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
722 DWORD last_attribute
= attrib_buffer
[0];
723 DWORD attrib_table_size
= 1;
725 for (i
= 1; i
< numfaces
; i
++) {
726 if (attrib_buffer
[i
] != last_attribute
) {
727 last_attribute
= attrib_buffer
[i
];
731 return attrib_table_size
;
734 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
735 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
737 DWORD attrib_table_size
= 0;
738 DWORD last_attribute
= attrib_buffer
[0];
739 DWORD min_vertex
, max_vertex
;
742 attrib_table
[0].AttribId
= last_attribute
;
743 attrib_table
[0].FaceStart
= 0;
744 min_vertex
= (DWORD
)-1;
746 for (i
= 0; i
< numfaces
; i
++) {
749 if (attrib_buffer
[i
] != last_attribute
) {
750 last_attribute
= attrib_buffer
[i
];
751 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
752 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
753 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
755 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
756 attrib_table
[attrib_table_size
].FaceStart
= i
;
757 min_vertex
= (DWORD
)-1;
760 for (j
= 0; j
< 3; j
++) {
761 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
762 if (vertex_index
< min_vertex
)
763 min_vertex
= vertex_index
;
764 if (vertex_index
> max_vertex
)
765 max_vertex
= vertex_index
;
768 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
769 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
770 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
774 static int attrib_entry_compare(const DWORD
**a
, const DWORD
**b
)
776 const DWORD
*ptr_a
= *a
;
777 const DWORD
*ptr_b
= *b
;
778 int delta
= *ptr_a
- *ptr_b
;
783 delta
= ptr_a
- ptr_b
; /* for stable sort */
787 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
788 static HRESULT
remap_faces_for_attrsort(ID3DXMeshImpl
*This
, const DWORD
*indices
,
789 const DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
791 const DWORD
**sorted_attrib_ptr_buffer
= NULL
;
794 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
795 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
796 if (!*face_remap
|| !sorted_attrib_ptr_buffer
) {
797 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
798 return E_OUTOFMEMORY
;
800 for (i
= 0; i
< This
->numfaces
; i
++)
801 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
802 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
),
803 (int(*)(const void *, const void *))attrib_entry_compare
);
805 for (i
= 0; i
< This
->numfaces
; i
++)
807 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
808 (*face_remap
)[old_face
] = i
;
811 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
812 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
813 for (i
= 0; i
< This
->numfaces
; i
++)
814 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
819 static HRESULT WINAPI
ID3DXMeshImpl_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, CONST DWORD
*adjacency_in
, DWORD
*adjacency_out
,
820 DWORD
*face_remap_out
, LPD3DXBUFFER
*vertex_remap_out
)
822 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
823 void *indices
= NULL
;
824 DWORD
*attrib_buffer
= NULL
;
826 ID3DXBuffer
*vertex_remap
= NULL
;
827 DWORD
*face_remap
= NULL
; /* old -> new mapping */
828 DWORD
*dword_indices
= NULL
;
829 DWORD new_num_vertices
= 0;
830 DWORD new_num_alloc_vertices
= 0;
831 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
832 DWORD
*sorted_attrib_buffer
= NULL
;
835 TRACE("(%p)->(%x,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
838 return D3DERR_INVALIDCALL
;
839 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
840 return D3DERR_INVALIDCALL
;
841 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
842 return D3DERR_INVALIDCALL
;
844 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
846 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
847 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
848 if (flags
& D3DXMESHOPT_STRIPREORDER
)
849 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
853 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, (void**)&indices
);
854 if (FAILED(hr
)) goto cleanup
;
856 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
857 if (!dword_indices
) return E_OUTOFMEMORY
;
858 if (This
->options
& D3DXMESH_32BIT
) {
859 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
861 WORD
*word_indices
= indices
;
862 for (i
= 0; i
< This
->numfaces
* 3; i
++)
863 dword_indices
[i
] = *word_indices
++;
866 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
868 new_num_alloc_vertices
= This
->numvertices
;
869 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
870 if (FAILED(hr
)) goto cleanup
;
871 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
872 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
874 FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
879 hr
= iface
->lpVtbl
->LockAttributeBuffer(iface
, 0, &attrib_buffer
);
880 if (FAILED(hr
)) goto cleanup
;
882 hr
= remap_faces_for_attrsort(This
, dword_indices
, attrib_buffer
, &sorted_attrib_buffer
, &face_remap
);
883 if (FAILED(hr
)) goto cleanup
;
888 /* reorder the vertices using vertex_remap */
889 D3DVERTEXBUFFER_DESC vertex_desc
;
890 DWORD
*vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
891 DWORD vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
895 hr
= IDirect3DVertexBuffer9_GetDesc(This
->vertex_buffer
, &vertex_desc
);
896 if (FAILED(hr
)) goto cleanup
;
898 hr
= IDirect3DDevice9_CreateVertexBuffer(This
->device
, new_num_alloc_vertices
* vertex_size
,
899 vertex_desc
.Usage
, This
->fvf
, vertex_desc
.Pool
, &vertex_buffer
, NULL
);
900 if (FAILED(hr
)) goto cleanup
;
902 hr
= IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, (void**)&orig_vertices
, D3DLOCK_READONLY
);
903 if (FAILED(hr
)) goto cleanup
;
905 hr
= IDirect3DVertexBuffer9_Lock(vertex_buffer
, 0, 0, (void**)&new_vertices
, D3DLOCK_DISCARD
);
907 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
911 for (i
= 0; i
< new_num_vertices
; i
++)
912 memcpy(new_vertices
+ i
* vertex_size
, orig_vertices
+ vertex_remap_ptr
[i
] * vertex_size
, vertex_size
);
914 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
915 IDirect3DVertexBuffer9_Unlock(vertex_buffer
);
916 } else if (vertex_remap_out
) {
917 DWORD
*vertex_remap_ptr
;
919 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), &vertex_remap
);
920 if (FAILED(hr
)) goto cleanup
;
921 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
922 for (i
= 0; i
< This
->numvertices
; i
++)
923 *vertex_remap_ptr
++ = i
;
926 if (flags
& D3DXMESHOPT_ATTRSORT
)
928 D3DXATTRIBUTERANGE
*attrib_table
;
929 DWORD attrib_table_size
;
931 attrib_table_size
= count_attributes(sorted_attrib_buffer
, This
->numfaces
);
932 attrib_table
= HeapAlloc(GetProcessHeap(), 0, attrib_table_size
* sizeof(*attrib_table
));
938 memcpy(attrib_buffer
, sorted_attrib_buffer
, This
->numfaces
* sizeof(*attrib_buffer
));
940 /* reorder the indices using face_remap */
941 if (This
->options
& D3DXMESH_32BIT
) {
942 for (i
= 0; i
< This
->numfaces
; i
++)
943 memcpy((DWORD
*)indices
+ face_remap
[i
] * 3, dword_indices
+ i
* 3, 3 * sizeof(DWORD
));
945 WORD
*word_indices
= indices
;
946 for (i
= 0; i
< This
->numfaces
; i
++) {
947 DWORD new_pos
= face_remap
[i
] * 3;
948 DWORD old_pos
= i
* 3;
949 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
950 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
951 word_indices
[new_pos
] = dword_indices
[old_pos
];
955 fill_attribute_table(attrib_buffer
, This
->numfaces
, indices
,
956 This
->options
& D3DXMESH_32BIT
, attrib_table
);
958 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
959 This
->attrib_table
= attrib_table
;
960 This
->attrib_table_size
= attrib_table_size
;
962 if (This
->options
& D3DXMESH_32BIT
) {
963 memcpy(indices
, dword_indices
, This
->numfaces
* 3 * sizeof(DWORD
));
965 WORD
*word_indices
= indices
;
966 for (i
= 0; i
< This
->numfaces
* 3; i
++)
967 *word_indices
++ = dword_indices
[i
];
973 for (i
= 0; i
< This
->numfaces
; i
++) {
974 DWORD old_pos
= i
* 3;
975 DWORD new_pos
= face_remap
[i
] * 3;
976 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
977 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
978 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
981 memcpy(adjacency_out
, adjacency_in
, This
->numfaces
* 3 * sizeof(*adjacency_out
));
984 if (face_remap_out
) {
986 for (i
= 0; i
< This
->numfaces
; i
++)
987 face_remap_out
[face_remap
[i
]] = i
;
989 for (i
= 0; i
< This
->numfaces
; i
++)
990 face_remap_out
[i
] = i
;
993 if (vertex_remap_out
)
994 *vertex_remap_out
= vertex_remap
;
998 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
999 This
->vertex_buffer
= vertex_buffer
;
1000 vertex_buffer
= NULL
;
1001 This
->numvertices
= new_num_vertices
;
1006 HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer
);
1007 HeapFree(GetProcessHeap(), 0, face_remap
);
1008 HeapFree(GetProcessHeap(), 0, dword_indices
);
1009 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
1010 if (vertex_buffer
) IDirect3DVertexBuffer9_Release(vertex_buffer
);
1011 if (attrib_buffer
) iface
->lpVtbl
->UnlockAttributeBuffer(iface
);
1012 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1016 static HRESULT WINAPI
ID3DXMeshImpl_SetAttributeTable(ID3DXMesh
*iface
, CONST D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
1018 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1019 D3DXATTRIBUTERANGE
*new_table
= NULL
;
1021 TRACE("(%p)->(%p,%u)\n", This
, attrib_table
, attrib_table_size
);
1023 if (attrib_table_size
) {
1024 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
1026 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
1028 return E_OUTOFMEMORY
;
1030 CopyMemory(new_table
, attrib_table
, size
);
1031 } else if (attrib_table
) {
1032 return D3DERR_INVALIDCALL
;
1034 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1035 This
->attrib_table
= new_table
;
1036 This
->attrib_table_size
= attrib_table_size
;
1041 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
1043 /*** IUnknown methods ***/
1044 ID3DXMeshImpl_QueryInterface
,
1045 ID3DXMeshImpl_AddRef
,
1046 ID3DXMeshImpl_Release
,
1047 /*** ID3DXBaseMesh ***/
1048 ID3DXMeshImpl_DrawSubset
,
1049 ID3DXMeshImpl_GetNumFaces
,
1050 ID3DXMeshImpl_GetNumVertices
,
1051 ID3DXMeshImpl_GetFVF
,
1052 ID3DXMeshImpl_GetDeclaration
,
1053 ID3DXMeshImpl_GetNumBytesPerVertex
,
1054 ID3DXMeshImpl_GetOptions
,
1055 ID3DXMeshImpl_GetDevice
,
1056 ID3DXMeshImpl_CloneMeshFVF
,
1057 ID3DXMeshImpl_CloneMesh
,
1058 ID3DXMeshImpl_GetVertexBuffer
,
1059 ID3DXMeshImpl_GetIndexBuffer
,
1060 ID3DXMeshImpl_LockVertexBuffer
,
1061 ID3DXMeshImpl_UnlockVertexBuffer
,
1062 ID3DXMeshImpl_LockIndexBuffer
,
1063 ID3DXMeshImpl_UnlockIndexBuffer
,
1064 ID3DXMeshImpl_GetAttributeTable
,
1065 ID3DXMeshImpl_ConvertPointRepsToAdjacency
,
1066 ID3DXMeshImpl_ConvertAdjacencyToPointReps
,
1067 ID3DXMeshImpl_GenerateAdjacency
,
1068 ID3DXMeshImpl_UpdateSemantics
,
1070 ID3DXMeshImpl_LockAttributeBuffer
,
1071 ID3DXMeshImpl_UnlockAttributeBuffer
,
1072 ID3DXMeshImpl_Optimize
,
1073 ID3DXMeshImpl_OptimizeInplace
,
1074 ID3DXMeshImpl_SetAttributeTable
1077 /*************************************************************************
1080 BOOL WINAPI
D3DXBoxBoundProbe(CONST D3DXVECTOR3
*pmin
, CONST D3DXVECTOR3
*pmax
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
1082 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algoritm
1083 Amy Williams University of Utah
1084 Steve Barrus University of Utah
1085 R. Keith Morley University of Utah
1086 Peter Shirley University of Utah
1088 International Conference on Computer Graphics and Interactive Techniques archive
1089 ACM SIGGRAPH 2005 Courses
1090 Los Angeles, California
1092 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1094 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1095 against each slab, if there's anything left of the ray after we're
1096 done we've got an intersection of the ray with the box.
1100 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
1102 div
= 1.0f
/ praydirection
->x
;
1105 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
1106 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
1110 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
1111 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
1114 if ( tmax
< 0.0f
) return FALSE
;
1116 div
= 1.0f
/ praydirection
->y
;
1119 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
1120 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
1124 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
1125 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
1128 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
1130 if ( tymin
> tmin
) tmin
= tymin
;
1131 if ( tymax
< tmax
) tmax
= tymax
;
1133 div
= 1.0f
/ praydirection
->z
;
1136 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
1137 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
1141 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
1142 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
1145 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
1150 /*************************************************************************
1151 * D3DXComputeBoundingBox
1153 HRESULT WINAPI
D3DXComputeBoundingBox(CONST D3DXVECTOR3
*pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
1158 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
1160 *pmin
= *pfirstposition
;
1163 for(i
=0; i
<numvertices
; i
++)
1165 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
1167 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
1168 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
1170 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
1171 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
1173 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
1174 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
1180 /*************************************************************************
1181 * D3DXComputeBoundingSphere
1183 HRESULT WINAPI
D3DXComputeBoundingSphere(CONST D3DXVECTOR3
* pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, FLOAT
*pradius
)
1185 D3DXVECTOR3 temp
, temp1
;
1189 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
1197 for(i
=0; i
<numvertices
; i
++)
1199 D3DXVec3Add(&temp1
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
1203 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/((FLOAT
)numvertices
));
1205 for(i
=0; i
<numvertices
; i
++)
1207 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
1208 if ( d
> *pradius
) *pradius
= d
;
1213 static const UINT d3dx_decltype_size
[D3DDECLTYPE_UNUSED
] =
1215 /* D3DDECLTYPE_FLOAT1 */ 1 * 4,
1216 /* D3DDECLTYPE_FLOAT2 */ 2 * 4,
1217 /* D3DDECLTYPE_FLOAT3 */ 3 * 4,
1218 /* D3DDECLTYPE_FLOAT4 */ 4 * 4,
1219 /* D3DDECLTYPE_D3DCOLOR */ 4 * 1,
1220 /* D3DDECLTYPE_UBYTE4 */ 4 * 1,
1221 /* D3DDECLTYPE_SHORT2 */ 2 * 2,
1222 /* D3DDECLTYPE_SHORT4 */ 4 * 2,
1223 /* D3DDECLTYPE_UBYTE4N */ 4 * 1,
1224 /* D3DDECLTYPE_SHORT2N */ 2 * 2,
1225 /* D3DDECLTYPE_SHORT4N */ 4 * 2,
1226 /* D3DDECLTYPE_USHORT2N */ 2 * 2,
1227 /* D3DDECLTYPE_USHORT4N */ 4 * 2,
1228 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
1229 /* D3DDECLTYPE_DEC3N */ 4,
1230 /* D3DDECLTYPE_FLOAT16_2 */ 2 * 2,
1231 /* D3DDECLTYPE_FLOAT16_4 */ 4 * 2,
1234 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
1235 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
1237 declaration
[*idx
].Stream
= 0;
1238 declaration
[*idx
].Offset
= *offset
;
1239 declaration
[*idx
].Type
= type
;
1240 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
1241 declaration
[*idx
].Usage
= usage
;
1242 declaration
[*idx
].UsageIndex
= usage_idx
;
1244 *offset
+= d3dx_decltype_size
[type
];
1248 /*************************************************************************
1249 * D3DXDeclaratorFromFVF
1251 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1253 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
1254 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
1255 unsigned int offset
= 0;
1256 unsigned int idx
= 0;
1259 TRACE("fvf %#x, declaration %p.\n", fvf
, declaration
);
1261 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
1263 if (fvf
& D3DFVF_POSITION_MASK
)
1265 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
1266 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
1267 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
1269 if (has_blend_idx
) --blend_count
;
1271 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
1272 || (has_blend
&& blend_count
> 4))
1273 return D3DERR_INVALIDCALL
;
1275 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
1276 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
1278 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
1282 switch (blend_count
)
1287 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1290 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1293 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1296 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1299 ERR("Invalid blend count %u.\n", blend_count
);
1305 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
1306 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
1307 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
1308 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
1313 if (fvf
& D3DFVF_NORMAL
)
1314 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
1315 if (fvf
& D3DFVF_PSIZE
)
1316 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
1317 if (fvf
& D3DFVF_DIFFUSE
)
1318 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
1319 if (fvf
& D3DFVF_SPECULAR
)
1320 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
1322 for (i
= 0; i
< tex_count
; ++i
)
1324 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
1326 case D3DFVF_TEXTUREFORMAT1
:
1327 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
1329 case D3DFVF_TEXTUREFORMAT2
:
1330 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
1332 case D3DFVF_TEXTUREFORMAT3
:
1333 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
1335 case D3DFVF_TEXTUREFORMAT4
:
1336 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
1341 declaration
[idx
] = end_element
;
1346 /*************************************************************************
1347 * D3DXFVFFromDeclarator
1349 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
1351 unsigned int i
= 0, texture
, offset
;
1353 TRACE("(%p, %p)\n", declaration
, fvf
);
1356 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
1358 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
1359 declaration
[1].UsageIndex
== 0) &&
1360 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
1361 declaration
[2].UsageIndex
== 0))
1363 return D3DERR_INVALIDCALL
;
1365 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
1366 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
1368 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
1370 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
1374 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
1378 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
1379 declaration
[1].UsageIndex
== 0)
1381 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
1382 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
1384 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
1386 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
1390 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
1392 switch (declaration
[1].Type
)
1394 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
1395 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
1396 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
1397 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
1403 switch (declaration
[1].Type
)
1405 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
1406 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
1407 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
1408 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
1419 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
1420 declaration
[0].UsageIndex
== 0)
1422 *fvf
|= D3DFVF_XYZRHW
;
1426 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
1428 *fvf
|= D3DFVF_NORMAL
;
1431 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
1432 declaration
[i
].UsageIndex
== 0)
1434 *fvf
|= D3DFVF_PSIZE
;
1437 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
1438 declaration
[i
].UsageIndex
== 0)
1440 *fvf
|= D3DFVF_DIFFUSE
;
1443 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
1444 declaration
[i
].UsageIndex
== 1)
1446 *fvf
|= D3DFVF_SPECULAR
;
1450 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
1452 if (declaration
[i
].Stream
== 0xFF)
1456 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1457 declaration
[i
].UsageIndex
== texture
)
1459 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
1461 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1462 declaration
[i
].UsageIndex
== texture
)
1464 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
1466 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1467 declaration
[i
].UsageIndex
== texture
)
1469 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
1471 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1472 declaration
[i
].UsageIndex
== texture
)
1474 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
1478 return D3DERR_INVALIDCALL
;
1482 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
1484 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
1485 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
1487 if (declaration
[i
].Offset
!= offset
)
1489 return D3DERR_INVALIDCALL
;
1496 /*************************************************************************
1497 * D3DXGetFVFVertexSize
1499 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
1501 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
1504 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
1508 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
1510 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
1511 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
1512 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
1513 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
1515 switch (FVF
& D3DFVF_POSITION_MASK
)
1517 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
1518 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
1519 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
1520 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
1521 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
1522 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
1523 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
1524 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
1527 for (i
= 0; i
< numTextures
; i
++)
1529 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
1535 /*************************************************************************
1536 * D3DXGetDeclVertexSize
1538 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
1540 const D3DVERTEXELEMENT9
*element
;
1543 TRACE("decl %p, stream_idx %u\n", decl
, stream_idx
);
1545 if (!decl
) return 0;
1547 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
1551 if (element
->Stream
!= stream_idx
) continue;
1553 if (element
->Type
>= sizeof(d3dx_decltype_size
) / sizeof(*d3dx_decltype_size
))
1555 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
1559 type_size
= d3dx_decltype_size
[element
->Type
];
1560 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
1566 /*************************************************************************
1569 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
1571 const D3DVERTEXELEMENT9
*element
;
1573 TRACE("decl %p\n", decl
);
1575 /* null decl results in exception on Windows XP */
1577 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
1579 return element
- decl
;
1582 /*************************************************************************
1585 BOOL WINAPI
D3DXIntersectTri(CONST D3DXVECTOR3
*p0
, CONST D3DXVECTOR3
*p1
, CONST D3DXVECTOR3
*p2
, CONST D3DXVECTOR3
*praypos
, CONST D3DXVECTOR3
*praydir
, FLOAT
*pu
, FLOAT
*pv
, FLOAT
*pdist
)
1590 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
1591 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
1592 m
.u
.m
[2][0] = -praydir
->x
;
1594 m
.u
.m
[0][1] = p1
->y
- p0
->z
;
1595 m
.u
.m
[1][1] = p2
->y
- p0
->z
;
1596 m
.u
.m
[2][1] = -praydir
->y
;
1598 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
1599 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
1600 m
.u
.m
[2][2] = -praydir
->z
;
1607 vec
.x
= praypos
->x
- p0
->x
;
1608 vec
.y
= praypos
->y
- p0
->y
;
1609 vec
.z
= praypos
->z
- p0
->z
;
1612 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
1614 D3DXVec4Transform(&vec
, &vec
, &m
);
1615 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
1619 *pdist
= fabs( vec
.z
);
1627 /*************************************************************************
1628 * D3DXSphereBoundProbe
1630 BOOL WINAPI
D3DXSphereBoundProbe(CONST D3DXVECTOR3
*pcenter
, FLOAT radius
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
1632 D3DXVECTOR3 difference
;
1635 a
= D3DXVec3LengthSq(praydirection
);
1636 if (!D3DXVec3Subtract(&difference
, prayposition
, pcenter
)) return FALSE
;
1637 b
= D3DXVec3Dot(&difference
, praydirection
);
1638 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
1641 if ( ( d
<= 0.0f
) || ( sqrt(d
) <= b
) ) return FALSE
;
1645 /*************************************************************************
1648 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
, CONST D3DVERTEXELEMENT9
*declaration
,
1649 LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
)
1653 IDirect3DVertexDeclaration9
*vertex_declaration
;
1654 IDirect3DVertexBuffer9
*vertex_buffer
;
1655 IDirect3DIndexBuffer9
*index_buffer
;
1656 DWORD
*attrib_buffer
;
1657 ID3DXMeshImpl
*object
;
1658 DWORD index_usage
= 0;
1659 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
1660 D3DFORMAT index_format
= D3DFMT_INDEX16
;
1661 DWORD vertex_usage
= 0;
1662 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
1665 TRACE("(%d, %d, %x, %p, %p, %p)\n", numfaces
, numvertices
, options
, declaration
, device
, mesh
);
1667 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
1668 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
1669 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
1671 return D3DERR_INVALIDCALL
;
1673 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1674 if (declaration
[i
].Stream
!= 0)
1675 return D3DERR_INVALIDCALL
;
1677 if (options
& D3DXMESH_32BIT
)
1678 index_format
= D3DFMT_INDEX32
;
1680 if (options
& D3DXMESH_DONOTCLIP
) {
1681 index_usage
|= D3DUSAGE_DONOTCLIP
;
1682 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
1684 if (options
& D3DXMESH_POINTS
) {
1685 index_usage
|= D3DUSAGE_POINTS
;
1686 vertex_usage
|= D3DUSAGE_POINTS
;
1688 if (options
& D3DXMESH_RTPATCHES
) {
1689 index_usage
|= D3DUSAGE_RTPATCHES
;
1690 vertex_usage
|= D3DUSAGE_RTPATCHES
;
1692 if (options
& D3DXMESH_NPATCHES
) {
1693 index_usage
|= D3DUSAGE_NPATCHES
;
1694 vertex_usage
|= D3DUSAGE_NPATCHES
;
1697 if (options
& D3DXMESH_VB_SYSTEMMEM
)
1698 vertex_pool
= D3DPOOL_SYSTEMMEM
;
1699 else if (options
& D3DXMESH_VB_MANAGED
)
1700 vertex_pool
= D3DPOOL_MANAGED
;
1702 if (options
& D3DXMESH_VB_WRITEONLY
)
1703 vertex_usage
|= D3DUSAGE_WRITEONLY
;
1704 if (options
& D3DXMESH_VB_DYNAMIC
)
1705 vertex_usage
|= D3DUSAGE_DYNAMIC
;
1706 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
1707 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
1709 if (options
& D3DXMESH_IB_SYSTEMMEM
)
1710 index_pool
= D3DPOOL_SYSTEMMEM
;
1711 else if (options
& D3DXMESH_IB_MANAGED
)
1712 index_pool
= D3DPOOL_MANAGED
;
1714 if (options
& D3DXMESH_IB_WRITEONLY
)
1715 index_usage
|= D3DUSAGE_WRITEONLY
;
1716 if (options
& D3DXMESH_IB_DYNAMIC
)
1717 index_usage
|= D3DUSAGE_DYNAMIC
;
1718 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
1719 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
1721 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
1727 /* Create vertex declaration */
1728 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
1730 &vertex_declaration
);
1733 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
1737 /* Create vertex buffer */
1738 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
1739 numvertices
* D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
),
1747 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
1748 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1752 /* Create index buffer */
1753 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
1754 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
1762 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
1763 IDirect3DVertexBuffer9_Release(vertex_buffer
);
1764 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1768 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
1769 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ID3DXMeshImpl
));
1770 if (object
== NULL
|| attrib_buffer
== NULL
)
1772 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
1773 IDirect3DIndexBuffer9_Release(index_buffer
);
1774 IDirect3DVertexBuffer9_Release(vertex_buffer
);
1775 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1777 return E_OUTOFMEMORY
;
1779 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
1782 object
->numfaces
= numfaces
;
1783 object
->numvertices
= numvertices
;
1784 object
->options
= options
;
1786 object
->device
= device
;
1787 IDirect3DDevice9_AddRef(device
);
1789 object
->vertex_declaration
= vertex_declaration
;
1790 object
->vertex_buffer
= vertex_buffer
;
1791 object
->index_buffer
= index_buffer
;
1792 object
->attrib_buffer
= attrib_buffer
;
1794 *mesh
= &object
->ID3DXMesh_iface
;
1799 /*************************************************************************
1802 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
, DWORD fvf
,
1803 LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
)
1806 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
1808 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
1810 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
1811 if (FAILED(hr
)) return hr
;
1813 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
1819 DWORD num_poly_faces
;
1820 DWORD num_tri_faces
;
1821 D3DXVECTOR3
*vertices
;
1822 DWORD
*num_tri_per_face
;
1827 /* optional mesh data */
1830 D3DXVECTOR3
*normals
;
1831 DWORD
*normal_indices
;
1834 static HRESULT
get_next_child(IDirectXFileData
*filedata
, IDirectXFileData
**child
, const GUID
**type
)
1837 IDirectXFileDataReference
*child_ref
= NULL
;
1838 IDirectXFileObject
*child_obj
= NULL
;
1839 IDirectXFileData
*child_data
= NULL
;
1841 hr
= IDirectXFileData_GetNextObject(filedata
, &child_obj
);
1842 if (FAILED(hr
)) return hr
;
1844 hr
= IDirectXFileObject_QueryInterface(child_obj
, &IID_IDirectXFileDataReference
, (void**)&child_ref
);
1845 if (SUCCEEDED(hr
)) {
1846 hr
= IDirectXFileDataReference_Resolve(child_ref
, &child_data
);
1847 IDirectXFileDataReference_Release(child_ref
);
1849 hr
= IDirectXFileObject_QueryInterface(child_obj
, &IID_IDirectXFileData
, (void**)&child_data
);
1851 IDirectXFileObject_Release(child_obj
);
1855 hr
= IDirectXFileData_GetType(child_data
, type
);
1857 IDirectXFileData_Release(child_data
);
1859 *child
= child_data
;
1865 static HRESULT
parse_normals(IDirectXFileData
*filedata
, struct mesh_data
*mesh
)
1870 DWORD
*index_out_ptr
;
1872 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
1874 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
1875 mesh
->num_normals
= 0;
1876 mesh
->normals
= NULL
;
1877 mesh
->normal_indices
= NULL
;
1878 mesh
->fvf
|= D3DFVF_NORMAL
;
1880 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
1881 if (FAILED(hr
)) return hr
;
1883 /* template Vector {
1888 * template MeshFace {
1889 * DWORD nFaceVertexIndices;
1890 * array DWORD faceVertexIndices[nFaceVertexIndices];
1892 * template MeshNormals {
1894 * array Vector normals[nNormals];
1895 * DWORD nFaceNormals;
1896 * array MeshFace faceNormals[nFaceNormals];
1900 if (data_size
< sizeof(DWORD
) * 2)
1901 goto truncated_data_error
;
1902 mesh
->num_normals
= *(DWORD
*)data
;
1903 data
+= sizeof(DWORD
);
1904 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
1905 num_face_indices
* sizeof(DWORD
))
1906 goto truncated_data_error
;
1908 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
1909 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
1910 if (!mesh
->normals
|| !mesh
->normal_indices
)
1911 return E_OUTOFMEMORY
;
1913 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
1914 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
1915 for (i
= 0; i
< mesh
->num_normals
; i
++)
1916 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
1918 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
1919 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
1920 *(DWORD
*)data
, mesh
->num_poly_faces
);
1923 data
+= sizeof(DWORD
);
1924 index_out_ptr
= mesh
->normal_indices
;
1925 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
1928 DWORD count
= *(DWORD
*)data
;
1929 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
1930 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
1931 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
1934 data
+= sizeof(DWORD
);
1936 for (j
= 0; j
< count
; j
++) {
1937 DWORD normal_index
= *(DWORD
*)data
;
1938 if (normal_index
>= mesh
->num_normals
) {
1939 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
1940 i
, j
, normal_index
, mesh
->num_normals
);
1943 *index_out_ptr
++ = normal_index
;
1944 data
+= sizeof(DWORD
);
1949 truncated_data_error
:
1950 WARN("truncated data (%u bytes)\n", data_size
);
1954 /* for provide_flags parameters */
1955 #define PROVIDE_MATERIALS 0x1
1956 #define PROVIDE_SKININFO 0x2
1958 static HRESULT
parse_mesh(IDirectXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
1962 BYTE
*data
, *in_ptr
;
1963 DWORD
*index_out_ptr
;
1965 IDirectXFileData
*child
;
1971 * array Vector vertices[nVertices];
1973 * array MeshFace faces[nFaces];
1978 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
1979 if (FAILED(hr
)) return hr
;
1982 if (data_size
< sizeof(DWORD
) * 2)
1983 goto truncated_data_error
;
1984 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
1985 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
))
1986 goto truncated_data_error
;
1987 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
1989 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
1990 in_ptr
+= sizeof(DWORD
);
1992 mesh_data
->num_tri_faces
= 0;
1993 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
1995 DWORD num_poly_vertices
;
1998 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
))
1999 goto truncated_data_error
;
2000 num_poly_vertices
= *(DWORD
*)in_ptr
;
2001 in_ptr
+= sizeof(DWORD
);
2002 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
))
2003 goto truncated_data_error
;
2004 if (num_poly_vertices
< 3) {
2005 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
2008 for (j
= 0; j
< num_poly_vertices
; j
++) {
2009 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
2010 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
2011 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
2014 in_ptr
+= sizeof(DWORD
);
2016 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
2019 mesh_data
->fvf
= D3DFVF_XYZ
;
2021 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
2022 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
2023 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
2024 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
2025 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
2026 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
2027 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
)
2028 return E_OUTOFMEMORY
;
2030 in_ptr
= data
+ sizeof(DWORD
);
2031 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
2032 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
2034 index_out_ptr
= mesh_data
->indices
;
2035 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
2039 count
= *(DWORD
*)in_ptr
;
2040 in_ptr
+= sizeof(DWORD
);
2041 mesh_data
->num_tri_per_face
[i
] = count
- 2;
2044 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
2045 in_ptr
+= sizeof(DWORD
);
2049 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
2051 if (IsEqualGUID(type
, &TID_D3DRMMeshNormals
)) {
2052 hr
= parse_normals(child
, mesh_data
);
2053 } else if (IsEqualGUID(type
, &TID_D3DRMMeshVertexColors
)) {
2054 FIXME("Mesh vertex color loading not implemented.\n");
2056 } else if (IsEqualGUID(type
, &TID_D3DRMMeshTextureCoords
)) {
2057 FIXME("Mesh texture coordinate loading not implemented.\n");
2059 } else if (IsEqualGUID(type
, &TID_D3DRMMeshMaterialList
) &&
2060 (provide_flags
& PROVIDE_MATERIALS
))
2062 FIXME("Mesh material list loading not implemented.\n");
2064 } else if (provide_flags
& PROVIDE_SKININFO
) {
2065 if (IsEqualGUID(type
, &DXFILEOBJ_XSkinMeshHeader
)) {
2066 FIXME("Skin mesh loading not implemented.\n");
2068 } else if (IsEqualGUID(type
, &DXFILEOBJ_SkinWeights
)) {
2069 /* ignored without XSkinMeshHeader */
2075 return hr
== DXFILEERR_NOMOREOBJECTS
? D3D_OK
: hr
;
2076 truncated_data_error
:
2077 WARN("truncated data (%u bytes)\n", data_size
);
2081 /* change to D3DXLoadSkinMeshFromXof when ID3DXFileData is implemented */
2082 static HRESULT
load_skin_mesh_from_xof(IDirectXFileData
*filedata
,
2084 LPDIRECT3DDEVICE9 device
,
2085 LPD3DXBUFFER
*adjacency_out
,
2086 LPD3DXBUFFER
*materials_out
,
2087 LPD3DXBUFFER
*effects_out
,
2088 DWORD
*num_materials_out
,
2089 LPD3DXSKININFO
*skin_info_out
,
2090 LPD3DXMESH
*mesh_out
)
2093 DWORD
*index_in_ptr
;
2094 struct mesh_data mesh_data
;
2095 DWORD total_vertices
;
2096 ID3DXMesh
*d3dxmesh
= NULL
;
2097 ID3DXBuffer
*adjacency
= NULL
;
2098 struct vertex_duplication
{
2101 } *duplications
= NULL
;
2103 void *vertices
= NULL
;
2104 void *indices
= NULL
;
2106 DWORD provide_flags
= 0;
2108 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
2110 if (num_materials_out
|| materials_out
|| effects_out
)
2111 provide_flags
|= PROVIDE_MATERIALS
;
2113 provide_flags
|= PROVIDE_SKININFO
;
2115 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
2116 if (FAILED(hr
)) goto cleanup
;
2118 total_vertices
= mesh_data
.num_vertices
;
2119 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
2120 /* duplicate vertices with multiple normals */
2121 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
2122 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
2123 if (!duplications
) {
2127 for (i
= 0; i
< total_vertices
; i
++)
2129 duplications
[i
].normal_index
= -1;
2130 list_init(&duplications
[i
].entry
);
2132 for (i
= 0; i
< num_face_indices
; i
++) {
2133 DWORD vertex_index
= mesh_data
.indices
[i
];
2134 DWORD normal_index
= mesh_data
.normal_indices
[i
];
2135 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
2137 if (dup_ptr
->normal_index
== -1) {
2138 dup_ptr
->normal_index
= normal_index
;
2140 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
2141 struct list
*dup_list
= &dup_ptr
->entry
;
2143 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
2144 if (new_normal
->x
== cur_normal
->x
&&
2145 new_normal
->y
== cur_normal
->y
&&
2146 new_normal
->z
== cur_normal
->z
)
2148 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
2150 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
2151 dup_ptr
= &duplications
[total_vertices
++];
2152 dup_ptr
->normal_index
= normal_index
;
2153 list_add_tail(dup_list
, &dup_ptr
->entry
);
2154 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
2157 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
2158 struct vertex_duplication
, entry
);
2165 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, D3DXMESH_MANAGED
, mesh_data
.fvf
, device
, &d3dxmesh
);
2166 if (FAILED(hr
)) goto cleanup
;
2168 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, D3DLOCK_DISCARD
, &vertices
);
2169 if (FAILED(hr
)) goto cleanup
;
2172 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
2173 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
2174 out_ptr
+= sizeof(D3DXVECTOR3
);
2175 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
2176 if (duplications
[i
].normal_index
== -1)
2177 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
2179 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
2180 out_ptr
+= sizeof(D3DXVECTOR3
);
2183 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
2184 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
2186 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
2187 struct vertex_duplication
*dup_ptr
;
2188 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
2190 int j
= dup_ptr
- duplications
;
2191 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
2193 memcpy(dest_vertex
, out_ptr
, vertex_size
);
2194 dest_vertex
+= sizeof(D3DXVECTOR3
);
2195 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
2197 out_ptr
+= vertex_size
;
2200 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
2202 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, D3DLOCK_DISCARD
, (void**)&indices
);
2203 if (FAILED(hr
)) goto cleanup
;
2205 index_in_ptr
= mesh_data
.indices
;
2206 #define FILL_INDEX_BUFFER(indices_var) \
2207 for (i = 0; i < mesh_data.num_poly_faces; i++) \
2209 DWORD count = mesh_data.num_tri_per_face[i]; \
2210 WORD first_index = *index_in_ptr++; \
2212 *indices_var++ = first_index; \
2213 *indices_var++ = *index_in_ptr; \
2215 *indices_var++ = *index_in_ptr; \
2219 if (options
& D3DXMESH_32BIT
) {
2220 DWORD
*dword_indices
= indices
;
2221 FILL_INDEX_BUFFER(dword_indices
)
2223 WORD
*word_indices
= indices
;
2224 FILL_INDEX_BUFFER(word_indices
)
2226 #undef FILL_INDEX_BUFFER
2227 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
2229 if (adjacency_out
) {
2230 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
2231 if (FAILED(hr
)) goto cleanup
;
2232 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
2233 if (FAILED(hr
)) goto cleanup
;
2236 *mesh_out
= d3dxmesh
;
2237 if (adjacency_out
) *adjacency_out
= adjacency
;
2238 if (num_materials_out
) *num_materials_out
= 0;
2239 if (materials_out
) *materials_out
= NULL
;
2240 if (effects_out
) *effects_out
= NULL
;
2241 if (skin_info_out
) *skin_info_out
= NULL
;
2246 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
2247 if (adjacency
) ID3DXBuffer_Release(adjacency
);
2249 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
2250 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
2251 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
2252 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
2253 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
2254 HeapFree(GetProcessHeap(), 0, duplications
);
2258 static HRESULT
filedata_get_name(IDirectXFileData
*filedata
, char **name
)
2263 hr
= IDirectXFileData_GetName(filedata
, NULL
, &name_len
);
2264 if (FAILED(hr
)) return hr
;
2268 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
2269 if (!*name
) return E_OUTOFMEMORY
;
2271 hr
= IDirectXFileObject_GetName(filedata
, *name
, &name_len
);
2273 HeapFree(GetProcessHeap(), 0, name
);
2280 static HRESULT
load_mesh_container(IDirectXFileData
*filedata
,
2282 LPDIRECT3DDEVICE9 device
,
2283 LPD3DXALLOCATEHIERARCHY alloc_hier
,
2284 D3DXMESHCONTAINER
**mesh_container
)
2287 ID3DXBuffer
*adjacency
= NULL
;
2288 ID3DXBuffer
*materials
= NULL
;
2289 ID3DXBuffer
*effects
= NULL
;
2290 ID3DXSkinInfo
*skin_info
= NULL
;
2291 D3DXMESHDATA mesh_data
;
2292 DWORD num_materials
= 0;
2295 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
2296 mesh_data
.u
.pMesh
= NULL
;
2298 hr
= load_skin_mesh_from_xof(filedata
, options
, device
,
2299 &adjacency
, &materials
, &effects
, &num_materials
,
2300 &skin_info
, &mesh_data
.u
.pMesh
);
2301 if (FAILED(hr
)) return hr
;
2303 hr
= filedata_get_name(filedata
, &name
);
2304 if (FAILED(hr
)) goto cleanup
;
2306 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
2307 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
2308 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
2310 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
2311 skin_info
, mesh_container
);
2314 if (materials
) ID3DXBuffer_Release(materials
);
2315 if (effects
) ID3DXBuffer_Release(effects
);
2316 if (adjacency
) ID3DXBuffer_Release(adjacency
);
2317 if (skin_info
) IUnknown_Release(skin_info
);
2318 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
2319 HeapFree(GetProcessHeap(), 0, name
);
2323 static HRESULT
parse_transform_matrix(IDirectXFileData
*filedata
, D3DXMATRIX
*transform
)
2329 /* template Matrix4x4 {
2330 * array FLOAT matrix[16];
2332 * template FrameTransformMatrix {
2333 * Matrix4x4 frameMatrix;
2337 hr
= IDirectXFileData_GetData(filedata
, NULL
, &data_size
, (void**)&data
);
2338 if (FAILED(hr
)) return hr
;
2340 if (data_size
!= sizeof(D3DXMATRIX
)) {
2341 WARN("incorrect data size (%u bytes)\n", data_size
);
2345 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
2350 static HRESULT
load_frame(IDirectXFileData
*filedata
,
2352 LPDIRECT3DDEVICE9 device
,
2353 LPD3DXALLOCATEHIERARCHY alloc_hier
,
2354 D3DXFRAME
**frame_out
)
2358 IDirectXFileData
*child
;
2360 D3DXFRAME
*frame
= NULL
;
2361 D3DXMESHCONTAINER
**next_container
;
2362 D3DXFRAME
**next_child
;
2364 hr
= filedata_get_name(filedata
, &name
);
2365 if (FAILED(hr
)) return hr
;
2367 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
2368 HeapFree(GetProcessHeap(), 0, name
);
2369 if (FAILED(hr
)) return E_FAIL
;
2372 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
2373 next_child
= &frame
->pFrameFirstChild
;
2374 next_container
= &frame
->pMeshContainer
;
2376 while (SUCCEEDED(hr
= get_next_child(filedata
, &child
, &type
)))
2378 if (IsEqualGUID(type
, &TID_D3DRMMesh
)) {
2379 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
2381 next_container
= &(*next_container
)->pNextMeshContainer
;
2382 } else if (IsEqualGUID(type
, &TID_D3DRMFrameTransformMatrix
)) {
2383 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
2384 } else if (IsEqualGUID(type
, &TID_D3DRMFrame
)) {
2385 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
2387 next_child
= &(*next_child
)->pFrameSibling
;
2389 if (FAILED(hr
)) break;
2391 if (hr
== DXFILEERR_NOMOREOBJECTS
)
2397 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(LPCVOID memory
,
2400 LPDIRECT3DDEVICE9 device
,
2401 LPD3DXALLOCATEHIERARCHY alloc_hier
,
2402 LPD3DXLOADUSERDATA load_user_data
,
2403 LPD3DXFRAME
*frame_hierarchy
,
2404 LPD3DXANIMATIONCONTROLLER
*anim_controller
)
2407 IDirectXFile
*dxfile
= NULL
;
2408 IDirectXFileEnumObject
*enumobj
= NULL
;
2409 IDirectXFileData
*filedata
= NULL
;
2410 DXFILELOADMEMORY source
;
2411 D3DXFRAME
*first_frame
= NULL
;
2412 D3DXFRAME
**next_frame
= &first_frame
;
2414 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
2415 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
2417 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
2418 return D3DERR_INVALIDCALL
;
2419 if (load_user_data
|| anim_controller
) {
2421 FIXME("Loading user data not implemented\n");
2422 if (anim_controller
)
2423 FIXME("Animation controller creation not implemented\n");
2427 hr
= DirectXFileCreate(&dxfile
);
2428 if (FAILED(hr
)) goto cleanup
;
2430 hr
= IDirectXFile_RegisterTemplates(dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
2431 if (FAILED(hr
)) goto cleanup
;
2433 source
.lpMemory
= (void*)memory
;
2434 source
.dSize
= memory_size
;
2435 hr
= IDirectXFile_CreateEnumObject(dxfile
, &source
, DXFILELOAD_FROMMEMORY
, &enumobj
);
2436 if (FAILED(hr
)) goto cleanup
;
2438 while (SUCCEEDED(hr
= IDirectXFileEnumObject_GetNextDataObject(enumobj
, &filedata
)))
2440 const GUID
*guid
= NULL
;
2442 hr
= IDirectXFileData_GetType(filedata
, &guid
);
2443 if (SUCCEEDED(hr
)) {
2444 if (IsEqualGUID(guid
, &TID_D3DRMMesh
)) {
2445 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
2451 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
2453 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
2454 if (FAILED(hr
)) goto cleanup
;
2455 } else if (IsEqualGUID(guid
, &TID_D3DRMFrame
)) {
2456 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
2457 if (FAILED(hr
)) goto cleanup
;
2460 next_frame
= &(*next_frame
)->pFrameSibling
;
2463 IDirectXFileData_Release(filedata
);
2468 if (hr
!= DXFILEERR_NOMOREOBJECTS
)
2473 } else if (first_frame
->pFrameSibling
) {
2474 D3DXFRAME
*root_frame
= NULL
;
2475 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
2480 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
2481 root_frame
->pFrameFirstChild
= first_frame
;
2482 *frame_hierarchy
= root_frame
;
2485 *frame_hierarchy
= first_frame
;
2490 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
2491 if (filedata
) IDirectXFileData_Release(filedata
);
2492 if (enumobj
) IDirectXFileEnumObject_Release(enumobj
);
2493 if (dxfile
) IDirectXFile_Release(dxfile
);
2497 HRESULT WINAPI
D3DXFrameDestroy(LPD3DXFRAME frame
, LPD3DXALLOCATEHIERARCHY alloc_hier
)
2502 TRACE("(%p, %p)\n", frame
, alloc_hier
);
2504 if (!frame
|| !alloc_hier
)
2505 return D3DERR_INVALIDCALL
;
2508 D3DXMESHCONTAINER
*container
;
2509 D3DXFRAME
*current_frame
;
2511 if (frame
->pFrameSibling
) {
2512 current_frame
= frame
->pFrameSibling
;
2513 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
2514 current_frame
->pFrameSibling
= NULL
;
2516 current_frame
= frame
;
2520 if (current_frame
->pFrameFirstChild
) {
2521 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
2522 if (FAILED(hr
)) return hr
;
2523 current_frame
->pFrameFirstChild
= NULL
;
2526 container
= current_frame
->pMeshContainer
;
2528 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
2529 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
2530 if (FAILED(hr
)) return hr
;
2531 container
= next_container
;
2533 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
2534 if (FAILED(hr
)) return hr
;
2539 HRESULT WINAPI
D3DXCreateBox(LPDIRECT3DDEVICE9 device
, FLOAT width
, FLOAT height
,
2540 FLOAT depth
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
2542 FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device
, width
, height
, depth
, mesh
, adjacency
);
2549 D3DXVECTOR3 position
;
2553 typedef WORD face
[3];
2561 static void free_sincos_table(struct sincos_table
*sincos_table
)
2563 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
2564 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
2567 /* pre compute sine and cosine tables; caller must free */
2568 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
2573 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
2574 if (!sincos_table
->sin
)
2578 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
2579 if (!sincos_table
->cos
)
2581 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
2585 angle
= angle_start
;
2586 for (i
= 0; i
< n
; i
++)
2588 sincos_table
->sin
[i
] = sin(angle
);
2589 sincos_table
->cos
[i
] = cos(angle
);
2590 angle
+= angle_step
;
2596 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
2598 return stack
*slices
+slice
+1;
2601 HRESULT WINAPI
D3DXCreateSphere(LPDIRECT3DDEVICE9 device
, FLOAT radius
, UINT slices
,
2602 UINT stacks
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
2604 DWORD number_of_vertices
, number_of_faces
;
2607 struct vertex
*vertices
;
2609 float phi_step
, phi_start
;
2610 struct sincos_table phi
;
2611 float theta_step
, theta
, sin_theta
, cos_theta
;
2615 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
2617 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
2619 return D3DERR_INVALIDCALL
;
2624 FIXME("Case of adjacency != NULL not implemented.\n");
2628 number_of_vertices
= 2 + slices
* (stacks
-1);
2629 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
2631 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
2632 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
2638 hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
2641 sphere
->lpVtbl
->Release(sphere
);
2645 hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
2648 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
2649 sphere
->lpVtbl
->Release(sphere
);
2653 /* phi = angle on xz plane wrt z axis */
2654 phi_step
= -2 * M_PI
/ slices
;
2655 phi_start
= M_PI
/ 2;
2657 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
2659 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
2660 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
2661 sphere
->lpVtbl
->Release(sphere
);
2662 return E_OUTOFMEMORY
;
2665 /* theta = angle on xy plane wrt x axis */
2666 theta_step
= M_PI
/ stacks
;
2673 vertices
[vertex
].normal
.x
= 0.0f
;
2674 vertices
[vertex
].normal
.y
= 0.0f
;
2675 vertices
[vertex
].normal
.z
= 1.0f
;
2676 vertices
[vertex
].position
.x
= 0.0f
;
2677 vertices
[vertex
].position
.y
= 0.0f
;
2678 vertices
[vertex
].position
.z
= radius
;
2681 for (stack
= 0; stack
< stacks
- 1; stack
++)
2683 sin_theta
= sin(theta
);
2684 cos_theta
= cos(theta
);
2686 for (slice
= 0; slice
< slices
; slice
++)
2688 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
2689 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
2690 vertices
[vertex
].normal
.z
= cos_theta
;
2691 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
2692 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
2693 vertices
[vertex
].position
.z
= radius
* cos_theta
;
2700 /* top stack is triangle fan */
2702 faces
[face
][1] = slice
+ 1;
2703 faces
[face
][2] = slice
;
2708 /* stacks in between top and bottom are quad strips */
2709 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
2710 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
2711 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
2714 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
2715 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
2716 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
2722 theta
+= theta_step
;
2728 faces
[face
][2] = slice
;
2733 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
2734 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
2735 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
2738 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
2739 faces
[face
][1] = vertex_index(slices
, 0, stack
);
2740 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
2745 vertices
[vertex
].position
.x
= 0.0f
;
2746 vertices
[vertex
].position
.y
= 0.0f
;
2747 vertices
[vertex
].position
.z
= -radius
;
2748 vertices
[vertex
].normal
.x
= 0.0f
;
2749 vertices
[vertex
].normal
.y
= 0.0f
;
2750 vertices
[vertex
].normal
.z
= -1.0f
;
2752 /* bottom stack is triangle fan */
2753 for (slice
= 1; slice
< slices
; slice
++)
2755 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
2756 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
2757 faces
[face
][2] = vertex
;
2761 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
2762 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
2763 faces
[face
][2] = vertex
;
2765 free_sincos_table(&phi
);
2766 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
2767 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
2773 HRESULT WINAPI
D3DXCreateCylinder(LPDIRECT3DDEVICE9 device
, FLOAT radius1
, FLOAT radius2
, FLOAT length
, UINT slices
,
2774 UINT stacks
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
2776 DWORD number_of_vertices
, number_of_faces
;
2778 ID3DXMesh
*cylinder
;
2779 struct vertex
*vertices
;
2781 float theta_step
, theta_start
;
2782 struct sincos_table theta
;
2783 float delta_radius
, radius
, radius_step
;
2784 float z
, z_step
, z_normal
;
2788 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
2790 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
2792 return D3DERR_INVALIDCALL
;
2797 FIXME("Case of adjacency != NULL not implemented.\n");
2801 number_of_vertices
= 2 + (slices
* (3 + stacks
));
2802 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
2804 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
2805 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
2811 hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
2814 cylinder
->lpVtbl
->Release(cylinder
);
2818 hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
2821 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
2822 cylinder
->lpVtbl
->Release(cylinder
);
2826 /* theta = angle on xy plane wrt x axis */
2827 theta_step
= -2 * M_PI
/ slices
;
2828 theta_start
= M_PI
/ 2;
2830 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
2832 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
2833 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
2834 cylinder
->lpVtbl
->Release(cylinder
);
2835 return E_OUTOFMEMORY
;
2841 delta_radius
= radius1
- radius2
;
2843 radius_step
= delta_radius
/ stacks
;
2846 z_step
= length
/ stacks
;
2847 z_normal
= delta_radius
/ length
;
2848 if (isnan(z_normal
))
2853 vertices
[vertex
].normal
.x
= 0.0f
;
2854 vertices
[vertex
].normal
.y
= 0.0f
;
2855 vertices
[vertex
].normal
.z
= -1.0f
;
2856 vertices
[vertex
].position
.x
= 0.0f
;
2857 vertices
[vertex
].position
.y
= 0.0f
;
2858 vertices
[vertex
++].position
.z
= z
;
2860 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
2862 vertices
[vertex
].normal
.x
= 0.0f
;
2863 vertices
[vertex
].normal
.y
= 0.0f
;
2864 vertices
[vertex
].normal
.z
= -1.0f
;
2865 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
2866 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
2867 vertices
[vertex
].position
.z
= z
;
2872 faces
[face
][1] = slice
;
2873 faces
[face
++][2] = slice
+ 1;
2878 faces
[face
][1] = slice
;
2879 faces
[face
++][2] = 1;
2881 for (stack
= 1; stack
<= stacks
+1; stack
++)
2883 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
2885 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
2886 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
2887 vertices
[vertex
].normal
.z
= z_normal
;
2888 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
2889 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
2890 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
2891 vertices
[vertex
].position
.z
= z
;
2893 if (stack
> 1 && slice
> 0)
2895 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
2896 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
2897 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
2899 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
2900 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
2901 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
2907 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
2908 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
2909 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
2911 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
2912 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
2913 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
2916 if (stack
< stacks
+ 1)
2919 radius
-= radius_step
;
2923 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
2925 vertices
[vertex
].normal
.x
= 0.0f
;
2926 vertices
[vertex
].normal
.y
= 0.0f
;
2927 vertices
[vertex
].normal
.z
= 1.0f
;
2928 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
2929 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
2930 vertices
[vertex
].position
.z
= z
;
2934 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
2935 faces
[face
][1] = number_of_vertices
- 1;
2936 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
2940 vertices
[vertex
].position
.x
= 0.0f
;
2941 vertices
[vertex
].position
.y
= 0.0f
;
2942 vertices
[vertex
].position
.z
= z
;
2943 vertices
[vertex
].normal
.x
= 0.0f
;
2944 vertices
[vertex
].normal
.y
= 0.0f
;
2945 vertices
[vertex
].normal
.z
= 1.0f
;
2947 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
2948 faces
[face
][1] = number_of_vertices
- 1;
2949 faces
[face
][2] = vertex_index(slices
, 0, stack
);
2951 free_sincos_table(&theta
);
2952 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
2953 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
2959 HRESULT WINAPI
D3DXCreateTeapot(LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
, LPD3DXBUFFER
* adjacency
)
2961 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
2966 HRESULT WINAPI
D3DXCreateTextA(LPDIRECT3DDEVICE9 device
,
2967 HDC hdc
, LPCSTR text
,
2968 FLOAT deviation
, FLOAT extrusion
,
2969 LPD3DXMESH
*mesh
, LPD3DXBUFFER
*adjacency
,
2970 LPGLYPHMETRICSFLOAT glyphmetrics
)
2976 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
2977 debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
2980 return D3DERR_INVALIDCALL
;
2982 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
2983 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2984 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
2986 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
2987 mesh
, adjacency
, glyphmetrics
);
2988 HeapFree(GetProcessHeap(), 0, textW
);
2994 POINTTYPE_CURVE
= 0,
2996 POINTTYPE_CURVE_START
,
2997 POINTTYPE_CURVE_END
,
2998 POINTTYPE_CURVE_MIDDLE
,
3004 enum pointtype corner
;
3007 struct dynamic_array
3009 int count
, capacity
;
3013 /* is a dynamic_array */
3016 int count
, capacity
;
3017 struct point2d
*items
;
3020 /* is a dynamic_array */
3021 struct outline_array
3023 int count
, capacity
;
3024 struct outline
*items
;
3033 struct point2d_index
3035 struct outline
*outline
;
3039 struct point2d_index_array
3042 struct point2d_index
*items
;
3047 struct outline_array outlines
;
3048 struct face_array faces
;
3049 struct point2d_index_array ordered_vertices
;
3053 /* is an dynamic_array */
3056 int count
, capacity
;
3060 /* complex polygons are split into monotone polygons, which have
3061 * at most 2 intersections with the vertical sweep line */
3062 struct triangulation
3064 struct word_array vertex_stack
;
3065 BOOL last_on_top
, merging
;
3068 /* is an dynamic_array */
3069 struct triangulation_array
3071 int count
, capacity
;
3072 struct triangulation
*items
;
3074 struct glyphinfo
*glyph
;
3077 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
3079 if (count
> array
->capacity
) {
3082 if (array
->items
&& array
->capacity
) {
3083 new_capacity
= max(array
->capacity
* 2, count
);
3084 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
3086 new_capacity
= max(16, count
);
3087 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
3091 array
->items
= new_buffer
;
3092 array
->capacity
= new_capacity
;
3097 static struct point2d
*add_points(struct outline
*array
, int num
)
3099 struct point2d
*item
;
3101 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
3104 item
= &array
->items
[array
->count
];
3105 array
->count
+= num
;
3109 static struct outline
*add_outline(struct outline_array
*array
)
3111 struct outline
*item
;
3113 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
3116 item
= &array
->items
[array
->count
++];
3117 ZeroMemory(item
, sizeof(*item
));
3121 static inline face
*add_face(struct face_array
*array
)
3123 return &array
->items
[array
->count
++];
3126 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
3128 struct triangulation
*item
;
3130 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
3133 item
= &array
->items
[array
->count
++];
3134 ZeroMemory(item
, sizeof(*item
));
3138 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
3140 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
3141 return E_OUTOFMEMORY
;
3143 array
->items
[array
->count
++] = vertex_index
;
3147 /* assume fixed point numbers can be converted to float point in place */
3148 C_ASSERT(sizeof(FIXED
) == sizeof(float));
3149 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
3151 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, float emsquare
)
3153 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
3155 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
3156 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
3157 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
3163 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
3164 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
3165 float max_deviation_sq
)
3167 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
3170 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
3171 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
3172 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
3174 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
3175 if (deviation_sq
< max_deviation_sq
) {
3176 struct point2d
*pt
= add_points(outline
, 1);
3177 if (!pt
) return E_OUTOFMEMORY
;
3179 pt
->corner
= POINTTYPE_CURVE
;
3180 /* the end point is omitted because the end line merges into the next segment of
3181 * the split bezier curve, and the end of the split bezier curve is added outside
3182 * this recursive function. */
3184 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
3185 if (hr
!= S_OK
) return hr
;
3186 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
3187 if (hr
!= S_OK
) return hr
;
3193 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
3195 /* dot product = cos(theta) */
3196 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
3199 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
3201 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
3211 static BOOL
attempt_line_merge(struct outline
*outline
,
3213 const D3DXVECTOR2
*nextpt
,
3215 const struct cos_table
*table
)
3217 D3DXVECTOR2 curdir
, lastdir
;
3218 struct point2d
*prevpt
, *pt
;
3221 pt
= &outline
->items
[pt_index
];
3222 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
3223 prevpt
= &outline
->items
[pt_index
];
3226 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
3228 if (outline
->count
< 2)
3231 /* remove last point if the next line continues the last line */
3232 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
3233 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
3234 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
3237 if (pt
->corner
== POINTTYPE_CURVE_END
)
3238 prevpt
->corner
= pt
->corner
;
3239 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
3240 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
3244 if (outline
->count
< 2)
3247 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
3248 prevpt
= &outline
->items
[pt_index
];
3249 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
3250 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
3255 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
3256 float max_deviation_sq
, float emsquare
, const struct cos_table
*cos_table
)
3258 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
3260 while ((char *)header
< (char *)raw_outline
+ datasize
)
3262 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
3263 struct point2d
*lastpt
, *pt
;
3264 D3DXVECTOR2 lastdir
;
3265 D3DXVECTOR2
*pt_flt
;
3267 struct outline
*outline
= add_outline(&glyph
->outlines
);
3270 return E_OUTOFMEMORY
;
3272 pt
= add_points(outline
, 1);
3274 return E_OUTOFMEMORY
;
3275 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
3277 pt
->corner
= POINTTYPE_CORNER
;
3279 if (header
->dwType
!= TT_POLYGON_TYPE
)
3280 FIXME("Unknown header type %d\n", header
->dwType
);
3282 while ((char *)curve
< (char *)header
+ header
->cb
)
3284 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
3285 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
3288 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
3292 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
3294 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
3299 int count
= curve
->cpfx
;
3304 D3DXVECTOR2 bezier_end
;
3306 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j
], &pt_flt
[j
+1]), 0.5f
);
3307 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j
], &bezier_end
, max_deviation_sq
);
3310 bezier_start
= bezier_end
;
3314 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j
], &pt_flt
[j
+1], max_deviation_sq
);
3318 pt
= add_points(outline
, 1);
3320 return E_OUTOFMEMORY
;
3322 pt
->pos
= pt_flt
[j
];
3323 pt
->corner
= POINTTYPE_CURVE_END
;
3325 pt
= add_points(outline
, curve
->cpfx
);
3327 return E_OUTOFMEMORY
;
3328 for (j
= 0; j
< curve
->cpfx
; j
++)
3330 pt
->pos
= pt_flt
[j
];
3331 pt
->corner
= POINTTYPE_CORNER
;
3336 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
3339 /* remove last point if the next line continues the last line */
3340 if (outline
->count
>= 3) {
3343 lastpt
= &outline
->items
[outline
->count
- 1];
3344 pt
= &outline
->items
[0];
3345 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
3346 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
3348 if (pt
->corner
== POINTTYPE_CURVE_START
)
3349 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
3351 pt
->corner
= POINTTYPE_CURVE_END
;
3354 lastpt
= &outline
->items
[outline
->count
- 1];
3356 /* outline closed with a line from end to start point */
3357 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
3359 lastpt
= &outline
->items
[0];
3360 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
3361 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
3362 lastpt
->corner
= POINTTYPE_CORNER
;
3363 pt
= &outline
->items
[1];
3364 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
3365 *lastpt
= outline
->items
[outline
->count
];
3368 lastpt
= &outline
->items
[outline
->count
- 1];
3369 pt
= &outline
->items
[0];
3370 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
3371 for (j
= 0; j
< outline
->count
; j
++)
3376 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
3377 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
3379 switch (lastpt
->corner
)
3381 case POINTTYPE_CURVE_START
:
3382 case POINTTYPE_CURVE_END
:
3383 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
3384 lastpt
->corner
= POINTTYPE_CORNER
;
3386 case POINTTYPE_CURVE_MIDDLE
:
3387 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
3388 lastpt
->corner
= POINTTYPE_CORNER
;
3390 lastpt
->corner
= POINTTYPE_CURVE
;
3398 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
3403 /* Get the y-distance from a line to a point */
3404 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
3405 D3DXVECTOR2
*line_pt2
,
3408 D3DXVECTOR2 line_vec
= {0, 0};
3412 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
3413 line_pt_dx
= point
->x
- line_pt1
->x
;
3414 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
3415 return point
->y
- line_y
;
3418 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
3420 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
3423 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
3425 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
3428 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
3430 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
3431 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
3435 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
3436 struct triangulation_array
*triangulations
,
3440 struct glyphinfo
*glyph
= triangulations
->glyph
;
3441 struct triangulation
*t
= *t_ptr
;
3446 if (t
->last_on_top
) {
3454 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
3455 /* consume all vertices on the stack */
3456 WORD last_pt
= t
->vertex_stack
.items
[0];
3458 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
3460 face
= add_face(&glyph
->faces
);
3461 if (!face
) return E_OUTOFMEMORY
;
3462 (*face
)[0] = vtx_idx
;
3463 (*face
)[f1
] = last_pt
;
3464 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
3466 t
->vertex_stack
.items
[0] = last_pt
;
3467 t
->vertex_stack
.count
= 1;
3468 } else if (t
->vertex_stack
.count
> 1) {
3469 int i
= t
->vertex_stack
.count
- 1;
3470 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
3471 WORD top_idx
= t
->vertex_stack
.items
[i
--];
3472 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
3476 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
3477 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
3479 if (prev_pt
->x
!= top_pt
->x
&&
3480 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
3481 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
3484 face
= add_face(&glyph
->faces
);
3485 if (!face
) return E_OUTOFMEMORY
;
3486 (*face
)[0] = vtx_idx
;
3487 (*face
)[f1
] = prev_idx
;
3488 (*face
)[f2
] = top_idx
;
3492 t
->vertex_stack
.count
--;
3495 t
->last_on_top
= to_top
;
3497 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
3499 if (hr
== S_OK
&& t
->merging
) {
3500 struct triangulation
*t2
;
3502 t2
= to_top
? t
- 1 : t
+ 1;
3503 t2
->merging
= FALSE
;
3504 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
3505 if (hr
!= S_OK
) return hr
;
3506 remove_triangulation(triangulations
, t
);
3514 /* check if the point is next on the outline for either the top or bottom */
3515 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
3517 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
3518 WORD idx
= t
->vertex_stack
.items
[i
];
3519 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
3520 struct outline
*outline
= pt_idx
->outline
;
3523 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
3525 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
3527 return &outline
->items
[i
].pos
;
3530 static int compare_vertex_indices(const void *a
, const void *b
)
3532 const struct point2d_index
*idx1
= a
, *idx2
= b
;
3533 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
3534 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
3535 float diff
= p1
->x
- p2
->x
;
3538 diff
= p1
->y
- p2
->y
;
3540 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
3543 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
3547 struct glyphinfo
*glyph
= triangulations
->glyph
;
3548 int nb_vertices
= 0;
3550 struct point2d_index
*idx_ptr
;
3552 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
3553 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
3555 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
3556 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
3557 if (!glyph
->ordered_vertices
.items
)
3558 return E_OUTOFMEMORY
;
3560 idx_ptr
= glyph
->ordered_vertices
.items
;
3561 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
3563 struct outline
*outline
= &glyph
->outlines
.items
[i
];
3566 idx_ptr
->outline
= outline
;
3567 idx_ptr
->vertex
= 0;
3569 for (j
= outline
->count
- 1; j
> 0; j
--)
3571 idx_ptr
->outline
= outline
;
3572 idx_ptr
->vertex
= j
;
3576 glyph
->ordered_vertices
.count
= nb_vertices
;
3578 /* Native implementation seems to try to create a triangle fan from
3579 * the first outline point if the glyph only has one outline. */
3580 if (glyph
->outlines
.count
== 1)
3582 struct outline
*outline
= glyph
->outlines
.items
;
3583 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
3584 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
3587 for (i
= 2; i
< outline
->count
; i
++)
3589 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
3590 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
3591 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
3593 D3DXVec2Subtract(&v1
, base
, last
);
3594 D3DXVec2Subtract(&v2
, last
, next
);
3595 ccw
= D3DXVec2CCW(&v1
, &v2
);
3603 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
3604 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
3605 if (!glyph
->faces
.items
)
3606 return E_OUTOFMEMORY
;
3608 glyph
->faces
.count
= outline
->count
- 2;
3609 for (i
= 0; i
< glyph
->faces
.count
; i
++)
3611 glyph
->faces
.items
[i
][0] = 0;
3612 glyph
->faces
.items
[i
][1] = i
+ 1;
3613 glyph
->faces
.items
[i
][2] = i
+ 2;
3619 /* Perform 2D polygon triangulation for complex glyphs.
3620 * Triangulation is performed using a sweep line concept, from right to left,
3621 * by processing vertices in sorted order. Complex polygons are split into
3622 * monotone polygons which are triangulated separately. */
3623 /* FIXME: The order of the faces is not consistent with the native implementation. */
3625 /* Reserve space for maximum possible faces from triangulation.
3626 * # faces for outer outlines = outline->count - 2
3627 * # faces for inner outlines = outline->count + 2
3628 * There must be at least 1 outer outline. */
3629 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
3630 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
3631 if (!glyph
->faces
.items
)
3632 return E_OUTOFMEMORY
;
3634 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
3635 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
3636 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
3639 int end
= triangulations
->count
;
3643 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
3644 int current
= (start
+ end
) / 2;
3645 struct triangulation
*t
= &triangulations
->items
[current
];
3646 BOOL on_top_outline
= FALSE
;
3647 D3DXVECTOR2
*top_next
, *bottom_next
;
3648 WORD top_idx
, bottom_idx
;
3650 if (t
->merging
&& t
->last_on_top
)
3651 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
3653 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
3654 if (sweep_vtx
== top_next
)
3656 if (t
->merging
&& t
->last_on_top
)
3658 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
3659 if (hr
!= S_OK
) return hr
;
3661 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
3662 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
3664 /* point also on bottom outline of higher triangulation */
3665 struct triangulation
*t2
= t
+ 1;
3666 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
3667 if (hr
!= S_OK
) return hr
;
3672 on_top_outline
= TRUE
;
3675 if (t
->merging
&& !t
->last_on_top
)
3676 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
3678 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
3679 if (sweep_vtx
== bottom_next
)
3681 if (t
->merging
&& !t
->last_on_top
)
3683 if (on_top_outline
) {
3684 /* outline finished */
3685 remove_triangulation(triangulations
, t
);
3689 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
3690 if (hr
!= S_OK
) return hr
;
3692 if (t
> triangulations
->items
&&
3693 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
3695 struct triangulation
*t2
= t
- 1;
3696 /* point also on top outline of lower triangulation */
3697 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
3698 if (hr
!= S_OK
) return hr
;
3699 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
3709 if (t
->last_on_top
) {
3710 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
3711 bottom_idx
= t
->vertex_stack
.items
[0];
3713 top_idx
= t
->vertex_stack
.items
[0];
3714 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
3717 /* check if the point is inside or outside this polygon */
3718 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
3719 top_next
, sweep_vtx
) > 0)
3721 start
= current
+ 1;
3722 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
3723 bottom_next
, sweep_vtx
) < 0)
3726 } else if (t
->merging
) {
3727 /* inside, so cancel merging */
3728 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
3730 t2
->merging
= FALSE
;
3731 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
3732 if (hr
!= S_OK
) return hr
;
3733 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
3734 if (hr
!= S_OK
) return hr
;
3737 /* inside, so split polygon into two monotone parts */
3738 struct triangulation
*t2
= add_triangulation(triangulations
);
3739 if (!t2
) return E_OUTOFMEMORY
;
3740 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
3741 if (t
->last_on_top
) {
3748 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
3749 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
3750 if (hr
!= S_OK
) return hr
;
3751 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
3752 if (hr
!= S_OK
) return hr
;
3753 t2
->last_on_top
= !t
->last_on_top
;
3755 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
3756 if (hr
!= S_OK
) return hr
;
3762 struct triangulation
*t
;
3763 struct triangulation
*t2
= add_triangulation(triangulations
);
3764 if (!t2
) return E_OUTOFMEMORY
;
3765 t
= &triangulations
->items
[start
];
3766 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
3767 ZeroMemory(t
, sizeof(*t
));
3768 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
3769 if (hr
!= S_OK
) return hr
;
3775 HRESULT WINAPI
D3DXCreateTextW(LPDIRECT3DDEVICE9 device
,
3776 HDC hdc
, LPCWSTR text
,
3777 FLOAT deviation
, FLOAT extrusion
,
3778 LPD3DXMESH
*mesh_ptr
, LPD3DXBUFFER
*adjacency
,
3779 LPGLYPHMETRICSFLOAT glyphmetrics
)
3782 ID3DXMesh
*mesh
= NULL
;
3783 DWORD nb_vertices
, nb_faces
;
3784 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
3785 struct vertex
*vertices
= NULL
;
3790 OUTLINETEXTMETRICW otm
;
3791 HFONT font
= NULL
, oldfont
= NULL
;
3792 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
3793 void *raw_outline
= NULL
;
3795 struct glyphinfo
*glyphs
= NULL
;
3797 struct triangulation_array triangulations
= {0, 0, NULL
};
3799 struct vertex
*vertex_ptr
;
3801 float max_deviation_sq
;
3802 const struct cos_table cos_table
= {
3803 cos(D3DXToRadian(0.5f
)),
3804 cos(D3DXToRadian(45.0f
)),
3805 cos(D3DXToRadian(90.0f
)),
3809 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
3810 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
3812 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
3813 return D3DERR_INVALIDCALL
;
3817 FIXME("Case of adjacency != NULL not implemented.\n");
3821 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
3822 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
3824 return D3DERR_INVALIDCALL
;
3827 if (deviation
== 0.0f
)
3828 deviation
= 1.0f
/ otm
.otmEMSquare
;
3829 max_deviation_sq
= deviation
* deviation
;
3831 lf
.lfHeight
= otm
.otmEMSquare
;
3833 font
= CreateFontIndirectW(&lf
);
3838 oldfont
= SelectObject(hdc
, font
);
3840 textlen
= strlenW(text
);
3841 for (i
= 0; i
< textlen
; i
++)
3843 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
3845 return D3DERR_INVALIDCALL
;
3846 if (bufsize
< datasize
)
3849 if (!bufsize
) { /* e.g. text == " " */
3850 hr
= D3DERR_INVALIDCALL
;
3854 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
3855 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
3856 if (!glyphs
|| !raw_outline
) {
3862 for (i
= 0; i
< textlen
; i
++)
3864 /* get outline points from data returned from GetGlyphOutline */
3867 glyphs
[i
].offset_x
= offset_x
;
3869 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
3870 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
3871 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
3872 if (hr
!= S_OK
) goto error
;
3874 triangulations
.glyph
= &glyphs
[i
];
3875 hr
= triangulate(&triangulations
);
3876 if (hr
!= S_OK
) goto error
;
3877 if (triangulations
.count
) {
3878 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
3879 triangulations
.count
= 0;
3884 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
3885 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
3886 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
3887 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
3888 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
3889 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
3891 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
3894 /* corner points need an extra vertex for the different side faces normals */
3896 nb_outline_points
= 0;
3898 for (i
= 0; i
< textlen
; i
++)
3901 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
3902 nb_front_faces
+= glyphs
[i
].faces
.count
;
3903 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
3906 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
3907 nb_corners
++; /* first outline point always repeated as a corner */
3908 for (k
= 1; k
< outline
->count
; k
++)
3909 if (outline
->items
[k
].corner
)
3914 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
3915 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
3918 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
3919 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
3923 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
3927 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
3931 /* convert 2D vertices and faces into 3D mesh */
3932 vertex_ptr
= vertices
;
3934 if (extrusion
== 0.0f
) {
3941 for (i
= 0; i
< textlen
; i
++)
3945 struct vertex
*back_vertices
;
3948 /* side vertices and faces */
3949 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
3951 struct vertex
*outline_vertices
= vertex_ptr
;
3952 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
3954 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
3955 struct point2d
*pt
= &outline
->items
[0];
3957 for (k
= 1; k
<= outline
->count
; k
++)
3960 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
3961 WORD vtx_idx
= vertex_ptr
- vertices
;
3964 if (pt
->corner
== POINTTYPE_CURVE_START
)
3965 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
3966 else if (pt
->corner
)
3967 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
3969 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
3970 D3DXVec2Normalize(&vec
, &vec
);
3971 vtx
.normal
.x
= -vec
.y
;
3972 vtx
.normal
.y
= vec
.x
;
3975 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
3976 vtx
.position
.y
= pt
->pos
.y
;
3978 *vertex_ptr
++ = vtx
;
3980 vtx
.position
.z
= -extrusion
;
3981 *vertex_ptr
++ = vtx
;
3983 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
3984 vtx
.position
.y
= nextpt
->pos
.y
;
3985 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
3986 vtx
.position
.z
= -extrusion
;
3987 *vertex_ptr
++ = vtx
;
3989 *vertex_ptr
++ = vtx
;
3991 (*face_ptr
)[0] = vtx_idx
;
3992 (*face_ptr
)[1] = vtx_idx
+ 2;
3993 (*face_ptr
)[2] = vtx_idx
+ 1;
3996 (*face_ptr
)[0] = vtx_idx
;
3997 (*face_ptr
)[1] = vtx_idx
+ 3;
3998 (*face_ptr
)[2] = vtx_idx
+ 2;
4001 if (nextpt
->corner
) {
4002 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
4003 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
4004 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
4006 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
4008 D3DXVec2Normalize(&vec
, &vec
);
4009 vtx
.normal
.x
= -vec
.y
;
4010 vtx
.normal
.y
= vec
.x
;
4013 *vertex_ptr
++ = vtx
;
4014 vtx
.position
.z
= -extrusion
;
4015 *vertex_ptr
++ = vtx
;
4018 (*face_ptr
)[0] = vtx_idx
;
4019 (*face_ptr
)[1] = vtx_idx
+ 3;
4020 (*face_ptr
)[2] = vtx_idx
+ 1;
4023 (*face_ptr
)[0] = vtx_idx
;
4024 (*face_ptr
)[1] = vtx_idx
+ 2;
4025 (*face_ptr
)[2] = vtx_idx
+ 3;
4033 *vertex_ptr
++ = *outline_vertices
++;
4034 *vertex_ptr
++ = *outline_vertices
++;
4038 /* back vertices and faces */
4039 back_faces
= face_ptr
;
4040 back_vertices
= vertex_ptr
;
4041 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
4043 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
4044 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
4045 vertex_ptr
->position
.y
= pt
->y
;
4046 vertex_ptr
->position
.z
= 0;
4047 vertex_ptr
->normal
.x
= 0;
4048 vertex_ptr
->normal
.y
= 0;
4049 vertex_ptr
->normal
.z
= 1;
4052 count
= back_vertices
- vertices
;
4053 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
4055 face
*f
= &glyphs
[i
].faces
.items
[j
];
4056 (*face_ptr
)[0] = (*f
)[0] + count
;
4057 (*face_ptr
)[1] = (*f
)[1] + count
;
4058 (*face_ptr
)[2] = (*f
)[2] + count
;
4062 /* front vertices and faces */
4063 j
= count
= vertex_ptr
- back_vertices
;
4066 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
4067 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
4068 vertex_ptr
->position
.z
= -extrusion
;
4069 vertex_ptr
->normal
.x
= 0;
4070 vertex_ptr
->normal
.y
= 0;
4071 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
4075 j
= face_ptr
- back_faces
;
4078 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
4079 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
4080 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
4090 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
4091 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
4092 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
4095 for (i
= 0; i
< textlen
; i
++)
4098 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
4099 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
4100 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
4101 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
4102 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
4104 HeapFree(GetProcessHeap(), 0, glyphs
);
4106 if (triangulations
.items
) {
4108 for (i
= 0; i
< triangulations
.count
; i
++)
4109 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
4110 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
4112 HeapFree(GetProcessHeap(), 0, raw_outline
);
4113 if (oldfont
) SelectObject(hdc
, oldfont
);
4114 if (font
) DeleteObject(font
);