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
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35 #include "d3dx9_36_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
39 typedef struct ID3DXMeshImpl
41 ID3DXMesh ID3DXMesh_iface
;
48 IDirect3DDevice9
*device
;
49 IDirect3DVertexDeclaration9
*vertex_declaration
;
50 IDirect3DVertexBuffer9
*vertex_buffer
;
51 IDirect3DIndexBuffer9
*index_buffer
;
53 int attrib_buffer_lock_count
;
54 DWORD attrib_table_size
;
55 D3DXATTRIBUTERANGE
*attrib_table
;
58 static inline ID3DXMeshImpl
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
60 return CONTAINING_RECORD(iface
, ID3DXMeshImpl
, ID3DXMesh_iface
);
63 static HRESULT WINAPI
ID3DXMeshImpl_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, LPVOID
*object
)
65 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
67 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), object
);
69 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
70 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
71 IsEqualGUID(riid
, &IID_ID3DXMesh
))
73 iface
->lpVtbl
->AddRef(iface
);
78 WARN("Interface %s not found.\n", debugstr_guid(riid
));
83 static ULONG WINAPI
ID3DXMeshImpl_AddRef(ID3DXMesh
*iface
)
85 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
87 TRACE("(%p)->(): AddRef from %d\n", This
, This
->ref
);
89 return InterlockedIncrement(&This
->ref
);
92 static ULONG WINAPI
ID3DXMeshImpl_Release(ID3DXMesh
*iface
)
94 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
95 ULONG ref
= InterlockedDecrement(&This
->ref
);
97 TRACE("(%p)->(): Release from %d\n", This
, ref
+ 1);
101 IDirect3DIndexBuffer9_Release(This
->index_buffer
);
102 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
103 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
104 IDirect3DDevice9_Release(This
->device
);
105 HeapFree(GetProcessHeap(), 0, This
->attrib_buffer
);
106 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
107 HeapFree(GetProcessHeap(), 0, This
);
113 /*** ID3DXBaseMesh ***/
114 static HRESULT WINAPI
ID3DXMeshImpl_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
116 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
122 TRACE("(%p)->(%u)\n", This
, attrib_id
);
124 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
126 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
127 if (FAILED(hr
)) return hr
;
128 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
129 if (FAILED(hr
)) return hr
;
130 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
131 if (FAILED(hr
)) return hr
;
133 while (face_end
< This
->numfaces
)
135 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
137 if (This
->attrib_buffer
[face_start
] == attrib_id
)
140 if (face_start
>= This
->numfaces
)
142 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
144 if (This
->attrib_buffer
[face_end
] != attrib_id
)
148 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
149 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
150 if (FAILED(hr
)) return hr
;
156 static DWORD WINAPI
ID3DXMeshImpl_GetNumFaces(ID3DXMesh
*iface
)
158 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
160 TRACE("(%p)\n", This
);
162 return This
->numfaces
;
165 static DWORD WINAPI
ID3DXMeshImpl_GetNumVertices(ID3DXMesh
*iface
)
167 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
169 TRACE("(%p)\n", This
);
171 return This
->numvertices
;
174 static DWORD WINAPI
ID3DXMeshImpl_GetFVF(ID3DXMesh
*iface
)
176 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
178 TRACE("(%p)\n", This
);
183 static HRESULT WINAPI
ID3DXMeshImpl_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
185 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
188 TRACE("(%p)\n", This
);
190 if (declaration
== NULL
) return D3DERR_INVALIDCALL
;
192 return IDirect3DVertexDeclaration9_GetDeclaration(This
->vertex_declaration
,
197 static DWORD WINAPI
ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh
*iface
)
199 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
201 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
203 TRACE("iface (%p)\n", This
);
205 IDirect3DVertexDeclaration9_GetDeclaration(This
->vertex_declaration
,
208 return D3DXGetDeclVertexSize(declaration
, 0);
211 static DWORD WINAPI
ID3DXMeshImpl_GetOptions(ID3DXMesh
*iface
)
213 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
215 TRACE("(%p)\n", This
);
217 return This
->options
;
220 static HRESULT WINAPI
ID3DXMeshImpl_GetDevice(ID3DXMesh
*iface
, LPDIRECT3DDEVICE9
*device
)
222 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
224 TRACE("(%p)->(%p)\n", This
, device
);
226 if (device
== NULL
) return D3DERR_INVALIDCALL
;
227 *device
= This
->device
;
228 IDirect3DDevice9_AddRef(This
->device
);
233 static HRESULT WINAPI
ID3DXMeshImpl_CloneMeshFVF(ID3DXMesh
*iface
, DWORD options
, DWORD fvf
, LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*clone_mesh
)
235 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
237 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
239 TRACE("(%p)->(%x,%x,%p,%p)\n", This
, options
, fvf
, device
, clone_mesh
);
241 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
242 if (FAILED(hr
)) return hr
;
244 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
247 static HRESULT WINAPI
ID3DXMeshImpl_CloneMesh(ID3DXMesh
*iface
, DWORD options
, CONST D3DVERTEXELEMENT9
*declaration
, LPDIRECT3DDEVICE9 device
,
248 LPD3DXMESH
*clone_mesh_out
)
250 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
251 ID3DXMeshImpl
*cloned_this
;
252 ID3DXMesh
*clone_mesh
;
253 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
254 void *data_in
, *data_out
;
259 TRACE("(%p)->(%x,%p,%p,%p)\n", This
, options
, declaration
, device
, clone_mesh_out
);
262 return D3DERR_INVALIDCALL
;
264 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
265 if (FAILED(hr
)) return hr
;
267 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++) {
268 if (memcmp(&orig_declaration
[i
], &declaration
[i
], sizeof(*declaration
)))
270 FIXME("Vertex buffer conversion not implemented.\n");
275 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
276 declaration
, device
, &clone_mesh
);
277 if (FAILED(hr
)) return hr
;
279 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
280 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
282 if (options
& D3DXMESH_VB_SHARE
) {
283 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
284 /* FIXME: refactor to avoid creating a new vertex buffer */
285 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
286 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
288 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
289 if (FAILED(hr
)) goto error
;
290 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, D3DLOCK_DISCARD
, &data_out
);
292 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
295 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
296 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
297 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
300 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
301 if (FAILED(hr
)) goto error
;
302 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, D3DLOCK_DISCARD
, &data_out
);
304 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
307 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
308 if (options
& D3DXMESH_32BIT
) {
309 for (i
= 0; i
< This
->numfaces
* 3; i
++)
310 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
312 for (i
= 0; i
< This
->numfaces
* 3; i
++)
313 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
316 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
318 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
319 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
321 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
323 if (This
->attrib_table_size
)
325 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
326 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
327 if (!cloned_this
->attrib_table
) {
331 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
334 *clone_mesh_out
= clone_mesh
;
338 IUnknown_Release(clone_mesh
);
342 static HRESULT WINAPI
ID3DXMeshImpl_GetVertexBuffer(ID3DXMesh
*iface
, LPDIRECT3DVERTEXBUFFER9
*vertex_buffer
)
344 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
346 TRACE("(%p)->(%p)\n", This
, vertex_buffer
);
348 if (vertex_buffer
== NULL
) return D3DERR_INVALIDCALL
;
349 *vertex_buffer
= This
->vertex_buffer
;
350 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
355 static HRESULT WINAPI
ID3DXMeshImpl_GetIndexBuffer(ID3DXMesh
*iface
, LPDIRECT3DINDEXBUFFER9
*index_buffer
)
357 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
359 TRACE("(%p)->(%p)\n", This
, index_buffer
);
361 if (index_buffer
== NULL
) return D3DERR_INVALIDCALL
;
362 *index_buffer
= This
->index_buffer
;
363 IDirect3DIndexBuffer9_AddRef(This
->index_buffer
);
368 static HRESULT WINAPI
ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
370 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
372 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
374 return IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, data
, flags
);
377 static HRESULT WINAPI
ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh
*iface
)
379 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
381 TRACE("(%p)\n", This
);
383 return IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
386 static HRESULT WINAPI
ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
388 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
390 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
392 return IDirect3DIndexBuffer9_Lock(This
->index_buffer
, 0, 0, data
, flags
);
395 static HRESULT WINAPI
ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh
*iface
)
397 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
399 TRACE("(%p)\n", This
);
401 return IDirect3DIndexBuffer9_Unlock(This
->index_buffer
);
404 static HRESULT WINAPI
ID3DXMeshImpl_GetAttributeTable(ID3DXMesh
*iface
, D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
406 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
408 TRACE("(%p)->(%p,%p)\n", This
, attrib_table
, attrib_table_size
);
410 if (attrib_table_size
)
411 *attrib_table_size
= This
->attrib_table_size
;
414 CopyMemory(attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*attrib_table
));
419 static HRESULT WINAPI
ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
, CONST DWORD
*point_reps
, DWORD
*adjacency
)
421 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
423 FIXME("(%p)->(%p,%p): stub\n", This
, point_reps
, adjacency
);
428 static HRESULT WINAPI
ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
, CONST DWORD
*adjacency
, DWORD
*point_reps
)
430 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
432 FIXME("(%p)->(%p,%p): stub\n", This
, adjacency
, point_reps
);
437 struct vertex_metadata
{
440 DWORD first_shared_index
;
443 static int compare_vertex_keys(const void *a
, const void *b
)
445 const struct vertex_metadata
*left
= a
;
446 const struct vertex_metadata
*right
= b
;
447 if (left
->key
== right
->key
)
449 return left
->key
< right
->key
? -1 : 1;
452 static HRESULT WINAPI
ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh
*iface
, FLOAT epsilon
, DWORD
*adjacency
)
454 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
456 BYTE
*vertices
= NULL
;
457 const DWORD
*indices
= NULL
;
460 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
461 struct vertex_metadata
*sorted_vertices
;
462 /* shared_indices links together identical indices in the index buffer so
463 * that adjacency checks can be limited to faces sharing a vertex */
464 DWORD
*shared_indices
= NULL
;
465 const FLOAT epsilon_sq
= epsilon
* epsilon
;
468 TRACE("(%p)->(%f,%p)\n", This
, epsilon
, adjacency
);
471 return D3DERR_INVALIDCALL
;
473 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
474 if (!(This
->options
& D3DXMESH_32BIT
))
475 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
476 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
478 return E_OUTOFMEMORY
;
479 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
481 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
482 if (FAILED(hr
)) goto cleanup
;
483 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
484 if (FAILED(hr
)) goto cleanup
;
486 if (!(This
->options
& D3DXMESH_32BIT
)) {
487 const WORD
*word_indices
= (const WORD
*)indices
;
488 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
489 indices
= dword_indices
;
490 for (i
= 0; i
< This
->numfaces
* 3; i
++)
491 *dword_indices
++ = *word_indices
++;
494 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
495 for (i
= 0; i
< This
->numvertices
; i
++) {
496 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
497 sorted_vertices
[i
].first_shared_index
= -1;
498 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
499 sorted_vertices
[i
].vertex_index
= i
;
501 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
502 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
503 shared_indices
[i
] = *first_shared_index
;
504 *first_shared_index
= i
;
507 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
509 for (i
= 0; i
< This
->numvertices
; i
++) {
510 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
511 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
512 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
514 while (shared_index_a
!= -1) {
516 DWORD shared_index_b
= shared_indices
[shared_index_a
];
517 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
520 while (shared_index_b
!= -1) {
521 /* faces are adjacent if they have another coincident vertex */
522 DWORD base_a
= (shared_index_a
/ 3) * 3;
523 DWORD base_b
= (shared_index_b
/ 3) * 3;
524 BOOL adjacent
= FALSE
;
527 for (k
= 0; k
< 3; k
++) {
528 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
534 for (k
= 1; k
<= 2; k
++) {
535 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
536 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
537 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
538 if (!adjacent
&& epsilon
>= 0.0f
) {
539 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
542 D3DXVec3Subtract(&delta
,
543 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
544 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
545 length_sq
= D3DXVec3LengthSq(&delta
);
546 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
549 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
550 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
551 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
552 adjacency
[adj_a
] = base_b
/ 3;
553 adjacency
[adj_b
] = base_a
/ 3;
560 shared_index_b
= shared_indices
[shared_index_b
];
562 while (++j
< This
->numvertices
) {
563 D3DXVECTOR3
*vertex_b
;
566 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
567 /* no more coincident vertices to try */
568 j
= This
->numvertices
;
571 /* check for coincidence */
572 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
573 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
574 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
575 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
580 if (j
>= This
->numvertices
)
582 shared_index_b
= sorted_vertex_b
->first_shared_index
;
585 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
586 shared_index_a
= sorted_vertex_a
->first_shared_index
;
592 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
593 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
594 HeapFree(GetProcessHeap(), 0, shared_indices
);
598 static HRESULT WINAPI
ID3DXMeshImpl_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
600 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
602 FIXME("(%p)->(%p): stub\n", This
, declaration
);
608 static HRESULT WINAPI
ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
610 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
612 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
614 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
616 if (!(flags
& D3DLOCK_READONLY
)) {
617 D3DXATTRIBUTERANGE
*attrib_table
= This
->attrib_table
;
618 This
->attrib_table_size
= 0;
619 This
->attrib_table
= NULL
;
620 HeapFree(GetProcessHeap(), 0, attrib_table
);
623 *data
= This
->attrib_buffer
;
628 static HRESULT WINAPI
ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh
*iface
)
630 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
633 TRACE("(%p)\n", This
);
635 lock_count
= InterlockedDecrement(&This
->attrib_buffer_lock_count
);
637 if (lock_count
< 0) {
638 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
639 return D3DERR_INVALIDCALL
;
645 static HRESULT WINAPI
ID3DXMeshImpl_Optimize(ID3DXMesh
*iface
, DWORD flags
, CONST DWORD
*adjacency_in
, DWORD
*adjacency_out
,
646 DWORD
*face_remap
, LPD3DXBUFFER
*vertex_remap
, LPD3DXMESH
*opt_mesh
)
648 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
650 FIXME("(%p)->(%u,%p,%p,%p,%p,%p): stub\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
655 /* Creates a vertex_remap that removes unused vertices.
656 * Indices are updated according to the vertex_remap. */
657 static HRESULT
compact_mesh(ID3DXMeshImpl
*This
, DWORD
*indices
, DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
660 DWORD
*vertex_remap_ptr
;
661 DWORD num_used_vertices
;
664 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
665 if (FAILED(hr
)) return hr
;
666 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
668 for (i
= 0; i
< This
->numfaces
* 3; i
++)
669 vertex_remap_ptr
[indices
[i
]] = 1;
671 /* create old->new vertex mapping */
672 num_used_vertices
= 0;
673 for (i
= 0; i
< This
->numvertices
; i
++) {
674 if (vertex_remap_ptr
[i
])
675 vertex_remap_ptr
[i
] = num_used_vertices
++;
677 vertex_remap_ptr
[i
] = -1;
679 /* convert indices */
680 for (i
= 0; i
< This
->numfaces
* 3; i
++)
681 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
683 /* create new->old vertex mapping */
684 num_used_vertices
= 0;
685 for (i
= 0; i
< This
->numvertices
; i
++) {
686 if (vertex_remap_ptr
[i
] != -1)
687 vertex_remap_ptr
[num_used_vertices
++] = i
;
689 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
690 vertex_remap_ptr
[i
] = -1;
692 *new_num_vertices
= num_used_vertices
;
697 static HRESULT WINAPI
ID3DXMeshImpl_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, CONST DWORD
*adjacency_in
, DWORD
*adjacency_out
,
698 DWORD
*face_remap_out
, LPD3DXBUFFER
*vertex_remap_out
)
700 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
701 void *indices
= NULL
;
703 ID3DXBuffer
*vertex_remap
= NULL
;
704 DWORD
*dword_indices
= NULL
;
705 DWORD new_num_vertices
= 0;
706 DWORD new_num_alloc_vertices
= 0;
707 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
710 TRACE("(%p)->(%x,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
713 return D3DERR_INVALIDCALL
;
714 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
715 return D3DERR_INVALIDCALL
;
716 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
717 return D3DERR_INVALIDCALL
;
719 if (flags
& (D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
721 if (flags
& D3DXMESHOPT_ATTRSORT
)
722 FIXME("D3DXMESHOPT_ATTRSORT not implemented.\n");
723 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
724 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
725 if (flags
& D3DXMESHOPT_STRIPREORDER
)
726 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
730 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, (void**)&indices
);
731 if (FAILED(hr
)) goto cleanup
;
733 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
734 if (!dword_indices
) return E_OUTOFMEMORY
;
735 if (This
->options
& D3DXMESH_32BIT
) {
736 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
738 WORD
*word_indices
= indices
;
739 for (i
= 0; i
< This
->numfaces
* 3; i
++)
740 dword_indices
[i
] = *word_indices
++;
743 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
)) == D3DXMESHOPT_COMPACT
)
745 new_num_alloc_vertices
= This
->numvertices
;
746 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
747 if (FAILED(hr
)) goto cleanup
;
752 /* reorder the vertices using vertex_remap */
753 D3DVERTEXBUFFER_DESC vertex_desc
;
754 DWORD
*vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
755 DWORD vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
759 hr
= IDirect3DVertexBuffer9_GetDesc(This
->vertex_buffer
, &vertex_desc
);
760 if (FAILED(hr
)) goto cleanup
;
762 hr
= IDirect3DDevice9_CreateVertexBuffer(This
->device
, new_num_alloc_vertices
* vertex_size
,
763 vertex_desc
.Usage
, This
->fvf
, vertex_desc
.Pool
, &vertex_buffer
, NULL
);
764 if (FAILED(hr
)) goto cleanup
;
766 hr
= IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, (void**)&orig_vertices
, D3DLOCK_READONLY
);
767 if (FAILED(hr
)) goto cleanup
;
769 hr
= IDirect3DVertexBuffer9_Lock(vertex_buffer
, 0, 0, (void**)&new_vertices
, D3DLOCK_DISCARD
);
771 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
775 for (i
= 0; i
< new_num_vertices
; i
++)
776 memcpy(new_vertices
+ i
* vertex_size
, orig_vertices
+ vertex_remap_ptr
[i
] * vertex_size
, vertex_size
);
778 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
779 IDirect3DVertexBuffer9_Unlock(vertex_buffer
);
780 } else if (vertex_remap_out
) {
781 DWORD
*vertex_remap_ptr
;
783 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), &vertex_remap
);
784 if (FAILED(hr
)) goto cleanup
;
785 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
786 for (i
= 0; i
< This
->numvertices
; i
++)
787 *vertex_remap_ptr
++ = i
;
790 if (This
->options
& D3DXMESH_32BIT
) {
791 memcpy(indices
, dword_indices
, This
->numfaces
* 3 * sizeof(DWORD
));
793 WORD
*word_indices
= indices
;
794 for (i
= 0; i
< This
->numfaces
* 3; i
++)
795 *word_indices
++ = dword_indices
[i
];
799 memcpy(adjacency_out
, adjacency_in
, This
->numfaces
* 3 * sizeof(*adjacency_out
));
801 if (face_remap_out
) {
802 for (i
= 0; i
< This
->numfaces
; i
++)
803 face_remap_out
[i
] = i
;
805 if (vertex_remap_out
)
806 *vertex_remap_out
= vertex_remap
;
810 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
811 This
->vertex_buffer
= vertex_buffer
;
812 vertex_buffer
= NULL
;
813 This
->numvertices
= new_num_vertices
;
818 HeapFree(GetProcessHeap(), 0, dword_indices
);
819 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
820 if (vertex_buffer
) IDirect3DVertexBuffer9_Release(vertex_buffer
);
821 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
825 static HRESULT WINAPI
ID3DXMeshImpl_SetAttributeTable(ID3DXMesh
*iface
, CONST D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
827 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
828 D3DXATTRIBUTERANGE
*new_table
= NULL
;
830 TRACE("(%p)->(%p,%u)\n", This
, attrib_table
, attrib_table_size
);
832 if (attrib_table_size
) {
833 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
835 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
837 return E_OUTOFMEMORY
;
839 CopyMemory(new_table
, attrib_table
, size
);
840 } else if (attrib_table
) {
841 return D3DERR_INVALIDCALL
;
843 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
844 This
->attrib_table
= new_table
;
845 This
->attrib_table_size
= attrib_table_size
;
850 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
852 /*** IUnknown methods ***/
853 ID3DXMeshImpl_QueryInterface
,
854 ID3DXMeshImpl_AddRef
,
855 ID3DXMeshImpl_Release
,
856 /*** ID3DXBaseMesh ***/
857 ID3DXMeshImpl_DrawSubset
,
858 ID3DXMeshImpl_GetNumFaces
,
859 ID3DXMeshImpl_GetNumVertices
,
860 ID3DXMeshImpl_GetFVF
,
861 ID3DXMeshImpl_GetDeclaration
,
862 ID3DXMeshImpl_GetNumBytesPerVertex
,
863 ID3DXMeshImpl_GetOptions
,
864 ID3DXMeshImpl_GetDevice
,
865 ID3DXMeshImpl_CloneMeshFVF
,
866 ID3DXMeshImpl_CloneMesh
,
867 ID3DXMeshImpl_GetVertexBuffer
,
868 ID3DXMeshImpl_GetIndexBuffer
,
869 ID3DXMeshImpl_LockVertexBuffer
,
870 ID3DXMeshImpl_UnlockVertexBuffer
,
871 ID3DXMeshImpl_LockIndexBuffer
,
872 ID3DXMeshImpl_UnlockIndexBuffer
,
873 ID3DXMeshImpl_GetAttributeTable
,
874 ID3DXMeshImpl_ConvertPointRepsToAdjacency
,
875 ID3DXMeshImpl_ConvertAdjacencyToPointReps
,
876 ID3DXMeshImpl_GenerateAdjacency
,
877 ID3DXMeshImpl_UpdateSemantics
,
879 ID3DXMeshImpl_LockAttributeBuffer
,
880 ID3DXMeshImpl_UnlockAttributeBuffer
,
881 ID3DXMeshImpl_Optimize
,
882 ID3DXMeshImpl_OptimizeInplace
,
883 ID3DXMeshImpl_SetAttributeTable
886 /*************************************************************************
889 BOOL WINAPI
D3DXBoxBoundProbe(CONST D3DXVECTOR3
*pmin
, CONST D3DXVECTOR3
*pmax
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
891 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algoritm
892 Amy Williams University of Utah
893 Steve Barrus University of Utah
894 R. Keith Morley University of Utah
895 Peter Shirley University of Utah
897 International Conference on Computer Graphics and Interactive Techniques archive
898 ACM SIGGRAPH 2005 Courses
899 Los Angeles, California
901 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
903 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
904 against each slab, if there's anything left of the ray after we're
905 done we've got an intersection of the ray with the box.
909 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
911 div
= 1.0f
/ praydirection
->x
;
914 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
915 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
919 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
920 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
923 if ( tmax
< 0.0f
) return FALSE
;
925 div
= 1.0f
/ praydirection
->y
;
928 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
929 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
933 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
934 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
937 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
939 if ( tymin
> tmin
) tmin
= tymin
;
940 if ( tymax
< tmax
) tmax
= tymax
;
942 div
= 1.0f
/ praydirection
->z
;
945 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
946 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
950 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
951 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
954 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
959 /*************************************************************************
960 * D3DXComputeBoundingBox
962 HRESULT WINAPI
D3DXComputeBoundingBox(CONST D3DXVECTOR3
*pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
967 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
969 *pmin
= *pfirstposition
;
972 for(i
=0; i
<numvertices
; i
++)
974 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
976 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
977 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
979 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
980 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
982 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
983 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
989 /*************************************************************************
990 * D3DXComputeBoundingSphere
992 HRESULT WINAPI
D3DXComputeBoundingSphere(CONST D3DXVECTOR3
* pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, FLOAT
*pradius
)
994 D3DXVECTOR3 temp
, temp1
;
998 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
1006 for(i
=0; i
<numvertices
; i
++)
1008 D3DXVec3Add(&temp1
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
1012 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/((FLOAT
)numvertices
));
1014 for(i
=0; i
<numvertices
; i
++)
1016 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
1017 if ( d
> *pradius
) *pradius
= d
;
1022 static const UINT d3dx_decltype_size
[D3DDECLTYPE_UNUSED
] =
1024 /* D3DDECLTYPE_FLOAT1 */ 1 * 4,
1025 /* D3DDECLTYPE_FLOAT2 */ 2 * 4,
1026 /* D3DDECLTYPE_FLOAT3 */ 3 * 4,
1027 /* D3DDECLTYPE_FLOAT4 */ 4 * 4,
1028 /* D3DDECLTYPE_D3DCOLOR */ 4 * 1,
1029 /* D3DDECLTYPE_UBYTE4 */ 4 * 1,
1030 /* D3DDECLTYPE_SHORT2 */ 2 * 2,
1031 /* D3DDECLTYPE_SHORT4 */ 4 * 2,
1032 /* D3DDECLTYPE_UBYTE4N */ 4 * 1,
1033 /* D3DDECLTYPE_SHORT2N */ 2 * 2,
1034 /* D3DDECLTYPE_SHORT4N */ 4 * 2,
1035 /* D3DDECLTYPE_USHORT2N */ 2 * 2,
1036 /* D3DDECLTYPE_USHORT4N */ 4 * 2,
1037 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
1038 /* D3DDECLTYPE_DEC3N */ 4,
1039 /* D3DDECLTYPE_FLOAT16_2 */ 2 * 2,
1040 /* D3DDECLTYPE_FLOAT16_4 */ 4 * 2,
1043 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
1044 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
1046 declaration
[*idx
].Stream
= 0;
1047 declaration
[*idx
].Offset
= *offset
;
1048 declaration
[*idx
].Type
= type
;
1049 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
1050 declaration
[*idx
].Usage
= usage
;
1051 declaration
[*idx
].UsageIndex
= usage_idx
;
1053 *offset
+= d3dx_decltype_size
[type
];
1057 /*************************************************************************
1058 * D3DXDeclaratorFromFVF
1060 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1062 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
1063 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
1064 unsigned int offset
= 0;
1065 unsigned int idx
= 0;
1068 TRACE("fvf %#x, declaration %p.\n", fvf
, declaration
);
1070 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
1072 if (fvf
& D3DFVF_POSITION_MASK
)
1074 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
1075 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
1076 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
1078 if (has_blend_idx
) --blend_count
;
1080 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
1081 || (has_blend
&& blend_count
> 4))
1082 return D3DERR_INVALIDCALL
;
1084 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
1085 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
1087 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
1091 switch (blend_count
)
1096 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1099 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1102 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1105 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
1108 ERR("Invalid blend count %u.\n", blend_count
);
1114 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
1115 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
1116 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
1117 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
1122 if (fvf
& D3DFVF_NORMAL
)
1123 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
1124 if (fvf
& D3DFVF_PSIZE
)
1125 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
1126 if (fvf
& D3DFVF_DIFFUSE
)
1127 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
1128 if (fvf
& D3DFVF_SPECULAR
)
1129 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
1131 for (i
= 0; i
< tex_count
; ++i
)
1133 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
1135 case D3DFVF_TEXTUREFORMAT1
:
1136 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
1138 case D3DFVF_TEXTUREFORMAT2
:
1139 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
1141 case D3DFVF_TEXTUREFORMAT3
:
1142 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
1144 case D3DFVF_TEXTUREFORMAT4
:
1145 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
1150 declaration
[idx
] = end_element
;
1155 /*************************************************************************
1156 * D3DXFVFFromDeclarator
1158 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
1160 unsigned int i
= 0, texture
, offset
;
1162 TRACE("(%p, %p)\n", declaration
, fvf
);
1165 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
1167 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
1168 declaration
[1].UsageIndex
== 0) &&
1169 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
1170 declaration
[2].UsageIndex
== 0))
1172 return D3DERR_INVALIDCALL
;
1174 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
1175 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
1177 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
1179 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
1183 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
1187 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
1188 declaration
[1].UsageIndex
== 0)
1190 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
1191 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
1193 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
1195 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
1199 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
1201 switch (declaration
[1].Type
)
1203 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
1204 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
1205 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
1206 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
1212 switch (declaration
[1].Type
)
1214 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
1215 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
1216 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
1217 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
1228 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
1229 declaration
[0].UsageIndex
== 0)
1231 *fvf
|= D3DFVF_XYZRHW
;
1235 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
1237 *fvf
|= D3DFVF_NORMAL
;
1240 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
1241 declaration
[i
].UsageIndex
== 0)
1243 *fvf
|= D3DFVF_PSIZE
;
1246 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
1247 declaration
[i
].UsageIndex
== 0)
1249 *fvf
|= D3DFVF_DIFFUSE
;
1252 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
1253 declaration
[i
].UsageIndex
== 1)
1255 *fvf
|= D3DFVF_SPECULAR
;
1259 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
1261 if (declaration
[i
].Stream
== 0xFF)
1265 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1266 declaration
[i
].UsageIndex
== texture
)
1268 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
1270 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1271 declaration
[i
].UsageIndex
== texture
)
1273 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
1275 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1276 declaration
[i
].UsageIndex
== texture
)
1278 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
1280 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
1281 declaration
[i
].UsageIndex
== texture
)
1283 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
1287 return D3DERR_INVALIDCALL
;
1291 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
1293 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
1294 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
1296 if (declaration
[i
].Offset
!= offset
)
1298 return D3DERR_INVALIDCALL
;
1305 /*************************************************************************
1306 * D3DXGetFVFVertexSize
1308 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
1310 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
1313 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
1317 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
1319 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
1320 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
1321 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
1322 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
1324 switch (FVF
& D3DFVF_POSITION_MASK
)
1326 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
1327 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
1328 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
1329 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
1330 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
1331 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
1332 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
1333 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
1336 for (i
= 0; i
< numTextures
; i
++)
1338 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
1344 /*************************************************************************
1345 * D3DXGetDeclVertexSize
1347 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
1349 const D3DVERTEXELEMENT9
*element
;
1352 TRACE("decl %p, stream_idx %u\n", decl
, stream_idx
);
1354 if (!decl
) return 0;
1356 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
1360 if (element
->Stream
!= stream_idx
) continue;
1362 if (element
->Type
>= sizeof(d3dx_decltype_size
) / sizeof(*d3dx_decltype_size
))
1364 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
1368 type_size
= d3dx_decltype_size
[element
->Type
];
1369 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
1375 /*************************************************************************
1378 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
1380 const D3DVERTEXELEMENT9
*element
;
1382 TRACE("decl %p\n", decl
);
1384 /* null decl results in exception on Windows XP */
1386 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
1388 return element
- decl
;
1391 /*************************************************************************
1394 BOOL WINAPI
D3DXIntersectTri(CONST D3DXVECTOR3
*p0
, CONST D3DXVECTOR3
*p1
, CONST D3DXVECTOR3
*p2
, CONST D3DXVECTOR3
*praypos
, CONST D3DXVECTOR3
*praydir
, FLOAT
*pu
, FLOAT
*pv
, FLOAT
*pdist
)
1399 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
1400 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
1401 m
.u
.m
[2][0] = -praydir
->x
;
1403 m
.u
.m
[0][1] = p1
->y
- p0
->z
;
1404 m
.u
.m
[1][1] = p2
->y
- p0
->z
;
1405 m
.u
.m
[2][1] = -praydir
->y
;
1407 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
1408 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
1409 m
.u
.m
[2][2] = -praydir
->z
;
1416 vec
.x
= praypos
->x
- p0
->x
;
1417 vec
.y
= praypos
->y
- p0
->y
;
1418 vec
.z
= praypos
->z
- p0
->z
;
1421 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
1423 D3DXVec4Transform(&vec
, &vec
, &m
);
1424 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
1428 *pdist
= fabs( vec
.z
);
1436 /*************************************************************************
1437 * D3DXSphereBoundProbe
1439 BOOL WINAPI
D3DXSphereBoundProbe(CONST D3DXVECTOR3
*pcenter
, FLOAT radius
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
1441 D3DXVECTOR3 difference
;
1444 a
= D3DXVec3LengthSq(praydirection
);
1445 if (!D3DXVec3Subtract(&difference
, prayposition
, pcenter
)) return FALSE
;
1446 b
= D3DXVec3Dot(&difference
, praydirection
);
1447 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
1450 if ( ( d
<= 0.0f
) || ( sqrt(d
) <= b
) ) return FALSE
;
1454 /*************************************************************************
1457 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
, CONST D3DVERTEXELEMENT9
*declaration
,
1458 LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
)
1462 IDirect3DVertexDeclaration9
*vertex_declaration
;
1463 IDirect3DVertexBuffer9
*vertex_buffer
;
1464 IDirect3DIndexBuffer9
*index_buffer
;
1465 DWORD
*attrib_buffer
;
1466 ID3DXMeshImpl
*object
;
1467 DWORD index_usage
= 0;
1468 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
1469 D3DFORMAT index_format
= D3DFMT_INDEX16
;
1470 DWORD vertex_usage
= 0;
1471 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
1474 TRACE("(%d, %d, %x, %p, %p, %p)\n", numfaces
, numvertices
, options
, declaration
, device
, mesh
);
1476 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
1477 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
1478 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
1480 return D3DERR_INVALIDCALL
;
1482 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1483 if (declaration
[i
].Stream
!= 0)
1484 return D3DERR_INVALIDCALL
;
1486 if (options
& D3DXMESH_32BIT
)
1487 index_format
= D3DFMT_INDEX32
;
1489 if (options
& D3DXMESH_DONOTCLIP
) {
1490 index_usage
|= D3DUSAGE_DONOTCLIP
;
1491 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
1493 if (options
& D3DXMESH_POINTS
) {
1494 index_usage
|= D3DUSAGE_POINTS
;
1495 vertex_usage
|= D3DUSAGE_POINTS
;
1497 if (options
& D3DXMESH_RTPATCHES
) {
1498 index_usage
|= D3DUSAGE_RTPATCHES
;
1499 vertex_usage
|= D3DUSAGE_RTPATCHES
;
1501 if (options
& D3DXMESH_NPATCHES
) {
1502 index_usage
|= D3DUSAGE_NPATCHES
;
1503 vertex_usage
|= D3DUSAGE_NPATCHES
;
1506 if (options
& D3DXMESH_VB_SYSTEMMEM
)
1507 vertex_pool
= D3DPOOL_SYSTEMMEM
;
1508 else if (options
& D3DXMESH_VB_MANAGED
)
1509 vertex_pool
= D3DPOOL_MANAGED
;
1511 if (options
& D3DXMESH_VB_WRITEONLY
)
1512 vertex_usage
|= D3DUSAGE_WRITEONLY
;
1513 if (options
& D3DXMESH_VB_DYNAMIC
)
1514 vertex_usage
|= D3DUSAGE_DYNAMIC
;
1515 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
1516 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
1518 if (options
& D3DXMESH_IB_SYSTEMMEM
)
1519 index_pool
= D3DPOOL_SYSTEMMEM
;
1520 else if (options
& D3DXMESH_IB_MANAGED
)
1521 index_pool
= D3DPOOL_MANAGED
;
1523 if (options
& D3DXMESH_IB_WRITEONLY
)
1524 index_usage
|= D3DUSAGE_WRITEONLY
;
1525 if (options
& D3DXMESH_IB_DYNAMIC
)
1526 index_usage
|= D3DUSAGE_DYNAMIC
;
1527 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
1528 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
1530 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
1536 /* Create vertex declaration */
1537 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
1539 &vertex_declaration
);
1542 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
1546 /* Create vertex buffer */
1547 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
1548 numvertices
* D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
),
1556 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
1557 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1561 /* Create index buffer */
1562 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
1563 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
1571 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
1572 IDirect3DVertexBuffer9_Release(vertex_buffer
);
1573 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1577 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
1578 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ID3DXMeshImpl
));
1579 if (object
== NULL
|| attrib_buffer
== NULL
)
1581 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
1582 IDirect3DIndexBuffer9_Release(index_buffer
);
1583 IDirect3DVertexBuffer9_Release(vertex_buffer
);
1584 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
1586 return E_OUTOFMEMORY
;
1588 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
1591 object
->numfaces
= numfaces
;
1592 object
->numvertices
= numvertices
;
1593 object
->options
= options
;
1595 object
->device
= device
;
1596 IDirect3DDevice9_AddRef(device
);
1598 object
->vertex_declaration
= vertex_declaration
;
1599 object
->vertex_buffer
= vertex_buffer
;
1600 object
->index_buffer
= index_buffer
;
1601 object
->attrib_buffer
= attrib_buffer
;
1603 *mesh
= &object
->ID3DXMesh_iface
;
1608 /*************************************************************************
1611 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
, DWORD fvf
,
1612 LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
)
1615 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
1617 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
1619 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
1620 if (FAILED(hr
)) return hr
;
1622 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
1625 HRESULT WINAPI
D3DXCreateBox(LPDIRECT3DDEVICE9 device
, FLOAT width
, FLOAT height
,
1626 FLOAT depth
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
1628 FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device
, width
, height
, depth
, mesh
, adjacency
);
1635 D3DXVECTOR3 position
;
1639 typedef WORD face
[3];
1647 static void free_sincos_table(struct sincos_table
*sincos_table
)
1649 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
1650 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
1653 /* pre compute sine and cosine tables; caller must free */
1654 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
1659 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
1660 if (!sincos_table
->sin
)
1664 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
1665 if (!sincos_table
->cos
)
1667 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
1671 angle
= angle_start
;
1672 for (i
= 0; i
< n
; i
++)
1674 sincos_table
->sin
[i
] = sin(angle
);
1675 sincos_table
->cos
[i
] = cos(angle
);
1676 angle
+= angle_step
;
1682 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
1684 return stack
*slices
+slice
+1;
1687 HRESULT WINAPI
D3DXCreateSphere(LPDIRECT3DDEVICE9 device
, FLOAT radius
, UINT slices
,
1688 UINT stacks
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
1690 DWORD number_of_vertices
, number_of_faces
;
1693 struct vertex
*vertices
;
1695 float phi_step
, phi_start
;
1696 struct sincos_table phi
;
1697 float theta_step
, theta
, sin_theta
, cos_theta
;
1701 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
1703 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
1705 return D3DERR_INVALIDCALL
;
1710 FIXME("Case of adjacency != NULL not implemented.\n");
1714 number_of_vertices
= 2 + slices
* (stacks
-1);
1715 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
1717 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
1718 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
1724 hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
1727 sphere
->lpVtbl
->Release(sphere
);
1731 hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
1734 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
1735 sphere
->lpVtbl
->Release(sphere
);
1739 /* phi = angle on xz plane wrt z axis */
1740 phi_step
= -2 * M_PI
/ slices
;
1741 phi_start
= M_PI
/ 2;
1743 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
1745 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
1746 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
1747 sphere
->lpVtbl
->Release(sphere
);
1748 return E_OUTOFMEMORY
;
1751 /* theta = angle on xy plane wrt x axis */
1752 theta_step
= M_PI
/ stacks
;
1759 vertices
[vertex
].normal
.x
= 0.0f
;
1760 vertices
[vertex
].normal
.y
= 0.0f
;
1761 vertices
[vertex
].normal
.z
= 1.0f
;
1762 vertices
[vertex
].position
.x
= 0.0f
;
1763 vertices
[vertex
].position
.y
= 0.0f
;
1764 vertices
[vertex
].position
.z
= radius
;
1767 for (stack
= 0; stack
< stacks
- 1; stack
++)
1769 sin_theta
= sin(theta
);
1770 cos_theta
= cos(theta
);
1772 for (slice
= 0; slice
< slices
; slice
++)
1774 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
1775 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
1776 vertices
[vertex
].normal
.z
= cos_theta
;
1777 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
1778 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
1779 vertices
[vertex
].position
.z
= radius
* cos_theta
;
1786 /* top stack is triangle fan */
1788 faces
[face
][1] = slice
+ 1;
1789 faces
[face
][2] = slice
;
1794 /* stacks in between top and bottom are quad strips */
1795 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
1796 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
1797 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
1800 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
1801 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
1802 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
1808 theta
+= theta_step
;
1814 faces
[face
][2] = slice
;
1819 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
1820 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
1821 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
1824 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
1825 faces
[face
][1] = vertex_index(slices
, 0, stack
);
1826 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
1831 vertices
[vertex
].position
.x
= 0.0f
;
1832 vertices
[vertex
].position
.y
= 0.0f
;
1833 vertices
[vertex
].position
.z
= -radius
;
1834 vertices
[vertex
].normal
.x
= 0.0f
;
1835 vertices
[vertex
].normal
.y
= 0.0f
;
1836 vertices
[vertex
].normal
.z
= -1.0f
;
1838 /* bottom stack is triangle fan */
1839 for (slice
= 1; slice
< slices
; slice
++)
1841 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
1842 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
1843 faces
[face
][2] = vertex
;
1847 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
1848 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
1849 faces
[face
][2] = vertex
;
1851 free_sincos_table(&phi
);
1852 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
1853 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
1859 HRESULT WINAPI
D3DXCreateCylinder(LPDIRECT3DDEVICE9 device
, FLOAT radius1
, FLOAT radius2
, FLOAT length
, UINT slices
,
1860 UINT stacks
, LPD3DXMESH
* mesh
, LPD3DXBUFFER
* adjacency
)
1862 DWORD number_of_vertices
, number_of_faces
;
1864 ID3DXMesh
*cylinder
;
1865 struct vertex
*vertices
;
1867 float theta_step
, theta_start
;
1868 struct sincos_table theta
;
1869 float delta_radius
, radius
, radius_step
;
1870 float z
, z_step
, z_normal
;
1874 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
1876 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
1878 return D3DERR_INVALIDCALL
;
1883 FIXME("Case of adjacency != NULL not implemented.\n");
1887 number_of_vertices
= 2 + (slices
* (3 + stacks
));
1888 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
1890 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
1891 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
1897 hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
1900 cylinder
->lpVtbl
->Release(cylinder
);
1904 hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
1907 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
1908 cylinder
->lpVtbl
->Release(cylinder
);
1912 /* theta = angle on xy plane wrt x axis */
1913 theta_step
= -2 * M_PI
/ slices
;
1914 theta_start
= M_PI
/ 2;
1916 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
1918 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
1919 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
1920 cylinder
->lpVtbl
->Release(cylinder
);
1921 return E_OUTOFMEMORY
;
1927 delta_radius
= radius1
- radius2
;
1929 radius_step
= delta_radius
/ stacks
;
1932 z_step
= length
/ stacks
;
1933 z_normal
= delta_radius
/ length
;
1934 if (isnan(z_normal
))
1939 vertices
[vertex
].normal
.x
= 0.0f
;
1940 vertices
[vertex
].normal
.y
= 0.0f
;
1941 vertices
[vertex
].normal
.z
= -1.0f
;
1942 vertices
[vertex
].position
.x
= 0.0f
;
1943 vertices
[vertex
].position
.y
= 0.0f
;
1944 vertices
[vertex
++].position
.z
= z
;
1946 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
1948 vertices
[vertex
].normal
.x
= 0.0f
;
1949 vertices
[vertex
].normal
.y
= 0.0f
;
1950 vertices
[vertex
].normal
.z
= -1.0f
;
1951 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
1952 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
1953 vertices
[vertex
].position
.z
= z
;
1958 faces
[face
][1] = slice
;
1959 faces
[face
++][2] = slice
+ 1;
1964 faces
[face
][1] = slice
;
1965 faces
[face
++][2] = 1;
1967 for (stack
= 1; stack
<= stacks
+1; stack
++)
1969 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
1971 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
1972 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
1973 vertices
[vertex
].normal
.z
= z_normal
;
1974 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
1975 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
1976 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
1977 vertices
[vertex
].position
.z
= z
;
1979 if (stack
> 1 && slice
> 0)
1981 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
1982 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
1983 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
1985 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
1986 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
1987 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
1993 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
1994 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
1995 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
1997 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
1998 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
1999 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
2002 if (stack
< stacks
+ 1)
2005 radius
-= radius_step
;
2009 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
2011 vertices
[vertex
].normal
.x
= 0.0f
;
2012 vertices
[vertex
].normal
.y
= 0.0f
;
2013 vertices
[vertex
].normal
.z
= 1.0f
;
2014 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
2015 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
2016 vertices
[vertex
].position
.z
= z
;
2020 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
2021 faces
[face
][1] = number_of_vertices
- 1;
2022 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
2026 vertices
[vertex
].position
.x
= 0.0f
;
2027 vertices
[vertex
].position
.y
= 0.0f
;
2028 vertices
[vertex
].position
.z
= z
;
2029 vertices
[vertex
].normal
.x
= 0.0f
;
2030 vertices
[vertex
].normal
.y
= 0.0f
;
2031 vertices
[vertex
].normal
.z
= 1.0f
;
2033 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
2034 faces
[face
][1] = number_of_vertices
- 1;
2035 faces
[face
][2] = vertex_index(slices
, 0, stack
);
2037 free_sincos_table(&theta
);
2038 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
2039 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
2045 HRESULT WINAPI
D3DXCreateTeapot(LPDIRECT3DDEVICE9 device
, LPD3DXMESH
*mesh
, LPD3DXBUFFER
* adjacency
)
2047 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
2052 HRESULT WINAPI
D3DXCreateTextA(LPDIRECT3DDEVICE9 device
,
2053 HDC hdc
, LPCSTR text
,
2054 FLOAT deviation
, FLOAT extrusion
,
2055 LPD3DXMESH
*mesh
, LPD3DXBUFFER
*adjacency
,
2056 LPGLYPHMETRICSFLOAT glyphmetrics
)
2062 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
2063 debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
2066 return D3DERR_INVALIDCALL
;
2068 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
2069 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2070 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
2072 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
2073 mesh
, adjacency
, glyphmetrics
);
2074 HeapFree(GetProcessHeap(), 0, textW
);
2080 POINTTYPE_CURVE
= 0,
2082 POINTTYPE_CURVE_START
,
2083 POINTTYPE_CURVE_END
,
2084 POINTTYPE_CURVE_MIDDLE
,
2090 enum pointtype corner
;
2093 struct dynamic_array
2095 int count
, capacity
;
2099 /* is a dynamic_array */
2102 int count
, capacity
;
2103 struct point2d
*items
;
2106 /* is a dynamic_array */
2107 struct outline_array
2109 int count
, capacity
;
2110 struct outline
*items
;
2119 struct point2d_index
2121 struct outline
*outline
;
2125 struct point2d_index_array
2128 struct point2d_index
*items
;
2133 struct outline_array outlines
;
2134 struct face_array faces
;
2135 struct point2d_index_array ordered_vertices
;
2139 /* is an dynamic_array */
2142 int count
, capacity
;
2146 /* complex polygons are split into monotone polygons, which have
2147 * at most 2 intersections with the vertical sweep line */
2148 struct triangulation
2150 struct word_array vertex_stack
;
2151 BOOL last_on_top
, merging
;
2154 /* is an dynamic_array */
2155 struct triangulation_array
2157 int count
, capacity
;
2158 struct triangulation
*items
;
2160 struct glyphinfo
*glyph
;
2163 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
2165 if (count
> array
->capacity
) {
2168 if (array
->items
&& array
->capacity
) {
2169 new_capacity
= max(array
->capacity
* 2, count
);
2170 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
2172 new_capacity
= max(16, count
);
2173 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
2177 array
->items
= new_buffer
;
2178 array
->capacity
= new_capacity
;
2183 static struct point2d
*add_points(struct outline
*array
, int num
)
2185 struct point2d
*item
;
2187 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
2190 item
= &array
->items
[array
->count
];
2191 array
->count
+= num
;
2195 static struct outline
*add_outline(struct outline_array
*array
)
2197 struct outline
*item
;
2199 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
2202 item
= &array
->items
[array
->count
++];
2203 ZeroMemory(item
, sizeof(*item
));
2207 static inline face
*add_face(struct face_array
*array
)
2209 return &array
->items
[array
->count
++];
2212 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
2214 struct triangulation
*item
;
2216 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
2219 item
= &array
->items
[array
->count
++];
2220 ZeroMemory(item
, sizeof(*item
));
2224 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
2226 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
2227 return E_OUTOFMEMORY
;
2229 array
->items
[array
->count
++] = vertex_index
;
2233 /* assume fixed point numbers can be converted to float point in place */
2234 C_ASSERT(sizeof(FIXED
) == sizeof(float));
2235 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
2237 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, float emsquare
)
2239 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
2241 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
2242 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
2243 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
2249 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
2250 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
2251 float max_deviation_sq
)
2253 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
2256 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
2257 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
2258 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
2260 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
2261 if (deviation_sq
< max_deviation_sq
) {
2262 struct point2d
*pt
= add_points(outline
, 1);
2263 if (!pt
) return E_OUTOFMEMORY
;
2265 pt
->corner
= POINTTYPE_CURVE
;
2266 /* the end point is omitted because the end line merges into the next segment of
2267 * the split bezier curve, and the end of the split bezier curve is added outside
2268 * this recursive function. */
2270 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
2271 if (hr
!= S_OK
) return hr
;
2272 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
2273 if (hr
!= S_OK
) return hr
;
2279 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
2281 /* dot product = cos(theta) */
2282 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
2285 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
2287 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
2297 static BOOL
attempt_line_merge(struct outline
*outline
,
2299 const D3DXVECTOR2
*nextpt
,
2301 const struct cos_table
*table
)
2303 D3DXVECTOR2 curdir
, lastdir
;
2304 struct point2d
*prevpt
, *pt
;
2307 pt
= &outline
->items
[pt_index
];
2308 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
2309 prevpt
= &outline
->items
[pt_index
];
2312 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
2314 if (outline
->count
< 2)
2317 /* remove last point if the next line continues the last line */
2318 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
2319 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
2320 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
2323 if (pt
->corner
== POINTTYPE_CURVE_END
)
2324 prevpt
->corner
= pt
->corner
;
2325 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
2326 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
2330 if (outline
->count
< 2)
2333 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
2334 prevpt
= &outline
->items
[pt_index
];
2335 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
2336 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
2341 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
2342 float max_deviation_sq
, float emsquare
, const struct cos_table
*cos_table
)
2344 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
2346 while ((char *)header
< (char *)raw_outline
+ datasize
)
2348 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
2349 struct point2d
*lastpt
, *pt
;
2350 D3DXVECTOR2 lastdir
;
2351 D3DXVECTOR2
*pt_flt
;
2353 struct outline
*outline
= add_outline(&glyph
->outlines
);
2356 return E_OUTOFMEMORY
;
2358 pt
= add_points(outline
, 1);
2360 return E_OUTOFMEMORY
;
2361 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
2363 pt
->corner
= POINTTYPE_CORNER
;
2365 if (header
->dwType
!= TT_POLYGON_TYPE
)
2366 FIXME("Unknown header type %d\n", header
->dwType
);
2368 while ((char *)curve
< (char *)header
+ header
->cb
)
2370 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
2371 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
2374 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
2378 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
2380 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
2385 int count
= curve
->cpfx
;
2390 D3DXVECTOR2 bezier_end
;
2392 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j
], &pt_flt
[j
+1]), 0.5f
);
2393 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j
], &bezier_end
, max_deviation_sq
);
2396 bezier_start
= bezier_end
;
2400 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j
], &pt_flt
[j
+1], max_deviation_sq
);
2404 pt
= add_points(outline
, 1);
2406 return E_OUTOFMEMORY
;
2408 pt
->pos
= pt_flt
[j
];
2409 pt
->corner
= POINTTYPE_CURVE_END
;
2411 pt
= add_points(outline
, curve
->cpfx
);
2413 return E_OUTOFMEMORY
;
2414 for (j
= 0; j
< curve
->cpfx
; j
++)
2416 pt
->pos
= pt_flt
[j
];
2417 pt
->corner
= POINTTYPE_CORNER
;
2422 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
2425 /* remove last point if the next line continues the last line */
2426 if (outline
->count
>= 3) {
2429 lastpt
= &outline
->items
[outline
->count
- 1];
2430 pt
= &outline
->items
[0];
2431 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
2432 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
2434 if (pt
->corner
== POINTTYPE_CURVE_START
)
2435 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
2437 pt
->corner
= POINTTYPE_CURVE_END
;
2440 lastpt
= &outline
->items
[outline
->count
- 1];
2442 /* outline closed with a line from end to start point */
2443 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
2445 lastpt
= &outline
->items
[0];
2446 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
2447 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
2448 lastpt
->corner
= POINTTYPE_CORNER
;
2449 pt
= &outline
->items
[1];
2450 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
2451 *lastpt
= outline
->items
[outline
->count
];
2454 lastpt
= &outline
->items
[outline
->count
- 1];
2455 pt
= &outline
->items
[0];
2456 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
2457 for (j
= 0; j
< outline
->count
; j
++)
2462 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
2463 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
2465 switch (lastpt
->corner
)
2467 case POINTTYPE_CURVE_START
:
2468 case POINTTYPE_CURVE_END
:
2469 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
2470 lastpt
->corner
= POINTTYPE_CORNER
;
2472 case POINTTYPE_CURVE_MIDDLE
:
2473 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
2474 lastpt
->corner
= POINTTYPE_CORNER
;
2476 lastpt
->corner
= POINTTYPE_CURVE
;
2484 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
2489 /* Get the y-distance from a line to a point */
2490 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
2491 D3DXVECTOR2
*line_pt2
,
2494 D3DXVECTOR2 line_vec
= {0, 0};
2498 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
2499 line_pt_dx
= point
->x
- line_pt1
->x
;
2500 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
2501 return point
->y
- line_y
;
2504 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
2506 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
2509 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
2511 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
2514 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
2516 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
2517 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
2521 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
2522 struct triangulation_array
*triangulations
,
2526 struct glyphinfo
*glyph
= triangulations
->glyph
;
2527 struct triangulation
*t
= *t_ptr
;
2532 if (t
->last_on_top
) {
2540 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
2541 /* consume all vertices on the stack */
2542 WORD last_pt
= t
->vertex_stack
.items
[0];
2544 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
2546 face
= add_face(&glyph
->faces
);
2547 if (!face
) return E_OUTOFMEMORY
;
2548 (*face
)[0] = vtx_idx
;
2549 (*face
)[f1
] = last_pt
;
2550 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
2552 t
->vertex_stack
.items
[0] = last_pt
;
2553 t
->vertex_stack
.count
= 1;
2554 } else if (t
->vertex_stack
.count
> 1) {
2555 int i
= t
->vertex_stack
.count
- 1;
2556 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
2557 WORD top_idx
= t
->vertex_stack
.items
[i
--];
2558 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
2562 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
2563 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
2565 if (prev_pt
->x
!= top_pt
->x
&&
2566 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
2567 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
2570 face
= add_face(&glyph
->faces
);
2571 if (!face
) return E_OUTOFMEMORY
;
2572 (*face
)[0] = vtx_idx
;
2573 (*face
)[f1
] = prev_idx
;
2574 (*face
)[f2
] = top_idx
;
2578 t
->vertex_stack
.count
--;
2581 t
->last_on_top
= to_top
;
2583 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
2585 if (hr
== S_OK
&& t
->merging
) {
2586 struct triangulation
*t2
;
2588 t2
= to_top
? t
- 1 : t
+ 1;
2589 t2
->merging
= FALSE
;
2590 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
2591 if (hr
!= S_OK
) return hr
;
2592 remove_triangulation(triangulations
, t
);
2600 /* check if the point is next on the outline for either the top or bottom */
2601 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
2603 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
2604 WORD idx
= t
->vertex_stack
.items
[i
];
2605 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
2606 struct outline
*outline
= pt_idx
->outline
;
2609 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
2611 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
2613 return &outline
->items
[i
].pos
;
2616 static int compare_vertex_indices(const void *a
, const void *b
)
2618 const struct point2d_index
*idx1
= a
, *idx2
= b
;
2619 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
2620 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
2621 float diff
= p1
->x
- p2
->x
;
2624 diff
= p1
->y
- p2
->y
;
2626 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
2629 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
2633 struct glyphinfo
*glyph
= triangulations
->glyph
;
2634 int nb_vertices
= 0;
2636 struct point2d_index
*idx_ptr
;
2638 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
2639 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
2641 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
2642 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
2643 if (!glyph
->ordered_vertices
.items
)
2644 return E_OUTOFMEMORY
;
2646 idx_ptr
= glyph
->ordered_vertices
.items
;
2647 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
2649 struct outline
*outline
= &glyph
->outlines
.items
[i
];
2652 idx_ptr
->outline
= outline
;
2653 idx_ptr
->vertex
= 0;
2655 for (j
= outline
->count
- 1; j
> 0; j
--)
2657 idx_ptr
->outline
= outline
;
2658 idx_ptr
->vertex
= j
;
2662 glyph
->ordered_vertices
.count
= nb_vertices
;
2664 /* Native implementation seems to try to create a triangle fan from
2665 * the first outline point if the glyph only has one outline. */
2666 if (glyph
->outlines
.count
== 1)
2668 struct outline
*outline
= glyph
->outlines
.items
;
2669 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
2670 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
2673 for (i
= 2; i
< outline
->count
; i
++)
2675 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
2676 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
2677 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
2679 D3DXVec2Subtract(&v1
, base
, last
);
2680 D3DXVec2Subtract(&v2
, last
, next
);
2681 ccw
= D3DXVec2CCW(&v1
, &v2
);
2689 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
2690 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
2691 if (!glyph
->faces
.items
)
2692 return E_OUTOFMEMORY
;
2694 glyph
->faces
.count
= outline
->count
- 2;
2695 for (i
= 0; i
< glyph
->faces
.count
; i
++)
2697 glyph
->faces
.items
[i
][0] = 0;
2698 glyph
->faces
.items
[i
][1] = i
+ 1;
2699 glyph
->faces
.items
[i
][2] = i
+ 2;
2705 /* Perform 2D polygon triangulation for complex glyphs.
2706 * Triangulation is performed using a sweep line concept, from right to left,
2707 * by processing vertices in sorted order. Complex polygons are split into
2708 * monotone polygons which are triangulated separately. */
2709 /* FIXME: The order of the faces is not consistent with the native implementation. */
2711 /* Reserve space for maximum possible faces from triangulation.
2712 * # faces for outer outlines = outline->count - 2
2713 * # faces for inner outlines = outline->count + 2
2714 * There must be at least 1 outer outline. */
2715 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
2716 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
2717 if (!glyph
->faces
.items
)
2718 return E_OUTOFMEMORY
;
2720 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
2721 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
2722 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
2725 int end
= triangulations
->count
;
2729 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
2730 int current
= (start
+ end
) / 2;
2731 struct triangulation
*t
= &triangulations
->items
[current
];
2732 BOOL on_top_outline
= FALSE
;
2733 D3DXVECTOR2
*top_next
, *bottom_next
;
2734 WORD top_idx
, bottom_idx
;
2736 if (t
->merging
&& t
->last_on_top
)
2737 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
2739 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
2740 if (sweep_vtx
== top_next
)
2742 if (t
->merging
&& t
->last_on_top
)
2744 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
2745 if (hr
!= S_OK
) return hr
;
2747 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
2748 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
2750 /* point also on bottom outline of higher triangulation */
2751 struct triangulation
*t2
= t
+ 1;
2752 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
2753 if (hr
!= S_OK
) return hr
;
2758 on_top_outline
= TRUE
;
2761 if (t
->merging
&& !t
->last_on_top
)
2762 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
2764 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
2765 if (sweep_vtx
== bottom_next
)
2767 if (t
->merging
&& !t
->last_on_top
)
2769 if (on_top_outline
) {
2770 /* outline finished */
2771 remove_triangulation(triangulations
, t
);
2775 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
2776 if (hr
!= S_OK
) return hr
;
2778 if (t
> triangulations
->items
&&
2779 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
2781 struct triangulation
*t2
= t
- 1;
2782 /* point also on top outline of lower triangulation */
2783 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
2784 if (hr
!= S_OK
) return hr
;
2785 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
2795 if (t
->last_on_top
) {
2796 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
2797 bottom_idx
= t
->vertex_stack
.items
[0];
2799 top_idx
= t
->vertex_stack
.items
[0];
2800 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
2803 /* check if the point is inside or outside this polygon */
2804 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
2805 top_next
, sweep_vtx
) > 0)
2807 start
= current
+ 1;
2808 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
2809 bottom_next
, sweep_vtx
) < 0)
2812 } else if (t
->merging
) {
2813 /* inside, so cancel merging */
2814 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
2816 t2
->merging
= FALSE
;
2817 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
2818 if (hr
!= S_OK
) return hr
;
2819 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
2820 if (hr
!= S_OK
) return hr
;
2823 /* inside, so split polygon into two monotone parts */
2824 struct triangulation
*t2
= add_triangulation(triangulations
);
2825 if (!t2
) return E_OUTOFMEMORY
;
2826 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
2827 if (t
->last_on_top
) {
2834 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
2835 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
2836 if (hr
!= S_OK
) return hr
;
2837 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
2838 if (hr
!= S_OK
) return hr
;
2839 t2
->last_on_top
= !t
->last_on_top
;
2841 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
2842 if (hr
!= S_OK
) return hr
;
2848 struct triangulation
*t
;
2849 struct triangulation
*t2
= add_triangulation(triangulations
);
2850 if (!t2
) return E_OUTOFMEMORY
;
2851 t
= &triangulations
->items
[start
];
2852 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
2853 ZeroMemory(t
, sizeof(*t
));
2854 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
2855 if (hr
!= S_OK
) return hr
;
2861 HRESULT WINAPI
D3DXCreateTextW(LPDIRECT3DDEVICE9 device
,
2862 HDC hdc
, LPCWSTR text
,
2863 FLOAT deviation
, FLOAT extrusion
,
2864 LPD3DXMESH
*mesh_ptr
, LPD3DXBUFFER
*adjacency
,
2865 LPGLYPHMETRICSFLOAT glyphmetrics
)
2868 ID3DXMesh
*mesh
= NULL
;
2869 DWORD nb_vertices
, nb_faces
;
2870 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
2871 struct vertex
*vertices
= NULL
;
2876 OUTLINETEXTMETRICW otm
;
2877 HFONT font
= NULL
, oldfont
= NULL
;
2878 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
2879 void *raw_outline
= NULL
;
2881 struct glyphinfo
*glyphs
= NULL
;
2883 struct triangulation_array triangulations
= {0, 0, NULL
};
2885 struct vertex
*vertex_ptr
;
2887 float max_deviation_sq
;
2888 const struct cos_table cos_table
= {
2889 cos(D3DXToRadian(0.5f
)),
2890 cos(D3DXToRadian(45.0f
)),
2891 cos(D3DXToRadian(90.0f
)),
2895 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
2896 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
2898 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
2899 return D3DERR_INVALIDCALL
;
2903 FIXME("Case of adjacency != NULL not implemented.\n");
2907 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
2908 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
2910 return D3DERR_INVALIDCALL
;
2913 if (deviation
== 0.0f
)
2914 deviation
= 1.0f
/ otm
.otmEMSquare
;
2915 max_deviation_sq
= deviation
* deviation
;
2917 lf
.lfHeight
= otm
.otmEMSquare
;
2919 font
= CreateFontIndirectW(&lf
);
2924 oldfont
= SelectObject(hdc
, font
);
2926 textlen
= strlenW(text
);
2927 for (i
= 0; i
< textlen
; i
++)
2929 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
2931 return D3DERR_INVALIDCALL
;
2932 if (bufsize
< datasize
)
2935 if (!bufsize
) { /* e.g. text == " " */
2936 hr
= D3DERR_INVALIDCALL
;
2940 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
2941 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
2942 if (!glyphs
|| !raw_outline
) {
2948 for (i
= 0; i
< textlen
; i
++)
2950 /* get outline points from data returned from GetGlyphOutline */
2953 glyphs
[i
].offset_x
= offset_x
;
2955 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
2956 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
2957 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
2958 if (hr
!= S_OK
) goto error
;
2960 triangulations
.glyph
= &glyphs
[i
];
2961 hr
= triangulate(&triangulations
);
2962 if (hr
!= S_OK
) goto error
;
2963 if (triangulations
.count
) {
2964 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
2965 triangulations
.count
= 0;
2970 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
2971 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
2972 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
2973 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
2974 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
2975 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
2977 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
2980 /* corner points need an extra vertex for the different side faces normals */
2982 nb_outline_points
= 0;
2984 for (i
= 0; i
< textlen
; i
++)
2987 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
2988 nb_front_faces
+= glyphs
[i
].faces
.count
;
2989 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
2992 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
2993 nb_corners
++; /* first outline point always repeated as a corner */
2994 for (k
= 1; k
< outline
->count
; k
++)
2995 if (outline
->items
[k
].corner
)
3000 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
3001 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
3004 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
3005 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
3009 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_DISCARD
, (LPVOID
*)&vertices
);
3013 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_DISCARD
, (LPVOID
*)&faces
);
3017 /* convert 2D vertices and faces into 3D mesh */
3018 vertex_ptr
= vertices
;
3020 if (extrusion
== 0.0f
) {
3027 for (i
= 0; i
< textlen
; i
++)
3031 struct vertex
*back_vertices
;
3034 /* side vertices and faces */
3035 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
3037 struct vertex
*outline_vertices
= vertex_ptr
;
3038 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
3040 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
3041 struct point2d
*pt
= &outline
->items
[0];
3043 for (k
= 1; k
<= outline
->count
; k
++)
3046 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
3047 WORD vtx_idx
= vertex_ptr
- vertices
;
3050 if (pt
->corner
== POINTTYPE_CURVE_START
)
3051 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
3052 else if (pt
->corner
)
3053 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
3055 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
3056 D3DXVec2Normalize(&vec
, &vec
);
3057 vtx
.normal
.x
= -vec
.y
;
3058 vtx
.normal
.y
= vec
.x
;
3061 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
3062 vtx
.position
.y
= pt
->pos
.y
;
3064 *vertex_ptr
++ = vtx
;
3066 vtx
.position
.z
= -extrusion
;
3067 *vertex_ptr
++ = vtx
;
3069 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
3070 vtx
.position
.y
= nextpt
->pos
.y
;
3071 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
3072 vtx
.position
.z
= -extrusion
;
3073 *vertex_ptr
++ = vtx
;
3075 *vertex_ptr
++ = vtx
;
3077 (*face_ptr
)[0] = vtx_idx
;
3078 (*face_ptr
)[1] = vtx_idx
+ 2;
3079 (*face_ptr
)[2] = vtx_idx
+ 1;
3082 (*face_ptr
)[0] = vtx_idx
;
3083 (*face_ptr
)[1] = vtx_idx
+ 3;
3084 (*face_ptr
)[2] = vtx_idx
+ 2;
3087 if (nextpt
->corner
) {
3088 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
3089 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
3090 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
3092 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
3094 D3DXVec2Normalize(&vec
, &vec
);
3095 vtx
.normal
.x
= -vec
.y
;
3096 vtx
.normal
.y
= vec
.x
;
3099 *vertex_ptr
++ = vtx
;
3100 vtx
.position
.z
= -extrusion
;
3101 *vertex_ptr
++ = vtx
;
3104 (*face_ptr
)[0] = vtx_idx
;
3105 (*face_ptr
)[1] = vtx_idx
+ 3;
3106 (*face_ptr
)[2] = vtx_idx
+ 1;
3109 (*face_ptr
)[0] = vtx_idx
;
3110 (*face_ptr
)[1] = vtx_idx
+ 2;
3111 (*face_ptr
)[2] = vtx_idx
+ 3;
3119 *vertex_ptr
++ = *outline_vertices
++;
3120 *vertex_ptr
++ = *outline_vertices
++;
3124 /* back vertices and faces */
3125 back_faces
= face_ptr
;
3126 back_vertices
= vertex_ptr
;
3127 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
3129 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
3130 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
3131 vertex_ptr
->position
.y
= pt
->y
;
3132 vertex_ptr
->position
.z
= 0;
3133 vertex_ptr
->normal
.x
= 0;
3134 vertex_ptr
->normal
.y
= 0;
3135 vertex_ptr
->normal
.z
= 1;
3138 count
= back_vertices
- vertices
;
3139 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
3141 face
*f
= &glyphs
[i
].faces
.items
[j
];
3142 (*face_ptr
)[0] = (*f
)[0] + count
;
3143 (*face_ptr
)[1] = (*f
)[1] + count
;
3144 (*face_ptr
)[2] = (*f
)[2] + count
;
3148 /* front vertices and faces */
3149 j
= count
= vertex_ptr
- back_vertices
;
3152 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
3153 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
3154 vertex_ptr
->position
.z
= -extrusion
;
3155 vertex_ptr
->normal
.x
= 0;
3156 vertex_ptr
->normal
.y
= 0;
3157 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
3161 j
= face_ptr
- back_faces
;
3164 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
3165 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
3166 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
3176 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
3177 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
3178 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
3181 for (i
= 0; i
< textlen
; i
++)
3184 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
3185 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
3186 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
3187 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
3188 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
3190 HeapFree(GetProcessHeap(), 0, glyphs
);
3192 if (triangulations
.items
) {
3194 for (i
= 0; i
< triangulations
.count
; i
++)
3195 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
3196 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
3198 HeapFree(GetProcessHeap(), 0, raw_outline
);
3199 if (oldfont
) SelectObject(hdc
, oldfont
);
3200 if (font
) DeleteObject(font
);