2 * Mesh operations specific to D3DX9.
4 * Copyright (C) 2005 Henri Verbeet
5 * Copyright (C) 2006 Ivan Gyurdiev
6 * Copyright (C) 2009 David Adam
7 * Copyright (C) 2010 Tony Wasserka
8 * Copyright (C) 2011 Dylan Smith
9 * Copyright (C) 2011 Michael Mc Donnell
10 * Copyright (C) 2013 Christian Costa
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "d3dx9_36_private.h"
38 #include "wine/list.h"
42 ID3DXMesh ID3DXMesh_iface
;
49 IDirect3DDevice9
*device
;
50 D3DVERTEXELEMENT9 cached_declaration
[MAX_FVF_DECL_SIZE
];
51 IDirect3DVertexDeclaration9
*vertex_declaration
;
52 UINT vertex_declaration_size
;
54 IDirect3DVertexBuffer9
*vertex_buffer
;
55 IDirect3DIndexBuffer9
*index_buffer
;
57 int attrib_buffer_lock_count
;
58 DWORD attrib_table_size
;
59 D3DXATTRIBUTERANGE
*attrib_table
;
62 const UINT d3dx_decltype_size
[] =
64 /* D3DDECLTYPE_FLOAT1 */ sizeof(FLOAT
),
65 /* D3DDECLTYPE_FLOAT2 */ sizeof(D3DXVECTOR2
),
66 /* D3DDECLTYPE_FLOAT3 */ sizeof(D3DXVECTOR3
),
67 /* D3DDECLTYPE_FLOAT4 */ sizeof(D3DXVECTOR4
),
68 /* D3DDECLTYPE_D3DCOLOR */ sizeof(D3DCOLOR
),
69 /* D3DDECLTYPE_UBYTE4 */ 4 * sizeof(BYTE
),
70 /* D3DDECLTYPE_SHORT2 */ 2 * sizeof(SHORT
),
71 /* D3DDECLTYPE_SHORT4 */ 4 * sizeof(SHORT
),
72 /* D3DDECLTYPE_UBYTE4N */ 4 * sizeof(BYTE
),
73 /* D3DDECLTYPE_SHORT2N */ 2 * sizeof(SHORT
),
74 /* D3DDECLTYPE_SHORT4N */ 4 * sizeof(SHORT
),
75 /* D3DDECLTYPE_USHORT2N */ 2 * sizeof(USHORT
),
76 /* D3DDECLTYPE_USHORT4N */ 4 * sizeof(USHORT
),
77 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
78 /* D3DDECLTYPE_DEC3N */ 4,
79 /* D3DDECLTYPE_FLOAT16_2 */ 2 * sizeof(D3DXFLOAT16
),
80 /* D3DDECLTYPE_FLOAT16_4 */ 4 * sizeof(D3DXFLOAT16
),
83 static inline struct d3dx9_mesh
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
85 return CONTAINING_RECORD(iface
, struct d3dx9_mesh
, ID3DXMesh_iface
);
88 static HRESULT WINAPI
d3dx9_mesh_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, void **out
)
90 TRACE("iface %p, riid %s, out %p.\n", iface
, debugstr_guid(riid
), out
);
92 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
93 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
94 IsEqualGUID(riid
, &IID_ID3DXMesh
))
96 iface
->lpVtbl
->AddRef(iface
);
101 WARN("Interface %s not found.\n", debugstr_guid(riid
));
103 return E_NOINTERFACE
;
106 static ULONG WINAPI
d3dx9_mesh_AddRef(ID3DXMesh
*iface
)
108 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
109 ULONG refcount
= InterlockedIncrement(&mesh
->ref
);
111 TRACE("%p increasing refcount to %u.\n", mesh
, refcount
);
116 static ULONG WINAPI
d3dx9_mesh_Release(ID3DXMesh
*iface
)
118 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
119 ULONG refcount
= InterlockedDecrement(&mesh
->ref
);
121 TRACE("%p decreasing refcount to %u.\n", mesh
, refcount
);
125 IDirect3DIndexBuffer9_Release(mesh
->index_buffer
);
126 IDirect3DVertexBuffer9_Release(mesh
->vertex_buffer
);
127 if (mesh
->vertex_declaration
)
128 IDirect3DVertexDeclaration9_Release(mesh
->vertex_declaration
);
129 IDirect3DDevice9_Release(mesh
->device
);
130 HeapFree(GetProcessHeap(), 0, mesh
->attrib_buffer
);
131 HeapFree(GetProcessHeap(), 0, mesh
->attrib_table
);
132 HeapFree(GetProcessHeap(), 0, mesh
);
138 static HRESULT WINAPI
d3dx9_mesh_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
140 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
146 TRACE("iface %p, attrib_id %u.\n", iface
, attrib_id
);
148 if (!This
->vertex_declaration
)
150 WARN("Can't draw a mesh with an invalid vertex declaration.\n");
154 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
156 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
157 if (FAILED(hr
)) return hr
;
158 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
159 if (FAILED(hr
)) return hr
;
160 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
161 if (FAILED(hr
)) return hr
;
163 while (face_end
< This
->numfaces
)
165 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
167 if (This
->attrib_buffer
[face_start
] == attrib_id
)
170 if (face_start
>= This
->numfaces
)
172 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
174 if (This
->attrib_buffer
[face_end
] != attrib_id
)
178 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
179 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
180 if (FAILED(hr
)) return hr
;
186 static DWORD WINAPI
d3dx9_mesh_GetNumFaces(ID3DXMesh
*iface
)
188 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
190 TRACE("iface %p.\n", iface
);
192 return mesh
->numfaces
;
195 static DWORD WINAPI
d3dx9_mesh_GetNumVertices(ID3DXMesh
*iface
)
197 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
199 TRACE("iface %p.\n", iface
);
201 return mesh
->numvertices
;
204 static DWORD WINAPI
d3dx9_mesh_GetFVF(ID3DXMesh
*iface
)
206 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
208 TRACE("iface %p.\n", iface
);
213 static void copy_declaration(D3DVERTEXELEMENT9
*dst
, const D3DVERTEXELEMENT9
*src
, UINT num_elem
)
215 memcpy(dst
, src
, num_elem
* sizeof(*src
));
218 static HRESULT WINAPI
d3dx9_mesh_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
220 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
222 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
225 return D3DERR_INVALIDCALL
;
227 copy_declaration(declaration
, mesh
->cached_declaration
, mesh
->num_elem
);
232 static DWORD WINAPI
d3dx9_mesh_GetNumBytesPerVertex(ID3DXMesh
*iface
)
234 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
236 TRACE("iface %p.\n", iface
);
238 return mesh
->vertex_declaration_size
;
241 static DWORD WINAPI
d3dx9_mesh_GetOptions(ID3DXMesh
*iface
)
243 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
245 TRACE("iface %p.\n", iface
);
247 return mesh
->options
;
250 static HRESULT WINAPI
d3dx9_mesh_GetDevice(struct ID3DXMesh
*iface
, struct IDirect3DDevice9
**device
)
252 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
254 TRACE("iface %p, device %p.\n", iface
, device
);
257 return D3DERR_INVALIDCALL
;
258 *device
= mesh
->device
;
259 IDirect3DDevice9_AddRef(mesh
->device
);
264 static HRESULT WINAPI
d3dx9_mesh_CloneMeshFVF(struct ID3DXMesh
*iface
, DWORD options
, DWORD fvf
,
265 struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh
)
268 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
270 TRACE("iface %p, options %#x, fvf %#x, device %p, clone_mesh %p.\n",
271 iface
, options
, fvf
, device
, clone_mesh
);
273 if (FAILED(hr
= D3DXDeclaratorFromFVF(fvf
, declaration
)))
276 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
279 static FLOAT
scale_clamp_ubyten(FLOAT value
)
281 value
= value
* UCHAR_MAX
;
289 if (value
> UCHAR_MAX
) /* Clamp at 255 */
296 static FLOAT
scale_clamp_shortn(FLOAT value
)
298 value
= value
* SHRT_MAX
;
300 /* The tests show that the range is SHRT_MIN + 1 to SHRT_MAX. */
301 if (value
<= SHRT_MIN
)
305 else if (value
> SHRT_MAX
)
315 static FLOAT
scale_clamp_ushortn(FLOAT value
)
317 value
= value
* USHRT_MAX
;
325 if (value
> USHRT_MAX
) /* Clamp at 65535 */
332 static INT
simple_round(FLOAT value
)
334 int res
= (INT
)(value
+ 0.5f
);
339 static void convert_float4(BYTE
*dst
, const D3DXVECTOR4
*src
, D3DDECLTYPE type_dst
)
341 BOOL fixme_once
= FALSE
;
345 case D3DDECLTYPE_FLOAT1
:
347 FLOAT
*dst_ptr
= (FLOAT
*)dst
;
351 case D3DDECLTYPE_FLOAT2
:
353 D3DXVECTOR2
*dst_ptr
= (D3DXVECTOR2
*)dst
;
358 case D3DDECLTYPE_FLOAT3
:
360 D3DXVECTOR3
*dst_ptr
= (D3DXVECTOR3
*)dst
;
366 case D3DDECLTYPE_FLOAT4
:
368 D3DXVECTOR4
*dst_ptr
= (D3DXVECTOR4
*)dst
;
375 case D3DDECLTYPE_D3DCOLOR
:
377 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
378 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
379 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
380 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
383 case D3DDECLTYPE_UBYTE4
:
385 dst
[0] = src
->x
< 0.0f
? 0 : (BYTE
)simple_round(src
->x
);
386 dst
[1] = src
->y
< 0.0f
? 0 : (BYTE
)simple_round(src
->y
);
387 dst
[2] = src
->z
< 0.0f
? 0 : (BYTE
)simple_round(src
->z
);
388 dst
[3] = src
->w
< 0.0f
? 0 : (BYTE
)simple_round(src
->w
);
391 case D3DDECLTYPE_SHORT2
:
393 SHORT
*dst_ptr
= (SHORT
*)dst
;
394 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
395 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
398 case D3DDECLTYPE_SHORT4
:
400 SHORT
*dst_ptr
= (SHORT
*)dst
;
401 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
402 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
403 dst_ptr
[2] = (SHORT
)simple_round(src
->z
);
404 dst_ptr
[3] = (SHORT
)simple_round(src
->w
);
407 case D3DDECLTYPE_UBYTE4N
:
409 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
410 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
411 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
412 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
415 case D3DDECLTYPE_SHORT2N
:
417 SHORT
*dst_ptr
= (SHORT
*)dst
;
418 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
419 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
422 case D3DDECLTYPE_SHORT4N
:
424 SHORT
*dst_ptr
= (SHORT
*)dst
;
425 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
426 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
427 dst_ptr
[2] = (SHORT
)simple_round(scale_clamp_shortn(src
->z
));
428 dst_ptr
[3] = (SHORT
)simple_round(scale_clamp_shortn(src
->w
));
431 case D3DDECLTYPE_USHORT2N
:
433 USHORT
*dst_ptr
= (USHORT
*)dst
;
434 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
435 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
438 case D3DDECLTYPE_USHORT4N
:
440 USHORT
*dst_ptr
= (USHORT
*)dst
;
441 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
442 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
443 dst_ptr
[2] = (USHORT
)simple_round(scale_clamp_ushortn(src
->z
));
444 dst_ptr
[3] = (USHORT
)simple_round(scale_clamp_ushortn(src
->w
));
447 case D3DDECLTYPE_FLOAT16_2
:
449 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 2);
452 case D3DDECLTYPE_FLOAT16_4
:
454 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 4);
459 FIXME("Conversion from D3DDECLTYPE_FLOAT4 to %d not implemented.\n", type_dst
);
464 static void convert_component(BYTE
*dst
, BYTE
*src
, D3DDECLTYPE type_dst
, D3DDECLTYPE type_src
)
466 BOOL fixme_once
= FALSE
;
470 case D3DDECLTYPE_FLOAT1
:
472 FLOAT
*src_ptr
= (FLOAT
*)src
;
473 D3DXVECTOR4 src_float4
= {*src_ptr
, 0.0f
, 0.0f
, 1.0f
};
474 convert_float4(dst
, &src_float4
, type_dst
);
477 case D3DDECLTYPE_FLOAT2
:
479 D3DXVECTOR2
*src_ptr
= (D3DXVECTOR2
*)src
;
480 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, 0.0f
, 1.0f
};
481 convert_float4(dst
, &src_float4
, type_dst
);
484 case D3DDECLTYPE_FLOAT3
:
486 D3DXVECTOR3
*src_ptr
= (D3DXVECTOR3
*)src
;
487 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, 1.0f
};
488 convert_float4(dst
, &src_float4
, type_dst
);
491 case D3DDECLTYPE_FLOAT4
:
493 D3DXVECTOR4
*src_ptr
= (D3DXVECTOR4
*)src
;
494 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, src_ptr
->w
};
495 convert_float4(dst
, &src_float4
, type_dst
);
498 case D3DDECLTYPE_D3DCOLOR
:
500 D3DXVECTOR4 src_float4
=
502 (FLOAT
)src
[2]/UCHAR_MAX
,
503 (FLOAT
)src
[1]/UCHAR_MAX
,
504 (FLOAT
)src
[0]/UCHAR_MAX
,
505 (FLOAT
)src
[3]/UCHAR_MAX
507 convert_float4(dst
, &src_float4
, type_dst
);
510 case D3DDECLTYPE_UBYTE4
:
512 D3DXVECTOR4 src_float4
= {src
[0], src
[1], src
[2], src
[3]};
513 convert_float4(dst
, &src_float4
, type_dst
);
516 case D3DDECLTYPE_SHORT2
:
518 SHORT
*src_ptr
= (SHORT
*)src
;
519 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], 0.0f
, 1.0f
};
520 convert_float4(dst
, &src_float4
, type_dst
);
523 case D3DDECLTYPE_SHORT4
:
525 SHORT
*src_ptr
= (SHORT
*)src
;
526 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], src_ptr
[2], src_ptr
[3]};
527 convert_float4(dst
, &src_float4
, type_dst
);
530 case D3DDECLTYPE_UBYTE4N
:
532 D3DXVECTOR4 src_float4
=
534 (FLOAT
)src
[0]/UCHAR_MAX
,
535 (FLOAT
)src
[1]/UCHAR_MAX
,
536 (FLOAT
)src
[2]/UCHAR_MAX
,
537 (FLOAT
)src
[3]/UCHAR_MAX
539 convert_float4(dst
, &src_float4
, type_dst
);
542 case D3DDECLTYPE_SHORT2N
:
544 SHORT
*src_ptr
= (SHORT
*)src
;
545 D3DXVECTOR4 src_float4
= {(FLOAT
)src_ptr
[0]/SHRT_MAX
, (FLOAT
)src_ptr
[1]/SHRT_MAX
, 0.0f
, 1.0f
};
546 convert_float4(dst
, &src_float4
, type_dst
);
549 case D3DDECLTYPE_SHORT4N
:
551 SHORT
*src_ptr
= (SHORT
*)src
;
552 D3DXVECTOR4 src_float4
=
554 (FLOAT
)src_ptr
[0]/SHRT_MAX
,
555 (FLOAT
)src_ptr
[1]/SHRT_MAX
,
556 (FLOAT
)src_ptr
[2]/SHRT_MAX
,
557 (FLOAT
)src_ptr
[3]/SHRT_MAX
559 convert_float4(dst
, &src_float4
, type_dst
);
562 case D3DDECLTYPE_FLOAT16_2
:
564 D3DXVECTOR4 src_float4
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
565 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 2);
566 convert_float4(dst
, &src_float4
, type_dst
);
569 case D3DDECLTYPE_FLOAT16_4
:
571 D3DXVECTOR4 src_float4
;
572 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 4);
573 convert_float4(dst
, &src_float4
, type_dst
);
578 FIXME("Conversion of D3DDECLTYPE %d to %d not implemented.\n", type_src
, type_dst
);
583 static INT
get_equivalent_declaration_index(D3DVERTEXELEMENT9 orig_declaration
, D3DVERTEXELEMENT9
*declaration
)
587 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
589 if (orig_declaration
.Usage
== declaration
[i
].Usage
590 && orig_declaration
.UsageIndex
== declaration
[i
].UsageIndex
)
599 static HRESULT
convert_vertex_buffer(ID3DXMesh
*mesh_dst
, ID3DXMesh
*mesh_src
)
602 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
603 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
607 UINT num_vertices
= mesh_src
->lpVtbl
->GetNumVertices(mesh_src
);
608 UINT dst_vertex_size
= mesh_dst
->lpVtbl
->GetNumBytesPerVertex(mesh_dst
);
609 UINT src_vertex_size
= mesh_src
->lpVtbl
->GetNumBytesPerVertex(mesh_src
);
611 hr
= mesh_src
->lpVtbl
->GetDeclaration(mesh_src
, orig_declaration
);
612 if (FAILED(hr
)) return hr
;
613 hr
= mesh_dst
->lpVtbl
->GetDeclaration(mesh_dst
, declaration
);
614 if (FAILED(hr
)) return hr
;
616 hr
= mesh_src
->lpVtbl
->LockVertexBuffer(mesh_src
, D3DLOCK_READONLY
, (void**)&vb_src
);
617 if (FAILED(hr
)) goto cleanup
;
618 hr
= mesh_dst
->lpVtbl
->LockVertexBuffer(mesh_dst
, 0, (void**)&vb_dst
);
619 if (FAILED(hr
)) goto cleanup
;
621 /* Clear all new fields by clearing the entire vertex buffer. */
622 memset(vb_dst
, 0, num_vertices
* dst_vertex_size
);
624 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++)
626 INT eq_idx
= get_equivalent_declaration_index(orig_declaration
[i
], declaration
);
631 for (j
= 0; j
< num_vertices
; j
++)
633 UINT idx_dst
= dst_vertex_size
* j
+ declaration
[eq_idx
].Offset
;
634 UINT idx_src
= src_vertex_size
* j
+ orig_declaration
[i
].Offset
;
635 UINT type_size
= d3dx_decltype_size
[orig_declaration
[i
].Type
];
637 if (orig_declaration
[i
].Type
== declaration
[eq_idx
].Type
)
638 memcpy(&vb_dst
[idx_dst
], &vb_src
[idx_src
], type_size
);
640 convert_component(&vb_dst
[idx_dst
], &vb_src
[idx_src
], declaration
[eq_idx
].Type
, orig_declaration
[i
].Type
);
647 if (vb_dst
) mesh_dst
->lpVtbl
->UnlockVertexBuffer(mesh_dst
);
648 if (vb_src
) mesh_src
->lpVtbl
->UnlockVertexBuffer(mesh_src
);
653 static BOOL
declaration_equals(const D3DVERTEXELEMENT9
*declaration1
, const D3DVERTEXELEMENT9
*declaration2
)
655 UINT size1
= 0, size2
= 0;
657 /* Find the size of each declaration */
658 while (declaration1
[size1
].Stream
!= 0xff) size1
++;
659 while (declaration2
[size2
].Stream
!= 0xff) size2
++;
661 /* If not same size then they are definitely not equal */
665 /* Check that all components are the same */
666 if (memcmp(declaration1
, declaration2
, size1
*sizeof(*declaration1
)) == 0)
672 static HRESULT WINAPI
d3dx9_mesh_CloneMesh(struct ID3DXMesh
*iface
, DWORD options
,
673 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh_out
)
675 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
676 struct d3dx9_mesh
*cloned_this
;
677 ID3DXMesh
*clone_mesh
;
678 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
679 void *data_in
, *data_out
;
682 BOOL same_declaration
;
684 TRACE("iface %p, options %#x, declaration %p, device %p, clone_mesh_out %p.\n",
685 iface
, options
, declaration
, device
, clone_mesh_out
);
688 return D3DERR_INVALIDCALL
;
690 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
691 if (FAILED(hr
)) return hr
;
693 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
694 declaration
, device
, &clone_mesh
);
695 if (FAILED(hr
)) return hr
;
697 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
698 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
699 same_declaration
= declaration_equals(declaration
, orig_declaration
);
701 if (options
& D3DXMESH_VB_SHARE
) {
702 if (!same_declaration
) {
703 hr
= D3DERR_INVALIDCALL
;
706 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
707 /* FIXME: refactor to avoid creating a new vertex buffer */
708 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
709 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
710 } else if (same_declaration
) {
711 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
712 if (FAILED(hr
)) goto error
;
713 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, 0, &data_out
);
715 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
718 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
719 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
720 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
722 hr
= convert_vertex_buffer(clone_mesh
, iface
);
723 if (FAILED(hr
)) goto error
;
726 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
727 if (FAILED(hr
)) goto error
;
728 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, 0, &data_out
);
730 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
733 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
735 if (options
& D3DXMESH_32BIT
) {
736 for (i
= 0; i
< This
->numfaces
* 3; i
++)
737 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
739 for (i
= 0; i
< This
->numfaces
* 3; i
++)
740 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
743 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
745 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
746 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
748 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
750 if (This
->attrib_table_size
)
752 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
753 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
754 if (!cloned_this
->attrib_table
) {
758 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
761 *clone_mesh_out
= clone_mesh
;
765 IUnknown_Release(clone_mesh
);
769 static HRESULT WINAPI
d3dx9_mesh_GetVertexBuffer(struct ID3DXMesh
*iface
,
770 struct IDirect3DVertexBuffer9
**vertex_buffer
)
772 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
774 TRACE("iface %p, vertex_buffer %p.\n", iface
, vertex_buffer
);
777 return D3DERR_INVALIDCALL
;
778 *vertex_buffer
= mesh
->vertex_buffer
;
779 IDirect3DVertexBuffer9_AddRef(mesh
->vertex_buffer
);
784 static HRESULT WINAPI
d3dx9_mesh_GetIndexBuffer(struct ID3DXMesh
*iface
,
785 struct IDirect3DIndexBuffer9
**index_buffer
)
787 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
789 TRACE("iface %p, index_buffer %p.\n", iface
, index_buffer
);
792 return D3DERR_INVALIDCALL
;
793 *index_buffer
= mesh
->index_buffer
;
794 IDirect3DIndexBuffer9_AddRef(mesh
->index_buffer
);
799 static HRESULT WINAPI
d3dx9_mesh_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
801 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
803 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
805 return IDirect3DVertexBuffer9_Lock(mesh
->vertex_buffer
, 0, 0, data
, flags
);
808 static HRESULT WINAPI
d3dx9_mesh_UnlockVertexBuffer(ID3DXMesh
*iface
)
810 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
812 TRACE("iface %p.\n", iface
);
814 return IDirect3DVertexBuffer9_Unlock(mesh
->vertex_buffer
);
817 static HRESULT WINAPI
d3dx9_mesh_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
819 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
821 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
823 return IDirect3DIndexBuffer9_Lock(mesh
->index_buffer
, 0, 0, data
, flags
);
826 static HRESULT WINAPI
d3dx9_mesh_UnlockIndexBuffer(ID3DXMesh
*iface
)
828 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
830 TRACE("iface %p.\n", iface
);
832 return IDirect3DIndexBuffer9_Unlock(mesh
->index_buffer
);
835 /* FIXME: This looks just wrong, we never check *attrib_table_size before
836 * copying the data. */
837 static HRESULT WINAPI
d3dx9_mesh_GetAttributeTable(ID3DXMesh
*iface
,
838 D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
840 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
842 TRACE("iface %p, attrib_table %p, attrib_table_size %p.\n",
843 iface
, attrib_table
, attrib_table_size
);
845 if (attrib_table_size
)
846 *attrib_table_size
= mesh
->attrib_table_size
;
849 memcpy(attrib_table
, mesh
->attrib_table
, mesh
->attrib_table_size
* sizeof(*attrib_table
));
864 struct edge_face
*entries
;
867 /* Builds up a map of which face a new edge belongs to. That way the adjacency
868 * of another edge can be looked up. An edge has an adjacent face if there
869 * is an edge going in the opposite direction in the map. For example if the
870 * edge (v1, v2) belongs to face 4, and there is a mapping (v2, v1)->7, then
871 * face 4 and 7 are adjacent.
873 * Each edge might have been replaced with another edge, or none at all. There
874 * is at most one edge to face mapping, i.e. an edge can only belong to one
877 static HRESULT
init_edge_face_map(struct edge_face_map
*edge_face_map
, const DWORD
*index_buffer
,
878 const DWORD
*point_reps
, DWORD num_faces
)
883 edge_face_map
->lists
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->lists
));
884 if (!edge_face_map
->lists
) return E_OUTOFMEMORY
;
886 edge_face_map
->entries
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->entries
));
887 if (!edge_face_map
->entries
) return E_OUTOFMEMORY
;
890 /* Initialize all lists */
891 for (i
= 0; i
< 3 * num_faces
; i
++)
893 list_init(&edge_face_map
->lists
[i
]);
895 /* Build edge face mapping */
896 for (face
= 0; face
< num_faces
; face
++)
898 for (edge
= 0; edge
< 3; edge
++)
900 DWORD v1
= index_buffer
[3*face
+ edge
];
901 DWORD v2
= index_buffer
[3*face
+ (edge
+1)%3];
902 DWORD new_v1
= point_reps
[v1
]; /* What v1 has been replaced with */
903 DWORD new_v2
= point_reps
[v2
];
905 if (v1
!= v2
) /* Only map non-collapsed edges */
908 edge_face_map
->entries
[i
].v2
= new_v2
;
909 edge_face_map
->entries
[i
].face
= face
;
910 list_add_head(&edge_face_map
->lists
[new_v1
], &edge_face_map
->entries
[i
].entry
);
918 static DWORD
find_adjacent_face(struct edge_face_map
*edge_face_map
, DWORD vertex1
, DWORD vertex2
, DWORD num_faces
)
920 struct edge_face
*edge_face_ptr
;
922 LIST_FOR_EACH_ENTRY(edge_face_ptr
, &edge_face_map
->lists
[vertex2
], struct edge_face
, entry
)
924 if (edge_face_ptr
->v2
== vertex1
)
925 return edge_face_ptr
->face
;
931 static DWORD
*generate_identity_point_reps(DWORD num_vertices
)
933 DWORD
*id_point_reps
;
936 id_point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*id_point_reps
));
940 for (i
= 0; i
< num_vertices
; i
++)
942 id_point_reps
[i
] = i
;
945 return id_point_reps
;
948 static HRESULT WINAPI
d3dx9_mesh_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
,
949 const DWORD
*point_reps
, DWORD
*adjacency
)
952 DWORD num_faces
= iface
->lpVtbl
->GetNumFaces(iface
);
953 DWORD num_vertices
= iface
->lpVtbl
->GetNumVertices(iface
);
954 DWORD options
= iface
->lpVtbl
->GetOptions(iface
);
955 BOOL indices_are_16_bit
= !(options
& D3DXMESH_32BIT
);
960 struct edge_face_map edge_face_map
= {0};
961 const DWORD
*point_reps_ptr
= NULL
;
962 DWORD
*id_point_reps
= NULL
;
964 TRACE("iface %p, point_reps %p, adjacency %p.\n", iface
, point_reps
, adjacency
);
966 if (!adjacency
) return D3DERR_INVALIDCALL
;
968 if (!point_reps
) /* Identity point reps */
970 id_point_reps
= generate_identity_point_reps(num_vertices
);
977 point_reps_ptr
= id_point_reps
;
981 point_reps_ptr
= point_reps
;
984 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &ib_ptr
);
985 if (FAILED(hr
)) goto cleanup
;
987 if (indices_are_16_bit
)
989 /* Widen 16 bit to 32 bit */
991 WORD
*ib_16bit
= ib_ptr
;
992 ib
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(DWORD
));
998 for (i
= 0; i
< 3 * num_faces
; i
++)
1000 ib
[i
] = ib_16bit
[i
];
1008 hr
= init_edge_face_map(&edge_face_map
, ib
, point_reps_ptr
, num_faces
);
1009 if (FAILED(hr
)) goto cleanup
;
1011 /* Create adjacency */
1012 for (face
= 0; face
< num_faces
; face
++)
1014 for (edge
= 0; edge
< 3; edge
++)
1016 DWORD v1
= ib
[3*face
+ edge
];
1017 DWORD v2
= ib
[3*face
+ (edge
+1)%3];
1018 DWORD new_v1
= point_reps_ptr
[v1
];
1019 DWORD new_v2
= point_reps_ptr
[v2
];
1022 adj_face
= find_adjacent_face(&edge_face_map
, new_v1
, new_v2
, num_faces
);
1023 adjacency
[3*face
+ edge
] = adj_face
;
1029 HeapFree(GetProcessHeap(), 0, id_point_reps
);
1030 if (indices_are_16_bit
) HeapFree(GetProcessHeap(), 0, ib
);
1031 HeapFree(GetProcessHeap(), 0, edge_face_map
.lists
);
1032 HeapFree(GetProcessHeap(), 0, edge_face_map
.entries
);
1033 if(ib_ptr
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1037 /* ConvertAdjacencyToPointReps helper function.
1039 * Goes around the edges of each face and replaces the vertices in any adjacent
1040 * face's edge with its own vertices(if its vertices have a lower index). This
1041 * way as few as possible low index vertices are shared among the faces. The
1042 * re-ordered index buffer is stored in new_indices.
1044 * The vertices in a point representation must be ordered sequentially, e.g.
1045 * index 5 holds the index of the vertex that replaces vertex 5, i.e. if
1046 * vertex 5 is replaced by vertex 3 then index 5 would contain 3. If no vertex
1047 * replaces it, then it contains the same number as the index itself, e.g.
1048 * index 5 would contain 5. */
1049 static HRESULT
propagate_face_vertices(const DWORD
*adjacency
, DWORD
*point_reps
,
1050 const DWORD
*indices
, DWORD
*new_indices
, DWORD face
, DWORD numfaces
)
1052 const unsigned int VERTS_PER_FACE
= 3;
1053 DWORD edge
, opp_edge
;
1054 DWORD face_base
= VERTS_PER_FACE
* face
;
1056 for (edge
= 0; edge
< VERTS_PER_FACE
; edge
++)
1058 DWORD adj_face
= adjacency
[face_base
+ edge
];
1059 DWORD adj_face_base
;
1061 if (adj_face
== -1) /* No adjacent face. */
1063 else if (adj_face
>= numfaces
)
1065 /* This throws exception on Windows */
1066 WARN("Index out of bounds. Got %d expected less than %d.\n",
1067 adj_face
, numfaces
);
1068 return D3DERR_INVALIDCALL
;
1070 adj_face_base
= 3 * adj_face
;
1072 /* Find opposite edge in adjacent face. */
1073 for (opp_edge
= 0; opp_edge
< VERTS_PER_FACE
; opp_edge
++)
1075 DWORD opp_edge_index
= adj_face_base
+ opp_edge
;
1076 if (adjacency
[opp_edge_index
] == face
)
1077 break; /* Found opposite edge. */
1080 /* Replaces vertices in opposite edge with vertices from current edge. */
1081 for (i
= 0; i
< 2; i
++)
1083 DWORD from
= face_base
+ (edge
+ (1 - i
)) % VERTS_PER_FACE
;
1084 DWORD to
= adj_face_base
+ (opp_edge
+ i
) % VERTS_PER_FACE
;
1086 /* Propagate lowest index. */
1087 if (new_indices
[to
] > new_indices
[from
])
1089 new_indices
[to
] = new_indices
[from
];
1090 point_reps
[indices
[to
]] = new_indices
[from
];
1098 static HRESULT WINAPI
d3dx9_mesh_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
,
1099 const DWORD
*adjacency
, DWORD
*point_reps
)
1101 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1105 DWORD
*indices
= NULL
;
1106 WORD
*indices_16bit
= NULL
;
1107 DWORD
*new_indices
= NULL
;
1108 const unsigned int VERTS_PER_FACE
= 3;
1110 TRACE("iface %p, adjacency %p, point_reps %p.\n", iface
, adjacency
, point_reps
);
1114 WARN("NULL adjacency.\n");
1115 hr
= D3DERR_INVALIDCALL
;
1121 WARN("NULL point_reps.\n");
1122 hr
= D3DERR_INVALIDCALL
;
1126 /* Should never happen as CreateMesh does not allow meshes with 0 faces */
1127 if (This
->numfaces
== 0)
1129 ERR("Number of faces was zero.\n");
1130 hr
= D3DERR_INVALIDCALL
;
1134 new_indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1141 if (This
->options
& D3DXMESH_32BIT
)
1143 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1144 if (FAILED(hr
)) goto cleanup
;
1145 memcpy(new_indices
, indices
, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1149 /* Make a widening copy of indices_16bit into indices and new_indices
1150 * in order to re-use the helper function */
1151 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices_16bit
);
1152 if (FAILED(hr
)) goto cleanup
;
1153 indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1159 for (i
= 0; i
< VERTS_PER_FACE
* This
->numfaces
; i
++)
1161 new_indices
[i
] = indices_16bit
[i
];
1162 indices
[i
] = indices_16bit
[i
];
1166 /* Vertices are ordered sequentially in the point representation. */
1167 for (i
= 0; i
< This
->numvertices
; i
++)
1172 /* Propagate vertices with low indices so as few vertices as possible
1173 * are used in the mesh.
1175 for (face
= 0; face
< This
->numfaces
; face
++)
1177 hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
, face
, This
->numfaces
);
1178 if (FAILED(hr
)) goto cleanup
;
1180 /* Go in opposite direction to catch all face orderings */
1181 for (face
= 0; face
< This
->numfaces
; face
++)
1183 hr
= propagate_face_vertices(adjacency
, point_reps
,
1184 indices
, new_indices
,
1185 (This
->numfaces
- 1) - face
, This
->numfaces
);
1186 if (FAILED(hr
)) goto cleanup
;
1191 if (This
->options
& D3DXMESH_32BIT
)
1193 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1197 if (indices_16bit
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1198 HeapFree(GetProcessHeap(), 0, indices
);
1200 HeapFree(GetProcessHeap(), 0, new_indices
);
1204 struct vertex_metadata
{
1207 DWORD first_shared_index
;
1210 static int compare_vertex_keys(const void *a
, const void *b
)
1212 const struct vertex_metadata
*left
= a
;
1213 const struct vertex_metadata
*right
= b
;
1214 if (left
->key
== right
->key
)
1216 return left
->key
< right
->key
? -1 : 1;
1219 static HRESULT WINAPI
d3dx9_mesh_GenerateAdjacency(ID3DXMesh
*iface
, float epsilon
, DWORD
*adjacency
)
1221 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1223 BYTE
*vertices
= NULL
;
1224 const DWORD
*indices
= NULL
;
1227 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
1228 struct vertex_metadata
*sorted_vertices
;
1229 /* shared_indices links together identical indices in the index buffer so
1230 * that adjacency checks can be limited to faces sharing a vertex */
1231 DWORD
*shared_indices
= NULL
;
1232 const FLOAT epsilon_sq
= epsilon
* epsilon
;
1235 TRACE("iface %p, epsilon %.8e, adjacency %p.\n", iface
, epsilon
, adjacency
);
1238 return D3DERR_INVALIDCALL
;
1240 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
1241 if (!(This
->options
& D3DXMESH_32BIT
))
1242 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
1243 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
1244 if (!shared_indices
)
1245 return E_OUTOFMEMORY
;
1246 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
1248 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
1249 if (FAILED(hr
)) goto cleanup
;
1250 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1251 if (FAILED(hr
)) goto cleanup
;
1253 if (!(This
->options
& D3DXMESH_32BIT
)) {
1254 const WORD
*word_indices
= (const WORD
*)indices
;
1255 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
1256 indices
= dword_indices
;
1257 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1258 *dword_indices
++ = *word_indices
++;
1261 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1262 for (i
= 0; i
< This
->numvertices
; i
++) {
1263 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
1264 sorted_vertices
[i
].first_shared_index
= -1;
1265 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
1266 sorted_vertices
[i
].vertex_index
= i
;
1268 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
1269 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
1270 shared_indices
[i
] = *first_shared_index
;
1271 *first_shared_index
= i
;
1274 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
1276 for (i
= 0; i
< This
->numvertices
; i
++) {
1277 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
1278 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
1279 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
1281 while (shared_index_a
!= -1) {
1283 DWORD shared_index_b
= shared_indices
[shared_index_a
];
1284 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
1287 while (shared_index_b
!= -1) {
1288 /* faces are adjacent if they have another coincident vertex */
1289 DWORD base_a
= (shared_index_a
/ 3) * 3;
1290 DWORD base_b
= (shared_index_b
/ 3) * 3;
1291 BOOL adjacent
= FALSE
;
1294 for (k
= 0; k
< 3; k
++) {
1295 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
1301 for (k
= 1; k
<= 2; k
++) {
1302 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
1303 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
1304 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
1305 if (!adjacent
&& epsilon
>= 0.0f
) {
1306 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
1309 D3DXVec3Subtract(&delta
,
1310 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
1311 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
1312 length_sq
= D3DXVec3LengthSq(&delta
);
1313 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
1316 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
1317 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
1318 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
1319 adjacency
[adj_a
] = base_b
/ 3;
1320 adjacency
[adj_b
] = base_a
/ 3;
1327 shared_index_b
= shared_indices
[shared_index_b
];
1329 while (++j
< This
->numvertices
) {
1330 D3DXVECTOR3
*vertex_b
;
1333 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
1334 /* no more coincident vertices to try */
1335 j
= This
->numvertices
;
1338 /* check for coincidence */
1339 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
1340 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
1341 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
1342 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
1347 if (j
>= This
->numvertices
)
1349 shared_index_b
= sorted_vertex_b
->first_shared_index
;
1352 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
1353 shared_index_a
= sorted_vertex_a
->first_shared_index
;
1359 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1360 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
1361 HeapFree(GetProcessHeap(), 0, shared_indices
);
1365 static HRESULT WINAPI
d3dx9_mesh_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1367 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1369 UINT vertex_declaration_size
;
1372 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
1376 WARN("Invalid declaration. Can't use NULL declaration.\n");
1377 return D3DERR_INVALIDCALL
;
1380 /* New declaration must be same size as original */
1381 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
1382 if (vertex_declaration_size
!= This
->vertex_declaration_size
)
1384 WARN("Invalid declaration. New vertex size does not match the original vertex size.\n");
1385 return D3DERR_INVALIDCALL
;
1388 /* New declaration must not contain non-zero Stream value */
1389 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1391 if (declaration
[i
].Stream
!= 0)
1393 WARN("Invalid declaration. New declaration contains non-zero Stream value.\n");
1394 return D3DERR_INVALIDCALL
;
1398 This
->num_elem
= i
+ 1;
1399 copy_declaration(This
->cached_declaration
, declaration
, This
->num_elem
);
1401 if (This
->vertex_declaration
)
1402 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
1404 /* An application can pass an invalid declaration to UpdateSemantics and
1405 * still expect D3D_OK (see tests). If the declaration is invalid, then
1406 * subsequent calls to DrawSubset will fail. This is handled by setting the
1407 * vertex declaration to NULL.
1408 * GetDeclaration, GetNumBytesPerVertex must, however, use the new
1409 * invalid declaration. This is handled by them using the cached vertex
1410 * declaration instead of the actual vertex declaration.
1412 hr
= IDirect3DDevice9_CreateVertexDeclaration(This
->device
,
1414 &This
->vertex_declaration
);
1417 WARN("Using invalid declaration. Calls to DrawSubset will fail.\n");
1418 This
->vertex_declaration
= NULL
;
1424 static HRESULT WINAPI
d3dx9_mesh_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
1426 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1428 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
1430 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1432 if (!(flags
& D3DLOCK_READONLY
))
1434 D3DXATTRIBUTERANGE
*attrib_table
= mesh
->attrib_table
;
1435 mesh
->attrib_table_size
= 0;
1436 mesh
->attrib_table
= NULL
;
1437 HeapFree(GetProcessHeap(), 0, attrib_table
);
1440 *data
= mesh
->attrib_buffer
;
1445 static HRESULT WINAPI
d3dx9_mesh_UnlockAttributeBuffer(ID3DXMesh
*iface
)
1447 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1450 TRACE("iface %p.\n", iface
);
1452 lock_count
= InterlockedDecrement(&mesh
->attrib_buffer_lock_count
);
1455 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1456 return D3DERR_INVALIDCALL
;
1462 static HRESULT WINAPI
d3dx9_mesh_Optimize(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1463 DWORD
*adjacency_out
, DWORD
*face_remap
, ID3DXBuffer
**vertex_remap
, ID3DXMesh
**opt_mesh
)
1465 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1467 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
1468 ID3DXMesh
*optimized_mesh
;
1470 TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap %p, vertex_remap %p, opt_mesh %p.\n",
1471 iface
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
1474 return D3DERR_INVALIDCALL
;
1476 hr
= iface
->lpVtbl
->GetDeclaration(iface
, declaration
);
1477 if (FAILED(hr
)) return hr
;
1479 if (FAILED(hr
= iface
->lpVtbl
->CloneMesh(iface
, mesh
->options
, declaration
, mesh
->device
, &optimized_mesh
)))
1482 hr
= optimized_mesh
->lpVtbl
->OptimizeInplace(optimized_mesh
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
);
1484 *opt_mesh
= optimized_mesh
;
1486 IUnknown_Release(optimized_mesh
);
1490 /* Creates a vertex_remap that removes unused vertices.
1491 * Indices are updated according to the vertex_remap. */
1492 static HRESULT
compact_mesh(struct d3dx9_mesh
*This
, DWORD
*indices
,
1493 DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
1496 DWORD
*vertex_remap_ptr
;
1497 DWORD num_used_vertices
;
1500 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
1501 if (FAILED(hr
)) return hr
;
1502 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
1504 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1505 vertex_remap_ptr
[indices
[i
]] = 1;
1507 /* create old->new vertex mapping */
1508 num_used_vertices
= 0;
1509 for (i
= 0; i
< This
->numvertices
; i
++) {
1510 if (vertex_remap_ptr
[i
])
1511 vertex_remap_ptr
[i
] = num_used_vertices
++;
1513 vertex_remap_ptr
[i
] = -1;
1515 /* convert indices */
1516 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1517 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
1519 /* create new->old vertex mapping */
1520 num_used_vertices
= 0;
1521 for (i
= 0; i
< This
->numvertices
; i
++) {
1522 if (vertex_remap_ptr
[i
] != -1)
1523 vertex_remap_ptr
[num_used_vertices
++] = i
;
1525 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
1526 vertex_remap_ptr
[i
] = -1;
1528 *new_num_vertices
= num_used_vertices
;
1533 /* count the number of unique attribute values in a sorted attribute buffer */
1534 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
1536 DWORD last_attribute
= attrib_buffer
[0];
1537 DWORD attrib_table_size
= 1;
1539 for (i
= 1; i
< numfaces
; i
++) {
1540 if (attrib_buffer
[i
] != last_attribute
) {
1541 last_attribute
= attrib_buffer
[i
];
1542 attrib_table_size
++;
1545 return attrib_table_size
;
1548 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
1549 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
1551 DWORD attrib_table_size
= 0;
1552 DWORD last_attribute
= attrib_buffer
[0];
1553 DWORD min_vertex
, max_vertex
;
1556 attrib_table
[0].AttribId
= last_attribute
;
1557 attrib_table
[0].FaceStart
= 0;
1558 min_vertex
= (DWORD
)-1;
1560 for (i
= 0; i
< numfaces
; i
++) {
1563 if (attrib_buffer
[i
] != last_attribute
) {
1564 last_attribute
= attrib_buffer
[i
];
1565 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1566 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1567 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1568 attrib_table_size
++;
1569 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
1570 attrib_table
[attrib_table_size
].FaceStart
= i
;
1571 min_vertex
= (DWORD
)-1;
1574 for (j
= 0; j
< 3; j
++) {
1575 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
1576 if (vertex_index
< min_vertex
)
1577 min_vertex
= vertex_index
;
1578 if (vertex_index
> max_vertex
)
1579 max_vertex
= vertex_index
;
1582 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1583 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1584 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1585 attrib_table_size
++;
1588 static int attrib_entry_compare(const DWORD
**a
, const DWORD
**b
)
1590 const DWORD
*ptr_a
= *a
;
1591 const DWORD
*ptr_b
= *b
;
1592 int delta
= *ptr_a
- *ptr_b
;
1597 delta
= ptr_a
- ptr_b
; /* for stable sort */
1601 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
1602 static HRESULT
remap_faces_for_attrsort(struct d3dx9_mesh
*This
, const DWORD
*indices
,
1603 DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
1605 DWORD
**sorted_attrib_ptr_buffer
= NULL
;
1608 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
1609 if (!sorted_attrib_ptr_buffer
)
1610 return E_OUTOFMEMORY
;
1612 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
1615 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
1616 return E_OUTOFMEMORY
;
1619 for (i
= 0; i
< This
->numfaces
; i
++)
1620 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
1621 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
),
1622 (int(*)(const void *, const void *))attrib_entry_compare
);
1624 for (i
= 0; i
< This
->numfaces
; i
++)
1626 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
1627 (*face_remap
)[old_face
] = i
;
1630 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
1631 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
1632 for (i
= 0; i
< This
->numfaces
; i
++)
1633 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
1638 static HRESULT WINAPI
d3dx9_mesh_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1639 DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
1641 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1642 void *indices
= NULL
;
1643 DWORD
*attrib_buffer
= NULL
;
1645 ID3DXBuffer
*vertex_remap
= NULL
;
1646 DWORD
*face_remap
= NULL
; /* old -> new mapping */
1647 DWORD
*dword_indices
= NULL
;
1648 DWORD new_num_vertices
= 0;
1649 DWORD new_num_alloc_vertices
= 0;
1650 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
1651 DWORD
*sorted_attrib_buffer
= NULL
;
1654 TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
1655 iface
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
1658 return D3DERR_INVALIDCALL
;
1659 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
1660 return D3DERR_INVALIDCALL
;
1661 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1662 return D3DERR_INVALIDCALL
;
1664 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1666 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
1667 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
1668 if (flags
& D3DXMESHOPT_STRIPREORDER
)
1669 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
1673 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, &indices
);
1674 if (FAILED(hr
)) goto cleanup
;
1676 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
1677 if (!dword_indices
) return E_OUTOFMEMORY
;
1678 if (This
->options
& D3DXMESH_32BIT
) {
1679 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1681 WORD
*word_indices
= indices
;
1682 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1683 dword_indices
[i
] = *word_indices
++;
1686 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
1688 new_num_alloc_vertices
= This
->numvertices
;
1689 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
1690 if (FAILED(hr
)) goto cleanup
;
1691 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
1692 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
1694 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
>= sizeof(d3dx_decltype_size
) / sizeof(*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 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
2374 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
2375 m
.u
.m
[2][0] = -praydir
->x
;
2377 m
.u
.m
[0][1] = p1
->y
- p0
->z
;
2378 m
.u
.m
[1][1] = p2
->y
- p0
->z
;
2379 m
.u
.m
[2][1] = -praydir
->y
;
2381 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
2382 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
2383 m
.u
.m
[2][2] = -praydir
->z
;
2390 vec
.x
= praypos
->x
- p0
->x
;
2391 vec
.y
= praypos
->y
- p0
->y
;
2392 vec
.z
= praypos
->z
- p0
->z
;
2395 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
2397 D3DXVec4Transform(&vec
, &vec
, &m
);
2398 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
2402 *pdist
= fabsf( vec
.z
);
2410 BOOL WINAPI
D3DXSphereBoundProbe(const D3DXVECTOR3
*pcenter
, float radius
,
2411 const D3DXVECTOR3
*prayposition
, const D3DXVECTOR3
*praydirection
)
2413 D3DXVECTOR3 difference
;
2416 a
= D3DXVec3LengthSq(praydirection
);
2417 if (!D3DXVec3Subtract(&difference
, prayposition
, pcenter
)) return FALSE
;
2418 b
= D3DXVec3Dot(&difference
, praydirection
);
2419 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
2422 if ( ( d
<= 0.0f
) || ( sqrt(d
) <= b
) ) return FALSE
;
2426 /*************************************************************************
2429 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2430 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2434 IDirect3DVertexDeclaration9
*vertex_declaration
;
2435 UINT vertex_declaration_size
;
2437 IDirect3DVertexBuffer9
*vertex_buffer
;
2438 IDirect3DIndexBuffer9
*index_buffer
;
2439 DWORD
*attrib_buffer
;
2440 struct d3dx9_mesh
*object
;
2441 DWORD index_usage
= 0;
2442 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
2443 D3DFORMAT index_format
= D3DFMT_INDEX16
;
2444 DWORD vertex_usage
= 0;
2445 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
2448 TRACE("numfaces %u, numvertices %u, options %#x, declaration %p, device %p, mesh %p.\n",
2449 numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2451 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
2452 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
2453 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
2455 return D3DERR_INVALIDCALL
;
2457 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
2458 if (declaration
[i
].Stream
!= 0)
2459 return D3DERR_INVALIDCALL
;
2462 if (options
& D3DXMESH_32BIT
)
2463 index_format
= D3DFMT_INDEX32
;
2465 if (options
& D3DXMESH_DONOTCLIP
) {
2466 index_usage
|= D3DUSAGE_DONOTCLIP
;
2467 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
2469 if (options
& D3DXMESH_POINTS
) {
2470 index_usage
|= D3DUSAGE_POINTS
;
2471 vertex_usage
|= D3DUSAGE_POINTS
;
2473 if (options
& D3DXMESH_RTPATCHES
) {
2474 index_usage
|= D3DUSAGE_RTPATCHES
;
2475 vertex_usage
|= D3DUSAGE_RTPATCHES
;
2477 if (options
& D3DXMESH_NPATCHES
) {
2478 index_usage
|= D3DUSAGE_NPATCHES
;
2479 vertex_usage
|= D3DUSAGE_NPATCHES
;
2482 if (options
& D3DXMESH_VB_SYSTEMMEM
)
2483 vertex_pool
= D3DPOOL_SYSTEMMEM
;
2484 else if (options
& D3DXMESH_VB_MANAGED
)
2485 vertex_pool
= D3DPOOL_MANAGED
;
2487 if (options
& D3DXMESH_VB_WRITEONLY
)
2488 vertex_usage
|= D3DUSAGE_WRITEONLY
;
2489 if (options
& D3DXMESH_VB_DYNAMIC
)
2490 vertex_usage
|= D3DUSAGE_DYNAMIC
;
2491 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
2492 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2494 if (options
& D3DXMESH_IB_SYSTEMMEM
)
2495 index_pool
= D3DPOOL_SYSTEMMEM
;
2496 else if (options
& D3DXMESH_IB_MANAGED
)
2497 index_pool
= D3DPOOL_MANAGED
;
2499 if (options
& D3DXMESH_IB_WRITEONLY
)
2500 index_usage
|= D3DUSAGE_WRITEONLY
;
2501 if (options
& D3DXMESH_IB_DYNAMIC
)
2502 index_usage
|= D3DUSAGE_DYNAMIC
;
2503 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
2504 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2506 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
2512 /* Create vertex declaration */
2513 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
2515 &vertex_declaration
);
2518 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
2521 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
2523 /* Create vertex buffer */
2524 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
2525 numvertices
* vertex_declaration_size
,
2533 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2534 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2538 /* Create index buffer */
2539 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
2540 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
2548 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2549 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2550 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2554 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
2555 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2556 if (object
== NULL
|| attrib_buffer
== NULL
)
2558 HeapFree(GetProcessHeap(), 0, object
);
2559 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
2560 IDirect3DIndexBuffer9_Release(index_buffer
);
2561 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2562 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2564 return E_OUTOFMEMORY
;
2566 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
2569 object
->numfaces
= numfaces
;
2570 object
->numvertices
= numvertices
;
2571 object
->options
= options
;
2573 object
->device
= device
;
2574 IDirect3DDevice9_AddRef(device
);
2576 copy_declaration(object
->cached_declaration
, declaration
, num_elem
);
2577 object
->vertex_declaration
= vertex_declaration
;
2578 object
->vertex_declaration_size
= vertex_declaration_size
;
2579 object
->num_elem
= num_elem
;
2580 object
->vertex_buffer
= vertex_buffer
;
2581 object
->index_buffer
= index_buffer
;
2582 object
->attrib_buffer
= attrib_buffer
;
2584 *mesh
= &object
->ID3DXMesh_iface
;
2589 /*************************************************************************
2592 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2593 DWORD fvf
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2596 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
2598 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
2600 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
2601 if (FAILED(hr
)) return hr
;
2603 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2609 DWORD num_poly_faces
;
2610 DWORD num_tri_faces
;
2611 D3DXVECTOR3
*vertices
;
2612 DWORD
*num_tri_per_face
;
2617 /* optional mesh data */
2620 D3DXVECTOR3
*normals
;
2621 DWORD
*normal_indices
;
2623 D3DXVECTOR2
*tex_coords
;
2625 DWORD
*vertex_colors
;
2627 DWORD num_materials
;
2628 D3DXMATERIAL
*materials
;
2629 DWORD
*material_indices
;
2631 struct ID3DXSkinInfo
*skin_info
;
2635 static HRESULT
parse_texture_filename(ID3DXFileData
*filedata
, char **filename_out
)
2641 char *filename
= NULL
;
2643 /* template TextureFilename {
2648 HeapFree(GetProcessHeap(), 0, *filename_out
);
2649 *filename_out
= NULL
;
2651 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2652 if (FAILED(hr
)) return hr
;
2654 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
2655 if (data_size
< sizeof(filename_in
))
2657 WARN("truncated data (%lu bytes)\n", data_size
);
2658 filedata
->lpVtbl
->Unlock(filedata
);
2661 filename_in
= *(char **)data
;
2663 filename
= HeapAlloc(GetProcessHeap(), 0, strlen(filename_in
) + 1);
2665 filedata
->lpVtbl
->Unlock(filedata
);
2666 return E_OUTOFMEMORY
;
2669 strcpy(filename
, filename_in
);
2670 *filename_out
= filename
;
2672 filedata
->lpVtbl
->Unlock(filedata
);
2677 static HRESULT
parse_material(ID3DXFileData
*filedata
, D3DXMATERIAL
*material
)
2683 ID3DXFileData
*child
;
2684 SIZE_T i
, nb_children
;
2686 material
->pTextureFilename
= NULL
;
2688 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2689 if (FAILED(hr
)) return hr
;
2692 * template ColorRGBA {
2698 * template ColorRGB {
2703 * template Material {
2704 * ColorRGBA faceColor;
2706 * ColorRGB specularColor;
2707 * ColorRGB emissiveColor;
2711 if (data_size
!= sizeof(FLOAT
) * 11) {
2712 WARN("incorrect data size (%ld bytes)\n", data_size
);
2713 filedata
->lpVtbl
->Unlock(filedata
);
2717 memcpy(&material
->MatD3D
.Diffuse
, data
, sizeof(D3DCOLORVALUE
));
2718 data
+= sizeof(D3DCOLORVALUE
);
2719 material
->MatD3D
.Power
= *(FLOAT
*)data
;
2720 data
+= sizeof(FLOAT
);
2721 memcpy(&material
->MatD3D
.Specular
, data
, sizeof(FLOAT
) * 3);
2722 material
->MatD3D
.Specular
.a
= 1.0f
;
2723 data
+= 3 * sizeof(FLOAT
);
2724 memcpy(&material
->MatD3D
.Emissive
, data
, sizeof(FLOAT
) * 3);
2725 material
->MatD3D
.Emissive
.a
= 1.0f
;
2726 material
->MatD3D
.Ambient
.r
= 0.0f
;
2727 material
->MatD3D
.Ambient
.g
= 0.0f
;
2728 material
->MatD3D
.Ambient
.b
= 0.0f
;
2729 material
->MatD3D
.Ambient
.a
= 1.0f
;
2731 filedata
->lpVtbl
->Unlock(filedata
);
2733 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2737 for (i
= 0; i
< nb_children
; i
++)
2739 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2742 hr
= child
->lpVtbl
->GetType(child
, &type
);
2746 if (IsEqualGUID(&type
, &TID_D3DRMTextureFilename
)) {
2747 hr
= parse_texture_filename(child
, &material
->pTextureFilename
);
2751 IUnknown_Release(child
);
2756 IUnknown_Release(child
);
2760 static void destroy_materials(struct mesh_data
*mesh
)
2763 for (i
= 0; i
< mesh
->num_materials
; i
++)
2764 HeapFree(GetProcessHeap(), 0, mesh
->materials
[i
].pTextureFilename
);
2765 HeapFree(GetProcessHeap(), 0, mesh
->materials
);
2766 HeapFree(GetProcessHeap(), 0, mesh
->material_indices
);
2767 mesh
->num_materials
= 0;
2768 mesh
->materials
= NULL
;
2769 mesh
->material_indices
= NULL
;
2772 static HRESULT
parse_material_list(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2776 const DWORD
*data
, *in_ptr
;
2778 ID3DXFileData
*child
= NULL
;
2779 DWORD num_materials
;
2783 destroy_materials(mesh
);
2785 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2786 if (FAILED(hr
)) return hr
;
2788 /* template MeshMaterialList {
2790 * DWORD nFaceIndexes;
2791 * array DWORD faceIndexes[nFaceIndexes];
2799 if (data_size
< sizeof(DWORD
)) {
2800 WARN("truncated data (%ld bytes)\n", data_size
);
2803 num_materials
= *in_ptr
++;
2804 if (!num_materials
) {
2809 if (data_size
< 2 * sizeof(DWORD
)) {
2810 WARN("truncated data (%ld bytes)\n", data_size
);
2813 if (*in_ptr
++ != mesh
->num_poly_faces
) {
2814 WARN("number of material face indices (%u) doesn't match number of faces (%u)\n",
2815 *(in_ptr
- 1), mesh
->num_poly_faces
);
2818 if (data_size
< 2 * sizeof(DWORD
) + mesh
->num_poly_faces
* sizeof(DWORD
)) {
2819 WARN("truncated data (%ld bytes)\n", data_size
);
2822 for (i
= 0; i
< mesh
->num_poly_faces
; i
++) {
2823 if (*in_ptr
++ >= num_materials
) {
2824 WARN("face %u: reference to undefined material %u (only %u materials)\n",
2825 i
, *(in_ptr
- 1), num_materials
);
2830 mesh
->materials
= HeapAlloc(GetProcessHeap(), 0, num_materials
* sizeof(*mesh
->materials
));
2831 mesh
->material_indices
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_poly_faces
* sizeof(*mesh
->material_indices
));
2832 if (!mesh
->materials
|| !mesh
->material_indices
) {
2836 memcpy(mesh
->material_indices
, data
+ 2, mesh
->num_poly_faces
* sizeof(DWORD
));
2838 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2842 for (i
= 0; i
< nb_children
; i
++)
2844 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2847 hr
= child
->lpVtbl
->GetType(child
, &type
);
2851 if (IsEqualGUID(&type
, &TID_D3DRMMaterial
)) {
2852 if (mesh
->num_materials
>= num_materials
) {
2853 WARN("more materials defined than declared\n");
2857 hr
= parse_material(child
, &mesh
->materials
[mesh
->num_materials
++]);
2862 IUnknown_Release(child
);
2865 if (num_materials
!= mesh
->num_materials
) {
2866 WARN("only %u of %u materials defined\n", num_materials
, mesh
->num_materials
);
2872 IUnknown_Release(child
);
2873 filedata
->lpVtbl
->Unlock(filedata
);
2877 static HRESULT
parse_texture_coords(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2883 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2884 mesh
->tex_coords
= NULL
;
2886 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2887 if (FAILED(hr
)) return hr
;
2889 /* template Coords2d {
2893 * template MeshTextureCoords {
2894 * DWORD nTextureCoords;
2895 * array Coords2d textureCoords[nTextureCoords];
2901 if (data_size
< sizeof(DWORD
)) {
2902 WARN("truncated data (%ld bytes)\n", data_size
);
2905 if (*(DWORD
*)data
!= mesh
->num_vertices
) {
2906 WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2907 *(DWORD
*)data
, mesh
->num_vertices
);
2910 data
+= sizeof(DWORD
);
2911 if (data_size
< sizeof(DWORD
) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
)) {
2912 WARN("truncated data (%ld bytes)\n", data_size
);
2916 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2917 if (!mesh
->tex_coords
) {
2921 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2923 mesh
->fvf
|= D3DFVF_TEX1
;
2928 filedata
->lpVtbl
->Unlock(filedata
);
2932 static HRESULT
parse_vertex_colors(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2940 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2941 mesh
->vertex_colors
= NULL
;
2943 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2944 if (FAILED(hr
)) return hr
;
2946 /* template IndexedColor {
2948 * ColorRGBA indexColor;
2950 * template MeshVertexColors {
2951 * DWORD nVertexColors;
2952 * array IndexedColor vertexColors[nVertexColors];
2958 if (data_size
< sizeof(DWORD
)) {
2959 WARN("truncated data (%ld bytes)\n", data_size
);
2962 num_colors
= *(DWORD
*)data
;
2963 data
+= sizeof(DWORD
);
2964 if (data_size
< sizeof(DWORD
) + num_colors
* (sizeof(DWORD
) + sizeof(D3DCOLORVALUE
))) {
2965 WARN("truncated data (%ld bytes)\n", data_size
);
2969 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(DWORD
));
2970 if (!mesh
->vertex_colors
) {
2975 for (i
= 0; i
< mesh
->num_vertices
; i
++)
2976 mesh
->vertex_colors
[i
] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2977 for (i
= 0; i
< num_colors
; i
++)
2979 D3DCOLORVALUE color
;
2980 DWORD index
= *(DWORD
*)data
;
2981 data
+= sizeof(DWORD
);
2982 if (index
>= mesh
->num_vertices
) {
2983 WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2984 i
, index
, mesh
->num_vertices
);
2987 memcpy(&color
, data
, sizeof(color
));
2988 data
+= sizeof(color
);
2989 color
.r
= min(1.0f
, max(0.0f
, color
.r
));
2990 color
.g
= min(1.0f
, max(0.0f
, color
.g
));
2991 color
.b
= min(1.0f
, max(0.0f
, color
.b
));
2992 color
.a
= min(1.0f
, max(0.0f
, color
.a
));
2993 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
2994 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
2995 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
2996 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
2999 mesh
->fvf
|= D3DFVF_DIFFUSE
;
3004 filedata
->lpVtbl
->Unlock(filedata
);
3008 static HRESULT
parse_normals(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
3013 DWORD
*index_out_ptr
;
3015 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
3017 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
3018 mesh
->num_normals
= 0;
3019 mesh
->normals
= NULL
;
3020 mesh
->normal_indices
= NULL
;
3021 mesh
->fvf
|= D3DFVF_NORMAL
;
3023 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3024 if (FAILED(hr
)) return hr
;
3026 /* template Vector {
3031 * template MeshFace {
3032 * DWORD nFaceVertexIndices;
3033 * array DWORD faceVertexIndices[nFaceVertexIndices];
3035 * template MeshNormals {
3037 * array Vector normals[nNormals];
3038 * DWORD nFaceNormals;
3039 * array MeshFace faceNormals[nFaceNormals];
3045 if (data_size
< sizeof(DWORD
) * 2) {
3046 WARN("truncated data (%ld bytes)\n", data_size
);
3049 mesh
->num_normals
= *(DWORD
*)data
;
3050 data
+= sizeof(DWORD
);
3051 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
3052 num_face_indices
* sizeof(DWORD
)) {
3053 WARN("truncated data (%ld bytes)\n", data_size
);
3057 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3058 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
3059 if (!mesh
->normals
|| !mesh
->normal_indices
) {
3064 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3065 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
3066 for (i
= 0; i
< mesh
->num_normals
; i
++)
3067 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
3069 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
3070 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
3071 *(DWORD
*)data
, mesh
->num_poly_faces
);
3074 data
+= sizeof(DWORD
);
3075 index_out_ptr
= mesh
->normal_indices
;
3076 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
3079 DWORD count
= *(DWORD
*)data
;
3080 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
3081 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
3082 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
3085 data
+= sizeof(DWORD
);
3087 for (j
= 0; j
< count
; j
++) {
3088 DWORD normal_index
= *(DWORD
*)data
;
3089 if (normal_index
>= mesh
->num_normals
) {
3090 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
3091 i
, j
, normal_index
, mesh
->num_normals
);
3094 *index_out_ptr
++ = normal_index
;
3095 data
+= sizeof(DWORD
);
3102 filedata
->lpVtbl
->Unlock(filedata
);
3106 static HRESULT
parse_skin_mesh_info(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD index
)
3112 TRACE("(%p, %p, %u)\n", filedata
, mesh_data
, index
);
3114 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3115 if (FAILED(hr
)) return hr
;
3119 if (!mesh_data
->skin_info
) {
3120 if (data_size
< sizeof(WORD
) * 3) {
3121 WARN("truncated data (%ld bytes)\n", data_size
);
3124 /* Skip nMaxSkinWeightsPerVertex and nMaxSkinWeightsPerFace */
3125 data
+= 2 * sizeof(WORD
);
3126 mesh_data
->nb_bones
= *(WORD
*)data
;
3127 hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
, mesh_data
->nb_bones
, &mesh_data
->skin_info
);
3130 DWORD nb_influences
;
3132 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
3133 name
= *(const char**)data
;
3134 data
+= sizeof(char*);
3136 nb_influences
= *(DWORD
*)data
;
3137 data
+= sizeof(DWORD
);
3139 if (data_size
< (sizeof(char*) + sizeof(DWORD
) + nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
)) + 16 * sizeof(FLOAT
))) {
3140 WARN("truncated data (%ld bytes)\n", data_size
);
3144 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneName(mesh_data
->skin_info
, index
, name
);
3146 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneInfluence(mesh_data
->skin_info
, index
, nb_influences
,
3147 (const DWORD
*)data
, (const FLOAT
*)(data
+ nb_influences
* sizeof(DWORD
)));
3149 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneOffsetMatrix(mesh_data
->skin_info
, index
,
3150 (const D3DMATRIX
*)(data
+ nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
))));
3154 filedata
->lpVtbl
->Unlock(filedata
);
3158 /* for provide_flags parameters */
3159 #define PROVIDE_MATERIALS 0x1
3160 #define PROVIDE_SKININFO 0x2
3161 #define PROVIDE_ADJACENCY 0x4
3163 static HRESULT
parse_mesh(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
3167 const BYTE
*data
, *in_ptr
;
3168 DWORD
*index_out_ptr
;
3170 ID3DXFileData
*child
= NULL
;
3173 DWORD nb_skin_weigths_info
= 0;
3178 * array Vector vertices[nVertices];
3180 * array MeshFace faces[nFaces];
3185 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3186 if (FAILED(hr
)) return hr
;
3191 if (data_size
< sizeof(DWORD
) * 2) {
3192 WARN("truncated data (%ld bytes)\n", data_size
);
3195 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
3196 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
)) {
3197 WARN("truncated data (%ld bytes)\n", data_size
);
3200 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
3202 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
3203 in_ptr
+= sizeof(DWORD
);
3205 mesh_data
->num_tri_faces
= 0;
3206 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3208 DWORD num_poly_vertices
;
3211 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
)) {
3212 WARN("truncated data (%ld bytes)\n", data_size
);
3215 num_poly_vertices
= *(DWORD
*)in_ptr
;
3216 in_ptr
+= sizeof(DWORD
);
3217 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
)) {
3218 WARN("truncated data (%ld bytes)\n", data_size
);
3221 if (num_poly_vertices
< 3) {
3222 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
3225 for (j
= 0; j
< num_poly_vertices
; j
++) {
3226 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
3227 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
3228 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
3231 in_ptr
+= sizeof(DWORD
);
3233 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
3236 mesh_data
->fvf
= D3DFVF_XYZ
;
3238 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
3239 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
3240 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
3241 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
3242 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
3243 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
3244 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
) {
3249 in_ptr
= data
+ sizeof(DWORD
);
3250 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
3251 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
3253 index_out_ptr
= mesh_data
->indices
;
3254 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3258 count
= *(DWORD
*)in_ptr
;
3259 in_ptr
+= sizeof(DWORD
);
3260 mesh_data
->num_tri_per_face
[i
] = count
- 2;
3263 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
3264 in_ptr
+= sizeof(DWORD
);
3268 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3272 for (i
= 0; i
< nb_children
; i
++)
3274 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3277 hr
= child
->lpVtbl
->GetType(child
, &type
);
3281 if (IsEqualGUID(&type
, &TID_D3DRMMeshNormals
)) {
3282 hr
= parse_normals(child
, mesh_data
);
3283 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshVertexColors
)) {
3284 hr
= parse_vertex_colors(child
, mesh_data
);
3285 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshTextureCoords
)) {
3286 hr
= parse_texture_coords(child
, mesh_data
);
3287 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshMaterialList
) &&
3288 (provide_flags
& PROVIDE_MATERIALS
))
3290 hr
= parse_material_list(child
, mesh_data
);
3291 } else if (provide_flags
& PROVIDE_SKININFO
) {
3292 if (IsEqualGUID(&type
, &DXFILEOBJ_XSkinMeshHeader
)) {
3293 if (mesh_data
->skin_info
) {
3294 WARN("Skin mesh header already encountered\n");
3298 hr
= parse_skin_mesh_info(child
, mesh_data
, 0);
3301 } else if (IsEqualGUID(&type
, &DXFILEOBJ_SkinWeights
)) {
3302 if (!mesh_data
->skin_info
) {
3303 WARN("Skin weigths found but skin mesh header not encountered yet\n");
3307 hr
= parse_skin_mesh_info(child
, mesh_data
, nb_skin_weigths_info
);
3310 nb_skin_weigths_info
++;
3316 IUnknown_Release(child
);
3320 if (mesh_data
->skin_info
&& (nb_skin_weigths_info
!= mesh_data
->nb_bones
)) {
3321 WARN("Mismatch between nb skin weights info %u encountered and nb bones %u from skin mesh header\n",
3322 nb_skin_weigths_info
, mesh_data
->nb_bones
);
3331 IUnknown_Release(child
);
3332 filedata
->lpVtbl
->Unlock(filedata
);
3336 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
3337 ID3DXBuffer
**effects
)
3340 D3DXEFFECTINSTANCE
*effect_ptr
;
3342 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3343 static const struct {
3344 const char *param_name
;
3348 } material_effects
[] = {
3349 #define EFFECT_TABLE_ENTRY(str, field) \
3350 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
3351 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
3352 EFFECT_TABLE_ENTRY("Power", Power
),
3353 EFFECT_TABLE_ENTRY("Specular", Specular
),
3354 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
3355 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
3356 #undef EFFECT_TABLE_ENTRY
3358 static const char texture_paramname
[] = "Texture0@Name";
3362 /* effects buffer layout:
3364 * D3DXEFFECTINSTANCE effects[num_materials];
3365 * for (effect in effects)
3367 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
3368 * for (default in defaults)
3370 * *default.pParamName;
3375 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
3376 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
3377 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
3378 buffer_size
+= material_effects
[i
].name_size
;
3379 buffer_size
+= material_effects
[i
].num_bytes
;
3381 buffer_size
*= num_materials
;
3382 for (i
= 0; i
< num_materials
; i
++) {
3383 if (material_ptr
[i
].pTextureFilename
) {
3384 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
3385 buffer_size
+= sizeof(texture_paramname
);
3386 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
3390 hr
= D3DXCreateBuffer(buffer_size
, effects
);
3391 if (FAILED(hr
)) return hr
;
3392 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
3393 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
3395 for (i
= 0; i
< num_materials
; i
++)
3398 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
3400 effect_ptr
->pDefaults
= defaults
;
3401 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
3402 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
3404 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
3406 defaults
->pParamName
= (char *)out_ptr
;
3407 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
3408 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
3409 defaults
->Type
= D3DXEDT_FLOATS
;
3410 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
3411 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
3412 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3416 if (material_ptr
->pTextureFilename
)
3418 defaults
->pParamName
= (char *)out_ptr
;
3419 strcpy(defaults
->pParamName
, texture_paramname
);
3420 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
3421 defaults
->Type
= D3DXEDT_STRING
;
3422 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
3423 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
3424 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3429 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
3434 HRESULT WINAPI
D3DXLoadSkinMeshFromXof(struct ID3DXFileData
*filedata
, DWORD options
,
3435 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
3436 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXSkinInfo
**skin_info_out
,
3437 struct ID3DXMesh
**mesh_out
)
3440 DWORD
*index_in_ptr
;
3441 struct mesh_data mesh_data
;
3442 DWORD total_vertices
;
3443 ID3DXMesh
*d3dxmesh
= NULL
;
3444 ID3DXBuffer
*adjacency
= NULL
;
3445 ID3DXBuffer
*materials
= NULL
;
3446 ID3DXBuffer
*effects
= NULL
;
3447 struct vertex_duplication
{
3450 } *duplications
= NULL
;
3452 void *vertices
= NULL
;
3453 void *indices
= NULL
;
3455 DWORD provide_flags
= 0;
3457 TRACE("(%p, %x, %p, %p, %p, %p, %p, %p, %p)\n", filedata
, options
, device
, adjacency_out
, materials_out
,
3458 effects_out
, num_materials_out
, skin_info_out
, mesh_out
);
3460 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
3462 if (num_materials_out
|| materials_out
|| effects_out
)
3463 provide_flags
|= PROVIDE_MATERIALS
;
3465 provide_flags
|= PROVIDE_SKININFO
;
3467 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
3468 if (FAILED(hr
)) goto cleanup
;
3470 total_vertices
= mesh_data
.num_vertices
;
3471 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3472 /* duplicate vertices with multiple normals */
3473 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
3474 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
3475 if (!duplications
) {
3479 for (i
= 0; i
< total_vertices
; i
++)
3481 duplications
[i
].normal_index
= -1;
3482 list_init(&duplications
[i
].entry
);
3484 for (i
= 0; i
< num_face_indices
; i
++) {
3485 DWORD vertex_index
= mesh_data
.indices
[i
];
3486 DWORD normal_index
= mesh_data
.normal_indices
[i
];
3487 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
3489 if (dup_ptr
->normal_index
== -1) {
3490 dup_ptr
->normal_index
= normal_index
;
3492 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
3493 struct list
*dup_list
= &dup_ptr
->entry
;
3495 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
3496 if (new_normal
->x
== cur_normal
->x
&&
3497 new_normal
->y
== cur_normal
->y
&&
3498 new_normal
->z
== cur_normal
->z
)
3500 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3502 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
3503 dup_ptr
= &duplications
[total_vertices
++];
3504 dup_ptr
->normal_index
= normal_index
;
3505 list_add_tail(dup_list
, &dup_ptr
->entry
);
3506 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3509 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
3510 struct vertex_duplication
, entry
);
3517 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
3518 if (FAILED(hr
)) goto cleanup
;
3520 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, 0, &vertices
);
3521 if (FAILED(hr
)) goto cleanup
;
3524 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3525 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
3526 out_ptr
+= sizeof(D3DXVECTOR3
);
3527 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3528 if (duplications
[i
].normal_index
== -1)
3529 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
3531 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
3532 out_ptr
+= sizeof(D3DXVECTOR3
);
3534 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
3535 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
3536 out_ptr
+= sizeof(DWORD
);
3538 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
3539 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
3540 out_ptr
+= sizeof(D3DXVECTOR2
);
3543 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3544 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
3546 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3547 struct vertex_duplication
*dup_ptr
;
3548 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
3550 int j
= dup_ptr
- duplications
;
3551 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
3553 memcpy(dest_vertex
, out_ptr
, vertex_size
);
3554 dest_vertex
+= sizeof(D3DXVECTOR3
);
3555 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
3557 out_ptr
+= vertex_size
;
3560 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
3562 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, 0, &indices
);
3563 if (FAILED(hr
)) goto cleanup
;
3565 index_in_ptr
= mesh_data
.indices
;
3566 #define FILL_INDEX_BUFFER(indices_var) \
3567 for (i = 0; i < mesh_data.num_poly_faces; i++) \
3569 DWORD count = mesh_data.num_tri_per_face[i]; \
3570 WORD first_index = *index_in_ptr++; \
3572 *indices_var++ = first_index; \
3573 *indices_var++ = *index_in_ptr; \
3575 *indices_var++ = *index_in_ptr; \
3579 if (options
& D3DXMESH_32BIT
) {
3580 DWORD
*dword_indices
= indices
;
3581 FILL_INDEX_BUFFER(dword_indices
)
3583 WORD
*word_indices
= indices
;
3584 FILL_INDEX_BUFFER(word_indices
)
3586 #undef FILL_INDEX_BUFFER
3587 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
3589 if (mesh_data
.material_indices
) {
3590 DWORD
*attrib_buffer
= NULL
;
3591 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, 0, &attrib_buffer
);
3592 if (FAILED(hr
)) goto cleanup
;
3593 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
3595 DWORD count
= mesh_data
.num_tri_per_face
[i
];
3597 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
3599 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
3601 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
3602 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
3603 NULL
, NULL
, NULL
, NULL
);
3604 if (FAILED(hr
)) goto cleanup
;
3607 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
3608 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
3609 char *strings_out_ptr
;
3610 D3DXMATERIAL
*materials_ptr
;
3612 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3613 if (mesh_data
.materials
[i
].pTextureFilename
)
3614 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3617 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3618 if (FAILED(hr
)) goto cleanup
;
3620 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3621 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
3622 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
3623 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3624 if (materials_ptr
[i
].pTextureFilename
) {
3625 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
3626 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
3627 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3632 if (mesh_data
.num_materials
&& effects_out
) {
3633 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
3634 if (FAILED(hr
)) goto cleanup
;
3636 if (!materials_out
) {
3637 ID3DXBuffer_Release(materials
);
3642 if (adjacency_out
) {
3643 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
3644 if (FAILED(hr
)) goto cleanup
;
3645 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
3646 if (FAILED(hr
)) goto cleanup
;
3649 *mesh_out
= d3dxmesh
;
3650 if (adjacency_out
) *adjacency_out
= adjacency
;
3651 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
3652 if (materials_out
) *materials_out
= materials
;
3653 if (effects_out
) *effects_out
= effects
;
3654 if (skin_info_out
) *skin_info_out
= mesh_data
.skin_info
;
3659 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
3660 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3661 if (materials
) ID3DXBuffer_Release(materials
);
3662 if (effects
) ID3DXBuffer_Release(effects
);
3663 if (mesh_data
.skin_info
) mesh_data
.skin_info
->lpVtbl
->Release(mesh_data
.skin_info
);
3664 if (skin_info_out
) *skin_info_out
= NULL
;
3666 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
3667 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
3668 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
3669 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
3670 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
3671 destroy_materials(&mesh_data
);
3672 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
3673 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
3674 HeapFree(GetProcessHeap(), 0, duplications
);
3678 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3679 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3680 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3686 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3687 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3688 debugstr_a(filename
), options
, device
, alloc_hier
,
3689 load_user_data
, frame_hierarchy
, anim_controller
);
3692 return D3DERR_INVALIDCALL
;
3694 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3695 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3696 if (!filenameW
) return E_OUTOFMEMORY
;
3697 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3699 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
3700 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3701 HeapFree(GetProcessHeap(), 0, filenameW
);
3706 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3707 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3708 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3714 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3715 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3716 debugstr_w(filename
), options
, device
, alloc_hier
,
3717 load_user_data
, frame_hierarchy
, anim_controller
);
3720 return D3DERR_INVALIDCALL
;
3722 hr
= map_view_of_file(filename
, &buffer
, &size
);
3724 return D3DXERR_INVALIDDATA
;
3726 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
3727 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3729 UnmapViewOfFile(buffer
);
3734 static HRESULT
filedata_get_name(ID3DXFileData
*filedata
, char **name
)
3739 hr
= filedata
->lpVtbl
->GetName(filedata
, NULL
, &name_len
);
3740 if (FAILED(hr
)) return hr
;
3744 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
3745 if (!*name
) return E_OUTOFMEMORY
;
3747 hr
= filedata
->lpVtbl
->GetName(filedata
, *name
, &name_len
);
3749 HeapFree(GetProcessHeap(), 0, *name
);
3756 static HRESULT
load_mesh_container(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3757 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXMESHCONTAINER
**mesh_container
)
3760 ID3DXBuffer
*adjacency
= NULL
;
3761 ID3DXBuffer
*materials
= NULL
;
3762 ID3DXBuffer
*effects
= NULL
;
3763 ID3DXSkinInfo
*skin_info
= NULL
;
3764 D3DXMESHDATA mesh_data
;
3765 DWORD num_materials
= 0;
3768 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
3769 mesh_data
.u
.pMesh
= NULL
;
3771 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
3772 &adjacency
, &materials
, &effects
, &num_materials
,
3773 &skin_info
, &mesh_data
.u
.pMesh
);
3774 if (FAILED(hr
)) return hr
;
3776 hr
= filedata_get_name(filedata
, &name
);
3777 if (FAILED(hr
)) goto cleanup
;
3779 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
3780 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
3781 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
3783 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
3784 skin_info
, mesh_container
);
3787 if (materials
) ID3DXBuffer_Release(materials
);
3788 if (effects
) ID3DXBuffer_Release(effects
);
3789 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3790 if (skin_info
) IUnknown_Release(skin_info
);
3791 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
3792 HeapFree(GetProcessHeap(), 0, name
);
3796 static HRESULT
parse_transform_matrix(ID3DXFileData
*filedata
, D3DXMATRIX
*transform
)
3802 /* template Matrix4x4 {
3803 * array FLOAT matrix[16];
3805 * template FrameTransformMatrix {
3806 * Matrix4x4 frameMatrix;
3810 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3811 if (FAILED(hr
)) return hr
;
3813 if (data_size
!= sizeof(D3DXMATRIX
)) {
3814 WARN("incorrect data size (%ld bytes)\n", data_size
);
3815 filedata
->lpVtbl
->Unlock(filedata
);
3819 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
3821 filedata
->lpVtbl
->Unlock(filedata
);
3825 static HRESULT
load_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3826 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXFRAME
**frame_out
)
3830 ID3DXFileData
*child
;
3832 D3DXFRAME
*frame
= NULL
;
3833 D3DXMESHCONTAINER
**next_container
;
3834 D3DXFRAME
**next_child
;
3835 SIZE_T i
, nb_children
;
3837 hr
= filedata_get_name(filedata
, &name
);
3838 if (FAILED(hr
)) return hr
;
3840 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
3841 HeapFree(GetProcessHeap(), 0, name
);
3842 if (FAILED(hr
)) return E_FAIL
;
3845 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
3846 next_child
= &frame
->pFrameFirstChild
;
3847 next_container
= &frame
->pMeshContainer
;
3849 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3853 for (i
= 0; i
< nb_children
; i
++)
3855 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3858 hr
= child
->lpVtbl
->GetType(child
, &type
);
3862 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
3863 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
3865 next_container
= &(*next_container
)->pNextMeshContainer
;
3866 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
3867 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
3868 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
3869 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
3871 next_child
= &(*next_child
)->pFrameSibling
;
3876 IUnknown_Release(child
);
3881 IUnknown_Release(child
);
3885 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
3886 struct IDirect3DDevice9
*device
, struct ID3DXAllocateHierarchy
*alloc_hier
,
3887 struct ID3DXLoadUserData
*load_user_data
, D3DXFRAME
**frame_hierarchy
,
3888 struct ID3DXAnimationController
**anim_controller
)
3891 ID3DXFile
*d3dxfile
= NULL
;
3892 ID3DXFileEnumObject
*enumobj
= NULL
;
3893 ID3DXFileData
*filedata
= NULL
;
3894 D3DXF_FILELOADMEMORY source
;
3895 D3DXFRAME
*first_frame
= NULL
;
3896 D3DXFRAME
**next_frame
= &first_frame
;
3897 SIZE_T i
, nb_children
;
3900 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3901 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3903 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
3904 return D3DERR_INVALIDCALL
;
3905 if (load_user_data
|| anim_controller
) {
3907 FIXME("Loading user data not implemented\n");
3908 if (anim_controller
)
3909 FIXME("Animation controller creation not implemented\n");
3913 hr
= D3DXFileCreate(&d3dxfile
);
3914 if (FAILED(hr
)) goto cleanup
;
3916 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3917 if (FAILED(hr
)) goto cleanup
;
3919 source
.lpMemory
= (void*)memory
;
3920 source
.dSize
= memory_size
;
3921 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
3922 if (FAILED(hr
)) goto cleanup
;
3924 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
3928 for (i
= 0; i
< nb_children
; i
++)
3930 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
3934 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
3935 if (SUCCEEDED(hr
)) {
3936 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
3937 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
3943 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
3945 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
3946 if (FAILED(hr
)) goto cleanup
;
3947 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
3948 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
3949 if (FAILED(hr
)) goto cleanup
;
3952 next_frame
= &(*next_frame
)->pFrameSibling
;
3955 filedata
->lpVtbl
->Release(filedata
);
3963 } else if (first_frame
->pFrameSibling
) {
3964 D3DXFRAME
*root_frame
= NULL
;
3965 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
3970 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
3971 root_frame
->pFrameFirstChild
= first_frame
;
3972 *frame_hierarchy
= root_frame
;
3975 *frame_hierarchy
= first_frame
;
3980 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
3981 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
3982 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
3983 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
3987 HRESULT WINAPI
D3DXCleanMesh(D3DXCLEANTYPE clean_type
, ID3DXMesh
*mesh_in
, const DWORD
*adjacency_in
,
3988 ID3DXMesh
**mesh_out
, DWORD
*adjacency_out
, ID3DXBuffer
**errors_and_warnings
)
3990 FIXME("(%u, %p, %p, %p, %p, %p)\n", clean_type
, mesh_in
, adjacency_in
, mesh_out
, adjacency_out
, errors_and_warnings
);
3995 HRESULT WINAPI
D3DXFrameDestroy(D3DXFRAME
*frame
, ID3DXAllocateHierarchy
*alloc_hier
)
4000 TRACE("(%p, %p)\n", frame
, alloc_hier
);
4002 if (!frame
|| !alloc_hier
)
4003 return D3DERR_INVALIDCALL
;
4006 D3DXMESHCONTAINER
*container
;
4007 D3DXFRAME
*current_frame
;
4009 if (frame
->pFrameSibling
) {
4010 current_frame
= frame
->pFrameSibling
;
4011 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
4012 current_frame
->pFrameSibling
= NULL
;
4014 current_frame
= frame
;
4018 if (current_frame
->pFrameFirstChild
) {
4019 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
4020 if (FAILED(hr
)) return hr
;
4021 current_frame
->pFrameFirstChild
= NULL
;
4024 container
= current_frame
->pMeshContainer
;
4026 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
4027 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
4028 if (FAILED(hr
)) return hr
;
4029 container
= next_container
;
4031 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
4032 if (FAILED(hr
)) return hr
;
4037 HRESULT WINAPI
D3DXLoadMeshFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4038 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4039 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4045 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4046 "effect_instances %p, num_materials %p, mesh %p.\n",
4047 debugstr_a(filename
), options
, device
, adjacency
, materials
,
4048 effect_instances
, num_materials
, mesh
);
4051 return D3DERR_INVALIDCALL
;
4053 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
4054 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4055 if (!filenameW
) return E_OUTOFMEMORY
;
4056 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
4058 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
4059 effect_instances
, num_materials
, mesh
);
4060 HeapFree(GetProcessHeap(), 0, filenameW
);
4065 HRESULT WINAPI
D3DXLoadMeshFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4066 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4067 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4073 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4074 "effect_instances %p, num_materials %p, mesh %p.\n",
4075 debugstr_w(filename
), options
, device
, adjacency
, materials
,
4076 effect_instances
, num_materials
, mesh
);
4079 return D3DERR_INVALIDCALL
;
4081 hr
= map_view_of_file(filename
, &buffer
, &size
);
4083 return D3DXERR_INVALIDDATA
;
4085 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4086 materials
, effect_instances
, num_materials
, mesh
);
4088 UnmapViewOfFile(buffer
);
4093 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
, const char *name
, const char *type
, DWORD options
,
4094 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
,
4095 struct ID3DXBuffer
**effect_instances
, DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4102 TRACE("module %p, name %s, type %s, options %#x, device %p, adjacency %p, "
4103 "materials %p, effect_instances %p, num_materials %p, mesh %p.\n",
4104 module
, debugstr_a(name
), debugstr_a(type
), options
, device
, adjacency
,
4105 materials
, effect_instances
, num_materials
, mesh
);
4107 resinfo
= FindResourceA(module
, name
, type
);
4108 if (!resinfo
) return D3DXERR_INVALIDDATA
;
4110 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
4111 if (FAILED(hr
)) return D3DXERR_INVALIDDATA
;
4113 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4114 materials
, effect_instances
, num_materials
, mesh
);
4117 struct mesh_container
4121 ID3DXBuffer
*adjacency
;
4122 ID3DXBuffer
*materials
;
4123 ID3DXBuffer
*effects
;
4124 DWORD num_materials
;
4125 D3DXMATRIX transform
;
4128 static HRESULT
parse_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
4129 const D3DXMATRIX
*parent_transform
, struct list
*container_list
, DWORD provide_flags
)
4132 D3DXMATRIX transform
= *parent_transform
;
4133 ID3DXFileData
*child
;
4135 SIZE_T i
, nb_children
;
4137 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
4141 for (i
= 0; i
< nb_children
; i
++)
4143 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
4146 hr
= child
->lpVtbl
->GetType(child
, &type
);
4150 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
4151 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
4157 list_add_tail(container_list
, &container
->entry
);
4158 container
->transform
= transform
;
4160 hr
= D3DXLoadSkinMeshFromXof(child
, options
, device
,
4161 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
4162 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
4163 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
4164 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
4165 D3DXMATRIX new_transform
;
4166 hr
= parse_transform_matrix(child
, &new_transform
);
4167 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
4168 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
4169 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
4174 IUnknown_Release(child
);
4179 IUnknown_Release(child
);
4183 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
4184 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
4185 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXMesh
**mesh_out
)
4188 ID3DXFile
*d3dxfile
= NULL
;
4189 ID3DXFileEnumObject
*enumobj
= NULL
;
4190 ID3DXFileData
*filedata
= NULL
;
4191 D3DXF_FILELOADMEMORY source
;
4192 ID3DXBuffer
*materials
= NULL
;
4193 ID3DXBuffer
*effects
= NULL
;
4194 ID3DXBuffer
*adjacency
= NULL
;
4195 struct list container_list
= LIST_INIT(container_list
);
4196 struct mesh_container
*container_ptr
, *next_container_ptr
;
4197 DWORD num_materials
;
4198 DWORD num_faces
, num_vertices
;
4199 D3DXMATRIX identity
;
4200 DWORD provide_flags
= 0;
4202 ID3DXMesh
*concat_mesh
= NULL
;
4203 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
4204 BYTE
*concat_vertices
= NULL
;
4205 void *concat_indices
= NULL
;
4207 DWORD concat_vertex_size
;
4208 SIZE_T i
, nb_children
;
4211 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
4212 device
, adjacency_out
, materials_out
, effects_out
, num_materials_out
, mesh_out
);
4214 if (!memory
|| !memory_size
|| !device
|| !mesh_out
)
4215 return D3DERR_INVALIDCALL
;
4217 hr
= D3DXFileCreate(&d3dxfile
);
4218 if (FAILED(hr
)) goto cleanup
;
4220 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
4221 if (FAILED(hr
)) goto cleanup
;
4223 source
.lpMemory
= (void*)memory
;
4224 source
.dSize
= memory_size
;
4225 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
4226 if (FAILED(hr
)) goto cleanup
;
4228 D3DXMatrixIdentity(&identity
);
4229 if (adjacency_out
) provide_flags
|= PROVIDE_ADJACENCY
;
4230 if (materials_out
|| effects_out
) provide_flags
|= PROVIDE_MATERIALS
;
4232 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
4236 for (i
= 0; i
< nb_children
; i
++)
4238 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
4242 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
4243 if (SUCCEEDED(hr
)) {
4244 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
4245 container_ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container_ptr
));
4246 if (!container_ptr
) {
4250 list_add_tail(&container_list
, &container_ptr
->entry
);
4251 D3DXMatrixIdentity(&container_ptr
->transform
);
4253 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
4254 (provide_flags
& PROVIDE_ADJACENCY
) ? &container_ptr
->adjacency
: NULL
,
4255 (provide_flags
& PROVIDE_MATERIALS
) ? &container_ptr
->materials
: NULL
,
4256 NULL
, &container_ptr
->num_materials
, NULL
, &container_ptr
->mesh
);
4257 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
4258 hr
= parse_frame(filedata
, options
, device
, &identity
, &container_list
, provide_flags
);
4260 if (FAILED(hr
)) goto cleanup
;
4262 filedata
->lpVtbl
->Release(filedata
);
4268 enumobj
->lpVtbl
->Release(enumobj
);
4270 d3dxfile
->lpVtbl
->Release(d3dxfile
);
4273 if (list_empty(&container_list
)) {
4282 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4284 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4285 fvf
|= mesh
->lpVtbl
->GetFVF(mesh
);
4286 num_faces
+= mesh
->lpVtbl
->GetNumFaces(mesh
);
4287 num_vertices
+= mesh
->lpVtbl
->GetNumVertices(mesh
);
4288 num_materials
+= container_ptr
->num_materials
;
4291 hr
= D3DXCreateMeshFVF(num_faces
, num_vertices
, options
, fvf
, device
, &concat_mesh
);
4292 if (FAILED(hr
)) goto cleanup
;
4294 hr
= concat_mesh
->lpVtbl
->GetDeclaration(concat_mesh
, concat_decl
);
4295 if (FAILED(hr
)) goto cleanup
;
4297 concat_vertex_size
= D3DXGetDeclVertexSize(concat_decl
, 0);
4299 hr
= concat_mesh
->lpVtbl
->LockVertexBuffer(concat_mesh
, 0, (void**)&concat_vertices
);
4300 if (FAILED(hr
)) goto cleanup
;
4302 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4304 D3DVERTEXELEMENT9 mesh_decl
[MAX_FVF_DECL_SIZE
];
4305 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4306 DWORD num_mesh_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
4307 DWORD mesh_vertex_size
;
4308 const BYTE
*mesh_vertices
;
4311 hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, mesh_decl
);
4312 if (FAILED(hr
)) goto cleanup
;
4314 mesh_vertex_size
= D3DXGetDeclVertexSize(mesh_decl
, 0);
4316 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_vertices
);
4317 if (FAILED(hr
)) goto cleanup
;
4319 for (i
= 0; i
< num_mesh_vertices
; i
++) {
4323 D3DXVec3TransformCoord((D3DXVECTOR3
*)concat_vertices
,
4324 (D3DXVECTOR3
*)mesh_vertices
,
4325 &container_ptr
->transform
);
4326 for (j
= 1; concat_decl
[j
].Stream
!= 0xff; j
++)
4328 if (concat_decl
[j
].Usage
== mesh_decl
[k
].Usage
&&
4329 concat_decl
[j
].UsageIndex
== mesh_decl
[k
].UsageIndex
)
4331 if (concat_decl
[j
].Usage
== D3DDECLUSAGE_NORMAL
) {
4332 D3DXVec3TransformCoord((D3DXVECTOR3
*)(concat_vertices
+ concat_decl
[j
].Offset
),
4333 (D3DXVECTOR3
*)(mesh_vertices
+ mesh_decl
[k
].Offset
),
4334 &container_ptr
->transform
);
4336 memcpy(concat_vertices
+ concat_decl
[j
].Offset
,
4337 mesh_vertices
+ mesh_decl
[k
].Offset
,
4338 d3dx_decltype_size
[mesh_decl
[k
].Type
]);
4343 mesh_vertices
+= mesh_vertex_size
;
4344 concat_vertices
+= concat_vertex_size
;
4347 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
4350 concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4351 concat_vertices
= NULL
;
4353 hr
= concat_mesh
->lpVtbl
->LockIndexBuffer(concat_mesh
, 0, &concat_indices
);
4354 if (FAILED(hr
)) goto cleanup
;
4357 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4359 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4360 const void *mesh_indices
;
4361 DWORD num_mesh_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4364 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_indices
);
4365 if (FAILED(hr
)) goto cleanup
;
4367 if (options
& D3DXMESH_32BIT
) {
4368 DWORD
*dest
= concat_indices
;
4369 const DWORD
*src
= mesh_indices
;
4370 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4371 *dest
++ = index_offset
+ *src
++;
4372 concat_indices
= dest
;
4374 WORD
*dest
= concat_indices
;
4375 const WORD
*src
= mesh_indices
;
4376 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4377 *dest
++ = index_offset
+ *src
++;
4378 concat_indices
= dest
;
4380 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
4382 index_offset
+= num_mesh_faces
* 3;
4385 concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4386 concat_indices
= NULL
;
4388 if (num_materials
) {
4389 DWORD
*concat_attrib_buffer
= NULL
;
4392 hr
= concat_mesh
->lpVtbl
->LockAttributeBuffer(concat_mesh
, 0, &concat_attrib_buffer
);
4393 if (FAILED(hr
)) goto cleanup
;
4395 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4397 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4398 const DWORD
*mesh_attrib_buffer
= NULL
;
4399 DWORD count
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4401 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, D3DLOCK_READONLY
, (DWORD
**)&mesh_attrib_buffer
);
4403 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4408 *concat_attrib_buffer
++ = offset
+ *mesh_attrib_buffer
++;
4410 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
4411 offset
+= container_ptr
->num_materials
;
4413 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4416 if (materials_out
|| effects_out
) {
4417 D3DXMATERIAL
*out_ptr
;
4418 if (!num_materials
) {
4419 /* create default material */
4420 hr
= D3DXCreateBuffer(sizeof(D3DXMATERIAL
), &materials
);
4421 if (FAILED(hr
)) goto cleanup
;
4423 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4424 out_ptr
->MatD3D
.Diffuse
.r
= 0.5f
;
4425 out_ptr
->MatD3D
.Diffuse
.g
= 0.5f
;
4426 out_ptr
->MatD3D
.Diffuse
.b
= 0.5f
;
4427 out_ptr
->MatD3D
.Specular
.r
= 0.5f
;
4428 out_ptr
->MatD3D
.Specular
.g
= 0.5f
;
4429 out_ptr
->MatD3D
.Specular
.b
= 0.5f
;
4430 /* D3DXCreateBuffer initializes the rest to zero */
4432 DWORD buffer_size
= num_materials
* sizeof(D3DXMATERIAL
);
4433 char *strings_out_ptr
;
4435 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4437 if (container_ptr
->materials
) {
4439 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4440 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4442 if (in_ptr
->pTextureFilename
)
4443 buffer_size
+= strlen(in_ptr
->pTextureFilename
) + 1;
4449 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
4450 if (FAILED(hr
)) goto cleanup
;
4451 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4452 strings_out_ptr
= (char*)(out_ptr
+ num_materials
);
4454 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4456 if (container_ptr
->materials
) {
4458 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4459 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4461 out_ptr
->MatD3D
= in_ptr
->MatD3D
;
4462 if (in_ptr
->pTextureFilename
) {
4463 out_ptr
->pTextureFilename
= strings_out_ptr
;
4464 strcpy(out_ptr
->pTextureFilename
, in_ptr
->pTextureFilename
);
4465 strings_out_ptr
+= strlen(in_ptr
->pTextureFilename
) + 1;
4478 generate_effects(materials
, num_materials
, &effects
);
4479 if (!materials_out
) {
4480 ID3DXBuffer_Release(materials
);
4485 if (adjacency_out
) {
4486 if (!list_next(&container_list
, list_head(&container_list
))) {
4487 container_ptr
= LIST_ENTRY(list_head(&container_list
), struct mesh_container
, entry
);
4488 adjacency
= container_ptr
->adjacency
;
4489 container_ptr
->adjacency
= NULL
;
4494 hr
= D3DXCreateBuffer(num_faces
* 3 * sizeof(DWORD
), &adjacency
);
4495 if (FAILED(hr
)) goto cleanup
;
4497 out_ptr
= ID3DXBuffer_GetBufferPointer(adjacency
);
4498 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4501 DWORD count
= 3 * container_ptr
->mesh
->lpVtbl
->GetNumFaces(container_ptr
->mesh
);
4502 DWORD
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->adjacency
);
4504 for (i
= 0; i
< count
; i
++)
4505 *out_ptr
++ = offset
+ *in_ptr
++;
4512 *mesh_out
= concat_mesh
;
4513 if (adjacency_out
) *adjacency_out
= adjacency
;
4514 if (materials_out
) *materials_out
= materials
;
4515 if (effects_out
) *effects_out
= effects
;
4516 if (num_materials_out
) *num_materials_out
= num_materials
;
4520 if (concat_indices
) concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4521 if (concat_vertices
) concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4522 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
4523 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
4524 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4526 if (concat_mesh
) IUnknown_Release(concat_mesh
);
4527 if (materials
) ID3DXBuffer_Release(materials
);
4528 if (effects
) ID3DXBuffer_Release(effects
);
4529 if (adjacency
) ID3DXBuffer_Release(adjacency
);
4531 LIST_FOR_EACH_ENTRY_SAFE(container_ptr
, next_container_ptr
, &container_list
, struct mesh_container
, entry
)
4533 if (container_ptr
->mesh
) IUnknown_Release(container_ptr
->mesh
);
4534 if (container_ptr
->adjacency
) ID3DXBuffer_Release(container_ptr
->adjacency
);
4535 if (container_ptr
->materials
) ID3DXBuffer_Release(container_ptr
->materials
);
4536 if (container_ptr
->effects
) ID3DXBuffer_Release(container_ptr
->effects
);
4537 HeapFree(GetProcessHeap(), 0, container_ptr
);
4544 D3DXVECTOR3 position
;
4548 HRESULT WINAPI
D3DXCreateBox(struct IDirect3DDevice9
*device
, float width
, float height
,
4549 float depth
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4553 struct vertex
*vertices
;
4555 DWORD
*adjacency_buf
;
4556 unsigned int i
, face
;
4557 static const D3DXVECTOR3 unit_box
[] =
4559 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, -0.5f
},
4560 {-0.5f
, 0.5f
, -0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, -0.5f
},
4561 { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, -0.5f
},
4562 {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, 0.5f
},
4563 {-0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
},
4564 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}
4566 static const D3DXVECTOR3 normals
[] =
4568 {-1.0f
, 0.0f
, 0.0f
}, { 0.0f
, 1.0f
, 0.0f
}, { 1.0f
, 0.0f
, 0.0f
},
4569 { 0.0f
, -1.0f
, 0.0f
}, { 0.0f
, 0.0f
, 1.0f
}, { 0.0f
, 0.0f
, -1.0f
}
4571 static const DWORD adjacency_table
[] =
4573 6, 9, 1, 2, 10, 0, 1, 9, 3, 4, 10, 2,
4574 3, 8, 5, 7, 11, 4, 0, 11, 7, 5, 8, 6,
4575 7, 4, 9, 2, 0, 8, 1, 3, 11, 5, 6, 10
4578 TRACE("device %p, width %f, height %f, depth %f, mesh %p, adjacency %p\n",
4579 device
, width
, height
, depth
, mesh
, adjacency
);
4581 if (!device
|| width
< 0.0f
|| height
< 0.0f
|| depth
< 0.0f
|| !mesh
)
4583 return D3DERR_INVALIDCALL
;
4586 if (FAILED(hr
= D3DXCreateMeshFVF(12, 24, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &box
)))
4591 if (FAILED(hr
= box
->lpVtbl
->LockVertexBuffer(box
, 0, (void **)&vertices
)))
4593 box
->lpVtbl
->Release(box
);
4597 if (FAILED(hr
= box
->lpVtbl
->LockIndexBuffer(box
, 0, (void **)&faces
)))
4599 box
->lpVtbl
->UnlockVertexBuffer(box
);
4600 box
->lpVtbl
->Release(box
);
4604 for (i
= 0; i
< 24; i
++)
4606 vertices
[i
].position
.x
= width
* unit_box
[i
].x
;
4607 vertices
[i
].position
.y
= height
* unit_box
[i
].y
;
4608 vertices
[i
].position
.z
= depth
* unit_box
[i
].z
;
4609 vertices
[i
].normal
.x
= normals
[i
/ 4].x
;
4610 vertices
[i
].normal
.y
= normals
[i
/ 4].y
;
4611 vertices
[i
].normal
.z
= normals
[i
/ 4].z
;
4615 for (i
= 0; i
< 12; i
++)
4617 faces
[i
][0] = face
++;
4618 faces
[i
][1] = face
++;
4619 faces
[i
][2] = (i
% 2) ? face
- 4 : face
;
4622 box
->lpVtbl
->UnlockIndexBuffer(box
);
4623 box
->lpVtbl
->UnlockVertexBuffer(box
);
4627 if (FAILED(hr
= D3DXCreateBuffer(sizeof(adjacency_table
), adjacency
)))
4629 box
->lpVtbl
->Release(box
);
4633 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4634 memcpy(adjacency_buf
, adjacency_table
, sizeof(adjacency_table
));
4642 typedef WORD face
[3];
4650 static void free_sincos_table(struct sincos_table
*sincos_table
)
4652 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
4653 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4656 /* pre compute sine and cosine tables; caller must free */
4657 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
4662 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
4663 if (!sincos_table
->sin
)
4667 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
4668 if (!sincos_table
->cos
)
4670 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4674 angle
= angle_start
;
4675 for (i
= 0; i
< n
; i
++)
4677 sincos_table
->sin
[i
] = sinf(angle
);
4678 sincos_table
->cos
[i
] = cosf(angle
);
4679 angle
+= angle_step
;
4685 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
4687 return stack
*slices
+slice
+1;
4690 HRESULT WINAPI
D3DXCreateSphere(struct IDirect3DDevice9
*device
, float radius
, UINT slices
,
4691 UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4693 DWORD number_of_vertices
, number_of_faces
;
4696 struct vertex
*vertices
;
4698 float phi_step
, phi_start
;
4699 struct sincos_table phi
;
4700 float theta_step
, theta
, sin_theta
, cos_theta
;
4701 DWORD vertex
, face
, stack
, slice
;
4703 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
4705 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
4707 return D3DERR_INVALIDCALL
;
4710 number_of_vertices
= 2 + slices
* (stacks
-1);
4711 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
4713 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4714 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
4720 if (FAILED(hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, 0, (void **)&vertices
)))
4722 sphere
->lpVtbl
->Release(sphere
);
4726 if (FAILED(hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, 0, (void **)&faces
)))
4728 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4729 sphere
->lpVtbl
->Release(sphere
);
4733 /* phi = angle on xz plane wrt z axis */
4734 phi_step
= -2.0f
* D3DX_PI
/ slices
;
4735 phi_start
= D3DX_PI
/ 2.0f
;
4737 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
4739 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4740 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4741 sphere
->lpVtbl
->Release(sphere
);
4742 return E_OUTOFMEMORY
;
4745 /* theta = angle on xy plane wrt x axis */
4746 theta_step
= D3DX_PI
/ stacks
;
4752 vertices
[vertex
].normal
.x
= 0.0f
;
4753 vertices
[vertex
].normal
.y
= 0.0f
;
4754 vertices
[vertex
].normal
.z
= 1.0f
;
4755 vertices
[vertex
].position
.x
= 0.0f
;
4756 vertices
[vertex
].position
.y
= 0.0f
;
4757 vertices
[vertex
].position
.z
= radius
;
4760 for (stack
= 0; stack
< stacks
- 1; stack
++)
4762 sin_theta
= sinf(theta
);
4763 cos_theta
= cosf(theta
);
4765 for (slice
= 0; slice
< slices
; slice
++)
4767 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
4768 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
4769 vertices
[vertex
].normal
.z
= cos_theta
;
4770 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
4771 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
4772 vertices
[vertex
].position
.z
= radius
* cos_theta
;
4779 /* top stack is triangle fan */
4781 faces
[face
][1] = slice
+ 1;
4782 faces
[face
][2] = slice
;
4787 /* stacks in between top and bottom are quad strips */
4788 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4789 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4790 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4793 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4794 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
4795 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4801 theta
+= theta_step
;
4807 faces
[face
][2] = slice
;
4812 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4813 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4814 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4817 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4818 faces
[face
][1] = vertex_index(slices
, 0, stack
);
4819 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4824 vertices
[vertex
].position
.x
= 0.0f
;
4825 vertices
[vertex
].position
.y
= 0.0f
;
4826 vertices
[vertex
].position
.z
= -radius
;
4827 vertices
[vertex
].normal
.x
= 0.0f
;
4828 vertices
[vertex
].normal
.y
= 0.0f
;
4829 vertices
[vertex
].normal
.z
= -1.0f
;
4831 /* bottom stack is triangle fan */
4832 for (slice
= 1; slice
< slices
; slice
++)
4834 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4835 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4836 faces
[face
][2] = vertex
;
4840 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4841 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4842 faces
[face
][2] = vertex
;
4844 free_sincos_table(&phi
);
4845 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4846 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4851 if (FAILED(hr
= D3DXCreateBuffer(number_of_faces
* sizeof(DWORD
) * 3, adjacency
)))
4853 sphere
->lpVtbl
->Release(sphere
);
4857 if (FAILED(hr
= sphere
->lpVtbl
->GenerateAdjacency(sphere
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
4859 (*adjacency
)->lpVtbl
->Release(*adjacency
);
4860 sphere
->lpVtbl
->Release(sphere
);
4870 HRESULT WINAPI
D3DXCreateCylinder(struct IDirect3DDevice9
*device
, float radius1
, float radius2
,
4871 float length
, UINT slices
, UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4873 DWORD number_of_vertices
, number_of_faces
;
4875 ID3DXMesh
*cylinder
;
4876 struct vertex
*vertices
;
4878 float theta_step
, theta_start
;
4879 struct sincos_table theta
;
4880 float delta_radius
, radius
, radius_step
;
4881 float z
, z_step
, z_normal
;
4882 DWORD vertex
, face
, slice
, stack
;
4884 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
4886 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
4888 return D3DERR_INVALIDCALL
;
4893 FIXME("Case of adjacency != NULL not implemented.\n");
4897 number_of_vertices
= 2 + (slices
* (3 + stacks
));
4898 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
4900 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4901 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
4907 if (FAILED(hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, 0, (void **)&vertices
)))
4909 cylinder
->lpVtbl
->Release(cylinder
);
4913 if (FAILED(hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, 0, (void **)&faces
)))
4915 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4916 cylinder
->lpVtbl
->Release(cylinder
);
4920 /* theta = angle on xy plane wrt x axis */
4921 theta_step
= -2.0f
* D3DX_PI
/ slices
;
4922 theta_start
= D3DX_PI
/ 2.0f
;
4924 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
4926 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
4927 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4928 cylinder
->lpVtbl
->Release(cylinder
);
4929 return E_OUTOFMEMORY
;
4935 delta_radius
= radius1
- radius2
;
4937 radius_step
= delta_radius
/ stacks
;
4940 z_step
= length
/ stacks
;
4941 z_normal
= delta_radius
/ length
;
4942 if (isnan(z_normal
))
4947 vertices
[vertex
].normal
.x
= 0.0f
;
4948 vertices
[vertex
].normal
.y
= 0.0f
;
4949 vertices
[vertex
].normal
.z
= -1.0f
;
4950 vertices
[vertex
].position
.x
= 0.0f
;
4951 vertices
[vertex
].position
.y
= 0.0f
;
4952 vertices
[vertex
++].position
.z
= z
;
4954 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4956 vertices
[vertex
].normal
.x
= 0.0f
;
4957 vertices
[vertex
].normal
.y
= 0.0f
;
4958 vertices
[vertex
].normal
.z
= -1.0f
;
4959 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4960 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4961 vertices
[vertex
].position
.z
= z
;
4966 faces
[face
][1] = slice
;
4967 faces
[face
++][2] = slice
+ 1;
4972 faces
[face
][1] = slice
;
4973 faces
[face
++][2] = 1;
4975 for (stack
= 1; stack
<= stacks
+1; stack
++)
4977 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4979 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
4980 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
4981 vertices
[vertex
].normal
.z
= z_normal
;
4982 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
4983 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4984 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4985 vertices
[vertex
].position
.z
= z
;
4987 if (stack
> 1 && slice
> 0)
4989 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4990 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4991 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
4993 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4994 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4995 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5001 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
5002 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5003 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
5005 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
5006 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5007 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
5010 if (stack
< stacks
+ 1)
5013 radius
-= radius_step
;
5017 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5019 vertices
[vertex
].normal
.x
= 0.0f
;
5020 vertices
[vertex
].normal
.y
= 0.0f
;
5021 vertices
[vertex
].normal
.z
= 1.0f
;
5022 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5023 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5024 vertices
[vertex
].position
.z
= z
;
5028 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5029 faces
[face
][1] = number_of_vertices
- 1;
5030 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5034 vertices
[vertex
].position
.x
= 0.0f
;
5035 vertices
[vertex
].position
.y
= 0.0f
;
5036 vertices
[vertex
].position
.z
= z
;
5037 vertices
[vertex
].normal
.x
= 0.0f
;
5038 vertices
[vertex
].normal
.y
= 0.0f
;
5039 vertices
[vertex
].normal
.z
= 1.0f
;
5041 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5042 faces
[face
][1] = number_of_vertices
- 1;
5043 faces
[face
][2] = vertex_index(slices
, 0, stack
);
5045 free_sincos_table(&theta
);
5046 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5047 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5053 HRESULT WINAPI
D3DXCreateTeapot(struct IDirect3DDevice9
*device
,
5054 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
5056 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
5061 HRESULT WINAPI
D3DXCreateTextA(struct IDirect3DDevice9
*device
, HDC hdc
, const char *text
, float deviation
,
5062 float extrusion
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5068 TRACE("device %p, hdc %p, text %s, deviation %.8e, extrusion %.8e, mesh %p, adjacency %p, glyphmetrics %p.\n",
5069 device
, hdc
, debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
5072 return D3DERR_INVALIDCALL
;
5074 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
5075 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5076 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
5078 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
5079 mesh
, adjacency
, glyphmetrics
);
5080 HeapFree(GetProcessHeap(), 0, textW
);
5085 HRESULT WINAPI
D3DXCreateTorus(struct IDirect3DDevice9
*device
,
5086 float innerradius
, float outerradius
, UINT sides
, UINT rings
, struct ID3DXMesh
**mesh
, ID3DXBuffer
**adjacency
)
5091 struct vertex
*vertices
;
5092 float phi
, phi_step
, sin_phi
, cos_phi
;
5093 float theta
, theta_step
, sin_theta
, cos_theta
;
5094 unsigned int i
, j
, numvert
, numfaces
;
5096 TRACE("device %p, innerradius %.8e, outerradius %.8e, sides %u, rings %u, mesh %p, adjacency %p.\n",
5097 device
, innerradius
, outerradius
, sides
, rings
, mesh
, adjacency
);
5099 numvert
= sides
* rings
;
5100 numfaces
= numvert
* 2;
5102 if (!device
|| innerradius
< 0.0f
|| outerradius
< 0.0f
|| sides
< 3 || rings
< 3 || !mesh
)
5104 WARN("Invalid arguments.\n");
5105 return D3DERR_INVALIDCALL
;
5108 if (FAILED(hr
= D3DXCreateMeshFVF(numfaces
, numvert
, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &torus
)))
5111 if (FAILED(hr
= torus
->lpVtbl
->LockVertexBuffer(torus
, 0, (void **)&vertices
)))
5113 torus
->lpVtbl
->Release(torus
);
5117 if (FAILED(hr
= torus
->lpVtbl
->LockIndexBuffer(torus
, 0, (void **)&faces
)))
5119 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5120 torus
->lpVtbl
->Release(torus
);
5124 phi_step
= D3DX_PI
/ sides
* 2.0f
;
5125 theta_step
= D3DX_PI
/ rings
* -2.0f
;
5129 for (i
= 0; i
< rings
; ++i
)
5133 sin_theta
= sinf(theta
);
5134 cos_theta
= cosf(theta
);
5136 for (j
= 0; j
< sides
; ++j
)
5138 sin_phi
= sinf(phi
);
5139 cos_phi
= cosf(phi
);
5141 vertices
[i
* sides
+ j
].position
.x
= (innerradius
* cos_phi
+ outerradius
) * cos_theta
;
5142 vertices
[i
* sides
+ j
].position
.y
= (innerradius
* cos_phi
+ outerradius
) * sin_theta
;
5143 vertices
[i
* sides
+ j
].position
.z
= innerradius
* sin_phi
;
5144 vertices
[i
* sides
+ j
].normal
.x
= cos_phi
* cos_theta
;
5145 vertices
[i
* sides
+ j
].normal
.y
= cos_phi
* sin_theta
;
5146 vertices
[i
* sides
+ j
].normal
.z
= sin_phi
;
5151 theta
+= theta_step
;
5154 for (i
= 0; i
< numfaces
- sides
* 2; ++i
)
5156 faces
[i
][0] = i
% 2 ? i
/ 2 + sides
: i
/ 2;
5157 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5158 faces
[i
][2] = (i
+ 1) % (sides
* 2) ? (i
+ 1) / 2 + sides
: (i
+ 1) / 2;
5161 for (j
= 0; i
< numfaces
; ++i
, ++j
)
5163 faces
[i
][0] = i
% 2 ? j
/ 2 : i
/ 2;
5164 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5165 faces
[i
][2] = i
== numfaces
- 1 ? 0 : (j
+ 1) / 2;
5168 torus
->lpVtbl
->UnlockIndexBuffer(torus
);
5169 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5173 if (FAILED(hr
= D3DXCreateBuffer(numfaces
* sizeof(DWORD
) * 3, adjacency
)))
5175 torus
->lpVtbl
->Release(torus
);
5179 if (FAILED(hr
= torus
->lpVtbl
->GenerateAdjacency(torus
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
5181 (*adjacency
)->lpVtbl
->Release(*adjacency
);
5182 torus
->lpVtbl
->Release(torus
);
5193 POINTTYPE_CURVE
= 0,
5195 POINTTYPE_CURVE_START
,
5196 POINTTYPE_CURVE_END
,
5197 POINTTYPE_CURVE_MIDDLE
,
5203 enum pointtype corner
;
5206 struct dynamic_array
5208 int count
, capacity
;
5212 /* is a dynamic_array */
5215 int count
, capacity
;
5216 struct point2d
*items
;
5219 /* is a dynamic_array */
5220 struct outline_array
5222 int count
, capacity
;
5223 struct outline
*items
;
5232 struct point2d_index
5234 struct outline
*outline
;
5238 struct point2d_index_array
5241 struct point2d_index
*items
;
5246 struct outline_array outlines
;
5247 struct face_array faces
;
5248 struct point2d_index_array ordered_vertices
;
5252 /* is an dynamic_array */
5255 int count
, capacity
;
5259 /* complex polygons are split into monotone polygons, which have
5260 * at most 2 intersections with the vertical sweep line */
5261 struct triangulation
5263 struct word_array vertex_stack
;
5264 BOOL last_on_top
, merging
;
5267 /* is an dynamic_array */
5268 struct triangulation_array
5270 int count
, capacity
;
5271 struct triangulation
*items
;
5273 struct glyphinfo
*glyph
;
5276 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
5278 if (count
> array
->capacity
) {
5281 if (array
->items
&& array
->capacity
) {
5282 new_capacity
= max(array
->capacity
* 2, count
);
5283 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
5285 new_capacity
= max(16, count
);
5286 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
5290 array
->items
= new_buffer
;
5291 array
->capacity
= new_capacity
;
5296 static struct point2d
*add_points(struct outline
*array
, int num
)
5298 struct point2d
*item
;
5300 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
5303 item
= &array
->items
[array
->count
];
5304 array
->count
+= num
;
5308 static struct outline
*add_outline(struct outline_array
*array
)
5310 struct outline
*item
;
5312 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5315 item
= &array
->items
[array
->count
++];
5316 ZeroMemory(item
, sizeof(*item
));
5320 static inline face
*add_face(struct face_array
*array
)
5322 return &array
->items
[array
->count
++];
5325 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
5327 struct triangulation
*item
;
5329 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5332 item
= &array
->items
[array
->count
++];
5333 ZeroMemory(item
, sizeof(*item
));
5337 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
5339 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5340 return E_OUTOFMEMORY
;
5342 array
->items
[array
->count
++] = vertex_index
;
5346 /* assume fixed point numbers can be converted to float point in place */
5347 C_ASSERT(sizeof(FIXED
) == sizeof(float));
5348 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
5350 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, unsigned int emsquare
)
5352 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
5354 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
5355 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
5356 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
5362 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
5363 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
5364 float max_deviation_sq
)
5366 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
5369 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
5370 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
5371 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
5373 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
5374 if (deviation_sq
< max_deviation_sq
) {
5375 struct point2d
*pt
= add_points(outline
, 1);
5376 if (!pt
) return E_OUTOFMEMORY
;
5378 pt
->corner
= POINTTYPE_CURVE
;
5379 /* the end point is omitted because the end line merges into the next segment of
5380 * the split bezier curve, and the end of the split bezier curve is added outside
5381 * this recursive function. */
5383 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
5384 if (hr
!= S_OK
) return hr
;
5385 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
5386 if (hr
!= S_OK
) return hr
;
5392 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
5394 /* dot product = cos(theta) */
5395 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
5398 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
5400 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
5410 static BOOL
attempt_line_merge(struct outline
*outline
,
5412 const D3DXVECTOR2
*nextpt
,
5414 const struct cos_table
*table
)
5416 D3DXVECTOR2 curdir
, lastdir
;
5417 struct point2d
*prevpt
, *pt
;
5420 pt
= &outline
->items
[pt_index
];
5421 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5422 prevpt
= &outline
->items
[pt_index
];
5425 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
5427 if (outline
->count
< 2)
5430 /* remove last point if the next line continues the last line */
5431 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5432 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5433 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
5436 if (pt
->corner
== POINTTYPE_CURVE_END
)
5437 prevpt
->corner
= pt
->corner
;
5438 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
5439 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5443 if (outline
->count
< 2)
5446 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5447 prevpt
= &outline
->items
[pt_index
];
5448 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5449 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5454 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
5455 float max_deviation_sq
, unsigned int emsquare
,
5456 const struct cos_table
*cos_table
)
5458 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
5460 while ((char *)header
< (char *)raw_outline
+ datasize
)
5462 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
5463 struct point2d
*lastpt
, *pt
;
5464 D3DXVECTOR2 lastdir
;
5465 D3DXVECTOR2
*pt_flt
;
5467 struct outline
*outline
= add_outline(&glyph
->outlines
);
5470 return E_OUTOFMEMORY
;
5472 pt
= add_points(outline
, 1);
5474 return E_OUTOFMEMORY
;
5475 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
5477 pt
->corner
= POINTTYPE_CORNER
;
5479 if (header
->dwType
!= TT_POLYGON_TYPE
)
5480 FIXME("Unknown header type %d\n", header
->dwType
);
5482 while ((char *)curve
< (char *)header
+ header
->cb
)
5484 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
5485 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
5486 unsigned int j2
= 0;
5489 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5493 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
5495 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
5500 int count
= curve
->cpfx
;
5504 D3DXVECTOR2 bezier_end
;
5506 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j2
], &pt_flt
[j2
+1]), 0.5f
);
5507 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &bezier_end
, max_deviation_sq
);
5510 bezier_start
= bezier_end
;
5514 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &pt_flt
[j2
+1], max_deviation_sq
);
5518 pt
= add_points(outline
, 1);
5520 return E_OUTOFMEMORY
;
5522 pt
->pos
= pt_flt
[j2
];
5523 pt
->corner
= POINTTYPE_CURVE_END
;
5525 pt
= add_points(outline
, curve
->cpfx
);
5527 return E_OUTOFMEMORY
;
5528 for (j2
= 0; j2
< curve
->cpfx
; j2
++)
5530 pt
->pos
= pt_flt
[j2
];
5531 pt
->corner
= POINTTYPE_CORNER
;
5536 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5539 /* remove last point if the next line continues the last line */
5540 if (outline
->count
>= 3) {
5543 lastpt
= &outline
->items
[outline
->count
- 1];
5544 pt
= &outline
->items
[0];
5545 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
5546 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
5548 if (pt
->corner
== POINTTYPE_CURVE_START
)
5549 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5551 pt
->corner
= POINTTYPE_CURVE_END
;
5554 lastpt
= &outline
->items
[outline
->count
- 1];
5556 /* outline closed with a line from end to start point */
5557 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
5559 lastpt
= &outline
->items
[0];
5560 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
5561 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
5562 lastpt
->corner
= POINTTYPE_CORNER
;
5563 pt
= &outline
->items
[1];
5564 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
5565 *lastpt
= outline
->items
[outline
->count
];
5568 lastpt
= &outline
->items
[outline
->count
- 1];
5569 pt
= &outline
->items
[0];
5570 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
5571 for (j
= 0; j
< outline
->count
; j
++)
5576 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
5577 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
5579 switch (lastpt
->corner
)
5581 case POINTTYPE_CURVE_START
:
5582 case POINTTYPE_CURVE_END
:
5583 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
5584 lastpt
->corner
= POINTTYPE_CORNER
;
5586 case POINTTYPE_CURVE_MIDDLE
:
5587 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
5588 lastpt
->corner
= POINTTYPE_CORNER
;
5590 lastpt
->corner
= POINTTYPE_CURVE
;
5598 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
5603 /* Get the y-distance from a line to a point */
5604 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
5605 D3DXVECTOR2
*line_pt2
,
5608 D3DXVECTOR2 line_vec
= {0, 0};
5612 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
5613 line_pt_dx
= point
->x
- line_pt1
->x
;
5614 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
5615 return point
->y
- line_y
;
5618 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
5620 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
5623 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
5625 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
5628 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
5630 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
5631 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
5635 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
5636 struct triangulation_array
*triangulations
,
5640 struct glyphinfo
*glyph
= triangulations
->glyph
;
5641 struct triangulation
*t
= *t_ptr
;
5646 if (t
->last_on_top
) {
5654 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
5655 /* consume all vertices on the stack */
5656 WORD last_pt
= t
->vertex_stack
.items
[0];
5658 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
5660 face
= add_face(&glyph
->faces
);
5661 if (!face
) return E_OUTOFMEMORY
;
5662 (*face
)[0] = vtx_idx
;
5663 (*face
)[f1
] = last_pt
;
5664 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
5666 t
->vertex_stack
.items
[0] = last_pt
;
5667 t
->vertex_stack
.count
= 1;
5668 } else if (t
->vertex_stack
.count
> 1) {
5669 int i
= t
->vertex_stack
.count
- 1;
5670 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
5671 WORD top_idx
= t
->vertex_stack
.items
[i
--];
5672 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
5676 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
5677 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
5679 if (prev_pt
->x
!= top_pt
->x
&&
5680 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
5681 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
5684 face
= add_face(&glyph
->faces
);
5685 if (!face
) return E_OUTOFMEMORY
;
5686 (*face
)[0] = vtx_idx
;
5687 (*face
)[f1
] = prev_idx
;
5688 (*face
)[f2
] = top_idx
;
5692 t
->vertex_stack
.count
--;
5695 t
->last_on_top
= to_top
;
5697 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
5699 if (hr
== S_OK
&& t
->merging
) {
5700 struct triangulation
*t2
;
5702 t2
= to_top
? t
- 1 : t
+ 1;
5703 t2
->merging
= FALSE
;
5704 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
5705 if (hr
!= S_OK
) return hr
;
5706 remove_triangulation(triangulations
, t
);
5714 /* check if the point is next on the outline for either the top or bottom */
5715 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
5717 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
5718 WORD idx
= t
->vertex_stack
.items
[i
];
5719 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
5720 struct outline
*outline
= pt_idx
->outline
;
5723 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
5725 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
5727 return &outline
->items
[i
].pos
;
5730 static int compare_vertex_indices(const void *a
, const void *b
)
5732 const struct point2d_index
*idx1
= a
, *idx2
= b
;
5733 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
5734 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
5735 float diff
= p1
->x
- p2
->x
;
5738 diff
= p1
->y
- p2
->y
;
5740 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
5743 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
5747 struct glyphinfo
*glyph
= triangulations
->glyph
;
5748 int nb_vertices
= 0;
5750 struct point2d_index
*idx_ptr
;
5752 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5753 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
5755 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
5756 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
5757 if (!glyph
->ordered_vertices
.items
)
5758 return E_OUTOFMEMORY
;
5760 idx_ptr
= glyph
->ordered_vertices
.items
;
5761 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5763 struct outline
*outline
= &glyph
->outlines
.items
[i
];
5766 idx_ptr
->outline
= outline
;
5767 idx_ptr
->vertex
= 0;
5769 for (j
= outline
->count
- 1; j
> 0; j
--)
5771 idx_ptr
->outline
= outline
;
5772 idx_ptr
->vertex
= j
;
5776 glyph
->ordered_vertices
.count
= nb_vertices
;
5778 /* Native implementation seems to try to create a triangle fan from
5779 * the first outline point if the glyph only has one outline. */
5780 if (glyph
->outlines
.count
== 1)
5782 struct outline
*outline
= glyph
->outlines
.items
;
5783 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
5784 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
5787 for (i
= 2; i
< outline
->count
; i
++)
5789 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
5790 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
5791 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
5793 D3DXVec2Subtract(&v1
, base
, last
);
5794 D3DXVec2Subtract(&v2
, last
, next
);
5795 ccw
= D3DXVec2CCW(&v1
, &v2
);
5803 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5804 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
5805 if (!glyph
->faces
.items
)
5806 return E_OUTOFMEMORY
;
5808 glyph
->faces
.count
= outline
->count
- 2;
5809 for (i
= 0; i
< glyph
->faces
.count
; i
++)
5811 glyph
->faces
.items
[i
][0] = 0;
5812 glyph
->faces
.items
[i
][1] = i
+ 1;
5813 glyph
->faces
.items
[i
][2] = i
+ 2;
5819 /* Perform 2D polygon triangulation for complex glyphs.
5820 * Triangulation is performed using a sweep line concept, from right to left,
5821 * by processing vertices in sorted order. Complex polygons are split into
5822 * monotone polygons which are triangulated separately. */
5823 /* FIXME: The order of the faces is not consistent with the native implementation. */
5825 /* Reserve space for maximum possible faces from triangulation.
5826 * # faces for outer outlines = outline->count - 2
5827 * # faces for inner outlines = outline->count + 2
5828 * There must be at least 1 outer outline. */
5829 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5830 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
5831 if (!glyph
->faces
.items
)
5832 return E_OUTOFMEMORY
;
5834 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
5835 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
5836 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
5839 int end
= triangulations
->count
;
5843 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
5844 int current
= (start
+ end
) / 2;
5845 struct triangulation
*t
= &triangulations
->items
[current
];
5846 BOOL on_top_outline
= FALSE
;
5847 D3DXVECTOR2
*top_next
, *bottom_next
;
5848 WORD top_idx
, bottom_idx
;
5850 if (t
->merging
&& t
->last_on_top
)
5851 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
5853 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
5854 if (sweep_vtx
== top_next
)
5856 if (t
->merging
&& t
->last_on_top
)
5858 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
5859 if (hr
!= S_OK
) return hr
;
5861 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
5862 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
5864 /* point also on bottom outline of higher triangulation */
5865 struct triangulation
*t2
= t
+ 1;
5866 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
5867 if (hr
!= S_OK
) return hr
;
5872 on_top_outline
= TRUE
;
5875 if (t
->merging
&& !t
->last_on_top
)
5876 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
5878 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
5879 if (sweep_vtx
== bottom_next
)
5881 if (t
->merging
&& !t
->last_on_top
)
5883 if (on_top_outline
) {
5884 /* outline finished */
5885 remove_triangulation(triangulations
, t
);
5889 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
5890 if (hr
!= S_OK
) return hr
;
5892 if (t
> triangulations
->items
&&
5893 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
5895 struct triangulation
*t2
= t
- 1;
5896 /* point also on top outline of lower triangulation */
5897 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
5898 if (hr
!= S_OK
) return hr
;
5899 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
5909 if (t
->last_on_top
) {
5910 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
5911 bottom_idx
= t
->vertex_stack
.items
[0];
5913 top_idx
= t
->vertex_stack
.items
[0];
5914 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
5917 /* check if the point is inside or outside this polygon */
5918 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
5919 top_next
, sweep_vtx
) > 0)
5921 start
= current
+ 1;
5922 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
5923 bottom_next
, sweep_vtx
) < 0)
5926 } else if (t
->merging
) {
5927 /* inside, so cancel merging */
5928 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
5930 t2
->merging
= FALSE
;
5931 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
5932 if (hr
!= S_OK
) return hr
;
5933 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
5934 if (hr
!= S_OK
) return hr
;
5937 /* inside, so split polygon into two monotone parts */
5938 struct triangulation
*t2
= add_triangulation(triangulations
);
5939 if (!t2
) return E_OUTOFMEMORY
;
5940 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
5941 if (t
->last_on_top
) {
5948 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
5949 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
5950 if (hr
!= S_OK
) return hr
;
5951 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
5952 if (hr
!= S_OK
) return hr
;
5953 t2
->last_on_top
= !t
->last_on_top
;
5955 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
5956 if (hr
!= S_OK
) return hr
;
5962 struct triangulation
*t
;
5963 struct triangulation
*t2
= add_triangulation(triangulations
);
5964 if (!t2
) return E_OUTOFMEMORY
;
5965 t
= &triangulations
->items
[start
];
5966 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
5967 ZeroMemory(t
, sizeof(*t
));
5968 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
5969 if (hr
!= S_OK
) return hr
;
5975 HRESULT WINAPI
D3DXCreateTextW(struct IDirect3DDevice9
*device
, HDC hdc
, const WCHAR
*text
, float deviation
,
5976 float extrusion
, struct ID3DXMesh
**mesh_ptr
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5979 ID3DXMesh
*mesh
= NULL
;
5980 DWORD nb_vertices
, nb_faces
;
5981 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
5982 struct vertex
*vertices
= NULL
;
5987 OUTLINETEXTMETRICW otm
;
5988 HFONT font
= NULL
, oldfont
= NULL
;
5989 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
5990 void *raw_outline
= NULL
;
5992 struct glyphinfo
*glyphs
= NULL
;
5994 struct triangulation_array triangulations
= {0, 0, NULL
};
5996 struct vertex
*vertex_ptr
;
5998 float max_deviation_sq
;
5999 const struct cos_table cos_table
= {
6000 cosf(D3DXToRadian(0.5f
)),
6001 cosf(D3DXToRadian(45.0f
)),
6002 cosf(D3DXToRadian(90.0f
)),
6006 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
6007 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
6009 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
6010 return D3DERR_INVALIDCALL
;
6014 FIXME("Case of adjacency != NULL not implemented.\n");
6018 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
6019 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
6021 return D3DERR_INVALIDCALL
;
6024 if (deviation
== 0.0f
)
6025 deviation
= 1.0f
/ otm
.otmEMSquare
;
6026 max_deviation_sq
= deviation
* deviation
;
6028 lf
.lfHeight
= otm
.otmEMSquare
;
6030 font
= CreateFontIndirectW(&lf
);
6035 oldfont
= SelectObject(hdc
, font
);
6037 textlen
= strlenW(text
);
6038 for (i
= 0; i
< textlen
; i
++)
6040 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
6042 return D3DERR_INVALIDCALL
;
6043 if (bufsize
< datasize
)
6046 if (!bufsize
) { /* e.g. text == " " */
6047 hr
= D3DERR_INVALIDCALL
;
6051 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
6052 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
6053 if (!glyphs
|| !raw_outline
) {
6059 for (i
= 0; i
< textlen
; i
++)
6061 /* get outline points from data returned from GetGlyphOutline */
6064 glyphs
[i
].offset_x
= offset_x
;
6066 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
6067 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
6068 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
6069 if (hr
!= S_OK
) goto error
;
6071 triangulations
.glyph
= &glyphs
[i
];
6072 hr
= triangulate(&triangulations
);
6073 if (hr
!= S_OK
) goto error
;
6074 if (triangulations
.count
) {
6075 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
6076 triangulations
.count
= 0;
6081 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
6082 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
6083 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
6084 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
6085 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6086 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
6088 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6091 /* corner points need an extra vertex for the different side faces normals */
6093 nb_outline_points
= 0;
6095 for (i
= 0; i
< textlen
; i
++)
6098 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
6099 nb_front_faces
+= glyphs
[i
].faces
.count
;
6100 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6103 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6104 nb_corners
++; /* first outline point always repeated as a corner */
6105 for (k
= 1; k
< outline
->count
; k
++)
6106 if (outline
->items
[k
].corner
)
6111 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
6112 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
6115 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
6116 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
6120 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
6123 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, (void **)&faces
)))
6126 /* convert 2D vertices and faces into 3D mesh */
6127 vertex_ptr
= vertices
;
6129 if (extrusion
== 0.0f
) {
6136 for (i
= 0; i
< textlen
; i
++)
6140 struct vertex
*back_vertices
;
6143 /* side vertices and faces */
6144 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6146 struct vertex
*outline_vertices
= vertex_ptr
;
6147 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6149 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
6150 struct point2d
*pt
= &outline
->items
[0];
6152 for (k
= 1; k
<= outline
->count
; k
++)
6155 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
6156 WORD vtx_idx
= vertex_ptr
- vertices
;
6159 if (pt
->corner
== POINTTYPE_CURVE_START
)
6160 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
6161 else if (pt
->corner
)
6162 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6164 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
6165 D3DXVec2Normalize(&vec
, &vec
);
6166 vtx
.normal
.x
= -vec
.y
;
6167 vtx
.normal
.y
= vec
.x
;
6170 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
6171 vtx
.position
.y
= pt
->pos
.y
;
6173 *vertex_ptr
++ = vtx
;
6175 vtx
.position
.z
= -extrusion
;
6176 *vertex_ptr
++ = vtx
;
6178 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
6179 vtx
.position
.y
= nextpt
->pos
.y
;
6180 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
6181 vtx
.position
.z
= -extrusion
;
6182 *vertex_ptr
++ = vtx
;
6184 *vertex_ptr
++ = vtx
;
6186 (*face_ptr
)[0] = vtx_idx
;
6187 (*face_ptr
)[1] = vtx_idx
+ 2;
6188 (*face_ptr
)[2] = vtx_idx
+ 1;
6191 (*face_ptr
)[0] = vtx_idx
;
6192 (*face_ptr
)[1] = vtx_idx
+ 3;
6193 (*face_ptr
)[2] = vtx_idx
+ 2;
6196 if (nextpt
->corner
) {
6197 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
6198 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
6199 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
6201 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6203 D3DXVec2Normalize(&vec
, &vec
);
6204 vtx
.normal
.x
= -vec
.y
;
6205 vtx
.normal
.y
= vec
.x
;
6208 *vertex_ptr
++ = vtx
;
6209 vtx
.position
.z
= -extrusion
;
6210 *vertex_ptr
++ = vtx
;
6213 (*face_ptr
)[0] = vtx_idx
;
6214 (*face_ptr
)[1] = vtx_idx
+ 3;
6215 (*face_ptr
)[2] = vtx_idx
+ 1;
6218 (*face_ptr
)[0] = vtx_idx
;
6219 (*face_ptr
)[1] = vtx_idx
+ 2;
6220 (*face_ptr
)[2] = vtx_idx
+ 3;
6228 *vertex_ptr
++ = *outline_vertices
++;
6229 *vertex_ptr
++ = *outline_vertices
++;
6233 /* back vertices and faces */
6234 back_faces
= face_ptr
;
6235 back_vertices
= vertex_ptr
;
6236 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
6238 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
6239 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
6240 vertex_ptr
->position
.y
= pt
->y
;
6241 vertex_ptr
->position
.z
= 0;
6242 vertex_ptr
->normal
.x
= 0;
6243 vertex_ptr
->normal
.y
= 0;
6244 vertex_ptr
->normal
.z
= 1;
6247 count
= back_vertices
- vertices
;
6248 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
6250 face
*f
= &glyphs
[i
].faces
.items
[j
];
6251 (*face_ptr
)[0] = (*f
)[0] + count
;
6252 (*face_ptr
)[1] = (*f
)[1] + count
;
6253 (*face_ptr
)[2] = (*f
)[2] + count
;
6257 /* front vertices and faces */
6258 j
= count
= vertex_ptr
- back_vertices
;
6261 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
6262 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
6263 vertex_ptr
->position
.z
= -extrusion
;
6264 vertex_ptr
->normal
.x
= 0;
6265 vertex_ptr
->normal
.y
= 0;
6266 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
6270 j
= face_ptr
- back_faces
;
6273 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
6274 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
6275 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
6285 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6286 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6287 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
6290 for (i
= 0; i
< textlen
; i
++)
6293 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6294 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
6295 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
6296 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
6297 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
6299 HeapFree(GetProcessHeap(), 0, glyphs
);
6301 if (triangulations
.items
) {
6303 for (i
= 0; i
< triangulations
.count
; i
++)
6304 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
6305 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
6307 HeapFree(GetProcessHeap(), 0, raw_outline
);
6308 if (oldfont
) SelectObject(hdc
, oldfont
);
6309 if (font
) DeleteObject(font
);
6314 HRESULT WINAPI
D3DXValidMesh(ID3DXMesh
*mesh
, const DWORD
*adjacency
, ID3DXBuffer
**errors_and_warnings
)
6316 FIXME("(%p, %p, %p): stub\n", mesh
, adjacency
, *errors_and_warnings
);
6321 static BOOL
weld_float1(void *to
, void *from
, FLOAT epsilon
)
6326 if (fabsf(*v1
- *v2
) <= epsilon
)
6336 static BOOL
weld_float2(void *to
, void *from
, FLOAT epsilon
)
6338 D3DXVECTOR2
*v1
= to
;
6339 D3DXVECTOR2
*v2
= from
;
6340 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6341 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6342 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6344 if (max_abs_diff
<= epsilon
)
6346 memcpy(to
, from
, sizeof(D3DXVECTOR2
));
6354 static BOOL
weld_float3(void *to
, void *from
, FLOAT epsilon
)
6356 D3DXVECTOR3
*v1
= to
;
6357 D3DXVECTOR3
*v2
= from
;
6358 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6359 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6360 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6361 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6362 max_abs_diff
= max(diff_z
, max_abs_diff
);
6364 if (max_abs_diff
<= epsilon
)
6366 memcpy(to
, from
, sizeof(D3DXVECTOR3
));
6374 static BOOL
weld_float4(void *to
, void *from
, FLOAT epsilon
)
6376 D3DXVECTOR4
*v1
= to
;
6377 D3DXVECTOR4
*v2
= from
;
6378 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6379 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6380 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6381 FLOAT diff_w
= fabsf(v1
->w
- v2
->w
);
6382 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6383 max_abs_diff
= max(diff_z
, max_abs_diff
);
6384 max_abs_diff
= max(diff_w
, max_abs_diff
);
6386 if (max_abs_diff
<= epsilon
)
6388 memcpy(to
, from
, sizeof(D3DXVECTOR4
));
6396 static BOOL
weld_ubyte4(void *to
, void *from
, FLOAT epsilon
)
6400 BYTE truncated_epsilon
= (BYTE
)epsilon
;
6401 BYTE diff_x
= b1
[0] > b2
[0] ? b1
[0] - b2
[0] : b2
[0] - b1
[0];
6402 BYTE diff_y
= b1
[1] > b2
[1] ? b1
[1] - b2
[1] : b2
[1] - b1
[1];
6403 BYTE diff_z
= b1
[2] > b2
[2] ? b1
[2] - b2
[2] : b2
[2] - b1
[2];
6404 BYTE diff_w
= b1
[3] > b2
[3] ? b1
[3] - b2
[3] : b2
[3] - b1
[3];
6405 BYTE max_diff
= max(diff_x
, diff_y
);
6406 max_diff
= max(diff_z
, max_diff
);
6407 max_diff
= max(diff_w
, max_diff
);
6409 if (max_diff
<= truncated_epsilon
)
6411 memcpy(to
, from
, 4 * sizeof(BYTE
));
6419 static BOOL
weld_ubyte4n(void *to
, void *from
, FLOAT epsilon
)
6421 return weld_ubyte4(to
, from
, epsilon
* UCHAR_MAX
);
6424 static BOOL
weld_d3dcolor(void *to
, void *from
, FLOAT epsilon
)
6426 return weld_ubyte4n(to
, from
, epsilon
);
6429 static BOOL
weld_short2(void *to
, void *from
, FLOAT epsilon
)
6433 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6434 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6435 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6436 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6438 if (max_abs_diff
<= truncated_epsilon
)
6440 memcpy(to
, from
, 2 * sizeof(SHORT
));
6448 static BOOL
weld_short2n(void *to
, void *from
, FLOAT epsilon
)
6450 return weld_short2(to
, from
, epsilon
* SHRT_MAX
);
6453 static BOOL
weld_short4(void *to
, void *from
, FLOAT epsilon
)
6457 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6458 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6459 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6460 SHORT diff_z
= abs(s1
[2] - s2
[2]);
6461 SHORT diff_w
= abs(s1
[3] - s2
[3]);
6462 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6463 max_abs_diff
= max(diff_z
, max_abs_diff
);
6464 max_abs_diff
= max(diff_w
, max_abs_diff
);
6466 if (max_abs_diff
<= truncated_epsilon
)
6468 memcpy(to
, from
, 4 * sizeof(SHORT
));
6476 static BOOL
weld_short4n(void *to
, void *from
, FLOAT epsilon
)
6478 return weld_short4(to
, from
, epsilon
* SHRT_MAX
);
6481 static BOOL
weld_ushort2n(void *to
, void *from
, FLOAT epsilon
)
6485 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6486 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6487 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6488 USHORT max_diff
= max(diff_x
, diff_y
);
6490 if (max_diff
<= scaled_epsilon
)
6492 memcpy(to
, from
, 2 * sizeof(USHORT
));
6500 static BOOL
weld_ushort4n(void *to
, void *from
, FLOAT epsilon
)
6504 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6505 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6506 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6507 USHORT diff_z
= s1
[2] > s2
[2] ? s1
[2] - s2
[2] : s2
[2] - s1
[2];
6508 USHORT diff_w
= s1
[3] > s2
[3] ? s1
[3] - s2
[3] : s2
[3] - s1
[3];
6509 USHORT max_diff
= max(diff_x
, diff_y
);
6510 max_diff
= max(diff_z
, max_diff
);
6511 max_diff
= max(diff_w
, max_diff
);
6513 if (max_diff
<= scaled_epsilon
)
6515 memcpy(to
, from
, 4 * sizeof(USHORT
));
6531 static struct udec3
dword_to_udec3(DWORD d
)
6536 v
.y
= (d
& 0xffc00) >> 10;
6537 v
.z
= (d
& 0x3ff00000) >> 20;
6538 v
.w
= (d
& 0xc0000000) >> 30;
6543 static BOOL
weld_udec3(void *to
, void *from
, FLOAT epsilon
)
6547 struct udec3 v1
= dword_to_udec3(*d1
);
6548 struct udec3 v2
= dword_to_udec3(*d2
);
6549 UINT truncated_epsilon
= (UINT
)epsilon
;
6550 UINT diff_x
= v1
.x
> v2
.x
? v1
.x
- v2
.x
: v2
.x
- v1
.x
;
6551 UINT diff_y
= v1
.y
> v2
.y
? v1
.y
- v2
.y
: v2
.y
- v1
.y
;
6552 UINT diff_z
= v1
.z
> v2
.z
? v1
.z
- v2
.z
: v2
.z
- v1
.z
;
6553 UINT diff_w
= v1
.w
> v2
.w
? v1
.w
- v2
.w
: v2
.w
- v1
.w
;
6554 UINT max_diff
= max(diff_x
, diff_y
);
6555 max_diff
= max(diff_z
, max_diff
);
6556 max_diff
= max(diff_w
, max_diff
);
6558 if (max_diff
<= truncated_epsilon
)
6560 memcpy(to
, from
, sizeof(DWORD
));
6576 static struct dec3n
dword_to_dec3n(DWORD d
)
6581 v
.y
= (d
& 0xffc00) >> 10;
6582 v
.z
= (d
& 0x3ff00000) >> 20;
6583 v
.w
= (d
& 0xc0000000) >> 30;
6588 static BOOL
weld_dec3n(void *to
, void *from
, FLOAT epsilon
)
6590 const UINT MAX_DEC3N
= 511;
6593 struct dec3n v1
= dword_to_dec3n(*d1
);
6594 struct dec3n v2
= dword_to_dec3n(*d2
);
6595 INT scaled_epsilon
= (INT
)(epsilon
* MAX_DEC3N
);
6596 INT diff_x
= abs(v1
.x
- v2
.x
);
6597 INT diff_y
= abs(v1
.y
- v2
.y
);
6598 INT diff_z
= abs(v1
.z
- v2
.z
);
6599 INT diff_w
= abs(v1
.w
- v2
.w
);
6600 INT max_abs_diff
= max(diff_x
, diff_y
);
6601 max_abs_diff
= max(diff_z
, max_abs_diff
);
6602 max_abs_diff
= max(diff_w
, max_abs_diff
);
6604 if (max_abs_diff
<= scaled_epsilon
)
6606 memcpy(to
, from
, sizeof(DWORD
));
6614 static BOOL
weld_float16_2(void *to
, void *from
, FLOAT epsilon
)
6616 D3DXFLOAT16
*v1_float16
= to
;
6617 D3DXFLOAT16
*v2_float16
= from
;
6625 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6626 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6628 diff_x
= fabsf(v1
[0] - v2
[0]);
6629 diff_y
= fabsf(v1
[1] - v2
[1]);
6630 max_abs_diff
= max(diff_x
, diff_y
);
6632 if (max_abs_diff
<= epsilon
)
6634 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6643 static BOOL
weld_float16_4(void *to
, void *from
, FLOAT epsilon
)
6645 D3DXFLOAT16
*v1_float16
= to
;
6646 D3DXFLOAT16
*v2_float16
= from
;
6656 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6657 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6659 diff_x
= fabsf(v1
[0] - v2
[0]);
6660 diff_y
= fabsf(v1
[1] - v2
[1]);
6661 diff_z
= fabsf(v1
[2] - v2
[2]);
6662 diff_w
= fabsf(v1
[3] - v2
[3]);
6663 max_abs_diff
= max(diff_x
, diff_y
);
6664 max_abs_diff
= max(diff_z
, max_abs_diff
);
6665 max_abs_diff
= max(diff_w
, max_abs_diff
);
6667 if (max_abs_diff
<= epsilon
)
6669 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6678 /* Sets the vertex components to the same value if they are within epsilon. */
6679 static BOOL
weld_component(void *to
, void *from
, D3DDECLTYPE type
, FLOAT epsilon
)
6681 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6682 BOOL fixme_once_unused
= FALSE
;
6683 BOOL fixme_once_unknown
= FALSE
;
6687 case D3DDECLTYPE_FLOAT1
:
6688 return weld_float1(to
, from
, epsilon
);
6690 case D3DDECLTYPE_FLOAT2
:
6691 return weld_float2(to
, from
, epsilon
);
6693 case D3DDECLTYPE_FLOAT3
:
6694 return weld_float3(to
, from
, epsilon
);
6696 case D3DDECLTYPE_FLOAT4
:
6697 return weld_float4(to
, from
, epsilon
);
6699 case D3DDECLTYPE_D3DCOLOR
:
6700 return weld_d3dcolor(to
, from
, epsilon
);
6702 case D3DDECLTYPE_UBYTE4
:
6703 return weld_ubyte4(to
, from
, epsilon
);
6705 case D3DDECLTYPE_SHORT2
:
6706 return weld_short2(to
, from
, epsilon
);
6708 case D3DDECLTYPE_SHORT4
:
6709 return weld_short4(to
, from
, epsilon
);
6711 case D3DDECLTYPE_UBYTE4N
:
6712 return weld_ubyte4n(to
, from
, epsilon
);
6714 case D3DDECLTYPE_SHORT2N
:
6715 return weld_short2n(to
, from
, epsilon
);
6717 case D3DDECLTYPE_SHORT4N
:
6718 return weld_short4n(to
, from
, epsilon
);
6720 case D3DDECLTYPE_USHORT2N
:
6721 return weld_ushort2n(to
, from
, epsilon
);
6723 case D3DDECLTYPE_USHORT4N
:
6724 return weld_ushort4n(to
, from
, epsilon
);
6726 case D3DDECLTYPE_UDEC3
:
6727 return weld_udec3(to
, from
, epsilon
);
6729 case D3DDECLTYPE_DEC3N
:
6730 return weld_dec3n(to
, from
, epsilon
);
6732 case D3DDECLTYPE_FLOAT16_2
:
6733 return weld_float16_2(to
, from
, epsilon
);
6735 case D3DDECLTYPE_FLOAT16_4
:
6736 return weld_float16_4(to
, from
, epsilon
);
6738 case D3DDECLTYPE_UNUSED
:
6739 if (!fixme_once_unused
++)
6740 FIXME("D3DDECLTYPE_UNUSED welding not implemented.\n");
6744 if (!fixme_once_unknown
++)
6745 FIXME("Welding of unknown declaration type %d is not implemented.\n", type
);
6752 static FLOAT
get_component_epsilon(const D3DVERTEXELEMENT9
*decl_ptr
, const D3DXWELDEPSILONS
*epsilons
)
6754 FLOAT epsilon
= 0.0f
;
6755 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6756 static BOOL fixme_once_blendindices
= FALSE
;
6757 static BOOL fixme_once_positiont
= FALSE
;
6758 static BOOL fixme_once_fog
= FALSE
;
6759 static BOOL fixme_once_depth
= FALSE
;
6760 static BOOL fixme_once_sample
= FALSE
;
6761 static BOOL fixme_once_unknown
= FALSE
;
6763 switch (decl_ptr
->Usage
)
6765 case D3DDECLUSAGE_POSITION
:
6766 epsilon
= epsilons
->Position
;
6768 case D3DDECLUSAGE_BLENDWEIGHT
:
6769 epsilon
= epsilons
->BlendWeights
;
6771 case D3DDECLUSAGE_NORMAL
:
6772 epsilon
= epsilons
->Normals
;
6774 case D3DDECLUSAGE_PSIZE
:
6775 epsilon
= epsilons
->PSize
;
6777 case D3DDECLUSAGE_TEXCOORD
:
6779 BYTE usage_index
= decl_ptr
->UsageIndex
;
6780 if (usage_index
> 7)
6782 epsilon
= epsilons
->Texcoords
[usage_index
];
6785 case D3DDECLUSAGE_TANGENT
:
6786 epsilon
= epsilons
->Tangent
;
6788 case D3DDECLUSAGE_BINORMAL
:
6789 epsilon
= epsilons
->Binormal
;
6791 case D3DDECLUSAGE_TESSFACTOR
:
6792 epsilon
= epsilons
->TessFactor
;
6794 case D3DDECLUSAGE_COLOR
:
6795 if (decl_ptr
->UsageIndex
== 0)
6796 epsilon
= epsilons
->Diffuse
;
6797 else if (decl_ptr
->UsageIndex
== 1)
6798 epsilon
= epsilons
->Specular
;
6802 case D3DDECLUSAGE_BLENDINDICES
:
6803 if (!fixme_once_blendindices
++)
6804 FIXME("D3DDECLUSAGE_BLENDINDICES welding not implemented.\n");
6806 case D3DDECLUSAGE_POSITIONT
:
6807 if (!fixme_once_positiont
++)
6808 FIXME("D3DDECLUSAGE_POSITIONT welding not implemented.\n");
6810 case D3DDECLUSAGE_FOG
:
6811 if (!fixme_once_fog
++)
6812 FIXME("D3DDECLUSAGE_FOG welding not implemented.\n");
6814 case D3DDECLUSAGE_DEPTH
:
6815 if (!fixme_once_depth
++)
6816 FIXME("D3DDECLUSAGE_DEPTH welding not implemented.\n");
6818 case D3DDECLUSAGE_SAMPLE
:
6819 if (!fixme_once_sample
++)
6820 FIXME("D3DDECLUSAGE_SAMPLE welding not implemented.\n");
6823 if (!fixme_once_unknown
++)
6824 FIXME("Unknown usage %x\n", decl_ptr
->Usage
);
6831 /* Helper function for reading a 32-bit index buffer. */
6832 static inline DWORD
read_ib(void *index_buffer
, BOOL indices_are_32bit
,
6835 if (indices_are_32bit
)
6837 DWORD
*indices
= index_buffer
;
6838 return indices
[index
];
6842 WORD
*indices
= index_buffer
;
6843 return indices
[index
];
6847 /* Helper function for writing to a 32-bit index buffer. */
6848 static inline void write_ib(void *index_buffer
, BOOL indices_are_32bit
,
6849 DWORD index
, DWORD value
)
6851 if (indices_are_32bit
)
6853 DWORD
*indices
= index_buffer
;
6854 indices
[index
] = value
;
6858 WORD
*indices
= index_buffer
;
6859 indices
[index
] = value
;
6863 /*************************************************************************
6864 * D3DXWeldVertices (D3DX9_36.@)
6866 * Welds together similar vertices. The similarity between vert-
6867 * ices can be the position and other components such as
6871 * mesh [I] Mesh which vertices will be welded together.
6872 * flags [I] D3DXWELDEPSILONSFLAGS specifying how to weld.
6873 * epsilons [I] How similar a component needs to be for welding.
6874 * adjacency [I] Which faces are adjacent to other faces.
6875 * adjacency_out [O] Updated adjacency after welding.
6876 * face_remap_out [O] Which faces the old faces have been mapped to.
6877 * vertex_remap_out [O] Which vertices the old vertices have been mapped to.
6881 * Failure: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
6884 * Attribute sorting not implemented.
6887 HRESULT WINAPI
D3DXWeldVertices(ID3DXMesh
*mesh
, DWORD flags
, const D3DXWELDEPSILONS
*epsilons
,
6888 const DWORD
*adjacency
, DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
6890 DWORD
*adjacency_generated
= NULL
;
6891 const DWORD
*adjacency_ptr
;
6892 DWORD
*attributes
= NULL
;
6893 const FLOAT DEFAULT_EPSILON
= 1.0e-6f
;
6896 void *indices
= NULL
;
6897 BOOL indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
6898 DWORD optimize_flags
;
6899 DWORD
*point_reps
= NULL
;
6900 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(mesh
);
6901 DWORD
*vertex_face_map
= NULL
;
6902 ID3DXBuffer
*vertex_remap
= NULL
;
6903 BYTE
*vertices
= NULL
;
6905 TRACE("mesh %p, flags %#x, epsilons %p, adjacency %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
6906 mesh
, flags
, epsilons
, adjacency
, adjacency_out
, face_remap_out
, vertex_remap_out
);
6910 WARN("No flags is undefined. Using D3DXWELDEPSILONS_WELDPARTIALMATCHES instead.\n");
6911 flags
= D3DXWELDEPSILONS_WELDPARTIALMATCHES
;
6914 if (adjacency
) /* Use supplied adjacency. */
6916 adjacency_ptr
= adjacency
;
6918 else /* Adjacency has to be generated. */
6920 adjacency_generated
= HeapAlloc(GetProcessHeap(), 0, 3 * This
->numfaces
* sizeof(*adjacency_generated
));
6921 if (!adjacency_generated
)
6923 ERR("Couldn't allocate memory for adjacency_generated.\n");
6927 hr
= mesh
->lpVtbl
->GenerateAdjacency(mesh
, DEFAULT_EPSILON
, adjacency_generated
);
6930 ERR("Couldn't generate adjacency.\n");
6933 adjacency_ptr
= adjacency_generated
;
6936 /* Point representation says which vertices can be replaced. */
6937 point_reps
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*point_reps
));
6941 ERR("Couldn't allocate memory for point_reps.\n");
6944 hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency_ptr
, point_reps
);
6947 ERR("ConvertAdjacencyToPointReps failed.\n");
6951 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
);
6954 ERR("Couldn't lock index buffer.\n");
6958 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, 0, &attributes
);
6961 ERR("Couldn't lock attribute buffer.\n");
6964 vertex_face_map
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*vertex_face_map
));
6965 if (!vertex_face_map
)
6968 ERR("Couldn't allocate memory for vertex_face_map.\n");
6971 /* Build vertex face map, so that a vertex's face can be looked up. */
6972 for (i
= 0; i
< This
->numfaces
; i
++)
6975 for (j
= 0; j
< 3; j
++)
6977 DWORD index
= read_ib(indices
, indices_are_32bit
, 3*i
+ j
);
6978 vertex_face_map
[index
] = i
;
6982 if (flags
& D3DXWELDEPSILONS_WELDPARTIALMATCHES
)
6984 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void**)&vertices
);
6987 ERR("Couldn't lock vertex buffer.\n");
6990 /* For each vertex that can be removed, compare its vertex components
6991 * with the vertex components from the vertex that can replace it. A
6992 * vertex is only fully replaced if all the components match and the
6993 * flag D3DXWELDEPSILONS_DONOTREMOVEVERTICES is not set, and they
6994 * belong to the same attribute group. Otherwise the vertex components
6995 * that are within epsilon are set to the same value.
6997 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
6999 D3DVERTEXELEMENT9
*decl_ptr
;
7000 DWORD vertex_size
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
7001 DWORD num_vertex_components
;
7004 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7006 for (decl_ptr
= This
->cached_declaration
, num_vertex_components
= 0; decl_ptr
->Stream
!= 0xFF; decl_ptr
++, num_vertex_components
++)
7008 BYTE
*to
= &vertices
[vertex_size
*index
+ decl_ptr
->Offset
];
7009 BYTE
*from
= &vertices
[vertex_size
*point_reps
[index
] + decl_ptr
->Offset
];
7010 FLOAT epsilon
= get_component_epsilon(decl_ptr
, epsilons
);
7012 /* Don't weld self */
7013 if (index
== point_reps
[index
])
7019 if (weld_component(to
, from
, decl_ptr
->Type
, epsilon
))
7023 all_match
= (num_vertex_components
== matches
);
7024 if (all_match
&& !(flags
& D3DXWELDEPSILONS_DONOTREMOVEVERTICES
))
7026 DWORD to_face
= vertex_face_map
[index
];
7027 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7028 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7030 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7033 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7036 else if (flags
& D3DXWELDEPSILONS_WELDALL
)
7038 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
7040 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7041 DWORD to_face
= vertex_face_map
[index
];
7042 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7043 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7045 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7048 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7050 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7053 /* Compact mesh using OptimizeInplace */
7054 optimize_flags
= D3DXMESHOPT_COMPACT
;
7055 hr
= mesh
->lpVtbl
->OptimizeInplace(mesh
, optimize_flags
, adjacency_ptr
, adjacency_out
, face_remap_out
, vertex_remap_out
);
7058 ERR("Couldn't compact mesh.\n");
7064 HeapFree(GetProcessHeap(), 0, adjacency_generated
);
7065 HeapFree(GetProcessHeap(), 0, point_reps
);
7066 HeapFree(GetProcessHeap(), 0, vertex_face_map
);
7067 if (attributes
) mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7068 if (indices
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7069 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
7070 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7075 /*************************************************************************
7076 * D3DXOptimizeFaces (D3DX9_36.@)
7078 * Re-orders the faces so the vertex cache is used optimally.
7081 * indices [I] Pointer to an index buffer belonging to a mesh.
7082 * num_faces [I] Number of faces in the mesh.
7083 * num_vertices [I] Number of vertices in the mesh.
7084 * indices_are_32bit [I] Specifies whether indices are 32- or 16-bit.
7085 * face_remap [I/O] The new order the faces should be drawn in.
7089 * Failure: D3DERR_INVALIDCALL.
7092 * The face re-ordering does not use the vertex cache optimally.
7095 HRESULT WINAPI
D3DXOptimizeFaces(const void *indices
, UINT num_faces
,
7096 UINT num_vertices
, BOOL indices_are_32bit
, DWORD
*face_remap
)
7099 UINT j
= num_faces
- 1;
7100 UINT limit_16_bit
= 2 << 15; /* According to MSDN */
7101 HRESULT hr
= D3D_OK
;
7103 FIXME("indices %p, num_faces %u, num_vertices %u, indices_are_32bit %#x, face_remap %p semi-stub. "
7104 "Face order will not be optimal.\n",
7105 indices
, num_faces
, num_vertices
, indices_are_32bit
, face_remap
);
7107 if (!indices_are_32bit
&& num_faces
>= limit_16_bit
)
7109 WARN("Number of faces must be less than %d when using 16-bit indices.\n",
7111 hr
= D3DERR_INVALIDCALL
;
7117 WARN("Face remap pointer is NULL.\n");
7118 hr
= D3DERR_INVALIDCALL
;
7122 /* The faces are drawn in reverse order for simple meshes. This ordering
7123 * is not optimal for complicated meshes, but will not break anything
7124 * either. The ordering should be changed to take advantage of the vertex
7125 * cache on the graphics card.
7127 * TODO Re-order to take advantage of vertex cache.
7129 for (i
= 0; i
< num_faces
; i
++)
7131 face_remap
[i
] = j
--;