6 * Mesh operations specific to D3DX9.
8 * Copyright (C) 2005 Henri Verbeet
9 * Copyright (C) 2006 Ivan Gyurdiev
10 * Copyright (C) 2009 David Adam
11 * Copyright (C) 2010 Tony Wasserka
12 * Copyright (C) 2011 Dylan Smith
13 * Copyright (C) 2011 Michael Mc Donnell
14 * Copyright (C) 2013 Christian Costa
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35 #include "d3dx9_private.h"
40 #include "wine/list.h"
41 #endif /* __REACTOS__ */
43 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
47 ID3DXMesh ID3DXMesh_iface
;
54 IDirect3DDevice9
*device
;
55 D3DVERTEXELEMENT9 cached_declaration
[MAX_FVF_DECL_SIZE
];
56 IDirect3DVertexDeclaration9
*vertex_declaration
;
57 UINT vertex_declaration_size
;
59 IDirect3DVertexBuffer9
*vertex_buffer
;
60 IDirect3DIndexBuffer9
*index_buffer
;
62 int attrib_buffer_lock_count
;
63 DWORD attrib_table_size
;
64 D3DXATTRIBUTERANGE
*attrib_table
;
67 static const UINT d3dx_decltype_size
[] =
69 /* D3DDECLTYPE_FLOAT1 */ sizeof(FLOAT
),
70 /* D3DDECLTYPE_FLOAT2 */ sizeof(D3DXVECTOR2
),
71 /* D3DDECLTYPE_FLOAT3 */ sizeof(D3DXVECTOR3
),
72 /* D3DDECLTYPE_FLOAT4 */ sizeof(D3DXVECTOR4
),
73 /* D3DDECLTYPE_D3DCOLOR */ sizeof(D3DCOLOR
),
74 /* D3DDECLTYPE_UBYTE4 */ 4 * sizeof(BYTE
),
75 /* D3DDECLTYPE_SHORT2 */ 2 * sizeof(SHORT
),
76 /* D3DDECLTYPE_SHORT4 */ 4 * sizeof(SHORT
),
77 /* D3DDECLTYPE_UBYTE4N */ 4 * sizeof(BYTE
),
78 /* D3DDECLTYPE_SHORT2N */ 2 * sizeof(SHORT
),
79 /* D3DDECLTYPE_SHORT4N */ 4 * sizeof(SHORT
),
80 /* D3DDECLTYPE_USHORT2N */ 2 * sizeof(USHORT
),
81 /* D3DDECLTYPE_USHORT4N */ 4 * sizeof(USHORT
),
82 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
83 /* D3DDECLTYPE_DEC3N */ 4,
84 /* D3DDECLTYPE_FLOAT16_2 */ 2 * sizeof(D3DXFLOAT16
),
85 /* D3DDECLTYPE_FLOAT16_4 */ 4 * sizeof(D3DXFLOAT16
),
88 static inline struct d3dx9_mesh
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
90 return CONTAINING_RECORD(iface
, struct d3dx9_mesh
, ID3DXMesh_iface
);
93 static HRESULT WINAPI
d3dx9_mesh_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, void **out
)
95 TRACE("iface %p, riid %s, out %p.\n", iface
, debugstr_guid(riid
), out
);
97 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
98 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
99 IsEqualGUID(riid
, &IID_ID3DXMesh
))
101 iface
->lpVtbl
->AddRef(iface
);
106 WARN("Interface %s not found.\n", debugstr_guid(riid
));
108 return E_NOINTERFACE
;
111 static ULONG WINAPI
d3dx9_mesh_AddRef(ID3DXMesh
*iface
)
113 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
114 ULONG refcount
= InterlockedIncrement(&mesh
->ref
);
116 TRACE("%p increasing refcount to %u.\n", mesh
, refcount
);
121 static ULONG WINAPI
d3dx9_mesh_Release(ID3DXMesh
*iface
)
123 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
124 ULONG refcount
= InterlockedDecrement(&mesh
->ref
);
126 TRACE("%p decreasing refcount to %u.\n", mesh
, refcount
);
130 IDirect3DIndexBuffer9_Release(mesh
->index_buffer
);
131 IDirect3DVertexBuffer9_Release(mesh
->vertex_buffer
);
132 if (mesh
->vertex_declaration
)
133 IDirect3DVertexDeclaration9_Release(mesh
->vertex_declaration
);
134 IDirect3DDevice9_Release(mesh
->device
);
135 HeapFree(GetProcessHeap(), 0, mesh
->attrib_buffer
);
136 HeapFree(GetProcessHeap(), 0, mesh
->attrib_table
);
137 HeapFree(GetProcessHeap(), 0, mesh
);
143 static HRESULT WINAPI
d3dx9_mesh_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
145 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
151 TRACE("iface %p, attrib_id %u.\n", iface
, attrib_id
);
153 if (!This
->vertex_declaration
)
155 WARN("Can't draw a mesh with an invalid vertex declaration.\n");
159 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
161 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
162 if (FAILED(hr
)) return hr
;
163 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
164 if (FAILED(hr
)) return hr
;
165 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
166 if (FAILED(hr
)) return hr
;
168 while (face_end
< This
->numfaces
)
170 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
172 if (This
->attrib_buffer
[face_start
] == attrib_id
)
175 if (face_start
>= This
->numfaces
)
177 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
179 if (This
->attrib_buffer
[face_end
] != attrib_id
)
183 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
184 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
185 if (FAILED(hr
)) return hr
;
191 static DWORD WINAPI
d3dx9_mesh_GetNumFaces(ID3DXMesh
*iface
)
193 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
195 TRACE("iface %p.\n", iface
);
197 return mesh
->numfaces
;
200 static DWORD WINAPI
d3dx9_mesh_GetNumVertices(ID3DXMesh
*iface
)
202 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
204 TRACE("iface %p.\n", iface
);
206 return mesh
->numvertices
;
209 static DWORD WINAPI
d3dx9_mesh_GetFVF(ID3DXMesh
*iface
)
211 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
213 TRACE("iface %p.\n", iface
);
218 static void copy_declaration(D3DVERTEXELEMENT9
*dst
, const D3DVERTEXELEMENT9
*src
, UINT num_elem
)
220 memcpy(dst
, src
, num_elem
* sizeof(*src
));
223 static HRESULT WINAPI
d3dx9_mesh_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
225 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
227 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
230 return D3DERR_INVALIDCALL
;
232 copy_declaration(declaration
, mesh
->cached_declaration
, mesh
->num_elem
);
237 static DWORD WINAPI
d3dx9_mesh_GetNumBytesPerVertex(ID3DXMesh
*iface
)
239 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
241 TRACE("iface %p.\n", iface
);
243 return mesh
->vertex_declaration_size
;
246 static DWORD WINAPI
d3dx9_mesh_GetOptions(ID3DXMesh
*iface
)
248 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
250 TRACE("iface %p.\n", iface
);
252 return mesh
->options
;
255 static HRESULT WINAPI
d3dx9_mesh_GetDevice(struct ID3DXMesh
*iface
, struct IDirect3DDevice9
**device
)
257 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
259 TRACE("iface %p, device %p.\n", iface
, device
);
262 return D3DERR_INVALIDCALL
;
263 *device
= mesh
->device
;
264 IDirect3DDevice9_AddRef(mesh
->device
);
269 static HRESULT WINAPI
d3dx9_mesh_CloneMeshFVF(struct ID3DXMesh
*iface
, DWORD options
, DWORD fvf
,
270 struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh
)
273 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
275 TRACE("iface %p, options %#x, fvf %#x, device %p, clone_mesh %p.\n",
276 iface
, options
, fvf
, device
, clone_mesh
);
278 if (FAILED(hr
= D3DXDeclaratorFromFVF(fvf
, declaration
)))
281 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
284 static FLOAT
scale_clamp_ubyten(FLOAT value
)
286 value
= value
* UCHAR_MAX
;
294 if (value
> UCHAR_MAX
) /* Clamp at 255 */
301 static FLOAT
scale_clamp_shortn(FLOAT value
)
303 value
= value
* SHRT_MAX
;
305 /* The tests show that the range is SHRT_MIN + 1 to SHRT_MAX. */
306 if (value
<= SHRT_MIN
)
310 else if (value
> SHRT_MAX
)
320 static FLOAT
scale_clamp_ushortn(FLOAT value
)
322 value
= value
* USHRT_MAX
;
330 if (value
> USHRT_MAX
) /* Clamp at 65535 */
337 static INT
simple_round(FLOAT value
)
339 int res
= (INT
)(value
+ 0.5f
);
344 static void convert_float4(BYTE
*dst
, const D3DXVECTOR4
*src
, D3DDECLTYPE type_dst
)
346 BOOL fixme_once
= FALSE
;
350 case D3DDECLTYPE_FLOAT1
:
352 FLOAT
*dst_ptr
= (FLOAT
*)dst
;
356 case D3DDECLTYPE_FLOAT2
:
358 D3DXVECTOR2
*dst_ptr
= (D3DXVECTOR2
*)dst
;
363 case D3DDECLTYPE_FLOAT3
:
365 D3DXVECTOR3
*dst_ptr
= (D3DXVECTOR3
*)dst
;
371 case D3DDECLTYPE_FLOAT4
:
373 D3DXVECTOR4
*dst_ptr
= (D3DXVECTOR4
*)dst
;
380 case D3DDECLTYPE_D3DCOLOR
:
382 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
383 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
384 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
385 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
388 case D3DDECLTYPE_UBYTE4
:
390 dst
[0] = src
->x
< 0.0f
? 0 : (BYTE
)simple_round(src
->x
);
391 dst
[1] = src
->y
< 0.0f
? 0 : (BYTE
)simple_round(src
->y
);
392 dst
[2] = src
->z
< 0.0f
? 0 : (BYTE
)simple_round(src
->z
);
393 dst
[3] = src
->w
< 0.0f
? 0 : (BYTE
)simple_round(src
->w
);
396 case D3DDECLTYPE_SHORT2
:
398 SHORT
*dst_ptr
= (SHORT
*)dst
;
399 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
400 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
403 case D3DDECLTYPE_SHORT4
:
405 SHORT
*dst_ptr
= (SHORT
*)dst
;
406 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
407 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
408 dst_ptr
[2] = (SHORT
)simple_round(src
->z
);
409 dst_ptr
[3] = (SHORT
)simple_round(src
->w
);
412 case D3DDECLTYPE_UBYTE4N
:
414 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
415 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
416 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
417 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
420 case D3DDECLTYPE_SHORT2N
:
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
));
427 case D3DDECLTYPE_SHORT4N
:
429 SHORT
*dst_ptr
= (SHORT
*)dst
;
430 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
431 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
432 dst_ptr
[2] = (SHORT
)simple_round(scale_clamp_shortn(src
->z
));
433 dst_ptr
[3] = (SHORT
)simple_round(scale_clamp_shortn(src
->w
));
436 case D3DDECLTYPE_USHORT2N
:
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
));
443 case D3DDECLTYPE_USHORT4N
:
445 USHORT
*dst_ptr
= (USHORT
*)dst
;
446 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
447 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
448 dst_ptr
[2] = (USHORT
)simple_round(scale_clamp_ushortn(src
->z
));
449 dst_ptr
[3] = (USHORT
)simple_round(scale_clamp_ushortn(src
->w
));
452 case D3DDECLTYPE_FLOAT16_2
:
454 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 2);
457 case D3DDECLTYPE_FLOAT16_4
:
459 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 4);
464 FIXME("Conversion from D3DDECLTYPE_FLOAT4 to %d not implemented.\n", type_dst
);
469 static void convert_component(BYTE
*dst
, BYTE
*src
, D3DDECLTYPE type_dst
, D3DDECLTYPE type_src
)
471 BOOL fixme_once
= FALSE
;
475 case D3DDECLTYPE_FLOAT1
:
477 FLOAT
*src_ptr
= (FLOAT
*)src
;
478 D3DXVECTOR4 src_float4
= {*src_ptr
, 0.0f
, 0.0f
, 1.0f
};
479 convert_float4(dst
, &src_float4
, type_dst
);
482 case D3DDECLTYPE_FLOAT2
:
484 D3DXVECTOR2
*src_ptr
= (D3DXVECTOR2
*)src
;
485 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, 0.0f
, 1.0f
};
486 convert_float4(dst
, &src_float4
, type_dst
);
489 case D3DDECLTYPE_FLOAT3
:
491 D3DXVECTOR3
*src_ptr
= (D3DXVECTOR3
*)src
;
492 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, 1.0f
};
493 convert_float4(dst
, &src_float4
, type_dst
);
496 case D3DDECLTYPE_FLOAT4
:
498 D3DXVECTOR4
*src_ptr
= (D3DXVECTOR4
*)src
;
499 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, src_ptr
->w
};
500 convert_float4(dst
, &src_float4
, type_dst
);
503 case D3DDECLTYPE_D3DCOLOR
:
505 D3DXVECTOR4 src_float4
=
507 (FLOAT
)src
[2]/UCHAR_MAX
,
508 (FLOAT
)src
[1]/UCHAR_MAX
,
509 (FLOAT
)src
[0]/UCHAR_MAX
,
510 (FLOAT
)src
[3]/UCHAR_MAX
512 convert_float4(dst
, &src_float4
, type_dst
);
515 case D3DDECLTYPE_UBYTE4
:
517 D3DXVECTOR4 src_float4
= {src
[0], src
[1], src
[2], src
[3]};
518 convert_float4(dst
, &src_float4
, type_dst
);
521 case D3DDECLTYPE_SHORT2
:
523 SHORT
*src_ptr
= (SHORT
*)src
;
524 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], 0.0f
, 1.0f
};
525 convert_float4(dst
, &src_float4
, type_dst
);
528 case D3DDECLTYPE_SHORT4
:
530 SHORT
*src_ptr
= (SHORT
*)src
;
531 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], src_ptr
[2], src_ptr
[3]};
532 convert_float4(dst
, &src_float4
, type_dst
);
535 case D3DDECLTYPE_UBYTE4N
:
537 D3DXVECTOR4 src_float4
=
539 (FLOAT
)src
[0]/UCHAR_MAX
,
540 (FLOAT
)src
[1]/UCHAR_MAX
,
541 (FLOAT
)src
[2]/UCHAR_MAX
,
542 (FLOAT
)src
[3]/UCHAR_MAX
544 convert_float4(dst
, &src_float4
, type_dst
);
547 case D3DDECLTYPE_SHORT2N
:
549 SHORT
*src_ptr
= (SHORT
*)src
;
550 D3DXVECTOR4 src_float4
= {(FLOAT
)src_ptr
[0]/SHRT_MAX
, (FLOAT
)src_ptr
[1]/SHRT_MAX
, 0.0f
, 1.0f
};
551 convert_float4(dst
, &src_float4
, type_dst
);
554 case D3DDECLTYPE_SHORT4N
:
556 SHORT
*src_ptr
= (SHORT
*)src
;
557 D3DXVECTOR4 src_float4
=
559 (FLOAT
)src_ptr
[0]/SHRT_MAX
,
560 (FLOAT
)src_ptr
[1]/SHRT_MAX
,
561 (FLOAT
)src_ptr
[2]/SHRT_MAX
,
562 (FLOAT
)src_ptr
[3]/SHRT_MAX
564 convert_float4(dst
, &src_float4
, type_dst
);
567 case D3DDECLTYPE_FLOAT16_2
:
569 D3DXVECTOR4 src_float4
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
570 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 2);
571 convert_float4(dst
, &src_float4
, type_dst
);
574 case D3DDECLTYPE_FLOAT16_4
:
576 D3DXVECTOR4 src_float4
;
577 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 4);
578 convert_float4(dst
, &src_float4
, type_dst
);
583 FIXME("Conversion of D3DDECLTYPE %d to %d not implemented.\n", type_src
, type_dst
);
588 static INT
get_equivalent_declaration_index(D3DVERTEXELEMENT9 orig_declaration
, D3DVERTEXELEMENT9
*declaration
)
592 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
594 if (orig_declaration
.Usage
== declaration
[i
].Usage
595 && orig_declaration
.UsageIndex
== declaration
[i
].UsageIndex
)
604 static HRESULT
convert_vertex_buffer(ID3DXMesh
*mesh_dst
, ID3DXMesh
*mesh_src
)
607 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
608 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
612 UINT num_vertices
= mesh_src
->lpVtbl
->GetNumVertices(mesh_src
);
613 UINT dst_vertex_size
= mesh_dst
->lpVtbl
->GetNumBytesPerVertex(mesh_dst
);
614 UINT src_vertex_size
= mesh_src
->lpVtbl
->GetNumBytesPerVertex(mesh_src
);
616 hr
= mesh_src
->lpVtbl
->GetDeclaration(mesh_src
, orig_declaration
);
617 if (FAILED(hr
)) return hr
;
618 hr
= mesh_dst
->lpVtbl
->GetDeclaration(mesh_dst
, declaration
);
619 if (FAILED(hr
)) return hr
;
621 hr
= mesh_src
->lpVtbl
->LockVertexBuffer(mesh_src
, D3DLOCK_READONLY
, (void**)&vb_src
);
622 if (FAILED(hr
)) goto cleanup
;
623 hr
= mesh_dst
->lpVtbl
->LockVertexBuffer(mesh_dst
, 0, (void**)&vb_dst
);
624 if (FAILED(hr
)) goto cleanup
;
626 /* Clear all new fields by clearing the entire vertex buffer. */
627 memset(vb_dst
, 0, num_vertices
* dst_vertex_size
);
629 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++)
631 INT eq_idx
= get_equivalent_declaration_index(orig_declaration
[i
], declaration
);
636 for (j
= 0; j
< num_vertices
; j
++)
638 UINT idx_dst
= dst_vertex_size
* j
+ declaration
[eq_idx
].Offset
;
639 UINT idx_src
= src_vertex_size
* j
+ orig_declaration
[i
].Offset
;
640 UINT type_size
= d3dx_decltype_size
[orig_declaration
[i
].Type
];
642 if (orig_declaration
[i
].Type
== declaration
[eq_idx
].Type
)
643 memcpy(&vb_dst
[idx_dst
], &vb_src
[idx_src
], type_size
);
645 convert_component(&vb_dst
[idx_dst
], &vb_src
[idx_src
], declaration
[eq_idx
].Type
, orig_declaration
[i
].Type
);
652 if (vb_dst
) mesh_dst
->lpVtbl
->UnlockVertexBuffer(mesh_dst
);
653 if (vb_src
) mesh_src
->lpVtbl
->UnlockVertexBuffer(mesh_src
);
658 static BOOL
declaration_equals(const D3DVERTEXELEMENT9
*declaration1
, const D3DVERTEXELEMENT9
*declaration2
)
660 UINT size1
= 0, size2
= 0;
662 /* Find the size of each declaration */
663 while (declaration1
[size1
].Stream
!= 0xff) size1
++;
664 while (declaration2
[size2
].Stream
!= 0xff) size2
++;
666 /* If not same size then they are definitely not equal */
670 /* Check that all components are the same */
671 if (memcmp(declaration1
, declaration2
, size1
*sizeof(*declaration1
)) == 0)
677 static HRESULT WINAPI
d3dx9_mesh_CloneMesh(struct ID3DXMesh
*iface
, DWORD options
,
678 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh_out
)
680 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
681 struct d3dx9_mesh
*cloned_this
;
682 ID3DXMesh
*clone_mesh
;
683 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
684 void *data_in
, *data_out
;
687 BOOL same_declaration
;
689 TRACE("iface %p, options %#x, declaration %p, device %p, clone_mesh_out %p.\n",
690 iface
, options
, declaration
, device
, clone_mesh_out
);
693 return D3DERR_INVALIDCALL
;
695 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
696 if (FAILED(hr
)) return hr
;
698 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
699 declaration
, device
, &clone_mesh
);
700 if (FAILED(hr
)) return hr
;
702 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
703 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
704 same_declaration
= declaration_equals(declaration
, orig_declaration
);
706 if (options
& D3DXMESH_VB_SHARE
) {
707 if (!same_declaration
) {
708 hr
= D3DERR_INVALIDCALL
;
711 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
712 /* FIXME: refactor to avoid creating a new vertex buffer */
713 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
714 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
715 } else if (same_declaration
) {
716 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
717 if (FAILED(hr
)) goto error
;
718 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, 0, &data_out
);
720 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
723 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
724 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
725 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
727 hr
= convert_vertex_buffer(clone_mesh
, iface
);
728 if (FAILED(hr
)) goto error
;
731 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
732 if (FAILED(hr
)) goto error
;
733 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, 0, &data_out
);
735 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
738 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
740 if (options
& D3DXMESH_32BIT
) {
741 for (i
= 0; i
< This
->numfaces
* 3; i
++)
742 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
744 for (i
= 0; i
< This
->numfaces
* 3; i
++)
745 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
748 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
750 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
751 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
753 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
755 if (This
->attrib_table_size
)
757 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
758 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
759 if (!cloned_this
->attrib_table
) {
763 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
766 *clone_mesh_out
= clone_mesh
;
770 IUnknown_Release(clone_mesh
);
774 static HRESULT WINAPI
d3dx9_mesh_GetVertexBuffer(struct ID3DXMesh
*iface
,
775 struct IDirect3DVertexBuffer9
**vertex_buffer
)
777 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
779 TRACE("iface %p, vertex_buffer %p.\n", iface
, vertex_buffer
);
782 return D3DERR_INVALIDCALL
;
783 *vertex_buffer
= mesh
->vertex_buffer
;
784 IDirect3DVertexBuffer9_AddRef(mesh
->vertex_buffer
);
789 static HRESULT WINAPI
d3dx9_mesh_GetIndexBuffer(struct ID3DXMesh
*iface
,
790 struct IDirect3DIndexBuffer9
**index_buffer
)
792 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
794 TRACE("iface %p, index_buffer %p.\n", iface
, index_buffer
);
797 return D3DERR_INVALIDCALL
;
798 *index_buffer
= mesh
->index_buffer
;
799 IDirect3DIndexBuffer9_AddRef(mesh
->index_buffer
);
804 static HRESULT WINAPI
d3dx9_mesh_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
806 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
808 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
810 return IDirect3DVertexBuffer9_Lock(mesh
->vertex_buffer
, 0, 0, data
, flags
);
813 static HRESULT WINAPI
d3dx9_mesh_UnlockVertexBuffer(ID3DXMesh
*iface
)
815 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
817 TRACE("iface %p.\n", iface
);
819 return IDirect3DVertexBuffer9_Unlock(mesh
->vertex_buffer
);
822 static HRESULT WINAPI
d3dx9_mesh_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
824 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
826 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
828 return IDirect3DIndexBuffer9_Lock(mesh
->index_buffer
, 0, 0, data
, flags
);
831 static HRESULT WINAPI
d3dx9_mesh_UnlockIndexBuffer(ID3DXMesh
*iface
)
833 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
835 TRACE("iface %p.\n", iface
);
837 return IDirect3DIndexBuffer9_Unlock(mesh
->index_buffer
);
840 /* FIXME: This looks just wrong, we never check *attrib_table_size before
841 * copying the data. */
842 static HRESULT WINAPI
d3dx9_mesh_GetAttributeTable(ID3DXMesh
*iface
,
843 D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
845 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
847 TRACE("iface %p, attrib_table %p, attrib_table_size %p.\n",
848 iface
, attrib_table
, attrib_table_size
);
850 if (attrib_table_size
)
851 *attrib_table_size
= mesh
->attrib_table_size
;
854 memcpy(attrib_table
, mesh
->attrib_table
, mesh
->attrib_table_size
* sizeof(*attrib_table
));
869 struct edge_face
*entries
;
872 /* Builds up a map of which face a new edge belongs to. That way the adjacency
873 * of another edge can be looked up. An edge has an adjacent face if there
874 * is an edge going in the opposite direction in the map. For example if the
875 * edge (v1, v2) belongs to face 4, and there is a mapping (v2, v1)->7, then
876 * face 4 and 7 are adjacent.
878 * Each edge might have been replaced with another edge, or none at all. There
879 * is at most one edge to face mapping, i.e. an edge can only belong to one
882 static HRESULT
init_edge_face_map(struct edge_face_map
*edge_face_map
, const DWORD
*index_buffer
,
883 const DWORD
*point_reps
, DWORD num_faces
)
888 edge_face_map
->lists
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->lists
));
889 if (!edge_face_map
->lists
) return E_OUTOFMEMORY
;
891 edge_face_map
->entries
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->entries
));
892 if (!edge_face_map
->entries
) return E_OUTOFMEMORY
;
895 /* Initialize all lists */
896 for (i
= 0; i
< 3 * num_faces
; i
++)
898 list_init(&edge_face_map
->lists
[i
]);
900 /* Build edge face mapping */
901 for (face
= 0; face
< num_faces
; face
++)
903 for (edge
= 0; edge
< 3; edge
++)
905 DWORD v1
= index_buffer
[3*face
+ edge
];
906 DWORD v2
= index_buffer
[3*face
+ (edge
+1)%3];
907 DWORD new_v1
= point_reps
[v1
]; /* What v1 has been replaced with */
908 DWORD new_v2
= point_reps
[v2
];
910 if (v1
!= v2
) /* Only map non-collapsed edges */
913 edge_face_map
->entries
[i
].v2
= new_v2
;
914 edge_face_map
->entries
[i
].face
= face
;
915 list_add_head(&edge_face_map
->lists
[new_v1
], &edge_face_map
->entries
[i
].entry
);
923 static DWORD
find_adjacent_face(struct edge_face_map
*edge_face_map
, DWORD vertex1
, DWORD vertex2
, DWORD num_faces
)
925 struct edge_face
*edge_face_ptr
;
927 LIST_FOR_EACH_ENTRY(edge_face_ptr
, &edge_face_map
->lists
[vertex2
], struct edge_face
, entry
)
929 if (edge_face_ptr
->v2
== vertex1
)
930 return edge_face_ptr
->face
;
936 static DWORD
*generate_identity_point_reps(DWORD num_vertices
)
938 DWORD
*id_point_reps
;
941 id_point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*id_point_reps
));
945 for (i
= 0; i
< num_vertices
; i
++)
947 id_point_reps
[i
] = i
;
950 return id_point_reps
;
953 static HRESULT WINAPI
d3dx9_mesh_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
,
954 const DWORD
*point_reps
, DWORD
*adjacency
)
957 DWORD num_faces
= iface
->lpVtbl
->GetNumFaces(iface
);
958 DWORD num_vertices
= iface
->lpVtbl
->GetNumVertices(iface
);
959 DWORD options
= iface
->lpVtbl
->GetOptions(iface
);
960 BOOL indices_are_16_bit
= !(options
& D3DXMESH_32BIT
);
965 struct edge_face_map edge_face_map
= {0};
966 const DWORD
*point_reps_ptr
= NULL
;
967 DWORD
*id_point_reps
= NULL
;
969 TRACE("iface %p, point_reps %p, adjacency %p.\n", iface
, point_reps
, adjacency
);
971 if (!adjacency
) return D3DERR_INVALIDCALL
;
973 if (!point_reps
) /* Identity point reps */
975 id_point_reps
= generate_identity_point_reps(num_vertices
);
982 point_reps_ptr
= id_point_reps
;
986 point_reps_ptr
= point_reps
;
989 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &ib_ptr
);
990 if (FAILED(hr
)) goto cleanup
;
992 if (indices_are_16_bit
)
994 /* Widen 16 bit to 32 bit */
996 WORD
*ib_16bit
= ib_ptr
;
997 ib
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(DWORD
));
1003 for (i
= 0; i
< 3 * num_faces
; i
++)
1005 ib
[i
] = ib_16bit
[i
];
1013 hr
= init_edge_face_map(&edge_face_map
, ib
, point_reps_ptr
, num_faces
);
1014 if (FAILED(hr
)) goto cleanup
;
1016 /* Create adjacency */
1017 for (face
= 0; face
< num_faces
; face
++)
1019 for (edge
= 0; edge
< 3; edge
++)
1021 DWORD v1
= ib
[3*face
+ edge
];
1022 DWORD v2
= ib
[3*face
+ (edge
+1)%3];
1023 DWORD new_v1
= point_reps_ptr
[v1
];
1024 DWORD new_v2
= point_reps_ptr
[v2
];
1027 adj_face
= find_adjacent_face(&edge_face_map
, new_v1
, new_v2
, num_faces
);
1028 adjacency
[3*face
+ edge
] = adj_face
;
1034 HeapFree(GetProcessHeap(), 0, id_point_reps
);
1035 if (indices_are_16_bit
) HeapFree(GetProcessHeap(), 0, ib
);
1036 HeapFree(GetProcessHeap(), 0, edge_face_map
.lists
);
1037 HeapFree(GetProcessHeap(), 0, edge_face_map
.entries
);
1038 if(ib_ptr
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1042 /* ConvertAdjacencyToPointReps helper function.
1044 * Goes around the edges of each face and replaces the vertices in any adjacent
1045 * face's edge with its own vertices(if its vertices have a lower index). This
1046 * way as few as possible low index vertices are shared among the faces. The
1047 * re-ordered index buffer is stored in new_indices.
1049 * The vertices in a point representation must be ordered sequentially, e.g.
1050 * index 5 holds the index of the vertex that replaces vertex 5, i.e. if
1051 * vertex 5 is replaced by vertex 3 then index 5 would contain 3. If no vertex
1052 * replaces it, then it contains the same number as the index itself, e.g.
1053 * index 5 would contain 5. */
1054 static HRESULT
propagate_face_vertices(const DWORD
*adjacency
, DWORD
*point_reps
,
1055 const DWORD
*indices
, DWORD
*new_indices
, DWORD face
, DWORD numfaces
)
1057 const unsigned int VERTS_PER_FACE
= 3;
1058 DWORD edge
, opp_edge
;
1059 DWORD face_base
= VERTS_PER_FACE
* face
;
1061 for (edge
= 0; edge
< VERTS_PER_FACE
; edge
++)
1063 DWORD adj_face
= adjacency
[face_base
+ edge
];
1064 DWORD adj_face_base
;
1066 if (adj_face
== -1) /* No adjacent face. */
1068 else if (adj_face
>= numfaces
)
1070 /* This throws exception on Windows */
1071 WARN("Index out of bounds. Got %d expected less than %d.\n",
1072 adj_face
, numfaces
);
1073 return D3DERR_INVALIDCALL
;
1075 adj_face_base
= 3 * adj_face
;
1077 /* Find opposite edge in adjacent face. */
1078 for (opp_edge
= 0; opp_edge
< VERTS_PER_FACE
; opp_edge
++)
1080 DWORD opp_edge_index
= adj_face_base
+ opp_edge
;
1081 if (adjacency
[opp_edge_index
] == face
)
1082 break; /* Found opposite edge. */
1085 /* Replaces vertices in opposite edge with vertices from current edge. */
1086 for (i
= 0; i
< 2; i
++)
1088 DWORD from
= face_base
+ (edge
+ (1 - i
)) % VERTS_PER_FACE
;
1089 DWORD to
= adj_face_base
+ (opp_edge
+ i
) % VERTS_PER_FACE
;
1091 /* Propagate lowest index. */
1092 if (new_indices
[to
] > new_indices
[from
])
1094 new_indices
[to
] = new_indices
[from
];
1095 point_reps
[indices
[to
]] = new_indices
[from
];
1103 static HRESULT WINAPI
d3dx9_mesh_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
,
1104 const DWORD
*adjacency
, DWORD
*point_reps
)
1106 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1110 DWORD
*indices
= NULL
;
1111 WORD
*indices_16bit
= NULL
;
1112 DWORD
*new_indices
= NULL
;
1113 const unsigned int VERTS_PER_FACE
= 3;
1115 TRACE("iface %p, adjacency %p, point_reps %p.\n", iface
, adjacency
, point_reps
);
1119 WARN("NULL adjacency.\n");
1120 hr
= D3DERR_INVALIDCALL
;
1126 WARN("NULL point_reps.\n");
1127 hr
= D3DERR_INVALIDCALL
;
1131 /* Should never happen as CreateMesh does not allow meshes with 0 faces */
1132 if (This
->numfaces
== 0)
1134 ERR("Number of faces was zero.\n");
1135 hr
= D3DERR_INVALIDCALL
;
1139 new_indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1146 if (This
->options
& D3DXMESH_32BIT
)
1148 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1149 if (FAILED(hr
)) goto cleanup
;
1150 memcpy(new_indices
, indices
, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1154 /* Make a widening copy of indices_16bit into indices and new_indices
1155 * in order to re-use the helper function */
1156 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices_16bit
);
1157 if (FAILED(hr
)) goto cleanup
;
1158 indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1164 for (i
= 0; i
< VERTS_PER_FACE
* This
->numfaces
; i
++)
1166 new_indices
[i
] = indices_16bit
[i
];
1167 indices
[i
] = indices_16bit
[i
];
1171 /* Vertices are ordered sequentially in the point representation. */
1172 for (i
= 0; i
< This
->numvertices
; i
++)
1177 /* Propagate vertices with low indices so as few vertices as possible
1178 * are used in the mesh.
1180 for (face
= 0; face
< This
->numfaces
; face
++)
1182 hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
, face
, This
->numfaces
);
1183 if (FAILED(hr
)) goto cleanup
;
1185 /* Go in opposite direction to catch all face orderings */
1186 for (face
= 0; face
< This
->numfaces
; face
++)
1188 hr
= propagate_face_vertices(adjacency
, point_reps
,
1189 indices
, new_indices
,
1190 (This
->numfaces
- 1) - face
, This
->numfaces
);
1191 if (FAILED(hr
)) goto cleanup
;
1196 if (This
->options
& D3DXMESH_32BIT
)
1198 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1202 if (indices_16bit
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1203 HeapFree(GetProcessHeap(), 0, indices
);
1205 HeapFree(GetProcessHeap(), 0, new_indices
);
1209 struct vertex_metadata
{
1212 DWORD first_shared_index
;
1215 static int __cdecl
compare_vertex_keys(const void *a
, const void *b
)
1217 const struct vertex_metadata
*left
= a
;
1218 const struct vertex_metadata
*right
= b
;
1219 if (left
->key
== right
->key
)
1221 return left
->key
< right
->key
? -1 : 1;
1224 static HRESULT WINAPI
d3dx9_mesh_GenerateAdjacency(ID3DXMesh
*iface
, float epsilon
, DWORD
*adjacency
)
1226 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1228 BYTE
*vertices
= NULL
;
1229 const DWORD
*indices
= NULL
;
1232 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
1233 struct vertex_metadata
*sorted_vertices
;
1234 /* shared_indices links together identical indices in the index buffer so
1235 * that adjacency checks can be limited to faces sharing a vertex */
1236 DWORD
*shared_indices
= NULL
;
1237 const FLOAT epsilon_sq
= epsilon
* epsilon
;
1240 TRACE("iface %p, epsilon %.8e, adjacency %p.\n", iface
, epsilon
, adjacency
);
1243 return D3DERR_INVALIDCALL
;
1245 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
1246 if (!(This
->options
& D3DXMESH_32BIT
))
1247 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
1248 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
1249 if (!shared_indices
)
1250 return E_OUTOFMEMORY
;
1251 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
1253 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
1254 if (FAILED(hr
)) goto cleanup
;
1255 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1256 if (FAILED(hr
)) goto cleanup
;
1258 if (!(This
->options
& D3DXMESH_32BIT
)) {
1259 const WORD
*word_indices
= (const WORD
*)indices
;
1260 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
1261 indices
= dword_indices
;
1262 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1263 *dword_indices
++ = *word_indices
++;
1266 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1267 for (i
= 0; i
< This
->numvertices
; i
++) {
1268 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
1269 sorted_vertices
[i
].first_shared_index
= -1;
1270 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
1271 sorted_vertices
[i
].vertex_index
= i
;
1273 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
1274 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
1275 shared_indices
[i
] = *first_shared_index
;
1276 *first_shared_index
= i
;
1279 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
1281 for (i
= 0; i
< This
->numvertices
; i
++) {
1282 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
1283 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
1284 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
1286 while (shared_index_a
!= -1) {
1288 DWORD shared_index_b
= shared_indices
[shared_index_a
];
1289 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
1292 while (shared_index_b
!= -1) {
1293 /* faces are adjacent if they have another coincident vertex */
1294 DWORD base_a
= (shared_index_a
/ 3) * 3;
1295 DWORD base_b
= (shared_index_b
/ 3) * 3;
1296 BOOL adjacent
= FALSE
;
1299 for (k
= 0; k
< 3; k
++) {
1300 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
1306 for (k
= 1; k
<= 2; k
++) {
1307 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
1308 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
1309 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
1310 if (!adjacent
&& epsilon
>= 0.0f
) {
1311 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
1314 D3DXVec3Subtract(&delta
,
1315 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
1316 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
1317 length_sq
= D3DXVec3LengthSq(&delta
);
1318 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
1321 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
1322 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
1323 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
1324 adjacency
[adj_a
] = base_b
/ 3;
1325 adjacency
[adj_b
] = base_a
/ 3;
1332 shared_index_b
= shared_indices
[shared_index_b
];
1334 while (++j
< This
->numvertices
) {
1335 D3DXVECTOR3
*vertex_b
;
1338 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
1339 /* no more coincident vertices to try */
1340 j
= This
->numvertices
;
1343 /* check for coincidence */
1344 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
1345 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
1346 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
1347 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
1352 if (j
>= This
->numvertices
)
1354 shared_index_b
= sorted_vertex_b
->first_shared_index
;
1357 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
1358 shared_index_a
= sorted_vertex_a
->first_shared_index
;
1364 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1365 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
1366 HeapFree(GetProcessHeap(), 0, shared_indices
);
1370 static HRESULT WINAPI
d3dx9_mesh_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1372 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1374 UINT vertex_declaration_size
;
1377 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
1381 WARN("Invalid declaration. Can't use NULL declaration.\n");
1382 return D3DERR_INVALIDCALL
;
1385 /* New declaration must be same size as original */
1386 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
1387 if (vertex_declaration_size
!= This
->vertex_declaration_size
)
1389 WARN("Invalid declaration. New vertex size does not match the original vertex size.\n");
1390 return D3DERR_INVALIDCALL
;
1393 /* New declaration must not contain non-zero Stream value */
1394 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1396 if (declaration
[i
].Stream
!= 0)
1398 WARN("Invalid declaration. New declaration contains non-zero Stream value.\n");
1399 return D3DERR_INVALIDCALL
;
1403 This
->num_elem
= i
+ 1;
1404 copy_declaration(This
->cached_declaration
, declaration
, This
->num_elem
);
1406 if (This
->vertex_declaration
)
1407 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
1409 /* An application can pass an invalid declaration to UpdateSemantics and
1410 * still expect D3D_OK (see tests). If the declaration is invalid, then
1411 * subsequent calls to DrawSubset will fail. This is handled by setting the
1412 * vertex declaration to NULL.
1413 * GetDeclaration, GetNumBytesPerVertex must, however, use the new
1414 * invalid declaration. This is handled by them using the cached vertex
1415 * declaration instead of the actual vertex declaration.
1417 hr
= IDirect3DDevice9_CreateVertexDeclaration(This
->device
,
1419 &This
->vertex_declaration
);
1422 WARN("Using invalid declaration. Calls to DrawSubset will fail.\n");
1423 This
->vertex_declaration
= NULL
;
1429 static HRESULT WINAPI
d3dx9_mesh_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
1431 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1433 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
1435 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1437 if (!(flags
& D3DLOCK_READONLY
))
1439 D3DXATTRIBUTERANGE
*attrib_table
= mesh
->attrib_table
;
1440 mesh
->attrib_table_size
= 0;
1441 mesh
->attrib_table
= NULL
;
1442 HeapFree(GetProcessHeap(), 0, attrib_table
);
1445 *data
= mesh
->attrib_buffer
;
1450 static HRESULT WINAPI
d3dx9_mesh_UnlockAttributeBuffer(ID3DXMesh
*iface
)
1452 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1455 TRACE("iface %p.\n", iface
);
1457 lock_count
= InterlockedDecrement(&mesh
->attrib_buffer_lock_count
);
1460 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1461 return D3DERR_INVALIDCALL
;
1467 static HRESULT WINAPI
d3dx9_mesh_Optimize(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1468 DWORD
*adjacency_out
, DWORD
*face_remap
, ID3DXBuffer
**vertex_remap
, ID3DXMesh
**opt_mesh
)
1470 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1472 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
1473 ID3DXMesh
*optimized_mesh
;
1475 TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap %p, vertex_remap %p, opt_mesh %p.\n",
1476 iface
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
1479 return D3DERR_INVALIDCALL
;
1481 hr
= iface
->lpVtbl
->GetDeclaration(iface
, declaration
);
1482 if (FAILED(hr
)) return hr
;
1484 if (FAILED(hr
= iface
->lpVtbl
->CloneMesh(iface
, mesh
->options
, declaration
, mesh
->device
, &optimized_mesh
)))
1487 hr
= optimized_mesh
->lpVtbl
->OptimizeInplace(optimized_mesh
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
);
1489 *opt_mesh
= optimized_mesh
;
1491 IUnknown_Release(optimized_mesh
);
1495 /* Creates a vertex_remap that removes unused vertices.
1496 * Indices are updated according to the vertex_remap. */
1497 static HRESULT
compact_mesh(struct d3dx9_mesh
*This
, DWORD
*indices
,
1498 DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
1501 DWORD
*vertex_remap_ptr
;
1502 DWORD num_used_vertices
;
1505 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
1506 if (FAILED(hr
)) return hr
;
1507 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
1509 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1510 vertex_remap_ptr
[indices
[i
]] = 1;
1512 /* create old->new vertex mapping */
1513 num_used_vertices
= 0;
1514 for (i
= 0; i
< This
->numvertices
; i
++) {
1515 if (vertex_remap_ptr
[i
])
1516 vertex_remap_ptr
[i
] = num_used_vertices
++;
1518 vertex_remap_ptr
[i
] = -1;
1520 /* convert indices */
1521 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1522 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
1524 /* create new->old vertex mapping */
1525 num_used_vertices
= 0;
1526 for (i
= 0; i
< This
->numvertices
; i
++) {
1527 if (vertex_remap_ptr
[i
] != -1)
1528 vertex_remap_ptr
[num_used_vertices
++] = i
;
1530 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
1531 vertex_remap_ptr
[i
] = -1;
1533 *new_num_vertices
= num_used_vertices
;
1538 /* count the number of unique attribute values in a sorted attribute buffer */
1539 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
1541 DWORD last_attribute
= attrib_buffer
[0];
1542 DWORD attrib_table_size
= 1;
1544 for (i
= 1; i
< numfaces
; i
++) {
1545 if (attrib_buffer
[i
] != last_attribute
) {
1546 last_attribute
= attrib_buffer
[i
];
1547 attrib_table_size
++;
1550 return attrib_table_size
;
1553 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
1554 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
1556 DWORD attrib_table_size
= 0;
1557 DWORD last_attribute
= attrib_buffer
[0];
1558 DWORD min_vertex
, max_vertex
;
1561 attrib_table
[0].AttribId
= last_attribute
;
1562 attrib_table
[0].FaceStart
= 0;
1563 min_vertex
= (DWORD
)-1;
1565 for (i
= 0; i
< numfaces
; i
++) {
1568 if (attrib_buffer
[i
] != last_attribute
) {
1569 last_attribute
= attrib_buffer
[i
];
1570 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1571 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1572 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1573 attrib_table_size
++;
1574 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
1575 attrib_table
[attrib_table_size
].FaceStart
= i
;
1576 min_vertex
= (DWORD
)-1;
1579 for (j
= 0; j
< 3; j
++) {
1580 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
1581 if (vertex_index
< min_vertex
)
1582 min_vertex
= vertex_index
;
1583 if (vertex_index
> max_vertex
)
1584 max_vertex
= vertex_index
;
1587 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1588 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1589 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1590 attrib_table_size
++;
1593 static int __cdecl
attrib_entry_compare(const void *a
, const void *b
)
1595 const DWORD
*ptr_a
= *(const DWORD
**)a
;
1596 const DWORD
*ptr_b
= *(const DWORD
**)b
;
1597 int delta
= *ptr_a
- *ptr_b
;
1602 delta
= ptr_a
- ptr_b
; /* for stable sort */
1606 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
1607 static HRESULT
remap_faces_for_attrsort(struct d3dx9_mesh
*This
, const DWORD
*indices
,
1608 DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
1610 DWORD
**sorted_attrib_ptr_buffer
= NULL
;
1613 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
1614 if (!sorted_attrib_ptr_buffer
)
1615 return E_OUTOFMEMORY
;
1617 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
1620 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
1621 return E_OUTOFMEMORY
;
1624 for (i
= 0; i
< This
->numfaces
; i
++)
1625 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
1626 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
), attrib_entry_compare
);
1628 for (i
= 0; i
< This
->numfaces
; i
++)
1630 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
1631 (*face_remap
)[old_face
] = i
;
1634 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
1635 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
1636 for (i
= 0; i
< This
->numfaces
; i
++)
1637 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
1642 static HRESULT WINAPI
d3dx9_mesh_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1643 DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
1645 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1646 void *indices
= NULL
;
1647 DWORD
*attrib_buffer
= NULL
;
1649 ID3DXBuffer
*vertex_remap
= NULL
;
1650 DWORD
*face_remap
= NULL
; /* old -> new mapping */
1651 DWORD
*dword_indices
= NULL
;
1652 DWORD new_num_vertices
= 0;
1653 DWORD new_num_alloc_vertices
= 0;
1654 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
1655 DWORD
*sorted_attrib_buffer
= NULL
;
1658 TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
1659 iface
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
1662 return D3DERR_INVALIDCALL
;
1663 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
1664 return D3DERR_INVALIDCALL
;
1665 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1666 return D3DERR_INVALIDCALL
;
1668 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1670 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
1671 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
1672 if (flags
& D3DXMESHOPT_STRIPREORDER
)
1673 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
1677 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, &indices
);
1678 if (FAILED(hr
)) goto cleanup
;
1680 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
1681 if (!dword_indices
) return E_OUTOFMEMORY
;
1682 if (This
->options
& D3DXMESH_32BIT
) {
1683 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1685 WORD
*word_indices
= indices
;
1686 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1687 dword_indices
[i
] = *word_indices
++;
1690 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
1692 new_num_alloc_vertices
= This
->numvertices
;
1693 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
1694 if (FAILED(hr
)) goto cleanup
;
1695 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
1696 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
1697 FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
1699 hr
= iface
->lpVtbl
->LockAttributeBuffer(iface
, 0, &attrib_buffer
);
1700 if (FAILED(hr
)) goto cleanup
;
1702 hr
= remap_faces_for_attrsort(This
, dword_indices
, attrib_buffer
, &sorted_attrib_buffer
, &face_remap
);
1703 if (FAILED(hr
)) goto cleanup
;
1708 /* reorder the vertices using vertex_remap */
1709 D3DVERTEXBUFFER_DESC vertex_desc
;
1710 DWORD
*vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1711 DWORD vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1712 BYTE
*orig_vertices
;
1715 hr
= IDirect3DVertexBuffer9_GetDesc(This
->vertex_buffer
, &vertex_desc
);
1716 if (FAILED(hr
)) goto cleanup
;
1718 hr
= IDirect3DDevice9_CreateVertexBuffer(This
->device
, new_num_alloc_vertices
* vertex_size
,
1719 vertex_desc
.Usage
, This
->fvf
, vertex_desc
.Pool
, &vertex_buffer
, NULL
);
1720 if (FAILED(hr
)) goto cleanup
;
1722 hr
= IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, (void**)&orig_vertices
, D3DLOCK_READONLY
);
1723 if (FAILED(hr
)) goto cleanup
;
1725 hr
= IDirect3DVertexBuffer9_Lock(vertex_buffer
, 0, 0, (void**)&new_vertices
, 0);
1727 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1731 for (i
= 0; i
< new_num_vertices
; i
++)
1732 memcpy(new_vertices
+ i
* vertex_size
, orig_vertices
+ vertex_remap_ptr
[i
] * vertex_size
, vertex_size
);
1734 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1735 IDirect3DVertexBuffer9_Unlock(vertex_buffer
);
1736 } else if (vertex_remap_out
) {
1737 DWORD
*vertex_remap_ptr
;
1739 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), &vertex_remap
);
1740 if (FAILED(hr
)) goto cleanup
;
1741 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1742 for (i
= 0; i
< This
->numvertices
; i
++)
1743 *vertex_remap_ptr
++ = i
;
1746 if (flags
& D3DXMESHOPT_ATTRSORT
)
1748 D3DXATTRIBUTERANGE
*attrib_table
;
1749 DWORD attrib_table_size
;
1751 attrib_table_size
= count_attributes(sorted_attrib_buffer
, This
->numfaces
);
1752 attrib_table
= HeapAlloc(GetProcessHeap(), 0, attrib_table_size
* sizeof(*attrib_table
));
1753 if (!attrib_table
) {
1758 memcpy(attrib_buffer
, sorted_attrib_buffer
, This
->numfaces
* sizeof(*attrib_buffer
));
1760 /* reorder the indices using face_remap */
1761 if (This
->options
& D3DXMESH_32BIT
) {
1762 for (i
= 0; i
< This
->numfaces
; i
++)
1763 memcpy((DWORD
*)indices
+ face_remap
[i
] * 3, dword_indices
+ i
* 3, 3 * sizeof(DWORD
));
1765 WORD
*word_indices
= indices
;
1766 for (i
= 0; i
< This
->numfaces
; i
++) {
1767 DWORD new_pos
= face_remap
[i
] * 3;
1768 DWORD old_pos
= i
* 3;
1769 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1770 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1771 word_indices
[new_pos
] = dword_indices
[old_pos
];
1775 fill_attribute_table(attrib_buffer
, This
->numfaces
, indices
,
1776 This
->options
& D3DXMESH_32BIT
, attrib_table
);
1778 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1779 This
->attrib_table
= attrib_table
;
1780 This
->attrib_table_size
= attrib_table_size
;
1782 if (This
->options
& D3DXMESH_32BIT
) {
1783 memcpy(indices
, dword_indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1785 WORD
*word_indices
= indices
;
1786 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1787 *word_indices
++ = dword_indices
[i
];
1791 if (adjacency_out
) {
1793 for (i
= 0; i
< This
->numfaces
; i
++) {
1794 DWORD old_pos
= i
* 3;
1795 DWORD new_pos
= face_remap
[i
] * 3;
1796 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1797 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1798 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1801 memcpy(adjacency_out
, adjacency_in
, This
->numfaces
* 3 * sizeof(*adjacency_out
));
1804 if (face_remap_out
) {
1806 for (i
= 0; i
< This
->numfaces
; i
++)
1807 face_remap_out
[face_remap
[i
]] = i
;
1809 for (i
= 0; i
< This
->numfaces
; i
++)
1810 face_remap_out
[i
] = i
;
1813 if (vertex_remap_out
)
1814 *vertex_remap_out
= vertex_remap
;
1815 vertex_remap
= NULL
;
1817 if (vertex_buffer
) {
1818 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
1819 This
->vertex_buffer
= vertex_buffer
;
1820 vertex_buffer
= NULL
;
1821 This
->numvertices
= new_num_vertices
;
1826 HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer
);
1827 HeapFree(GetProcessHeap(), 0, face_remap
);
1828 HeapFree(GetProcessHeap(), 0, dword_indices
);
1829 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
1830 if (vertex_buffer
) IDirect3DVertexBuffer9_Release(vertex_buffer
);
1831 if (attrib_buffer
) iface
->lpVtbl
->UnlockAttributeBuffer(iface
);
1832 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1836 static HRESULT WINAPI
d3dx9_mesh_SetAttributeTable(ID3DXMesh
*iface
,
1837 const D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
1839 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1840 D3DXATTRIBUTERANGE
*new_table
= NULL
;
1842 TRACE("iface %p, attrib_table %p, attrib_table_size %u.\n", iface
, attrib_table
, attrib_table_size
);
1844 if (attrib_table_size
) {
1845 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
1847 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
1849 return E_OUTOFMEMORY
;
1851 CopyMemory(new_table
, attrib_table
, size
);
1852 } else if (attrib_table
) {
1853 return D3DERR_INVALIDCALL
;
1855 HeapFree(GetProcessHeap(), 0, mesh
->attrib_table
);
1856 mesh
->attrib_table
= new_table
;
1857 mesh
->attrib_table_size
= attrib_table_size
;
1862 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
1864 d3dx9_mesh_QueryInterface
,
1867 d3dx9_mesh_DrawSubset
,
1868 d3dx9_mesh_GetNumFaces
,
1869 d3dx9_mesh_GetNumVertices
,
1871 d3dx9_mesh_GetDeclaration
,
1872 d3dx9_mesh_GetNumBytesPerVertex
,
1873 d3dx9_mesh_GetOptions
,
1874 d3dx9_mesh_GetDevice
,
1875 d3dx9_mesh_CloneMeshFVF
,
1876 d3dx9_mesh_CloneMesh
,
1877 d3dx9_mesh_GetVertexBuffer
,
1878 d3dx9_mesh_GetIndexBuffer
,
1879 d3dx9_mesh_LockVertexBuffer
,
1880 d3dx9_mesh_UnlockVertexBuffer
,
1881 d3dx9_mesh_LockIndexBuffer
,
1882 d3dx9_mesh_UnlockIndexBuffer
,
1883 d3dx9_mesh_GetAttributeTable
,
1884 d3dx9_mesh_ConvertPointRepsToAdjacency
,
1885 d3dx9_mesh_ConvertAdjacencyToPointReps
,
1886 d3dx9_mesh_GenerateAdjacency
,
1887 d3dx9_mesh_UpdateSemantics
,
1888 d3dx9_mesh_LockAttributeBuffer
,
1889 d3dx9_mesh_UnlockAttributeBuffer
,
1890 d3dx9_mesh_Optimize
,
1891 d3dx9_mesh_OptimizeInplace
,
1892 d3dx9_mesh_SetAttributeTable
,
1896 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algorithm
1897 Amy Williams University of Utah
1898 Steve Barrus University of Utah
1899 R. Keith Morley University of Utah
1900 Peter Shirley University of Utah
1902 International Conference on Computer Graphics and Interactive Techniques archive
1903 ACM SIGGRAPH 2005 Courses
1904 Los Angeles, California
1906 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1908 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1909 against each slab, if there's anything left of the ray after we're
1910 done we've got an intersection of the ray with the box. */
1911 BOOL WINAPI
D3DXBoxBoundProbe(const D3DXVECTOR3
*pmin
, const D3DXVECTOR3
*pmax
,
1912 const D3DXVECTOR3
*prayposition
, const D3DXVECTOR3
*praydirection
)
1914 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
1916 div
= 1.0f
/ praydirection
->x
;
1919 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
1920 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
1924 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
1925 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
1928 if ( tmax
< 0.0f
) return FALSE
;
1930 div
= 1.0f
/ praydirection
->y
;
1933 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
1934 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
1938 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
1939 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
1942 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
1944 if ( tymin
> tmin
) tmin
= tymin
;
1945 if ( tymax
< tmax
) tmax
= tymax
;
1947 div
= 1.0f
/ praydirection
->z
;
1950 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
1951 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
1955 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
1956 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
1959 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
1964 HRESULT WINAPI
D3DXComputeBoundingBox(const D3DXVECTOR3
*pfirstposition
,
1965 DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
1970 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
1972 *pmin
= *pfirstposition
;
1975 for(i
=0; i
<numvertices
; i
++)
1977 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
1979 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
1980 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
1982 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
1983 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
1985 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
1986 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
1992 HRESULT WINAPI
D3DXComputeBoundingSphere(const D3DXVECTOR3
*pfirstposition
,
1993 DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, float *pradius
)
1999 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
2006 for(i
=0; i
<numvertices
; i
++)
2007 D3DXVec3Add(&temp
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
2009 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/ numvertices
);
2011 for(i
=0; i
<numvertices
; i
++)
2013 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
2014 if ( d
> *pradius
) *pradius
= d
;
2019 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
2020 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
2022 declaration
[*idx
].Stream
= 0;
2023 declaration
[*idx
].Offset
= *offset
;
2024 declaration
[*idx
].Type
= type
;
2025 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
2026 declaration
[*idx
].Usage
= usage
;
2027 declaration
[*idx
].UsageIndex
= usage_idx
;
2029 *offset
+= d3dx_decltype_size
[type
];
2033 /*************************************************************************
2034 * D3DXDeclaratorFromFVF
2036 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
2038 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
2039 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2040 unsigned int offset
= 0;
2041 unsigned int idx
= 0;
2044 TRACE("fvf %#x, declaration %p.\n", fvf
, declaration
);
2046 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
2048 if (fvf
& D3DFVF_POSITION_MASK
)
2050 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
2051 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
2052 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
2054 if (has_blend_idx
) --blend_count
;
2056 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
2057 || (has_blend
&& blend_count
> 4))
2058 return D3DERR_INVALIDCALL
;
2060 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
2061 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
2063 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
2067 switch (blend_count
)
2072 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2075 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2078 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2081 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2084 ERR("Invalid blend count %u.\n", blend_count
);
2090 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
2091 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
2092 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
2093 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
2098 if (fvf
& D3DFVF_NORMAL
)
2099 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
2100 if (fvf
& D3DFVF_PSIZE
)
2101 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
2102 if (fvf
& D3DFVF_DIFFUSE
)
2103 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
2104 if (fvf
& D3DFVF_SPECULAR
)
2105 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
2107 for (i
= 0; i
< tex_count
; ++i
)
2109 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
2111 case D3DFVF_TEXTUREFORMAT1
:
2112 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
2114 case D3DFVF_TEXTUREFORMAT2
:
2115 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
2117 case D3DFVF_TEXTUREFORMAT3
:
2118 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
2120 case D3DFVF_TEXTUREFORMAT4
:
2121 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
2126 declaration
[idx
] = end_element
;
2131 /*************************************************************************
2132 * D3DXFVFFromDeclarator
2134 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
2136 unsigned int i
= 0, texture
, offset
;
2138 TRACE("(%p, %p)\n", declaration
, fvf
);
2141 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
2143 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2144 declaration
[1].UsageIndex
== 0) &&
2145 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
2146 declaration
[2].UsageIndex
== 0))
2148 return D3DERR_INVALIDCALL
;
2150 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2151 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
2153 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
2155 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
2159 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
2163 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2164 declaration
[1].UsageIndex
== 0)
2166 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2167 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
2169 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
2171 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
2175 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
2177 switch (declaration
[1].Type
)
2179 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
2180 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
2181 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
2182 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
2188 switch (declaration
[1].Type
)
2190 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
2191 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
2192 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
2193 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
2204 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
2205 declaration
[0].UsageIndex
== 0)
2207 *fvf
|= D3DFVF_XYZRHW
;
2211 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
2213 *fvf
|= D3DFVF_NORMAL
;
2216 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
2217 declaration
[i
].UsageIndex
== 0)
2219 *fvf
|= D3DFVF_PSIZE
;
2222 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2223 declaration
[i
].UsageIndex
== 0)
2225 *fvf
|= D3DFVF_DIFFUSE
;
2228 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2229 declaration
[i
].UsageIndex
== 1)
2231 *fvf
|= D3DFVF_SPECULAR
;
2235 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
2237 if (declaration
[i
].Stream
== 0xFF)
2241 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2242 declaration
[i
].UsageIndex
== texture
)
2244 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
2246 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2247 declaration
[i
].UsageIndex
== texture
)
2249 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
2251 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2252 declaration
[i
].UsageIndex
== texture
)
2254 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
2256 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2257 declaration
[i
].UsageIndex
== texture
)
2259 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
2263 return D3DERR_INVALIDCALL
;
2267 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
2269 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
2270 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
2272 if (declaration
[i
].Offset
!= offset
)
2274 return D3DERR_INVALIDCALL
;
2281 /*************************************************************************
2282 * D3DXGetFVFVertexSize
2284 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
2286 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
2289 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
2293 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2295 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
2296 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
2297 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
2298 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
2300 switch (FVF
& D3DFVF_POSITION_MASK
)
2302 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
2303 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
2304 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
2305 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
2306 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
2307 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
2308 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
2309 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
2312 for (i
= 0; i
< numTextures
; i
++)
2314 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
2320 /*************************************************************************
2321 * D3DXGetDeclVertexSize
2323 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
2325 const D3DVERTEXELEMENT9
*element
;
2328 TRACE("decl %p, stream_idx %u\n", decl
, stream_idx
);
2330 if (!decl
) return 0;
2332 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
2336 if (element
->Stream
!= stream_idx
) continue;
2338 if (element
->Type
>= ARRAY_SIZE(d3dx_decltype_size
))
2340 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
2344 type_size
= d3dx_decltype_size
[element
->Type
];
2345 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
2351 /*************************************************************************
2354 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
2356 const D3DVERTEXELEMENT9
*element
;
2358 TRACE("decl %p\n", decl
);
2360 /* null decl results in exception on Windows XP */
2362 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
2364 return element
- decl
;
2367 BOOL WINAPI
D3DXIntersectTri(const D3DXVECTOR3
*p0
, const D3DXVECTOR3
*p1
, const D3DXVECTOR3
*p2
,
2368 const D3DXVECTOR3
*praypos
, const D3DXVECTOR3
*praydir
, float *pu
, float *pv
, float *pdist
)
2373 TRACE("p0 %p, p1 %p, p2 %p, praypos %p, praydir %p, pu %p, pv %p, pdist %p.\n",
2374 p0
, p1
, p2
, praypos
, praydir
, pu
, pv
, pdist
);
2376 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
2377 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
2378 m
.u
.m
[2][0] = -praydir
->x
;
2380 m
.u
.m
[0][1] = p1
->y
- p0
->y
;
2381 m
.u
.m
[1][1] = p2
->y
- p0
->y
;
2382 m
.u
.m
[2][1] = -praydir
->y
;
2384 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
2385 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
2386 m
.u
.m
[2][2] = -praydir
->z
;
2393 vec
.x
= praypos
->x
- p0
->x
;
2394 vec
.y
= praypos
->y
- p0
->y
;
2395 vec
.z
= praypos
->z
- p0
->z
;
2398 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
2400 D3DXVec4Transform(&vec
, &vec
, &m
);
2401 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
2403 if (pu
) *pu
= vec
.x
;
2404 if (pv
) *pv
= vec
.y
;
2405 if (pdist
) *pdist
= fabsf( vec
.z
);
2413 BOOL WINAPI
D3DXSphereBoundProbe(const D3DXVECTOR3
*center
, float radius
,
2414 const D3DXVECTOR3
*ray_position
, const D3DXVECTOR3
*ray_direction
)
2416 D3DXVECTOR3 difference
= {0};
2419 D3DXVec3Subtract(&difference
, ray_position
, center
);
2420 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
2423 a
= D3DXVec3LengthSq(ray_direction
);
2424 b
= D3DXVec3Dot(&difference
, ray_direction
);
2427 return d
>= 0.0f
&& (b
<= 0.0f
|| d
> b
* b
);
2430 /*************************************************************************
2433 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2434 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2438 IDirect3DVertexDeclaration9
*vertex_declaration
;
2439 UINT vertex_declaration_size
;
2441 IDirect3DVertexBuffer9
*vertex_buffer
;
2442 IDirect3DIndexBuffer9
*index_buffer
;
2443 DWORD
*attrib_buffer
;
2444 struct d3dx9_mesh
*object
;
2445 DWORD index_usage
= 0;
2446 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
2447 D3DFORMAT index_format
= D3DFMT_INDEX16
;
2448 DWORD vertex_usage
= 0;
2449 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
2452 TRACE("numfaces %u, numvertices %u, options %#x, declaration %p, device %p, mesh %p.\n",
2453 numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2455 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
2456 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
2457 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
2459 return D3DERR_INVALIDCALL
;
2461 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
2462 if (declaration
[i
].Stream
!= 0)
2463 return D3DERR_INVALIDCALL
;
2466 if (options
& D3DXMESH_32BIT
)
2467 index_format
= D3DFMT_INDEX32
;
2469 if (options
& D3DXMESH_DONOTCLIP
) {
2470 index_usage
|= D3DUSAGE_DONOTCLIP
;
2471 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
2473 if (options
& D3DXMESH_POINTS
) {
2474 index_usage
|= D3DUSAGE_POINTS
;
2475 vertex_usage
|= D3DUSAGE_POINTS
;
2477 if (options
& D3DXMESH_RTPATCHES
) {
2478 index_usage
|= D3DUSAGE_RTPATCHES
;
2479 vertex_usage
|= D3DUSAGE_RTPATCHES
;
2481 if (options
& D3DXMESH_NPATCHES
) {
2482 index_usage
|= D3DUSAGE_NPATCHES
;
2483 vertex_usage
|= D3DUSAGE_NPATCHES
;
2486 if (options
& D3DXMESH_VB_SYSTEMMEM
)
2487 vertex_pool
= D3DPOOL_SYSTEMMEM
;
2488 else if (options
& D3DXMESH_VB_MANAGED
)
2489 vertex_pool
= D3DPOOL_MANAGED
;
2491 if (options
& D3DXMESH_VB_WRITEONLY
)
2492 vertex_usage
|= D3DUSAGE_WRITEONLY
;
2493 if (options
& D3DXMESH_VB_DYNAMIC
)
2494 vertex_usage
|= D3DUSAGE_DYNAMIC
;
2495 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
2496 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2498 if (options
& D3DXMESH_IB_SYSTEMMEM
)
2499 index_pool
= D3DPOOL_SYSTEMMEM
;
2500 else if (options
& D3DXMESH_IB_MANAGED
)
2501 index_pool
= D3DPOOL_MANAGED
;
2503 if (options
& D3DXMESH_IB_WRITEONLY
)
2504 index_usage
|= D3DUSAGE_WRITEONLY
;
2505 if (options
& D3DXMESH_IB_DYNAMIC
)
2506 index_usage
|= D3DUSAGE_DYNAMIC
;
2507 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
2508 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2510 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
2516 /* Create vertex declaration */
2517 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
2519 &vertex_declaration
);
2522 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
2525 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
2527 /* Create vertex buffer */
2528 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
2529 numvertices
* vertex_declaration_size
,
2537 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2538 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2542 /* Create index buffer */
2543 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
2544 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
2552 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2553 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2554 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2558 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
2559 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2560 if (object
== NULL
|| attrib_buffer
== NULL
)
2562 HeapFree(GetProcessHeap(), 0, object
);
2563 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
2564 IDirect3DIndexBuffer9_Release(index_buffer
);
2565 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2566 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2568 return E_OUTOFMEMORY
;
2570 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
2573 object
->numfaces
= numfaces
;
2574 object
->numvertices
= numvertices
;
2575 object
->options
= options
;
2577 object
->device
= device
;
2578 IDirect3DDevice9_AddRef(device
);
2580 copy_declaration(object
->cached_declaration
, declaration
, num_elem
);
2581 object
->vertex_declaration
= vertex_declaration
;
2582 object
->vertex_declaration_size
= vertex_declaration_size
;
2583 object
->num_elem
= num_elem
;
2584 object
->vertex_buffer
= vertex_buffer
;
2585 object
->index_buffer
= index_buffer
;
2586 object
->attrib_buffer
= attrib_buffer
;
2588 *mesh
= &object
->ID3DXMesh_iface
;
2593 /*************************************************************************
2596 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2597 DWORD fvf
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2600 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
2602 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
2604 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
2605 if (FAILED(hr
)) return hr
;
2607 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2613 DWORD num_poly_faces
;
2614 DWORD num_tri_faces
;
2615 D3DXVECTOR3
*vertices
;
2616 DWORD
*num_tri_per_face
;
2621 /* optional mesh data */
2624 D3DXVECTOR3
*normals
;
2625 DWORD
*normal_indices
;
2627 D3DXVECTOR2
*tex_coords
;
2629 DWORD
*vertex_colors
;
2631 DWORD num_materials
;
2632 D3DXMATERIAL
*materials
;
2633 DWORD
*material_indices
;
2635 struct ID3DXSkinInfo
*skin_info
;
2639 static HRESULT
parse_texture_filename(ID3DXFileData
*filedata
, char **filename_out
)
2645 char *filename
= NULL
;
2647 /* template TextureFilename {
2652 HeapFree(GetProcessHeap(), 0, *filename_out
);
2653 *filename_out
= NULL
;
2655 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2656 if (FAILED(hr
)) return hr
;
2658 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
2659 if (data_size
< sizeof(filename_in
))
2661 WARN("truncated data (%lu bytes)\n", data_size
);
2662 filedata
->lpVtbl
->Unlock(filedata
);
2665 filename_in
= *(char **)data
;
2667 filename
= HeapAlloc(GetProcessHeap(), 0, strlen(filename_in
) + 1);
2669 filedata
->lpVtbl
->Unlock(filedata
);
2670 return E_OUTOFMEMORY
;
2673 strcpy(filename
, filename_in
);
2674 *filename_out
= filename
;
2676 filedata
->lpVtbl
->Unlock(filedata
);
2681 static HRESULT
parse_material(ID3DXFileData
*filedata
, D3DXMATERIAL
*material
)
2687 ID3DXFileData
*child
;
2688 SIZE_T i
, nb_children
;
2690 material
->pTextureFilename
= NULL
;
2692 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2693 if (FAILED(hr
)) return hr
;
2696 * template ColorRGBA {
2702 * template ColorRGB {
2707 * template Material {
2708 * ColorRGBA faceColor;
2710 * ColorRGB specularColor;
2711 * ColorRGB emissiveColor;
2715 if (data_size
!= sizeof(FLOAT
) * 11) {
2716 WARN("incorrect data size (%ld bytes)\n", data_size
);
2717 filedata
->lpVtbl
->Unlock(filedata
);
2721 memcpy(&material
->MatD3D
.Diffuse
, data
, sizeof(D3DCOLORVALUE
));
2722 data
+= sizeof(D3DCOLORVALUE
);
2723 material
->MatD3D
.Power
= *(FLOAT
*)data
;
2724 data
+= sizeof(FLOAT
);
2725 memcpy(&material
->MatD3D
.Specular
, data
, sizeof(FLOAT
) * 3);
2726 material
->MatD3D
.Specular
.a
= 1.0f
;
2727 data
+= 3 * sizeof(FLOAT
);
2728 memcpy(&material
->MatD3D
.Emissive
, data
, sizeof(FLOAT
) * 3);
2729 material
->MatD3D
.Emissive
.a
= 1.0f
;
2730 material
->MatD3D
.Ambient
.r
= 0.0f
;
2731 material
->MatD3D
.Ambient
.g
= 0.0f
;
2732 material
->MatD3D
.Ambient
.b
= 0.0f
;
2733 material
->MatD3D
.Ambient
.a
= 1.0f
;
2735 filedata
->lpVtbl
->Unlock(filedata
);
2737 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2741 for (i
= 0; i
< nb_children
; i
++)
2743 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2746 hr
= child
->lpVtbl
->GetType(child
, &type
);
2750 if (IsEqualGUID(&type
, &TID_D3DRMTextureFilename
)) {
2751 hr
= parse_texture_filename(child
, &material
->pTextureFilename
);
2755 IUnknown_Release(child
);
2760 IUnknown_Release(child
);
2764 static void destroy_materials(struct mesh_data
*mesh
)
2767 for (i
= 0; i
< mesh
->num_materials
; i
++)
2768 HeapFree(GetProcessHeap(), 0, mesh
->materials
[i
].pTextureFilename
);
2769 HeapFree(GetProcessHeap(), 0, mesh
->materials
);
2770 HeapFree(GetProcessHeap(), 0, mesh
->material_indices
);
2771 mesh
->num_materials
= 0;
2772 mesh
->materials
= NULL
;
2773 mesh
->material_indices
= NULL
;
2776 static HRESULT
parse_material_list(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2780 const DWORD
*data
, *in_ptr
;
2782 ID3DXFileData
*child
= NULL
;
2783 DWORD num_materials
;
2787 destroy_materials(mesh
);
2789 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2790 if (FAILED(hr
)) return hr
;
2792 /* template MeshMaterialList {
2794 * DWORD nFaceIndexes;
2795 * array DWORD faceIndexes[nFaceIndexes];
2803 if (data_size
< sizeof(DWORD
)) {
2804 WARN("truncated data (%ld bytes)\n", data_size
);
2807 num_materials
= *in_ptr
++;
2808 if (!num_materials
) {
2813 if (data_size
< 2 * sizeof(DWORD
)) {
2814 WARN("truncated data (%ld bytes)\n", data_size
);
2817 if (*in_ptr
++ != mesh
->num_poly_faces
) {
2818 WARN("number of material face indices (%u) doesn't match number of faces (%u)\n",
2819 *(in_ptr
- 1), mesh
->num_poly_faces
);
2822 if (data_size
< 2 * sizeof(DWORD
) + mesh
->num_poly_faces
* sizeof(DWORD
)) {
2823 WARN("truncated data (%ld bytes)\n", data_size
);
2826 for (i
= 0; i
< mesh
->num_poly_faces
; i
++) {
2827 if (*in_ptr
++ >= num_materials
) {
2828 WARN("face %u: reference to undefined material %u (only %u materials)\n",
2829 i
, *(in_ptr
- 1), num_materials
);
2834 mesh
->materials
= HeapAlloc(GetProcessHeap(), 0, num_materials
* sizeof(*mesh
->materials
));
2835 mesh
->material_indices
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_poly_faces
* sizeof(*mesh
->material_indices
));
2836 if (!mesh
->materials
|| !mesh
->material_indices
) {
2840 memcpy(mesh
->material_indices
, data
+ 2, mesh
->num_poly_faces
* sizeof(DWORD
));
2842 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2846 for (i
= 0; i
< nb_children
; i
++)
2848 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2851 hr
= child
->lpVtbl
->GetType(child
, &type
);
2855 if (IsEqualGUID(&type
, &TID_D3DRMMaterial
)) {
2856 if (mesh
->num_materials
>= num_materials
) {
2857 WARN("more materials defined than declared\n");
2861 hr
= parse_material(child
, &mesh
->materials
[mesh
->num_materials
++]);
2866 IUnknown_Release(child
);
2869 if (num_materials
!= mesh
->num_materials
) {
2870 WARN("only %u of %u materials defined\n", num_materials
, mesh
->num_materials
);
2876 IUnknown_Release(child
);
2877 filedata
->lpVtbl
->Unlock(filedata
);
2881 static HRESULT
parse_texture_coords(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2887 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2888 mesh
->tex_coords
= NULL
;
2890 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2891 if (FAILED(hr
)) return hr
;
2893 /* template Coords2d {
2897 * template MeshTextureCoords {
2898 * DWORD nTextureCoords;
2899 * array Coords2d textureCoords[nTextureCoords];
2905 if (data_size
< sizeof(DWORD
)) {
2906 WARN("truncated data (%ld bytes)\n", data_size
);
2909 if (*(DWORD
*)data
!= mesh
->num_vertices
) {
2910 WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2911 *(DWORD
*)data
, mesh
->num_vertices
);
2914 data
+= sizeof(DWORD
);
2915 if (data_size
< sizeof(DWORD
) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
)) {
2916 WARN("truncated data (%ld bytes)\n", data_size
);
2920 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2921 if (!mesh
->tex_coords
) {
2925 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2927 mesh
->fvf
|= D3DFVF_TEX1
;
2932 filedata
->lpVtbl
->Unlock(filedata
);
2936 static HRESULT
parse_vertex_colors(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2944 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2945 mesh
->vertex_colors
= NULL
;
2947 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2948 if (FAILED(hr
)) return hr
;
2950 /* template IndexedColor {
2952 * ColorRGBA indexColor;
2954 * template MeshVertexColors {
2955 * DWORD nVertexColors;
2956 * array IndexedColor vertexColors[nVertexColors];
2962 if (data_size
< sizeof(DWORD
)) {
2963 WARN("truncated data (%ld bytes)\n", data_size
);
2966 num_colors
= *(DWORD
*)data
;
2967 data
+= sizeof(DWORD
);
2968 if (data_size
< sizeof(DWORD
) + num_colors
* (sizeof(DWORD
) + sizeof(D3DCOLORVALUE
))) {
2969 WARN("truncated data (%ld bytes)\n", data_size
);
2973 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(DWORD
));
2974 if (!mesh
->vertex_colors
) {
2979 for (i
= 0; i
< mesh
->num_vertices
; i
++)
2980 mesh
->vertex_colors
[i
] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2981 for (i
= 0; i
< num_colors
; i
++)
2983 D3DCOLORVALUE color
;
2984 DWORD index
= *(DWORD
*)data
;
2985 data
+= sizeof(DWORD
);
2986 if (index
>= mesh
->num_vertices
) {
2987 WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2988 i
, index
, mesh
->num_vertices
);
2991 memcpy(&color
, data
, sizeof(color
));
2992 data
+= sizeof(color
);
2993 color
.r
= min(1.0f
, max(0.0f
, color
.r
));
2994 color
.g
= min(1.0f
, max(0.0f
, color
.g
));
2995 color
.b
= min(1.0f
, max(0.0f
, color
.b
));
2996 color
.a
= min(1.0f
, max(0.0f
, color
.a
));
2997 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
2998 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
2999 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
3000 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
3003 mesh
->fvf
|= D3DFVF_DIFFUSE
;
3008 filedata
->lpVtbl
->Unlock(filedata
);
3012 static HRESULT
parse_normals(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
3017 DWORD
*index_out_ptr
;
3019 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
3021 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
3022 mesh
->num_normals
= 0;
3023 mesh
->normals
= NULL
;
3024 mesh
->normal_indices
= NULL
;
3025 mesh
->fvf
|= D3DFVF_NORMAL
;
3027 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3028 if (FAILED(hr
)) return hr
;
3030 /* template Vector {
3035 * template MeshFace {
3036 * DWORD nFaceVertexIndices;
3037 * array DWORD faceVertexIndices[nFaceVertexIndices];
3039 * template MeshNormals {
3041 * array Vector normals[nNormals];
3042 * DWORD nFaceNormals;
3043 * array MeshFace faceNormals[nFaceNormals];
3049 if (data_size
< sizeof(DWORD
) * 2) {
3050 WARN("truncated data (%ld bytes)\n", data_size
);
3053 mesh
->num_normals
= *(DWORD
*)data
;
3054 data
+= sizeof(DWORD
);
3055 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
3056 num_face_indices
* sizeof(DWORD
)) {
3057 WARN("truncated data (%ld bytes)\n", data_size
);
3061 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3062 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
3063 if (!mesh
->normals
|| !mesh
->normal_indices
) {
3068 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3069 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
3070 for (i
= 0; i
< mesh
->num_normals
; i
++)
3071 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
3073 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
3074 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
3075 *(DWORD
*)data
, mesh
->num_poly_faces
);
3078 data
+= sizeof(DWORD
);
3079 index_out_ptr
= mesh
->normal_indices
;
3080 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
3083 DWORD count
= *(DWORD
*)data
;
3084 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
3085 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
3086 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
3089 data
+= sizeof(DWORD
);
3091 for (j
= 0; j
< count
; j
++) {
3092 DWORD normal_index
= *(DWORD
*)data
;
3093 if (normal_index
>= mesh
->num_normals
) {
3094 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
3095 i
, j
, normal_index
, mesh
->num_normals
);
3098 *index_out_ptr
++ = normal_index
;
3099 data
+= sizeof(DWORD
);
3106 filedata
->lpVtbl
->Unlock(filedata
);
3110 static HRESULT
parse_skin_mesh_info(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD index
)
3116 TRACE("(%p, %p, %u)\n", filedata
, mesh_data
, index
);
3118 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3119 if (FAILED(hr
)) return hr
;
3123 if (!mesh_data
->skin_info
) {
3124 if (data_size
< sizeof(WORD
) * 3) {
3125 WARN("truncated data (%ld bytes)\n", data_size
);
3128 /* Skip nMaxSkinWeightsPerVertex and nMaxSkinWeightsPerFace */
3129 data
+= 2 * sizeof(WORD
);
3130 mesh_data
->nb_bones
= *(WORD
*)data
;
3131 hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
, mesh_data
->nb_bones
, &mesh_data
->skin_info
);
3134 DWORD nb_influences
;
3136 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
3137 name
= *(const char**)data
;
3138 data
+= sizeof(char*);
3140 nb_influences
= *(DWORD
*)data
;
3141 data
+= sizeof(DWORD
);
3143 if (data_size
< (sizeof(char*) + sizeof(DWORD
) + nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
)) + 16 * sizeof(FLOAT
))) {
3144 WARN("truncated data (%ld bytes)\n", data_size
);
3148 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneName(mesh_data
->skin_info
, index
, name
);
3150 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneInfluence(mesh_data
->skin_info
, index
, nb_influences
,
3151 (const DWORD
*)data
, (const FLOAT
*)(data
+ nb_influences
* sizeof(DWORD
)));
3153 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneOffsetMatrix(mesh_data
->skin_info
, index
,
3154 (const D3DMATRIX
*)(data
+ nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
))));
3158 filedata
->lpVtbl
->Unlock(filedata
);
3162 /* for provide_flags parameters */
3163 #define PROVIDE_MATERIALS 0x1
3164 #define PROVIDE_SKININFO 0x2
3165 #define PROVIDE_ADJACENCY 0x4
3167 static HRESULT
parse_mesh(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
3171 const BYTE
*data
, *in_ptr
;
3172 DWORD
*index_out_ptr
;
3174 ID3DXFileData
*child
= NULL
;
3177 DWORD nb_skin_weights_info
= 0;
3182 * array Vector vertices[nVertices];
3184 * array MeshFace faces[nFaces];
3189 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3190 if (FAILED(hr
)) return hr
;
3195 if (data_size
< sizeof(DWORD
) * 2) {
3196 WARN("truncated data (%ld bytes)\n", data_size
);
3199 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
3200 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
)) {
3201 WARN("truncated data (%ld bytes)\n", data_size
);
3204 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
3206 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
3207 in_ptr
+= sizeof(DWORD
);
3209 mesh_data
->num_tri_faces
= 0;
3210 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3212 DWORD num_poly_vertices
;
3215 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
)) {
3216 WARN("truncated data (%ld bytes)\n", data_size
);
3219 num_poly_vertices
= *(DWORD
*)in_ptr
;
3220 in_ptr
+= sizeof(DWORD
);
3221 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
)) {
3222 WARN("truncated data (%ld bytes)\n", data_size
);
3225 if (num_poly_vertices
< 3) {
3226 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
3229 for (j
= 0; j
< num_poly_vertices
; j
++) {
3230 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
3231 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
3232 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
3235 in_ptr
+= sizeof(DWORD
);
3237 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
3240 mesh_data
->fvf
= D3DFVF_XYZ
;
3242 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
3243 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
3244 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
3245 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
3246 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
3247 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
3248 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
) {
3253 in_ptr
= data
+ sizeof(DWORD
);
3254 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
3255 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
3257 index_out_ptr
= mesh_data
->indices
;
3258 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3262 count
= *(DWORD
*)in_ptr
;
3263 in_ptr
+= sizeof(DWORD
);
3264 mesh_data
->num_tri_per_face
[i
] = count
- 2;
3267 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
3268 in_ptr
+= sizeof(DWORD
);
3272 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3276 for (i
= 0; i
< nb_children
; i
++)
3278 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3281 hr
= child
->lpVtbl
->GetType(child
, &type
);
3285 if (IsEqualGUID(&type
, &TID_D3DRMMeshNormals
)) {
3286 hr
= parse_normals(child
, mesh_data
);
3287 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshVertexColors
)) {
3288 hr
= parse_vertex_colors(child
, mesh_data
);
3289 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshTextureCoords
)) {
3290 hr
= parse_texture_coords(child
, mesh_data
);
3291 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshMaterialList
) &&
3292 (provide_flags
& PROVIDE_MATERIALS
))
3294 hr
= parse_material_list(child
, mesh_data
);
3295 } else if (provide_flags
& PROVIDE_SKININFO
) {
3296 if (IsEqualGUID(&type
, &DXFILEOBJ_XSkinMeshHeader
)) {
3297 if (mesh_data
->skin_info
) {
3298 WARN("Skin mesh header already encountered\n");
3302 hr
= parse_skin_mesh_info(child
, mesh_data
, 0);
3305 } else if (IsEqualGUID(&type
, &DXFILEOBJ_SkinWeights
)) {
3306 if (!mesh_data
->skin_info
) {
3307 WARN("Skin weights found but skin mesh header not encountered yet\n");
3311 hr
= parse_skin_mesh_info(child
, mesh_data
, nb_skin_weights_info
);
3314 nb_skin_weights_info
++;
3320 IUnknown_Release(child
);
3324 if (mesh_data
->skin_info
&& (nb_skin_weights_info
!= mesh_data
->nb_bones
)) {
3325 WARN("Mismatch between nb skin weights info %u encountered and nb bones %u from skin mesh header\n",
3326 nb_skin_weights_info
, mesh_data
->nb_bones
);
3331 if ((provide_flags
& PROVIDE_SKININFO
) && !mesh_data
->skin_info
)
3333 if (FAILED(hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
,
3334 mesh_data
->nb_bones
, &mesh_data
->skin_info
)))
3342 IUnknown_Release(child
);
3343 filedata
->lpVtbl
->Unlock(filedata
);
3347 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
3348 ID3DXBuffer
**effects
)
3351 D3DXEFFECTINSTANCE
*effect_ptr
;
3353 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3354 static const struct {
3355 const char *param_name
;
3359 } material_effects
[] = {
3360 #define EFFECT_TABLE_ENTRY(str, field) \
3361 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
3362 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
3363 EFFECT_TABLE_ENTRY("Power", Power
),
3364 EFFECT_TABLE_ENTRY("Specular", Specular
),
3365 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
3366 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
3367 #undef EFFECT_TABLE_ENTRY
3369 static const char texture_paramname
[] = "Texture0@Name";
3373 /* effects buffer layout:
3375 * D3DXEFFECTINSTANCE effects[num_materials];
3376 * for (effect in effects)
3378 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
3379 * for (default in defaults)
3381 * *default.pParamName;
3386 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
3387 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
3388 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
3389 buffer_size
+= material_effects
[i
].name_size
;
3390 buffer_size
+= material_effects
[i
].num_bytes
;
3392 buffer_size
*= num_materials
;
3393 for (i
= 0; i
< num_materials
; i
++) {
3394 if (material_ptr
[i
].pTextureFilename
) {
3395 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
3396 buffer_size
+= sizeof(texture_paramname
);
3397 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
3401 hr
= D3DXCreateBuffer(buffer_size
, effects
);
3402 if (FAILED(hr
)) return hr
;
3403 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
3404 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
3406 for (i
= 0; i
< num_materials
; i
++)
3409 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
3411 effect_ptr
->pDefaults
= defaults
;
3412 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
3413 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
3415 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
3417 defaults
->pParamName
= (char *)out_ptr
;
3418 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
3419 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
3420 defaults
->Type
= D3DXEDT_FLOATS
;
3421 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
3422 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
3423 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3427 if (material_ptr
->pTextureFilename
)
3429 defaults
->pParamName
= (char *)out_ptr
;
3430 strcpy(defaults
->pParamName
, texture_paramname
);
3431 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
3432 defaults
->Type
= D3DXEDT_STRING
;
3433 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
3434 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
3435 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3440 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
3445 HRESULT WINAPI
D3DXLoadSkinMeshFromXof(struct ID3DXFileData
*filedata
, DWORD options
,
3446 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
3447 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXSkinInfo
**skin_info_out
,
3448 struct ID3DXMesh
**mesh_out
)
3451 DWORD
*index_in_ptr
;
3452 struct mesh_data mesh_data
;
3453 DWORD total_vertices
;
3454 ID3DXMesh
*d3dxmesh
= NULL
;
3455 ID3DXBuffer
*adjacency
= NULL
;
3456 ID3DXBuffer
*materials
= NULL
;
3457 ID3DXBuffer
*effects
= NULL
;
3458 struct vertex_duplication
{
3461 } *duplications
= NULL
;
3463 void *vertices
= NULL
;
3464 void *indices
= NULL
;
3466 DWORD provide_flags
= 0;
3468 TRACE("(%p, %x, %p, %p, %p, %p, %p, %p, %p)\n", filedata
, options
, device
, adjacency_out
, materials_out
,
3469 effects_out
, num_materials_out
, skin_info_out
, mesh_out
);
3471 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
3473 if (num_materials_out
|| materials_out
|| effects_out
)
3474 provide_flags
|= PROVIDE_MATERIALS
;
3476 provide_flags
|= PROVIDE_SKININFO
;
3478 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
3479 if (FAILED(hr
)) goto cleanup
;
3481 total_vertices
= mesh_data
.num_vertices
;
3482 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3483 /* duplicate vertices with multiple normals */
3484 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
3485 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
3486 if (!duplications
) {
3490 for (i
= 0; i
< total_vertices
; i
++)
3492 duplications
[i
].normal_index
= -1;
3493 list_init(&duplications
[i
].entry
);
3495 for (i
= 0; i
< num_face_indices
; i
++) {
3496 DWORD vertex_index
= mesh_data
.indices
[i
];
3497 DWORD normal_index
= mesh_data
.normal_indices
[i
];
3498 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
3500 if (dup_ptr
->normal_index
== -1) {
3501 dup_ptr
->normal_index
= normal_index
;
3503 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
3504 struct list
*dup_list
= &dup_ptr
->entry
;
3506 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
3507 if (new_normal
->x
== cur_normal
->x
&&
3508 new_normal
->y
== cur_normal
->y
&&
3509 new_normal
->z
== cur_normal
->z
)
3511 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3513 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
3514 dup_ptr
= &duplications
[total_vertices
++];
3515 dup_ptr
->normal_index
= normal_index
;
3516 list_add_tail(dup_list
, &dup_ptr
->entry
);
3517 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3520 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
3521 struct vertex_duplication
, entry
);
3528 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
3529 if (FAILED(hr
)) goto cleanup
;
3531 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, 0, &vertices
);
3532 if (FAILED(hr
)) goto cleanup
;
3535 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3536 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
3537 out_ptr
+= sizeof(D3DXVECTOR3
);
3538 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3539 if (duplications
[i
].normal_index
== -1)
3540 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
3542 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
3543 out_ptr
+= sizeof(D3DXVECTOR3
);
3545 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
3546 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
3547 out_ptr
+= sizeof(DWORD
);
3549 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
3550 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
3551 out_ptr
+= sizeof(D3DXVECTOR2
);
3554 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3555 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
3557 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3558 struct vertex_duplication
*dup_ptr
;
3559 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
3561 int j
= dup_ptr
- duplications
;
3562 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
3564 memcpy(dest_vertex
, out_ptr
, vertex_size
);
3565 dest_vertex
+= sizeof(D3DXVECTOR3
);
3566 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
3568 out_ptr
+= vertex_size
;
3571 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
3573 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, 0, &indices
);
3574 if (FAILED(hr
)) goto cleanup
;
3576 index_in_ptr
= mesh_data
.indices
;
3577 #define FILL_INDEX_BUFFER(indices_var) \
3578 for (i = 0; i < mesh_data.num_poly_faces; i++) \
3580 DWORD count = mesh_data.num_tri_per_face[i]; \
3581 WORD first_index = *index_in_ptr++; \
3583 *indices_var++ = first_index; \
3584 *indices_var++ = *index_in_ptr; \
3586 *indices_var++ = *index_in_ptr; \
3590 if (options
& D3DXMESH_32BIT
) {
3591 DWORD
*dword_indices
= indices
;
3592 FILL_INDEX_BUFFER(dword_indices
)
3594 WORD
*word_indices
= indices
;
3595 FILL_INDEX_BUFFER(word_indices
)
3597 #undef FILL_INDEX_BUFFER
3598 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
3600 if (mesh_data
.material_indices
) {
3601 DWORD
*attrib_buffer
= NULL
;
3602 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, 0, &attrib_buffer
);
3603 if (FAILED(hr
)) goto cleanup
;
3604 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
3606 DWORD count
= mesh_data
.num_tri_per_face
[i
];
3608 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
3610 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
3612 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
3613 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
3614 NULL
, NULL
, NULL
, NULL
);
3615 if (FAILED(hr
)) goto cleanup
;
3618 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
3619 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
3620 char *strings_out_ptr
;
3621 D3DXMATERIAL
*materials_ptr
;
3623 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3624 if (mesh_data
.materials
[i
].pTextureFilename
)
3625 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3628 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3629 if (FAILED(hr
)) goto cleanup
;
3631 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3632 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
3633 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
3634 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3635 if (materials_ptr
[i
].pTextureFilename
) {
3636 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
3637 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
3638 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3643 if (mesh_data
.num_materials
&& effects_out
) {
3644 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
3645 if (FAILED(hr
)) goto cleanup
;
3647 if (!materials_out
) {
3648 ID3DXBuffer_Release(materials
);
3653 if (adjacency_out
) {
3654 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
3655 if (FAILED(hr
)) goto cleanup
;
3656 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
3657 if (FAILED(hr
)) goto cleanup
;
3660 *mesh_out
= d3dxmesh
;
3661 if (adjacency_out
) *adjacency_out
= adjacency
;
3662 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
3663 if (materials_out
) *materials_out
= materials
;
3664 if (effects_out
) *effects_out
= effects
;
3665 if (skin_info_out
) *skin_info_out
= mesh_data
.skin_info
;
3670 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
3671 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3672 if (materials
) ID3DXBuffer_Release(materials
);
3673 if (effects
) ID3DXBuffer_Release(effects
);
3674 if (mesh_data
.skin_info
) mesh_data
.skin_info
->lpVtbl
->Release(mesh_data
.skin_info
);
3675 if (skin_info_out
) *skin_info_out
= NULL
;
3677 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
3678 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
3679 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
3680 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
3681 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
3682 destroy_materials(&mesh_data
);
3683 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
3684 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
3685 HeapFree(GetProcessHeap(), 0, duplications
);
3689 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3690 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3691 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3697 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3698 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3699 debugstr_a(filename
), options
, device
, alloc_hier
,
3700 load_user_data
, frame_hierarchy
, anim_controller
);
3703 return D3DERR_INVALIDCALL
;
3705 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3706 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3707 if (!filenameW
) return E_OUTOFMEMORY
;
3708 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3710 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
3711 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3712 HeapFree(GetProcessHeap(), 0, filenameW
);
3717 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3718 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3719 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3725 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3726 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3727 debugstr_w(filename
), options
, device
, alloc_hier
,
3728 load_user_data
, frame_hierarchy
, anim_controller
);
3731 return D3DERR_INVALIDCALL
;
3733 hr
= map_view_of_file(filename
, &buffer
, &size
);
3735 return D3DXERR_INVALIDDATA
;
3737 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
3738 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3740 UnmapViewOfFile(buffer
);
3745 static HRESULT
filedata_get_name(ID3DXFileData
*filedata
, char **name
)
3750 hr
= filedata
->lpVtbl
->GetName(filedata
, NULL
, &name_len
);
3751 if (FAILED(hr
)) return hr
;
3755 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
3756 if (!*name
) return E_OUTOFMEMORY
;
3758 hr
= filedata
->lpVtbl
->GetName(filedata
, *name
, &name_len
);
3760 HeapFree(GetProcessHeap(), 0, *name
);
3767 static HRESULT
load_mesh_container(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3768 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXMESHCONTAINER
**mesh_container
)
3771 ID3DXBuffer
*adjacency
= NULL
;
3772 ID3DXBuffer
*materials
= NULL
;
3773 ID3DXBuffer
*effects
= NULL
;
3774 ID3DXSkinInfo
*skin_info
= NULL
;
3775 D3DXMESHDATA mesh_data
;
3776 DWORD num_materials
= 0;
3779 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
3780 mesh_data
.u
.pMesh
= NULL
;
3782 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
3783 &adjacency
, &materials
, &effects
, &num_materials
,
3784 &skin_info
, &mesh_data
.u
.pMesh
);
3785 if (FAILED(hr
)) return hr
;
3787 hr
= filedata_get_name(filedata
, &name
);
3788 if (FAILED(hr
)) goto cleanup
;
3790 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
3791 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
3792 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
3794 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
3795 skin_info
, mesh_container
);
3798 if (materials
) ID3DXBuffer_Release(materials
);
3799 if (effects
) ID3DXBuffer_Release(effects
);
3800 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3801 if (skin_info
) IUnknown_Release(skin_info
);
3802 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
3803 HeapFree(GetProcessHeap(), 0, name
);
3807 static HRESULT
parse_transform_matrix(ID3DXFileData
*filedata
, D3DXMATRIX
*transform
)
3813 /* template Matrix4x4 {
3814 * array FLOAT matrix[16];
3816 * template FrameTransformMatrix {
3817 * Matrix4x4 frameMatrix;
3821 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3822 if (FAILED(hr
)) return hr
;
3824 if (data_size
!= sizeof(D3DXMATRIX
)) {
3825 WARN("incorrect data size (%ld bytes)\n", data_size
);
3826 filedata
->lpVtbl
->Unlock(filedata
);
3830 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
3832 filedata
->lpVtbl
->Unlock(filedata
);
3836 static HRESULT
load_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3837 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXFRAME
**frame_out
)
3841 ID3DXFileData
*child
;
3843 D3DXFRAME
*frame
= NULL
;
3844 D3DXMESHCONTAINER
**next_container
;
3845 D3DXFRAME
**next_child
;
3846 SIZE_T i
, nb_children
;
3848 hr
= filedata_get_name(filedata
, &name
);
3849 if (FAILED(hr
)) return hr
;
3851 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
3852 HeapFree(GetProcessHeap(), 0, name
);
3853 if (FAILED(hr
)) return E_FAIL
;
3856 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
3857 next_child
= &frame
->pFrameFirstChild
;
3858 next_container
= &frame
->pMeshContainer
;
3860 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3864 for (i
= 0; i
< nb_children
; i
++)
3866 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3869 hr
= child
->lpVtbl
->GetType(child
, &type
);
3873 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
3874 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
3876 next_container
= &(*next_container
)->pNextMeshContainer
;
3877 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
3878 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
3879 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
3880 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
3882 next_child
= &(*next_child
)->pFrameSibling
;
3887 IUnknown_Release(child
);
3892 IUnknown_Release(child
);
3896 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
3897 struct IDirect3DDevice9
*device
, struct ID3DXAllocateHierarchy
*alloc_hier
,
3898 struct ID3DXLoadUserData
*load_user_data
, D3DXFRAME
**frame_hierarchy
,
3899 struct ID3DXAnimationController
**anim_controller
)
3902 ID3DXFile
*d3dxfile
= NULL
;
3903 ID3DXFileEnumObject
*enumobj
= NULL
;
3904 ID3DXFileData
*filedata
= NULL
;
3905 D3DXF_FILELOADMEMORY source
;
3906 D3DXFRAME
*first_frame
= NULL
;
3907 D3DXFRAME
**next_frame
= &first_frame
;
3908 SIZE_T i
, nb_children
;
3911 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3912 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3914 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
3915 return D3DERR_INVALIDCALL
;
3918 FIXME("Loading user data not implemented.\n");
3922 hr
= D3DXFileCreate(&d3dxfile
);
3923 if (FAILED(hr
)) goto cleanup
;
3925 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3926 if (FAILED(hr
)) goto cleanup
;
3928 source
.lpMemory
= (void*)memory
;
3929 source
.dSize
= memory_size
;
3930 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
3931 if (FAILED(hr
)) goto cleanup
;
3933 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
3937 for (i
= 0; i
< nb_children
; i
++)
3939 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
3943 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
3944 if (SUCCEEDED(hr
)) {
3945 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
3946 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
3952 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
3954 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
3955 if (FAILED(hr
)) goto cleanup
;
3956 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
3957 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
3958 if (FAILED(hr
)) goto cleanup
;
3961 next_frame
= &(*next_frame
)->pFrameSibling
;
3964 filedata
->lpVtbl
->Release(filedata
);
3972 } else if (first_frame
->pFrameSibling
) {
3973 D3DXFRAME
*root_frame
= NULL
;
3974 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
3979 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
3980 root_frame
->pFrameFirstChild
= first_frame
;
3981 *frame_hierarchy
= root_frame
;
3984 *frame_hierarchy
= first_frame
;
3988 if (anim_controller
)
3990 *anim_controller
= NULL
;
3991 FIXME("Animation controller creation not implemented.\n");
3995 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
3996 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
3997 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
3998 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4002 HRESULT WINAPI
D3DXCleanMesh(D3DXCLEANTYPE clean_type
, ID3DXMesh
*mesh_in
, const DWORD
*adjacency_in
,
4003 ID3DXMesh
**mesh_out
, DWORD
*adjacency_out
, ID3DXBuffer
**errors_and_warnings
)
4005 FIXME("(%u, %p, %p, %p, %p, %p)\n", clean_type
, mesh_in
, adjacency_in
, mesh_out
, adjacency_out
, errors_and_warnings
);
4010 HRESULT WINAPI
D3DXFrameDestroy(D3DXFRAME
*frame
, ID3DXAllocateHierarchy
*alloc_hier
)
4015 TRACE("(%p, %p)\n", frame
, alloc_hier
);
4017 if (!frame
|| !alloc_hier
)
4018 return D3DERR_INVALIDCALL
;
4021 D3DXMESHCONTAINER
*container
;
4022 D3DXFRAME
*current_frame
;
4024 if (frame
->pFrameSibling
) {
4025 current_frame
= frame
->pFrameSibling
;
4026 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
4027 current_frame
->pFrameSibling
= NULL
;
4029 current_frame
= frame
;
4033 if (current_frame
->pFrameFirstChild
) {
4034 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
4035 if (FAILED(hr
)) return hr
;
4036 current_frame
->pFrameFirstChild
= NULL
;
4039 container
= current_frame
->pMeshContainer
;
4041 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
4042 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
4043 if (FAILED(hr
)) return hr
;
4044 container
= next_container
;
4046 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
4047 if (FAILED(hr
)) return hr
;
4052 HRESULT WINAPI
D3DXLoadMeshFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4053 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4054 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4060 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4061 "effect_instances %p, num_materials %p, mesh %p.\n",
4062 debugstr_a(filename
), options
, device
, adjacency
, materials
,
4063 effect_instances
, num_materials
, mesh
);
4066 return D3DERR_INVALIDCALL
;
4068 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
4069 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4070 if (!filenameW
) return E_OUTOFMEMORY
;
4071 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
4073 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
4074 effect_instances
, num_materials
, mesh
);
4075 HeapFree(GetProcessHeap(), 0, filenameW
);
4080 HRESULT WINAPI
D3DXLoadMeshFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4081 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4082 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4088 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4089 "effect_instances %p, num_materials %p, mesh %p.\n",
4090 debugstr_w(filename
), options
, device
, adjacency
, materials
,
4091 effect_instances
, num_materials
, mesh
);
4094 return D3DERR_INVALIDCALL
;
4096 hr
= map_view_of_file(filename
, &buffer
, &size
);
4098 return D3DXERR_INVALIDDATA
;
4100 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4101 materials
, effect_instances
, num_materials
, mesh
);
4103 UnmapViewOfFile(buffer
);
4108 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
, const char *name
, const char *type
, DWORD options
,
4109 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
,
4110 struct ID3DXBuffer
**effect_instances
, DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4117 TRACE("module %p, name %s, type %s, options %#x, device %p, adjacency %p, "
4118 "materials %p, effect_instances %p, num_materials %p, mesh %p.\n",
4119 module
, debugstr_a(name
), debugstr_a(type
), options
, device
, adjacency
,
4120 materials
, effect_instances
, num_materials
, mesh
);
4122 resinfo
= FindResourceA(module
, name
, type
);
4123 if (!resinfo
) return D3DXERR_INVALIDDATA
;
4125 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
4126 if (FAILED(hr
)) return D3DXERR_INVALIDDATA
;
4128 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4129 materials
, effect_instances
, num_materials
, mesh
);
4132 struct mesh_container
4136 ID3DXBuffer
*adjacency
;
4137 ID3DXBuffer
*materials
;
4138 ID3DXBuffer
*effects
;
4139 DWORD num_materials
;
4140 D3DXMATRIX transform
;
4143 static HRESULT
parse_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
4144 const D3DXMATRIX
*parent_transform
, struct list
*container_list
, DWORD provide_flags
)
4147 D3DXMATRIX transform
= *parent_transform
;
4148 ID3DXFileData
*child
;
4150 SIZE_T i
, nb_children
;
4152 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
4156 for (i
= 0; i
< nb_children
; i
++)
4158 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
4161 hr
= child
->lpVtbl
->GetType(child
, &type
);
4165 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
4166 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
4172 list_add_tail(container_list
, &container
->entry
);
4173 container
->transform
= transform
;
4175 hr
= D3DXLoadSkinMeshFromXof(child
, options
, device
,
4176 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
4177 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
4178 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
4179 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
4180 D3DXMATRIX new_transform
;
4181 hr
= parse_transform_matrix(child
, &new_transform
);
4182 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
4183 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
4184 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
4189 IUnknown_Release(child
);
4194 IUnknown_Release(child
);
4198 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
4199 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
4200 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXMesh
**mesh_out
)
4203 ID3DXFile
*d3dxfile
= NULL
;
4204 ID3DXFileEnumObject
*enumobj
= NULL
;
4205 ID3DXFileData
*filedata
= NULL
;
4206 D3DXF_FILELOADMEMORY source
;
4207 ID3DXBuffer
*materials
= NULL
;
4208 ID3DXBuffer
*effects
= NULL
;
4209 ID3DXBuffer
*adjacency
= NULL
;
4210 struct list container_list
= LIST_INIT(container_list
);
4211 struct mesh_container
*container_ptr
, *next_container_ptr
;
4212 DWORD num_materials
;
4213 DWORD num_faces
, num_vertices
;
4214 D3DXMATRIX identity
;
4215 DWORD provide_flags
= 0;
4217 ID3DXMesh
*concat_mesh
= NULL
;
4218 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
4219 BYTE
*concat_vertices
= NULL
;
4220 void *concat_indices
= NULL
;
4222 DWORD concat_vertex_size
;
4223 SIZE_T i
, nb_children
;
4226 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
4227 device
, adjacency_out
, materials_out
, effects_out
, num_materials_out
, mesh_out
);
4229 if (!memory
|| !memory_size
|| !device
|| !mesh_out
)
4230 return D3DERR_INVALIDCALL
;
4232 hr
= D3DXFileCreate(&d3dxfile
);
4233 if (FAILED(hr
)) goto cleanup
;
4235 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
4236 if (FAILED(hr
)) goto cleanup
;
4238 source
.lpMemory
= (void*)memory
;
4239 source
.dSize
= memory_size
;
4240 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
4241 if (FAILED(hr
)) goto cleanup
;
4243 D3DXMatrixIdentity(&identity
);
4244 if (adjacency_out
) provide_flags
|= PROVIDE_ADJACENCY
;
4245 if (materials_out
|| effects_out
) provide_flags
|= PROVIDE_MATERIALS
;
4247 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
4251 for (i
= 0; i
< nb_children
; i
++)
4253 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
4257 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
4258 if (SUCCEEDED(hr
)) {
4259 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
4260 container_ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container_ptr
));
4261 if (!container_ptr
) {
4265 list_add_tail(&container_list
, &container_ptr
->entry
);
4266 D3DXMatrixIdentity(&container_ptr
->transform
);
4268 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
4269 (provide_flags
& PROVIDE_ADJACENCY
) ? &container_ptr
->adjacency
: NULL
,
4270 (provide_flags
& PROVIDE_MATERIALS
) ? &container_ptr
->materials
: NULL
,
4271 NULL
, &container_ptr
->num_materials
, NULL
, &container_ptr
->mesh
);
4272 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
4273 hr
= parse_frame(filedata
, options
, device
, &identity
, &container_list
, provide_flags
);
4275 if (FAILED(hr
)) goto cleanup
;
4277 filedata
->lpVtbl
->Release(filedata
);
4283 enumobj
->lpVtbl
->Release(enumobj
);
4285 d3dxfile
->lpVtbl
->Release(d3dxfile
);
4288 if (list_empty(&container_list
)) {
4297 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4299 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4300 fvf
|= mesh
->lpVtbl
->GetFVF(mesh
);
4301 num_faces
+= mesh
->lpVtbl
->GetNumFaces(mesh
);
4302 num_vertices
+= mesh
->lpVtbl
->GetNumVertices(mesh
);
4303 num_materials
+= container_ptr
->num_materials
;
4306 hr
= D3DXCreateMeshFVF(num_faces
, num_vertices
, options
, fvf
, device
, &concat_mesh
);
4307 if (FAILED(hr
)) goto cleanup
;
4309 hr
= concat_mesh
->lpVtbl
->GetDeclaration(concat_mesh
, concat_decl
);
4310 if (FAILED(hr
)) goto cleanup
;
4312 concat_vertex_size
= D3DXGetDeclVertexSize(concat_decl
, 0);
4314 hr
= concat_mesh
->lpVtbl
->LockVertexBuffer(concat_mesh
, 0, (void**)&concat_vertices
);
4315 if (FAILED(hr
)) goto cleanup
;
4317 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4319 D3DVERTEXELEMENT9 mesh_decl
[MAX_FVF_DECL_SIZE
];
4320 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4321 DWORD num_mesh_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
4322 DWORD mesh_vertex_size
;
4323 const BYTE
*mesh_vertices
;
4326 hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, mesh_decl
);
4327 if (FAILED(hr
)) goto cleanup
;
4329 mesh_vertex_size
= D3DXGetDeclVertexSize(mesh_decl
, 0);
4331 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_vertices
);
4332 if (FAILED(hr
)) goto cleanup
;
4334 for (i
= 0; i
< num_mesh_vertices
; i
++) {
4338 D3DXVec3TransformCoord((D3DXVECTOR3
*)concat_vertices
,
4339 (D3DXVECTOR3
*)mesh_vertices
,
4340 &container_ptr
->transform
);
4341 for (j
= 1; concat_decl
[j
].Stream
!= 0xff; j
++)
4343 if (concat_decl
[j
].Usage
== mesh_decl
[k
].Usage
&&
4344 concat_decl
[j
].UsageIndex
== mesh_decl
[k
].UsageIndex
)
4346 if (concat_decl
[j
].Usage
== D3DDECLUSAGE_NORMAL
) {
4347 D3DXVec3TransformCoord((D3DXVECTOR3
*)(concat_vertices
+ concat_decl
[j
].Offset
),
4348 (D3DXVECTOR3
*)(mesh_vertices
+ mesh_decl
[k
].Offset
),
4349 &container_ptr
->transform
);
4351 memcpy(concat_vertices
+ concat_decl
[j
].Offset
,
4352 mesh_vertices
+ mesh_decl
[k
].Offset
,
4353 d3dx_decltype_size
[mesh_decl
[k
].Type
]);
4358 mesh_vertices
+= mesh_vertex_size
;
4359 concat_vertices
+= concat_vertex_size
;
4362 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
4365 concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4366 concat_vertices
= NULL
;
4368 hr
= concat_mesh
->lpVtbl
->LockIndexBuffer(concat_mesh
, 0, &concat_indices
);
4369 if (FAILED(hr
)) goto cleanup
;
4372 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4374 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4375 const void *mesh_indices
;
4376 DWORD num_mesh_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4379 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_indices
);
4380 if (FAILED(hr
)) goto cleanup
;
4382 if (options
& D3DXMESH_32BIT
) {
4383 DWORD
*dest
= concat_indices
;
4384 const DWORD
*src
= mesh_indices
;
4385 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4386 *dest
++ = index_offset
+ *src
++;
4387 concat_indices
= dest
;
4389 WORD
*dest
= concat_indices
;
4390 const WORD
*src
= mesh_indices
;
4391 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4392 *dest
++ = index_offset
+ *src
++;
4393 concat_indices
= dest
;
4395 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
4397 index_offset
+= num_mesh_faces
* 3;
4400 concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4401 concat_indices
= NULL
;
4403 if (num_materials
) {
4404 DWORD
*concat_attrib_buffer
= NULL
;
4407 hr
= concat_mesh
->lpVtbl
->LockAttributeBuffer(concat_mesh
, 0, &concat_attrib_buffer
);
4408 if (FAILED(hr
)) goto cleanup
;
4410 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4412 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4413 const DWORD
*mesh_attrib_buffer
= NULL
;
4414 DWORD count
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4416 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, D3DLOCK_READONLY
, (DWORD
**)&mesh_attrib_buffer
);
4418 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4423 *concat_attrib_buffer
++ = offset
+ *mesh_attrib_buffer
++;
4425 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
4426 offset
+= container_ptr
->num_materials
;
4428 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4431 if (materials_out
|| effects_out
) {
4432 D3DXMATERIAL
*out_ptr
;
4433 if (!num_materials
) {
4434 /* create default material */
4435 hr
= D3DXCreateBuffer(sizeof(D3DXMATERIAL
), &materials
);
4436 if (FAILED(hr
)) goto cleanup
;
4438 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4439 out_ptr
->MatD3D
.Diffuse
.r
= 0.5f
;
4440 out_ptr
->MatD3D
.Diffuse
.g
= 0.5f
;
4441 out_ptr
->MatD3D
.Diffuse
.b
= 0.5f
;
4442 out_ptr
->MatD3D
.Specular
.r
= 0.5f
;
4443 out_ptr
->MatD3D
.Specular
.g
= 0.5f
;
4444 out_ptr
->MatD3D
.Specular
.b
= 0.5f
;
4445 /* D3DXCreateBuffer initializes the rest to zero */
4447 DWORD buffer_size
= num_materials
* sizeof(D3DXMATERIAL
);
4448 char *strings_out_ptr
;
4450 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4452 if (container_ptr
->materials
) {
4454 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4455 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4457 if (in_ptr
->pTextureFilename
)
4458 buffer_size
+= strlen(in_ptr
->pTextureFilename
) + 1;
4464 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
4465 if (FAILED(hr
)) goto cleanup
;
4466 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4467 strings_out_ptr
= (char*)(out_ptr
+ num_materials
);
4469 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4471 if (container_ptr
->materials
) {
4473 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4474 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4476 out_ptr
->MatD3D
= in_ptr
->MatD3D
;
4477 if (in_ptr
->pTextureFilename
) {
4478 out_ptr
->pTextureFilename
= strings_out_ptr
;
4479 strcpy(out_ptr
->pTextureFilename
, in_ptr
->pTextureFilename
);
4480 strings_out_ptr
+= strlen(in_ptr
->pTextureFilename
) + 1;
4493 generate_effects(materials
, num_materials
, &effects
);
4494 if (!materials_out
) {
4495 ID3DXBuffer_Release(materials
);
4500 if (adjacency_out
) {
4501 if (!list_next(&container_list
, list_head(&container_list
))) {
4502 container_ptr
= LIST_ENTRY(list_head(&container_list
), struct mesh_container
, entry
);
4503 adjacency
= container_ptr
->adjacency
;
4504 container_ptr
->adjacency
= NULL
;
4509 hr
= D3DXCreateBuffer(num_faces
* 3 * sizeof(DWORD
), &adjacency
);
4510 if (FAILED(hr
)) goto cleanup
;
4512 out_ptr
= ID3DXBuffer_GetBufferPointer(adjacency
);
4513 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4516 DWORD count
= 3 * container_ptr
->mesh
->lpVtbl
->GetNumFaces(container_ptr
->mesh
);
4517 DWORD
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->adjacency
);
4519 for (i
= 0; i
< count
; i
++)
4520 *out_ptr
++ = offset
+ *in_ptr
++;
4527 *mesh_out
= concat_mesh
;
4528 if (adjacency_out
) *adjacency_out
= adjacency
;
4529 if (materials_out
) *materials_out
= materials
;
4530 if (effects_out
) *effects_out
= effects
;
4531 if (num_materials_out
) *num_materials_out
= num_materials
;
4535 if (concat_indices
) concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4536 if (concat_vertices
) concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4537 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
4538 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
4539 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4541 if (concat_mesh
) IUnknown_Release(concat_mesh
);
4542 if (materials
) ID3DXBuffer_Release(materials
);
4543 if (effects
) ID3DXBuffer_Release(effects
);
4544 if (adjacency
) ID3DXBuffer_Release(adjacency
);
4546 LIST_FOR_EACH_ENTRY_SAFE(container_ptr
, next_container_ptr
, &container_list
, struct mesh_container
, entry
)
4548 if (container_ptr
->mesh
) IUnknown_Release(container_ptr
->mesh
);
4549 if (container_ptr
->adjacency
) ID3DXBuffer_Release(container_ptr
->adjacency
);
4550 if (container_ptr
->materials
) ID3DXBuffer_Release(container_ptr
->materials
);
4551 if (container_ptr
->effects
) ID3DXBuffer_Release(container_ptr
->effects
);
4552 HeapFree(GetProcessHeap(), 0, container_ptr
);
4559 D3DXVECTOR3 position
;
4563 HRESULT WINAPI
D3DXCreatePolygon(struct IDirect3DDevice9
*device
, float length
, UINT sides
,
4564 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4568 struct vertex
*vertices
;
4570 DWORD (*adjacency_buf
)[3];
4574 TRACE("device %p, length %f, sides %u, mesh %p, adjacency %p.\n",
4575 device
, length
, sides
, mesh
, adjacency
);
4577 if (!device
|| length
< 0.0f
|| sides
< 3 || !mesh
)
4578 return D3DERR_INVALIDCALL
;
4580 if (FAILED(hr
= D3DXCreateMeshFVF(sides
, sides
+ 1, D3DXMESH_MANAGED
,
4581 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &polygon
)))
4586 if (FAILED(hr
= polygon
->lpVtbl
->LockVertexBuffer(polygon
, 0, (void **)&vertices
)))
4588 polygon
->lpVtbl
->Release(polygon
);
4592 if (FAILED(hr
= polygon
->lpVtbl
->LockIndexBuffer(polygon
, 0, (void **)&faces
)))
4594 polygon
->lpVtbl
->UnlockVertexBuffer(polygon
);
4595 polygon
->lpVtbl
->Release(polygon
);
4599 angle
= D3DX_PI
/ sides
;
4600 scale
= 0.5f
* length
/ sinf(angle
);
4603 vertices
[0].position
.x
= 0.0f
;
4604 vertices
[0].position
.y
= 0.0f
;
4605 vertices
[0].position
.z
= 0.0f
;
4606 vertices
[0].normal
.x
= 0.0f
;
4607 vertices
[0].normal
.y
= 0.0f
;
4608 vertices
[0].normal
.z
= 1.0f
;
4610 for (i
= 0; i
< sides
; ++i
)
4612 vertices
[i
+ 1].position
.x
= cosf(angle
* i
) * scale
;
4613 vertices
[i
+ 1].position
.y
= sinf(angle
* i
) * scale
;
4614 vertices
[i
+ 1].position
.z
= 0.0f
;
4615 vertices
[i
+ 1].normal
.x
= 0.0f
;
4616 vertices
[i
+ 1].normal
.y
= 0.0f
;
4617 vertices
[i
+ 1].normal
.z
= 1.0f
;
4620 faces
[i
][1] = i
+ 1;
4621 faces
[i
][2] = i
+ 2;
4624 faces
[sides
- 1][2] = 1;
4626 polygon
->lpVtbl
->UnlockVertexBuffer(polygon
);
4627 polygon
->lpVtbl
->UnlockIndexBuffer(polygon
);
4631 if (FAILED(hr
= D3DXCreateBuffer(sides
* sizeof(DWORD
) * 3, adjacency
)))
4633 polygon
->lpVtbl
->Release(polygon
);
4637 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4638 for (i
= 0; i
< sides
; ++i
)
4640 adjacency_buf
[i
][0] = i
- 1;
4641 adjacency_buf
[i
][1] = ~0U;
4642 adjacency_buf
[i
][2] = i
+ 1;
4644 adjacency_buf
[0][0] = sides
- 1;
4645 adjacency_buf
[sides
- 1][2] = 0;
4653 HRESULT WINAPI
D3DXCreateBox(struct IDirect3DDevice9
*device
, float width
, float height
,
4654 float depth
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4658 struct vertex
*vertices
;
4660 DWORD
*adjacency_buf
;
4661 unsigned int i
, face
;
4662 static const D3DXVECTOR3 unit_box
[] =
4664 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, -0.5f
},
4665 {-0.5f
, 0.5f
, -0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, -0.5f
},
4666 { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, -0.5f
},
4667 {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, 0.5f
},
4668 {-0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
},
4669 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}
4671 static const D3DXVECTOR3 normals
[] =
4673 {-1.0f
, 0.0f
, 0.0f
}, { 0.0f
, 1.0f
, 0.0f
}, { 1.0f
, 0.0f
, 0.0f
},
4674 { 0.0f
, -1.0f
, 0.0f
}, { 0.0f
, 0.0f
, 1.0f
}, { 0.0f
, 0.0f
, -1.0f
}
4676 static const DWORD adjacency_table
[] =
4678 6, 9, 1, 2, 10, 0, 1, 9, 3, 4, 10, 2,
4679 3, 8, 5, 7, 11, 4, 0, 11, 7, 5, 8, 6,
4680 7, 4, 9, 2, 0, 8, 1, 3, 11, 5, 6, 10
4683 TRACE("device %p, width %f, height %f, depth %f, mesh %p, adjacency %p\n",
4684 device
, width
, height
, depth
, mesh
, adjacency
);
4686 if (!device
|| width
< 0.0f
|| height
< 0.0f
|| depth
< 0.0f
|| !mesh
)
4688 return D3DERR_INVALIDCALL
;
4691 if (FAILED(hr
= D3DXCreateMeshFVF(12, 24, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &box
)))
4696 if (FAILED(hr
= box
->lpVtbl
->LockVertexBuffer(box
, 0, (void **)&vertices
)))
4698 box
->lpVtbl
->Release(box
);
4702 if (FAILED(hr
= box
->lpVtbl
->LockIndexBuffer(box
, 0, (void **)&faces
)))
4704 box
->lpVtbl
->UnlockVertexBuffer(box
);
4705 box
->lpVtbl
->Release(box
);
4709 for (i
= 0; i
< 24; i
++)
4711 vertices
[i
].position
.x
= width
* unit_box
[i
].x
;
4712 vertices
[i
].position
.y
= height
* unit_box
[i
].y
;
4713 vertices
[i
].position
.z
= depth
* unit_box
[i
].z
;
4714 vertices
[i
].normal
.x
= normals
[i
/ 4].x
;
4715 vertices
[i
].normal
.y
= normals
[i
/ 4].y
;
4716 vertices
[i
].normal
.z
= normals
[i
/ 4].z
;
4720 for (i
= 0; i
< 12; i
++)
4722 faces
[i
][0] = face
++;
4723 faces
[i
][1] = face
++;
4724 faces
[i
][2] = (i
% 2) ? face
- 4 : face
;
4727 box
->lpVtbl
->UnlockIndexBuffer(box
);
4728 box
->lpVtbl
->UnlockVertexBuffer(box
);
4732 if (FAILED(hr
= D3DXCreateBuffer(sizeof(adjacency_table
), adjacency
)))
4734 box
->lpVtbl
->Release(box
);
4738 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4739 memcpy(adjacency_buf
, adjacency_table
, sizeof(adjacency_table
));
4747 typedef WORD face
[3];
4755 static void free_sincos_table(struct sincos_table
*sincos_table
)
4757 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
4758 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4761 /* pre compute sine and cosine tables; caller must free */
4762 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
4767 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
4768 if (!sincos_table
->sin
)
4772 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
4773 if (!sincos_table
->cos
)
4775 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4779 angle
= angle_start
;
4780 for (i
= 0; i
< n
; i
++)
4782 sincos_table
->sin
[i
] = sinf(angle
);
4783 sincos_table
->cos
[i
] = cosf(angle
);
4784 angle
+= angle_step
;
4790 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
4792 return stack
*slices
+slice
+1;
4795 HRESULT WINAPI
D3DXCreateSphere(struct IDirect3DDevice9
*device
, float radius
, UINT slices
,
4796 UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4798 DWORD number_of_vertices
, number_of_faces
;
4801 struct vertex
*vertices
;
4803 float phi_step
, phi_start
;
4804 struct sincos_table phi
;
4805 float theta_step
, theta
, sin_theta
, cos_theta
;
4806 DWORD vertex
, face
, stack
, slice
;
4808 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
4810 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
4812 return D3DERR_INVALIDCALL
;
4815 number_of_vertices
= 2 + slices
* (stacks
-1);
4816 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
4818 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4819 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
4825 if (FAILED(hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, 0, (void **)&vertices
)))
4827 sphere
->lpVtbl
->Release(sphere
);
4831 if (FAILED(hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, 0, (void **)&faces
)))
4833 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4834 sphere
->lpVtbl
->Release(sphere
);
4838 /* phi = angle on xz plane wrt z axis */
4839 phi_step
= -2.0f
* D3DX_PI
/ slices
;
4840 phi_start
= D3DX_PI
/ 2.0f
;
4842 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
4844 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4845 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4846 sphere
->lpVtbl
->Release(sphere
);
4847 return E_OUTOFMEMORY
;
4850 /* theta = angle on xy plane wrt x axis */
4851 theta_step
= D3DX_PI
/ stacks
;
4857 vertices
[vertex
].normal
.x
= 0.0f
;
4858 vertices
[vertex
].normal
.y
= 0.0f
;
4859 vertices
[vertex
].normal
.z
= 1.0f
;
4860 vertices
[vertex
].position
.x
= 0.0f
;
4861 vertices
[vertex
].position
.y
= 0.0f
;
4862 vertices
[vertex
].position
.z
= radius
;
4865 for (stack
= 0; stack
< stacks
- 1; stack
++)
4867 sin_theta
= sinf(theta
);
4868 cos_theta
= cosf(theta
);
4870 for (slice
= 0; slice
< slices
; slice
++)
4872 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
4873 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
4874 vertices
[vertex
].normal
.z
= cos_theta
;
4875 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
4876 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
4877 vertices
[vertex
].position
.z
= radius
* cos_theta
;
4884 /* top stack is triangle fan */
4886 faces
[face
][1] = slice
+ 1;
4887 faces
[face
][2] = slice
;
4892 /* stacks in between top and bottom are quad strips */
4893 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4894 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4895 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4898 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4899 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
4900 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4906 theta
+= theta_step
;
4912 faces
[face
][2] = slice
;
4917 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4918 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4919 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4922 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4923 faces
[face
][1] = vertex_index(slices
, 0, stack
);
4924 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4929 vertices
[vertex
].position
.x
= 0.0f
;
4930 vertices
[vertex
].position
.y
= 0.0f
;
4931 vertices
[vertex
].position
.z
= -radius
;
4932 vertices
[vertex
].normal
.x
= 0.0f
;
4933 vertices
[vertex
].normal
.y
= 0.0f
;
4934 vertices
[vertex
].normal
.z
= -1.0f
;
4936 /* bottom stack is triangle fan */
4937 for (slice
= 1; slice
< slices
; slice
++)
4939 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4940 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4941 faces
[face
][2] = vertex
;
4945 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4946 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4947 faces
[face
][2] = vertex
;
4949 free_sincos_table(&phi
);
4950 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4951 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4956 if (FAILED(hr
= D3DXCreateBuffer(number_of_faces
* sizeof(DWORD
) * 3, adjacency
)))
4958 sphere
->lpVtbl
->Release(sphere
);
4962 if (FAILED(hr
= sphere
->lpVtbl
->GenerateAdjacency(sphere
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
4964 (*adjacency
)->lpVtbl
->Release(*adjacency
);
4965 sphere
->lpVtbl
->Release(sphere
);
4975 HRESULT WINAPI
D3DXCreateCylinder(struct IDirect3DDevice9
*device
, float radius1
, float radius2
,
4976 float length
, UINT slices
, UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4978 DWORD number_of_vertices
, number_of_faces
;
4980 ID3DXMesh
*cylinder
;
4981 struct vertex
*vertices
;
4983 float theta_step
, theta_start
;
4984 struct sincos_table theta
;
4985 float delta_radius
, radius
, radius_step
;
4986 float z
, z_step
, z_normal
;
4987 DWORD vertex
, face
, slice
, stack
;
4989 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
4991 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
4993 return D3DERR_INVALIDCALL
;
4996 number_of_vertices
= 2 + (slices
* (3 + stacks
));
4997 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
4999 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
5000 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
5006 if (FAILED(hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, 0, (void **)&vertices
)))
5008 cylinder
->lpVtbl
->Release(cylinder
);
5012 if (FAILED(hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, 0, (void **)&faces
)))
5014 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5015 cylinder
->lpVtbl
->Release(cylinder
);
5019 /* theta = angle on xy plane wrt x axis */
5020 theta_step
= -2.0f
* D3DX_PI
/ slices
;
5021 theta_start
= D3DX_PI
/ 2.0f
;
5023 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
5025 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5026 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5027 cylinder
->lpVtbl
->Release(cylinder
);
5028 return E_OUTOFMEMORY
;
5034 delta_radius
= radius1
- radius2
;
5036 radius_step
= delta_radius
/ stacks
;
5039 z_step
= length
/ stacks
;
5040 z_normal
= delta_radius
/ length
;
5041 if (isnan(z_normal
))
5046 vertices
[vertex
].normal
.x
= 0.0f
;
5047 vertices
[vertex
].normal
.y
= 0.0f
;
5048 vertices
[vertex
].normal
.z
= -1.0f
;
5049 vertices
[vertex
].position
.x
= 0.0f
;
5050 vertices
[vertex
].position
.y
= 0.0f
;
5051 vertices
[vertex
++].position
.z
= z
;
5053 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5055 vertices
[vertex
].normal
.x
= 0.0f
;
5056 vertices
[vertex
].normal
.y
= 0.0f
;
5057 vertices
[vertex
].normal
.z
= -1.0f
;
5058 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5059 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5060 vertices
[vertex
].position
.z
= z
;
5065 faces
[face
][1] = slice
;
5066 faces
[face
++][2] = slice
+ 1;
5071 faces
[face
][1] = slice
;
5072 faces
[face
++][2] = 1;
5074 for (stack
= 1; stack
<= stacks
+1; stack
++)
5076 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5078 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
5079 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
5080 vertices
[vertex
].normal
.z
= z_normal
;
5081 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
5082 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5083 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5084 vertices
[vertex
].position
.z
= z
;
5086 if (stack
> 1 && slice
> 0)
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
, slice
, stack
-1);
5092 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
5093 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5094 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5100 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
5101 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5102 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
5104 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
5105 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5106 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
5109 if (stack
< stacks
+ 1)
5112 radius
-= radius_step
;
5116 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5118 vertices
[vertex
].normal
.x
= 0.0f
;
5119 vertices
[vertex
].normal
.y
= 0.0f
;
5120 vertices
[vertex
].normal
.z
= 1.0f
;
5121 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5122 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5123 vertices
[vertex
].position
.z
= z
;
5127 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5128 faces
[face
][1] = number_of_vertices
- 1;
5129 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5133 vertices
[vertex
].position
.x
= 0.0f
;
5134 vertices
[vertex
].position
.y
= 0.0f
;
5135 vertices
[vertex
].position
.z
= z
;
5136 vertices
[vertex
].normal
.x
= 0.0f
;
5137 vertices
[vertex
].normal
.y
= 0.0f
;
5138 vertices
[vertex
].normal
.z
= 1.0f
;
5140 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5141 faces
[face
][1] = number_of_vertices
- 1;
5142 faces
[face
][2] = vertex_index(slices
, 0, stack
);
5144 free_sincos_table(&theta
);
5145 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5146 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5150 if (FAILED(hr
= D3DXCreateBuffer(number_of_faces
* sizeof(DWORD
) * 3, adjacency
)))
5152 cylinder
->lpVtbl
->Release(cylinder
);
5156 if (FAILED(hr
= cylinder
->lpVtbl
->GenerateAdjacency(cylinder
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
5158 (*adjacency
)->lpVtbl
->Release(*adjacency
);
5159 cylinder
->lpVtbl
->Release(cylinder
);
5169 HRESULT WINAPI
D3DXCreateTeapot(struct IDirect3DDevice9
*device
,
5170 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
5172 FIXME("device %p, mesh %p, adjacency %p semi-stub.\n", device
, mesh
, adjacency
);
5174 return D3DXCreateSphere(device
, 1.0f
, 4, 4, mesh
, adjacency
);
5177 HRESULT WINAPI
D3DXCreateTextA(struct IDirect3DDevice9
*device
, HDC hdc
, const char *text
, float deviation
,
5178 float extrusion
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5184 TRACE("device %p, hdc %p, text %s, deviation %.8e, extrusion %.8e, mesh %p, adjacency %p, glyphmetrics %p.\n",
5185 device
, hdc
, debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
5188 return D3DERR_INVALIDCALL
;
5190 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
5191 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5192 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
5194 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
5195 mesh
, adjacency
, glyphmetrics
);
5196 HeapFree(GetProcessHeap(), 0, textW
);
5201 HRESULT WINAPI
D3DXCreateTorus(struct IDirect3DDevice9
*device
,
5202 float innerradius
, float outerradius
, UINT sides
, UINT rings
, struct ID3DXMesh
**mesh
, ID3DXBuffer
**adjacency
)
5207 struct vertex
*vertices
;
5208 float phi
, phi_step
, sin_phi
, cos_phi
;
5209 float theta
, theta_step
, sin_theta
, cos_theta
;
5210 unsigned int i
, j
, numvert
, numfaces
;
5212 TRACE("device %p, innerradius %.8e, outerradius %.8e, sides %u, rings %u, mesh %p, adjacency %p.\n",
5213 device
, innerradius
, outerradius
, sides
, rings
, mesh
, adjacency
);
5215 numvert
= sides
* rings
;
5216 numfaces
= numvert
* 2;
5218 if (!device
|| innerradius
< 0.0f
|| outerradius
< 0.0f
|| sides
< 3 || rings
< 3 || !mesh
)
5220 WARN("Invalid arguments.\n");
5221 return D3DERR_INVALIDCALL
;
5224 if (FAILED(hr
= D3DXCreateMeshFVF(numfaces
, numvert
, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &torus
)))
5227 if (FAILED(hr
= torus
->lpVtbl
->LockVertexBuffer(torus
, 0, (void **)&vertices
)))
5229 torus
->lpVtbl
->Release(torus
);
5233 if (FAILED(hr
= torus
->lpVtbl
->LockIndexBuffer(torus
, 0, (void **)&faces
)))
5235 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5236 torus
->lpVtbl
->Release(torus
);
5240 phi_step
= D3DX_PI
/ sides
* 2.0f
;
5241 theta_step
= D3DX_PI
/ rings
* -2.0f
;
5245 for (i
= 0; i
< rings
; ++i
)
5249 sin_theta
= sinf(theta
);
5250 cos_theta
= cosf(theta
);
5252 for (j
= 0; j
< sides
; ++j
)
5254 sin_phi
= sinf(phi
);
5255 cos_phi
= cosf(phi
);
5257 vertices
[i
* sides
+ j
].position
.x
= (innerradius
* cos_phi
+ outerradius
) * cos_theta
;
5258 vertices
[i
* sides
+ j
].position
.y
= (innerradius
* cos_phi
+ outerradius
) * sin_theta
;
5259 vertices
[i
* sides
+ j
].position
.z
= innerradius
* sin_phi
;
5260 vertices
[i
* sides
+ j
].normal
.x
= cos_phi
* cos_theta
;
5261 vertices
[i
* sides
+ j
].normal
.y
= cos_phi
* sin_theta
;
5262 vertices
[i
* sides
+ j
].normal
.z
= sin_phi
;
5267 theta
+= theta_step
;
5270 for (i
= 0; i
< numfaces
- sides
* 2; ++i
)
5272 faces
[i
][0] = i
% 2 ? i
/ 2 + sides
: i
/ 2;
5273 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5274 faces
[i
][2] = (i
+ 1) % (sides
* 2) ? (i
+ 1) / 2 + sides
: (i
+ 1) / 2;
5277 for (j
= 0; i
< numfaces
; ++i
, ++j
)
5279 faces
[i
][0] = i
% 2 ? j
/ 2 : i
/ 2;
5280 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5281 faces
[i
][2] = i
== numfaces
- 1 ? 0 : (j
+ 1) / 2;
5284 torus
->lpVtbl
->UnlockIndexBuffer(torus
);
5285 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5289 if (FAILED(hr
= D3DXCreateBuffer(numfaces
* sizeof(DWORD
) * 3, adjacency
)))
5291 torus
->lpVtbl
->Release(torus
);
5295 if (FAILED(hr
= torus
->lpVtbl
->GenerateAdjacency(torus
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
5297 (*adjacency
)->lpVtbl
->Release(*adjacency
);
5298 torus
->lpVtbl
->Release(torus
);
5309 POINTTYPE_CURVE
= 0,
5311 POINTTYPE_CURVE_START
,
5312 POINTTYPE_CURVE_END
,
5313 POINTTYPE_CURVE_MIDDLE
,
5319 enum pointtype corner
;
5322 struct dynamic_array
5324 int count
, capacity
;
5328 /* is a dynamic_array */
5331 int count
, capacity
;
5332 struct point2d
*items
;
5335 /* is a dynamic_array */
5336 struct outline_array
5338 int count
, capacity
;
5339 struct outline
*items
;
5348 struct point2d_index
5350 struct outline
*outline
;
5354 struct point2d_index_array
5357 struct point2d_index
*items
;
5362 struct outline_array outlines
;
5363 struct face_array faces
;
5364 struct point2d_index_array ordered_vertices
;
5368 /* is an dynamic_array */
5371 int count
, capacity
;
5375 /* complex polygons are split into monotone polygons, which have
5376 * at most 2 intersections with the vertical sweep line */
5377 struct triangulation
5379 struct word_array vertex_stack
;
5380 BOOL last_on_top
, merging
;
5383 /* is an dynamic_array */
5384 struct triangulation_array
5386 int count
, capacity
;
5387 struct triangulation
*items
;
5389 struct glyphinfo
*glyph
;
5392 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
5394 if (count
> array
->capacity
) {
5397 if (array
->items
&& array
->capacity
) {
5398 new_capacity
= max(array
->capacity
* 2, count
);
5399 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
5401 new_capacity
= max(16, count
);
5402 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
5406 array
->items
= new_buffer
;
5407 array
->capacity
= new_capacity
;
5412 static struct point2d
*add_points(struct outline
*array
, int num
)
5414 struct point2d
*item
;
5416 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
5419 item
= &array
->items
[array
->count
];
5420 array
->count
+= num
;
5424 static struct outline
*add_outline(struct outline_array
*array
)
5426 struct outline
*item
;
5428 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5431 item
= &array
->items
[array
->count
++];
5432 ZeroMemory(item
, sizeof(*item
));
5436 static inline face
*add_face(struct face_array
*array
)
5438 return &array
->items
[array
->count
++];
5441 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
5443 struct triangulation
*item
;
5445 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5448 item
= &array
->items
[array
->count
++];
5449 ZeroMemory(item
, sizeof(*item
));
5453 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
5455 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5456 return E_OUTOFMEMORY
;
5458 array
->items
[array
->count
++] = vertex_index
;
5462 /* assume fixed point numbers can be converted to float point in place */
5463 C_ASSERT(sizeof(FIXED
) == sizeof(float));
5464 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
5466 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, unsigned int emsquare
)
5468 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
5470 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
5471 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
5472 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
5478 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
5479 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
5480 float max_deviation_sq
)
5482 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
5485 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
5486 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
5487 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
5489 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
5490 if (deviation_sq
< max_deviation_sq
) {
5491 struct point2d
*pt
= add_points(outline
, 1);
5492 if (!pt
) return E_OUTOFMEMORY
;
5494 pt
->corner
= POINTTYPE_CURVE
;
5495 /* the end point is omitted because the end line merges into the next segment of
5496 * the split bezier curve, and the end of the split bezier curve is added outside
5497 * this recursive function. */
5499 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
5500 if (hr
!= S_OK
) return hr
;
5501 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
5502 if (hr
!= S_OK
) return hr
;
5508 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
5510 /* dot product = cos(theta) */
5511 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
5514 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
5516 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
5526 static BOOL
attempt_line_merge(struct outline
*outline
,
5528 const D3DXVECTOR2
*nextpt
,
5530 const struct cos_table
*table
)
5532 D3DXVECTOR2 curdir
, lastdir
;
5533 struct point2d
*prevpt
, *pt
;
5536 pt
= &outline
->items
[pt_index
];
5537 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5538 prevpt
= &outline
->items
[pt_index
];
5541 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
5543 if (outline
->count
< 2)
5546 /* remove last point if the next line continues the last line */
5547 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5548 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5549 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
5552 if (pt
->corner
== POINTTYPE_CURVE_END
)
5553 prevpt
->corner
= pt
->corner
;
5554 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
5555 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5559 if (outline
->count
< 2)
5562 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5563 prevpt
= &outline
->items
[pt_index
];
5564 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5565 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5570 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
5571 float max_deviation_sq
, unsigned int emsquare
,
5572 const struct cos_table
*cos_table
)
5574 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
5576 while ((char *)header
< (char *)raw_outline
+ datasize
)
5578 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
5579 struct point2d
*lastpt
, *pt
;
5580 D3DXVECTOR2 lastdir
;
5581 D3DXVECTOR2
*pt_flt
;
5583 struct outline
*outline
= add_outline(&glyph
->outlines
);
5586 return E_OUTOFMEMORY
;
5588 pt
= add_points(outline
, 1);
5590 return E_OUTOFMEMORY
;
5591 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
5593 pt
->corner
= POINTTYPE_CORNER
;
5595 if (header
->dwType
!= TT_POLYGON_TYPE
)
5596 FIXME("Unknown header type %d\n", header
->dwType
);
5598 while ((char *)curve
< (char *)header
+ header
->cb
)
5600 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
5601 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
5602 unsigned int j2
= 0;
5605 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5609 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
5611 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
5616 int count
= curve
->cpfx
;
5620 D3DXVECTOR2 bezier_end
;
5622 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j2
], &pt_flt
[j2
+1]), 0.5f
);
5623 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &bezier_end
, max_deviation_sq
);
5626 bezier_start
= bezier_end
;
5630 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &pt_flt
[j2
+1], max_deviation_sq
);
5634 pt
= add_points(outline
, 1);
5636 return E_OUTOFMEMORY
;
5638 pt
->pos
= pt_flt
[j2
];
5639 pt
->corner
= POINTTYPE_CURVE_END
;
5641 pt
= add_points(outline
, curve
->cpfx
);
5643 return E_OUTOFMEMORY
;
5644 for (j2
= 0; j2
< curve
->cpfx
; j2
++)
5646 pt
->pos
= pt_flt
[j2
];
5647 pt
->corner
= POINTTYPE_CORNER
;
5652 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5655 /* remove last point if the next line continues the last line */
5656 if (outline
->count
>= 3) {
5659 lastpt
= &outline
->items
[outline
->count
- 1];
5660 pt
= &outline
->items
[0];
5661 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
5662 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
5664 if (pt
->corner
== POINTTYPE_CURVE_START
)
5665 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5667 pt
->corner
= POINTTYPE_CURVE_END
;
5671 /* outline closed with a line from end to start point */
5672 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
5674 lastpt
= &outline
->items
[0];
5675 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
5676 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
5677 lastpt
->corner
= POINTTYPE_CORNER
;
5678 pt
= &outline
->items
[1];
5679 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
5680 *lastpt
= outline
->items
[outline
->count
];
5683 lastpt
= &outline
->items
[outline
->count
- 1];
5684 pt
= &outline
->items
[0];
5685 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
5686 for (j
= 0; j
< outline
->count
; j
++)
5691 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
5692 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
5694 switch (lastpt
->corner
)
5696 case POINTTYPE_CURVE_START
:
5697 case POINTTYPE_CURVE_END
:
5698 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
5699 lastpt
->corner
= POINTTYPE_CORNER
;
5701 case POINTTYPE_CURVE_MIDDLE
:
5702 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
5703 lastpt
->corner
= POINTTYPE_CORNER
;
5705 lastpt
->corner
= POINTTYPE_CURVE
;
5713 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
5718 /* Get the y-distance from a line to a point */
5719 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
5720 D3DXVECTOR2
*line_pt2
,
5723 D3DXVECTOR2 line_vec
= {0, 0};
5727 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
5728 line_pt_dx
= point
->x
- line_pt1
->x
;
5729 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
5730 return point
->y
- line_y
;
5733 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
5735 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
5738 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
5740 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
5743 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
5745 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
5746 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
5750 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
5751 struct triangulation_array
*triangulations
,
5755 struct glyphinfo
*glyph
= triangulations
->glyph
;
5756 struct triangulation
*t
= *t_ptr
;
5761 if (t
->last_on_top
) {
5769 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
5770 /* consume all vertices on the stack */
5771 WORD last_pt
= t
->vertex_stack
.items
[0];
5773 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
5775 face
= add_face(&glyph
->faces
);
5776 if (!face
) return E_OUTOFMEMORY
;
5777 (*face
)[0] = vtx_idx
;
5778 (*face
)[f1
] = last_pt
;
5779 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
5781 t
->vertex_stack
.items
[0] = last_pt
;
5782 t
->vertex_stack
.count
= 1;
5783 } else if (t
->vertex_stack
.count
> 1) {
5784 int i
= t
->vertex_stack
.count
- 1;
5785 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
5786 WORD top_idx
= t
->vertex_stack
.items
[i
--];
5787 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
5791 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
5792 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
5794 if (prev_pt
->x
!= top_pt
->x
&&
5795 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
5796 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
5799 face
= add_face(&glyph
->faces
);
5800 if (!face
) return E_OUTOFMEMORY
;
5801 (*face
)[0] = vtx_idx
;
5802 (*face
)[f1
] = prev_idx
;
5803 (*face
)[f2
] = top_idx
;
5807 t
->vertex_stack
.count
--;
5810 t
->last_on_top
= to_top
;
5812 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
5814 if (hr
== S_OK
&& t
->merging
) {
5815 struct triangulation
*t2
;
5817 t2
= to_top
? t
- 1 : t
+ 1;
5818 t2
->merging
= FALSE
;
5819 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
5820 if (hr
!= S_OK
) return hr
;
5821 remove_triangulation(triangulations
, t
);
5829 /* check if the point is next on the outline for either the top or bottom */
5830 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
5832 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
5833 WORD idx
= t
->vertex_stack
.items
[i
];
5834 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
5835 struct outline
*outline
= pt_idx
->outline
;
5838 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
5840 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
5842 return &outline
->items
[i
].pos
;
5845 static int __cdecl
compare_vertex_indices(const void *a
, const void *b
)
5847 const struct point2d_index
*idx1
= a
, *idx2
= b
;
5848 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
5849 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
5850 float diff
= p1
->x
- p2
->x
;
5853 diff
= p1
->y
- p2
->y
;
5855 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
5858 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
5862 struct glyphinfo
*glyph
= triangulations
->glyph
;
5863 int nb_vertices
= 0;
5865 struct point2d_index
*idx_ptr
;
5867 /* Glyphs without outlines do not generate any vertices. */
5868 if (!glyph
->outlines
.count
)
5871 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5872 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
5874 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
5875 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
5876 if (!glyph
->ordered_vertices
.items
)
5877 return E_OUTOFMEMORY
;
5879 idx_ptr
= glyph
->ordered_vertices
.items
;
5880 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5882 struct outline
*outline
= &glyph
->outlines
.items
[i
];
5885 idx_ptr
->outline
= outline
;
5886 idx_ptr
->vertex
= 0;
5888 for (j
= outline
->count
- 1; j
> 0; j
--)
5890 idx_ptr
->outline
= outline
;
5891 idx_ptr
->vertex
= j
;
5895 glyph
->ordered_vertices
.count
= nb_vertices
;
5897 /* Native implementation seems to try to create a triangle fan from
5898 * the first outline point if the glyph only has one outline. */
5899 if (glyph
->outlines
.count
== 1)
5901 struct outline
*outline
= glyph
->outlines
.items
;
5902 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
5903 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
5906 for (i
= 2; i
< outline
->count
; i
++)
5908 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
5909 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
5910 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
5912 D3DXVec2Subtract(&v1
, base
, last
);
5913 D3DXVec2Subtract(&v2
, last
, next
);
5914 ccw
= D3DXVec2CCW(&v1
, &v2
);
5922 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5923 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
5924 if (!glyph
->faces
.items
)
5925 return E_OUTOFMEMORY
;
5927 glyph
->faces
.count
= outline
->count
- 2;
5928 for (i
= 0; i
< glyph
->faces
.count
; i
++)
5930 glyph
->faces
.items
[i
][0] = 0;
5931 glyph
->faces
.items
[i
][1] = i
+ 1;
5932 glyph
->faces
.items
[i
][2] = i
+ 2;
5938 /* Perform 2D polygon triangulation for complex glyphs.
5939 * Triangulation is performed using a sweep line concept, from right to left,
5940 * by processing vertices in sorted order. Complex polygons are split into
5941 * monotone polygons which are triangulated separately. */
5942 /* FIXME: The order of the faces is not consistent with the native implementation. */
5944 /* Reserve space for maximum possible faces from triangulation.
5945 * # faces for outer outlines = outline->count - 2
5946 * # faces for inner outlines = outline->count + 2
5947 * There must be at least 1 outer outline. */
5948 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5949 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
5950 if (!glyph
->faces
.items
)
5951 return E_OUTOFMEMORY
;
5953 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
5954 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
5955 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
5958 int end
= triangulations
->count
;
5962 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
5963 int current
= (start
+ end
) / 2;
5964 struct triangulation
*t
= &triangulations
->items
[current
];
5965 BOOL on_top_outline
= FALSE
;
5966 D3DXVECTOR2
*top_next
, *bottom_next
;
5967 WORD top_idx
, bottom_idx
;
5969 if (t
->merging
&& t
->last_on_top
)
5970 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
5972 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
5973 if (sweep_vtx
== top_next
)
5975 if (t
->merging
&& t
->last_on_top
)
5977 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
5978 if (hr
!= S_OK
) return hr
;
5980 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
5981 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
5983 /* point also on bottom outline of higher triangulation */
5984 struct triangulation
*t2
= t
+ 1;
5985 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
5986 if (hr
!= S_OK
) return hr
;
5991 on_top_outline
= TRUE
;
5994 if (t
->merging
&& !t
->last_on_top
)
5995 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
5997 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
5998 if (sweep_vtx
== bottom_next
)
6000 if (t
->merging
&& !t
->last_on_top
)
6002 if (on_top_outline
) {
6003 /* outline finished */
6004 remove_triangulation(triangulations
, t
);
6008 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
6009 if (hr
!= S_OK
) return hr
;
6011 if (t
> triangulations
->items
&&
6012 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
6014 struct triangulation
*t2
= t
- 1;
6015 /* point also on top outline of lower triangulation */
6016 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
6017 if (hr
!= S_OK
) return hr
;
6018 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
6028 if (t
->last_on_top
) {
6029 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
6030 bottom_idx
= t
->vertex_stack
.items
[0];
6032 top_idx
= t
->vertex_stack
.items
[0];
6033 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
6036 /* check if the point is inside or outside this polygon */
6037 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
6038 top_next
, sweep_vtx
) > 0)
6040 start
= current
+ 1;
6041 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
6042 bottom_next
, sweep_vtx
) < 0)
6045 } else if (t
->merging
) {
6046 /* inside, so cancel merging */
6047 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
6049 t2
->merging
= FALSE
;
6050 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
6051 if (hr
!= S_OK
) return hr
;
6052 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
6053 if (hr
!= S_OK
) return hr
;
6056 /* inside, so split polygon into two monotone parts */
6057 struct triangulation
*t2
= add_triangulation(triangulations
);
6058 if (!t2
) return E_OUTOFMEMORY
;
6059 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
6060 if (t
->last_on_top
) {
6067 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
6068 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
6069 if (hr
!= S_OK
) return hr
;
6070 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
6071 if (hr
!= S_OK
) return hr
;
6072 t2
->last_on_top
= !t
->last_on_top
;
6074 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
6075 if (hr
!= S_OK
) return hr
;
6081 struct triangulation
*t
;
6082 struct triangulation
*t2
= add_triangulation(triangulations
);
6083 if (!t2
) return E_OUTOFMEMORY
;
6084 t
= &triangulations
->items
[start
];
6085 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
6086 ZeroMemory(t
, sizeof(*t
));
6087 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
6088 if (hr
!= S_OK
) return hr
;
6094 HRESULT WINAPI
D3DXCreateTextW(struct IDirect3DDevice9
*device
, HDC hdc
, const WCHAR
*text
, float deviation
,
6095 float extrusion
, struct ID3DXMesh
**mesh_ptr
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
6098 ID3DXMesh
*mesh
= NULL
;
6099 DWORD nb_vertices
, nb_faces
;
6100 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
6101 struct vertex
*vertices
= NULL
;
6106 OUTLINETEXTMETRICW otm
;
6107 HFONT font
= NULL
, oldfont
= NULL
;
6108 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
6109 void *raw_outline
= NULL
;
6111 struct glyphinfo
*glyphs
= NULL
;
6113 struct triangulation_array triangulations
= {0, 0, NULL
};
6115 struct vertex
*vertex_ptr
;
6117 float max_deviation_sq
;
6118 const struct cos_table cos_table
= {
6119 cosf(D3DXToRadian(0.5f
)),
6120 cosf(D3DXToRadian(45.0f
)),
6121 cosf(D3DXToRadian(90.0f
)),
6125 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
6126 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
6128 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
6129 return D3DERR_INVALIDCALL
;
6133 FIXME("Case of adjacency != NULL not implemented.\n");
6137 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
6138 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
6140 return D3DERR_INVALIDCALL
;
6143 if (deviation
== 0.0f
)
6144 deviation
= 1.0f
/ otm
.otmEMSquare
;
6145 max_deviation_sq
= deviation
* deviation
;
6147 lf
.lfHeight
= otm
.otmEMSquare
;
6149 font
= CreateFontIndirectW(&lf
);
6154 oldfont
= SelectObject(hdc
, font
);
6156 textlen
= lstrlenW(text
);
6157 for (i
= 0; i
< textlen
; i
++)
6159 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
6161 return D3DERR_INVALIDCALL
;
6162 if (bufsize
< datasize
)
6165 if (!bufsize
) { /* e.g. text == " " */
6166 hr
= D3DERR_INVALIDCALL
;
6170 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
6171 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
6172 if (!glyphs
|| !raw_outline
) {
6178 for (i
= 0; i
< textlen
; i
++)
6180 /* get outline points from data returned from GetGlyphOutline */
6183 glyphs
[i
].offset_x
= offset_x
;
6185 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
6186 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
6187 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
6188 if (hr
!= S_OK
) goto error
;
6190 triangulations
.glyph
= &glyphs
[i
];
6191 hr
= triangulate(&triangulations
);
6192 if (hr
!= S_OK
) goto error
;
6193 if (triangulations
.count
) {
6194 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
6195 triangulations
.count
= 0;
6200 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
6201 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
6202 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
6203 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
6204 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6205 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
6207 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6210 /* corner points need an extra vertex for the different side faces normals */
6212 nb_outline_points
= 0;
6214 for (i
= 0; i
< textlen
; i
++)
6217 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
6218 nb_front_faces
+= glyphs
[i
].faces
.count
;
6219 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6222 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6223 nb_corners
++; /* first outline point always repeated as a corner */
6224 for (k
= 1; k
< outline
->count
; k
++)
6225 if (outline
->items
[k
].corner
)
6230 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
6231 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
6234 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
6235 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
6239 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
6242 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, (void **)&faces
)))
6245 /* convert 2D vertices and faces into 3D mesh */
6246 vertex_ptr
= vertices
;
6248 if (extrusion
== 0.0f
) {
6255 for (i
= 0; i
< textlen
; i
++)
6259 struct vertex
*back_vertices
;
6262 /* side vertices and faces */
6263 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6265 struct vertex
*outline_vertices
= vertex_ptr
;
6266 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6268 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
6269 struct point2d
*pt
= &outline
->items
[0];
6271 for (k
= 1; k
<= outline
->count
; k
++)
6274 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
6275 WORD vtx_idx
= vertex_ptr
- vertices
;
6278 if (pt
->corner
== POINTTYPE_CURVE_START
)
6279 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
6280 else if (pt
->corner
)
6281 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6283 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
6284 D3DXVec2Normalize(&vec
, &vec
);
6285 vtx
.normal
.x
= -vec
.y
;
6286 vtx
.normal
.y
= vec
.x
;
6289 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
6290 vtx
.position
.y
= pt
->pos
.y
;
6292 *vertex_ptr
++ = vtx
;
6294 vtx
.position
.z
= -extrusion
;
6295 *vertex_ptr
++ = vtx
;
6297 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
6298 vtx
.position
.y
= nextpt
->pos
.y
;
6299 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
6300 vtx
.position
.z
= -extrusion
;
6301 *vertex_ptr
++ = vtx
;
6303 *vertex_ptr
++ = vtx
;
6305 (*face_ptr
)[0] = vtx_idx
;
6306 (*face_ptr
)[1] = vtx_idx
+ 2;
6307 (*face_ptr
)[2] = vtx_idx
+ 1;
6310 (*face_ptr
)[0] = vtx_idx
;
6311 (*face_ptr
)[1] = vtx_idx
+ 3;
6312 (*face_ptr
)[2] = vtx_idx
+ 2;
6315 if (nextpt
->corner
) {
6316 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
6317 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
6318 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
6320 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6322 D3DXVec2Normalize(&vec
, &vec
);
6323 vtx
.normal
.x
= -vec
.y
;
6324 vtx
.normal
.y
= vec
.x
;
6327 *vertex_ptr
++ = vtx
;
6328 vtx
.position
.z
= -extrusion
;
6329 *vertex_ptr
++ = vtx
;
6332 (*face_ptr
)[0] = vtx_idx
;
6333 (*face_ptr
)[1] = vtx_idx
+ 3;
6334 (*face_ptr
)[2] = vtx_idx
+ 1;
6337 (*face_ptr
)[0] = vtx_idx
;
6338 (*face_ptr
)[1] = vtx_idx
+ 2;
6339 (*face_ptr
)[2] = vtx_idx
+ 3;
6347 *vertex_ptr
++ = *outline_vertices
++;
6348 *vertex_ptr
++ = *outline_vertices
++;
6352 /* back vertices and faces */
6353 back_faces
= face_ptr
;
6354 back_vertices
= vertex_ptr
;
6355 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
6357 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
6358 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
6359 vertex_ptr
->position
.y
= pt
->y
;
6360 vertex_ptr
->position
.z
= 0;
6361 vertex_ptr
->normal
.x
= 0;
6362 vertex_ptr
->normal
.y
= 0;
6363 vertex_ptr
->normal
.z
= 1;
6366 count
= back_vertices
- vertices
;
6367 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
6369 face
*f
= &glyphs
[i
].faces
.items
[j
];
6370 (*face_ptr
)[0] = (*f
)[0] + count
;
6371 (*face_ptr
)[1] = (*f
)[1] + count
;
6372 (*face_ptr
)[2] = (*f
)[2] + count
;
6376 /* front vertices and faces */
6377 j
= count
= vertex_ptr
- back_vertices
;
6380 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
6381 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
6382 vertex_ptr
->position
.z
= -extrusion
;
6383 vertex_ptr
->normal
.x
= 0;
6384 vertex_ptr
->normal
.y
= 0;
6385 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
6389 j
= face_ptr
- back_faces
;
6392 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
6393 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
6394 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
6404 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6405 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6406 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
6409 for (i
= 0; i
< textlen
; i
++)
6412 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6413 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
6414 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
6415 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
6416 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
6418 HeapFree(GetProcessHeap(), 0, glyphs
);
6420 if (triangulations
.items
) {
6422 for (i
= 0; i
< triangulations
.count
; i
++)
6423 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
6424 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
6426 HeapFree(GetProcessHeap(), 0, raw_outline
);
6427 if (oldfont
) SelectObject(hdc
, oldfont
);
6428 if (font
) DeleteObject(font
);
6433 HRESULT WINAPI
D3DXValidMesh(ID3DXMesh
*mesh
, const DWORD
*adjacency
, ID3DXBuffer
**errors_and_warnings
)
6435 FIXME("(%p, %p, %p): stub\n", mesh
, adjacency
, *errors_and_warnings
);
6440 static BOOL
weld_float1(void *to
, void *from
, FLOAT epsilon
)
6445 if (fabsf(*v1
- *v2
) <= epsilon
)
6455 static BOOL
weld_float2(void *to
, void *from
, FLOAT epsilon
)
6457 D3DXVECTOR2
*v1
= to
;
6458 D3DXVECTOR2
*v2
= from
;
6459 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6460 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6461 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6463 if (max_abs_diff
<= epsilon
)
6465 memcpy(to
, from
, sizeof(D3DXVECTOR2
));
6473 static BOOL
weld_float3(void *to
, void *from
, FLOAT epsilon
)
6475 D3DXVECTOR3
*v1
= to
;
6476 D3DXVECTOR3
*v2
= from
;
6477 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6478 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6479 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6480 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6481 max_abs_diff
= max(diff_z
, max_abs_diff
);
6483 if (max_abs_diff
<= epsilon
)
6485 memcpy(to
, from
, sizeof(D3DXVECTOR3
));
6493 static BOOL
weld_float4(void *to
, void *from
, FLOAT epsilon
)
6495 D3DXVECTOR4
*v1
= to
;
6496 D3DXVECTOR4
*v2
= from
;
6497 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6498 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6499 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6500 FLOAT diff_w
= fabsf(v1
->w
- v2
->w
);
6501 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6502 max_abs_diff
= max(diff_z
, max_abs_diff
);
6503 max_abs_diff
= max(diff_w
, max_abs_diff
);
6505 if (max_abs_diff
<= epsilon
)
6507 memcpy(to
, from
, sizeof(D3DXVECTOR4
));
6515 static BOOL
weld_ubyte4(void *to
, void *from
, FLOAT epsilon
)
6519 BYTE truncated_epsilon
= (BYTE
)epsilon
;
6520 BYTE diff_x
= b1
[0] > b2
[0] ? b1
[0] - b2
[0] : b2
[0] - b1
[0];
6521 BYTE diff_y
= b1
[1] > b2
[1] ? b1
[1] - b2
[1] : b2
[1] - b1
[1];
6522 BYTE diff_z
= b1
[2] > b2
[2] ? b1
[2] - b2
[2] : b2
[2] - b1
[2];
6523 BYTE diff_w
= b1
[3] > b2
[3] ? b1
[3] - b2
[3] : b2
[3] - b1
[3];
6524 BYTE max_diff
= max(diff_x
, diff_y
);
6525 max_diff
= max(diff_z
, max_diff
);
6526 max_diff
= max(diff_w
, max_diff
);
6528 if (max_diff
<= truncated_epsilon
)
6530 memcpy(to
, from
, 4 * sizeof(BYTE
));
6538 static BOOL
weld_ubyte4n(void *to
, void *from
, FLOAT epsilon
)
6540 return weld_ubyte4(to
, from
, epsilon
* UCHAR_MAX
);
6543 static BOOL
weld_d3dcolor(void *to
, void *from
, FLOAT epsilon
)
6545 return weld_ubyte4n(to
, from
, epsilon
);
6548 static BOOL
weld_short2(void *to
, void *from
, FLOAT epsilon
)
6552 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6553 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6554 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6555 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6557 if (max_abs_diff
<= truncated_epsilon
)
6559 memcpy(to
, from
, 2 * sizeof(SHORT
));
6567 static BOOL
weld_short2n(void *to
, void *from
, FLOAT epsilon
)
6569 return weld_short2(to
, from
, epsilon
* SHRT_MAX
);
6572 static BOOL
weld_short4(void *to
, void *from
, FLOAT epsilon
)
6576 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6577 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6578 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6579 SHORT diff_z
= abs(s1
[2] - s2
[2]);
6580 SHORT diff_w
= abs(s1
[3] - s2
[3]);
6581 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6582 max_abs_diff
= max(diff_z
, max_abs_diff
);
6583 max_abs_diff
= max(diff_w
, max_abs_diff
);
6585 if (max_abs_diff
<= truncated_epsilon
)
6587 memcpy(to
, from
, 4 * sizeof(SHORT
));
6595 static BOOL
weld_short4n(void *to
, void *from
, FLOAT epsilon
)
6597 return weld_short4(to
, from
, epsilon
* SHRT_MAX
);
6600 static BOOL
weld_ushort2n(void *to
, void *from
, FLOAT epsilon
)
6604 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6605 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6606 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6607 USHORT max_diff
= max(diff_x
, diff_y
);
6609 if (max_diff
<= scaled_epsilon
)
6611 memcpy(to
, from
, 2 * sizeof(USHORT
));
6619 static BOOL
weld_ushort4n(void *to
, void *from
, FLOAT epsilon
)
6623 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6624 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6625 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6626 USHORT diff_z
= s1
[2] > s2
[2] ? s1
[2] - s2
[2] : s2
[2] - s1
[2];
6627 USHORT diff_w
= s1
[3] > s2
[3] ? s1
[3] - s2
[3] : s2
[3] - s1
[3];
6628 USHORT max_diff
= max(diff_x
, diff_y
);
6629 max_diff
= max(diff_z
, max_diff
);
6630 max_diff
= max(diff_w
, max_diff
);
6632 if (max_diff
<= scaled_epsilon
)
6634 memcpy(to
, from
, 4 * sizeof(USHORT
));
6650 static struct udec3
dword_to_udec3(DWORD d
)
6655 v
.y
= (d
& 0xffc00) >> 10;
6656 v
.z
= (d
& 0x3ff00000) >> 20;
6657 v
.w
= (d
& 0xc0000000) >> 30;
6662 static BOOL
weld_udec3(void *to
, void *from
, FLOAT epsilon
)
6666 struct udec3 v1
= dword_to_udec3(*d1
);
6667 struct udec3 v2
= dword_to_udec3(*d2
);
6668 UINT truncated_epsilon
= (UINT
)epsilon
;
6669 UINT diff_x
= v1
.x
> v2
.x
? v1
.x
- v2
.x
: v2
.x
- v1
.x
;
6670 UINT diff_y
= v1
.y
> v2
.y
? v1
.y
- v2
.y
: v2
.y
- v1
.y
;
6671 UINT diff_z
= v1
.z
> v2
.z
? v1
.z
- v2
.z
: v2
.z
- v1
.z
;
6672 UINT diff_w
= v1
.w
> v2
.w
? v1
.w
- v2
.w
: v2
.w
- v1
.w
;
6673 UINT max_diff
= max(diff_x
, diff_y
);
6674 max_diff
= max(diff_z
, max_diff
);
6675 max_diff
= max(diff_w
, max_diff
);
6677 if (max_diff
<= truncated_epsilon
)
6679 memcpy(to
, from
, sizeof(DWORD
));
6695 static struct dec3n
dword_to_dec3n(DWORD d
)
6700 v
.y
= (d
& 0xffc00) >> 10;
6701 v
.z
= (d
& 0x3ff00000) >> 20;
6702 v
.w
= (d
& 0xc0000000) >> 30;
6707 static BOOL
weld_dec3n(void *to
, void *from
, FLOAT epsilon
)
6709 const UINT MAX_DEC3N
= 511;
6712 struct dec3n v1
= dword_to_dec3n(*d1
);
6713 struct dec3n v2
= dword_to_dec3n(*d2
);
6714 INT scaled_epsilon
= (INT
)(epsilon
* MAX_DEC3N
);
6715 INT diff_x
= abs(v1
.x
- v2
.x
);
6716 INT diff_y
= abs(v1
.y
- v2
.y
);
6717 INT diff_z
= abs(v1
.z
- v2
.z
);
6718 INT diff_w
= abs(v1
.w
- v2
.w
);
6719 INT max_abs_diff
= max(diff_x
, diff_y
);
6720 max_abs_diff
= max(diff_z
, max_abs_diff
);
6721 max_abs_diff
= max(diff_w
, max_abs_diff
);
6723 if (max_abs_diff
<= scaled_epsilon
)
6725 memcpy(to
, from
, sizeof(DWORD
));
6733 static BOOL
weld_float16_2(void *to
, void *from
, FLOAT epsilon
)
6735 D3DXFLOAT16
*v1_float16
= to
;
6736 D3DXFLOAT16
*v2_float16
= from
;
6744 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6745 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6747 diff_x
= fabsf(v1
[0] - v2
[0]);
6748 diff_y
= fabsf(v1
[1] - v2
[1]);
6749 max_abs_diff
= max(diff_x
, diff_y
);
6751 if (max_abs_diff
<= epsilon
)
6753 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6762 static BOOL
weld_float16_4(void *to
, void *from
, FLOAT epsilon
)
6764 D3DXFLOAT16
*v1_float16
= to
;
6765 D3DXFLOAT16
*v2_float16
= from
;
6775 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6776 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6778 diff_x
= fabsf(v1
[0] - v2
[0]);
6779 diff_y
= fabsf(v1
[1] - v2
[1]);
6780 diff_z
= fabsf(v1
[2] - v2
[2]);
6781 diff_w
= fabsf(v1
[3] - v2
[3]);
6782 max_abs_diff
= max(diff_x
, diff_y
);
6783 max_abs_diff
= max(diff_z
, max_abs_diff
);
6784 max_abs_diff
= max(diff_w
, max_abs_diff
);
6786 if (max_abs_diff
<= epsilon
)
6788 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6797 /* Sets the vertex components to the same value if they are within epsilon. */
6798 static BOOL
weld_component(void *to
, void *from
, D3DDECLTYPE type
, FLOAT epsilon
)
6800 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6801 BOOL fixme_once_unused
= FALSE
;
6802 BOOL fixme_once_unknown
= FALSE
;
6806 case D3DDECLTYPE_FLOAT1
:
6807 return weld_float1(to
, from
, epsilon
);
6809 case D3DDECLTYPE_FLOAT2
:
6810 return weld_float2(to
, from
, epsilon
);
6812 case D3DDECLTYPE_FLOAT3
:
6813 return weld_float3(to
, from
, epsilon
);
6815 case D3DDECLTYPE_FLOAT4
:
6816 return weld_float4(to
, from
, epsilon
);
6818 case D3DDECLTYPE_D3DCOLOR
:
6819 return weld_d3dcolor(to
, from
, epsilon
);
6821 case D3DDECLTYPE_UBYTE4
:
6822 return weld_ubyte4(to
, from
, epsilon
);
6824 case D3DDECLTYPE_SHORT2
:
6825 return weld_short2(to
, from
, epsilon
);
6827 case D3DDECLTYPE_SHORT4
:
6828 return weld_short4(to
, from
, epsilon
);
6830 case D3DDECLTYPE_UBYTE4N
:
6831 return weld_ubyte4n(to
, from
, epsilon
);
6833 case D3DDECLTYPE_SHORT2N
:
6834 return weld_short2n(to
, from
, epsilon
);
6836 case D3DDECLTYPE_SHORT4N
:
6837 return weld_short4n(to
, from
, epsilon
);
6839 case D3DDECLTYPE_USHORT2N
:
6840 return weld_ushort2n(to
, from
, epsilon
);
6842 case D3DDECLTYPE_USHORT4N
:
6843 return weld_ushort4n(to
, from
, epsilon
);
6845 case D3DDECLTYPE_UDEC3
:
6846 return weld_udec3(to
, from
, epsilon
);
6848 case D3DDECLTYPE_DEC3N
:
6849 return weld_dec3n(to
, from
, epsilon
);
6851 case D3DDECLTYPE_FLOAT16_2
:
6852 return weld_float16_2(to
, from
, epsilon
);
6854 case D3DDECLTYPE_FLOAT16_4
:
6855 return weld_float16_4(to
, from
, epsilon
);
6857 case D3DDECLTYPE_UNUSED
:
6858 if (!fixme_once_unused
++)
6859 FIXME("D3DDECLTYPE_UNUSED welding not implemented.\n");
6863 if (!fixme_once_unknown
++)
6864 FIXME("Welding of unknown declaration type %d is not implemented.\n", type
);
6871 static FLOAT
get_component_epsilon(const D3DVERTEXELEMENT9
*decl_ptr
, const D3DXWELDEPSILONS
*epsilons
)
6873 FLOAT epsilon
= 0.0f
;
6874 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6875 static BOOL fixme_once_blendindices
= FALSE
;
6876 static BOOL fixme_once_positiont
= FALSE
;
6877 static BOOL fixme_once_fog
= FALSE
;
6878 static BOOL fixme_once_depth
= FALSE
;
6879 static BOOL fixme_once_sample
= FALSE
;
6880 static BOOL fixme_once_unknown
= FALSE
;
6882 switch (decl_ptr
->Usage
)
6884 case D3DDECLUSAGE_POSITION
:
6885 epsilon
= epsilons
->Position
;
6887 case D3DDECLUSAGE_BLENDWEIGHT
:
6888 epsilon
= epsilons
->BlendWeights
;
6890 case D3DDECLUSAGE_NORMAL
:
6891 epsilon
= epsilons
->Normals
;
6893 case D3DDECLUSAGE_PSIZE
:
6894 epsilon
= epsilons
->PSize
;
6896 case D3DDECLUSAGE_TEXCOORD
:
6898 BYTE usage_index
= decl_ptr
->UsageIndex
;
6899 if (usage_index
> 7)
6901 epsilon
= epsilons
->Texcoords
[usage_index
];
6904 case D3DDECLUSAGE_TANGENT
:
6905 epsilon
= epsilons
->Tangent
;
6907 case D3DDECLUSAGE_BINORMAL
:
6908 epsilon
= epsilons
->Binormal
;
6910 case D3DDECLUSAGE_TESSFACTOR
:
6911 epsilon
= epsilons
->TessFactor
;
6913 case D3DDECLUSAGE_COLOR
:
6914 if (decl_ptr
->UsageIndex
== 0)
6915 epsilon
= epsilons
->Diffuse
;
6916 else if (decl_ptr
->UsageIndex
== 1)
6917 epsilon
= epsilons
->Specular
;
6921 case D3DDECLUSAGE_BLENDINDICES
:
6922 if (!fixme_once_blendindices
++)
6923 FIXME("D3DDECLUSAGE_BLENDINDICES welding not implemented.\n");
6925 case D3DDECLUSAGE_POSITIONT
:
6926 if (!fixme_once_positiont
++)
6927 FIXME("D3DDECLUSAGE_POSITIONT welding not implemented.\n");
6929 case D3DDECLUSAGE_FOG
:
6930 if (!fixme_once_fog
++)
6931 FIXME("D3DDECLUSAGE_FOG welding not implemented.\n");
6933 case D3DDECLUSAGE_DEPTH
:
6934 if (!fixme_once_depth
++)
6935 FIXME("D3DDECLUSAGE_DEPTH welding not implemented.\n");
6937 case D3DDECLUSAGE_SAMPLE
:
6938 if (!fixme_once_sample
++)
6939 FIXME("D3DDECLUSAGE_SAMPLE welding not implemented.\n");
6942 if (!fixme_once_unknown
++)
6943 FIXME("Unknown usage %x\n", decl_ptr
->Usage
);
6950 /* Helper function for reading a 32-bit index buffer. */
6951 static inline DWORD
read_ib(void *index_buffer
, BOOL indices_are_32bit
,
6954 if (indices_are_32bit
)
6956 DWORD
*indices
= index_buffer
;
6957 return indices
[index
];
6961 WORD
*indices
= index_buffer
;
6962 return indices
[index
];
6966 /* Helper function for writing to a 32-bit index buffer. */
6967 static inline void write_ib(void *index_buffer
, BOOL indices_are_32bit
,
6968 DWORD index
, DWORD value
)
6970 if (indices_are_32bit
)
6972 DWORD
*indices
= index_buffer
;
6973 indices
[index
] = value
;
6977 WORD
*indices
= index_buffer
;
6978 indices
[index
] = value
;
6982 /*************************************************************************
6983 * D3DXWeldVertices (D3DX9_36.@)
6985 * Welds together similar vertices. The similarity between vert-
6986 * ices can be the position and other components such as
6990 * mesh [I] Mesh which vertices will be welded together.
6991 * flags [I] D3DXWELDEPSILONSFLAGS specifying how to weld.
6992 * epsilons [I] How similar a component needs to be for welding.
6993 * adjacency [I] Which faces are adjacent to other faces.
6994 * adjacency_out [O] Updated adjacency after welding.
6995 * face_remap_out [O] Which faces the old faces have been mapped to.
6996 * vertex_remap_out [O] Which vertices the old vertices have been mapped to.
7000 * Failure: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
7003 * Attribute sorting not implemented.
7006 HRESULT WINAPI
D3DXWeldVertices(ID3DXMesh
*mesh
, DWORD flags
, const D3DXWELDEPSILONS
*epsilons
,
7007 const DWORD
*adjacency
, DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
7009 DWORD
*adjacency_generated
= NULL
;
7010 const DWORD
*adjacency_ptr
;
7011 DWORD
*attributes
= NULL
;
7012 const FLOAT DEFAULT_EPSILON
= 1.0e-6f
;
7015 void *indices
= NULL
;
7016 BOOL indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
7017 DWORD optimize_flags
;
7018 DWORD
*point_reps
= NULL
;
7019 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(mesh
);
7020 DWORD
*vertex_face_map
= NULL
;
7021 BYTE
*vertices
= NULL
;
7023 TRACE("mesh %p, flags %#x, epsilons %p, adjacency %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
7024 mesh
, flags
, epsilons
, adjacency
, adjacency_out
, face_remap_out
, vertex_remap_out
);
7028 WARN("No flags are undefined. Using D3DXWELDEPSILONS_WELDPARTIALMATCHES instead.\n");
7029 flags
= D3DXWELDEPSILONS_WELDPARTIALMATCHES
;
7032 if (adjacency
) /* Use supplied adjacency. */
7034 adjacency_ptr
= adjacency
;
7036 else /* Adjacency has to be generated. */
7038 adjacency_generated
= HeapAlloc(GetProcessHeap(), 0, 3 * This
->numfaces
* sizeof(*adjacency_generated
));
7039 if (!adjacency_generated
)
7041 ERR("Couldn't allocate memory for adjacency_generated.\n");
7045 hr
= mesh
->lpVtbl
->GenerateAdjacency(mesh
, DEFAULT_EPSILON
, adjacency_generated
);
7048 ERR("Couldn't generate adjacency.\n");
7051 adjacency_ptr
= adjacency_generated
;
7054 /* Point representation says which vertices can be replaced. */
7055 point_reps
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*point_reps
));
7059 ERR("Couldn't allocate memory for point_reps.\n");
7062 hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency_ptr
, point_reps
);
7065 ERR("ConvertAdjacencyToPointReps failed.\n");
7069 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
);
7072 ERR("Couldn't lock index buffer.\n");
7076 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, 0, &attributes
);
7079 ERR("Couldn't lock attribute buffer.\n");
7082 vertex_face_map
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*vertex_face_map
));
7083 if (!vertex_face_map
)
7086 ERR("Couldn't allocate memory for vertex_face_map.\n");
7089 /* Build vertex face map, so that a vertex's face can be looked up. */
7090 for (i
= 0; i
< This
->numfaces
; i
++)
7093 for (j
= 0; j
< 3; j
++)
7095 DWORD index
= read_ib(indices
, indices_are_32bit
, 3*i
+ j
);
7096 vertex_face_map
[index
] = i
;
7100 if (flags
& D3DXWELDEPSILONS_WELDPARTIALMATCHES
)
7102 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void**)&vertices
);
7105 ERR("Couldn't lock vertex buffer.\n");
7108 /* For each vertex that can be removed, compare its vertex components
7109 * with the vertex components from the vertex that can replace it. A
7110 * vertex is only fully replaced if all the components match and the
7111 * flag D3DXWELDEPSILONS_DONOTREMOVEVERTICES is not set, and they
7112 * belong to the same attribute group. Otherwise the vertex components
7113 * that are within epsilon are set to the same value.
7115 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
7117 D3DVERTEXELEMENT9
*decl_ptr
;
7118 DWORD vertex_size
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
7119 DWORD num_vertex_components
;
7122 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7124 for (decl_ptr
= This
->cached_declaration
, num_vertex_components
= 0; decl_ptr
->Stream
!= 0xFF; decl_ptr
++, num_vertex_components
++)
7126 BYTE
*to
= &vertices
[vertex_size
*index
+ decl_ptr
->Offset
];
7127 BYTE
*from
= &vertices
[vertex_size
*point_reps
[index
] + decl_ptr
->Offset
];
7128 FLOAT epsilon
= get_component_epsilon(decl_ptr
, epsilons
);
7130 /* Don't weld self */
7131 if (index
== point_reps
[index
])
7137 if (weld_component(to
, from
, decl_ptr
->Type
, epsilon
))
7141 all_match
= (num_vertex_components
== matches
);
7142 if (all_match
&& !(flags
& D3DXWELDEPSILONS_DONOTREMOVEVERTICES
))
7144 DWORD to_face
= vertex_face_map
[index
];
7145 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7146 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7148 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7151 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7154 else if (flags
& D3DXWELDEPSILONS_WELDALL
)
7156 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
7158 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7159 DWORD to_face
= vertex_face_map
[index
];
7160 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7161 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7163 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7166 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7168 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7171 /* Compact mesh using OptimizeInplace */
7172 optimize_flags
= D3DXMESHOPT_COMPACT
;
7173 hr
= mesh
->lpVtbl
->OptimizeInplace(mesh
, optimize_flags
, adjacency_ptr
, adjacency_out
, face_remap_out
, vertex_remap_out
);
7176 ERR("Couldn't compact mesh.\n");
7182 HeapFree(GetProcessHeap(), 0, adjacency_generated
);
7183 HeapFree(GetProcessHeap(), 0, point_reps
);
7184 HeapFree(GetProcessHeap(), 0, vertex_face_map
);
7185 if (attributes
) mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7186 if (indices
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7187 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7193 /*************************************************************************
7194 * D3DXOptimizeVertices (D3DX9_36.@)
7196 HRESULT WINAPI
D3DXOptimizeVertices(const void *indices
, UINT num_faces
,
7197 UINT num_vertices
, BOOL indices_are_32bit
, DWORD
*vertex_remap
)
7201 FIXME("indices %p, num_faces %u, num_vertices %u, indices_are_32bit %#x, vertex_remap %p semi-stub.\n",
7202 indices
, num_faces
, num_vertices
, indices_are_32bit
, vertex_remap
);
7206 WARN("vertex remap pointer is NULL.\n");
7207 return D3DERR_INVALIDCALL
;
7210 for (i
= 0; i
< num_vertices
; i
++)
7212 vertex_remap
[i
] = i
;
7219 /*************************************************************************
7220 * D3DXOptimizeFaces (D3DX9_36.@)
7222 * Re-orders the faces so the vertex cache is used optimally.
7225 * indices [I] Pointer to an index buffer belonging to a mesh.
7226 * num_faces [I] Number of faces in the mesh.
7227 * num_vertices [I] Number of vertices in the mesh.
7228 * indices_are_32bit [I] Specifies whether indices are 32- or 16-bit.
7229 * face_remap [I/O] The new order the faces should be drawn in.
7233 * Failure: D3DERR_INVALIDCALL.
7236 * The face re-ordering does not use the vertex cache optimally.
7239 HRESULT WINAPI
D3DXOptimizeFaces(const void *indices
, UINT num_faces
,
7240 UINT num_vertices
, BOOL indices_are_32bit
, DWORD
*face_remap
)
7243 UINT j
= num_faces
- 1;
7244 UINT limit_16_bit
= 2 << 15; /* According to MSDN */
7245 HRESULT hr
= D3D_OK
;
7247 FIXME("indices %p, num_faces %u, num_vertices %u, indices_are_32bit %#x, face_remap %p semi-stub. "
7248 "Face order will not be optimal.\n",
7249 indices
, num_faces
, num_vertices
, indices_are_32bit
, face_remap
);
7251 if (!indices_are_32bit
&& num_faces
>= limit_16_bit
)
7253 WARN("Number of faces must be less than %d when using 16-bit indices.\n",
7255 hr
= D3DERR_INVALIDCALL
;
7261 WARN("Face remap pointer is NULL.\n");
7262 hr
= D3DERR_INVALIDCALL
;
7266 /* The faces are drawn in reverse order for simple meshes. This ordering
7267 * is not optimal for complicated meshes, but will not break anything
7268 * either. The ordering should be changed to take advantage of the vertex
7269 * cache on the graphics card.
7271 * TODO Re-order to take advantage of vertex cache.
7273 for (i
= 0; i
< num_faces
; i
++)
7275 face_remap
[i
] = j
--;
7284 static D3DXVECTOR3
*vertex_element_vec3(BYTE
*vertices
, const D3DVERTEXELEMENT9
*declaration
,
7285 DWORD vertex_stride
, DWORD index
)
7287 return (D3DXVECTOR3
*)(vertices
+ declaration
->Offset
+ index
* vertex_stride
);
7290 static D3DXVECTOR3
read_vec3(BYTE
*vertices
, const D3DVERTEXELEMENT9
*declaration
,
7291 DWORD vertex_stride
, DWORD index
)
7293 D3DXVECTOR3 vec3
= {0};
7294 const D3DXVECTOR3
*src
= vertex_element_vec3(vertices
, declaration
, vertex_stride
, index
);
7296 switch (declaration
->Type
)
7298 case D3DDECLTYPE_FLOAT1
:
7301 case D3DDECLTYPE_FLOAT2
:
7305 case D3DDECLTYPE_FLOAT3
:
7306 case D3DDECLTYPE_FLOAT4
:
7310 ERR("Cannot read vec3\n");
7317 /*************************************************************************
7318 * D3DXComputeTangentFrameEx (D3DX9_36.@)
7320 HRESULT WINAPI
D3DXComputeTangentFrameEx(ID3DXMesh
*mesh
, DWORD texture_in_semantic
, DWORD texture_in_index
,
7321 DWORD u_partial_out_semantic
, DWORD u_partial_out_index
, DWORD v_partial_out_semantic
,
7322 DWORD v_partial_out_index
, DWORD normal_out_semantic
, DWORD normal_out_index
, DWORD options
,
7323 const DWORD
*adjacency
, float partial_edge_threshold
, float singular_point_threshold
,
7324 float normal_edge_threshold
, ID3DXMesh
**mesh_out
, ID3DXBuffer
**vertex_mapping
)
7327 void *indices
= NULL
;
7328 BYTE
*vertices
= NULL
;
7329 DWORD
*point_reps
= NULL
;
7331 BOOL indices_are_32bit
;
7332 DWORD i
, j
, num_faces
, num_vertices
, vertex_stride
;
7333 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
7334 D3DVERTEXELEMENT9
*position_declaration
= NULL
, *normal_declaration
= NULL
;
7335 DWORD weighting_method
= options
& (D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
);
7337 TRACE("mesh %p, texture_in_semantic %u, texture_in_index %u, u_partial_out_semantic %u, u_partial_out_index %u, "
7338 "v_partial_out_semantic %u, v_partial_out_index %u, normal_out_semantic %u, normal_out_index %u, "
7339 "options %#x, adjacency %p, partial_edge_threshold %f, singular_point_threshold %f, "
7340 "normal_edge_threshold %f, mesh_out %p, vertex_mapping %p\n",
7341 mesh
, texture_in_semantic
, texture_in_index
, u_partial_out_semantic
, u_partial_out_index
,
7342 v_partial_out_semantic
, v_partial_out_index
, normal_out_semantic
, normal_out_index
, options
, adjacency
,
7343 partial_edge_threshold
, singular_point_threshold
, normal_edge_threshold
, mesh_out
, vertex_mapping
);
7347 WARN("mesh is NULL\n");
7348 return D3DERR_INVALIDCALL
;
7351 if (weighting_method
== (D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
))
7353 WARN("D3DXTANGENT_WEIGHT_BY_AREA and D3DXTANGENT_WEIGHT_EQUAL are mutally exclusive\n");
7354 return D3DERR_INVALIDCALL
;
7357 if (u_partial_out_semantic
!= D3DX_DEFAULT
)
7359 FIXME("tangent vectors computation is not supported\n");
7363 if (v_partial_out_semantic
!= D3DX_DEFAULT
)
7365 FIXME("binormal vectors computation is not supported\n");
7369 if (options
& ~(D3DXTANGENT_GENERATE_IN_PLACE
| D3DXTANGENT_CALCULATE_NORMALS
| D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
))
7371 FIXME("unsupported options %#x\n", options
);
7375 if (!(options
& D3DXTANGENT_CALCULATE_NORMALS
))
7377 FIXME("only normals computation is supported\n");
7381 if (!(options
& D3DXTANGENT_GENERATE_IN_PLACE
) || mesh_out
|| vertex_mapping
)
7383 FIXME("only D3DXTANGENT_GENERATE_IN_PLACE is supported\n");
7387 if (FAILED(hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, declaration
)))
7390 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
7392 if (declaration
[i
].Usage
== D3DDECLUSAGE_POSITION
&& !declaration
[i
].UsageIndex
)
7393 position_declaration
= &declaration
[i
];
7394 if (declaration
[i
].Usage
== normal_out_semantic
&& declaration
[i
].UsageIndex
== normal_out_index
)
7395 normal_declaration
= &declaration
[i
];
7398 if (!position_declaration
|| !normal_declaration
)
7399 return D3DERR_INVALIDCALL
;
7401 if (normal_declaration
->Type
== D3DDECLTYPE_FLOAT3
)
7403 normal_size
= sizeof(D3DXVECTOR3
);
7405 else if (normal_declaration
->Type
== D3DDECLTYPE_FLOAT4
)
7407 normal_size
= sizeof(D3DXVECTOR4
);
7411 WARN("unsupported normals type %u\n", normal_declaration
->Type
);
7412 return D3DERR_INVALIDCALL
;
7415 num_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
7416 num_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
7417 vertex_stride
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
7418 indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
7420 point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*point_reps
));
7429 if (FAILED(hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency
, point_reps
)))
7434 for (i
= 0; i
< num_vertices
; i
++)
7438 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
)))
7441 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
7444 for (i
= 0; i
< num_vertices
; i
++)
7446 static const D3DXVECTOR4 default_vector
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
7447 void *normal
= vertices
+ normal_declaration
->Offset
+ i
* vertex_stride
;
7449 memcpy(normal
, &default_vector
, normal_size
);
7452 for (i
= 0; i
< num_faces
; i
++)
7454 float denominator
, weights
[3];
7455 D3DXVECTOR3 a
, b
, cross
, face_normal
;
7456 const DWORD face_indices
[3] =
7458 read_ib(indices
, indices_are_32bit
, 3 * i
+ 0),
7459 read_ib(indices
, indices_are_32bit
, 3 * i
+ 1),
7460 read_ib(indices
, indices_are_32bit
, 3 * i
+ 2)
7462 const D3DXVECTOR3 v0
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[0]);
7463 const D3DXVECTOR3 v1
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[1]);
7464 const D3DXVECTOR3 v2
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[2]);
7466 D3DXVec3Cross(&cross
, D3DXVec3Subtract(&a
, &v0
, &v1
), D3DXVec3Subtract(&b
, &v0
, &v2
));
7468 switch (weighting_method
)
7470 case D3DXTANGENT_WEIGHT_EQUAL
:
7471 weights
[0] = weights
[1] = weights
[2] = 1.0f
;
7473 case D3DXTANGENT_WEIGHT_BY_AREA
:
7474 weights
[0] = weights
[1] = weights
[2] = D3DXVec3Length(&cross
);
7477 /* weight by angle */
7478 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7482 weights
[0] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7484 D3DXVec3Subtract(&a
, &v1
, &v0
);
7485 D3DXVec3Subtract(&b
, &v1
, &v2
);
7486 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7490 weights
[1] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7492 D3DXVec3Subtract(&a
, &v2
, &v0
);
7493 D3DXVec3Subtract(&b
, &v2
, &v1
);
7494 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7498 weights
[2] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7503 D3DXVec3Normalize(&face_normal
, &cross
);
7505 for (j
= 0; j
< 3; j
++)
7508 DWORD rep_index
= point_reps
[face_indices
[j
]];
7509 D3DXVECTOR3
*rep_normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, rep_index
);
7511 D3DXVec3Scale(&normal
, &face_normal
, weights
[j
]);
7512 D3DXVec3Add(rep_normal
, rep_normal
, &normal
);
7516 for (i
= 0; i
< num_vertices
; i
++)
7518 DWORD rep_index
= point_reps
[i
];
7519 D3DXVECTOR3
*normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, i
);
7520 D3DXVECTOR3
*rep_normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, rep_index
);
7523 D3DXVec3Normalize(rep_normal
, rep_normal
);
7525 *normal
= *rep_normal
;
7532 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7535 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7537 HeapFree(GetProcessHeap(), 0, point_reps
);
7542 /*************************************************************************
7543 * D3DXComputeTangent (D3DX9_36.@)
7545 HRESULT WINAPI
D3DXComputeTangent(ID3DXMesh
*mesh
, DWORD stage_idx
, DWORD tangent_idx
,
7546 DWORD binorm_idx
, DWORD wrap
, const DWORD
*adjacency
)
7548 TRACE("mesh %p, stage_idx %d, tangent_idx %d, binorm_idx %d, wrap %d, adjacency %p.\n",
7549 mesh
, stage_idx
, tangent_idx
, binorm_idx
, wrap
, adjacency
);
7551 return D3DXComputeTangentFrameEx( mesh
, D3DDECLUSAGE_TEXCOORD
, stage_idx
,
7552 ( binorm_idx
== D3DX_DEFAULT
) ? D3DX_DEFAULT
: D3DDECLUSAGE_BINORMAL
,
7554 ( tangent_idx
== D3DX_DEFAULT
) ? D3DX_DEFAULT
: D3DDECLUSAGE_TANGENT
,
7555 tangent_idx
, D3DX_DEFAULT
, 0,
7556 ( wrap
? D3DXTANGENT_WRAP_UV
: 0 ) | D3DXTANGENT_GENERATE_IN_PLACE
| D3DXTANGENT_ORTHOGONALIZE_FROM_U
,
7557 adjacency
, -1.01f
, -0.01f
, -1.01f
, NULL
, NULL
);
7560 /*************************************************************************
7561 * D3DXComputeNormals (D3DX9_36.@)
7563 HRESULT WINAPI
D3DXComputeNormals(struct ID3DXBaseMesh
*mesh
, const DWORD
*adjacency
)
7565 TRACE("mesh %p, adjacency %p\n", mesh
, adjacency
);
7567 if (mesh
&& (ID3DXMeshVtbl
*)mesh
->lpVtbl
!= &D3DXMesh_Vtbl
)
7569 ERR("Invalid virtual table\n");
7570 return D3DERR_INVALIDCALL
;
7573 return D3DXComputeTangentFrameEx((ID3DXMesh
*)mesh
, D3DX_DEFAULT
, 0,
7574 D3DX_DEFAULT
, 0, D3DX_DEFAULT
, 0, D3DDECLUSAGE_NORMAL
, 0,
7575 D3DXTANGENT_GENERATE_IN_PLACE
| D3DXTANGENT_CALCULATE_NORMALS
,
7576 adjacency
, -1.01f
, -0.01f
, -1.01f
, NULL
, NULL
);
7579 /*************************************************************************
7580 * D3DXIntersect (D3DX9_36.@)
7582 HRESULT WINAPI
D3DXIntersect(ID3DXBaseMesh
*mesh
, const D3DXVECTOR3
*ray_pos
, const D3DXVECTOR3
*ray_dir
,
7583 BOOL
*hit
, DWORD
*face_index
, float *u
, float *v
, float *distance
, ID3DXBuffer
**all_hits
, DWORD
*count_of_hits
)
7585 FIXME("mesh %p, ray_pos %p, ray_dir %p, hit %p, face_index %p, u %p, v %p, distance %p, all_hits %p, "
7586 "count_of_hits %p stub!\n", mesh
, ray_pos
, ray_dir
, hit
, face_index
, u
, v
, distance
, all_hits
, count_of_hits
);
7591 HRESULT WINAPI
D3DXTessellateNPatches(ID3DXMesh
*mesh
, const DWORD
*adjacency_in
, float num_segs
,
7592 BOOL quadratic_normals
, ID3DXMesh
**mesh_out
, ID3DXBuffer
**adjacency_out
)
7594 FIXME("mesh %p, adjacency_in %p, num_segs %f, quadratic_normals %d, mesh_out %p, adjacency_out %p stub.\n",
7595 mesh
, adjacency_in
, num_segs
, quadratic_normals
, mesh_out
, adjacency_out
);
7600 HRESULT WINAPI
D3DXConvertMeshSubsetToSingleStrip(struct ID3DXBaseMesh
*mesh_in
, DWORD attribute_id
,
7601 DWORD ib_flags
, struct IDirect3DIndexBuffer9
**index_buffer
, DWORD
*index_count
)
7603 FIXME("mesh_in %p, attribute_id %u, ib_flags %u, index_buffer %p, index_count %p stub.\n",
7604 mesh_in
, attribute_id
, ib_flags
, index_buffer
, index_count
);
7615 static BOOL
queue_frame_node(struct list
*queue
, D3DXFRAME
*frame
)
7617 struct frame_node
*node
;
7619 if (!frame
->pFrameFirstChild
)
7622 node
= HeapAlloc(GetProcessHeap(), 0, sizeof(*node
));
7626 node
->frame
= frame
;
7627 list_add_tail(queue
, &node
->entry
);
7632 static void empty_frame_queue(struct list
*queue
)
7634 struct frame_node
*cur
, *cur2
;
7635 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, queue
, struct frame_node
, entry
)
7637 list_remove(&cur
->entry
);
7638 HeapFree(GetProcessHeap(), 0, cur
);
7642 D3DXFRAME
* WINAPI
D3DXFrameFind(const D3DXFRAME
*root
, const char *name
)
7644 D3DXFRAME
*found
= NULL
, *frame
;
7647 TRACE("root frame %p, name %s.\n", root
, debugstr_a(name
));
7654 frame
= (D3DXFRAME
*)root
;
7658 struct frame_node
*node
;
7662 if ((name
&& frame
->Name
&& !strcmp(frame
->Name
, name
)) || (!name
&& !frame
->Name
))
7668 if (!queue_frame_node(&queue
, frame
))
7671 frame
= frame
->pFrameSibling
;
7674 if (list_empty(&queue
))
7677 node
= LIST_ENTRY(list_head(&queue
), struct frame_node
, entry
);
7678 list_remove(&node
->entry
);
7679 frame
= node
->frame
->pFrameFirstChild
;
7680 HeapFree(GetProcessHeap(), 0, node
);
7684 empty_frame_queue(&queue
);