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
);
2756 static void destroy_materials(struct mesh_data
*mesh
)
2759 for (i
= 0; i
< mesh
->num_materials
; i
++)
2760 HeapFree(GetProcessHeap(), 0, mesh
->materials
[i
].pTextureFilename
);
2761 HeapFree(GetProcessHeap(), 0, mesh
->materials
);
2762 HeapFree(GetProcessHeap(), 0, mesh
->material_indices
);
2763 mesh
->num_materials
= 0;
2764 mesh
->materials
= NULL
;
2765 mesh
->material_indices
= NULL
;
2768 static HRESULT
parse_material_list(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2772 const DWORD
*data
, *in_ptr
;
2774 ID3DXFileData
*child
;
2775 DWORD num_materials
;
2779 destroy_materials(mesh
);
2781 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2782 if (FAILED(hr
)) return hr
;
2784 /* template MeshMaterialList {
2786 * DWORD nFaceIndexes;
2787 * array DWORD faceIndexes[nFaceIndexes];
2795 if (data_size
< sizeof(DWORD
)) {
2796 WARN("truncated data (%ld bytes)\n", data_size
);
2799 num_materials
= *in_ptr
++;
2800 if (!num_materials
) {
2805 if (data_size
< 2 * sizeof(DWORD
)) {
2806 WARN("truncated data (%ld bytes)\n", data_size
);
2809 if (*in_ptr
++ != mesh
->num_poly_faces
) {
2810 WARN("number of material face indices (%u) doesn't match number of faces (%u)\n",
2811 *(in_ptr
- 1), mesh
->num_poly_faces
);
2814 if (data_size
< 2 * sizeof(DWORD
) + mesh
->num_poly_faces
* sizeof(DWORD
)) {
2815 WARN("truncated data (%ld bytes)\n", data_size
);
2818 for (i
= 0; i
< mesh
->num_poly_faces
; i
++) {
2819 if (*in_ptr
++ >= num_materials
) {
2820 WARN("face %u: reference to undefined material %u (only %u materials)\n",
2821 i
, *(in_ptr
- 1), num_materials
);
2826 mesh
->materials
= HeapAlloc(GetProcessHeap(), 0, num_materials
* sizeof(*mesh
->materials
));
2827 mesh
->material_indices
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_poly_faces
* sizeof(*mesh
->material_indices
));
2828 if (!mesh
->materials
|| !mesh
->material_indices
) {
2832 memcpy(mesh
->material_indices
, data
+ 2, mesh
->num_poly_faces
* sizeof(DWORD
));
2834 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2838 for (i
= 0; i
< nb_children
; i
++)
2840 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2843 hr
= child
->lpVtbl
->GetType(child
, &type
);
2847 if (IsEqualGUID(&type
, &TID_D3DRMMaterial
)) {
2848 if (mesh
->num_materials
>= num_materials
) {
2849 WARN("more materials defined than declared\n");
2853 hr
= parse_material(child
, &mesh
->materials
[mesh
->num_materials
++]);
2858 if (num_materials
!= mesh
->num_materials
) {
2859 WARN("only %u of %u materials defined\n", num_materials
, mesh
->num_materials
);
2864 filedata
->lpVtbl
->Unlock(filedata
);
2868 static HRESULT
parse_texture_coords(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2874 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2875 mesh
->tex_coords
= NULL
;
2877 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2878 if (FAILED(hr
)) return hr
;
2880 /* template Coords2d {
2884 * template MeshTextureCoords {
2885 * DWORD nTextureCoords;
2886 * array Coords2d textureCoords[nTextureCoords];
2892 if (data_size
< sizeof(DWORD
)) {
2893 WARN("truncated data (%ld bytes)\n", data_size
);
2896 if (*(DWORD
*)data
!= mesh
->num_vertices
) {
2897 WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2898 *(DWORD
*)data
, mesh
->num_vertices
);
2901 data
+= sizeof(DWORD
);
2902 if (data_size
< sizeof(DWORD
) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
)) {
2903 WARN("truncated data (%ld bytes)\n", data_size
);
2907 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2908 if (!mesh
->tex_coords
) {
2912 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2914 mesh
->fvf
|= D3DFVF_TEX1
;
2919 filedata
->lpVtbl
->Unlock(filedata
);
2923 static HRESULT
parse_vertex_colors(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2931 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2932 mesh
->vertex_colors
= NULL
;
2934 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2935 if (FAILED(hr
)) return hr
;
2937 /* template IndexedColor {
2939 * ColorRGBA indexColor;
2941 * template MeshVertexColors {
2942 * DWORD nVertexColors;
2943 * array IndexedColor vertexColors[nVertexColors];
2949 if (data_size
< sizeof(DWORD
)) {
2950 WARN("truncated data (%ld bytes)\n", data_size
);
2953 num_colors
= *(DWORD
*)data
;
2954 data
+= sizeof(DWORD
);
2955 if (data_size
< sizeof(DWORD
) + num_colors
* (sizeof(DWORD
) + sizeof(D3DCOLORVALUE
))) {
2956 WARN("truncated data (%ld bytes)\n", data_size
);
2960 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(DWORD
));
2961 if (!mesh
->vertex_colors
) {
2966 for (i
= 0; i
< mesh
->num_vertices
; i
++)
2967 mesh
->vertex_colors
[i
] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2968 for (i
= 0; i
< num_colors
; i
++)
2970 D3DCOLORVALUE color
;
2971 DWORD index
= *(DWORD
*)data
;
2972 data
+= sizeof(DWORD
);
2973 if (index
>= mesh
->num_vertices
) {
2974 WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2975 i
, index
, mesh
->num_vertices
);
2978 memcpy(&color
, data
, sizeof(color
));
2979 data
+= sizeof(color
);
2980 color
.r
= min(1.0f
, max(0.0f
, color
.r
));
2981 color
.g
= min(1.0f
, max(0.0f
, color
.g
));
2982 color
.b
= min(1.0f
, max(0.0f
, color
.b
));
2983 color
.a
= min(1.0f
, max(0.0f
, color
.a
));
2984 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
2985 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
2986 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
2987 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
2990 mesh
->fvf
|= D3DFVF_DIFFUSE
;
2995 filedata
->lpVtbl
->Unlock(filedata
);
2999 static HRESULT
parse_normals(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
3004 DWORD
*index_out_ptr
;
3006 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
3008 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
3009 mesh
->num_normals
= 0;
3010 mesh
->normals
= NULL
;
3011 mesh
->normal_indices
= NULL
;
3012 mesh
->fvf
|= D3DFVF_NORMAL
;
3014 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3015 if (FAILED(hr
)) return hr
;
3017 /* template Vector {
3022 * template MeshFace {
3023 * DWORD nFaceVertexIndices;
3024 * array DWORD faceVertexIndices[nFaceVertexIndices];
3026 * template MeshNormals {
3028 * array Vector normals[nNormals];
3029 * DWORD nFaceNormals;
3030 * array MeshFace faceNormals[nFaceNormals];
3036 if (data_size
< sizeof(DWORD
) * 2) {
3037 WARN("truncated data (%ld bytes)\n", data_size
);
3040 mesh
->num_normals
= *(DWORD
*)data
;
3041 data
+= sizeof(DWORD
);
3042 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
3043 num_face_indices
* sizeof(DWORD
)) {
3044 WARN("truncated data (%ld bytes)\n", data_size
);
3048 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3049 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
3050 if (!mesh
->normals
|| !mesh
->normal_indices
) {
3055 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3056 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
3057 for (i
= 0; i
< mesh
->num_normals
; i
++)
3058 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
3060 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
3061 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
3062 *(DWORD
*)data
, mesh
->num_poly_faces
);
3065 data
+= sizeof(DWORD
);
3066 index_out_ptr
= mesh
->normal_indices
;
3067 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
3070 DWORD count
= *(DWORD
*)data
;
3071 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
3072 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
3073 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
3076 data
+= sizeof(DWORD
);
3078 for (j
= 0; j
< count
; j
++) {
3079 DWORD normal_index
= *(DWORD
*)data
;
3080 if (normal_index
>= mesh
->num_normals
) {
3081 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
3082 i
, j
, normal_index
, mesh
->num_normals
);
3085 *index_out_ptr
++ = normal_index
;
3086 data
+= sizeof(DWORD
);
3093 filedata
->lpVtbl
->Unlock(filedata
);
3097 static HRESULT
parse_skin_mesh_info(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD index
)
3103 TRACE("(%p, %p, %u)\n", filedata
, mesh_data
, index
);
3105 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3106 if (FAILED(hr
)) return hr
;
3110 if (!mesh_data
->skin_info
) {
3111 if (data_size
< sizeof(WORD
) * 3) {
3112 WARN("truncated data (%ld bytes)\n", data_size
);
3115 /* Skip nMaxSkinWeightsPerVertex and nMaxSkinWeightsPerFace */
3116 data
+= 2 * sizeof(WORD
);
3117 mesh_data
->nb_bones
= *(WORD
*)data
;
3118 hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
, mesh_data
->nb_bones
, &mesh_data
->skin_info
);
3121 DWORD nb_influences
;
3123 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
3124 name
= *(const char**)data
;
3125 data
+= sizeof(char*);
3127 nb_influences
= *(DWORD
*)data
;
3128 data
+= sizeof(DWORD
);
3130 if (data_size
< (sizeof(char*) + sizeof(DWORD
) + nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
)) + 16 * sizeof(FLOAT
))) {
3131 WARN("truncated data (%ld bytes)\n", data_size
);
3135 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneName(mesh_data
->skin_info
, index
, name
);
3137 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneInfluence(mesh_data
->skin_info
, index
, nb_influences
,
3138 (const DWORD
*)data
, (const FLOAT
*)(data
+ nb_influences
* sizeof(DWORD
)));
3140 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneOffsetMatrix(mesh_data
->skin_info
, index
,
3141 (const D3DMATRIX
*)(data
+ nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
))));
3145 filedata
->lpVtbl
->Unlock(filedata
);
3149 /* for provide_flags parameters */
3150 #define PROVIDE_MATERIALS 0x1
3151 #define PROVIDE_SKININFO 0x2
3152 #define PROVIDE_ADJACENCY 0x4
3154 static HRESULT
parse_mesh(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
3158 const BYTE
*data
, *in_ptr
;
3159 DWORD
*index_out_ptr
;
3161 ID3DXFileData
*child
;
3164 DWORD nb_skin_weigths_info
= 0;
3169 * array Vector vertices[nVertices];
3171 * array MeshFace faces[nFaces];
3176 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3177 if (FAILED(hr
)) return hr
;
3182 if (data_size
< sizeof(DWORD
) * 2) {
3183 WARN("truncated data (%ld bytes)\n", data_size
);
3186 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
3187 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
)) {
3188 WARN("truncated data (%ld bytes)\n", data_size
);
3191 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
3193 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
3194 in_ptr
+= sizeof(DWORD
);
3196 mesh_data
->num_tri_faces
= 0;
3197 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3199 DWORD num_poly_vertices
;
3202 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
)) {
3203 WARN("truncated data (%ld bytes)\n", data_size
);
3206 num_poly_vertices
= *(DWORD
*)in_ptr
;
3207 in_ptr
+= sizeof(DWORD
);
3208 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
)) {
3209 WARN("truncated data (%ld bytes)\n", data_size
);
3212 if (num_poly_vertices
< 3) {
3213 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
3216 for (j
= 0; j
< num_poly_vertices
; j
++) {
3217 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
3218 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
3219 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
3222 in_ptr
+= sizeof(DWORD
);
3224 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
3227 mesh_data
->fvf
= D3DFVF_XYZ
;
3229 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
3230 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
3231 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
3232 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
3233 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
3234 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
3235 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
) {
3240 in_ptr
= data
+ sizeof(DWORD
);
3241 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
3242 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
3244 index_out_ptr
= mesh_data
->indices
;
3245 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3249 count
= *(DWORD
*)in_ptr
;
3250 in_ptr
+= sizeof(DWORD
);
3251 mesh_data
->num_tri_per_face
[i
] = count
- 2;
3254 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
3255 in_ptr
+= sizeof(DWORD
);
3259 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3263 for (i
= 0; i
< nb_children
; i
++)
3265 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3268 hr
= child
->lpVtbl
->GetType(child
, &type
);
3272 if (IsEqualGUID(&type
, &TID_D3DRMMeshNormals
)) {
3273 hr
= parse_normals(child
, mesh_data
);
3274 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshVertexColors
)) {
3275 hr
= parse_vertex_colors(child
, mesh_data
);
3276 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshTextureCoords
)) {
3277 hr
= parse_texture_coords(child
, mesh_data
);
3278 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3281 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshMaterialList
) &&
3282 (provide_flags
& PROVIDE_MATERIALS
))
3284 hr
= parse_material_list(child
, mesh_data
);
3285 } else if (provide_flags
& PROVIDE_SKININFO
) {
3286 if (IsEqualGUID(&type
, &DXFILEOBJ_XSkinMeshHeader
)) {
3287 if (mesh_data
->skin_info
) {
3288 WARN("Skin mesh header already encountered\n");
3292 hr
= parse_skin_mesh_info(child
, mesh_data
, 0);
3295 } else if (IsEqualGUID(&type
, &DXFILEOBJ_SkinWeights
)) {
3296 if (!mesh_data
->skin_info
) {
3297 WARN("Skin weigths found but skin mesh header not encountered yet\n");
3301 hr
= parse_skin_mesh_info(child
, mesh_data
, nb_skin_weigths_info
);
3304 nb_skin_weigths_info
++;
3311 if (mesh_data
->skin_info
&& (nb_skin_weigths_info
!= mesh_data
->nb_bones
)) {
3312 WARN("Mismatch between nb skin weights info %u encountered and nb bones %u from skin mesh header\n",
3313 nb_skin_weigths_info
, mesh_data
->nb_bones
);
3321 filedata
->lpVtbl
->Unlock(filedata
);
3325 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
3326 ID3DXBuffer
**effects
)
3329 D3DXEFFECTINSTANCE
*effect_ptr
;
3331 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3332 static const struct {
3333 const char *param_name
;
3337 } material_effects
[] = {
3338 #define EFFECT_TABLE_ENTRY(str, field) \
3339 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
3340 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
3341 EFFECT_TABLE_ENTRY("Power", Power
),
3342 EFFECT_TABLE_ENTRY("Specular", Specular
),
3343 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
3344 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
3345 #undef EFFECT_TABLE_ENTRY
3347 static const char texture_paramname
[] = "Texture0@Name";
3351 /* effects buffer layout:
3353 * D3DXEFFECTINSTANCE effects[num_materials];
3354 * for (effect in effects)
3356 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
3357 * for (default in defaults)
3359 * *default.pParamName;
3364 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
3365 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
3366 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
3367 buffer_size
+= material_effects
[i
].name_size
;
3368 buffer_size
+= material_effects
[i
].num_bytes
;
3370 buffer_size
*= num_materials
;
3371 for (i
= 0; i
< num_materials
; i
++) {
3372 if (material_ptr
[i
].pTextureFilename
) {
3373 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
3374 buffer_size
+= sizeof(texture_paramname
);
3375 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
3379 hr
= D3DXCreateBuffer(buffer_size
, effects
);
3380 if (FAILED(hr
)) return hr
;
3381 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
3382 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
3384 for (i
= 0; i
< num_materials
; i
++)
3387 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
3389 effect_ptr
->pDefaults
= defaults
;
3390 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
3391 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
3393 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
3395 defaults
->pParamName
= (char *)out_ptr
;
3396 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
3397 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
3398 defaults
->Type
= D3DXEDT_FLOATS
;
3399 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
3400 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
3401 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3405 if (material_ptr
->pTextureFilename
)
3407 defaults
->pParamName
= (char *)out_ptr
;
3408 strcpy(defaults
->pParamName
, texture_paramname
);
3409 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
3410 defaults
->Type
= D3DXEDT_STRING
;
3411 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
3412 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
3413 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3418 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
3423 HRESULT WINAPI
D3DXLoadSkinMeshFromXof(struct ID3DXFileData
*filedata
, DWORD options
,
3424 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
3425 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXSkinInfo
**skin_info_out
,
3426 struct ID3DXMesh
**mesh_out
)
3429 DWORD
*index_in_ptr
;
3430 struct mesh_data mesh_data
;
3431 DWORD total_vertices
;
3432 ID3DXMesh
*d3dxmesh
= NULL
;
3433 ID3DXBuffer
*adjacency
= NULL
;
3434 ID3DXBuffer
*materials
= NULL
;
3435 ID3DXBuffer
*effects
= NULL
;
3436 struct vertex_duplication
{
3439 } *duplications
= NULL
;
3441 void *vertices
= NULL
;
3442 void *indices
= NULL
;
3444 DWORD provide_flags
= 0;
3446 TRACE("(%p, %x, %p, %p, %p, %p, %p, %p, %p)\n", filedata
, options
, device
, adjacency_out
, materials_out
,
3447 effects_out
, num_materials_out
, skin_info_out
, mesh_out
);
3449 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
3451 if (num_materials_out
|| materials_out
|| effects_out
)
3452 provide_flags
|= PROVIDE_MATERIALS
;
3454 provide_flags
|= PROVIDE_SKININFO
;
3456 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
3457 if (FAILED(hr
)) goto cleanup
;
3459 total_vertices
= mesh_data
.num_vertices
;
3460 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3461 /* duplicate vertices with multiple normals */
3462 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
3463 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
3464 if (!duplications
) {
3468 for (i
= 0; i
< total_vertices
; i
++)
3470 duplications
[i
].normal_index
= -1;
3471 list_init(&duplications
[i
].entry
);
3473 for (i
= 0; i
< num_face_indices
; i
++) {
3474 DWORD vertex_index
= mesh_data
.indices
[i
];
3475 DWORD normal_index
= mesh_data
.normal_indices
[i
];
3476 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
3478 if (dup_ptr
->normal_index
== -1) {
3479 dup_ptr
->normal_index
= normal_index
;
3481 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
3482 struct list
*dup_list
= &dup_ptr
->entry
;
3484 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
3485 if (new_normal
->x
== cur_normal
->x
&&
3486 new_normal
->y
== cur_normal
->y
&&
3487 new_normal
->z
== cur_normal
->z
)
3489 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3491 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
3492 dup_ptr
= &duplications
[total_vertices
++];
3493 dup_ptr
->normal_index
= normal_index
;
3494 list_add_tail(dup_list
, &dup_ptr
->entry
);
3495 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3498 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
3499 struct vertex_duplication
, entry
);
3506 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
3507 if (FAILED(hr
)) goto cleanup
;
3509 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, 0, &vertices
);
3510 if (FAILED(hr
)) goto cleanup
;
3513 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3514 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
3515 out_ptr
+= sizeof(D3DXVECTOR3
);
3516 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3517 if (duplications
[i
].normal_index
== -1)
3518 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
3520 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
3521 out_ptr
+= sizeof(D3DXVECTOR3
);
3523 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
3524 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
3525 out_ptr
+= sizeof(DWORD
);
3527 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
3528 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
3529 out_ptr
+= sizeof(D3DXVECTOR2
);
3532 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3533 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
3535 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3536 struct vertex_duplication
*dup_ptr
;
3537 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
3539 int j
= dup_ptr
- duplications
;
3540 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
3542 memcpy(dest_vertex
, out_ptr
, vertex_size
);
3543 dest_vertex
+= sizeof(D3DXVECTOR3
);
3544 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
3546 out_ptr
+= vertex_size
;
3549 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
3551 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, 0, &indices
);
3552 if (FAILED(hr
)) goto cleanup
;
3554 index_in_ptr
= mesh_data
.indices
;
3555 #define FILL_INDEX_BUFFER(indices_var) \
3556 for (i = 0; i < mesh_data.num_poly_faces; i++) \
3558 DWORD count = mesh_data.num_tri_per_face[i]; \
3559 WORD first_index = *index_in_ptr++; \
3561 *indices_var++ = first_index; \
3562 *indices_var++ = *index_in_ptr; \
3564 *indices_var++ = *index_in_ptr; \
3568 if (options
& D3DXMESH_32BIT
) {
3569 DWORD
*dword_indices
= indices
;
3570 FILL_INDEX_BUFFER(dword_indices
)
3572 WORD
*word_indices
= indices
;
3573 FILL_INDEX_BUFFER(word_indices
)
3575 #undef FILL_INDEX_BUFFER
3576 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
3578 if (mesh_data
.material_indices
) {
3579 DWORD
*attrib_buffer
= NULL
;
3580 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, 0, &attrib_buffer
);
3581 if (FAILED(hr
)) goto cleanup
;
3582 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
3584 DWORD count
= mesh_data
.num_tri_per_face
[i
];
3586 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
3588 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
3590 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
3591 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
3592 NULL
, NULL
, NULL
, NULL
);
3593 if (FAILED(hr
)) goto cleanup
;
3596 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
3597 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
3598 char *strings_out_ptr
;
3599 D3DXMATERIAL
*materials_ptr
;
3601 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3602 if (mesh_data
.materials
[i
].pTextureFilename
)
3603 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3606 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3607 if (FAILED(hr
)) goto cleanup
;
3609 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3610 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
3611 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
3612 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3613 if (materials_ptr
[i
].pTextureFilename
) {
3614 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
3615 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
3616 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3621 if (mesh_data
.num_materials
&& effects_out
) {
3622 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
3623 if (FAILED(hr
)) goto cleanup
;
3625 if (!materials_out
) {
3626 ID3DXBuffer_Release(materials
);
3631 if (adjacency_out
) {
3632 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
3633 if (FAILED(hr
)) goto cleanup
;
3634 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
3635 if (FAILED(hr
)) goto cleanup
;
3638 *mesh_out
= d3dxmesh
;
3639 if (adjacency_out
) *adjacency_out
= adjacency
;
3640 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
3641 if (materials_out
) *materials_out
= materials
;
3642 if (effects_out
) *effects_out
= effects
;
3643 if (skin_info_out
) *skin_info_out
= mesh_data
.skin_info
;
3648 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
3649 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3650 if (materials
) ID3DXBuffer_Release(materials
);
3651 if (effects
) ID3DXBuffer_Release(effects
);
3652 if (mesh_data
.skin_info
) mesh_data
.skin_info
->lpVtbl
->Release(mesh_data
.skin_info
);
3653 if (skin_info_out
) *skin_info_out
= NULL
;
3655 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
3656 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
3657 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
3658 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
3659 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
3660 destroy_materials(&mesh_data
);
3661 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
3662 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
3663 HeapFree(GetProcessHeap(), 0, duplications
);
3667 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3668 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3669 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3675 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3676 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3677 debugstr_a(filename
), options
, device
, alloc_hier
,
3678 load_user_data
, frame_hierarchy
, anim_controller
);
3681 return D3DERR_INVALIDCALL
;
3683 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3684 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3685 if (!filenameW
) return E_OUTOFMEMORY
;
3686 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3688 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
3689 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3690 HeapFree(GetProcessHeap(), 0, filenameW
);
3695 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3696 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3697 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3703 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3704 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3705 debugstr_w(filename
), options
, device
, alloc_hier
,
3706 load_user_data
, frame_hierarchy
, anim_controller
);
3709 return D3DERR_INVALIDCALL
;
3711 hr
= map_view_of_file(filename
, &buffer
, &size
);
3713 return D3DXERR_INVALIDDATA
;
3715 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
3716 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3718 UnmapViewOfFile(buffer
);
3723 static HRESULT
filedata_get_name(ID3DXFileData
*filedata
, char **name
)
3728 hr
= filedata
->lpVtbl
->GetName(filedata
, NULL
, &name_len
);
3729 if (FAILED(hr
)) return hr
;
3733 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
3734 if (!*name
) return E_OUTOFMEMORY
;
3736 hr
= filedata
->lpVtbl
->GetName(filedata
, *name
, &name_len
);
3738 HeapFree(GetProcessHeap(), 0, *name
);
3745 static HRESULT
load_mesh_container(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3746 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXMESHCONTAINER
**mesh_container
)
3749 ID3DXBuffer
*adjacency
= NULL
;
3750 ID3DXBuffer
*materials
= NULL
;
3751 ID3DXBuffer
*effects
= NULL
;
3752 ID3DXSkinInfo
*skin_info
= NULL
;
3753 D3DXMESHDATA mesh_data
;
3754 DWORD num_materials
= 0;
3757 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
3758 mesh_data
.u
.pMesh
= NULL
;
3760 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
3761 &adjacency
, &materials
, &effects
, &num_materials
,
3762 &skin_info
, &mesh_data
.u
.pMesh
);
3763 if (FAILED(hr
)) return hr
;
3765 hr
= filedata_get_name(filedata
, &name
);
3766 if (FAILED(hr
)) goto cleanup
;
3768 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
3769 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
3770 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
3772 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
3773 skin_info
, mesh_container
);
3776 if (materials
) ID3DXBuffer_Release(materials
);
3777 if (effects
) ID3DXBuffer_Release(effects
);
3778 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3779 if (skin_info
) IUnknown_Release(skin_info
);
3780 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
3781 HeapFree(GetProcessHeap(), 0, name
);
3785 static HRESULT
parse_transform_matrix(ID3DXFileData
*filedata
, D3DXMATRIX
*transform
)
3791 /* template Matrix4x4 {
3792 * array FLOAT matrix[16];
3794 * template FrameTransformMatrix {
3795 * Matrix4x4 frameMatrix;
3799 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3800 if (FAILED(hr
)) return hr
;
3802 if (data_size
!= sizeof(D3DXMATRIX
)) {
3803 WARN("incorrect data size (%ld bytes)\n", data_size
);
3804 filedata
->lpVtbl
->Unlock(filedata
);
3808 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
3810 filedata
->lpVtbl
->Unlock(filedata
);
3814 static HRESULT
load_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3815 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXFRAME
**frame_out
)
3819 ID3DXFileData
*child
;
3821 D3DXFRAME
*frame
= NULL
;
3822 D3DXMESHCONTAINER
**next_container
;
3823 D3DXFRAME
**next_child
;
3824 SIZE_T i
, nb_children
;
3826 hr
= filedata_get_name(filedata
, &name
);
3827 if (FAILED(hr
)) return hr
;
3829 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
3830 HeapFree(GetProcessHeap(), 0, name
);
3831 if (FAILED(hr
)) return E_FAIL
;
3834 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
3835 next_child
= &frame
->pFrameFirstChild
;
3836 next_container
= &frame
->pMeshContainer
;
3838 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3842 for (i
= 0; i
< nb_children
; i
++)
3844 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3847 hr
= child
->lpVtbl
->GetType(child
, &type
);
3851 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
3852 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
3854 next_container
= &(*next_container
)->pNextMeshContainer
;
3855 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
3856 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
3857 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
3858 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
3860 next_child
= &(*next_child
)->pFrameSibling
;
3869 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
3870 struct IDirect3DDevice9
*device
, struct ID3DXAllocateHierarchy
*alloc_hier
,
3871 struct ID3DXLoadUserData
*load_user_data
, D3DXFRAME
**frame_hierarchy
,
3872 struct ID3DXAnimationController
**anim_controller
)
3875 ID3DXFile
*d3dxfile
= NULL
;
3876 ID3DXFileEnumObject
*enumobj
= NULL
;
3877 ID3DXFileData
*filedata
= NULL
;
3878 D3DXF_FILELOADMEMORY source
;
3879 D3DXFRAME
*first_frame
= NULL
;
3880 D3DXFRAME
**next_frame
= &first_frame
;
3881 SIZE_T i
, nb_children
;
3884 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3885 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3887 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
3888 return D3DERR_INVALIDCALL
;
3889 if (load_user_data
|| anim_controller
) {
3891 FIXME("Loading user data not implemented\n");
3892 if (anim_controller
)
3893 FIXME("Animation controller creation not implemented\n");
3897 hr
= D3DXFileCreate(&d3dxfile
);
3898 if (FAILED(hr
)) goto cleanup
;
3900 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3901 if (FAILED(hr
)) goto cleanup
;
3903 source
.lpMemory
= (void*)memory
;
3904 source
.dSize
= memory_size
;
3905 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
3906 if (FAILED(hr
)) goto cleanup
;
3908 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
3912 for (i
= 0; i
< nb_children
; i
++)
3914 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
3918 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
3919 if (SUCCEEDED(hr
)) {
3920 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
3921 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
3927 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
3929 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
3930 if (FAILED(hr
)) goto cleanup
;
3931 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
3932 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
3933 if (FAILED(hr
)) goto cleanup
;
3936 next_frame
= &(*next_frame
)->pFrameSibling
;
3939 filedata
->lpVtbl
->Release(filedata
);
3947 } else if (first_frame
->pFrameSibling
) {
3948 D3DXFRAME
*root_frame
= NULL
;
3949 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
3954 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
3955 root_frame
->pFrameFirstChild
= first_frame
;
3956 *frame_hierarchy
= root_frame
;
3959 *frame_hierarchy
= first_frame
;
3964 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
3965 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
3966 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
3967 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
3971 HRESULT WINAPI
D3DXCleanMesh(D3DXCLEANTYPE clean_type
, ID3DXMesh
*mesh_in
, const DWORD
*adjacency_in
,
3972 ID3DXMesh
**mesh_out
, DWORD
*adjacency_out
, ID3DXBuffer
**errors_and_warnings
)
3974 FIXME("(%u, %p, %p, %p, %p, %p)\n", clean_type
, mesh_in
, adjacency_in
, mesh_out
, adjacency_out
, errors_and_warnings
);
3979 HRESULT WINAPI
D3DXFrameDestroy(D3DXFRAME
*frame
, ID3DXAllocateHierarchy
*alloc_hier
)
3984 TRACE("(%p, %p)\n", frame
, alloc_hier
);
3986 if (!frame
|| !alloc_hier
)
3987 return D3DERR_INVALIDCALL
;
3990 D3DXMESHCONTAINER
*container
;
3991 D3DXFRAME
*current_frame
;
3993 if (frame
->pFrameSibling
) {
3994 current_frame
= frame
->pFrameSibling
;
3995 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
3996 current_frame
->pFrameSibling
= NULL
;
3998 current_frame
= frame
;
4002 if (current_frame
->pFrameFirstChild
) {
4003 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
4004 if (FAILED(hr
)) return hr
;
4005 current_frame
->pFrameFirstChild
= NULL
;
4008 container
= current_frame
->pMeshContainer
;
4010 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
4011 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
4012 if (FAILED(hr
)) return hr
;
4013 container
= next_container
;
4015 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
4016 if (FAILED(hr
)) return hr
;
4021 HRESULT WINAPI
D3DXLoadMeshFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4022 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4023 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4029 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4030 "effect_instances %p, num_materials %p, mesh %p.\n",
4031 debugstr_a(filename
), options
, device
, adjacency
, materials
,
4032 effect_instances
, num_materials
, mesh
);
4035 return D3DERR_INVALIDCALL
;
4037 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
4038 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4039 if (!filenameW
) return E_OUTOFMEMORY
;
4040 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
4042 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
4043 effect_instances
, num_materials
, mesh
);
4044 HeapFree(GetProcessHeap(), 0, filenameW
);
4049 HRESULT WINAPI
D3DXLoadMeshFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4050 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4051 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4057 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4058 "effect_instances %p, num_materials %p, mesh %p.\n",
4059 debugstr_w(filename
), options
, device
, adjacency
, materials
,
4060 effect_instances
, num_materials
, mesh
);
4063 return D3DERR_INVALIDCALL
;
4065 hr
= map_view_of_file(filename
, &buffer
, &size
);
4067 return D3DXERR_INVALIDDATA
;
4069 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4070 materials
, effect_instances
, num_materials
, mesh
);
4072 UnmapViewOfFile(buffer
);
4077 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
, const char *name
, const char *type
, DWORD options
,
4078 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
,
4079 struct ID3DXBuffer
**effect_instances
, DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4086 TRACE("module %p, name %s, type %s, options %#x, device %p, adjacency %p, "
4087 "materials %p, effect_instances %p, num_materials %p, mesh %p.\n",
4088 module
, debugstr_a(name
), debugstr_a(type
), options
, device
, adjacency
,
4089 materials
, effect_instances
, num_materials
, mesh
);
4091 resinfo
= FindResourceA(module
, name
, type
);
4092 if (!resinfo
) return D3DXERR_INVALIDDATA
;
4094 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
4095 if (FAILED(hr
)) return D3DXERR_INVALIDDATA
;
4097 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4098 materials
, effect_instances
, num_materials
, mesh
);
4101 struct mesh_container
4105 ID3DXBuffer
*adjacency
;
4106 ID3DXBuffer
*materials
;
4107 ID3DXBuffer
*effects
;
4108 DWORD num_materials
;
4109 D3DXMATRIX transform
;
4112 static HRESULT
parse_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
4113 const D3DXMATRIX
*parent_transform
, struct list
*container_list
, DWORD provide_flags
)
4116 D3DXMATRIX transform
= *parent_transform
;
4117 ID3DXFileData
*child
;
4119 SIZE_T i
, nb_children
;
4121 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
4125 for (i
= 0; i
< nb_children
; i
++)
4127 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
4130 hr
= child
->lpVtbl
->GetType(child
, &type
);
4134 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
4135 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
4137 return E_OUTOFMEMORY
;
4138 list_add_tail(container_list
, &container
->entry
);
4139 container
->transform
= transform
;
4141 hr
= D3DXLoadSkinMeshFromXof(child
, options
, device
,
4142 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
4143 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
4144 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
4145 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
4146 D3DXMATRIX new_transform
;
4147 hr
= parse_transform_matrix(child
, &new_transform
);
4148 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
4149 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
4150 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
4159 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
4160 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
4161 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXMesh
**mesh_out
)
4164 ID3DXFile
*d3dxfile
= NULL
;
4165 ID3DXFileEnumObject
*enumobj
= NULL
;
4166 ID3DXFileData
*filedata
= NULL
;
4167 D3DXF_FILELOADMEMORY source
;
4168 ID3DXBuffer
*materials
= NULL
;
4169 ID3DXBuffer
*effects
= NULL
;
4170 ID3DXBuffer
*adjacency
= NULL
;
4171 struct list container_list
= LIST_INIT(container_list
);
4172 struct mesh_container
*container_ptr
, *next_container_ptr
;
4173 DWORD num_materials
;
4174 DWORD num_faces
, num_vertices
;
4175 D3DXMATRIX identity
;
4176 DWORD provide_flags
= 0;
4178 ID3DXMesh
*concat_mesh
= NULL
;
4179 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
4180 BYTE
*concat_vertices
= NULL
;
4181 void *concat_indices
= NULL
;
4183 DWORD concat_vertex_size
;
4184 SIZE_T i
, nb_children
;
4187 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
4188 device
, adjacency_out
, materials_out
, effects_out
, num_materials_out
, mesh_out
);
4190 if (!memory
|| !memory_size
|| !device
|| !mesh_out
)
4191 return D3DERR_INVALIDCALL
;
4193 hr
= D3DXFileCreate(&d3dxfile
);
4194 if (FAILED(hr
)) goto cleanup
;
4196 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
4197 if (FAILED(hr
)) goto cleanup
;
4199 source
.lpMemory
= (void*)memory
;
4200 source
.dSize
= memory_size
;
4201 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
4202 if (FAILED(hr
)) goto cleanup
;
4204 D3DXMatrixIdentity(&identity
);
4205 if (adjacency_out
) provide_flags
|= PROVIDE_ADJACENCY
;
4206 if (materials_out
|| effects_out
) provide_flags
|= PROVIDE_MATERIALS
;
4208 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
4212 for (i
= 0; i
< nb_children
; i
++)
4214 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
4218 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
4219 if (SUCCEEDED(hr
)) {
4220 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
4221 container_ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container_ptr
));
4222 if (!container_ptr
) {
4226 list_add_tail(&container_list
, &container_ptr
->entry
);
4227 D3DXMatrixIdentity(&container_ptr
->transform
);
4229 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
4230 (provide_flags
& PROVIDE_ADJACENCY
) ? &container_ptr
->adjacency
: NULL
,
4231 (provide_flags
& PROVIDE_MATERIALS
) ? &container_ptr
->materials
: NULL
,
4232 NULL
, &container_ptr
->num_materials
, NULL
, &container_ptr
->mesh
);
4233 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
4234 hr
= parse_frame(filedata
, options
, device
, &identity
, &container_list
, provide_flags
);
4236 if (FAILED(hr
)) goto cleanup
;
4238 filedata
->lpVtbl
->Release(filedata
);
4244 enumobj
->lpVtbl
->Release(enumobj
);
4246 d3dxfile
->lpVtbl
->Release(d3dxfile
);
4249 if (list_empty(&container_list
)) {
4258 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4260 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4261 fvf
|= mesh
->lpVtbl
->GetFVF(mesh
);
4262 num_faces
+= mesh
->lpVtbl
->GetNumFaces(mesh
);
4263 num_vertices
+= mesh
->lpVtbl
->GetNumVertices(mesh
);
4264 num_materials
+= container_ptr
->num_materials
;
4267 hr
= D3DXCreateMeshFVF(num_faces
, num_vertices
, options
, fvf
, device
, &concat_mesh
);
4268 if (FAILED(hr
)) goto cleanup
;
4270 hr
= concat_mesh
->lpVtbl
->GetDeclaration(concat_mesh
, concat_decl
);
4271 if (FAILED(hr
)) goto cleanup
;
4273 concat_vertex_size
= D3DXGetDeclVertexSize(concat_decl
, 0);
4275 hr
= concat_mesh
->lpVtbl
->LockVertexBuffer(concat_mesh
, 0, (void**)&concat_vertices
);
4276 if (FAILED(hr
)) goto cleanup
;
4278 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4280 D3DVERTEXELEMENT9 mesh_decl
[MAX_FVF_DECL_SIZE
];
4281 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4282 DWORD num_mesh_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
4283 DWORD mesh_vertex_size
;
4284 const BYTE
*mesh_vertices
;
4287 hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, mesh_decl
);
4288 if (FAILED(hr
)) goto cleanup
;
4290 mesh_vertex_size
= D3DXGetDeclVertexSize(mesh_decl
, 0);
4292 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_vertices
);
4293 if (FAILED(hr
)) goto cleanup
;
4295 for (i
= 0; i
< num_mesh_vertices
; i
++) {
4299 D3DXVec3TransformCoord((D3DXVECTOR3
*)concat_vertices
,
4300 (D3DXVECTOR3
*)mesh_vertices
,
4301 &container_ptr
->transform
);
4302 for (j
= 1; concat_decl
[j
].Stream
!= 0xff; j
++)
4304 if (concat_decl
[j
].Usage
== mesh_decl
[k
].Usage
&&
4305 concat_decl
[j
].UsageIndex
== mesh_decl
[k
].UsageIndex
)
4307 if (concat_decl
[j
].Usage
== D3DDECLUSAGE_NORMAL
) {
4308 D3DXVec3TransformCoord((D3DXVECTOR3
*)(concat_vertices
+ concat_decl
[j
].Offset
),
4309 (D3DXVECTOR3
*)(mesh_vertices
+ mesh_decl
[k
].Offset
),
4310 &container_ptr
->transform
);
4312 memcpy(concat_vertices
+ concat_decl
[j
].Offset
,
4313 mesh_vertices
+ mesh_decl
[k
].Offset
,
4314 d3dx_decltype_size
[mesh_decl
[k
].Type
]);
4319 mesh_vertices
+= mesh_vertex_size
;
4320 concat_vertices
+= concat_vertex_size
;
4323 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
4326 concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4327 concat_vertices
= NULL
;
4329 hr
= concat_mesh
->lpVtbl
->LockIndexBuffer(concat_mesh
, 0, &concat_indices
);
4330 if (FAILED(hr
)) goto cleanup
;
4333 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4335 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4336 const void *mesh_indices
;
4337 DWORD num_mesh_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4340 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_indices
);
4341 if (FAILED(hr
)) goto cleanup
;
4343 if (options
& D3DXMESH_32BIT
) {
4344 DWORD
*dest
= concat_indices
;
4345 const DWORD
*src
= mesh_indices
;
4346 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4347 *dest
++ = index_offset
+ *src
++;
4348 concat_indices
= dest
;
4350 WORD
*dest
= concat_indices
;
4351 const WORD
*src
= mesh_indices
;
4352 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4353 *dest
++ = index_offset
+ *src
++;
4354 concat_indices
= dest
;
4356 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
4358 index_offset
+= num_mesh_faces
* 3;
4361 concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4362 concat_indices
= NULL
;
4364 if (num_materials
) {
4365 DWORD
*concat_attrib_buffer
= NULL
;
4368 hr
= concat_mesh
->lpVtbl
->LockAttributeBuffer(concat_mesh
, 0, &concat_attrib_buffer
);
4369 if (FAILED(hr
)) goto cleanup
;
4371 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4373 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4374 const DWORD
*mesh_attrib_buffer
= NULL
;
4375 DWORD count
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4377 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, D3DLOCK_READONLY
, (DWORD
**)&mesh_attrib_buffer
);
4379 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4384 *concat_attrib_buffer
++ = offset
+ *mesh_attrib_buffer
++;
4386 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
4387 offset
+= container_ptr
->num_materials
;
4389 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4392 if (materials_out
|| effects_out
) {
4393 D3DXMATERIAL
*out_ptr
;
4394 if (!num_materials
) {
4395 /* create default material */
4396 hr
= D3DXCreateBuffer(sizeof(D3DXMATERIAL
), &materials
);
4397 if (FAILED(hr
)) goto cleanup
;
4399 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4400 out_ptr
->MatD3D
.Diffuse
.r
= 0.5f
;
4401 out_ptr
->MatD3D
.Diffuse
.g
= 0.5f
;
4402 out_ptr
->MatD3D
.Diffuse
.b
= 0.5f
;
4403 out_ptr
->MatD3D
.Specular
.r
= 0.5f
;
4404 out_ptr
->MatD3D
.Specular
.g
= 0.5f
;
4405 out_ptr
->MatD3D
.Specular
.b
= 0.5f
;
4406 /* D3DXCreateBuffer initializes the rest to zero */
4408 DWORD buffer_size
= num_materials
* sizeof(D3DXMATERIAL
);
4409 char *strings_out_ptr
;
4411 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4413 if (container_ptr
->materials
) {
4415 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4416 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4418 if (in_ptr
->pTextureFilename
)
4419 buffer_size
+= strlen(in_ptr
->pTextureFilename
) + 1;
4425 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
4426 if (FAILED(hr
)) goto cleanup
;
4427 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4428 strings_out_ptr
= (char*)(out_ptr
+ num_materials
);
4430 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4432 if (container_ptr
->materials
) {
4434 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4435 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4437 out_ptr
->MatD3D
= in_ptr
->MatD3D
;
4438 if (in_ptr
->pTextureFilename
) {
4439 out_ptr
->pTextureFilename
= strings_out_ptr
;
4440 strcpy(out_ptr
->pTextureFilename
, in_ptr
->pTextureFilename
);
4441 strings_out_ptr
+= strlen(in_ptr
->pTextureFilename
) + 1;
4454 generate_effects(materials
, num_materials
, &effects
);
4455 if (!materials_out
) {
4456 ID3DXBuffer_Release(materials
);
4461 if (adjacency_out
) {
4462 if (!list_next(&container_list
, list_head(&container_list
))) {
4463 container_ptr
= LIST_ENTRY(list_head(&container_list
), struct mesh_container
, entry
);
4464 adjacency
= container_ptr
->adjacency
;
4465 container_ptr
->adjacency
= NULL
;
4470 hr
= D3DXCreateBuffer(num_faces
* 3 * sizeof(DWORD
), &adjacency
);
4471 if (FAILED(hr
)) goto cleanup
;
4473 out_ptr
= ID3DXBuffer_GetBufferPointer(adjacency
);
4474 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4477 DWORD count
= 3 * container_ptr
->mesh
->lpVtbl
->GetNumFaces(container_ptr
->mesh
);
4478 DWORD
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->adjacency
);
4480 for (i
= 0; i
< count
; i
++)
4481 *out_ptr
++ = offset
+ *in_ptr
++;
4488 *mesh_out
= concat_mesh
;
4489 if (adjacency_out
) *adjacency_out
= adjacency
;
4490 if (materials_out
) *materials_out
= materials
;
4491 if (effects_out
) *effects_out
= effects
;
4492 if (num_materials_out
) *num_materials_out
= num_materials
;
4496 if (concat_indices
) concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4497 if (concat_vertices
) concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4498 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
4499 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
4500 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4502 if (concat_mesh
) IUnknown_Release(concat_mesh
);
4503 if (materials
) ID3DXBuffer_Release(materials
);
4504 if (effects
) ID3DXBuffer_Release(effects
);
4505 if (adjacency
) ID3DXBuffer_Release(adjacency
);
4507 LIST_FOR_EACH_ENTRY_SAFE(container_ptr
, next_container_ptr
, &container_list
, struct mesh_container
, entry
)
4509 if (container_ptr
->mesh
) IUnknown_Release(container_ptr
->mesh
);
4510 if (container_ptr
->adjacency
) ID3DXBuffer_Release(container_ptr
->adjacency
);
4511 if (container_ptr
->materials
) ID3DXBuffer_Release(container_ptr
->materials
);
4512 if (container_ptr
->effects
) ID3DXBuffer_Release(container_ptr
->effects
);
4513 HeapFree(GetProcessHeap(), 0, container_ptr
);
4520 D3DXVECTOR3 position
;
4524 HRESULT WINAPI
D3DXCreateBox(struct IDirect3DDevice9
*device
, float width
, float height
,
4525 float depth
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4529 struct vertex
*vertices
;
4531 DWORD
*adjacency_buf
;
4532 unsigned int i
, face
;
4533 static const D3DXVECTOR3 unit_box
[] =
4535 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, -0.5f
},
4536 {-0.5f
, 0.5f
, -0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, -0.5f
},
4537 { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, -0.5f
},
4538 {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, 0.5f
},
4539 {-0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
},
4540 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}
4542 static const D3DXVECTOR3 normals
[] =
4544 {-1.0f
, 0.0f
, 0.0f
}, { 0.0f
, 1.0f
, 0.0f
}, { 1.0f
, 0.0f
, 0.0f
},
4545 { 0.0f
, -1.0f
, 0.0f
}, { 0.0f
, 0.0f
, 1.0f
}, { 0.0f
, 0.0f
, -1.0f
}
4547 static const DWORD adjacency_table
[] =
4549 6, 9, 1, 2, 10, 0, 1, 9, 3, 4, 10, 2,
4550 3, 8, 5, 7, 11, 4, 0, 11, 7, 5, 8, 6,
4551 7, 4, 9, 2, 0, 8, 1, 3, 11, 5, 6, 10
4554 TRACE("device %p, width %f, height %f, depth %f, mesh %p, adjacency %p\n",
4555 device
, width
, height
, depth
, mesh
, adjacency
);
4557 if (!device
|| width
< 0.0f
|| height
< 0.0f
|| depth
< 0.0f
|| !mesh
)
4559 return D3DERR_INVALIDCALL
;
4562 if (FAILED(hr
= D3DXCreateMeshFVF(12, 24, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &box
)))
4567 if (FAILED(hr
= box
->lpVtbl
->LockVertexBuffer(box
, 0, (void **)&vertices
)))
4569 box
->lpVtbl
->Release(box
);
4573 if (FAILED(hr
= box
->lpVtbl
->LockIndexBuffer(box
, 0, (void **)&faces
)))
4575 box
->lpVtbl
->UnlockVertexBuffer(box
);
4576 box
->lpVtbl
->Release(box
);
4580 for (i
= 0; i
< 24; i
++)
4582 vertices
[i
].position
.x
= width
* unit_box
[i
].x
;
4583 vertices
[i
].position
.y
= height
* unit_box
[i
].y
;
4584 vertices
[i
].position
.z
= depth
* unit_box
[i
].z
;
4585 vertices
[i
].normal
.x
= normals
[i
/ 4].x
;
4586 vertices
[i
].normal
.y
= normals
[i
/ 4].y
;
4587 vertices
[i
].normal
.z
= normals
[i
/ 4].z
;
4591 for (i
= 0; i
< 12; i
++)
4593 faces
[i
][0] = face
++;
4594 faces
[i
][1] = face
++;
4595 faces
[i
][2] = (i
% 2) ? face
- 4 : face
;
4598 box
->lpVtbl
->UnlockIndexBuffer(box
);
4599 box
->lpVtbl
->UnlockVertexBuffer(box
);
4603 if (FAILED(hr
= D3DXCreateBuffer(sizeof(adjacency_table
), adjacency
)))
4605 box
->lpVtbl
->Release(box
);
4609 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4610 memcpy(adjacency_buf
, adjacency_table
, sizeof(adjacency_table
));
4618 typedef WORD face
[3];
4626 static void free_sincos_table(struct sincos_table
*sincos_table
)
4628 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
4629 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4632 /* pre compute sine and cosine tables; caller must free */
4633 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
4638 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
4639 if (!sincos_table
->sin
)
4643 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
4644 if (!sincos_table
->cos
)
4646 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4650 angle
= angle_start
;
4651 for (i
= 0; i
< n
; i
++)
4653 sincos_table
->sin
[i
] = sinf(angle
);
4654 sincos_table
->cos
[i
] = cosf(angle
);
4655 angle
+= angle_step
;
4661 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
4663 return stack
*slices
+slice
+1;
4666 HRESULT WINAPI
D3DXCreateSphere(struct IDirect3DDevice9
*device
, float radius
, UINT slices
,
4667 UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4669 DWORD number_of_vertices
, number_of_faces
;
4672 struct vertex
*vertices
;
4674 float phi_step
, phi_start
;
4675 struct sincos_table phi
;
4676 float theta_step
, theta
, sin_theta
, cos_theta
;
4677 DWORD vertex
, face
, stack
, slice
;
4679 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
4681 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
4683 return D3DERR_INVALIDCALL
;
4688 FIXME("Case of adjacency != NULL not implemented.\n");
4692 number_of_vertices
= 2 + slices
* (stacks
-1);
4693 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
4695 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4696 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
4702 if (FAILED(hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, 0, (void **)&vertices
)))
4704 sphere
->lpVtbl
->Release(sphere
);
4708 if (FAILED(hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, 0, (void **)&faces
)))
4710 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4711 sphere
->lpVtbl
->Release(sphere
);
4715 /* phi = angle on xz plane wrt z axis */
4716 phi_step
= -2.0f
* D3DX_PI
/ slices
;
4717 phi_start
= D3DX_PI
/ 2.0f
;
4719 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
4721 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4722 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4723 sphere
->lpVtbl
->Release(sphere
);
4724 return E_OUTOFMEMORY
;
4727 /* theta = angle on xy plane wrt x axis */
4728 theta_step
= D3DX_PI
/ stacks
;
4734 vertices
[vertex
].normal
.x
= 0.0f
;
4735 vertices
[vertex
].normal
.y
= 0.0f
;
4736 vertices
[vertex
].normal
.z
= 1.0f
;
4737 vertices
[vertex
].position
.x
= 0.0f
;
4738 vertices
[vertex
].position
.y
= 0.0f
;
4739 vertices
[vertex
].position
.z
= radius
;
4742 for (stack
= 0; stack
< stacks
- 1; stack
++)
4744 sin_theta
= sinf(theta
);
4745 cos_theta
= cosf(theta
);
4747 for (slice
= 0; slice
< slices
; slice
++)
4749 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
4750 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
4751 vertices
[vertex
].normal
.z
= cos_theta
;
4752 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
4753 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
4754 vertices
[vertex
].position
.z
= radius
* cos_theta
;
4761 /* top stack is triangle fan */
4763 faces
[face
][1] = slice
+ 1;
4764 faces
[face
][2] = slice
;
4769 /* stacks in between top and bottom are quad strips */
4770 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4771 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4772 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4775 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4776 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
4777 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4783 theta
+= theta_step
;
4789 faces
[face
][2] = slice
;
4794 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4795 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4796 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4799 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4800 faces
[face
][1] = vertex_index(slices
, 0, stack
);
4801 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4806 vertices
[vertex
].position
.x
= 0.0f
;
4807 vertices
[vertex
].position
.y
= 0.0f
;
4808 vertices
[vertex
].position
.z
= -radius
;
4809 vertices
[vertex
].normal
.x
= 0.0f
;
4810 vertices
[vertex
].normal
.y
= 0.0f
;
4811 vertices
[vertex
].normal
.z
= -1.0f
;
4813 /* bottom stack is triangle fan */
4814 for (slice
= 1; slice
< slices
; slice
++)
4816 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4817 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4818 faces
[face
][2] = vertex
;
4822 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4823 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4824 faces
[face
][2] = vertex
;
4826 free_sincos_table(&phi
);
4827 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4828 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4834 HRESULT WINAPI
D3DXCreateCylinder(struct IDirect3DDevice9
*device
, float radius1
, float radius2
,
4835 float length
, UINT slices
, UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4837 DWORD number_of_vertices
, number_of_faces
;
4839 ID3DXMesh
*cylinder
;
4840 struct vertex
*vertices
;
4842 float theta_step
, theta_start
;
4843 struct sincos_table theta
;
4844 float delta_radius
, radius
, radius_step
;
4845 float z
, z_step
, z_normal
;
4846 DWORD vertex
, face
, slice
, stack
;
4848 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
4850 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
4852 return D3DERR_INVALIDCALL
;
4857 FIXME("Case of adjacency != NULL not implemented.\n");
4861 number_of_vertices
= 2 + (slices
* (3 + stacks
));
4862 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
4864 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4865 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
4871 if (FAILED(hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, 0, (void **)&vertices
)))
4873 cylinder
->lpVtbl
->Release(cylinder
);
4877 if (FAILED(hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, 0, (void **)&faces
)))
4879 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4880 cylinder
->lpVtbl
->Release(cylinder
);
4884 /* theta = angle on xy plane wrt x axis */
4885 theta_step
= -2.0f
* D3DX_PI
/ slices
;
4886 theta_start
= D3DX_PI
/ 2.0f
;
4888 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
4890 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
4891 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4892 cylinder
->lpVtbl
->Release(cylinder
);
4893 return E_OUTOFMEMORY
;
4899 delta_radius
= radius1
- radius2
;
4901 radius_step
= delta_radius
/ stacks
;
4904 z_step
= length
/ stacks
;
4905 z_normal
= delta_radius
/ length
;
4906 if (isnan(z_normal
))
4911 vertices
[vertex
].normal
.x
= 0.0f
;
4912 vertices
[vertex
].normal
.y
= 0.0f
;
4913 vertices
[vertex
].normal
.z
= -1.0f
;
4914 vertices
[vertex
].position
.x
= 0.0f
;
4915 vertices
[vertex
].position
.y
= 0.0f
;
4916 vertices
[vertex
++].position
.z
= z
;
4918 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4920 vertices
[vertex
].normal
.x
= 0.0f
;
4921 vertices
[vertex
].normal
.y
= 0.0f
;
4922 vertices
[vertex
].normal
.z
= -1.0f
;
4923 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4924 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4925 vertices
[vertex
].position
.z
= z
;
4930 faces
[face
][1] = slice
;
4931 faces
[face
++][2] = slice
+ 1;
4936 faces
[face
][1] = slice
;
4937 faces
[face
++][2] = 1;
4939 for (stack
= 1; stack
<= stacks
+1; stack
++)
4941 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4943 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
4944 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
4945 vertices
[vertex
].normal
.z
= z_normal
;
4946 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
4947 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4948 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4949 vertices
[vertex
].position
.z
= z
;
4951 if (stack
> 1 && slice
> 0)
4953 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4954 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4955 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
4957 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4958 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4959 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
4965 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4966 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4967 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
4969 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4970 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4971 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
4974 if (stack
< stacks
+ 1)
4977 radius
-= radius_step
;
4981 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4983 vertices
[vertex
].normal
.x
= 0.0f
;
4984 vertices
[vertex
].normal
.y
= 0.0f
;
4985 vertices
[vertex
].normal
.z
= 1.0f
;
4986 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4987 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4988 vertices
[vertex
].position
.z
= z
;
4992 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
4993 faces
[face
][1] = number_of_vertices
- 1;
4994 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
4998 vertices
[vertex
].position
.x
= 0.0f
;
4999 vertices
[vertex
].position
.y
= 0.0f
;
5000 vertices
[vertex
].position
.z
= z
;
5001 vertices
[vertex
].normal
.x
= 0.0f
;
5002 vertices
[vertex
].normal
.y
= 0.0f
;
5003 vertices
[vertex
].normal
.z
= 1.0f
;
5005 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5006 faces
[face
][1] = number_of_vertices
- 1;
5007 faces
[face
][2] = vertex_index(slices
, 0, stack
);
5009 free_sincos_table(&theta
);
5010 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5011 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5017 HRESULT WINAPI
D3DXCreateTeapot(struct IDirect3DDevice9
*device
,
5018 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
5020 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
5025 HRESULT WINAPI
D3DXCreateTextA(struct IDirect3DDevice9
*device
, HDC hdc
, const char *text
, float deviation
,
5026 float extrusion
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5032 TRACE("device %p, hdc %p, text %s, deviation %.8e, extrusion %.8e, mesh %p, adjacency %p, glyphmetrics %p.\n",
5033 device
, hdc
, debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
5036 return D3DERR_INVALIDCALL
;
5038 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
5039 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5040 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
5042 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
5043 mesh
, adjacency
, glyphmetrics
);
5044 HeapFree(GetProcessHeap(), 0, textW
);
5050 POINTTYPE_CURVE
= 0,
5052 POINTTYPE_CURVE_START
,
5053 POINTTYPE_CURVE_END
,
5054 POINTTYPE_CURVE_MIDDLE
,
5060 enum pointtype corner
;
5063 struct dynamic_array
5065 int count
, capacity
;
5069 /* is a dynamic_array */
5072 int count
, capacity
;
5073 struct point2d
*items
;
5076 /* is a dynamic_array */
5077 struct outline_array
5079 int count
, capacity
;
5080 struct outline
*items
;
5089 struct point2d_index
5091 struct outline
*outline
;
5095 struct point2d_index_array
5098 struct point2d_index
*items
;
5103 struct outline_array outlines
;
5104 struct face_array faces
;
5105 struct point2d_index_array ordered_vertices
;
5109 /* is an dynamic_array */
5112 int count
, capacity
;
5116 /* complex polygons are split into monotone polygons, which have
5117 * at most 2 intersections with the vertical sweep line */
5118 struct triangulation
5120 struct word_array vertex_stack
;
5121 BOOL last_on_top
, merging
;
5124 /* is an dynamic_array */
5125 struct triangulation_array
5127 int count
, capacity
;
5128 struct triangulation
*items
;
5130 struct glyphinfo
*glyph
;
5133 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
5135 if (count
> array
->capacity
) {
5138 if (array
->items
&& array
->capacity
) {
5139 new_capacity
= max(array
->capacity
* 2, count
);
5140 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
5142 new_capacity
= max(16, count
);
5143 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
5147 array
->items
= new_buffer
;
5148 array
->capacity
= new_capacity
;
5153 static struct point2d
*add_points(struct outline
*array
, int num
)
5155 struct point2d
*item
;
5157 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
5160 item
= &array
->items
[array
->count
];
5161 array
->count
+= num
;
5165 static struct outline
*add_outline(struct outline_array
*array
)
5167 struct outline
*item
;
5169 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5172 item
= &array
->items
[array
->count
++];
5173 ZeroMemory(item
, sizeof(*item
));
5177 static inline face
*add_face(struct face_array
*array
)
5179 return &array
->items
[array
->count
++];
5182 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
5184 struct triangulation
*item
;
5186 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5189 item
= &array
->items
[array
->count
++];
5190 ZeroMemory(item
, sizeof(*item
));
5194 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
5196 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5197 return E_OUTOFMEMORY
;
5199 array
->items
[array
->count
++] = vertex_index
;
5203 /* assume fixed point numbers can be converted to float point in place */
5204 C_ASSERT(sizeof(FIXED
) == sizeof(float));
5205 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
5207 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, unsigned int emsquare
)
5209 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
5211 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
5212 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
5213 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
5219 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
5220 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
5221 float max_deviation_sq
)
5223 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
5226 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
5227 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
5228 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
5230 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
5231 if (deviation_sq
< max_deviation_sq
) {
5232 struct point2d
*pt
= add_points(outline
, 1);
5233 if (!pt
) return E_OUTOFMEMORY
;
5235 pt
->corner
= POINTTYPE_CURVE
;
5236 /* the end point is omitted because the end line merges into the next segment of
5237 * the split bezier curve, and the end of the split bezier curve is added outside
5238 * this recursive function. */
5240 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
5241 if (hr
!= S_OK
) return hr
;
5242 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
5243 if (hr
!= S_OK
) return hr
;
5249 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
5251 /* dot product = cos(theta) */
5252 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
5255 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
5257 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
5267 static BOOL
attempt_line_merge(struct outline
*outline
,
5269 const D3DXVECTOR2
*nextpt
,
5271 const struct cos_table
*table
)
5273 D3DXVECTOR2 curdir
, lastdir
;
5274 struct point2d
*prevpt
, *pt
;
5277 pt
= &outline
->items
[pt_index
];
5278 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5279 prevpt
= &outline
->items
[pt_index
];
5282 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
5284 if (outline
->count
< 2)
5287 /* remove last point if the next line continues the last line */
5288 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5289 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5290 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
5293 if (pt
->corner
== POINTTYPE_CURVE_END
)
5294 prevpt
->corner
= pt
->corner
;
5295 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
5296 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5300 if (outline
->count
< 2)
5303 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5304 prevpt
= &outline
->items
[pt_index
];
5305 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5306 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5311 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
5312 float max_deviation_sq
, unsigned int emsquare
,
5313 const struct cos_table
*cos_table
)
5315 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
5317 while ((char *)header
< (char *)raw_outline
+ datasize
)
5319 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
5320 struct point2d
*lastpt
, *pt
;
5321 D3DXVECTOR2 lastdir
;
5322 D3DXVECTOR2
*pt_flt
;
5324 struct outline
*outline
= add_outline(&glyph
->outlines
);
5327 return E_OUTOFMEMORY
;
5329 pt
= add_points(outline
, 1);
5331 return E_OUTOFMEMORY
;
5332 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
5334 pt
->corner
= POINTTYPE_CORNER
;
5336 if (header
->dwType
!= TT_POLYGON_TYPE
)
5337 FIXME("Unknown header type %d\n", header
->dwType
);
5339 while ((char *)curve
< (char *)header
+ header
->cb
)
5341 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
5342 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
5343 unsigned int j2
= 0;
5346 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5350 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
5352 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
5357 int count
= curve
->cpfx
;
5361 D3DXVECTOR2 bezier_end
;
5363 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j2
], &pt_flt
[j2
+1]), 0.5f
);
5364 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &bezier_end
, max_deviation_sq
);
5367 bezier_start
= bezier_end
;
5371 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &pt_flt
[j2
+1], max_deviation_sq
);
5375 pt
= add_points(outline
, 1);
5377 return E_OUTOFMEMORY
;
5379 pt
->pos
= pt_flt
[j2
];
5380 pt
->corner
= POINTTYPE_CURVE_END
;
5382 pt
= add_points(outline
, curve
->cpfx
);
5384 return E_OUTOFMEMORY
;
5385 for (j2
= 0; j2
< curve
->cpfx
; j2
++)
5387 pt
->pos
= pt_flt
[j2
];
5388 pt
->corner
= POINTTYPE_CORNER
;
5393 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5396 /* remove last point if the next line continues the last line */
5397 if (outline
->count
>= 3) {
5400 lastpt
= &outline
->items
[outline
->count
- 1];
5401 pt
= &outline
->items
[0];
5402 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
5403 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
5405 if (pt
->corner
== POINTTYPE_CURVE_START
)
5406 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5408 pt
->corner
= POINTTYPE_CURVE_END
;
5411 lastpt
= &outline
->items
[outline
->count
- 1];
5413 /* outline closed with a line from end to start point */
5414 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
5416 lastpt
= &outline
->items
[0];
5417 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
5418 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
5419 lastpt
->corner
= POINTTYPE_CORNER
;
5420 pt
= &outline
->items
[1];
5421 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
5422 *lastpt
= outline
->items
[outline
->count
];
5425 lastpt
= &outline
->items
[outline
->count
- 1];
5426 pt
= &outline
->items
[0];
5427 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
5428 for (j
= 0; j
< outline
->count
; j
++)
5433 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
5434 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
5436 switch (lastpt
->corner
)
5438 case POINTTYPE_CURVE_START
:
5439 case POINTTYPE_CURVE_END
:
5440 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
5441 lastpt
->corner
= POINTTYPE_CORNER
;
5443 case POINTTYPE_CURVE_MIDDLE
:
5444 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
5445 lastpt
->corner
= POINTTYPE_CORNER
;
5447 lastpt
->corner
= POINTTYPE_CURVE
;
5455 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
5460 /* Get the y-distance from a line to a point */
5461 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
5462 D3DXVECTOR2
*line_pt2
,
5465 D3DXVECTOR2 line_vec
= {0, 0};
5469 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
5470 line_pt_dx
= point
->x
- line_pt1
->x
;
5471 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
5472 return point
->y
- line_y
;
5475 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
5477 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
5480 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
5482 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
5485 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
5487 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
5488 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
5492 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
5493 struct triangulation_array
*triangulations
,
5497 struct glyphinfo
*glyph
= triangulations
->glyph
;
5498 struct triangulation
*t
= *t_ptr
;
5503 if (t
->last_on_top
) {
5511 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
5512 /* consume all vertices on the stack */
5513 WORD last_pt
= t
->vertex_stack
.items
[0];
5515 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
5517 face
= add_face(&glyph
->faces
);
5518 if (!face
) return E_OUTOFMEMORY
;
5519 (*face
)[0] = vtx_idx
;
5520 (*face
)[f1
] = last_pt
;
5521 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
5523 t
->vertex_stack
.items
[0] = last_pt
;
5524 t
->vertex_stack
.count
= 1;
5525 } else if (t
->vertex_stack
.count
> 1) {
5526 int i
= t
->vertex_stack
.count
- 1;
5527 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
5528 WORD top_idx
= t
->vertex_stack
.items
[i
--];
5529 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
5533 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
5534 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
5536 if (prev_pt
->x
!= top_pt
->x
&&
5537 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
5538 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
5541 face
= add_face(&glyph
->faces
);
5542 if (!face
) return E_OUTOFMEMORY
;
5543 (*face
)[0] = vtx_idx
;
5544 (*face
)[f1
] = prev_idx
;
5545 (*face
)[f2
] = top_idx
;
5549 t
->vertex_stack
.count
--;
5552 t
->last_on_top
= to_top
;
5554 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
5556 if (hr
== S_OK
&& t
->merging
) {
5557 struct triangulation
*t2
;
5559 t2
= to_top
? t
- 1 : t
+ 1;
5560 t2
->merging
= FALSE
;
5561 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
5562 if (hr
!= S_OK
) return hr
;
5563 remove_triangulation(triangulations
, t
);
5571 /* check if the point is next on the outline for either the top or bottom */
5572 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
5574 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
5575 WORD idx
= t
->vertex_stack
.items
[i
];
5576 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
5577 struct outline
*outline
= pt_idx
->outline
;
5580 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
5582 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
5584 return &outline
->items
[i
].pos
;
5587 static int compare_vertex_indices(const void *a
, const void *b
)
5589 const struct point2d_index
*idx1
= a
, *idx2
= b
;
5590 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
5591 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
5592 float diff
= p1
->x
- p2
->x
;
5595 diff
= p1
->y
- p2
->y
;
5597 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
5600 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
5604 struct glyphinfo
*glyph
= triangulations
->glyph
;
5605 int nb_vertices
= 0;
5607 struct point2d_index
*idx_ptr
;
5609 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5610 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
5612 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
5613 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
5614 if (!glyph
->ordered_vertices
.items
)
5615 return E_OUTOFMEMORY
;
5617 idx_ptr
= glyph
->ordered_vertices
.items
;
5618 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5620 struct outline
*outline
= &glyph
->outlines
.items
[i
];
5623 idx_ptr
->outline
= outline
;
5624 idx_ptr
->vertex
= 0;
5626 for (j
= outline
->count
- 1; j
> 0; j
--)
5628 idx_ptr
->outline
= outline
;
5629 idx_ptr
->vertex
= j
;
5633 glyph
->ordered_vertices
.count
= nb_vertices
;
5635 /* Native implementation seems to try to create a triangle fan from
5636 * the first outline point if the glyph only has one outline. */
5637 if (glyph
->outlines
.count
== 1)
5639 struct outline
*outline
= glyph
->outlines
.items
;
5640 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
5641 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
5644 for (i
= 2; i
< outline
->count
; i
++)
5646 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
5647 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
5648 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
5650 D3DXVec2Subtract(&v1
, base
, last
);
5651 D3DXVec2Subtract(&v2
, last
, next
);
5652 ccw
= D3DXVec2CCW(&v1
, &v2
);
5660 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5661 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
5662 if (!glyph
->faces
.items
)
5663 return E_OUTOFMEMORY
;
5665 glyph
->faces
.count
= outline
->count
- 2;
5666 for (i
= 0; i
< glyph
->faces
.count
; i
++)
5668 glyph
->faces
.items
[i
][0] = 0;
5669 glyph
->faces
.items
[i
][1] = i
+ 1;
5670 glyph
->faces
.items
[i
][2] = i
+ 2;
5676 /* Perform 2D polygon triangulation for complex glyphs.
5677 * Triangulation is performed using a sweep line concept, from right to left,
5678 * by processing vertices in sorted order. Complex polygons are split into
5679 * monotone polygons which are triangulated separately. */
5680 /* FIXME: The order of the faces is not consistent with the native implementation. */
5682 /* Reserve space for maximum possible faces from triangulation.
5683 * # faces for outer outlines = outline->count - 2
5684 * # faces for inner outlines = outline->count + 2
5685 * There must be at least 1 outer outline. */
5686 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5687 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
5688 if (!glyph
->faces
.items
)
5689 return E_OUTOFMEMORY
;
5691 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
5692 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
5693 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
5696 int end
= triangulations
->count
;
5700 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
5701 int current
= (start
+ end
) / 2;
5702 struct triangulation
*t
= &triangulations
->items
[current
];
5703 BOOL on_top_outline
= FALSE
;
5704 D3DXVECTOR2
*top_next
, *bottom_next
;
5705 WORD top_idx
, bottom_idx
;
5707 if (t
->merging
&& t
->last_on_top
)
5708 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
5710 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
5711 if (sweep_vtx
== top_next
)
5713 if (t
->merging
&& t
->last_on_top
)
5715 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
5716 if (hr
!= S_OK
) return hr
;
5718 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
5719 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
5721 /* point also on bottom outline of higher triangulation */
5722 struct triangulation
*t2
= t
+ 1;
5723 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
5724 if (hr
!= S_OK
) return hr
;
5729 on_top_outline
= TRUE
;
5732 if (t
->merging
&& !t
->last_on_top
)
5733 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
5735 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
5736 if (sweep_vtx
== bottom_next
)
5738 if (t
->merging
&& !t
->last_on_top
)
5740 if (on_top_outline
) {
5741 /* outline finished */
5742 remove_triangulation(triangulations
, t
);
5746 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
5747 if (hr
!= S_OK
) return hr
;
5749 if (t
> triangulations
->items
&&
5750 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
5752 struct triangulation
*t2
= t
- 1;
5753 /* point also on top outline of lower triangulation */
5754 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
5755 if (hr
!= S_OK
) return hr
;
5756 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
5766 if (t
->last_on_top
) {
5767 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
5768 bottom_idx
= t
->vertex_stack
.items
[0];
5770 top_idx
= t
->vertex_stack
.items
[0];
5771 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
5774 /* check if the point is inside or outside this polygon */
5775 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
5776 top_next
, sweep_vtx
) > 0)
5778 start
= current
+ 1;
5779 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
5780 bottom_next
, sweep_vtx
) < 0)
5783 } else if (t
->merging
) {
5784 /* inside, so cancel merging */
5785 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
5787 t2
->merging
= FALSE
;
5788 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
5789 if (hr
!= S_OK
) return hr
;
5790 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
5791 if (hr
!= S_OK
) return hr
;
5794 /* inside, so split polygon into two monotone parts */
5795 struct triangulation
*t2
= add_triangulation(triangulations
);
5796 if (!t2
) return E_OUTOFMEMORY
;
5797 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
5798 if (t
->last_on_top
) {
5805 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
5806 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
5807 if (hr
!= S_OK
) return hr
;
5808 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
5809 if (hr
!= S_OK
) return hr
;
5810 t2
->last_on_top
= !t
->last_on_top
;
5812 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
5813 if (hr
!= S_OK
) return hr
;
5819 struct triangulation
*t
;
5820 struct triangulation
*t2
= add_triangulation(triangulations
);
5821 if (!t2
) return E_OUTOFMEMORY
;
5822 t
= &triangulations
->items
[start
];
5823 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
5824 ZeroMemory(t
, sizeof(*t
));
5825 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
5826 if (hr
!= S_OK
) return hr
;
5832 HRESULT WINAPI
D3DXCreateTextW(struct IDirect3DDevice9
*device
, HDC hdc
, const WCHAR
*text
, float deviation
,
5833 float extrusion
, struct ID3DXMesh
**mesh_ptr
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5836 ID3DXMesh
*mesh
= NULL
;
5837 DWORD nb_vertices
, nb_faces
;
5838 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
5839 struct vertex
*vertices
= NULL
;
5844 OUTLINETEXTMETRICW otm
;
5845 HFONT font
= NULL
, oldfont
= NULL
;
5846 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
5847 void *raw_outline
= NULL
;
5849 struct glyphinfo
*glyphs
= NULL
;
5851 struct triangulation_array triangulations
= {0, 0, NULL
};
5853 struct vertex
*vertex_ptr
;
5855 float max_deviation_sq
;
5856 const struct cos_table cos_table
= {
5857 cosf(D3DXToRadian(0.5f
)),
5858 cosf(D3DXToRadian(45.0f
)),
5859 cosf(D3DXToRadian(90.0f
)),
5863 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
5864 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
5866 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
5867 return D3DERR_INVALIDCALL
;
5871 FIXME("Case of adjacency != NULL not implemented.\n");
5875 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
5876 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
5878 return D3DERR_INVALIDCALL
;
5881 if (deviation
== 0.0f
)
5882 deviation
= 1.0f
/ otm
.otmEMSquare
;
5883 max_deviation_sq
= deviation
* deviation
;
5885 lf
.lfHeight
= otm
.otmEMSquare
;
5887 font
= CreateFontIndirectW(&lf
);
5892 oldfont
= SelectObject(hdc
, font
);
5894 textlen
= strlenW(text
);
5895 for (i
= 0; i
< textlen
; i
++)
5897 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
5899 return D3DERR_INVALIDCALL
;
5900 if (bufsize
< datasize
)
5903 if (!bufsize
) { /* e.g. text == " " */
5904 hr
= D3DERR_INVALIDCALL
;
5908 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
5909 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
5910 if (!glyphs
|| !raw_outline
) {
5916 for (i
= 0; i
< textlen
; i
++)
5918 /* get outline points from data returned from GetGlyphOutline */
5921 glyphs
[i
].offset_x
= offset_x
;
5923 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
5924 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
5925 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
5926 if (hr
!= S_OK
) goto error
;
5928 triangulations
.glyph
= &glyphs
[i
];
5929 hr
= triangulate(&triangulations
);
5930 if (hr
!= S_OK
) goto error
;
5931 if (triangulations
.count
) {
5932 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
5933 triangulations
.count
= 0;
5938 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
5939 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
5940 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
5941 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
5942 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
5943 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
5945 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
5948 /* corner points need an extra vertex for the different side faces normals */
5950 nb_outline_points
= 0;
5952 for (i
= 0; i
< textlen
; i
++)
5955 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
5956 nb_front_faces
+= glyphs
[i
].faces
.count
;
5957 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
5960 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
5961 nb_corners
++; /* first outline point always repeated as a corner */
5962 for (k
= 1; k
< outline
->count
; k
++)
5963 if (outline
->items
[k
].corner
)
5968 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
5969 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
5972 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
5973 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
5977 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
5980 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, (void **)&faces
)))
5983 /* convert 2D vertices and faces into 3D mesh */
5984 vertex_ptr
= vertices
;
5986 if (extrusion
== 0.0f
) {
5993 for (i
= 0; i
< textlen
; i
++)
5997 struct vertex
*back_vertices
;
6000 /* side vertices and faces */
6001 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6003 struct vertex
*outline_vertices
= vertex_ptr
;
6004 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6006 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
6007 struct point2d
*pt
= &outline
->items
[0];
6009 for (k
= 1; k
<= outline
->count
; k
++)
6012 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
6013 WORD vtx_idx
= vertex_ptr
- vertices
;
6016 if (pt
->corner
== POINTTYPE_CURVE_START
)
6017 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
6018 else if (pt
->corner
)
6019 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6021 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
6022 D3DXVec2Normalize(&vec
, &vec
);
6023 vtx
.normal
.x
= -vec
.y
;
6024 vtx
.normal
.y
= vec
.x
;
6027 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
6028 vtx
.position
.y
= pt
->pos
.y
;
6030 *vertex_ptr
++ = vtx
;
6032 vtx
.position
.z
= -extrusion
;
6033 *vertex_ptr
++ = vtx
;
6035 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
6036 vtx
.position
.y
= nextpt
->pos
.y
;
6037 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
6038 vtx
.position
.z
= -extrusion
;
6039 *vertex_ptr
++ = vtx
;
6041 *vertex_ptr
++ = vtx
;
6043 (*face_ptr
)[0] = vtx_idx
;
6044 (*face_ptr
)[1] = vtx_idx
+ 2;
6045 (*face_ptr
)[2] = vtx_idx
+ 1;
6048 (*face_ptr
)[0] = vtx_idx
;
6049 (*face_ptr
)[1] = vtx_idx
+ 3;
6050 (*face_ptr
)[2] = vtx_idx
+ 2;
6053 if (nextpt
->corner
) {
6054 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
6055 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
6056 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
6058 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6060 D3DXVec2Normalize(&vec
, &vec
);
6061 vtx
.normal
.x
= -vec
.y
;
6062 vtx
.normal
.y
= vec
.x
;
6065 *vertex_ptr
++ = vtx
;
6066 vtx
.position
.z
= -extrusion
;
6067 *vertex_ptr
++ = vtx
;
6070 (*face_ptr
)[0] = vtx_idx
;
6071 (*face_ptr
)[1] = vtx_idx
+ 3;
6072 (*face_ptr
)[2] = vtx_idx
+ 1;
6075 (*face_ptr
)[0] = vtx_idx
;
6076 (*face_ptr
)[1] = vtx_idx
+ 2;
6077 (*face_ptr
)[2] = vtx_idx
+ 3;
6085 *vertex_ptr
++ = *outline_vertices
++;
6086 *vertex_ptr
++ = *outline_vertices
++;
6090 /* back vertices and faces */
6091 back_faces
= face_ptr
;
6092 back_vertices
= vertex_ptr
;
6093 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
6095 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
6096 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
6097 vertex_ptr
->position
.y
= pt
->y
;
6098 vertex_ptr
->position
.z
= 0;
6099 vertex_ptr
->normal
.x
= 0;
6100 vertex_ptr
->normal
.y
= 0;
6101 vertex_ptr
->normal
.z
= 1;
6104 count
= back_vertices
- vertices
;
6105 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
6107 face
*f
= &glyphs
[i
].faces
.items
[j
];
6108 (*face_ptr
)[0] = (*f
)[0] + count
;
6109 (*face_ptr
)[1] = (*f
)[1] + count
;
6110 (*face_ptr
)[2] = (*f
)[2] + count
;
6114 /* front vertices and faces */
6115 j
= count
= vertex_ptr
- back_vertices
;
6118 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
6119 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
6120 vertex_ptr
->position
.z
= -extrusion
;
6121 vertex_ptr
->normal
.x
= 0;
6122 vertex_ptr
->normal
.y
= 0;
6123 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
6127 j
= face_ptr
- back_faces
;
6130 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
6131 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
6132 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
6142 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6143 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6144 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
6147 for (i
= 0; i
< textlen
; i
++)
6150 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6151 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
6152 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
6153 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
6154 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
6156 HeapFree(GetProcessHeap(), 0, glyphs
);
6158 if (triangulations
.items
) {
6160 for (i
= 0; i
< triangulations
.count
; i
++)
6161 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
6162 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
6164 HeapFree(GetProcessHeap(), 0, raw_outline
);
6165 if (oldfont
) SelectObject(hdc
, oldfont
);
6166 if (font
) DeleteObject(font
);
6171 HRESULT WINAPI
D3DXValidMesh(ID3DXMesh
*mesh
, const DWORD
*adjacency
, ID3DXBuffer
**errors_and_warnings
)
6173 FIXME("(%p, %p, %p): stub\n", mesh
, adjacency
, *errors_and_warnings
);
6178 static BOOL
weld_float1(void *to
, void *from
, FLOAT epsilon
)
6183 if (fabsf(*v1
- *v2
) <= epsilon
)
6193 static BOOL
weld_float2(void *to
, void *from
, FLOAT epsilon
)
6195 D3DXVECTOR2
*v1
= to
;
6196 D3DXVECTOR2
*v2
= from
;
6197 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6198 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6199 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6201 if (max_abs_diff
<= epsilon
)
6203 memcpy(to
, from
, sizeof(D3DXVECTOR2
));
6211 static BOOL
weld_float3(void *to
, void *from
, FLOAT epsilon
)
6213 D3DXVECTOR3
*v1
= to
;
6214 D3DXVECTOR3
*v2
= from
;
6215 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6216 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6217 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6218 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6219 max_abs_diff
= max(diff_z
, max_abs_diff
);
6221 if (max_abs_diff
<= epsilon
)
6223 memcpy(to
, from
, sizeof(D3DXVECTOR3
));
6231 static BOOL
weld_float4(void *to
, void *from
, FLOAT epsilon
)
6233 D3DXVECTOR4
*v1
= to
;
6234 D3DXVECTOR4
*v2
= from
;
6235 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6236 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6237 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6238 FLOAT diff_w
= fabsf(v1
->w
- v2
->w
);
6239 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6240 max_abs_diff
= max(diff_z
, max_abs_diff
);
6241 max_abs_diff
= max(diff_w
, max_abs_diff
);
6243 if (max_abs_diff
<= epsilon
)
6245 memcpy(to
, from
, sizeof(D3DXVECTOR4
));
6253 static BOOL
weld_ubyte4(void *to
, void *from
, FLOAT epsilon
)
6257 BYTE truncated_epsilon
= (BYTE
)epsilon
;
6258 BYTE diff_x
= b1
[0] > b2
[0] ? b1
[0] - b2
[0] : b2
[0] - b1
[0];
6259 BYTE diff_y
= b1
[1] > b2
[1] ? b1
[1] - b2
[1] : b2
[1] - b1
[1];
6260 BYTE diff_z
= b1
[2] > b2
[2] ? b1
[2] - b2
[2] : b2
[2] - b1
[2];
6261 BYTE diff_w
= b1
[3] > b2
[3] ? b1
[3] - b2
[3] : b2
[3] - b1
[3];
6262 BYTE max_diff
= max(diff_x
, diff_y
);
6263 max_diff
= max(diff_z
, max_diff
);
6264 max_diff
= max(diff_w
, max_diff
);
6266 if (max_diff
<= truncated_epsilon
)
6268 memcpy(to
, from
, 4 * sizeof(BYTE
));
6276 static BOOL
weld_ubyte4n(void *to
, void *from
, FLOAT epsilon
)
6278 return weld_ubyte4(to
, from
, epsilon
* UCHAR_MAX
);
6281 static BOOL
weld_d3dcolor(void *to
, void *from
, FLOAT epsilon
)
6283 return weld_ubyte4n(to
, from
, epsilon
);
6286 static BOOL
weld_short2(void *to
, void *from
, FLOAT epsilon
)
6290 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6291 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6292 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6293 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6295 if (max_abs_diff
<= truncated_epsilon
)
6297 memcpy(to
, from
, 2 * sizeof(SHORT
));
6305 static BOOL
weld_short2n(void *to
, void *from
, FLOAT epsilon
)
6307 return weld_short2(to
, from
, epsilon
* SHRT_MAX
);
6310 static BOOL
weld_short4(void *to
, void *from
, FLOAT epsilon
)
6314 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6315 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6316 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6317 SHORT diff_z
= abs(s1
[2] - s2
[2]);
6318 SHORT diff_w
= abs(s1
[3] - s2
[3]);
6319 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6320 max_abs_diff
= max(diff_z
, max_abs_diff
);
6321 max_abs_diff
= max(diff_w
, max_abs_diff
);
6323 if (max_abs_diff
<= truncated_epsilon
)
6325 memcpy(to
, from
, 4 * sizeof(SHORT
));
6333 static BOOL
weld_short4n(void *to
, void *from
, FLOAT epsilon
)
6335 return weld_short4(to
, from
, epsilon
* SHRT_MAX
);
6338 static BOOL
weld_ushort2n(void *to
, void *from
, FLOAT epsilon
)
6342 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6343 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6344 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6345 USHORT max_diff
= max(diff_x
, diff_y
);
6347 if (max_diff
<= scaled_epsilon
)
6349 memcpy(to
, from
, 2 * sizeof(USHORT
));
6357 static BOOL
weld_ushort4n(void *to
, void *from
, FLOAT epsilon
)
6361 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6362 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6363 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6364 USHORT diff_z
= s1
[2] > s2
[2] ? s1
[2] - s2
[2] : s2
[2] - s1
[2];
6365 USHORT diff_w
= s1
[3] > s2
[3] ? s1
[3] - s2
[3] : s2
[3] - s1
[3];
6366 USHORT max_diff
= max(diff_x
, diff_y
);
6367 max_diff
= max(diff_z
, max_diff
);
6368 max_diff
= max(diff_w
, max_diff
);
6370 if (max_diff
<= scaled_epsilon
)
6372 memcpy(to
, from
, 4 * sizeof(USHORT
));
6388 static struct udec3
dword_to_udec3(DWORD d
)
6393 v
.y
= (d
& 0xffc00) >> 10;
6394 v
.z
= (d
& 0x3ff00000) >> 20;
6395 v
.w
= (d
& 0xc0000000) >> 30;
6400 static BOOL
weld_udec3(void *to
, void *from
, FLOAT epsilon
)
6404 struct udec3 v1
= dword_to_udec3(*d1
);
6405 struct udec3 v2
= dword_to_udec3(*d2
);
6406 UINT truncated_epsilon
= (UINT
)epsilon
;
6407 UINT diff_x
= v1
.x
> v2
.x
? v1
.x
- v2
.x
: v2
.x
- v1
.x
;
6408 UINT diff_y
= v1
.y
> v2
.y
? v1
.y
- v2
.y
: v2
.y
- v1
.y
;
6409 UINT diff_z
= v1
.z
> v2
.z
? v1
.z
- v2
.z
: v2
.z
- v1
.z
;
6410 UINT diff_w
= v1
.w
> v2
.w
? v1
.w
- v2
.w
: v2
.w
- v1
.w
;
6411 UINT max_diff
= max(diff_x
, diff_y
);
6412 max_diff
= max(diff_z
, max_diff
);
6413 max_diff
= max(diff_w
, max_diff
);
6415 if (max_diff
<= truncated_epsilon
)
6417 memcpy(to
, from
, sizeof(DWORD
));
6433 static struct dec3n
dword_to_dec3n(DWORD d
)
6438 v
.y
= (d
& 0xffc00) >> 10;
6439 v
.z
= (d
& 0x3ff00000) >> 20;
6440 v
.w
= (d
& 0xc0000000) >> 30;
6445 static BOOL
weld_dec3n(void *to
, void *from
, FLOAT epsilon
)
6447 const UINT MAX_DEC3N
= 511;
6450 struct dec3n v1
= dword_to_dec3n(*d1
);
6451 struct dec3n v2
= dword_to_dec3n(*d2
);
6452 INT scaled_epsilon
= (INT
)(epsilon
* MAX_DEC3N
);
6453 INT diff_x
= abs(v1
.x
- v2
.x
);
6454 INT diff_y
= abs(v1
.y
- v2
.y
);
6455 INT diff_z
= abs(v1
.z
- v2
.z
);
6456 INT diff_w
= abs(v1
.w
- v2
.w
);
6457 INT max_abs_diff
= max(diff_x
, diff_y
);
6458 max_abs_diff
= max(diff_z
, max_abs_diff
);
6459 max_abs_diff
= max(diff_w
, max_abs_diff
);
6461 if (max_abs_diff
<= scaled_epsilon
)
6463 memcpy(to
, from
, sizeof(DWORD
));
6471 static BOOL
weld_float16_2(void *to
, void *from
, FLOAT epsilon
)
6473 D3DXFLOAT16
*v1_float16
= to
;
6474 D3DXFLOAT16
*v2_float16
= from
;
6482 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6483 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6485 diff_x
= fabsf(v1
[0] - v2
[0]);
6486 diff_y
= fabsf(v1
[1] - v2
[1]);
6487 max_abs_diff
= max(diff_x
, diff_y
);
6489 if (max_abs_diff
<= epsilon
)
6491 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6500 static BOOL
weld_float16_4(void *to
, void *from
, FLOAT epsilon
)
6502 D3DXFLOAT16
*v1_float16
= to
;
6503 D3DXFLOAT16
*v2_float16
= from
;
6513 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6514 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6516 diff_x
= fabsf(v1
[0] - v2
[0]);
6517 diff_y
= fabsf(v1
[1] - v2
[1]);
6518 diff_z
= fabsf(v1
[2] - v2
[2]);
6519 diff_w
= fabsf(v1
[3] - v2
[3]);
6520 max_abs_diff
= max(diff_x
, diff_y
);
6521 max_abs_diff
= max(diff_z
, max_abs_diff
);
6522 max_abs_diff
= max(diff_w
, max_abs_diff
);
6524 if (max_abs_diff
<= epsilon
)
6526 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6535 /* Sets the vertex components to the same value if they are within epsilon. */
6536 static BOOL
weld_component(void *to
, void *from
, D3DDECLTYPE type
, FLOAT epsilon
)
6538 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6539 BOOL fixme_once_unused
= FALSE
;
6540 BOOL fixme_once_unknown
= FALSE
;
6544 case D3DDECLTYPE_FLOAT1
:
6545 return weld_float1(to
, from
, epsilon
);
6547 case D3DDECLTYPE_FLOAT2
:
6548 return weld_float2(to
, from
, epsilon
);
6550 case D3DDECLTYPE_FLOAT3
:
6551 return weld_float3(to
, from
, epsilon
);
6553 case D3DDECLTYPE_FLOAT4
:
6554 return weld_float4(to
, from
, epsilon
);
6556 case D3DDECLTYPE_D3DCOLOR
:
6557 return weld_d3dcolor(to
, from
, epsilon
);
6559 case D3DDECLTYPE_UBYTE4
:
6560 return weld_ubyte4(to
, from
, epsilon
);
6562 case D3DDECLTYPE_SHORT2
:
6563 return weld_short2(to
, from
, epsilon
);
6565 case D3DDECLTYPE_SHORT4
:
6566 return weld_short4(to
, from
, epsilon
);
6568 case D3DDECLTYPE_UBYTE4N
:
6569 return weld_ubyte4n(to
, from
, epsilon
);
6571 case D3DDECLTYPE_SHORT2N
:
6572 return weld_short2n(to
, from
, epsilon
);
6574 case D3DDECLTYPE_SHORT4N
:
6575 return weld_short4n(to
, from
, epsilon
);
6577 case D3DDECLTYPE_USHORT2N
:
6578 return weld_ushort2n(to
, from
, epsilon
);
6580 case D3DDECLTYPE_USHORT4N
:
6581 return weld_ushort4n(to
, from
, epsilon
);
6583 case D3DDECLTYPE_UDEC3
:
6584 return weld_udec3(to
, from
, epsilon
);
6586 case D3DDECLTYPE_DEC3N
:
6587 return weld_dec3n(to
, from
, epsilon
);
6589 case D3DDECLTYPE_FLOAT16_2
:
6590 return weld_float16_2(to
, from
, epsilon
);
6592 case D3DDECLTYPE_FLOAT16_4
:
6593 return weld_float16_4(to
, from
, epsilon
);
6595 case D3DDECLTYPE_UNUSED
:
6596 if (!fixme_once_unused
++)
6597 FIXME("D3DDECLTYPE_UNUSED welding not implemented.\n");
6601 if (!fixme_once_unknown
++)
6602 FIXME("Welding of unknown declaration type %d is not implemented.\n", type
);
6609 static FLOAT
get_component_epsilon(const D3DVERTEXELEMENT9
*decl_ptr
, const D3DXWELDEPSILONS
*epsilons
)
6611 FLOAT epsilon
= 0.0f
;
6612 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6613 static BOOL fixme_once_blendindices
= FALSE
;
6614 static BOOL fixme_once_positiont
= FALSE
;
6615 static BOOL fixme_once_fog
= FALSE
;
6616 static BOOL fixme_once_depth
= FALSE
;
6617 static BOOL fixme_once_sample
= FALSE
;
6618 static BOOL fixme_once_unknown
= FALSE
;
6620 switch (decl_ptr
->Usage
)
6622 case D3DDECLUSAGE_POSITION
:
6623 epsilon
= epsilons
->Position
;
6625 case D3DDECLUSAGE_BLENDWEIGHT
:
6626 epsilon
= epsilons
->BlendWeights
;
6628 case D3DDECLUSAGE_NORMAL
:
6629 epsilon
= epsilons
->Normals
;
6631 case D3DDECLUSAGE_PSIZE
:
6632 epsilon
= epsilons
->PSize
;
6634 case D3DDECLUSAGE_TEXCOORD
:
6636 BYTE usage_index
= decl_ptr
->UsageIndex
;
6637 if (usage_index
> 7)
6639 epsilon
= epsilons
->Texcoords
[usage_index
];
6642 case D3DDECLUSAGE_TANGENT
:
6643 epsilon
= epsilons
->Tangent
;
6645 case D3DDECLUSAGE_BINORMAL
:
6646 epsilon
= epsilons
->Binormal
;
6648 case D3DDECLUSAGE_TESSFACTOR
:
6649 epsilon
= epsilons
->TessFactor
;
6651 case D3DDECLUSAGE_COLOR
:
6652 if (decl_ptr
->UsageIndex
== 0)
6653 epsilon
= epsilons
->Diffuse
;
6654 else if (decl_ptr
->UsageIndex
== 1)
6655 epsilon
= epsilons
->Specular
;
6659 case D3DDECLUSAGE_BLENDINDICES
:
6660 if (!fixme_once_blendindices
++)
6661 FIXME("D3DDECLUSAGE_BLENDINDICES welding not implemented.\n");
6663 case D3DDECLUSAGE_POSITIONT
:
6664 if (!fixme_once_positiont
++)
6665 FIXME("D3DDECLUSAGE_POSITIONT welding not implemented.\n");
6667 case D3DDECLUSAGE_FOG
:
6668 if (!fixme_once_fog
++)
6669 FIXME("D3DDECLUSAGE_FOG welding not implemented.\n");
6671 case D3DDECLUSAGE_DEPTH
:
6672 if (!fixme_once_depth
++)
6673 FIXME("D3DDECLUSAGE_DEPTH welding not implemented.\n");
6675 case D3DDECLUSAGE_SAMPLE
:
6676 if (!fixme_once_sample
++)
6677 FIXME("D3DDECLUSAGE_SAMPLE welding not implemented.\n");
6680 if (!fixme_once_unknown
++)
6681 FIXME("Unknown usage %x\n", decl_ptr
->Usage
);
6688 /* Helper function for reading a 32-bit index buffer. */
6689 static inline DWORD
read_ib(void *index_buffer
, BOOL indices_are_32bit
,
6692 if (indices_are_32bit
)
6694 DWORD
*indices
= index_buffer
;
6695 return indices
[index
];
6699 WORD
*indices
= index_buffer
;
6700 return indices
[index
];
6704 /* Helper function for writing to a 32-bit index buffer. */
6705 static inline void write_ib(void *index_buffer
, BOOL indices_are_32bit
,
6706 DWORD index
, DWORD value
)
6708 if (indices_are_32bit
)
6710 DWORD
*indices
= index_buffer
;
6711 indices
[index
] = value
;
6715 WORD
*indices
= index_buffer
;
6716 indices
[index
] = value
;
6720 /*************************************************************************
6721 * D3DXWeldVertices (D3DX9_36.@)
6723 * Welds together similar vertices. The similarity between vert-
6724 * ices can be the position and other components such as
6728 * mesh [I] Mesh which vertices will be welded together.
6729 * flags [I] D3DXWELDEPSILONSFLAGS specifying how to weld.
6730 * epsilons [I] How similar a component needs to be for welding.
6731 * adjacency [I] Which faces are adjacent to other faces.
6732 * adjacency_out [O] Updated adjacency after welding.
6733 * face_remap_out [O] Which faces the old faces have been mapped to.
6734 * vertex_remap_out [O] Which vertices the old vertices have been mapped to.
6738 * Failure: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
6741 * Attribute sorting not implemented.
6744 HRESULT WINAPI
D3DXWeldVertices(ID3DXMesh
*mesh
, DWORD flags
, const D3DXWELDEPSILONS
*epsilons
,
6745 const DWORD
*adjacency
, DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
6747 DWORD
*adjacency_generated
= NULL
;
6748 const DWORD
*adjacency_ptr
;
6749 DWORD
*attributes
= NULL
;
6750 const FLOAT DEFAULT_EPSILON
= 1.0e-6f
;
6753 void *indices
= NULL
;
6754 BOOL indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
6755 DWORD optimize_flags
;
6756 DWORD
*point_reps
= NULL
;
6757 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(mesh
);
6758 DWORD
*vertex_face_map
= NULL
;
6759 ID3DXBuffer
*vertex_remap
= NULL
;
6760 BYTE
*vertices
= NULL
;
6762 TRACE("mesh %p, flags %#x, epsilons %p, adjacency %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
6763 mesh
, flags
, epsilons
, adjacency
, adjacency_out
, face_remap_out
, vertex_remap_out
);
6767 WARN("No flags is undefined. Using D3DXWELDEPSILONS_WELDPARTIALMATCHES instead.\n");
6768 flags
= D3DXWELDEPSILONS_WELDPARTIALMATCHES
;
6771 if (adjacency
) /* Use supplied adjacency. */
6773 adjacency_ptr
= adjacency
;
6775 else /* Adjacency has to be generated. */
6777 adjacency_generated
= HeapAlloc(GetProcessHeap(), 0, 3 * This
->numfaces
* sizeof(*adjacency_generated
));
6778 if (!adjacency_generated
)
6780 ERR("Couldn't allocate memory for adjacency_generated.\n");
6784 hr
= mesh
->lpVtbl
->GenerateAdjacency(mesh
, DEFAULT_EPSILON
, adjacency_generated
);
6787 ERR("Couldn't generate adjacency.\n");
6790 adjacency_ptr
= adjacency_generated
;
6793 /* Point representation says which vertices can be replaced. */
6794 point_reps
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*point_reps
));
6798 ERR("Couldn't allocate memory for point_reps.\n");
6801 hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency_ptr
, point_reps
);
6804 ERR("ConvertAdjacencyToPointReps failed.\n");
6808 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
);
6811 ERR("Couldn't lock index buffer.\n");
6815 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, 0, &attributes
);
6818 ERR("Couldn't lock attribute buffer.\n");
6821 vertex_face_map
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*vertex_face_map
));
6822 if (!vertex_face_map
)
6825 ERR("Couldn't allocate memory for vertex_face_map.\n");
6828 /* Build vertex face map, so that a vertex's face can be looked up. */
6829 for (i
= 0; i
< This
->numfaces
; i
++)
6832 for (j
= 0; j
< 3; j
++)
6834 DWORD index
= read_ib(indices
, indices_are_32bit
, 3*i
+ j
);
6835 vertex_face_map
[index
] = i
;
6839 if (flags
& D3DXWELDEPSILONS_WELDPARTIALMATCHES
)
6841 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void**)&vertices
);
6844 ERR("Couldn't lock vertex buffer.\n");
6847 /* For each vertex that can be removed, compare its vertex components
6848 * with the vertex components from the vertex that can replace it. A
6849 * vertex is only fully replaced if all the components match and the
6850 * flag D3DXWELDEPSILONS_DONOTREMOVEVERTICES is not set, and they
6851 * belong to the same attribute group. Otherwise the vertex components
6852 * that are within epsilon are set to the same value.
6854 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
6856 D3DVERTEXELEMENT9
*decl_ptr
;
6857 DWORD vertex_size
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
6858 DWORD num_vertex_components
;
6861 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
6863 for (decl_ptr
= This
->cached_declaration
, num_vertex_components
= 0; decl_ptr
->Stream
!= 0xFF; decl_ptr
++, num_vertex_components
++)
6865 BYTE
*to
= &vertices
[vertex_size
*index
+ decl_ptr
->Offset
];
6866 BYTE
*from
= &vertices
[vertex_size
*point_reps
[index
] + decl_ptr
->Offset
];
6867 FLOAT epsilon
= get_component_epsilon(decl_ptr
, epsilons
);
6869 /* Don't weld self */
6870 if (index
== point_reps
[index
])
6876 if (weld_component(to
, from
, decl_ptr
->Type
, epsilon
))
6880 all_match
= (num_vertex_components
== matches
);
6881 if (all_match
&& !(flags
& D3DXWELDEPSILONS_DONOTREMOVEVERTICES
))
6883 DWORD to_face
= vertex_face_map
[index
];
6884 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
6885 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
6887 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
6890 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6893 else if (flags
& D3DXWELDEPSILONS_WELDALL
)
6895 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
6897 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
6898 DWORD to_face
= vertex_face_map
[index
];
6899 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
6900 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
6902 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
6905 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
6907 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6910 /* Compact mesh using OptimizeInplace */
6911 optimize_flags
= D3DXMESHOPT_COMPACT
;
6912 hr
= mesh
->lpVtbl
->OptimizeInplace(mesh
, optimize_flags
, adjacency_ptr
, adjacency_out
, face_remap_out
, vertex_remap_out
);
6915 ERR("Couldn't compact mesh.\n");
6921 HeapFree(GetProcessHeap(), 0, adjacency_generated
);
6922 HeapFree(GetProcessHeap(), 0, point_reps
);
6923 HeapFree(GetProcessHeap(), 0, vertex_face_map
);
6924 if (attributes
) mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
6925 if (indices
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6926 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
6927 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6932 /*************************************************************************
6933 * D3DXOptimizeFaces (D3DX9_36.@)
6935 * Re-orders the faces so the vertex cache is used optimally.
6938 * indices [I] Pointer to an index buffer belonging to a mesh.
6939 * num_faces [I] Number of faces in the mesh.
6940 * num_vertices [I] Number of vertices in the mesh.
6941 * indices_are_32bit [I] Specifies whether indices are 32- or 16-bit.
6942 * face_remap [I/O] The new order the faces should be drawn in.
6946 * Failure: D3DERR_INVALIDCALL.
6949 * The face re-ordering does not use the vertex cache optimally.
6952 HRESULT WINAPI
D3DXOptimizeFaces(const void *indices
, UINT num_faces
,
6953 UINT num_vertices
, BOOL indices_are_32bit
, DWORD
*face_remap
)
6956 UINT j
= num_faces
- 1;
6957 UINT limit_16_bit
= 2 << 15; /* According to MSDN */
6958 HRESULT hr
= D3D_OK
;
6960 FIXME("indices %p, num_faces %u, num_vertices %u, indices_are_32bit %#x, face_remap %p semi-stub. "
6961 "Face order will not be optimal.\n",
6962 indices
, num_faces
, num_vertices
, indices_are_32bit
, face_remap
);
6964 if (!indices_are_32bit
&& num_faces
>= limit_16_bit
)
6966 WARN("Number of faces must be less than %d when using 16-bit indices.\n",
6968 hr
= D3DERR_INVALIDCALL
;
6974 WARN("Face remap pointer is NULL.\n");
6975 hr
= D3DERR_INVALIDCALL
;
6979 /* The faces are drawn in reverse order for simple meshes. This ordering
6980 * is not optimal for complicated meshes, but will not break anything
6981 * either. The ordering should be changed to take advantage of the vertex
6982 * cache on the graphics card.
6984 * TODO Re-order to take advantage of vertex cache.
6986 for (i
= 0; i
< num_faces
; i
++)
6988 face_remap
[i
] = j
--;