2 * Mesh operations specific to D3DX9.
4 * Copyright (C) 2005 Henri Verbeet
5 * Copyright (C) 2006 Ivan Gyurdiev
6 * Copyright (C) 2009 David Adam
7 * Copyright (C) 2010 Tony Wasserka
8 * Copyright (C) 2011 Dylan Smith
9 * Copyright (C) 2011 Michael Mc Donnell
10 * Copyright (C) 2013 Christian Costa
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "d3dx9_36_private.h"
36 #include "wine/list.h"
40 ID3DXMesh ID3DXMesh_iface
;
47 IDirect3DDevice9
*device
;
48 D3DVERTEXELEMENT9 cached_declaration
[MAX_FVF_DECL_SIZE
];
49 IDirect3DVertexDeclaration9
*vertex_declaration
;
50 UINT vertex_declaration_size
;
52 IDirect3DVertexBuffer9
*vertex_buffer
;
53 IDirect3DIndexBuffer9
*index_buffer
;
55 int attrib_buffer_lock_count
;
56 DWORD attrib_table_size
;
57 D3DXATTRIBUTERANGE
*attrib_table
;
60 static const UINT d3dx_decltype_size
[] =
62 /* D3DDECLTYPE_FLOAT1 */ sizeof(FLOAT
),
63 /* D3DDECLTYPE_FLOAT2 */ sizeof(D3DXVECTOR2
),
64 /* D3DDECLTYPE_FLOAT3 */ sizeof(D3DXVECTOR3
),
65 /* D3DDECLTYPE_FLOAT4 */ sizeof(D3DXVECTOR4
),
66 /* D3DDECLTYPE_D3DCOLOR */ sizeof(D3DCOLOR
),
67 /* D3DDECLTYPE_UBYTE4 */ 4 * sizeof(BYTE
),
68 /* D3DDECLTYPE_SHORT2 */ 2 * sizeof(SHORT
),
69 /* D3DDECLTYPE_SHORT4 */ 4 * sizeof(SHORT
),
70 /* D3DDECLTYPE_UBYTE4N */ 4 * sizeof(BYTE
),
71 /* D3DDECLTYPE_SHORT2N */ 2 * sizeof(SHORT
),
72 /* D3DDECLTYPE_SHORT4N */ 4 * sizeof(SHORT
),
73 /* D3DDECLTYPE_USHORT2N */ 2 * sizeof(USHORT
),
74 /* D3DDECLTYPE_USHORT4N */ 4 * sizeof(USHORT
),
75 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
76 /* D3DDECLTYPE_DEC3N */ 4,
77 /* D3DDECLTYPE_FLOAT16_2 */ 2 * sizeof(D3DXFLOAT16
),
78 /* D3DDECLTYPE_FLOAT16_4 */ 4 * sizeof(D3DXFLOAT16
),
81 static inline struct d3dx9_mesh
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
83 return CONTAINING_RECORD(iface
, struct d3dx9_mesh
, ID3DXMesh_iface
);
86 static HRESULT WINAPI
d3dx9_mesh_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, void **out
)
88 TRACE("iface %p, riid %s, out %p.\n", iface
, debugstr_guid(riid
), out
);
90 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
91 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
92 IsEqualGUID(riid
, &IID_ID3DXMesh
))
94 iface
->lpVtbl
->AddRef(iface
);
99 WARN("Interface %s not found.\n", debugstr_guid(riid
));
101 return E_NOINTERFACE
;
104 static ULONG WINAPI
d3dx9_mesh_AddRef(ID3DXMesh
*iface
)
106 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
107 ULONG refcount
= InterlockedIncrement(&mesh
->ref
);
109 TRACE("%p increasing refcount to %u.\n", mesh
, refcount
);
114 static ULONG WINAPI
d3dx9_mesh_Release(ID3DXMesh
*iface
)
116 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
117 ULONG refcount
= InterlockedDecrement(&mesh
->ref
);
119 TRACE("%p decreasing refcount to %u.\n", mesh
, refcount
);
123 IDirect3DIndexBuffer9_Release(mesh
->index_buffer
);
124 IDirect3DVertexBuffer9_Release(mesh
->vertex_buffer
);
125 if (mesh
->vertex_declaration
)
126 IDirect3DVertexDeclaration9_Release(mesh
->vertex_declaration
);
127 IDirect3DDevice9_Release(mesh
->device
);
128 HeapFree(GetProcessHeap(), 0, mesh
->attrib_buffer
);
129 HeapFree(GetProcessHeap(), 0, mesh
->attrib_table
);
130 HeapFree(GetProcessHeap(), 0, mesh
);
136 static HRESULT WINAPI
d3dx9_mesh_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
138 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
144 TRACE("iface %p, attrib_id %u.\n", iface
, attrib_id
);
146 if (!This
->vertex_declaration
)
148 WARN("Can't draw a mesh with an invalid vertex declaration.\n");
152 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
154 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
155 if (FAILED(hr
)) return hr
;
156 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
157 if (FAILED(hr
)) return hr
;
158 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
159 if (FAILED(hr
)) return hr
;
161 while (face_end
< This
->numfaces
)
163 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
165 if (This
->attrib_buffer
[face_start
] == attrib_id
)
168 if (face_start
>= This
->numfaces
)
170 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
172 if (This
->attrib_buffer
[face_end
] != attrib_id
)
176 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
177 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
178 if (FAILED(hr
)) return hr
;
184 static DWORD WINAPI
d3dx9_mesh_GetNumFaces(ID3DXMesh
*iface
)
186 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
188 TRACE("iface %p.\n", iface
);
190 return mesh
->numfaces
;
193 static DWORD WINAPI
d3dx9_mesh_GetNumVertices(ID3DXMesh
*iface
)
195 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
197 TRACE("iface %p.\n", iface
);
199 return mesh
->numvertices
;
202 static DWORD WINAPI
d3dx9_mesh_GetFVF(ID3DXMesh
*iface
)
204 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
206 TRACE("iface %p.\n", iface
);
211 static void copy_declaration(D3DVERTEXELEMENT9
*dst
, const D3DVERTEXELEMENT9
*src
, UINT num_elem
)
213 memcpy(dst
, src
, num_elem
* sizeof(*src
));
216 static HRESULT WINAPI
d3dx9_mesh_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
218 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
220 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
223 return D3DERR_INVALIDCALL
;
225 copy_declaration(declaration
, mesh
->cached_declaration
, mesh
->num_elem
);
230 static DWORD WINAPI
d3dx9_mesh_GetNumBytesPerVertex(ID3DXMesh
*iface
)
232 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
234 TRACE("iface %p.\n", iface
);
236 return mesh
->vertex_declaration_size
;
239 static DWORD WINAPI
d3dx9_mesh_GetOptions(ID3DXMesh
*iface
)
241 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
243 TRACE("iface %p.\n", iface
);
245 return mesh
->options
;
248 static HRESULT WINAPI
d3dx9_mesh_GetDevice(struct ID3DXMesh
*iface
, struct IDirect3DDevice9
**device
)
250 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
252 TRACE("iface %p, device %p.\n", iface
, device
);
255 return D3DERR_INVALIDCALL
;
256 *device
= mesh
->device
;
257 IDirect3DDevice9_AddRef(mesh
->device
);
262 static HRESULT WINAPI
d3dx9_mesh_CloneMeshFVF(struct ID3DXMesh
*iface
, DWORD options
, DWORD fvf
,
263 struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh
)
266 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
268 TRACE("iface %p, options %#x, fvf %#x, device %p, clone_mesh %p.\n",
269 iface
, options
, fvf
, device
, clone_mesh
);
271 if (FAILED(hr
= D3DXDeclaratorFromFVF(fvf
, declaration
)))
274 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
277 static FLOAT
scale_clamp_ubyten(FLOAT value
)
279 value
= value
* UCHAR_MAX
;
287 if (value
> UCHAR_MAX
) /* Clamp at 255 */
294 static FLOAT
scale_clamp_shortn(FLOAT value
)
296 value
= value
* SHRT_MAX
;
298 /* The tests show that the range is SHRT_MIN + 1 to SHRT_MAX. */
299 if (value
<= SHRT_MIN
)
303 else if (value
> SHRT_MAX
)
313 static FLOAT
scale_clamp_ushortn(FLOAT value
)
315 value
= value
* USHRT_MAX
;
323 if (value
> USHRT_MAX
) /* Clamp at 65535 */
330 static INT
simple_round(FLOAT value
)
332 int res
= (INT
)(value
+ 0.5f
);
337 static void convert_float4(BYTE
*dst
, const D3DXVECTOR4
*src
, D3DDECLTYPE type_dst
)
339 BOOL fixme_once
= FALSE
;
343 case D3DDECLTYPE_FLOAT1
:
345 FLOAT
*dst_ptr
= (FLOAT
*)dst
;
349 case D3DDECLTYPE_FLOAT2
:
351 D3DXVECTOR2
*dst_ptr
= (D3DXVECTOR2
*)dst
;
356 case D3DDECLTYPE_FLOAT3
:
358 D3DXVECTOR3
*dst_ptr
= (D3DXVECTOR3
*)dst
;
364 case D3DDECLTYPE_FLOAT4
:
366 D3DXVECTOR4
*dst_ptr
= (D3DXVECTOR4
*)dst
;
373 case D3DDECLTYPE_D3DCOLOR
:
375 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
376 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
377 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
378 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
381 case D3DDECLTYPE_UBYTE4
:
383 dst
[0] = src
->x
< 0.0f
? 0 : (BYTE
)simple_round(src
->x
);
384 dst
[1] = src
->y
< 0.0f
? 0 : (BYTE
)simple_round(src
->y
);
385 dst
[2] = src
->z
< 0.0f
? 0 : (BYTE
)simple_round(src
->z
);
386 dst
[3] = src
->w
< 0.0f
? 0 : (BYTE
)simple_round(src
->w
);
389 case D3DDECLTYPE_SHORT2
:
391 SHORT
*dst_ptr
= (SHORT
*)dst
;
392 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
393 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
396 case D3DDECLTYPE_SHORT4
:
398 SHORT
*dst_ptr
= (SHORT
*)dst
;
399 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
400 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
401 dst_ptr
[2] = (SHORT
)simple_round(src
->z
);
402 dst_ptr
[3] = (SHORT
)simple_round(src
->w
);
405 case D3DDECLTYPE_UBYTE4N
:
407 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
408 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
409 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
410 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
413 case D3DDECLTYPE_SHORT2N
:
415 SHORT
*dst_ptr
= (SHORT
*)dst
;
416 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
417 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
420 case D3DDECLTYPE_SHORT4N
:
422 SHORT
*dst_ptr
= (SHORT
*)dst
;
423 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
424 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
425 dst_ptr
[2] = (SHORT
)simple_round(scale_clamp_shortn(src
->z
));
426 dst_ptr
[3] = (SHORT
)simple_round(scale_clamp_shortn(src
->w
));
429 case D3DDECLTYPE_USHORT2N
:
431 USHORT
*dst_ptr
= (USHORT
*)dst
;
432 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
433 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
436 case D3DDECLTYPE_USHORT4N
:
438 USHORT
*dst_ptr
= (USHORT
*)dst
;
439 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
440 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
441 dst_ptr
[2] = (USHORT
)simple_round(scale_clamp_ushortn(src
->z
));
442 dst_ptr
[3] = (USHORT
)simple_round(scale_clamp_ushortn(src
->w
));
445 case D3DDECLTYPE_FLOAT16_2
:
447 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 2);
450 case D3DDECLTYPE_FLOAT16_4
:
452 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 4);
457 FIXME("Conversion from D3DDECLTYPE_FLOAT4 to %d not implemented.\n", type_dst
);
462 static void convert_component(BYTE
*dst
, BYTE
*src
, D3DDECLTYPE type_dst
, D3DDECLTYPE type_src
)
464 BOOL fixme_once
= FALSE
;
468 case D3DDECLTYPE_FLOAT1
:
470 FLOAT
*src_ptr
= (FLOAT
*)src
;
471 D3DXVECTOR4 src_float4
= {*src_ptr
, 0.0f
, 0.0f
, 1.0f
};
472 convert_float4(dst
, &src_float4
, type_dst
);
475 case D3DDECLTYPE_FLOAT2
:
477 D3DXVECTOR2
*src_ptr
= (D3DXVECTOR2
*)src
;
478 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, 0.0f
, 1.0f
};
479 convert_float4(dst
, &src_float4
, type_dst
);
482 case D3DDECLTYPE_FLOAT3
:
484 D3DXVECTOR3
*src_ptr
= (D3DXVECTOR3
*)src
;
485 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, 1.0f
};
486 convert_float4(dst
, &src_float4
, type_dst
);
489 case D3DDECLTYPE_FLOAT4
:
491 D3DXVECTOR4
*src_ptr
= (D3DXVECTOR4
*)src
;
492 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, src_ptr
->w
};
493 convert_float4(dst
, &src_float4
, type_dst
);
496 case D3DDECLTYPE_D3DCOLOR
:
498 D3DXVECTOR4 src_float4
=
500 (FLOAT
)src
[2]/UCHAR_MAX
,
501 (FLOAT
)src
[1]/UCHAR_MAX
,
502 (FLOAT
)src
[0]/UCHAR_MAX
,
503 (FLOAT
)src
[3]/UCHAR_MAX
505 convert_float4(dst
, &src_float4
, type_dst
);
508 case D3DDECLTYPE_UBYTE4
:
510 D3DXVECTOR4 src_float4
= {src
[0], src
[1], src
[2], src
[3]};
511 convert_float4(dst
, &src_float4
, type_dst
);
514 case D3DDECLTYPE_SHORT2
:
516 SHORT
*src_ptr
= (SHORT
*)src
;
517 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], 0.0f
, 1.0f
};
518 convert_float4(dst
, &src_float4
, type_dst
);
521 case D3DDECLTYPE_SHORT4
:
523 SHORT
*src_ptr
= (SHORT
*)src
;
524 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], src_ptr
[2], src_ptr
[3]};
525 convert_float4(dst
, &src_float4
, type_dst
);
528 case D3DDECLTYPE_UBYTE4N
:
530 D3DXVECTOR4 src_float4
=
532 (FLOAT
)src
[0]/UCHAR_MAX
,
533 (FLOAT
)src
[1]/UCHAR_MAX
,
534 (FLOAT
)src
[2]/UCHAR_MAX
,
535 (FLOAT
)src
[3]/UCHAR_MAX
537 convert_float4(dst
, &src_float4
, type_dst
);
540 case D3DDECLTYPE_SHORT2N
:
542 SHORT
*src_ptr
= (SHORT
*)src
;
543 D3DXVECTOR4 src_float4
= {(FLOAT
)src_ptr
[0]/SHRT_MAX
, (FLOAT
)src_ptr
[1]/SHRT_MAX
, 0.0f
, 1.0f
};
544 convert_float4(dst
, &src_float4
, type_dst
);
547 case D3DDECLTYPE_SHORT4N
:
549 SHORT
*src_ptr
= (SHORT
*)src
;
550 D3DXVECTOR4 src_float4
=
552 (FLOAT
)src_ptr
[0]/SHRT_MAX
,
553 (FLOAT
)src_ptr
[1]/SHRT_MAX
,
554 (FLOAT
)src_ptr
[2]/SHRT_MAX
,
555 (FLOAT
)src_ptr
[3]/SHRT_MAX
557 convert_float4(dst
, &src_float4
, type_dst
);
560 case D3DDECLTYPE_FLOAT16_2
:
562 D3DXVECTOR4 src_float4
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
563 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 2);
564 convert_float4(dst
, &src_float4
, type_dst
);
567 case D3DDECLTYPE_FLOAT16_4
:
569 D3DXVECTOR4 src_float4
;
570 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 4);
571 convert_float4(dst
, &src_float4
, type_dst
);
576 FIXME("Conversion of D3DDECLTYPE %d to %d not implemented.\n", type_src
, type_dst
);
581 static INT
get_equivalent_declaration_index(D3DVERTEXELEMENT9 orig_declaration
, D3DVERTEXELEMENT9
*declaration
)
585 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
587 if (orig_declaration
.Usage
== declaration
[i
].Usage
588 && orig_declaration
.UsageIndex
== declaration
[i
].UsageIndex
)
597 static HRESULT
convert_vertex_buffer(ID3DXMesh
*mesh_dst
, ID3DXMesh
*mesh_src
)
600 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
601 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
605 UINT num_vertices
= mesh_src
->lpVtbl
->GetNumVertices(mesh_src
);
606 UINT dst_vertex_size
= mesh_dst
->lpVtbl
->GetNumBytesPerVertex(mesh_dst
);
607 UINT src_vertex_size
= mesh_src
->lpVtbl
->GetNumBytesPerVertex(mesh_src
);
609 hr
= mesh_src
->lpVtbl
->GetDeclaration(mesh_src
, orig_declaration
);
610 if (FAILED(hr
)) return hr
;
611 hr
= mesh_dst
->lpVtbl
->GetDeclaration(mesh_dst
, declaration
);
612 if (FAILED(hr
)) return hr
;
614 hr
= mesh_src
->lpVtbl
->LockVertexBuffer(mesh_src
, D3DLOCK_READONLY
, (void**)&vb_src
);
615 if (FAILED(hr
)) goto cleanup
;
616 hr
= mesh_dst
->lpVtbl
->LockVertexBuffer(mesh_dst
, 0, (void**)&vb_dst
);
617 if (FAILED(hr
)) goto cleanup
;
619 /* Clear all new fields by clearing the entire vertex buffer. */
620 memset(vb_dst
, 0, num_vertices
* dst_vertex_size
);
622 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++)
624 INT eq_idx
= get_equivalent_declaration_index(orig_declaration
[i
], declaration
);
629 for (j
= 0; j
< num_vertices
; j
++)
631 UINT idx_dst
= dst_vertex_size
* j
+ declaration
[eq_idx
].Offset
;
632 UINT idx_src
= src_vertex_size
* j
+ orig_declaration
[i
].Offset
;
633 UINT type_size
= d3dx_decltype_size
[orig_declaration
[i
].Type
];
635 if (orig_declaration
[i
].Type
== declaration
[eq_idx
].Type
)
636 memcpy(&vb_dst
[idx_dst
], &vb_src
[idx_src
], type_size
);
638 convert_component(&vb_dst
[idx_dst
], &vb_src
[idx_src
], declaration
[eq_idx
].Type
, orig_declaration
[i
].Type
);
645 if (vb_dst
) mesh_dst
->lpVtbl
->UnlockVertexBuffer(mesh_dst
);
646 if (vb_src
) mesh_src
->lpVtbl
->UnlockVertexBuffer(mesh_src
);
651 static BOOL
declaration_equals(const D3DVERTEXELEMENT9
*declaration1
, const D3DVERTEXELEMENT9
*declaration2
)
653 UINT size1
= 0, size2
= 0;
655 /* Find the size of each declaration */
656 while (declaration1
[size1
].Stream
!= 0xff) size1
++;
657 while (declaration2
[size2
].Stream
!= 0xff) size2
++;
659 /* If not same size then they are definitely not equal */
663 /* Check that all components are the same */
664 if (memcmp(declaration1
, declaration2
, size1
*sizeof(*declaration1
)) == 0)
670 static HRESULT WINAPI
d3dx9_mesh_CloneMesh(struct ID3DXMesh
*iface
, DWORD options
,
671 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh_out
)
673 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
674 struct d3dx9_mesh
*cloned_this
;
675 ID3DXMesh
*clone_mesh
;
676 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
677 void *data_in
, *data_out
;
680 BOOL same_declaration
;
682 TRACE("iface %p, options %#x, declaration %p, device %p, clone_mesh_out %p.\n",
683 iface
, options
, declaration
, device
, clone_mesh_out
);
686 return D3DERR_INVALIDCALL
;
688 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
689 if (FAILED(hr
)) return hr
;
691 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
692 declaration
, device
, &clone_mesh
);
693 if (FAILED(hr
)) return hr
;
695 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
696 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
697 same_declaration
= declaration_equals(declaration
, orig_declaration
);
699 if (options
& D3DXMESH_VB_SHARE
) {
700 if (!same_declaration
) {
701 hr
= D3DERR_INVALIDCALL
;
704 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
705 /* FIXME: refactor to avoid creating a new vertex buffer */
706 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
707 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
708 } else if (same_declaration
) {
709 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
710 if (FAILED(hr
)) goto error
;
711 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, 0, &data_out
);
713 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
716 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
717 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
718 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
720 hr
= convert_vertex_buffer(clone_mesh
, iface
);
721 if (FAILED(hr
)) goto error
;
724 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
725 if (FAILED(hr
)) goto error
;
726 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, 0, &data_out
);
728 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
731 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
733 if (options
& D3DXMESH_32BIT
) {
734 for (i
= 0; i
< This
->numfaces
* 3; i
++)
735 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
737 for (i
= 0; i
< This
->numfaces
* 3; i
++)
738 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
741 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
743 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
744 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
746 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
748 if (This
->attrib_table_size
)
750 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
751 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
752 if (!cloned_this
->attrib_table
) {
756 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
759 *clone_mesh_out
= clone_mesh
;
763 IUnknown_Release(clone_mesh
);
767 static HRESULT WINAPI
d3dx9_mesh_GetVertexBuffer(struct ID3DXMesh
*iface
,
768 struct IDirect3DVertexBuffer9
**vertex_buffer
)
770 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
772 TRACE("iface %p, vertex_buffer %p.\n", iface
, vertex_buffer
);
775 return D3DERR_INVALIDCALL
;
776 *vertex_buffer
= mesh
->vertex_buffer
;
777 IDirect3DVertexBuffer9_AddRef(mesh
->vertex_buffer
);
782 static HRESULT WINAPI
d3dx9_mesh_GetIndexBuffer(struct ID3DXMesh
*iface
,
783 struct IDirect3DIndexBuffer9
**index_buffer
)
785 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
787 TRACE("iface %p, index_buffer %p.\n", iface
, index_buffer
);
790 return D3DERR_INVALIDCALL
;
791 *index_buffer
= mesh
->index_buffer
;
792 IDirect3DIndexBuffer9_AddRef(mesh
->index_buffer
);
797 static HRESULT WINAPI
d3dx9_mesh_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
799 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
801 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
803 return IDirect3DVertexBuffer9_Lock(mesh
->vertex_buffer
, 0, 0, data
, flags
);
806 static HRESULT WINAPI
d3dx9_mesh_UnlockVertexBuffer(ID3DXMesh
*iface
)
808 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
810 TRACE("iface %p.\n", iface
);
812 return IDirect3DVertexBuffer9_Unlock(mesh
->vertex_buffer
);
815 static HRESULT WINAPI
d3dx9_mesh_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
817 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
819 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
821 return IDirect3DIndexBuffer9_Lock(mesh
->index_buffer
, 0, 0, data
, flags
);
824 static HRESULT WINAPI
d3dx9_mesh_UnlockIndexBuffer(ID3DXMesh
*iface
)
826 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
828 TRACE("iface %p.\n", iface
);
830 return IDirect3DIndexBuffer9_Unlock(mesh
->index_buffer
);
833 /* FIXME: This looks just wrong, we never check *attrib_table_size before
834 * copying the data. */
835 static HRESULT WINAPI
d3dx9_mesh_GetAttributeTable(ID3DXMesh
*iface
,
836 D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
838 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
840 TRACE("iface %p, attrib_table %p, attrib_table_size %p.\n",
841 iface
, attrib_table
, attrib_table_size
);
843 if (attrib_table_size
)
844 *attrib_table_size
= mesh
->attrib_table_size
;
847 memcpy(attrib_table
, mesh
->attrib_table
, mesh
->attrib_table_size
* sizeof(*attrib_table
));
862 struct edge_face
*entries
;
865 /* Builds up a map of which face a new edge belongs to. That way the adjacency
866 * of another edge can be looked up. An edge has an adjacent face if there
867 * is an edge going in the opposite direction in the map. For example if the
868 * edge (v1, v2) belongs to face 4, and there is a mapping (v2, v1)->7, then
869 * face 4 and 7 are adjacent.
871 * Each edge might have been replaced with another edge, or none at all. There
872 * is at most one edge to face mapping, i.e. an edge can only belong to one
875 static HRESULT
init_edge_face_map(struct edge_face_map
*edge_face_map
, const DWORD
*index_buffer
,
876 const DWORD
*point_reps
, DWORD num_faces
)
881 edge_face_map
->lists
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->lists
));
882 if (!edge_face_map
->lists
) return E_OUTOFMEMORY
;
884 edge_face_map
->entries
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->entries
));
885 if (!edge_face_map
->entries
) return E_OUTOFMEMORY
;
888 /* Initialize all lists */
889 for (i
= 0; i
< 3 * num_faces
; i
++)
891 list_init(&edge_face_map
->lists
[i
]);
893 /* Build edge face mapping */
894 for (face
= 0; face
< num_faces
; face
++)
896 for (edge
= 0; edge
< 3; edge
++)
898 DWORD v1
= index_buffer
[3*face
+ edge
];
899 DWORD v2
= index_buffer
[3*face
+ (edge
+1)%3];
900 DWORD new_v1
= point_reps
[v1
]; /* What v1 has been replaced with */
901 DWORD new_v2
= point_reps
[v2
];
903 if (v1
!= v2
) /* Only map non-collapsed edges */
906 edge_face_map
->entries
[i
].v2
= new_v2
;
907 edge_face_map
->entries
[i
].face
= face
;
908 list_add_head(&edge_face_map
->lists
[new_v1
], &edge_face_map
->entries
[i
].entry
);
916 static DWORD
find_adjacent_face(struct edge_face_map
*edge_face_map
, DWORD vertex1
, DWORD vertex2
, DWORD num_faces
)
918 struct edge_face
*edge_face_ptr
;
920 LIST_FOR_EACH_ENTRY(edge_face_ptr
, &edge_face_map
->lists
[vertex2
], struct edge_face
, entry
)
922 if (edge_face_ptr
->v2
== vertex1
)
923 return edge_face_ptr
->face
;
929 static DWORD
*generate_identity_point_reps(DWORD num_vertices
)
931 DWORD
*id_point_reps
;
934 id_point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*id_point_reps
));
938 for (i
= 0; i
< num_vertices
; i
++)
940 id_point_reps
[i
] = i
;
943 return id_point_reps
;
946 static HRESULT WINAPI
d3dx9_mesh_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
,
947 const DWORD
*point_reps
, DWORD
*adjacency
)
950 DWORD num_faces
= iface
->lpVtbl
->GetNumFaces(iface
);
951 DWORD num_vertices
= iface
->lpVtbl
->GetNumVertices(iface
);
952 DWORD options
= iface
->lpVtbl
->GetOptions(iface
);
953 BOOL indices_are_16_bit
= !(options
& D3DXMESH_32BIT
);
958 struct edge_face_map edge_face_map
= {0};
959 const DWORD
*point_reps_ptr
= NULL
;
960 DWORD
*id_point_reps
= NULL
;
962 TRACE("iface %p, point_reps %p, adjacency %p.\n", iface
, point_reps
, adjacency
);
964 if (!adjacency
) return D3DERR_INVALIDCALL
;
966 if (!point_reps
) /* Identity point reps */
968 id_point_reps
= generate_identity_point_reps(num_vertices
);
975 point_reps_ptr
= id_point_reps
;
979 point_reps_ptr
= point_reps
;
982 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &ib_ptr
);
983 if (FAILED(hr
)) goto cleanup
;
985 if (indices_are_16_bit
)
987 /* Widen 16 bit to 32 bit */
989 WORD
*ib_16bit
= ib_ptr
;
990 ib
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(DWORD
));
996 for (i
= 0; i
< 3 * num_faces
; i
++)
1006 hr
= init_edge_face_map(&edge_face_map
, ib
, point_reps_ptr
, num_faces
);
1007 if (FAILED(hr
)) goto cleanup
;
1009 /* Create adjacency */
1010 for (face
= 0; face
< num_faces
; face
++)
1012 for (edge
= 0; edge
< 3; edge
++)
1014 DWORD v1
= ib
[3*face
+ edge
];
1015 DWORD v2
= ib
[3*face
+ (edge
+1)%3];
1016 DWORD new_v1
= point_reps_ptr
[v1
];
1017 DWORD new_v2
= point_reps_ptr
[v2
];
1020 adj_face
= find_adjacent_face(&edge_face_map
, new_v1
, new_v2
, num_faces
);
1021 adjacency
[3*face
+ edge
] = adj_face
;
1027 HeapFree(GetProcessHeap(), 0, id_point_reps
);
1028 if (indices_are_16_bit
) HeapFree(GetProcessHeap(), 0, ib
);
1029 HeapFree(GetProcessHeap(), 0, edge_face_map
.lists
);
1030 HeapFree(GetProcessHeap(), 0, edge_face_map
.entries
);
1031 if(ib_ptr
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1035 /* ConvertAdjacencyToPointReps helper function.
1037 * Goes around the edges of each face and replaces the vertices in any adjacent
1038 * face's edge with its own vertices(if its vertices have a lower index). This
1039 * way as few as possible low index vertices are shared among the faces. The
1040 * re-ordered index buffer is stored in new_indices.
1042 * The vertices in a point representation must be ordered sequentially, e.g.
1043 * index 5 holds the index of the vertex that replaces vertex 5, i.e. if
1044 * vertex 5 is replaced by vertex 3 then index 5 would contain 3. If no vertex
1045 * replaces it, then it contains the same number as the index itself, e.g.
1046 * index 5 would contain 5. */
1047 static HRESULT
propagate_face_vertices(const DWORD
*adjacency
, DWORD
*point_reps
,
1048 const DWORD
*indices
, DWORD
*new_indices
, DWORD face
, DWORD numfaces
)
1050 const unsigned int VERTS_PER_FACE
= 3;
1051 DWORD edge
, opp_edge
;
1052 DWORD face_base
= VERTS_PER_FACE
* face
;
1054 for (edge
= 0; edge
< VERTS_PER_FACE
; edge
++)
1056 DWORD adj_face
= adjacency
[face_base
+ edge
];
1057 DWORD adj_face_base
;
1059 if (adj_face
== -1) /* No adjacent face. */
1061 else if (adj_face
>= numfaces
)
1063 /* This throws exception on Windows */
1064 WARN("Index out of bounds. Got %d expected less than %d.\n",
1065 adj_face
, numfaces
);
1066 return D3DERR_INVALIDCALL
;
1068 adj_face_base
= 3 * adj_face
;
1070 /* Find opposite edge in adjacent face. */
1071 for (opp_edge
= 0; opp_edge
< VERTS_PER_FACE
; opp_edge
++)
1073 DWORD opp_edge_index
= adj_face_base
+ opp_edge
;
1074 if (adjacency
[opp_edge_index
] == face
)
1075 break; /* Found opposite edge. */
1078 /* Replaces vertices in opposite edge with vertices from current edge. */
1079 for (i
= 0; i
< 2; i
++)
1081 DWORD from
= face_base
+ (edge
+ (1 - i
)) % VERTS_PER_FACE
;
1082 DWORD to
= adj_face_base
+ (opp_edge
+ i
) % VERTS_PER_FACE
;
1084 /* Propagate lowest index. */
1085 if (new_indices
[to
] > new_indices
[from
])
1087 new_indices
[to
] = new_indices
[from
];
1088 point_reps
[indices
[to
]] = new_indices
[from
];
1096 static HRESULT WINAPI
d3dx9_mesh_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
,
1097 const DWORD
*adjacency
, DWORD
*point_reps
)
1099 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1103 DWORD
*indices
= NULL
;
1104 WORD
*indices_16bit
= NULL
;
1105 DWORD
*new_indices
= NULL
;
1106 const unsigned int VERTS_PER_FACE
= 3;
1108 TRACE("iface %p, adjacency %p, point_reps %p.\n", iface
, adjacency
, point_reps
);
1112 WARN("NULL adjacency.\n");
1113 hr
= D3DERR_INVALIDCALL
;
1119 WARN("NULL point_reps.\n");
1120 hr
= D3DERR_INVALIDCALL
;
1124 /* Should never happen as CreateMesh does not allow meshes with 0 faces */
1125 if (This
->numfaces
== 0)
1127 ERR("Number of faces was zero.\n");
1128 hr
= D3DERR_INVALIDCALL
;
1132 new_indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1139 if (This
->options
& D3DXMESH_32BIT
)
1141 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1142 if (FAILED(hr
)) goto cleanup
;
1143 memcpy(new_indices
, indices
, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1147 /* Make a widening copy of indices_16bit into indices and new_indices
1148 * in order to re-use the helper function */
1149 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices_16bit
);
1150 if (FAILED(hr
)) goto cleanup
;
1151 indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1157 for (i
= 0; i
< VERTS_PER_FACE
* This
->numfaces
; i
++)
1159 new_indices
[i
] = indices_16bit
[i
];
1160 indices
[i
] = indices_16bit
[i
];
1164 /* Vertices are ordered sequentially in the point representation. */
1165 for (i
= 0; i
< This
->numvertices
; i
++)
1170 /* Propagate vertices with low indices so as few vertices as possible
1171 * are used in the mesh.
1173 for (face
= 0; face
< This
->numfaces
; face
++)
1175 hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
, face
, This
->numfaces
);
1176 if (FAILED(hr
)) goto cleanup
;
1178 /* Go in opposite direction to catch all face orderings */
1179 for (face
= 0; face
< This
->numfaces
; face
++)
1181 hr
= propagate_face_vertices(adjacency
, point_reps
,
1182 indices
, new_indices
,
1183 (This
->numfaces
- 1) - face
, This
->numfaces
);
1184 if (FAILED(hr
)) goto cleanup
;
1189 if (This
->options
& D3DXMESH_32BIT
)
1191 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1195 if (indices_16bit
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1196 HeapFree(GetProcessHeap(), 0, indices
);
1198 HeapFree(GetProcessHeap(), 0, new_indices
);
1202 struct vertex_metadata
{
1205 DWORD first_shared_index
;
1208 static int compare_vertex_keys(const void *a
, const void *b
)
1210 const struct vertex_metadata
*left
= a
;
1211 const struct vertex_metadata
*right
= b
;
1212 if (left
->key
== right
->key
)
1214 return left
->key
< right
->key
? -1 : 1;
1217 static HRESULT WINAPI
d3dx9_mesh_GenerateAdjacency(ID3DXMesh
*iface
, float epsilon
, DWORD
*adjacency
)
1219 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1221 BYTE
*vertices
= NULL
;
1222 const DWORD
*indices
= NULL
;
1225 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
1226 struct vertex_metadata
*sorted_vertices
;
1227 /* shared_indices links together identical indices in the index buffer so
1228 * that adjacency checks can be limited to faces sharing a vertex */
1229 DWORD
*shared_indices
= NULL
;
1230 const FLOAT epsilon_sq
= epsilon
* epsilon
;
1233 TRACE("iface %p, epsilon %.8e, adjacency %p.\n", iface
, epsilon
, adjacency
);
1236 return D3DERR_INVALIDCALL
;
1238 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
1239 if (!(This
->options
& D3DXMESH_32BIT
))
1240 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
1241 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
1242 if (!shared_indices
)
1243 return E_OUTOFMEMORY
;
1244 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
1246 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
1247 if (FAILED(hr
)) goto cleanup
;
1248 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1249 if (FAILED(hr
)) goto cleanup
;
1251 if (!(This
->options
& D3DXMESH_32BIT
)) {
1252 const WORD
*word_indices
= (const WORD
*)indices
;
1253 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
1254 indices
= dword_indices
;
1255 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1256 *dword_indices
++ = *word_indices
++;
1259 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1260 for (i
= 0; i
< This
->numvertices
; i
++) {
1261 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
1262 sorted_vertices
[i
].first_shared_index
= -1;
1263 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
1264 sorted_vertices
[i
].vertex_index
= i
;
1266 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
1267 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
1268 shared_indices
[i
] = *first_shared_index
;
1269 *first_shared_index
= i
;
1272 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
1274 for (i
= 0; i
< This
->numvertices
; i
++) {
1275 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
1276 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
1277 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
1279 while (shared_index_a
!= -1) {
1281 DWORD shared_index_b
= shared_indices
[shared_index_a
];
1282 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
1285 while (shared_index_b
!= -1) {
1286 /* faces are adjacent if they have another coincident vertex */
1287 DWORD base_a
= (shared_index_a
/ 3) * 3;
1288 DWORD base_b
= (shared_index_b
/ 3) * 3;
1289 BOOL adjacent
= FALSE
;
1292 for (k
= 0; k
< 3; k
++) {
1293 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
1299 for (k
= 1; k
<= 2; k
++) {
1300 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
1301 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
1302 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
1303 if (!adjacent
&& epsilon
>= 0.0f
) {
1304 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
1307 D3DXVec3Subtract(&delta
,
1308 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
1309 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
1310 length_sq
= D3DXVec3LengthSq(&delta
);
1311 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
1314 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
1315 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
1316 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
1317 adjacency
[adj_a
] = base_b
/ 3;
1318 adjacency
[adj_b
] = base_a
/ 3;
1325 shared_index_b
= shared_indices
[shared_index_b
];
1327 while (++j
< This
->numvertices
) {
1328 D3DXVECTOR3
*vertex_b
;
1331 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
1332 /* no more coincident vertices to try */
1333 j
= This
->numvertices
;
1336 /* check for coincidence */
1337 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
1338 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
1339 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
1340 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
1345 if (j
>= This
->numvertices
)
1347 shared_index_b
= sorted_vertex_b
->first_shared_index
;
1350 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
1351 shared_index_a
= sorted_vertex_a
->first_shared_index
;
1357 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1358 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
1359 HeapFree(GetProcessHeap(), 0, shared_indices
);
1363 static HRESULT WINAPI
d3dx9_mesh_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1365 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1367 UINT vertex_declaration_size
;
1370 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
1374 WARN("Invalid declaration. Can't use NULL declaration.\n");
1375 return D3DERR_INVALIDCALL
;
1378 /* New declaration must be same size as original */
1379 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
1380 if (vertex_declaration_size
!= This
->vertex_declaration_size
)
1382 WARN("Invalid declaration. New vertex size does not match the original vertex size.\n");
1383 return D3DERR_INVALIDCALL
;
1386 /* New declaration must not contain non-zero Stream value */
1387 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1389 if (declaration
[i
].Stream
!= 0)
1391 WARN("Invalid declaration. New declaration contains non-zero Stream value.\n");
1392 return D3DERR_INVALIDCALL
;
1396 This
->num_elem
= i
+ 1;
1397 copy_declaration(This
->cached_declaration
, declaration
, This
->num_elem
);
1399 if (This
->vertex_declaration
)
1400 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
1402 /* An application can pass an invalid declaration to UpdateSemantics and
1403 * still expect D3D_OK (see tests). If the declaration is invalid, then
1404 * subsequent calls to DrawSubset will fail. This is handled by setting the
1405 * vertex declaration to NULL.
1406 * GetDeclaration, GetNumBytesPerVertex must, however, use the new
1407 * invalid declaration. This is handled by them using the cached vertex
1408 * declaration instead of the actual vertex declaration.
1410 hr
= IDirect3DDevice9_CreateVertexDeclaration(This
->device
,
1412 &This
->vertex_declaration
);
1415 WARN("Using invalid declaration. Calls to DrawSubset will fail.\n");
1416 This
->vertex_declaration
= NULL
;
1422 static HRESULT WINAPI
d3dx9_mesh_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
1424 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1426 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
1428 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1430 if (!(flags
& D3DLOCK_READONLY
))
1432 D3DXATTRIBUTERANGE
*attrib_table
= mesh
->attrib_table
;
1433 mesh
->attrib_table_size
= 0;
1434 mesh
->attrib_table
= NULL
;
1435 HeapFree(GetProcessHeap(), 0, attrib_table
);
1438 *data
= mesh
->attrib_buffer
;
1443 static HRESULT WINAPI
d3dx9_mesh_UnlockAttributeBuffer(ID3DXMesh
*iface
)
1445 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1448 TRACE("iface %p.\n", iface
);
1450 lock_count
= InterlockedDecrement(&mesh
->attrib_buffer_lock_count
);
1453 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1454 return D3DERR_INVALIDCALL
;
1460 static HRESULT WINAPI
d3dx9_mesh_Optimize(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1461 DWORD
*adjacency_out
, DWORD
*face_remap
, ID3DXBuffer
**vertex_remap
, ID3DXMesh
**opt_mesh
)
1463 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1465 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
1466 ID3DXMesh
*optimized_mesh
;
1468 TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap %p, vertex_remap %p, opt_mesh %p.\n",
1469 iface
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
1472 return D3DERR_INVALIDCALL
;
1474 hr
= iface
->lpVtbl
->GetDeclaration(iface
, declaration
);
1475 if (FAILED(hr
)) return hr
;
1477 if (FAILED(hr
= iface
->lpVtbl
->CloneMesh(iface
, mesh
->options
, declaration
, mesh
->device
, &optimized_mesh
)))
1480 hr
= optimized_mesh
->lpVtbl
->OptimizeInplace(optimized_mesh
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
);
1482 *opt_mesh
= optimized_mesh
;
1484 IUnknown_Release(optimized_mesh
);
1488 /* Creates a vertex_remap that removes unused vertices.
1489 * Indices are updated according to the vertex_remap. */
1490 static HRESULT
compact_mesh(struct d3dx9_mesh
*This
, DWORD
*indices
,
1491 DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
1494 DWORD
*vertex_remap_ptr
;
1495 DWORD num_used_vertices
;
1498 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
1499 if (FAILED(hr
)) return hr
;
1500 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
1502 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1503 vertex_remap_ptr
[indices
[i
]] = 1;
1505 /* create old->new vertex mapping */
1506 num_used_vertices
= 0;
1507 for (i
= 0; i
< This
->numvertices
; i
++) {
1508 if (vertex_remap_ptr
[i
])
1509 vertex_remap_ptr
[i
] = num_used_vertices
++;
1511 vertex_remap_ptr
[i
] = -1;
1513 /* convert indices */
1514 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1515 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
1517 /* create new->old vertex mapping */
1518 num_used_vertices
= 0;
1519 for (i
= 0; i
< This
->numvertices
; i
++) {
1520 if (vertex_remap_ptr
[i
] != -1)
1521 vertex_remap_ptr
[num_used_vertices
++] = i
;
1523 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
1524 vertex_remap_ptr
[i
] = -1;
1526 *new_num_vertices
= num_used_vertices
;
1531 /* count the number of unique attribute values in a sorted attribute buffer */
1532 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
1534 DWORD last_attribute
= attrib_buffer
[0];
1535 DWORD attrib_table_size
= 1;
1537 for (i
= 1; i
< numfaces
; i
++) {
1538 if (attrib_buffer
[i
] != last_attribute
) {
1539 last_attribute
= attrib_buffer
[i
];
1540 attrib_table_size
++;
1543 return attrib_table_size
;
1546 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
1547 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
1549 DWORD attrib_table_size
= 0;
1550 DWORD last_attribute
= attrib_buffer
[0];
1551 DWORD min_vertex
, max_vertex
;
1554 attrib_table
[0].AttribId
= last_attribute
;
1555 attrib_table
[0].FaceStart
= 0;
1556 min_vertex
= (DWORD
)-1;
1558 for (i
= 0; i
< numfaces
; i
++) {
1561 if (attrib_buffer
[i
] != last_attribute
) {
1562 last_attribute
= attrib_buffer
[i
];
1563 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1564 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1565 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1566 attrib_table_size
++;
1567 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
1568 attrib_table
[attrib_table_size
].FaceStart
= i
;
1569 min_vertex
= (DWORD
)-1;
1572 for (j
= 0; j
< 3; j
++) {
1573 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
1574 if (vertex_index
< min_vertex
)
1575 min_vertex
= vertex_index
;
1576 if (vertex_index
> max_vertex
)
1577 max_vertex
= vertex_index
;
1580 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1581 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1582 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1583 attrib_table_size
++;
1586 static int attrib_entry_compare(const DWORD
**a
, const DWORD
**b
)
1588 const DWORD
*ptr_a
= *a
;
1589 const DWORD
*ptr_b
= *b
;
1590 int delta
= *ptr_a
- *ptr_b
;
1595 delta
= ptr_a
- ptr_b
; /* for stable sort */
1599 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
1600 static HRESULT
remap_faces_for_attrsort(struct d3dx9_mesh
*This
, const DWORD
*indices
,
1601 DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
1603 DWORD
**sorted_attrib_ptr_buffer
= NULL
;
1606 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
1607 if (!sorted_attrib_ptr_buffer
)
1608 return E_OUTOFMEMORY
;
1610 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
1613 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
1614 return E_OUTOFMEMORY
;
1617 for (i
= 0; i
< This
->numfaces
; i
++)
1618 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
1619 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
),
1620 (int(*)(const void *, const void *))attrib_entry_compare
);
1622 for (i
= 0; i
< This
->numfaces
; i
++)
1624 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
1625 (*face_remap
)[old_face
] = i
;
1628 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
1629 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
1630 for (i
= 0; i
< This
->numfaces
; i
++)
1631 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
1636 static HRESULT WINAPI
d3dx9_mesh_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1637 DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
1639 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1640 void *indices
= NULL
;
1641 DWORD
*attrib_buffer
= NULL
;
1643 ID3DXBuffer
*vertex_remap
= NULL
;
1644 DWORD
*face_remap
= NULL
; /* old -> new mapping */
1645 DWORD
*dword_indices
= NULL
;
1646 DWORD new_num_vertices
= 0;
1647 DWORD new_num_alloc_vertices
= 0;
1648 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
1649 DWORD
*sorted_attrib_buffer
= NULL
;
1652 TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
1653 iface
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
1656 return D3DERR_INVALIDCALL
;
1657 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
1658 return D3DERR_INVALIDCALL
;
1659 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1660 return D3DERR_INVALIDCALL
;
1662 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1664 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
1665 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
1666 if (flags
& D3DXMESHOPT_STRIPREORDER
)
1667 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
1671 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, &indices
);
1672 if (FAILED(hr
)) goto cleanup
;
1674 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
1675 if (!dword_indices
) return E_OUTOFMEMORY
;
1676 if (This
->options
& D3DXMESH_32BIT
) {
1677 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1679 WORD
*word_indices
= indices
;
1680 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1681 dword_indices
[i
] = *word_indices
++;
1684 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
1686 new_num_alloc_vertices
= This
->numvertices
;
1687 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
1688 if (FAILED(hr
)) goto cleanup
;
1689 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
1690 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
1692 FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
1697 hr
= iface
->lpVtbl
->LockAttributeBuffer(iface
, 0, &attrib_buffer
);
1698 if (FAILED(hr
)) goto cleanup
;
1700 hr
= remap_faces_for_attrsort(This
, dword_indices
, attrib_buffer
, &sorted_attrib_buffer
, &face_remap
);
1701 if (FAILED(hr
)) goto cleanup
;
1706 /* reorder the vertices using vertex_remap */
1707 D3DVERTEXBUFFER_DESC vertex_desc
;
1708 DWORD
*vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1709 DWORD vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1710 BYTE
*orig_vertices
;
1713 hr
= IDirect3DVertexBuffer9_GetDesc(This
->vertex_buffer
, &vertex_desc
);
1714 if (FAILED(hr
)) goto cleanup
;
1716 hr
= IDirect3DDevice9_CreateVertexBuffer(This
->device
, new_num_alloc_vertices
* vertex_size
,
1717 vertex_desc
.Usage
, This
->fvf
, vertex_desc
.Pool
, &vertex_buffer
, NULL
);
1718 if (FAILED(hr
)) goto cleanup
;
1720 hr
= IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, (void**)&orig_vertices
, D3DLOCK_READONLY
);
1721 if (FAILED(hr
)) goto cleanup
;
1723 hr
= IDirect3DVertexBuffer9_Lock(vertex_buffer
, 0, 0, (void**)&new_vertices
, 0);
1725 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1729 for (i
= 0; i
< new_num_vertices
; i
++)
1730 memcpy(new_vertices
+ i
* vertex_size
, orig_vertices
+ vertex_remap_ptr
[i
] * vertex_size
, vertex_size
);
1732 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1733 IDirect3DVertexBuffer9_Unlock(vertex_buffer
);
1734 } else if (vertex_remap_out
) {
1735 DWORD
*vertex_remap_ptr
;
1737 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), &vertex_remap
);
1738 if (FAILED(hr
)) goto cleanup
;
1739 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1740 for (i
= 0; i
< This
->numvertices
; i
++)
1741 *vertex_remap_ptr
++ = i
;
1744 if (flags
& D3DXMESHOPT_ATTRSORT
)
1746 D3DXATTRIBUTERANGE
*attrib_table
;
1747 DWORD attrib_table_size
;
1749 attrib_table_size
= count_attributes(sorted_attrib_buffer
, This
->numfaces
);
1750 attrib_table
= HeapAlloc(GetProcessHeap(), 0, attrib_table_size
* sizeof(*attrib_table
));
1751 if (!attrib_table
) {
1756 memcpy(attrib_buffer
, sorted_attrib_buffer
, This
->numfaces
* sizeof(*attrib_buffer
));
1758 /* reorder the indices using face_remap */
1759 if (This
->options
& D3DXMESH_32BIT
) {
1760 for (i
= 0; i
< This
->numfaces
; i
++)
1761 memcpy((DWORD
*)indices
+ face_remap
[i
] * 3, dword_indices
+ i
* 3, 3 * sizeof(DWORD
));
1763 WORD
*word_indices
= indices
;
1764 for (i
= 0; i
< This
->numfaces
; i
++) {
1765 DWORD new_pos
= face_remap
[i
] * 3;
1766 DWORD old_pos
= i
* 3;
1767 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1768 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1769 word_indices
[new_pos
] = dword_indices
[old_pos
];
1773 fill_attribute_table(attrib_buffer
, This
->numfaces
, indices
,
1774 This
->options
& D3DXMESH_32BIT
, attrib_table
);
1776 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1777 This
->attrib_table
= attrib_table
;
1778 This
->attrib_table_size
= attrib_table_size
;
1780 if (This
->options
& D3DXMESH_32BIT
) {
1781 memcpy(indices
, dword_indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1783 WORD
*word_indices
= indices
;
1784 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1785 *word_indices
++ = dword_indices
[i
];
1789 if (adjacency_out
) {
1791 for (i
= 0; i
< This
->numfaces
; i
++) {
1792 DWORD old_pos
= i
* 3;
1793 DWORD new_pos
= face_remap
[i
] * 3;
1794 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1795 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1796 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1799 memcpy(adjacency_out
, adjacency_in
, This
->numfaces
* 3 * sizeof(*adjacency_out
));
1802 if (face_remap_out
) {
1804 for (i
= 0; i
< This
->numfaces
; i
++)
1805 face_remap_out
[face_remap
[i
]] = i
;
1807 for (i
= 0; i
< This
->numfaces
; i
++)
1808 face_remap_out
[i
] = i
;
1811 if (vertex_remap_out
)
1812 *vertex_remap_out
= vertex_remap
;
1813 vertex_remap
= NULL
;
1815 if (vertex_buffer
) {
1816 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
1817 This
->vertex_buffer
= vertex_buffer
;
1818 vertex_buffer
= NULL
;
1819 This
->numvertices
= new_num_vertices
;
1824 HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer
);
1825 HeapFree(GetProcessHeap(), 0, face_remap
);
1826 HeapFree(GetProcessHeap(), 0, dword_indices
);
1827 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
1828 if (vertex_buffer
) IDirect3DVertexBuffer9_Release(vertex_buffer
);
1829 if (attrib_buffer
) iface
->lpVtbl
->UnlockAttributeBuffer(iface
);
1830 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1834 static HRESULT WINAPI
d3dx9_mesh_SetAttributeTable(ID3DXMesh
*iface
,
1835 const D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
1837 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1838 D3DXATTRIBUTERANGE
*new_table
= NULL
;
1840 TRACE("iface %p, attrib_table %p, attrib_table_size %u.\n", iface
, attrib_table
, attrib_table_size
);
1842 if (attrib_table_size
) {
1843 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
1845 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
1847 return E_OUTOFMEMORY
;
1849 CopyMemory(new_table
, attrib_table
, size
);
1850 } else if (attrib_table
) {
1851 return D3DERR_INVALIDCALL
;
1853 HeapFree(GetProcessHeap(), 0, mesh
->attrib_table
);
1854 mesh
->attrib_table
= new_table
;
1855 mesh
->attrib_table_size
= attrib_table_size
;
1860 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
1862 d3dx9_mesh_QueryInterface
,
1865 d3dx9_mesh_DrawSubset
,
1866 d3dx9_mesh_GetNumFaces
,
1867 d3dx9_mesh_GetNumVertices
,
1869 d3dx9_mesh_GetDeclaration
,
1870 d3dx9_mesh_GetNumBytesPerVertex
,
1871 d3dx9_mesh_GetOptions
,
1872 d3dx9_mesh_GetDevice
,
1873 d3dx9_mesh_CloneMeshFVF
,
1874 d3dx9_mesh_CloneMesh
,
1875 d3dx9_mesh_GetVertexBuffer
,
1876 d3dx9_mesh_GetIndexBuffer
,
1877 d3dx9_mesh_LockVertexBuffer
,
1878 d3dx9_mesh_UnlockVertexBuffer
,
1879 d3dx9_mesh_LockIndexBuffer
,
1880 d3dx9_mesh_UnlockIndexBuffer
,
1881 d3dx9_mesh_GetAttributeTable
,
1882 d3dx9_mesh_ConvertPointRepsToAdjacency
,
1883 d3dx9_mesh_ConvertAdjacencyToPointReps
,
1884 d3dx9_mesh_GenerateAdjacency
,
1885 d3dx9_mesh_UpdateSemantics
,
1886 d3dx9_mesh_LockAttributeBuffer
,
1887 d3dx9_mesh_UnlockAttributeBuffer
,
1888 d3dx9_mesh_Optimize
,
1889 d3dx9_mesh_OptimizeInplace
,
1890 d3dx9_mesh_SetAttributeTable
,
1894 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algorithm
1895 Amy Williams University of Utah
1896 Steve Barrus University of Utah
1897 R. Keith Morley University of Utah
1898 Peter Shirley University of Utah
1900 International Conference on Computer Graphics and Interactive Techniques archive
1901 ACM SIGGRAPH 2005 Courses
1902 Los Angeles, California
1904 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1906 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1907 against each slab, if there's anything left of the ray after we're
1908 done we've got an intersection of the ray with the box. */
1909 BOOL WINAPI
D3DXBoxBoundProbe(const D3DXVECTOR3
*pmin
, const D3DXVECTOR3
*pmax
,
1910 const D3DXVECTOR3
*prayposition
, const D3DXVECTOR3
*praydirection
)
1912 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
1914 div
= 1.0f
/ praydirection
->x
;
1917 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
1918 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
1922 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
1923 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
1926 if ( tmax
< 0.0f
) return FALSE
;
1928 div
= 1.0f
/ praydirection
->y
;
1931 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
1932 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
1936 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
1937 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
1940 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
1942 if ( tymin
> tmin
) tmin
= tymin
;
1943 if ( tymax
< tmax
) tmax
= tymax
;
1945 div
= 1.0f
/ praydirection
->z
;
1948 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
1949 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
1953 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
1954 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
1957 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
1962 HRESULT WINAPI
D3DXComputeBoundingBox(const D3DXVECTOR3
*pfirstposition
,
1963 DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
1968 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
1970 *pmin
= *pfirstposition
;
1973 for(i
=0; i
<numvertices
; i
++)
1975 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
1977 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
1978 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
1980 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
1981 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
1983 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
1984 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
1990 HRESULT WINAPI
D3DXComputeBoundingSphere(const D3DXVECTOR3
*pfirstposition
,
1991 DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, float *pradius
)
1997 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
2004 for(i
=0; i
<numvertices
; i
++)
2005 D3DXVec3Add(&temp
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
2007 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/ numvertices
);
2009 for(i
=0; i
<numvertices
; i
++)
2011 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
2012 if ( d
> *pradius
) *pradius
= d
;
2017 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
2018 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
2020 declaration
[*idx
].Stream
= 0;
2021 declaration
[*idx
].Offset
= *offset
;
2022 declaration
[*idx
].Type
= type
;
2023 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
2024 declaration
[*idx
].Usage
= usage
;
2025 declaration
[*idx
].UsageIndex
= usage_idx
;
2027 *offset
+= d3dx_decltype_size
[type
];
2031 /*************************************************************************
2032 * D3DXDeclaratorFromFVF
2034 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
2036 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
2037 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2038 unsigned int offset
= 0;
2039 unsigned int idx
= 0;
2042 TRACE("fvf %#x, declaration %p.\n", fvf
, declaration
);
2044 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
2046 if (fvf
& D3DFVF_POSITION_MASK
)
2048 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
2049 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
2050 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
2052 if (has_blend_idx
) --blend_count
;
2054 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
2055 || (has_blend
&& blend_count
> 4))
2056 return D3DERR_INVALIDCALL
;
2058 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
2059 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
2061 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
2065 switch (blend_count
)
2070 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2073 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2076 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2079 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2082 ERR("Invalid blend count %u.\n", blend_count
);
2088 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
2089 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
2090 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
2091 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
2096 if (fvf
& D3DFVF_NORMAL
)
2097 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
2098 if (fvf
& D3DFVF_PSIZE
)
2099 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
2100 if (fvf
& D3DFVF_DIFFUSE
)
2101 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
2102 if (fvf
& D3DFVF_SPECULAR
)
2103 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
2105 for (i
= 0; i
< tex_count
; ++i
)
2107 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
2109 case D3DFVF_TEXTUREFORMAT1
:
2110 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
2112 case D3DFVF_TEXTUREFORMAT2
:
2113 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
2115 case D3DFVF_TEXTUREFORMAT3
:
2116 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
2118 case D3DFVF_TEXTUREFORMAT4
:
2119 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
2124 declaration
[idx
] = end_element
;
2129 /*************************************************************************
2130 * D3DXFVFFromDeclarator
2132 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
2134 unsigned int i
= 0, texture
, offset
;
2136 TRACE("(%p, %p)\n", declaration
, fvf
);
2139 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
2141 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2142 declaration
[1].UsageIndex
== 0) &&
2143 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
2144 declaration
[2].UsageIndex
== 0))
2146 return D3DERR_INVALIDCALL
;
2148 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2149 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
2151 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
2153 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
2157 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
2161 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2162 declaration
[1].UsageIndex
== 0)
2164 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2165 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
2167 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
2169 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
2173 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
2175 switch (declaration
[1].Type
)
2177 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
2178 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
2179 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
2180 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
2186 switch (declaration
[1].Type
)
2188 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
2189 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
2190 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
2191 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
2202 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
2203 declaration
[0].UsageIndex
== 0)
2205 *fvf
|= D3DFVF_XYZRHW
;
2209 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
2211 *fvf
|= D3DFVF_NORMAL
;
2214 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
2215 declaration
[i
].UsageIndex
== 0)
2217 *fvf
|= D3DFVF_PSIZE
;
2220 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2221 declaration
[i
].UsageIndex
== 0)
2223 *fvf
|= D3DFVF_DIFFUSE
;
2226 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2227 declaration
[i
].UsageIndex
== 1)
2229 *fvf
|= D3DFVF_SPECULAR
;
2233 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
2235 if (declaration
[i
].Stream
== 0xFF)
2239 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2240 declaration
[i
].UsageIndex
== texture
)
2242 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
2244 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2245 declaration
[i
].UsageIndex
== texture
)
2247 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
2249 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2250 declaration
[i
].UsageIndex
== texture
)
2252 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
2254 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2255 declaration
[i
].UsageIndex
== texture
)
2257 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
2261 return D3DERR_INVALIDCALL
;
2265 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
2267 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
2268 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
2270 if (declaration
[i
].Offset
!= offset
)
2272 return D3DERR_INVALIDCALL
;
2279 /*************************************************************************
2280 * D3DXGetFVFVertexSize
2282 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
2284 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
2287 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
2291 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2293 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
2294 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
2295 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
2296 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
2298 switch (FVF
& D3DFVF_POSITION_MASK
)
2300 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
2301 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
2302 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
2303 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
2304 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
2305 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
2306 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
2307 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
2310 for (i
= 0; i
< numTextures
; i
++)
2312 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
2318 /*************************************************************************
2319 * D3DXGetDeclVertexSize
2321 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
2323 const D3DVERTEXELEMENT9
*element
;
2326 TRACE("decl %p, stream_idx %u\n", decl
, stream_idx
);
2328 if (!decl
) return 0;
2330 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
2334 if (element
->Stream
!= stream_idx
) continue;
2336 if (element
->Type
>= sizeof(d3dx_decltype_size
) / sizeof(*d3dx_decltype_size
))
2338 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
2342 type_size
= d3dx_decltype_size
[element
->Type
];
2343 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
2349 /*************************************************************************
2352 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
2354 const D3DVERTEXELEMENT9
*element
;
2356 TRACE("decl %p\n", decl
);
2358 /* null decl results in exception on Windows XP */
2360 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
2362 return element
- decl
;
2365 BOOL WINAPI
D3DXIntersectTri(const D3DXVECTOR3
*p0
, const D3DXVECTOR3
*p1
, const D3DXVECTOR3
*p2
,
2366 const D3DXVECTOR3
*praypos
, const D3DXVECTOR3
*praydir
, float *pu
, float *pv
, float *pdist
)
2371 TRACE("p0 %p, p1 %p, p2 %p, praypos %p, praydir %p, pu %p, pv %p, pdist %p.\n",
2372 p0
, p1
, p2
, praypos
, praydir
, pu
, pv
, pdist
);
2374 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
2375 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
2376 m
.u
.m
[2][0] = -praydir
->x
;
2378 m
.u
.m
[0][1] = p1
->y
- p0
->y
;
2379 m
.u
.m
[1][1] = p2
->y
- p0
->y
;
2380 m
.u
.m
[2][1] = -praydir
->y
;
2382 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
2383 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
2384 m
.u
.m
[2][2] = -praydir
->z
;
2391 vec
.x
= praypos
->x
- p0
->x
;
2392 vec
.y
= praypos
->y
- p0
->y
;
2393 vec
.z
= praypos
->z
- p0
->z
;
2396 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
2398 D3DXVec4Transform(&vec
, &vec
, &m
);
2399 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
2401 if (pu
) *pu
= vec
.x
;
2402 if (pv
) *pv
= vec
.y
;
2403 if (pdist
) *pdist
= fabsf( vec
.z
);
2411 BOOL WINAPI
D3DXSphereBoundProbe(const D3DXVECTOR3
*pcenter
, float radius
,
2412 const D3DXVECTOR3
*prayposition
, const D3DXVECTOR3
*praydirection
)
2414 D3DXVECTOR3 difference
;
2417 a
= D3DXVec3LengthSq(praydirection
);
2418 if (!D3DXVec3Subtract(&difference
, prayposition
, pcenter
)) return FALSE
;
2419 b
= D3DXVec3Dot(&difference
, praydirection
);
2420 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
2423 if ( ( d
<= 0.0f
) || ( sqrt(d
) <= b
) ) return FALSE
;
2427 /*************************************************************************
2430 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2431 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2435 IDirect3DVertexDeclaration9
*vertex_declaration
;
2436 UINT vertex_declaration_size
;
2438 IDirect3DVertexBuffer9
*vertex_buffer
;
2439 IDirect3DIndexBuffer9
*index_buffer
;
2440 DWORD
*attrib_buffer
;
2441 struct d3dx9_mesh
*object
;
2442 DWORD index_usage
= 0;
2443 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
2444 D3DFORMAT index_format
= D3DFMT_INDEX16
;
2445 DWORD vertex_usage
= 0;
2446 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
2449 TRACE("numfaces %u, numvertices %u, options %#x, declaration %p, device %p, mesh %p.\n",
2450 numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2452 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
2453 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
2454 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
2456 return D3DERR_INVALIDCALL
;
2458 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
2459 if (declaration
[i
].Stream
!= 0)
2460 return D3DERR_INVALIDCALL
;
2463 if (options
& D3DXMESH_32BIT
)
2464 index_format
= D3DFMT_INDEX32
;
2466 if (options
& D3DXMESH_DONOTCLIP
) {
2467 index_usage
|= D3DUSAGE_DONOTCLIP
;
2468 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
2470 if (options
& D3DXMESH_POINTS
) {
2471 index_usage
|= D3DUSAGE_POINTS
;
2472 vertex_usage
|= D3DUSAGE_POINTS
;
2474 if (options
& D3DXMESH_RTPATCHES
) {
2475 index_usage
|= D3DUSAGE_RTPATCHES
;
2476 vertex_usage
|= D3DUSAGE_RTPATCHES
;
2478 if (options
& D3DXMESH_NPATCHES
) {
2479 index_usage
|= D3DUSAGE_NPATCHES
;
2480 vertex_usage
|= D3DUSAGE_NPATCHES
;
2483 if (options
& D3DXMESH_VB_SYSTEMMEM
)
2484 vertex_pool
= D3DPOOL_SYSTEMMEM
;
2485 else if (options
& D3DXMESH_VB_MANAGED
)
2486 vertex_pool
= D3DPOOL_MANAGED
;
2488 if (options
& D3DXMESH_VB_WRITEONLY
)
2489 vertex_usage
|= D3DUSAGE_WRITEONLY
;
2490 if (options
& D3DXMESH_VB_DYNAMIC
)
2491 vertex_usage
|= D3DUSAGE_DYNAMIC
;
2492 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
2493 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2495 if (options
& D3DXMESH_IB_SYSTEMMEM
)
2496 index_pool
= D3DPOOL_SYSTEMMEM
;
2497 else if (options
& D3DXMESH_IB_MANAGED
)
2498 index_pool
= D3DPOOL_MANAGED
;
2500 if (options
& D3DXMESH_IB_WRITEONLY
)
2501 index_usage
|= D3DUSAGE_WRITEONLY
;
2502 if (options
& D3DXMESH_IB_DYNAMIC
)
2503 index_usage
|= D3DUSAGE_DYNAMIC
;
2504 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
2505 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2507 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
2513 /* Create vertex declaration */
2514 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
2516 &vertex_declaration
);
2519 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
2522 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
2524 /* Create vertex buffer */
2525 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
2526 numvertices
* vertex_declaration_size
,
2534 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2535 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2539 /* Create index buffer */
2540 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
2541 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
2549 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2550 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2551 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2555 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
2556 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2557 if (object
== NULL
|| attrib_buffer
== NULL
)
2559 HeapFree(GetProcessHeap(), 0, object
);
2560 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
2561 IDirect3DIndexBuffer9_Release(index_buffer
);
2562 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2563 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2565 return E_OUTOFMEMORY
;
2567 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
2570 object
->numfaces
= numfaces
;
2571 object
->numvertices
= numvertices
;
2572 object
->options
= options
;
2574 object
->device
= device
;
2575 IDirect3DDevice9_AddRef(device
);
2577 copy_declaration(object
->cached_declaration
, declaration
, num_elem
);
2578 object
->vertex_declaration
= vertex_declaration
;
2579 object
->vertex_declaration_size
= vertex_declaration_size
;
2580 object
->num_elem
= num_elem
;
2581 object
->vertex_buffer
= vertex_buffer
;
2582 object
->index_buffer
= index_buffer
;
2583 object
->attrib_buffer
= attrib_buffer
;
2585 *mesh
= &object
->ID3DXMesh_iface
;
2590 /*************************************************************************
2593 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2594 DWORD fvf
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2597 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
2599 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
2601 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
2602 if (FAILED(hr
)) return hr
;
2604 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2610 DWORD num_poly_faces
;
2611 DWORD num_tri_faces
;
2612 D3DXVECTOR3
*vertices
;
2613 DWORD
*num_tri_per_face
;
2618 /* optional mesh data */
2621 D3DXVECTOR3
*normals
;
2622 DWORD
*normal_indices
;
2624 D3DXVECTOR2
*tex_coords
;
2626 DWORD
*vertex_colors
;
2628 DWORD num_materials
;
2629 D3DXMATERIAL
*materials
;
2630 DWORD
*material_indices
;
2632 struct ID3DXSkinInfo
*skin_info
;
2636 static HRESULT
parse_texture_filename(ID3DXFileData
*filedata
, char **filename_out
)
2642 char *filename
= NULL
;
2644 /* template TextureFilename {
2649 HeapFree(GetProcessHeap(), 0, *filename_out
);
2650 *filename_out
= NULL
;
2652 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2653 if (FAILED(hr
)) return hr
;
2655 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
2656 if (data_size
< sizeof(filename_in
))
2658 WARN("truncated data (%lu bytes)\n", data_size
);
2659 filedata
->lpVtbl
->Unlock(filedata
);
2662 filename_in
= *(char **)data
;
2664 filename
= HeapAlloc(GetProcessHeap(), 0, strlen(filename_in
) + 1);
2666 filedata
->lpVtbl
->Unlock(filedata
);
2667 return E_OUTOFMEMORY
;
2670 strcpy(filename
, filename_in
);
2671 *filename_out
= filename
;
2673 filedata
->lpVtbl
->Unlock(filedata
);
2678 static HRESULT
parse_material(ID3DXFileData
*filedata
, D3DXMATERIAL
*material
)
2684 ID3DXFileData
*child
;
2685 SIZE_T i
, nb_children
;
2687 material
->pTextureFilename
= NULL
;
2689 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2690 if (FAILED(hr
)) return hr
;
2693 * template ColorRGBA {
2699 * template ColorRGB {
2704 * template Material {
2705 * ColorRGBA faceColor;
2707 * ColorRGB specularColor;
2708 * ColorRGB emissiveColor;
2712 if (data_size
!= sizeof(FLOAT
) * 11) {
2713 WARN("incorrect data size (%ld bytes)\n", data_size
);
2714 filedata
->lpVtbl
->Unlock(filedata
);
2718 memcpy(&material
->MatD3D
.Diffuse
, data
, sizeof(D3DCOLORVALUE
));
2719 data
+= sizeof(D3DCOLORVALUE
);
2720 material
->MatD3D
.Power
= *(FLOAT
*)data
;
2721 data
+= sizeof(FLOAT
);
2722 memcpy(&material
->MatD3D
.Specular
, data
, sizeof(FLOAT
) * 3);
2723 material
->MatD3D
.Specular
.a
= 1.0f
;
2724 data
+= 3 * sizeof(FLOAT
);
2725 memcpy(&material
->MatD3D
.Emissive
, data
, sizeof(FLOAT
) * 3);
2726 material
->MatD3D
.Emissive
.a
= 1.0f
;
2727 material
->MatD3D
.Ambient
.r
= 0.0f
;
2728 material
->MatD3D
.Ambient
.g
= 0.0f
;
2729 material
->MatD3D
.Ambient
.b
= 0.0f
;
2730 material
->MatD3D
.Ambient
.a
= 1.0f
;
2732 filedata
->lpVtbl
->Unlock(filedata
);
2734 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2738 for (i
= 0; i
< nb_children
; i
++)
2740 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2743 hr
= child
->lpVtbl
->GetType(child
, &type
);
2747 if (IsEqualGUID(&type
, &TID_D3DRMTextureFilename
)) {
2748 hr
= parse_texture_filename(child
, &material
->pTextureFilename
);
2752 IUnknown_Release(child
);
2757 IUnknown_Release(child
);
2761 static void destroy_materials(struct mesh_data
*mesh
)
2764 for (i
= 0; i
< mesh
->num_materials
; i
++)
2765 HeapFree(GetProcessHeap(), 0, mesh
->materials
[i
].pTextureFilename
);
2766 HeapFree(GetProcessHeap(), 0, mesh
->materials
);
2767 HeapFree(GetProcessHeap(), 0, mesh
->material_indices
);
2768 mesh
->num_materials
= 0;
2769 mesh
->materials
= NULL
;
2770 mesh
->material_indices
= NULL
;
2773 static HRESULT
parse_material_list(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2777 const DWORD
*data
, *in_ptr
;
2779 ID3DXFileData
*child
= NULL
;
2780 DWORD num_materials
;
2784 destroy_materials(mesh
);
2786 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2787 if (FAILED(hr
)) return hr
;
2789 /* template MeshMaterialList {
2791 * DWORD nFaceIndexes;
2792 * array DWORD faceIndexes[nFaceIndexes];
2800 if (data_size
< sizeof(DWORD
)) {
2801 WARN("truncated data (%ld bytes)\n", data_size
);
2804 num_materials
= *in_ptr
++;
2805 if (!num_materials
) {
2810 if (data_size
< 2 * sizeof(DWORD
)) {
2811 WARN("truncated data (%ld bytes)\n", data_size
);
2814 if (*in_ptr
++ != mesh
->num_poly_faces
) {
2815 WARN("number of material face indices (%u) doesn't match number of faces (%u)\n",
2816 *(in_ptr
- 1), mesh
->num_poly_faces
);
2819 if (data_size
< 2 * sizeof(DWORD
) + mesh
->num_poly_faces
* sizeof(DWORD
)) {
2820 WARN("truncated data (%ld bytes)\n", data_size
);
2823 for (i
= 0; i
< mesh
->num_poly_faces
; i
++) {
2824 if (*in_ptr
++ >= num_materials
) {
2825 WARN("face %u: reference to undefined material %u (only %u materials)\n",
2826 i
, *(in_ptr
- 1), num_materials
);
2831 mesh
->materials
= HeapAlloc(GetProcessHeap(), 0, num_materials
* sizeof(*mesh
->materials
));
2832 mesh
->material_indices
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_poly_faces
* sizeof(*mesh
->material_indices
));
2833 if (!mesh
->materials
|| !mesh
->material_indices
) {
2837 memcpy(mesh
->material_indices
, data
+ 2, mesh
->num_poly_faces
* sizeof(DWORD
));
2839 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2843 for (i
= 0; i
< nb_children
; i
++)
2845 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2848 hr
= child
->lpVtbl
->GetType(child
, &type
);
2852 if (IsEqualGUID(&type
, &TID_D3DRMMaterial
)) {
2853 if (mesh
->num_materials
>= num_materials
) {
2854 WARN("more materials defined than declared\n");
2858 hr
= parse_material(child
, &mesh
->materials
[mesh
->num_materials
++]);
2863 IUnknown_Release(child
);
2866 if (num_materials
!= mesh
->num_materials
) {
2867 WARN("only %u of %u materials defined\n", num_materials
, mesh
->num_materials
);
2873 IUnknown_Release(child
);
2874 filedata
->lpVtbl
->Unlock(filedata
);
2878 static HRESULT
parse_texture_coords(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2884 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2885 mesh
->tex_coords
= NULL
;
2887 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2888 if (FAILED(hr
)) return hr
;
2890 /* template Coords2d {
2894 * template MeshTextureCoords {
2895 * DWORD nTextureCoords;
2896 * array Coords2d textureCoords[nTextureCoords];
2902 if (data_size
< sizeof(DWORD
)) {
2903 WARN("truncated data (%ld bytes)\n", data_size
);
2906 if (*(DWORD
*)data
!= mesh
->num_vertices
) {
2907 WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2908 *(DWORD
*)data
, mesh
->num_vertices
);
2911 data
+= sizeof(DWORD
);
2912 if (data_size
< sizeof(DWORD
) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
)) {
2913 WARN("truncated data (%ld bytes)\n", data_size
);
2917 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2918 if (!mesh
->tex_coords
) {
2922 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2924 mesh
->fvf
|= D3DFVF_TEX1
;
2929 filedata
->lpVtbl
->Unlock(filedata
);
2933 static HRESULT
parse_vertex_colors(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2941 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2942 mesh
->vertex_colors
= NULL
;
2944 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2945 if (FAILED(hr
)) return hr
;
2947 /* template IndexedColor {
2949 * ColorRGBA indexColor;
2951 * template MeshVertexColors {
2952 * DWORD nVertexColors;
2953 * array IndexedColor vertexColors[nVertexColors];
2959 if (data_size
< sizeof(DWORD
)) {
2960 WARN("truncated data (%ld bytes)\n", data_size
);
2963 num_colors
= *(DWORD
*)data
;
2964 data
+= sizeof(DWORD
);
2965 if (data_size
< sizeof(DWORD
) + num_colors
* (sizeof(DWORD
) + sizeof(D3DCOLORVALUE
))) {
2966 WARN("truncated data (%ld bytes)\n", data_size
);
2970 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(DWORD
));
2971 if (!mesh
->vertex_colors
) {
2976 for (i
= 0; i
< mesh
->num_vertices
; i
++)
2977 mesh
->vertex_colors
[i
] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2978 for (i
= 0; i
< num_colors
; i
++)
2980 D3DCOLORVALUE color
;
2981 DWORD index
= *(DWORD
*)data
;
2982 data
+= sizeof(DWORD
);
2983 if (index
>= mesh
->num_vertices
) {
2984 WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2985 i
, index
, mesh
->num_vertices
);
2988 memcpy(&color
, data
, sizeof(color
));
2989 data
+= sizeof(color
);
2990 color
.r
= min(1.0f
, max(0.0f
, color
.r
));
2991 color
.g
= min(1.0f
, max(0.0f
, color
.g
));
2992 color
.b
= min(1.0f
, max(0.0f
, color
.b
));
2993 color
.a
= min(1.0f
, max(0.0f
, color
.a
));
2994 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
2995 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
2996 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
2997 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
3000 mesh
->fvf
|= D3DFVF_DIFFUSE
;
3005 filedata
->lpVtbl
->Unlock(filedata
);
3009 static HRESULT
parse_normals(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
3014 DWORD
*index_out_ptr
;
3016 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
3018 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
3019 mesh
->num_normals
= 0;
3020 mesh
->normals
= NULL
;
3021 mesh
->normal_indices
= NULL
;
3022 mesh
->fvf
|= D3DFVF_NORMAL
;
3024 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3025 if (FAILED(hr
)) return hr
;
3027 /* template Vector {
3032 * template MeshFace {
3033 * DWORD nFaceVertexIndices;
3034 * array DWORD faceVertexIndices[nFaceVertexIndices];
3036 * template MeshNormals {
3038 * array Vector normals[nNormals];
3039 * DWORD nFaceNormals;
3040 * array MeshFace faceNormals[nFaceNormals];
3046 if (data_size
< sizeof(DWORD
) * 2) {
3047 WARN("truncated data (%ld bytes)\n", data_size
);
3050 mesh
->num_normals
= *(DWORD
*)data
;
3051 data
+= sizeof(DWORD
);
3052 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
3053 num_face_indices
* sizeof(DWORD
)) {
3054 WARN("truncated data (%ld bytes)\n", data_size
);
3058 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3059 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
3060 if (!mesh
->normals
|| !mesh
->normal_indices
) {
3065 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3066 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
3067 for (i
= 0; i
< mesh
->num_normals
; i
++)
3068 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
3070 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
3071 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
3072 *(DWORD
*)data
, mesh
->num_poly_faces
);
3075 data
+= sizeof(DWORD
);
3076 index_out_ptr
= mesh
->normal_indices
;
3077 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
3080 DWORD count
= *(DWORD
*)data
;
3081 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
3082 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
3083 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
3086 data
+= sizeof(DWORD
);
3088 for (j
= 0; j
< count
; j
++) {
3089 DWORD normal_index
= *(DWORD
*)data
;
3090 if (normal_index
>= mesh
->num_normals
) {
3091 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
3092 i
, j
, normal_index
, mesh
->num_normals
);
3095 *index_out_ptr
++ = normal_index
;
3096 data
+= sizeof(DWORD
);
3103 filedata
->lpVtbl
->Unlock(filedata
);
3107 static HRESULT
parse_skin_mesh_info(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD index
)
3113 TRACE("(%p, %p, %u)\n", filedata
, mesh_data
, index
);
3115 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3116 if (FAILED(hr
)) return hr
;
3120 if (!mesh_data
->skin_info
) {
3121 if (data_size
< sizeof(WORD
) * 3) {
3122 WARN("truncated data (%ld bytes)\n", data_size
);
3125 /* Skip nMaxSkinWeightsPerVertex and nMaxSkinWeightsPerFace */
3126 data
+= 2 * sizeof(WORD
);
3127 mesh_data
->nb_bones
= *(WORD
*)data
;
3128 hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
, mesh_data
->nb_bones
, &mesh_data
->skin_info
);
3131 DWORD nb_influences
;
3133 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
3134 name
= *(const char**)data
;
3135 data
+= sizeof(char*);
3137 nb_influences
= *(DWORD
*)data
;
3138 data
+= sizeof(DWORD
);
3140 if (data_size
< (sizeof(char*) + sizeof(DWORD
) + nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
)) + 16 * sizeof(FLOAT
))) {
3141 WARN("truncated data (%ld bytes)\n", data_size
);
3145 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneName(mesh_data
->skin_info
, index
, name
);
3147 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneInfluence(mesh_data
->skin_info
, index
, nb_influences
,
3148 (const DWORD
*)data
, (const FLOAT
*)(data
+ nb_influences
* sizeof(DWORD
)));
3150 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneOffsetMatrix(mesh_data
->skin_info
, index
,
3151 (const D3DMATRIX
*)(data
+ nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
))));
3155 filedata
->lpVtbl
->Unlock(filedata
);
3159 /* for provide_flags parameters */
3160 #define PROVIDE_MATERIALS 0x1
3161 #define PROVIDE_SKININFO 0x2
3162 #define PROVIDE_ADJACENCY 0x4
3164 static HRESULT
parse_mesh(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
3168 const BYTE
*data
, *in_ptr
;
3169 DWORD
*index_out_ptr
;
3171 ID3DXFileData
*child
= NULL
;
3174 DWORD nb_skin_weights_info
= 0;
3179 * array Vector vertices[nVertices];
3181 * array MeshFace faces[nFaces];
3186 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3187 if (FAILED(hr
)) return hr
;
3192 if (data_size
< sizeof(DWORD
) * 2) {
3193 WARN("truncated data (%ld bytes)\n", data_size
);
3196 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
3197 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
)) {
3198 WARN("truncated data (%ld bytes)\n", data_size
);
3201 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
3203 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
3204 in_ptr
+= sizeof(DWORD
);
3206 mesh_data
->num_tri_faces
= 0;
3207 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3209 DWORD num_poly_vertices
;
3212 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
)) {
3213 WARN("truncated data (%ld bytes)\n", data_size
);
3216 num_poly_vertices
= *(DWORD
*)in_ptr
;
3217 in_ptr
+= sizeof(DWORD
);
3218 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
)) {
3219 WARN("truncated data (%ld bytes)\n", data_size
);
3222 if (num_poly_vertices
< 3) {
3223 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
3226 for (j
= 0; j
< num_poly_vertices
; j
++) {
3227 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
3228 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
3229 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
3232 in_ptr
+= sizeof(DWORD
);
3234 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
3237 mesh_data
->fvf
= D3DFVF_XYZ
;
3239 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
3240 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
3241 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
3242 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
3243 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
3244 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
3245 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
) {
3250 in_ptr
= data
+ sizeof(DWORD
);
3251 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
3252 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
3254 index_out_ptr
= mesh_data
->indices
;
3255 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3259 count
= *(DWORD
*)in_ptr
;
3260 in_ptr
+= sizeof(DWORD
);
3261 mesh_data
->num_tri_per_face
[i
] = count
- 2;
3264 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
3265 in_ptr
+= sizeof(DWORD
);
3269 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3273 for (i
= 0; i
< nb_children
; i
++)
3275 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3278 hr
= child
->lpVtbl
->GetType(child
, &type
);
3282 if (IsEqualGUID(&type
, &TID_D3DRMMeshNormals
)) {
3283 hr
= parse_normals(child
, mesh_data
);
3284 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshVertexColors
)) {
3285 hr
= parse_vertex_colors(child
, mesh_data
);
3286 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshTextureCoords
)) {
3287 hr
= parse_texture_coords(child
, mesh_data
);
3288 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshMaterialList
) &&
3289 (provide_flags
& PROVIDE_MATERIALS
))
3291 hr
= parse_material_list(child
, mesh_data
);
3292 } else if (provide_flags
& PROVIDE_SKININFO
) {
3293 if (IsEqualGUID(&type
, &DXFILEOBJ_XSkinMeshHeader
)) {
3294 if (mesh_data
->skin_info
) {
3295 WARN("Skin mesh header already encountered\n");
3299 hr
= parse_skin_mesh_info(child
, mesh_data
, 0);
3302 } else if (IsEqualGUID(&type
, &DXFILEOBJ_SkinWeights
)) {
3303 if (!mesh_data
->skin_info
) {
3304 WARN("Skin weights found but skin mesh header not encountered yet\n");
3308 hr
= parse_skin_mesh_info(child
, mesh_data
, nb_skin_weights_info
);
3311 nb_skin_weights_info
++;
3317 IUnknown_Release(child
);
3321 if (mesh_data
->skin_info
&& (nb_skin_weights_info
!= mesh_data
->nb_bones
)) {
3322 WARN("Mismatch between nb skin weights info %u encountered and nb bones %u from skin mesh header\n",
3323 nb_skin_weights_info
, mesh_data
->nb_bones
);
3332 IUnknown_Release(child
);
3333 filedata
->lpVtbl
->Unlock(filedata
);
3337 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
3338 ID3DXBuffer
**effects
)
3341 D3DXEFFECTINSTANCE
*effect_ptr
;
3343 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3344 static const struct {
3345 const char *param_name
;
3349 } material_effects
[] = {
3350 #define EFFECT_TABLE_ENTRY(str, field) \
3351 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
3352 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
3353 EFFECT_TABLE_ENTRY("Power", Power
),
3354 EFFECT_TABLE_ENTRY("Specular", Specular
),
3355 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
3356 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
3357 #undef EFFECT_TABLE_ENTRY
3359 static const char texture_paramname
[] = "Texture0@Name";
3363 /* effects buffer layout:
3365 * D3DXEFFECTINSTANCE effects[num_materials];
3366 * for (effect in effects)
3368 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
3369 * for (default in defaults)
3371 * *default.pParamName;
3376 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
3377 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
3378 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
3379 buffer_size
+= material_effects
[i
].name_size
;
3380 buffer_size
+= material_effects
[i
].num_bytes
;
3382 buffer_size
*= num_materials
;
3383 for (i
= 0; i
< num_materials
; i
++) {
3384 if (material_ptr
[i
].pTextureFilename
) {
3385 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
3386 buffer_size
+= sizeof(texture_paramname
);
3387 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
3391 hr
= D3DXCreateBuffer(buffer_size
, effects
);
3392 if (FAILED(hr
)) return hr
;
3393 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
3394 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
3396 for (i
= 0; i
< num_materials
; i
++)
3399 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
3401 effect_ptr
->pDefaults
= defaults
;
3402 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
3403 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
3405 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
3407 defaults
->pParamName
= (char *)out_ptr
;
3408 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
3409 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
3410 defaults
->Type
= D3DXEDT_FLOATS
;
3411 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
3412 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
3413 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3417 if (material_ptr
->pTextureFilename
)
3419 defaults
->pParamName
= (char *)out_ptr
;
3420 strcpy(defaults
->pParamName
, texture_paramname
);
3421 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
3422 defaults
->Type
= D3DXEDT_STRING
;
3423 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
3424 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
3425 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3430 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
3435 HRESULT WINAPI
D3DXLoadSkinMeshFromXof(struct ID3DXFileData
*filedata
, DWORD options
,
3436 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
3437 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXSkinInfo
**skin_info_out
,
3438 struct ID3DXMesh
**mesh_out
)
3441 DWORD
*index_in_ptr
;
3442 struct mesh_data mesh_data
;
3443 DWORD total_vertices
;
3444 ID3DXMesh
*d3dxmesh
= NULL
;
3445 ID3DXBuffer
*adjacency
= NULL
;
3446 ID3DXBuffer
*materials
= NULL
;
3447 ID3DXBuffer
*effects
= NULL
;
3448 struct vertex_duplication
{
3451 } *duplications
= NULL
;
3453 void *vertices
= NULL
;
3454 void *indices
= NULL
;
3456 DWORD provide_flags
= 0;
3458 TRACE("(%p, %x, %p, %p, %p, %p, %p, %p, %p)\n", filedata
, options
, device
, adjacency_out
, materials_out
,
3459 effects_out
, num_materials_out
, skin_info_out
, mesh_out
);
3461 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
3463 if (num_materials_out
|| materials_out
|| effects_out
)
3464 provide_flags
|= PROVIDE_MATERIALS
;
3466 provide_flags
|= PROVIDE_SKININFO
;
3468 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
3469 if (FAILED(hr
)) goto cleanup
;
3471 total_vertices
= mesh_data
.num_vertices
;
3472 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3473 /* duplicate vertices with multiple normals */
3474 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
3475 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
3476 if (!duplications
) {
3480 for (i
= 0; i
< total_vertices
; i
++)
3482 duplications
[i
].normal_index
= -1;
3483 list_init(&duplications
[i
].entry
);
3485 for (i
= 0; i
< num_face_indices
; i
++) {
3486 DWORD vertex_index
= mesh_data
.indices
[i
];
3487 DWORD normal_index
= mesh_data
.normal_indices
[i
];
3488 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
3490 if (dup_ptr
->normal_index
== -1) {
3491 dup_ptr
->normal_index
= normal_index
;
3493 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
3494 struct list
*dup_list
= &dup_ptr
->entry
;
3496 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
3497 if (new_normal
->x
== cur_normal
->x
&&
3498 new_normal
->y
== cur_normal
->y
&&
3499 new_normal
->z
== cur_normal
->z
)
3501 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3503 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
3504 dup_ptr
= &duplications
[total_vertices
++];
3505 dup_ptr
->normal_index
= normal_index
;
3506 list_add_tail(dup_list
, &dup_ptr
->entry
);
3507 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3510 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
3511 struct vertex_duplication
, entry
);
3518 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
3519 if (FAILED(hr
)) goto cleanup
;
3521 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, 0, &vertices
);
3522 if (FAILED(hr
)) goto cleanup
;
3525 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3526 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
3527 out_ptr
+= sizeof(D3DXVECTOR3
);
3528 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3529 if (duplications
[i
].normal_index
== -1)
3530 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
3532 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
3533 out_ptr
+= sizeof(D3DXVECTOR3
);
3535 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
3536 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
3537 out_ptr
+= sizeof(DWORD
);
3539 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
3540 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
3541 out_ptr
+= sizeof(D3DXVECTOR2
);
3544 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3545 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
3547 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3548 struct vertex_duplication
*dup_ptr
;
3549 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
3551 int j
= dup_ptr
- duplications
;
3552 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
3554 memcpy(dest_vertex
, out_ptr
, vertex_size
);
3555 dest_vertex
+= sizeof(D3DXVECTOR3
);
3556 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
3558 out_ptr
+= vertex_size
;
3561 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
3563 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, 0, &indices
);
3564 if (FAILED(hr
)) goto cleanup
;
3566 index_in_ptr
= mesh_data
.indices
;
3567 #define FILL_INDEX_BUFFER(indices_var) \
3568 for (i = 0; i < mesh_data.num_poly_faces; i++) \
3570 DWORD count = mesh_data.num_tri_per_face[i]; \
3571 WORD first_index = *index_in_ptr++; \
3573 *indices_var++ = first_index; \
3574 *indices_var++ = *index_in_ptr; \
3576 *indices_var++ = *index_in_ptr; \
3580 if (options
& D3DXMESH_32BIT
) {
3581 DWORD
*dword_indices
= indices
;
3582 FILL_INDEX_BUFFER(dword_indices
)
3584 WORD
*word_indices
= indices
;
3585 FILL_INDEX_BUFFER(word_indices
)
3587 #undef FILL_INDEX_BUFFER
3588 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
3590 if (mesh_data
.material_indices
) {
3591 DWORD
*attrib_buffer
= NULL
;
3592 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, 0, &attrib_buffer
);
3593 if (FAILED(hr
)) goto cleanup
;
3594 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
3596 DWORD count
= mesh_data
.num_tri_per_face
[i
];
3598 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
3600 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
3602 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
3603 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
3604 NULL
, NULL
, NULL
, NULL
);
3605 if (FAILED(hr
)) goto cleanup
;
3608 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
3609 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
3610 char *strings_out_ptr
;
3611 D3DXMATERIAL
*materials_ptr
;
3613 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3614 if (mesh_data
.materials
[i
].pTextureFilename
)
3615 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3618 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3619 if (FAILED(hr
)) goto cleanup
;
3621 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3622 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
3623 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
3624 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3625 if (materials_ptr
[i
].pTextureFilename
) {
3626 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
3627 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
3628 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3633 if (mesh_data
.num_materials
&& effects_out
) {
3634 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
3635 if (FAILED(hr
)) goto cleanup
;
3637 if (!materials_out
) {
3638 ID3DXBuffer_Release(materials
);
3643 if (adjacency_out
) {
3644 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
3645 if (FAILED(hr
)) goto cleanup
;
3646 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
3647 if (FAILED(hr
)) goto cleanup
;
3650 *mesh_out
= d3dxmesh
;
3651 if (adjacency_out
) *adjacency_out
= adjacency
;
3652 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
3653 if (materials_out
) *materials_out
= materials
;
3654 if (effects_out
) *effects_out
= effects
;
3655 if (skin_info_out
) *skin_info_out
= mesh_data
.skin_info
;
3660 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
3661 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3662 if (materials
) ID3DXBuffer_Release(materials
);
3663 if (effects
) ID3DXBuffer_Release(effects
);
3664 if (mesh_data
.skin_info
) mesh_data
.skin_info
->lpVtbl
->Release(mesh_data
.skin_info
);
3665 if (skin_info_out
) *skin_info_out
= NULL
;
3667 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
3668 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
3669 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
3670 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
3671 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
3672 destroy_materials(&mesh_data
);
3673 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
3674 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
3675 HeapFree(GetProcessHeap(), 0, duplications
);
3679 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3680 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3681 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3687 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3688 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3689 debugstr_a(filename
), options
, device
, alloc_hier
,
3690 load_user_data
, frame_hierarchy
, anim_controller
);
3693 return D3DERR_INVALIDCALL
;
3695 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3696 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3697 if (!filenameW
) return E_OUTOFMEMORY
;
3698 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3700 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
3701 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3702 HeapFree(GetProcessHeap(), 0, filenameW
);
3707 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3708 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3709 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3715 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3716 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3717 debugstr_w(filename
), options
, device
, alloc_hier
,
3718 load_user_data
, frame_hierarchy
, anim_controller
);
3721 return D3DERR_INVALIDCALL
;
3723 hr
= map_view_of_file(filename
, &buffer
, &size
);
3725 return D3DXERR_INVALIDDATA
;
3727 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
3728 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3730 UnmapViewOfFile(buffer
);
3735 static HRESULT
filedata_get_name(ID3DXFileData
*filedata
, char **name
)
3740 hr
= filedata
->lpVtbl
->GetName(filedata
, NULL
, &name_len
);
3741 if (FAILED(hr
)) return hr
;
3745 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
3746 if (!*name
) return E_OUTOFMEMORY
;
3748 hr
= filedata
->lpVtbl
->GetName(filedata
, *name
, &name_len
);
3750 HeapFree(GetProcessHeap(), 0, *name
);
3757 static HRESULT
load_mesh_container(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3758 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXMESHCONTAINER
**mesh_container
)
3761 ID3DXBuffer
*adjacency
= NULL
;
3762 ID3DXBuffer
*materials
= NULL
;
3763 ID3DXBuffer
*effects
= NULL
;
3764 ID3DXSkinInfo
*skin_info
= NULL
;
3765 D3DXMESHDATA mesh_data
;
3766 DWORD num_materials
= 0;
3769 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
3770 mesh_data
.u
.pMesh
= NULL
;
3772 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
3773 &adjacency
, &materials
, &effects
, &num_materials
,
3774 &skin_info
, &mesh_data
.u
.pMesh
);
3775 if (FAILED(hr
)) return hr
;
3777 hr
= filedata_get_name(filedata
, &name
);
3778 if (FAILED(hr
)) goto cleanup
;
3780 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
3781 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
3782 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
3784 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
3785 skin_info
, mesh_container
);
3788 if (materials
) ID3DXBuffer_Release(materials
);
3789 if (effects
) ID3DXBuffer_Release(effects
);
3790 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3791 if (skin_info
) IUnknown_Release(skin_info
);
3792 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
3793 HeapFree(GetProcessHeap(), 0, name
);
3797 static HRESULT
parse_transform_matrix(ID3DXFileData
*filedata
, D3DXMATRIX
*transform
)
3803 /* template Matrix4x4 {
3804 * array FLOAT matrix[16];
3806 * template FrameTransformMatrix {
3807 * Matrix4x4 frameMatrix;
3811 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3812 if (FAILED(hr
)) return hr
;
3814 if (data_size
!= sizeof(D3DXMATRIX
)) {
3815 WARN("incorrect data size (%ld bytes)\n", data_size
);
3816 filedata
->lpVtbl
->Unlock(filedata
);
3820 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
3822 filedata
->lpVtbl
->Unlock(filedata
);
3826 static HRESULT
load_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3827 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXFRAME
**frame_out
)
3831 ID3DXFileData
*child
;
3833 D3DXFRAME
*frame
= NULL
;
3834 D3DXMESHCONTAINER
**next_container
;
3835 D3DXFRAME
**next_child
;
3836 SIZE_T i
, nb_children
;
3838 hr
= filedata_get_name(filedata
, &name
);
3839 if (FAILED(hr
)) return hr
;
3841 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
3842 HeapFree(GetProcessHeap(), 0, name
);
3843 if (FAILED(hr
)) return E_FAIL
;
3846 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
3847 next_child
= &frame
->pFrameFirstChild
;
3848 next_container
= &frame
->pMeshContainer
;
3850 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3854 for (i
= 0; i
< nb_children
; i
++)
3856 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3859 hr
= child
->lpVtbl
->GetType(child
, &type
);
3863 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
3864 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
3866 next_container
= &(*next_container
)->pNextMeshContainer
;
3867 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
3868 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
3869 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
3870 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
3872 next_child
= &(*next_child
)->pFrameSibling
;
3877 IUnknown_Release(child
);
3882 IUnknown_Release(child
);
3886 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
3887 struct IDirect3DDevice9
*device
, struct ID3DXAllocateHierarchy
*alloc_hier
,
3888 struct ID3DXLoadUserData
*load_user_data
, D3DXFRAME
**frame_hierarchy
,
3889 struct ID3DXAnimationController
**anim_controller
)
3892 ID3DXFile
*d3dxfile
= NULL
;
3893 ID3DXFileEnumObject
*enumobj
= NULL
;
3894 ID3DXFileData
*filedata
= NULL
;
3895 D3DXF_FILELOADMEMORY source
;
3896 D3DXFRAME
*first_frame
= NULL
;
3897 D3DXFRAME
**next_frame
= &first_frame
;
3898 SIZE_T i
, nb_children
;
3901 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3902 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3904 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
3905 return D3DERR_INVALIDCALL
;
3908 FIXME("Loading user data not implemented.\n");
3912 hr
= D3DXFileCreate(&d3dxfile
);
3913 if (FAILED(hr
)) goto cleanup
;
3915 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3916 if (FAILED(hr
)) goto cleanup
;
3918 source
.lpMemory
= (void*)memory
;
3919 source
.dSize
= memory_size
;
3920 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
3921 if (FAILED(hr
)) goto cleanup
;
3923 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
3927 for (i
= 0; i
< nb_children
; i
++)
3929 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
3933 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
3934 if (SUCCEEDED(hr
)) {
3935 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
3936 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
3942 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
3944 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
3945 if (FAILED(hr
)) goto cleanup
;
3946 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
3947 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
3948 if (FAILED(hr
)) goto cleanup
;
3951 next_frame
= &(*next_frame
)->pFrameSibling
;
3954 filedata
->lpVtbl
->Release(filedata
);
3962 } else if (first_frame
->pFrameSibling
) {
3963 D3DXFRAME
*root_frame
= NULL
;
3964 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
3969 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
3970 root_frame
->pFrameFirstChild
= first_frame
;
3971 *frame_hierarchy
= root_frame
;
3974 *frame_hierarchy
= first_frame
;
3978 if (anim_controller
)
3980 *anim_controller
= NULL
;
3981 FIXME("Animation controller creation not implemented.\n");
3985 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
3986 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
3987 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
3988 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
3992 HRESULT WINAPI
D3DXCleanMesh(D3DXCLEANTYPE clean_type
, ID3DXMesh
*mesh_in
, const DWORD
*adjacency_in
,
3993 ID3DXMesh
**mesh_out
, DWORD
*adjacency_out
, ID3DXBuffer
**errors_and_warnings
)
3995 FIXME("(%u, %p, %p, %p, %p, %p)\n", clean_type
, mesh_in
, adjacency_in
, mesh_out
, adjacency_out
, errors_and_warnings
);
4000 HRESULT WINAPI
D3DXFrameDestroy(D3DXFRAME
*frame
, ID3DXAllocateHierarchy
*alloc_hier
)
4005 TRACE("(%p, %p)\n", frame
, alloc_hier
);
4007 if (!frame
|| !alloc_hier
)
4008 return D3DERR_INVALIDCALL
;
4011 D3DXMESHCONTAINER
*container
;
4012 D3DXFRAME
*current_frame
;
4014 if (frame
->pFrameSibling
) {
4015 current_frame
= frame
->pFrameSibling
;
4016 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
4017 current_frame
->pFrameSibling
= NULL
;
4019 current_frame
= frame
;
4023 if (current_frame
->pFrameFirstChild
) {
4024 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
4025 if (FAILED(hr
)) return hr
;
4026 current_frame
->pFrameFirstChild
= NULL
;
4029 container
= current_frame
->pMeshContainer
;
4031 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
4032 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
4033 if (FAILED(hr
)) return hr
;
4034 container
= next_container
;
4036 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
4037 if (FAILED(hr
)) return hr
;
4042 HRESULT WINAPI
D3DXLoadMeshFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4043 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4044 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4050 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4051 "effect_instances %p, num_materials %p, mesh %p.\n",
4052 debugstr_a(filename
), options
, device
, adjacency
, materials
,
4053 effect_instances
, num_materials
, mesh
);
4056 return D3DERR_INVALIDCALL
;
4058 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
4059 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4060 if (!filenameW
) return E_OUTOFMEMORY
;
4061 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
4063 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
4064 effect_instances
, num_materials
, mesh
);
4065 HeapFree(GetProcessHeap(), 0, filenameW
);
4070 HRESULT WINAPI
D3DXLoadMeshFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4071 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4072 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4078 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4079 "effect_instances %p, num_materials %p, mesh %p.\n",
4080 debugstr_w(filename
), options
, device
, adjacency
, materials
,
4081 effect_instances
, num_materials
, mesh
);
4084 return D3DERR_INVALIDCALL
;
4086 hr
= map_view_of_file(filename
, &buffer
, &size
);
4088 return D3DXERR_INVALIDDATA
;
4090 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4091 materials
, effect_instances
, num_materials
, mesh
);
4093 UnmapViewOfFile(buffer
);
4098 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
, const char *name
, const char *type
, DWORD options
,
4099 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
,
4100 struct ID3DXBuffer
**effect_instances
, DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4107 TRACE("module %p, name %s, type %s, options %#x, device %p, adjacency %p, "
4108 "materials %p, effect_instances %p, num_materials %p, mesh %p.\n",
4109 module
, debugstr_a(name
), debugstr_a(type
), options
, device
, adjacency
,
4110 materials
, effect_instances
, num_materials
, mesh
);
4112 resinfo
= FindResourceA(module
, name
, type
);
4113 if (!resinfo
) return D3DXERR_INVALIDDATA
;
4115 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
4116 if (FAILED(hr
)) return D3DXERR_INVALIDDATA
;
4118 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4119 materials
, effect_instances
, num_materials
, mesh
);
4122 struct mesh_container
4126 ID3DXBuffer
*adjacency
;
4127 ID3DXBuffer
*materials
;
4128 ID3DXBuffer
*effects
;
4129 DWORD num_materials
;
4130 D3DXMATRIX transform
;
4133 static HRESULT
parse_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
4134 const D3DXMATRIX
*parent_transform
, struct list
*container_list
, DWORD provide_flags
)
4137 D3DXMATRIX transform
= *parent_transform
;
4138 ID3DXFileData
*child
;
4140 SIZE_T i
, nb_children
;
4142 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
4146 for (i
= 0; i
< nb_children
; i
++)
4148 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
4151 hr
= child
->lpVtbl
->GetType(child
, &type
);
4155 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
4156 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
4162 list_add_tail(container_list
, &container
->entry
);
4163 container
->transform
= transform
;
4165 hr
= D3DXLoadSkinMeshFromXof(child
, options
, device
,
4166 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
4167 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
4168 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
4169 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
4170 D3DXMATRIX new_transform
;
4171 hr
= parse_transform_matrix(child
, &new_transform
);
4172 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
4173 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
4174 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
4179 IUnknown_Release(child
);
4184 IUnknown_Release(child
);
4188 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
4189 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
4190 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXMesh
**mesh_out
)
4193 ID3DXFile
*d3dxfile
= NULL
;
4194 ID3DXFileEnumObject
*enumobj
= NULL
;
4195 ID3DXFileData
*filedata
= NULL
;
4196 D3DXF_FILELOADMEMORY source
;
4197 ID3DXBuffer
*materials
= NULL
;
4198 ID3DXBuffer
*effects
= NULL
;
4199 ID3DXBuffer
*adjacency
= NULL
;
4200 struct list container_list
= LIST_INIT(container_list
);
4201 struct mesh_container
*container_ptr
, *next_container_ptr
;
4202 DWORD num_materials
;
4203 DWORD num_faces
, num_vertices
;
4204 D3DXMATRIX identity
;
4205 DWORD provide_flags
= 0;
4207 ID3DXMesh
*concat_mesh
= NULL
;
4208 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
4209 BYTE
*concat_vertices
= NULL
;
4210 void *concat_indices
= NULL
;
4212 DWORD concat_vertex_size
;
4213 SIZE_T i
, nb_children
;
4216 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
4217 device
, adjacency_out
, materials_out
, effects_out
, num_materials_out
, mesh_out
);
4219 if (!memory
|| !memory_size
|| !device
|| !mesh_out
)
4220 return D3DERR_INVALIDCALL
;
4222 hr
= D3DXFileCreate(&d3dxfile
);
4223 if (FAILED(hr
)) goto cleanup
;
4225 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
4226 if (FAILED(hr
)) goto cleanup
;
4228 source
.lpMemory
= (void*)memory
;
4229 source
.dSize
= memory_size
;
4230 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
4231 if (FAILED(hr
)) goto cleanup
;
4233 D3DXMatrixIdentity(&identity
);
4234 if (adjacency_out
) provide_flags
|= PROVIDE_ADJACENCY
;
4235 if (materials_out
|| effects_out
) provide_flags
|= PROVIDE_MATERIALS
;
4237 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
4241 for (i
= 0; i
< nb_children
; i
++)
4243 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
4247 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
4248 if (SUCCEEDED(hr
)) {
4249 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
4250 container_ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container_ptr
));
4251 if (!container_ptr
) {
4255 list_add_tail(&container_list
, &container_ptr
->entry
);
4256 D3DXMatrixIdentity(&container_ptr
->transform
);
4258 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
4259 (provide_flags
& PROVIDE_ADJACENCY
) ? &container_ptr
->adjacency
: NULL
,
4260 (provide_flags
& PROVIDE_MATERIALS
) ? &container_ptr
->materials
: NULL
,
4261 NULL
, &container_ptr
->num_materials
, NULL
, &container_ptr
->mesh
);
4262 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
4263 hr
= parse_frame(filedata
, options
, device
, &identity
, &container_list
, provide_flags
);
4265 if (FAILED(hr
)) goto cleanup
;
4267 filedata
->lpVtbl
->Release(filedata
);
4273 enumobj
->lpVtbl
->Release(enumobj
);
4275 d3dxfile
->lpVtbl
->Release(d3dxfile
);
4278 if (list_empty(&container_list
)) {
4287 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4289 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4290 fvf
|= mesh
->lpVtbl
->GetFVF(mesh
);
4291 num_faces
+= mesh
->lpVtbl
->GetNumFaces(mesh
);
4292 num_vertices
+= mesh
->lpVtbl
->GetNumVertices(mesh
);
4293 num_materials
+= container_ptr
->num_materials
;
4296 hr
= D3DXCreateMeshFVF(num_faces
, num_vertices
, options
, fvf
, device
, &concat_mesh
);
4297 if (FAILED(hr
)) goto cleanup
;
4299 hr
= concat_mesh
->lpVtbl
->GetDeclaration(concat_mesh
, concat_decl
);
4300 if (FAILED(hr
)) goto cleanup
;
4302 concat_vertex_size
= D3DXGetDeclVertexSize(concat_decl
, 0);
4304 hr
= concat_mesh
->lpVtbl
->LockVertexBuffer(concat_mesh
, 0, (void**)&concat_vertices
);
4305 if (FAILED(hr
)) goto cleanup
;
4307 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4309 D3DVERTEXELEMENT9 mesh_decl
[MAX_FVF_DECL_SIZE
];
4310 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4311 DWORD num_mesh_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
4312 DWORD mesh_vertex_size
;
4313 const BYTE
*mesh_vertices
;
4316 hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, mesh_decl
);
4317 if (FAILED(hr
)) goto cleanup
;
4319 mesh_vertex_size
= D3DXGetDeclVertexSize(mesh_decl
, 0);
4321 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_vertices
);
4322 if (FAILED(hr
)) goto cleanup
;
4324 for (i
= 0; i
< num_mesh_vertices
; i
++) {
4328 D3DXVec3TransformCoord((D3DXVECTOR3
*)concat_vertices
,
4329 (D3DXVECTOR3
*)mesh_vertices
,
4330 &container_ptr
->transform
);
4331 for (j
= 1; concat_decl
[j
].Stream
!= 0xff; j
++)
4333 if (concat_decl
[j
].Usage
== mesh_decl
[k
].Usage
&&
4334 concat_decl
[j
].UsageIndex
== mesh_decl
[k
].UsageIndex
)
4336 if (concat_decl
[j
].Usage
== D3DDECLUSAGE_NORMAL
) {
4337 D3DXVec3TransformCoord((D3DXVECTOR3
*)(concat_vertices
+ concat_decl
[j
].Offset
),
4338 (D3DXVECTOR3
*)(mesh_vertices
+ mesh_decl
[k
].Offset
),
4339 &container_ptr
->transform
);
4341 memcpy(concat_vertices
+ concat_decl
[j
].Offset
,
4342 mesh_vertices
+ mesh_decl
[k
].Offset
,
4343 d3dx_decltype_size
[mesh_decl
[k
].Type
]);
4348 mesh_vertices
+= mesh_vertex_size
;
4349 concat_vertices
+= concat_vertex_size
;
4352 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
4355 concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4356 concat_vertices
= NULL
;
4358 hr
= concat_mesh
->lpVtbl
->LockIndexBuffer(concat_mesh
, 0, &concat_indices
);
4359 if (FAILED(hr
)) goto cleanup
;
4362 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4364 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4365 const void *mesh_indices
;
4366 DWORD num_mesh_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4369 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_indices
);
4370 if (FAILED(hr
)) goto cleanup
;
4372 if (options
& D3DXMESH_32BIT
) {
4373 DWORD
*dest
= concat_indices
;
4374 const DWORD
*src
= mesh_indices
;
4375 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4376 *dest
++ = index_offset
+ *src
++;
4377 concat_indices
= dest
;
4379 WORD
*dest
= concat_indices
;
4380 const WORD
*src
= mesh_indices
;
4381 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4382 *dest
++ = index_offset
+ *src
++;
4383 concat_indices
= dest
;
4385 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
4387 index_offset
+= num_mesh_faces
* 3;
4390 concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4391 concat_indices
= NULL
;
4393 if (num_materials
) {
4394 DWORD
*concat_attrib_buffer
= NULL
;
4397 hr
= concat_mesh
->lpVtbl
->LockAttributeBuffer(concat_mesh
, 0, &concat_attrib_buffer
);
4398 if (FAILED(hr
)) goto cleanup
;
4400 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4402 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4403 const DWORD
*mesh_attrib_buffer
= NULL
;
4404 DWORD count
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4406 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, D3DLOCK_READONLY
, (DWORD
**)&mesh_attrib_buffer
);
4408 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4413 *concat_attrib_buffer
++ = offset
+ *mesh_attrib_buffer
++;
4415 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
4416 offset
+= container_ptr
->num_materials
;
4418 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4421 if (materials_out
|| effects_out
) {
4422 D3DXMATERIAL
*out_ptr
;
4423 if (!num_materials
) {
4424 /* create default material */
4425 hr
= D3DXCreateBuffer(sizeof(D3DXMATERIAL
), &materials
);
4426 if (FAILED(hr
)) goto cleanup
;
4428 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4429 out_ptr
->MatD3D
.Diffuse
.r
= 0.5f
;
4430 out_ptr
->MatD3D
.Diffuse
.g
= 0.5f
;
4431 out_ptr
->MatD3D
.Diffuse
.b
= 0.5f
;
4432 out_ptr
->MatD3D
.Specular
.r
= 0.5f
;
4433 out_ptr
->MatD3D
.Specular
.g
= 0.5f
;
4434 out_ptr
->MatD3D
.Specular
.b
= 0.5f
;
4435 /* D3DXCreateBuffer initializes the rest to zero */
4437 DWORD buffer_size
= num_materials
* sizeof(D3DXMATERIAL
);
4438 char *strings_out_ptr
;
4440 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4442 if (container_ptr
->materials
) {
4444 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4445 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4447 if (in_ptr
->pTextureFilename
)
4448 buffer_size
+= strlen(in_ptr
->pTextureFilename
) + 1;
4454 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
4455 if (FAILED(hr
)) goto cleanup
;
4456 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4457 strings_out_ptr
= (char*)(out_ptr
+ num_materials
);
4459 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4461 if (container_ptr
->materials
) {
4463 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4464 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4466 out_ptr
->MatD3D
= in_ptr
->MatD3D
;
4467 if (in_ptr
->pTextureFilename
) {
4468 out_ptr
->pTextureFilename
= strings_out_ptr
;
4469 strcpy(out_ptr
->pTextureFilename
, in_ptr
->pTextureFilename
);
4470 strings_out_ptr
+= strlen(in_ptr
->pTextureFilename
) + 1;
4483 generate_effects(materials
, num_materials
, &effects
);
4484 if (!materials_out
) {
4485 ID3DXBuffer_Release(materials
);
4490 if (adjacency_out
) {
4491 if (!list_next(&container_list
, list_head(&container_list
))) {
4492 container_ptr
= LIST_ENTRY(list_head(&container_list
), struct mesh_container
, entry
);
4493 adjacency
= container_ptr
->adjacency
;
4494 container_ptr
->adjacency
= NULL
;
4499 hr
= D3DXCreateBuffer(num_faces
* 3 * sizeof(DWORD
), &adjacency
);
4500 if (FAILED(hr
)) goto cleanup
;
4502 out_ptr
= ID3DXBuffer_GetBufferPointer(adjacency
);
4503 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4506 DWORD count
= 3 * container_ptr
->mesh
->lpVtbl
->GetNumFaces(container_ptr
->mesh
);
4507 DWORD
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->adjacency
);
4509 for (i
= 0; i
< count
; i
++)
4510 *out_ptr
++ = offset
+ *in_ptr
++;
4517 *mesh_out
= concat_mesh
;
4518 if (adjacency_out
) *adjacency_out
= adjacency
;
4519 if (materials_out
) *materials_out
= materials
;
4520 if (effects_out
) *effects_out
= effects
;
4521 if (num_materials_out
) *num_materials_out
= num_materials
;
4525 if (concat_indices
) concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4526 if (concat_vertices
) concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4527 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
4528 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
4529 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4531 if (concat_mesh
) IUnknown_Release(concat_mesh
);
4532 if (materials
) ID3DXBuffer_Release(materials
);
4533 if (effects
) ID3DXBuffer_Release(effects
);
4534 if (adjacency
) ID3DXBuffer_Release(adjacency
);
4536 LIST_FOR_EACH_ENTRY_SAFE(container_ptr
, next_container_ptr
, &container_list
, struct mesh_container
, entry
)
4538 if (container_ptr
->mesh
) IUnknown_Release(container_ptr
->mesh
);
4539 if (container_ptr
->adjacency
) ID3DXBuffer_Release(container_ptr
->adjacency
);
4540 if (container_ptr
->materials
) ID3DXBuffer_Release(container_ptr
->materials
);
4541 if (container_ptr
->effects
) ID3DXBuffer_Release(container_ptr
->effects
);
4542 HeapFree(GetProcessHeap(), 0, container_ptr
);
4549 D3DXVECTOR3 position
;
4553 HRESULT WINAPI
D3DXCreatePolygon(struct IDirect3DDevice9
*device
, float length
, UINT sides
,
4554 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4558 struct vertex
*vertices
;
4560 DWORD (*adjacency_buf
)[3];
4564 TRACE("device %p, length %f, sides %u, mesh %p, adjacency %p.\n",
4565 device
, length
, sides
, mesh
, adjacency
);
4567 if (!device
|| length
< 0.0f
|| sides
< 3 || !mesh
)
4568 return D3DERR_INVALIDCALL
;
4570 if (FAILED(hr
= D3DXCreateMeshFVF(sides
, sides
+ 1, D3DXMESH_MANAGED
,
4571 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &polygon
)))
4576 if (FAILED(hr
= polygon
->lpVtbl
->LockVertexBuffer(polygon
, 0, (void **)&vertices
)))
4578 polygon
->lpVtbl
->Release(polygon
);
4582 if (FAILED(hr
= polygon
->lpVtbl
->LockIndexBuffer(polygon
, 0, (void **)&faces
)))
4584 polygon
->lpVtbl
->UnlockVertexBuffer(polygon
);
4585 polygon
->lpVtbl
->Release(polygon
);
4589 scale
= 0.5f
* length
/ sinf(D3DX_PI
/ sides
);
4591 vertices
[0].position
.x
= 0.0f
;
4592 vertices
[0].position
.y
= 0.0f
;
4593 vertices
[0].position
.z
= 0.0f
;
4594 vertices
[0].normal
.x
= 0.0f
;
4595 vertices
[0].normal
.y
= 0.0f
;
4596 vertices
[0].normal
.z
= 1.0f
;
4598 for (i
= 0; i
< sides
; ++i
)
4600 vertices
[i
+ 1].position
.x
= cosf(2.0f
* D3DX_PI
* i
/ sides
) * scale
;
4601 vertices
[i
+ 1].position
.y
= sinf(2.0f
* D3DX_PI
* i
/ sides
) * scale
;
4602 vertices
[i
+ 1].position
.z
= 0.0f
;
4603 vertices
[i
+ 1].normal
.x
= 0.0f
;
4604 vertices
[i
+ 1].normal
.y
= 0.0f
;
4605 vertices
[i
+ 1].normal
.z
= 1.0f
;
4608 faces
[i
][1] = i
+ 1;
4609 faces
[i
][2] = i
+ 2;
4612 faces
[sides
- 1][2] = 1;
4614 polygon
->lpVtbl
->UnlockVertexBuffer(polygon
);
4615 polygon
->lpVtbl
->UnlockIndexBuffer(polygon
);
4619 if (FAILED(hr
= D3DXCreateBuffer(sides
* sizeof(DWORD
) * 3, adjacency
)))
4621 polygon
->lpVtbl
->Release(polygon
);
4625 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4626 for (i
= 0; i
< sides
; ++i
)
4628 adjacency_buf
[i
][0] = i
- 1;
4629 adjacency_buf
[i
][1] = ~0U;
4630 adjacency_buf
[i
][2] = i
+ 1;
4632 adjacency_buf
[0][0] = sides
- 1;
4633 adjacency_buf
[sides
- 1][2] = 0;
4641 HRESULT WINAPI
D3DXCreateBox(struct IDirect3DDevice9
*device
, float width
, float height
,
4642 float depth
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4646 struct vertex
*vertices
;
4648 DWORD
*adjacency_buf
;
4649 unsigned int i
, face
;
4650 static const D3DXVECTOR3 unit_box
[] =
4652 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, -0.5f
},
4653 {-0.5f
, 0.5f
, -0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, -0.5f
},
4654 { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, -0.5f
},
4655 {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, 0.5f
},
4656 {-0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
},
4657 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}
4659 static const D3DXVECTOR3 normals
[] =
4661 {-1.0f
, 0.0f
, 0.0f
}, { 0.0f
, 1.0f
, 0.0f
}, { 1.0f
, 0.0f
, 0.0f
},
4662 { 0.0f
, -1.0f
, 0.0f
}, { 0.0f
, 0.0f
, 1.0f
}, { 0.0f
, 0.0f
, -1.0f
}
4664 static const DWORD adjacency_table
[] =
4666 6, 9, 1, 2, 10, 0, 1, 9, 3, 4, 10, 2,
4667 3, 8, 5, 7, 11, 4, 0, 11, 7, 5, 8, 6,
4668 7, 4, 9, 2, 0, 8, 1, 3, 11, 5, 6, 10
4671 TRACE("device %p, width %f, height %f, depth %f, mesh %p, adjacency %p\n",
4672 device
, width
, height
, depth
, mesh
, adjacency
);
4674 if (!device
|| width
< 0.0f
|| height
< 0.0f
|| depth
< 0.0f
|| !mesh
)
4676 return D3DERR_INVALIDCALL
;
4679 if (FAILED(hr
= D3DXCreateMeshFVF(12, 24, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &box
)))
4684 if (FAILED(hr
= box
->lpVtbl
->LockVertexBuffer(box
, 0, (void **)&vertices
)))
4686 box
->lpVtbl
->Release(box
);
4690 if (FAILED(hr
= box
->lpVtbl
->LockIndexBuffer(box
, 0, (void **)&faces
)))
4692 box
->lpVtbl
->UnlockVertexBuffer(box
);
4693 box
->lpVtbl
->Release(box
);
4697 for (i
= 0; i
< 24; i
++)
4699 vertices
[i
].position
.x
= width
* unit_box
[i
].x
;
4700 vertices
[i
].position
.y
= height
* unit_box
[i
].y
;
4701 vertices
[i
].position
.z
= depth
* unit_box
[i
].z
;
4702 vertices
[i
].normal
.x
= normals
[i
/ 4].x
;
4703 vertices
[i
].normal
.y
= normals
[i
/ 4].y
;
4704 vertices
[i
].normal
.z
= normals
[i
/ 4].z
;
4708 for (i
= 0; i
< 12; i
++)
4710 faces
[i
][0] = face
++;
4711 faces
[i
][1] = face
++;
4712 faces
[i
][2] = (i
% 2) ? face
- 4 : face
;
4715 box
->lpVtbl
->UnlockIndexBuffer(box
);
4716 box
->lpVtbl
->UnlockVertexBuffer(box
);
4720 if (FAILED(hr
= D3DXCreateBuffer(sizeof(adjacency_table
), adjacency
)))
4722 box
->lpVtbl
->Release(box
);
4726 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4727 memcpy(adjacency_buf
, adjacency_table
, sizeof(adjacency_table
));
4735 typedef WORD face
[3];
4743 static void free_sincos_table(struct sincos_table
*sincos_table
)
4745 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
4746 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4749 /* pre compute sine and cosine tables; caller must free */
4750 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
4755 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
4756 if (!sincos_table
->sin
)
4760 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
4761 if (!sincos_table
->cos
)
4763 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4767 angle
= angle_start
;
4768 for (i
= 0; i
< n
; i
++)
4770 sincos_table
->sin
[i
] = sinf(angle
);
4771 sincos_table
->cos
[i
] = cosf(angle
);
4772 angle
+= angle_step
;
4778 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
4780 return stack
*slices
+slice
+1;
4783 HRESULT WINAPI
D3DXCreateSphere(struct IDirect3DDevice9
*device
, float radius
, UINT slices
,
4784 UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4786 DWORD number_of_vertices
, number_of_faces
;
4789 struct vertex
*vertices
;
4791 float phi_step
, phi_start
;
4792 struct sincos_table phi
;
4793 float theta_step
, theta
, sin_theta
, cos_theta
;
4794 DWORD vertex
, face
, stack
, slice
;
4796 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
4798 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
4800 return D3DERR_INVALIDCALL
;
4803 number_of_vertices
= 2 + slices
* (stacks
-1);
4804 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
4806 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4807 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
4813 if (FAILED(hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, 0, (void **)&vertices
)))
4815 sphere
->lpVtbl
->Release(sphere
);
4819 if (FAILED(hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, 0, (void **)&faces
)))
4821 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4822 sphere
->lpVtbl
->Release(sphere
);
4826 /* phi = angle on xz plane wrt z axis */
4827 phi_step
= -2.0f
* D3DX_PI
/ slices
;
4828 phi_start
= D3DX_PI
/ 2.0f
;
4830 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
4832 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4833 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4834 sphere
->lpVtbl
->Release(sphere
);
4835 return E_OUTOFMEMORY
;
4838 /* theta = angle on xy plane wrt x axis */
4839 theta_step
= D3DX_PI
/ stacks
;
4845 vertices
[vertex
].normal
.x
= 0.0f
;
4846 vertices
[vertex
].normal
.y
= 0.0f
;
4847 vertices
[vertex
].normal
.z
= 1.0f
;
4848 vertices
[vertex
].position
.x
= 0.0f
;
4849 vertices
[vertex
].position
.y
= 0.0f
;
4850 vertices
[vertex
].position
.z
= radius
;
4853 for (stack
= 0; stack
< stacks
- 1; stack
++)
4855 sin_theta
= sinf(theta
);
4856 cos_theta
= cosf(theta
);
4858 for (slice
= 0; slice
< slices
; slice
++)
4860 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
4861 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
4862 vertices
[vertex
].normal
.z
= cos_theta
;
4863 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
4864 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
4865 vertices
[vertex
].position
.z
= radius
* cos_theta
;
4872 /* top stack is triangle fan */
4874 faces
[face
][1] = slice
+ 1;
4875 faces
[face
][2] = slice
;
4880 /* stacks in between top and bottom are quad strips */
4881 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4882 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4883 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4886 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4887 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
4888 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4894 theta
+= theta_step
;
4900 faces
[face
][2] = slice
;
4905 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4906 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4907 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4910 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4911 faces
[face
][1] = vertex_index(slices
, 0, stack
);
4912 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4917 vertices
[vertex
].position
.x
= 0.0f
;
4918 vertices
[vertex
].position
.y
= 0.0f
;
4919 vertices
[vertex
].position
.z
= -radius
;
4920 vertices
[vertex
].normal
.x
= 0.0f
;
4921 vertices
[vertex
].normal
.y
= 0.0f
;
4922 vertices
[vertex
].normal
.z
= -1.0f
;
4924 /* bottom stack is triangle fan */
4925 for (slice
= 1; slice
< slices
; slice
++)
4927 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4928 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4929 faces
[face
][2] = vertex
;
4933 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4934 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4935 faces
[face
][2] = vertex
;
4937 free_sincos_table(&phi
);
4938 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4939 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4944 if (FAILED(hr
= D3DXCreateBuffer(number_of_faces
* sizeof(DWORD
) * 3, adjacency
)))
4946 sphere
->lpVtbl
->Release(sphere
);
4950 if (FAILED(hr
= sphere
->lpVtbl
->GenerateAdjacency(sphere
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
4952 (*adjacency
)->lpVtbl
->Release(*adjacency
);
4953 sphere
->lpVtbl
->Release(sphere
);
4963 HRESULT WINAPI
D3DXCreateCylinder(struct IDirect3DDevice9
*device
, float radius1
, float radius2
,
4964 float length
, UINT slices
, UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4966 DWORD number_of_vertices
, number_of_faces
;
4968 ID3DXMesh
*cylinder
;
4969 struct vertex
*vertices
;
4971 float theta_step
, theta_start
;
4972 struct sincos_table theta
;
4973 float delta_radius
, radius
, radius_step
;
4974 float z
, z_step
, z_normal
;
4975 DWORD vertex
, face
, slice
, stack
;
4977 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
4979 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
4981 return D3DERR_INVALIDCALL
;
4984 number_of_vertices
= 2 + (slices
* (3 + stacks
));
4985 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
4987 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4988 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
4994 if (FAILED(hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, 0, (void **)&vertices
)))
4996 cylinder
->lpVtbl
->Release(cylinder
);
5000 if (FAILED(hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, 0, (void **)&faces
)))
5002 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5003 cylinder
->lpVtbl
->Release(cylinder
);
5007 /* theta = angle on xy plane wrt x axis */
5008 theta_step
= -2.0f
* D3DX_PI
/ slices
;
5009 theta_start
= D3DX_PI
/ 2.0f
;
5011 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
5013 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5014 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5015 cylinder
->lpVtbl
->Release(cylinder
);
5016 return E_OUTOFMEMORY
;
5022 delta_radius
= radius1
- radius2
;
5024 radius_step
= delta_radius
/ stacks
;
5027 z_step
= length
/ stacks
;
5028 z_normal
= delta_radius
/ length
;
5029 if (isnan(z_normal
))
5034 vertices
[vertex
].normal
.x
= 0.0f
;
5035 vertices
[vertex
].normal
.y
= 0.0f
;
5036 vertices
[vertex
].normal
.z
= -1.0f
;
5037 vertices
[vertex
].position
.x
= 0.0f
;
5038 vertices
[vertex
].position
.y
= 0.0f
;
5039 vertices
[vertex
++].position
.z
= z
;
5041 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5043 vertices
[vertex
].normal
.x
= 0.0f
;
5044 vertices
[vertex
].normal
.y
= 0.0f
;
5045 vertices
[vertex
].normal
.z
= -1.0f
;
5046 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5047 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5048 vertices
[vertex
].position
.z
= z
;
5053 faces
[face
][1] = slice
;
5054 faces
[face
++][2] = slice
+ 1;
5059 faces
[face
][1] = slice
;
5060 faces
[face
++][2] = 1;
5062 for (stack
= 1; stack
<= stacks
+1; stack
++)
5064 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5066 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
5067 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
5068 vertices
[vertex
].normal
.z
= z_normal
;
5069 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
5070 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5071 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5072 vertices
[vertex
].position
.z
= z
;
5074 if (stack
> 1 && slice
> 0)
5076 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
5077 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5078 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
5080 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
5081 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5082 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5088 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
5089 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5090 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
5092 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
5093 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5094 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
5097 if (stack
< stacks
+ 1)
5100 radius
-= radius_step
;
5104 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5106 vertices
[vertex
].normal
.x
= 0.0f
;
5107 vertices
[vertex
].normal
.y
= 0.0f
;
5108 vertices
[vertex
].normal
.z
= 1.0f
;
5109 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5110 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5111 vertices
[vertex
].position
.z
= z
;
5115 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5116 faces
[face
][1] = number_of_vertices
- 1;
5117 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5121 vertices
[vertex
].position
.x
= 0.0f
;
5122 vertices
[vertex
].position
.y
= 0.0f
;
5123 vertices
[vertex
].position
.z
= z
;
5124 vertices
[vertex
].normal
.x
= 0.0f
;
5125 vertices
[vertex
].normal
.y
= 0.0f
;
5126 vertices
[vertex
].normal
.z
= 1.0f
;
5128 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5129 faces
[face
][1] = number_of_vertices
- 1;
5130 faces
[face
][2] = vertex_index(slices
, 0, stack
);
5132 free_sincos_table(&theta
);
5133 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5134 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5138 if (FAILED(hr
= D3DXCreateBuffer(number_of_faces
* sizeof(DWORD
) * 3, adjacency
)))
5140 cylinder
->lpVtbl
->Release(cylinder
);
5144 if (FAILED(hr
= cylinder
->lpVtbl
->GenerateAdjacency(cylinder
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
5146 (*adjacency
)->lpVtbl
->Release(*adjacency
);
5147 cylinder
->lpVtbl
->Release(cylinder
);
5157 HRESULT WINAPI
D3DXCreateTeapot(struct IDirect3DDevice9
*device
,
5158 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
5160 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
5165 HRESULT WINAPI
D3DXCreateTextA(struct IDirect3DDevice9
*device
, HDC hdc
, const char *text
, float deviation
,
5166 float extrusion
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5172 TRACE("device %p, hdc %p, text %s, deviation %.8e, extrusion %.8e, mesh %p, adjacency %p, glyphmetrics %p.\n",
5173 device
, hdc
, debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
5176 return D3DERR_INVALIDCALL
;
5178 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
5179 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5180 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
5182 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
5183 mesh
, adjacency
, glyphmetrics
);
5184 HeapFree(GetProcessHeap(), 0, textW
);
5189 HRESULT WINAPI
D3DXCreateTorus(struct IDirect3DDevice9
*device
,
5190 float innerradius
, float outerradius
, UINT sides
, UINT rings
, struct ID3DXMesh
**mesh
, ID3DXBuffer
**adjacency
)
5195 struct vertex
*vertices
;
5196 float phi
, phi_step
, sin_phi
, cos_phi
;
5197 float theta
, theta_step
, sin_theta
, cos_theta
;
5198 unsigned int i
, j
, numvert
, numfaces
;
5200 TRACE("device %p, innerradius %.8e, outerradius %.8e, sides %u, rings %u, mesh %p, adjacency %p.\n",
5201 device
, innerradius
, outerradius
, sides
, rings
, mesh
, adjacency
);
5203 numvert
= sides
* rings
;
5204 numfaces
= numvert
* 2;
5206 if (!device
|| innerradius
< 0.0f
|| outerradius
< 0.0f
|| sides
< 3 || rings
< 3 || !mesh
)
5208 WARN("Invalid arguments.\n");
5209 return D3DERR_INVALIDCALL
;
5212 if (FAILED(hr
= D3DXCreateMeshFVF(numfaces
, numvert
, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &torus
)))
5215 if (FAILED(hr
= torus
->lpVtbl
->LockVertexBuffer(torus
, 0, (void **)&vertices
)))
5217 torus
->lpVtbl
->Release(torus
);
5221 if (FAILED(hr
= torus
->lpVtbl
->LockIndexBuffer(torus
, 0, (void **)&faces
)))
5223 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5224 torus
->lpVtbl
->Release(torus
);
5228 phi_step
= D3DX_PI
/ sides
* 2.0f
;
5229 theta_step
= D3DX_PI
/ rings
* -2.0f
;
5233 for (i
= 0; i
< rings
; ++i
)
5237 sin_theta
= sinf(theta
);
5238 cos_theta
= cosf(theta
);
5240 for (j
= 0; j
< sides
; ++j
)
5242 sin_phi
= sinf(phi
);
5243 cos_phi
= cosf(phi
);
5245 vertices
[i
* sides
+ j
].position
.x
= (innerradius
* cos_phi
+ outerradius
) * cos_theta
;
5246 vertices
[i
* sides
+ j
].position
.y
= (innerradius
* cos_phi
+ outerradius
) * sin_theta
;
5247 vertices
[i
* sides
+ j
].position
.z
= innerradius
* sin_phi
;
5248 vertices
[i
* sides
+ j
].normal
.x
= cos_phi
* cos_theta
;
5249 vertices
[i
* sides
+ j
].normal
.y
= cos_phi
* sin_theta
;
5250 vertices
[i
* sides
+ j
].normal
.z
= sin_phi
;
5255 theta
+= theta_step
;
5258 for (i
= 0; i
< numfaces
- sides
* 2; ++i
)
5260 faces
[i
][0] = i
% 2 ? i
/ 2 + sides
: i
/ 2;
5261 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5262 faces
[i
][2] = (i
+ 1) % (sides
* 2) ? (i
+ 1) / 2 + sides
: (i
+ 1) / 2;
5265 for (j
= 0; i
< numfaces
; ++i
, ++j
)
5267 faces
[i
][0] = i
% 2 ? j
/ 2 : i
/ 2;
5268 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5269 faces
[i
][2] = i
== numfaces
- 1 ? 0 : (j
+ 1) / 2;
5272 torus
->lpVtbl
->UnlockIndexBuffer(torus
);
5273 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5277 if (FAILED(hr
= D3DXCreateBuffer(numfaces
* sizeof(DWORD
) * 3, adjacency
)))
5279 torus
->lpVtbl
->Release(torus
);
5283 if (FAILED(hr
= torus
->lpVtbl
->GenerateAdjacency(torus
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
5285 (*adjacency
)->lpVtbl
->Release(*adjacency
);
5286 torus
->lpVtbl
->Release(torus
);
5297 POINTTYPE_CURVE
= 0,
5299 POINTTYPE_CURVE_START
,
5300 POINTTYPE_CURVE_END
,
5301 POINTTYPE_CURVE_MIDDLE
,
5307 enum pointtype corner
;
5310 struct dynamic_array
5312 int count
, capacity
;
5316 /* is a dynamic_array */
5319 int count
, capacity
;
5320 struct point2d
*items
;
5323 /* is a dynamic_array */
5324 struct outline_array
5326 int count
, capacity
;
5327 struct outline
*items
;
5336 struct point2d_index
5338 struct outline
*outline
;
5342 struct point2d_index_array
5345 struct point2d_index
*items
;
5350 struct outline_array outlines
;
5351 struct face_array faces
;
5352 struct point2d_index_array ordered_vertices
;
5356 /* is an dynamic_array */
5359 int count
, capacity
;
5363 /* complex polygons are split into monotone polygons, which have
5364 * at most 2 intersections with the vertical sweep line */
5365 struct triangulation
5367 struct word_array vertex_stack
;
5368 BOOL last_on_top
, merging
;
5371 /* is an dynamic_array */
5372 struct triangulation_array
5374 int count
, capacity
;
5375 struct triangulation
*items
;
5377 struct glyphinfo
*glyph
;
5380 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
5382 if (count
> array
->capacity
) {
5385 if (array
->items
&& array
->capacity
) {
5386 new_capacity
= max(array
->capacity
* 2, count
);
5387 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
5389 new_capacity
= max(16, count
);
5390 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
5394 array
->items
= new_buffer
;
5395 array
->capacity
= new_capacity
;
5400 static struct point2d
*add_points(struct outline
*array
, int num
)
5402 struct point2d
*item
;
5404 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
5407 item
= &array
->items
[array
->count
];
5408 array
->count
+= num
;
5412 static struct outline
*add_outline(struct outline_array
*array
)
5414 struct outline
*item
;
5416 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5419 item
= &array
->items
[array
->count
++];
5420 ZeroMemory(item
, sizeof(*item
));
5424 static inline face
*add_face(struct face_array
*array
)
5426 return &array
->items
[array
->count
++];
5429 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
5431 struct triangulation
*item
;
5433 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5436 item
= &array
->items
[array
->count
++];
5437 ZeroMemory(item
, sizeof(*item
));
5441 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
5443 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5444 return E_OUTOFMEMORY
;
5446 array
->items
[array
->count
++] = vertex_index
;
5450 /* assume fixed point numbers can be converted to float point in place */
5451 C_ASSERT(sizeof(FIXED
) == sizeof(float));
5452 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
5454 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, unsigned int emsquare
)
5456 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
5458 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
5459 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
5460 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
5466 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
5467 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
5468 float max_deviation_sq
)
5470 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
5473 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
5474 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
5475 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
5477 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
5478 if (deviation_sq
< max_deviation_sq
) {
5479 struct point2d
*pt
= add_points(outline
, 1);
5480 if (!pt
) return E_OUTOFMEMORY
;
5482 pt
->corner
= POINTTYPE_CURVE
;
5483 /* the end point is omitted because the end line merges into the next segment of
5484 * the split bezier curve, and the end of the split bezier curve is added outside
5485 * this recursive function. */
5487 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
5488 if (hr
!= S_OK
) return hr
;
5489 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
5490 if (hr
!= S_OK
) return hr
;
5496 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
5498 /* dot product = cos(theta) */
5499 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
5502 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
5504 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
5514 static BOOL
attempt_line_merge(struct outline
*outline
,
5516 const D3DXVECTOR2
*nextpt
,
5518 const struct cos_table
*table
)
5520 D3DXVECTOR2 curdir
, lastdir
;
5521 struct point2d
*prevpt
, *pt
;
5524 pt
= &outline
->items
[pt_index
];
5525 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5526 prevpt
= &outline
->items
[pt_index
];
5529 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
5531 if (outline
->count
< 2)
5534 /* remove last point if the next line continues the last line */
5535 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5536 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5537 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
5540 if (pt
->corner
== POINTTYPE_CURVE_END
)
5541 prevpt
->corner
= pt
->corner
;
5542 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
5543 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5547 if (outline
->count
< 2)
5550 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5551 prevpt
= &outline
->items
[pt_index
];
5552 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5553 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5558 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
5559 float max_deviation_sq
, unsigned int emsquare
,
5560 const struct cos_table
*cos_table
)
5562 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
5564 while ((char *)header
< (char *)raw_outline
+ datasize
)
5566 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
5567 struct point2d
*lastpt
, *pt
;
5568 D3DXVECTOR2 lastdir
;
5569 D3DXVECTOR2
*pt_flt
;
5571 struct outline
*outline
= add_outline(&glyph
->outlines
);
5574 return E_OUTOFMEMORY
;
5576 pt
= add_points(outline
, 1);
5578 return E_OUTOFMEMORY
;
5579 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
5581 pt
->corner
= POINTTYPE_CORNER
;
5583 if (header
->dwType
!= TT_POLYGON_TYPE
)
5584 FIXME("Unknown header type %d\n", header
->dwType
);
5586 while ((char *)curve
< (char *)header
+ header
->cb
)
5588 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
5589 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
5590 unsigned int j2
= 0;
5593 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5597 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
5599 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
5604 int count
= curve
->cpfx
;
5608 D3DXVECTOR2 bezier_end
;
5610 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j2
], &pt_flt
[j2
+1]), 0.5f
);
5611 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &bezier_end
, max_deviation_sq
);
5614 bezier_start
= bezier_end
;
5618 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &pt_flt
[j2
+1], max_deviation_sq
);
5622 pt
= add_points(outline
, 1);
5624 return E_OUTOFMEMORY
;
5626 pt
->pos
= pt_flt
[j2
];
5627 pt
->corner
= POINTTYPE_CURVE_END
;
5629 pt
= add_points(outline
, curve
->cpfx
);
5631 return E_OUTOFMEMORY
;
5632 for (j2
= 0; j2
< curve
->cpfx
; j2
++)
5634 pt
->pos
= pt_flt
[j2
];
5635 pt
->corner
= POINTTYPE_CORNER
;
5640 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5643 /* remove last point if the next line continues the last line */
5644 if (outline
->count
>= 3) {
5647 lastpt
= &outline
->items
[outline
->count
- 1];
5648 pt
= &outline
->items
[0];
5649 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
5650 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
5652 if (pt
->corner
== POINTTYPE_CURVE_START
)
5653 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5655 pt
->corner
= POINTTYPE_CURVE_END
;
5659 /* outline closed with a line from end to start point */
5660 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
5662 lastpt
= &outline
->items
[0];
5663 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
5664 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
5665 lastpt
->corner
= POINTTYPE_CORNER
;
5666 pt
= &outline
->items
[1];
5667 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
5668 *lastpt
= outline
->items
[outline
->count
];
5671 lastpt
= &outline
->items
[outline
->count
- 1];
5672 pt
= &outline
->items
[0];
5673 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
5674 for (j
= 0; j
< outline
->count
; j
++)
5679 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
5680 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
5682 switch (lastpt
->corner
)
5684 case POINTTYPE_CURVE_START
:
5685 case POINTTYPE_CURVE_END
:
5686 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
5687 lastpt
->corner
= POINTTYPE_CORNER
;
5689 case POINTTYPE_CURVE_MIDDLE
:
5690 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
5691 lastpt
->corner
= POINTTYPE_CORNER
;
5693 lastpt
->corner
= POINTTYPE_CURVE
;
5701 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
5706 /* Get the y-distance from a line to a point */
5707 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
5708 D3DXVECTOR2
*line_pt2
,
5711 D3DXVECTOR2 line_vec
= {0, 0};
5715 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
5716 line_pt_dx
= point
->x
- line_pt1
->x
;
5717 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
5718 return point
->y
- line_y
;
5721 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
5723 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
5726 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
5728 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
5731 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
5733 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
5734 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
5738 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
5739 struct triangulation_array
*triangulations
,
5743 struct glyphinfo
*glyph
= triangulations
->glyph
;
5744 struct triangulation
*t
= *t_ptr
;
5749 if (t
->last_on_top
) {
5757 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
5758 /* consume all vertices on the stack */
5759 WORD last_pt
= t
->vertex_stack
.items
[0];
5761 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
5763 face
= add_face(&glyph
->faces
);
5764 if (!face
) return E_OUTOFMEMORY
;
5765 (*face
)[0] = vtx_idx
;
5766 (*face
)[f1
] = last_pt
;
5767 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
5769 t
->vertex_stack
.items
[0] = last_pt
;
5770 t
->vertex_stack
.count
= 1;
5771 } else if (t
->vertex_stack
.count
> 1) {
5772 int i
= t
->vertex_stack
.count
- 1;
5773 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
5774 WORD top_idx
= t
->vertex_stack
.items
[i
--];
5775 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
5779 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
5780 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
5782 if (prev_pt
->x
!= top_pt
->x
&&
5783 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
5784 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
5787 face
= add_face(&glyph
->faces
);
5788 if (!face
) return E_OUTOFMEMORY
;
5789 (*face
)[0] = vtx_idx
;
5790 (*face
)[f1
] = prev_idx
;
5791 (*face
)[f2
] = top_idx
;
5795 t
->vertex_stack
.count
--;
5798 t
->last_on_top
= to_top
;
5800 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
5802 if (hr
== S_OK
&& t
->merging
) {
5803 struct triangulation
*t2
;
5805 t2
= to_top
? t
- 1 : t
+ 1;
5806 t2
->merging
= FALSE
;
5807 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
5808 if (hr
!= S_OK
) return hr
;
5809 remove_triangulation(triangulations
, t
);
5817 /* check if the point is next on the outline for either the top or bottom */
5818 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
5820 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
5821 WORD idx
= t
->vertex_stack
.items
[i
];
5822 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
5823 struct outline
*outline
= pt_idx
->outline
;
5826 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
5828 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
5830 return &outline
->items
[i
].pos
;
5833 static int compare_vertex_indices(const void *a
, const void *b
)
5835 const struct point2d_index
*idx1
= a
, *idx2
= b
;
5836 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
5837 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
5838 float diff
= p1
->x
- p2
->x
;
5841 diff
= p1
->y
- p2
->y
;
5843 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
5846 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
5850 struct glyphinfo
*glyph
= triangulations
->glyph
;
5851 int nb_vertices
= 0;
5853 struct point2d_index
*idx_ptr
;
5855 /* Glyphs without outlines do not generate any vertices. */
5856 if (!glyph
->outlines
.count
)
5859 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5860 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
5862 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
5863 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
5864 if (!glyph
->ordered_vertices
.items
)
5865 return E_OUTOFMEMORY
;
5867 idx_ptr
= glyph
->ordered_vertices
.items
;
5868 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5870 struct outline
*outline
= &glyph
->outlines
.items
[i
];
5873 idx_ptr
->outline
= outline
;
5874 idx_ptr
->vertex
= 0;
5876 for (j
= outline
->count
- 1; j
> 0; j
--)
5878 idx_ptr
->outline
= outline
;
5879 idx_ptr
->vertex
= j
;
5883 glyph
->ordered_vertices
.count
= nb_vertices
;
5885 /* Native implementation seems to try to create a triangle fan from
5886 * the first outline point if the glyph only has one outline. */
5887 if (glyph
->outlines
.count
== 1)
5889 struct outline
*outline
= glyph
->outlines
.items
;
5890 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
5891 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
5894 for (i
= 2; i
< outline
->count
; i
++)
5896 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
5897 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
5898 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
5900 D3DXVec2Subtract(&v1
, base
, last
);
5901 D3DXVec2Subtract(&v2
, last
, next
);
5902 ccw
= D3DXVec2CCW(&v1
, &v2
);
5910 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5911 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
5912 if (!glyph
->faces
.items
)
5913 return E_OUTOFMEMORY
;
5915 glyph
->faces
.count
= outline
->count
- 2;
5916 for (i
= 0; i
< glyph
->faces
.count
; i
++)
5918 glyph
->faces
.items
[i
][0] = 0;
5919 glyph
->faces
.items
[i
][1] = i
+ 1;
5920 glyph
->faces
.items
[i
][2] = i
+ 2;
5926 /* Perform 2D polygon triangulation for complex glyphs.
5927 * Triangulation is performed using a sweep line concept, from right to left,
5928 * by processing vertices in sorted order. Complex polygons are split into
5929 * monotone polygons which are triangulated separately. */
5930 /* FIXME: The order of the faces is not consistent with the native implementation. */
5932 /* Reserve space for maximum possible faces from triangulation.
5933 * # faces for outer outlines = outline->count - 2
5934 * # faces for inner outlines = outline->count + 2
5935 * There must be at least 1 outer outline. */
5936 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5937 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
5938 if (!glyph
->faces
.items
)
5939 return E_OUTOFMEMORY
;
5941 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
5942 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
5943 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
5946 int end
= triangulations
->count
;
5950 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
5951 int current
= (start
+ end
) / 2;
5952 struct triangulation
*t
= &triangulations
->items
[current
];
5953 BOOL on_top_outline
= FALSE
;
5954 D3DXVECTOR2
*top_next
, *bottom_next
;
5955 WORD top_idx
, bottom_idx
;
5957 if (t
->merging
&& t
->last_on_top
)
5958 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
5960 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
5961 if (sweep_vtx
== top_next
)
5963 if (t
->merging
&& t
->last_on_top
)
5965 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
5966 if (hr
!= S_OK
) return hr
;
5968 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
5969 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
5971 /* point also on bottom outline of higher triangulation */
5972 struct triangulation
*t2
= t
+ 1;
5973 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
5974 if (hr
!= S_OK
) return hr
;
5979 on_top_outline
= TRUE
;
5982 if (t
->merging
&& !t
->last_on_top
)
5983 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
5985 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
5986 if (sweep_vtx
== bottom_next
)
5988 if (t
->merging
&& !t
->last_on_top
)
5990 if (on_top_outline
) {
5991 /* outline finished */
5992 remove_triangulation(triangulations
, t
);
5996 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
5997 if (hr
!= S_OK
) return hr
;
5999 if (t
> triangulations
->items
&&
6000 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
6002 struct triangulation
*t2
= t
- 1;
6003 /* point also on top outline of lower triangulation */
6004 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
6005 if (hr
!= S_OK
) return hr
;
6006 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
6016 if (t
->last_on_top
) {
6017 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
6018 bottom_idx
= t
->vertex_stack
.items
[0];
6020 top_idx
= t
->vertex_stack
.items
[0];
6021 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
6024 /* check if the point is inside or outside this polygon */
6025 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
6026 top_next
, sweep_vtx
) > 0)
6028 start
= current
+ 1;
6029 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
6030 bottom_next
, sweep_vtx
) < 0)
6033 } else if (t
->merging
) {
6034 /* inside, so cancel merging */
6035 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
6037 t2
->merging
= FALSE
;
6038 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
6039 if (hr
!= S_OK
) return hr
;
6040 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
6041 if (hr
!= S_OK
) return hr
;
6044 /* inside, so split polygon into two monotone parts */
6045 struct triangulation
*t2
= add_triangulation(triangulations
);
6046 if (!t2
) return E_OUTOFMEMORY
;
6047 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
6048 if (t
->last_on_top
) {
6055 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
6056 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
6057 if (hr
!= S_OK
) return hr
;
6058 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
6059 if (hr
!= S_OK
) return hr
;
6060 t2
->last_on_top
= !t
->last_on_top
;
6062 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
6063 if (hr
!= S_OK
) return hr
;
6069 struct triangulation
*t
;
6070 struct triangulation
*t2
= add_triangulation(triangulations
);
6071 if (!t2
) return E_OUTOFMEMORY
;
6072 t
= &triangulations
->items
[start
];
6073 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
6074 ZeroMemory(t
, sizeof(*t
));
6075 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
6076 if (hr
!= S_OK
) return hr
;
6082 HRESULT WINAPI
D3DXCreateTextW(struct IDirect3DDevice9
*device
, HDC hdc
, const WCHAR
*text
, float deviation
,
6083 float extrusion
, struct ID3DXMesh
**mesh_ptr
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
6086 ID3DXMesh
*mesh
= NULL
;
6087 DWORD nb_vertices
, nb_faces
;
6088 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
6089 struct vertex
*vertices
= NULL
;
6094 OUTLINETEXTMETRICW otm
;
6095 HFONT font
= NULL
, oldfont
= NULL
;
6096 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
6097 void *raw_outline
= NULL
;
6099 struct glyphinfo
*glyphs
= NULL
;
6101 struct triangulation_array triangulations
= {0, 0, NULL
};
6103 struct vertex
*vertex_ptr
;
6105 float max_deviation_sq
;
6106 const struct cos_table cos_table
= {
6107 cosf(D3DXToRadian(0.5f
)),
6108 cosf(D3DXToRadian(45.0f
)),
6109 cosf(D3DXToRadian(90.0f
)),
6113 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
6114 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
6116 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
6117 return D3DERR_INVALIDCALL
;
6121 FIXME("Case of adjacency != NULL not implemented.\n");
6125 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
6126 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
6128 return D3DERR_INVALIDCALL
;
6131 if (deviation
== 0.0f
)
6132 deviation
= 1.0f
/ otm
.otmEMSquare
;
6133 max_deviation_sq
= deviation
* deviation
;
6135 lf
.lfHeight
= otm
.otmEMSquare
;
6137 font
= CreateFontIndirectW(&lf
);
6142 oldfont
= SelectObject(hdc
, font
);
6144 textlen
= strlenW(text
);
6145 for (i
= 0; i
< textlen
; i
++)
6147 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
6149 return D3DERR_INVALIDCALL
;
6150 if (bufsize
< datasize
)
6153 if (!bufsize
) { /* e.g. text == " " */
6154 hr
= D3DERR_INVALIDCALL
;
6158 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
6159 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
6160 if (!glyphs
|| !raw_outline
) {
6166 for (i
= 0; i
< textlen
; i
++)
6168 /* get outline points from data returned from GetGlyphOutline */
6171 glyphs
[i
].offset_x
= offset_x
;
6173 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
6174 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
6175 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
6176 if (hr
!= S_OK
) goto error
;
6178 triangulations
.glyph
= &glyphs
[i
];
6179 hr
= triangulate(&triangulations
);
6180 if (hr
!= S_OK
) goto error
;
6181 if (triangulations
.count
) {
6182 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
6183 triangulations
.count
= 0;
6188 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
6189 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
6190 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
6191 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
6192 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6193 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
6195 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6198 /* corner points need an extra vertex for the different side faces normals */
6200 nb_outline_points
= 0;
6202 for (i
= 0; i
< textlen
; i
++)
6205 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
6206 nb_front_faces
+= glyphs
[i
].faces
.count
;
6207 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6210 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6211 nb_corners
++; /* first outline point always repeated as a corner */
6212 for (k
= 1; k
< outline
->count
; k
++)
6213 if (outline
->items
[k
].corner
)
6218 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
6219 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
6222 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
6223 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
6227 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
6230 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, (void **)&faces
)))
6233 /* convert 2D vertices and faces into 3D mesh */
6234 vertex_ptr
= vertices
;
6236 if (extrusion
== 0.0f
) {
6243 for (i
= 0; i
< textlen
; i
++)
6247 struct vertex
*back_vertices
;
6250 /* side vertices and faces */
6251 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6253 struct vertex
*outline_vertices
= vertex_ptr
;
6254 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6256 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
6257 struct point2d
*pt
= &outline
->items
[0];
6259 for (k
= 1; k
<= outline
->count
; k
++)
6262 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
6263 WORD vtx_idx
= vertex_ptr
- vertices
;
6266 if (pt
->corner
== POINTTYPE_CURVE_START
)
6267 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
6268 else if (pt
->corner
)
6269 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6271 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
6272 D3DXVec2Normalize(&vec
, &vec
);
6273 vtx
.normal
.x
= -vec
.y
;
6274 vtx
.normal
.y
= vec
.x
;
6277 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
6278 vtx
.position
.y
= pt
->pos
.y
;
6280 *vertex_ptr
++ = vtx
;
6282 vtx
.position
.z
= -extrusion
;
6283 *vertex_ptr
++ = vtx
;
6285 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
6286 vtx
.position
.y
= nextpt
->pos
.y
;
6287 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
6288 vtx
.position
.z
= -extrusion
;
6289 *vertex_ptr
++ = vtx
;
6291 *vertex_ptr
++ = vtx
;
6293 (*face_ptr
)[0] = vtx_idx
;
6294 (*face_ptr
)[1] = vtx_idx
+ 2;
6295 (*face_ptr
)[2] = vtx_idx
+ 1;
6298 (*face_ptr
)[0] = vtx_idx
;
6299 (*face_ptr
)[1] = vtx_idx
+ 3;
6300 (*face_ptr
)[2] = vtx_idx
+ 2;
6303 if (nextpt
->corner
) {
6304 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
6305 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
6306 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
6308 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6310 D3DXVec2Normalize(&vec
, &vec
);
6311 vtx
.normal
.x
= -vec
.y
;
6312 vtx
.normal
.y
= vec
.x
;
6315 *vertex_ptr
++ = vtx
;
6316 vtx
.position
.z
= -extrusion
;
6317 *vertex_ptr
++ = vtx
;
6320 (*face_ptr
)[0] = vtx_idx
;
6321 (*face_ptr
)[1] = vtx_idx
+ 3;
6322 (*face_ptr
)[2] = vtx_idx
+ 1;
6325 (*face_ptr
)[0] = vtx_idx
;
6326 (*face_ptr
)[1] = vtx_idx
+ 2;
6327 (*face_ptr
)[2] = vtx_idx
+ 3;
6335 *vertex_ptr
++ = *outline_vertices
++;
6336 *vertex_ptr
++ = *outline_vertices
++;
6340 /* back vertices and faces */
6341 back_faces
= face_ptr
;
6342 back_vertices
= vertex_ptr
;
6343 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
6345 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
6346 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
6347 vertex_ptr
->position
.y
= pt
->y
;
6348 vertex_ptr
->position
.z
= 0;
6349 vertex_ptr
->normal
.x
= 0;
6350 vertex_ptr
->normal
.y
= 0;
6351 vertex_ptr
->normal
.z
= 1;
6354 count
= back_vertices
- vertices
;
6355 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
6357 face
*f
= &glyphs
[i
].faces
.items
[j
];
6358 (*face_ptr
)[0] = (*f
)[0] + count
;
6359 (*face_ptr
)[1] = (*f
)[1] + count
;
6360 (*face_ptr
)[2] = (*f
)[2] + count
;
6364 /* front vertices and faces */
6365 j
= count
= vertex_ptr
- back_vertices
;
6368 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
6369 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
6370 vertex_ptr
->position
.z
= -extrusion
;
6371 vertex_ptr
->normal
.x
= 0;
6372 vertex_ptr
->normal
.y
= 0;
6373 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
6377 j
= face_ptr
- back_faces
;
6380 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
6381 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
6382 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
6392 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6393 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6394 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
6397 for (i
= 0; i
< textlen
; i
++)
6400 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6401 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
6402 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
6403 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
6404 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
6406 HeapFree(GetProcessHeap(), 0, glyphs
);
6408 if (triangulations
.items
) {
6410 for (i
= 0; i
< triangulations
.count
; i
++)
6411 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
6412 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
6414 HeapFree(GetProcessHeap(), 0, raw_outline
);
6415 if (oldfont
) SelectObject(hdc
, oldfont
);
6416 if (font
) DeleteObject(font
);
6421 HRESULT WINAPI
D3DXValidMesh(ID3DXMesh
*mesh
, const DWORD
*adjacency
, ID3DXBuffer
**errors_and_warnings
)
6423 FIXME("(%p, %p, %p): stub\n", mesh
, adjacency
, *errors_and_warnings
);
6428 static BOOL
weld_float1(void *to
, void *from
, FLOAT epsilon
)
6433 if (fabsf(*v1
- *v2
) <= epsilon
)
6443 static BOOL
weld_float2(void *to
, void *from
, FLOAT epsilon
)
6445 D3DXVECTOR2
*v1
= to
;
6446 D3DXVECTOR2
*v2
= from
;
6447 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6448 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6449 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6451 if (max_abs_diff
<= epsilon
)
6453 memcpy(to
, from
, sizeof(D3DXVECTOR2
));
6461 static BOOL
weld_float3(void *to
, void *from
, FLOAT epsilon
)
6463 D3DXVECTOR3
*v1
= to
;
6464 D3DXVECTOR3
*v2
= from
;
6465 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6466 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6467 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6468 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6469 max_abs_diff
= max(diff_z
, max_abs_diff
);
6471 if (max_abs_diff
<= epsilon
)
6473 memcpy(to
, from
, sizeof(D3DXVECTOR3
));
6481 static BOOL
weld_float4(void *to
, void *from
, FLOAT epsilon
)
6483 D3DXVECTOR4
*v1
= to
;
6484 D3DXVECTOR4
*v2
= from
;
6485 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6486 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6487 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6488 FLOAT diff_w
= fabsf(v1
->w
- v2
->w
);
6489 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6490 max_abs_diff
= max(diff_z
, max_abs_diff
);
6491 max_abs_diff
= max(diff_w
, max_abs_diff
);
6493 if (max_abs_diff
<= epsilon
)
6495 memcpy(to
, from
, sizeof(D3DXVECTOR4
));
6503 static BOOL
weld_ubyte4(void *to
, void *from
, FLOAT epsilon
)
6507 BYTE truncated_epsilon
= (BYTE
)epsilon
;
6508 BYTE diff_x
= b1
[0] > b2
[0] ? b1
[0] - b2
[0] : b2
[0] - b1
[0];
6509 BYTE diff_y
= b1
[1] > b2
[1] ? b1
[1] - b2
[1] : b2
[1] - b1
[1];
6510 BYTE diff_z
= b1
[2] > b2
[2] ? b1
[2] - b2
[2] : b2
[2] - b1
[2];
6511 BYTE diff_w
= b1
[3] > b2
[3] ? b1
[3] - b2
[3] : b2
[3] - b1
[3];
6512 BYTE max_diff
= max(diff_x
, diff_y
);
6513 max_diff
= max(diff_z
, max_diff
);
6514 max_diff
= max(diff_w
, max_diff
);
6516 if (max_diff
<= truncated_epsilon
)
6518 memcpy(to
, from
, 4 * sizeof(BYTE
));
6526 static BOOL
weld_ubyte4n(void *to
, void *from
, FLOAT epsilon
)
6528 return weld_ubyte4(to
, from
, epsilon
* UCHAR_MAX
);
6531 static BOOL
weld_d3dcolor(void *to
, void *from
, FLOAT epsilon
)
6533 return weld_ubyte4n(to
, from
, epsilon
);
6536 static BOOL
weld_short2(void *to
, void *from
, FLOAT epsilon
)
6540 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6541 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6542 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6543 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6545 if (max_abs_diff
<= truncated_epsilon
)
6547 memcpy(to
, from
, 2 * sizeof(SHORT
));
6555 static BOOL
weld_short2n(void *to
, void *from
, FLOAT epsilon
)
6557 return weld_short2(to
, from
, epsilon
* SHRT_MAX
);
6560 static BOOL
weld_short4(void *to
, void *from
, FLOAT epsilon
)
6564 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6565 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6566 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6567 SHORT diff_z
= abs(s1
[2] - s2
[2]);
6568 SHORT diff_w
= abs(s1
[3] - s2
[3]);
6569 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6570 max_abs_diff
= max(diff_z
, max_abs_diff
);
6571 max_abs_diff
= max(diff_w
, max_abs_diff
);
6573 if (max_abs_diff
<= truncated_epsilon
)
6575 memcpy(to
, from
, 4 * sizeof(SHORT
));
6583 static BOOL
weld_short4n(void *to
, void *from
, FLOAT epsilon
)
6585 return weld_short4(to
, from
, epsilon
* SHRT_MAX
);
6588 static BOOL
weld_ushort2n(void *to
, void *from
, FLOAT epsilon
)
6592 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6593 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6594 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6595 USHORT max_diff
= max(diff_x
, diff_y
);
6597 if (max_diff
<= scaled_epsilon
)
6599 memcpy(to
, from
, 2 * sizeof(USHORT
));
6607 static BOOL
weld_ushort4n(void *to
, void *from
, FLOAT epsilon
)
6611 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6612 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6613 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6614 USHORT diff_z
= s1
[2] > s2
[2] ? s1
[2] - s2
[2] : s2
[2] - s1
[2];
6615 USHORT diff_w
= s1
[3] > s2
[3] ? s1
[3] - s2
[3] : s2
[3] - s1
[3];
6616 USHORT max_diff
= max(diff_x
, diff_y
);
6617 max_diff
= max(diff_z
, max_diff
);
6618 max_diff
= max(diff_w
, max_diff
);
6620 if (max_diff
<= scaled_epsilon
)
6622 memcpy(to
, from
, 4 * sizeof(USHORT
));
6638 static struct udec3
dword_to_udec3(DWORD d
)
6643 v
.y
= (d
& 0xffc00) >> 10;
6644 v
.z
= (d
& 0x3ff00000) >> 20;
6645 v
.w
= (d
& 0xc0000000) >> 30;
6650 static BOOL
weld_udec3(void *to
, void *from
, FLOAT epsilon
)
6654 struct udec3 v1
= dword_to_udec3(*d1
);
6655 struct udec3 v2
= dword_to_udec3(*d2
);
6656 UINT truncated_epsilon
= (UINT
)epsilon
;
6657 UINT diff_x
= v1
.x
> v2
.x
? v1
.x
- v2
.x
: v2
.x
- v1
.x
;
6658 UINT diff_y
= v1
.y
> v2
.y
? v1
.y
- v2
.y
: v2
.y
- v1
.y
;
6659 UINT diff_z
= v1
.z
> v2
.z
? v1
.z
- v2
.z
: v2
.z
- v1
.z
;
6660 UINT diff_w
= v1
.w
> v2
.w
? v1
.w
- v2
.w
: v2
.w
- v1
.w
;
6661 UINT max_diff
= max(diff_x
, diff_y
);
6662 max_diff
= max(diff_z
, max_diff
);
6663 max_diff
= max(diff_w
, max_diff
);
6665 if (max_diff
<= truncated_epsilon
)
6667 memcpy(to
, from
, sizeof(DWORD
));
6683 static struct dec3n
dword_to_dec3n(DWORD d
)
6688 v
.y
= (d
& 0xffc00) >> 10;
6689 v
.z
= (d
& 0x3ff00000) >> 20;
6690 v
.w
= (d
& 0xc0000000) >> 30;
6695 static BOOL
weld_dec3n(void *to
, void *from
, FLOAT epsilon
)
6697 const UINT MAX_DEC3N
= 511;
6700 struct dec3n v1
= dword_to_dec3n(*d1
);
6701 struct dec3n v2
= dword_to_dec3n(*d2
);
6702 INT scaled_epsilon
= (INT
)(epsilon
* MAX_DEC3N
);
6703 INT diff_x
= abs(v1
.x
- v2
.x
);
6704 INT diff_y
= abs(v1
.y
- v2
.y
);
6705 INT diff_z
= abs(v1
.z
- v2
.z
);
6706 INT diff_w
= abs(v1
.w
- v2
.w
);
6707 INT max_abs_diff
= max(diff_x
, diff_y
);
6708 max_abs_diff
= max(diff_z
, max_abs_diff
);
6709 max_abs_diff
= max(diff_w
, max_abs_diff
);
6711 if (max_abs_diff
<= scaled_epsilon
)
6713 memcpy(to
, from
, sizeof(DWORD
));
6721 static BOOL
weld_float16_2(void *to
, void *from
, FLOAT epsilon
)
6723 D3DXFLOAT16
*v1_float16
= to
;
6724 D3DXFLOAT16
*v2_float16
= from
;
6732 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6733 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6735 diff_x
= fabsf(v1
[0] - v2
[0]);
6736 diff_y
= fabsf(v1
[1] - v2
[1]);
6737 max_abs_diff
= max(diff_x
, diff_y
);
6739 if (max_abs_diff
<= epsilon
)
6741 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6750 static BOOL
weld_float16_4(void *to
, void *from
, FLOAT epsilon
)
6752 D3DXFLOAT16
*v1_float16
= to
;
6753 D3DXFLOAT16
*v2_float16
= from
;
6763 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6764 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6766 diff_x
= fabsf(v1
[0] - v2
[0]);
6767 diff_y
= fabsf(v1
[1] - v2
[1]);
6768 diff_z
= fabsf(v1
[2] - v2
[2]);
6769 diff_w
= fabsf(v1
[3] - v2
[3]);
6770 max_abs_diff
= max(diff_x
, diff_y
);
6771 max_abs_diff
= max(diff_z
, max_abs_diff
);
6772 max_abs_diff
= max(diff_w
, max_abs_diff
);
6774 if (max_abs_diff
<= epsilon
)
6776 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6785 /* Sets the vertex components to the same value if they are within epsilon. */
6786 static BOOL
weld_component(void *to
, void *from
, D3DDECLTYPE type
, FLOAT epsilon
)
6788 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6789 BOOL fixme_once_unused
= FALSE
;
6790 BOOL fixme_once_unknown
= FALSE
;
6794 case D3DDECLTYPE_FLOAT1
:
6795 return weld_float1(to
, from
, epsilon
);
6797 case D3DDECLTYPE_FLOAT2
:
6798 return weld_float2(to
, from
, epsilon
);
6800 case D3DDECLTYPE_FLOAT3
:
6801 return weld_float3(to
, from
, epsilon
);
6803 case D3DDECLTYPE_FLOAT4
:
6804 return weld_float4(to
, from
, epsilon
);
6806 case D3DDECLTYPE_D3DCOLOR
:
6807 return weld_d3dcolor(to
, from
, epsilon
);
6809 case D3DDECLTYPE_UBYTE4
:
6810 return weld_ubyte4(to
, from
, epsilon
);
6812 case D3DDECLTYPE_SHORT2
:
6813 return weld_short2(to
, from
, epsilon
);
6815 case D3DDECLTYPE_SHORT4
:
6816 return weld_short4(to
, from
, epsilon
);
6818 case D3DDECLTYPE_UBYTE4N
:
6819 return weld_ubyte4n(to
, from
, epsilon
);
6821 case D3DDECLTYPE_SHORT2N
:
6822 return weld_short2n(to
, from
, epsilon
);
6824 case D3DDECLTYPE_SHORT4N
:
6825 return weld_short4n(to
, from
, epsilon
);
6827 case D3DDECLTYPE_USHORT2N
:
6828 return weld_ushort2n(to
, from
, epsilon
);
6830 case D3DDECLTYPE_USHORT4N
:
6831 return weld_ushort4n(to
, from
, epsilon
);
6833 case D3DDECLTYPE_UDEC3
:
6834 return weld_udec3(to
, from
, epsilon
);
6836 case D3DDECLTYPE_DEC3N
:
6837 return weld_dec3n(to
, from
, epsilon
);
6839 case D3DDECLTYPE_FLOAT16_2
:
6840 return weld_float16_2(to
, from
, epsilon
);
6842 case D3DDECLTYPE_FLOAT16_4
:
6843 return weld_float16_4(to
, from
, epsilon
);
6845 case D3DDECLTYPE_UNUSED
:
6846 if (!fixme_once_unused
++)
6847 FIXME("D3DDECLTYPE_UNUSED welding not implemented.\n");
6851 if (!fixme_once_unknown
++)
6852 FIXME("Welding of unknown declaration type %d is not implemented.\n", type
);
6859 static FLOAT
get_component_epsilon(const D3DVERTEXELEMENT9
*decl_ptr
, const D3DXWELDEPSILONS
*epsilons
)
6861 FLOAT epsilon
= 0.0f
;
6862 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6863 static BOOL fixme_once_blendindices
= FALSE
;
6864 static BOOL fixme_once_positiont
= FALSE
;
6865 static BOOL fixme_once_fog
= FALSE
;
6866 static BOOL fixme_once_depth
= FALSE
;
6867 static BOOL fixme_once_sample
= FALSE
;
6868 static BOOL fixme_once_unknown
= FALSE
;
6870 switch (decl_ptr
->Usage
)
6872 case D3DDECLUSAGE_POSITION
:
6873 epsilon
= epsilons
->Position
;
6875 case D3DDECLUSAGE_BLENDWEIGHT
:
6876 epsilon
= epsilons
->BlendWeights
;
6878 case D3DDECLUSAGE_NORMAL
:
6879 epsilon
= epsilons
->Normals
;
6881 case D3DDECLUSAGE_PSIZE
:
6882 epsilon
= epsilons
->PSize
;
6884 case D3DDECLUSAGE_TEXCOORD
:
6886 BYTE usage_index
= decl_ptr
->UsageIndex
;
6887 if (usage_index
> 7)
6889 epsilon
= epsilons
->Texcoords
[usage_index
];
6892 case D3DDECLUSAGE_TANGENT
:
6893 epsilon
= epsilons
->Tangent
;
6895 case D3DDECLUSAGE_BINORMAL
:
6896 epsilon
= epsilons
->Binormal
;
6898 case D3DDECLUSAGE_TESSFACTOR
:
6899 epsilon
= epsilons
->TessFactor
;
6901 case D3DDECLUSAGE_COLOR
:
6902 if (decl_ptr
->UsageIndex
== 0)
6903 epsilon
= epsilons
->Diffuse
;
6904 else if (decl_ptr
->UsageIndex
== 1)
6905 epsilon
= epsilons
->Specular
;
6909 case D3DDECLUSAGE_BLENDINDICES
:
6910 if (!fixme_once_blendindices
++)
6911 FIXME("D3DDECLUSAGE_BLENDINDICES welding not implemented.\n");
6913 case D3DDECLUSAGE_POSITIONT
:
6914 if (!fixme_once_positiont
++)
6915 FIXME("D3DDECLUSAGE_POSITIONT welding not implemented.\n");
6917 case D3DDECLUSAGE_FOG
:
6918 if (!fixme_once_fog
++)
6919 FIXME("D3DDECLUSAGE_FOG welding not implemented.\n");
6921 case D3DDECLUSAGE_DEPTH
:
6922 if (!fixme_once_depth
++)
6923 FIXME("D3DDECLUSAGE_DEPTH welding not implemented.\n");
6925 case D3DDECLUSAGE_SAMPLE
:
6926 if (!fixme_once_sample
++)
6927 FIXME("D3DDECLUSAGE_SAMPLE welding not implemented.\n");
6930 if (!fixme_once_unknown
++)
6931 FIXME("Unknown usage %x\n", decl_ptr
->Usage
);
6938 /* Helper function for reading a 32-bit index buffer. */
6939 static inline DWORD
read_ib(void *index_buffer
, BOOL indices_are_32bit
,
6942 if (indices_are_32bit
)
6944 DWORD
*indices
= index_buffer
;
6945 return indices
[index
];
6949 WORD
*indices
= index_buffer
;
6950 return indices
[index
];
6954 /* Helper function for writing to a 32-bit index buffer. */
6955 static inline void write_ib(void *index_buffer
, BOOL indices_are_32bit
,
6956 DWORD index
, DWORD value
)
6958 if (indices_are_32bit
)
6960 DWORD
*indices
= index_buffer
;
6961 indices
[index
] = value
;
6965 WORD
*indices
= index_buffer
;
6966 indices
[index
] = value
;
6970 /*************************************************************************
6971 * D3DXWeldVertices (D3DX9_36.@)
6973 * Welds together similar vertices. The similarity between vert-
6974 * ices can be the position and other components such as
6978 * mesh [I] Mesh which vertices will be welded together.
6979 * flags [I] D3DXWELDEPSILONSFLAGS specifying how to weld.
6980 * epsilons [I] How similar a component needs to be for welding.
6981 * adjacency [I] Which faces are adjacent to other faces.
6982 * adjacency_out [O] Updated adjacency after welding.
6983 * face_remap_out [O] Which faces the old faces have been mapped to.
6984 * vertex_remap_out [O] Which vertices the old vertices have been mapped to.
6988 * Failure: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
6991 * Attribute sorting not implemented.
6994 HRESULT WINAPI
D3DXWeldVertices(ID3DXMesh
*mesh
, DWORD flags
, const D3DXWELDEPSILONS
*epsilons
,
6995 const DWORD
*adjacency
, DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
6997 DWORD
*adjacency_generated
= NULL
;
6998 const DWORD
*adjacency_ptr
;
6999 DWORD
*attributes
= NULL
;
7000 const FLOAT DEFAULT_EPSILON
= 1.0e-6f
;
7003 void *indices
= NULL
;
7004 BOOL indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
7005 DWORD optimize_flags
;
7006 DWORD
*point_reps
= NULL
;
7007 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(mesh
);
7008 DWORD
*vertex_face_map
= NULL
;
7009 BYTE
*vertices
= NULL
;
7011 TRACE("mesh %p, flags %#x, epsilons %p, adjacency %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
7012 mesh
, flags
, epsilons
, adjacency
, adjacency_out
, face_remap_out
, vertex_remap_out
);
7016 WARN("No flags are undefined. Using D3DXWELDEPSILONS_WELDPARTIALMATCHES instead.\n");
7017 flags
= D3DXWELDEPSILONS_WELDPARTIALMATCHES
;
7020 if (adjacency
) /* Use supplied adjacency. */
7022 adjacency_ptr
= adjacency
;
7024 else /* Adjacency has to be generated. */
7026 adjacency_generated
= HeapAlloc(GetProcessHeap(), 0, 3 * This
->numfaces
* sizeof(*adjacency_generated
));
7027 if (!adjacency_generated
)
7029 ERR("Couldn't allocate memory for adjacency_generated.\n");
7033 hr
= mesh
->lpVtbl
->GenerateAdjacency(mesh
, DEFAULT_EPSILON
, adjacency_generated
);
7036 ERR("Couldn't generate adjacency.\n");
7039 adjacency_ptr
= adjacency_generated
;
7042 /* Point representation says which vertices can be replaced. */
7043 point_reps
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*point_reps
));
7047 ERR("Couldn't allocate memory for point_reps.\n");
7050 hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency_ptr
, point_reps
);
7053 ERR("ConvertAdjacencyToPointReps failed.\n");
7057 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
);
7060 ERR("Couldn't lock index buffer.\n");
7064 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, 0, &attributes
);
7067 ERR("Couldn't lock attribute buffer.\n");
7070 vertex_face_map
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*vertex_face_map
));
7071 if (!vertex_face_map
)
7074 ERR("Couldn't allocate memory for vertex_face_map.\n");
7077 /* Build vertex face map, so that a vertex's face can be looked up. */
7078 for (i
= 0; i
< This
->numfaces
; i
++)
7081 for (j
= 0; j
< 3; j
++)
7083 DWORD index
= read_ib(indices
, indices_are_32bit
, 3*i
+ j
);
7084 vertex_face_map
[index
] = i
;
7088 if (flags
& D3DXWELDEPSILONS_WELDPARTIALMATCHES
)
7090 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void**)&vertices
);
7093 ERR("Couldn't lock vertex buffer.\n");
7096 /* For each vertex that can be removed, compare its vertex components
7097 * with the vertex components from the vertex that can replace it. A
7098 * vertex is only fully replaced if all the components match and the
7099 * flag D3DXWELDEPSILONS_DONOTREMOVEVERTICES is not set, and they
7100 * belong to the same attribute group. Otherwise the vertex components
7101 * that are within epsilon are set to the same value.
7103 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
7105 D3DVERTEXELEMENT9
*decl_ptr
;
7106 DWORD vertex_size
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
7107 DWORD num_vertex_components
;
7110 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7112 for (decl_ptr
= This
->cached_declaration
, num_vertex_components
= 0; decl_ptr
->Stream
!= 0xFF; decl_ptr
++, num_vertex_components
++)
7114 BYTE
*to
= &vertices
[vertex_size
*index
+ decl_ptr
->Offset
];
7115 BYTE
*from
= &vertices
[vertex_size
*point_reps
[index
] + decl_ptr
->Offset
];
7116 FLOAT epsilon
= get_component_epsilon(decl_ptr
, epsilons
);
7118 /* Don't weld self */
7119 if (index
== point_reps
[index
])
7125 if (weld_component(to
, from
, decl_ptr
->Type
, epsilon
))
7129 all_match
= (num_vertex_components
== matches
);
7130 if (all_match
&& !(flags
& D3DXWELDEPSILONS_DONOTREMOVEVERTICES
))
7132 DWORD to_face
= vertex_face_map
[index
];
7133 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7134 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7136 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7139 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7142 else if (flags
& D3DXWELDEPSILONS_WELDALL
)
7144 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
7146 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7147 DWORD to_face
= vertex_face_map
[index
];
7148 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7149 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7151 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7154 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7156 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7159 /* Compact mesh using OptimizeInplace */
7160 optimize_flags
= D3DXMESHOPT_COMPACT
;
7161 hr
= mesh
->lpVtbl
->OptimizeInplace(mesh
, optimize_flags
, adjacency_ptr
, adjacency_out
, face_remap_out
, vertex_remap_out
);
7164 ERR("Couldn't compact mesh.\n");
7170 HeapFree(GetProcessHeap(), 0, adjacency_generated
);
7171 HeapFree(GetProcessHeap(), 0, point_reps
);
7172 HeapFree(GetProcessHeap(), 0, vertex_face_map
);
7173 if (attributes
) mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7174 if (indices
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7175 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7180 /*************************************************************************
7181 * D3DXOptimizeFaces (D3DX9_36.@)
7183 * Re-orders the faces so the vertex cache is used optimally.
7186 * indices [I] Pointer to an index buffer belonging to a mesh.
7187 * num_faces [I] Number of faces in the mesh.
7188 * num_vertices [I] Number of vertices in the mesh.
7189 * indices_are_32bit [I] Specifies whether indices are 32- or 16-bit.
7190 * face_remap [I/O] The new order the faces should be drawn in.
7194 * Failure: D3DERR_INVALIDCALL.
7197 * The face re-ordering does not use the vertex cache optimally.
7200 HRESULT WINAPI
D3DXOptimizeFaces(const void *indices
, UINT num_faces
,
7201 UINT num_vertices
, BOOL indices_are_32bit
, DWORD
*face_remap
)
7204 UINT j
= num_faces
- 1;
7205 UINT limit_16_bit
= 2 << 15; /* According to MSDN */
7206 HRESULT hr
= D3D_OK
;
7208 FIXME("indices %p, num_faces %u, num_vertices %u, indices_are_32bit %#x, face_remap %p semi-stub. "
7209 "Face order will not be optimal.\n",
7210 indices
, num_faces
, num_vertices
, indices_are_32bit
, face_remap
);
7212 if (!indices_are_32bit
&& num_faces
>= limit_16_bit
)
7214 WARN("Number of faces must be less than %d when using 16-bit indices.\n",
7216 hr
= D3DERR_INVALIDCALL
;
7222 WARN("Face remap pointer is NULL.\n");
7223 hr
= D3DERR_INVALIDCALL
;
7227 /* The faces are drawn in reverse order for simple meshes. This ordering
7228 * is not optimal for complicated meshes, but will not break anything
7229 * either. The ordering should be changed to take advantage of the vertex
7230 * cache on the graphics card.
7232 * TODO Re-order to take advantage of vertex cache.
7234 for (i
= 0; i
< num_faces
; i
++)
7236 face_remap
[i
] = j
--;
7245 static D3DXVECTOR3
*vertex_element_vec3(BYTE
*vertices
, const D3DVERTEXELEMENT9
*declaration
,
7246 DWORD vertex_stride
, DWORD index
)
7248 return (D3DXVECTOR3
*)(vertices
+ declaration
->Offset
+ index
* vertex_stride
);
7251 static D3DXVECTOR3
read_vec3(BYTE
*vertices
, const D3DVERTEXELEMENT9
*declaration
,
7252 DWORD vertex_stride
, DWORD index
)
7254 D3DXVECTOR3 vec3
= {0};
7255 const D3DXVECTOR3
*src
= vertex_element_vec3(vertices
, declaration
, vertex_stride
, index
);
7257 switch (declaration
->Type
)
7259 case D3DDECLTYPE_FLOAT1
:
7262 case D3DDECLTYPE_FLOAT2
:
7266 case D3DDECLTYPE_FLOAT3
:
7267 case D3DDECLTYPE_FLOAT4
:
7271 ERR("Cannot read vec3\n");
7278 /*************************************************************************
7279 * D3DXComputeTangentFrameEx (D3DX9_36.@)
7281 HRESULT WINAPI
D3DXComputeTangentFrameEx(ID3DXMesh
*mesh
, DWORD texture_in_semantic
, DWORD texture_in_index
,
7282 DWORD u_partial_out_semantic
, DWORD u_partial_out_index
, DWORD v_partial_out_semantic
,
7283 DWORD v_partial_out_index
, DWORD normal_out_semantic
, DWORD normal_out_index
, DWORD options
,
7284 const DWORD
*adjacency
, float partial_edge_threshold
, float singular_point_threshold
,
7285 float normal_edge_threshold
, ID3DXMesh
**mesh_out
, ID3DXBuffer
**vertex_mapping
)
7288 void *indices
= NULL
;
7289 BYTE
*vertices
= NULL
;
7290 DWORD
*point_reps
= NULL
;
7292 BOOL indices_are_32bit
;
7293 DWORD i
, j
, num_faces
, num_vertices
, vertex_stride
;
7294 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
7295 D3DVERTEXELEMENT9
*position_declaration
= NULL
, *normal_declaration
= NULL
;
7296 DWORD weighting_method
= options
& (D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
);
7298 TRACE("mesh %p, texture_in_semantic %u, texture_in_index %u, u_partial_out_semantic %u, u_partial_out_index %u, "
7299 "v_partial_out_semantic %u, v_partial_out_index %u, normal_out_semantic %u, normal_out_index %u, "
7300 "options %#x, adjacency %p, partial_edge_threshold %f, singular_point_threshold %f, "
7301 "normal_edge_threshold %f, mesh_out %p, vertex_mapping %p\n",
7302 mesh
, texture_in_semantic
, texture_in_index
, u_partial_out_semantic
, u_partial_out_index
,
7303 v_partial_out_semantic
, v_partial_out_index
, normal_out_semantic
, normal_out_index
, options
, adjacency
,
7304 partial_edge_threshold
, singular_point_threshold
, normal_edge_threshold
, mesh_out
, vertex_mapping
);
7308 WARN("mesh is NULL\n");
7309 return D3DERR_INVALIDCALL
;
7312 if (weighting_method
== (D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
))
7314 WARN("D3DXTANGENT_WEIGHT_BY_AREA and D3DXTANGENT_WEIGHT_EQUAL are mutally exclusive\n");
7315 return D3DERR_INVALIDCALL
;
7318 if (u_partial_out_semantic
!= D3DX_DEFAULT
)
7320 FIXME("tangent vectors computation is not supported\n");
7324 if (v_partial_out_semantic
!= D3DX_DEFAULT
)
7326 FIXME("binormal vectors computation is not supported\n");
7330 if (options
& ~(D3DXTANGENT_GENERATE_IN_PLACE
| D3DXTANGENT_CALCULATE_NORMALS
| D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
))
7332 FIXME("unsupported options %#x\n", options
);
7336 if (!(options
& D3DXTANGENT_CALCULATE_NORMALS
))
7338 FIXME("only normals computation is supported\n");
7342 if (!(options
& D3DXTANGENT_GENERATE_IN_PLACE
) || mesh_out
|| vertex_mapping
)
7344 FIXME("only D3DXTANGENT_GENERATE_IN_PLACE is supported\n");
7348 if (FAILED(hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, declaration
)))
7351 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
7353 if (declaration
[i
].Usage
== D3DDECLUSAGE_POSITION
&& !declaration
[i
].UsageIndex
)
7354 position_declaration
= &declaration
[i
];
7355 if (declaration
[i
].Usage
== normal_out_semantic
&& declaration
[i
].UsageIndex
== normal_out_index
)
7356 normal_declaration
= &declaration
[i
];
7359 if (!position_declaration
|| !normal_declaration
)
7360 return D3DERR_INVALIDCALL
;
7362 if (normal_declaration
->Type
== D3DDECLTYPE_FLOAT3
)
7364 normal_size
= sizeof(D3DXVECTOR3
);
7366 else if (normal_declaration
->Type
== D3DDECLTYPE_FLOAT4
)
7368 normal_size
= sizeof(D3DXVECTOR4
);
7372 WARN("unsupported normals type %u\n", normal_declaration
->Type
);
7373 return D3DERR_INVALIDCALL
;
7376 num_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
7377 num_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
7378 vertex_stride
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
7379 indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
7381 point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*point_reps
));
7390 if (FAILED(hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency
, point_reps
)))
7395 for (i
= 0; i
< num_vertices
; i
++)
7399 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
)))
7402 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
7405 for (i
= 0; i
< num_vertices
; i
++)
7407 static const D3DXVECTOR4 default_vector
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
7408 void *normal
= vertices
+ normal_declaration
->Offset
+ i
* vertex_stride
;
7410 memcpy(normal
, &default_vector
, normal_size
);
7413 for (i
= 0; i
< num_faces
; i
++)
7415 float denominator
, weights
[3];
7416 D3DXVECTOR3 a
, b
, cross
, face_normal
;
7417 const DWORD face_indices
[3] =
7419 read_ib(indices
, indices_are_32bit
, 3 * i
+ 0),
7420 read_ib(indices
, indices_are_32bit
, 3 * i
+ 1),
7421 read_ib(indices
, indices_are_32bit
, 3 * i
+ 2)
7423 const D3DXVECTOR3 v0
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[0]);
7424 const D3DXVECTOR3 v1
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[1]);
7425 const D3DXVECTOR3 v2
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[2]);
7427 D3DXVec3Cross(&cross
, D3DXVec3Subtract(&a
, &v0
, &v1
), D3DXVec3Subtract(&b
, &v0
, &v2
));
7429 switch (weighting_method
)
7431 case D3DXTANGENT_WEIGHT_EQUAL
:
7432 weights
[0] = weights
[1] = weights
[2] = 1.0f
;
7434 case D3DXTANGENT_WEIGHT_BY_AREA
:
7435 weights
[0] = weights
[1] = weights
[2] = D3DXVec3Length(&cross
);
7438 /* weight by angle */
7439 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7443 weights
[0] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7445 D3DXVec3Subtract(&a
, &v1
, &v0
);
7446 D3DXVec3Subtract(&b
, &v1
, &v2
);
7447 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7451 weights
[1] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7453 D3DXVec3Subtract(&a
, &v2
, &v0
);
7454 D3DXVec3Subtract(&b
, &v2
, &v1
);
7455 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7459 weights
[2] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7464 D3DXVec3Normalize(&face_normal
, &cross
);
7466 for (j
= 0; j
< 3; j
++)
7469 DWORD rep_index
= point_reps
[face_indices
[j
]];
7470 D3DXVECTOR3
*rep_normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, rep_index
);
7472 D3DXVec3Scale(&normal
, &face_normal
, weights
[j
]);
7473 D3DXVec3Add(rep_normal
, rep_normal
, &normal
);
7477 for (i
= 0; i
< num_vertices
; i
++)
7479 DWORD rep_index
= point_reps
[i
];
7480 D3DXVECTOR3
*normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, i
);
7481 D3DXVECTOR3
*rep_normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, rep_index
);
7484 D3DXVec3Normalize(rep_normal
, rep_normal
);
7486 *normal
= *rep_normal
;
7493 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7496 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7498 HeapFree(GetProcessHeap(), 0, point_reps
);
7503 /*************************************************************************
7504 * D3DXComputeNormals (D3DX9_36.@)
7506 HRESULT WINAPI
D3DXComputeNormals(struct ID3DXBaseMesh
*mesh
, const DWORD
*adjacency
)
7508 TRACE("mesh %p, adjacency %p\n", mesh
, adjacency
);
7510 if (mesh
&& (ID3DXMeshVtbl
*)mesh
->lpVtbl
!= &D3DXMesh_Vtbl
)
7512 ERR("Invalid virtual table\n");
7513 return D3DERR_INVALIDCALL
;
7516 return D3DXComputeTangentFrameEx((ID3DXMesh
*)mesh
, D3DX_DEFAULT
, 0,
7517 D3DX_DEFAULT
, 0, D3DX_DEFAULT
, 0, D3DDECLUSAGE_NORMAL
, 0,
7518 D3DXTANGENT_GENERATE_IN_PLACE
| D3DXTANGENT_CALCULATE_NORMALS
,
7519 adjacency
, -1.01f
, -0.01f
, -1.01f
, NULL
, NULL
);
7522 /*************************************************************************
7523 * D3DXIntersect (D3DX9_36.@)
7525 HRESULT WINAPI
D3DXIntersect(ID3DXBaseMesh
*mesh
, const D3DXVECTOR3
*ray_pos
, const D3DXVECTOR3
*ray_dir
,
7526 BOOL
*hit
, DWORD
*face_index
, float *u
, float *v
, float *distance
, ID3DXBuffer
**all_hits
, DWORD
*count_of_hits
)
7528 FIXME("mesh %p, ray_pos %p, ray_dir %p, hit %p, face_index %p, u %p, v %p, distance %p, all_hits %p, "
7529 "count_of_hits %p stub!\n", mesh
, ray_pos
, ray_dir
, hit
, face_index
, u
, v
, distance
, all_hits
, count_of_hits
);
7534 HRESULT WINAPI
D3DXTessellateNPatches(ID3DXMesh
*mesh
, const DWORD
*adjacency_in
, float num_segs
,
7535 BOOL quadratic_normals
, ID3DXMesh
**mesh_out
, ID3DXBuffer
**adjacency_out
)
7537 FIXME("mesh %p, adjacency_in %p, num_segs %f, quadratic_normals %d, mesh_out %p, adjacency_out %p stub.\n",
7538 mesh
, adjacency_in
, num_segs
, quadratic_normals
, mesh_out
, adjacency_out
);
7543 HRESULT WINAPI
D3DXConvertMeshSubsetToSingleStrip(struct ID3DXBaseMesh
*mesh_in
, DWORD attribute_id
,
7544 DWORD ib_flags
, struct IDirect3DIndexBuffer9
**index_buffer
, DWORD
*index_count
)
7546 FIXME("mesh_in %p, attribute_id %u, ib_flags %u, index_buffer %p, index_count %p stub.\n",
7547 mesh_in
, attribute_id
, ib_flags
, index_buffer
, index_count
);
7558 static BOOL
queue_frame_node(struct list
*queue
, D3DXFRAME
*frame
)
7560 struct frame_node
*node
;
7562 if (!frame
->pFrameFirstChild
)
7565 node
= HeapAlloc(GetProcessHeap(), 0, sizeof(*node
));
7569 node
->frame
= frame
;
7570 list_add_tail(queue
, &node
->entry
);
7575 static void empty_frame_queue(struct list
*queue
)
7577 struct frame_node
*cur
, *cur2
;
7578 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, queue
, struct frame_node
, entry
)
7580 list_remove(&cur
->entry
);
7581 HeapFree(GetProcessHeap(), 0, cur
);
7585 D3DXFRAME
* WINAPI
D3DXFrameFind(const D3DXFRAME
*root
, const char *name
)
7587 D3DXFRAME
*found
= NULL
, *frame
;
7590 TRACE("root frame %p, name %s.\n", root
, debugstr_a(name
));
7597 frame
= (D3DXFRAME
*)root
;
7601 struct frame_node
*node
;
7605 if ((name
&& frame
->Name
&& !strcmp(frame
->Name
, name
)) || (!name
&& !frame
->Name
))
7611 if (!queue_frame_node(&queue
, frame
))
7614 frame
= frame
->pFrameSibling
;
7617 if (list_empty(&queue
))
7620 node
= LIST_ENTRY(list_head(&queue
), struct frame_node
, entry
);
7621 list_remove(&node
->entry
);
7622 frame
= node
->frame
->pFrameFirstChild
;
7623 HeapFree(GetProcessHeap(), 0, node
);
7627 empty_frame_queue(&queue
);