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
28 #include "wine/port.h"
31 #define NONAMELESSUNION
43 #include "wine/debug.h"
44 #include "wine/unicode.h"
45 #include "wine/list.h"
46 #include "d3dx9_36_private.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
50 typedef struct ID3DXMeshImpl
52 ID3DXMesh ID3DXMesh_iface
;
59 IDirect3DDevice9
*device
;
60 D3DVERTEXELEMENT9 cached_declaration
[MAX_FVF_DECL_SIZE
];
61 IDirect3DVertexDeclaration9
*vertex_declaration
;
62 UINT vertex_declaration_size
;
64 IDirect3DVertexBuffer9
*vertex_buffer
;
65 IDirect3DIndexBuffer9
*index_buffer
;
67 int attrib_buffer_lock_count
;
68 DWORD attrib_table_size
;
69 D3DXATTRIBUTERANGE
*attrib_table
;
72 const UINT d3dx_decltype_size
[] =
74 /* D3DDECLTYPE_FLOAT1 */ sizeof(FLOAT
),
75 /* D3DDECLTYPE_FLOAT2 */ sizeof(D3DXVECTOR2
),
76 /* D3DDECLTYPE_FLOAT3 */ sizeof(D3DXVECTOR3
),
77 /* D3DDECLTYPE_FLOAT4 */ sizeof(D3DXVECTOR4
),
78 /* D3DDECLTYPE_D3DCOLOR */ sizeof(D3DCOLOR
),
79 /* D3DDECLTYPE_UBYTE4 */ 4 * sizeof(BYTE
),
80 /* D3DDECLTYPE_SHORT2 */ 2 * sizeof(SHORT
),
81 /* D3DDECLTYPE_SHORT4 */ 4 * sizeof(SHORT
),
82 /* D3DDECLTYPE_UBYTE4N */ 4 * sizeof(BYTE
),
83 /* D3DDECLTYPE_SHORT2N */ 2 * sizeof(SHORT
),
84 /* D3DDECLTYPE_SHORT4N */ 4 * sizeof(SHORT
),
85 /* D3DDECLTYPE_USHORT2N */ 2 * sizeof(USHORT
),
86 /* D3DDECLTYPE_USHORT4N */ 4 * sizeof(USHORT
),
87 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
88 /* D3DDECLTYPE_DEC3N */ 4,
89 /* D3DDECLTYPE_FLOAT16_2 */ 2 * sizeof(D3DXFLOAT16
),
90 /* D3DDECLTYPE_FLOAT16_4 */ 4 * sizeof(D3DXFLOAT16
),
93 static inline ID3DXMeshImpl
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
95 return CONTAINING_RECORD(iface
, ID3DXMeshImpl
, ID3DXMesh_iface
);
98 static HRESULT WINAPI
ID3DXMeshImpl_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, LPVOID
*object
)
100 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), object
);
102 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
103 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
104 IsEqualGUID(riid
, &IID_ID3DXMesh
))
106 iface
->lpVtbl
->AddRef(iface
);
111 WARN("Interface %s not found.\n", debugstr_guid(riid
));
113 return E_NOINTERFACE
;
116 static ULONG WINAPI
ID3DXMeshImpl_AddRef(ID3DXMesh
*iface
)
118 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
120 TRACE("(%p)->(): AddRef from %d\n", This
, This
->ref
);
122 return InterlockedIncrement(&This
->ref
);
125 static ULONG WINAPI
ID3DXMeshImpl_Release(ID3DXMesh
*iface
)
127 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
128 ULONG ref
= InterlockedDecrement(&This
->ref
);
130 TRACE("(%p)->(): Release from %d\n", This
, ref
+ 1);
134 IDirect3DIndexBuffer9_Release(This
->index_buffer
);
135 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
136 if (This
->vertex_declaration
)
137 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
138 IDirect3DDevice9_Release(This
->device
);
139 HeapFree(GetProcessHeap(), 0, This
->attrib_buffer
);
140 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
141 HeapFree(GetProcessHeap(), 0, This
);
147 /*** ID3DXBaseMesh ***/
148 static HRESULT WINAPI
ID3DXMeshImpl_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
150 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
156 TRACE("(%p)->(%u)\n", This
, attrib_id
);
158 if (!This
->vertex_declaration
)
160 WARN("Can't draw a mesh with an invalid vertex declaration.\n");
164 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
166 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
167 if (FAILED(hr
)) return hr
;
168 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
169 if (FAILED(hr
)) return hr
;
170 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
171 if (FAILED(hr
)) return hr
;
173 while (face_end
< This
->numfaces
)
175 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
177 if (This
->attrib_buffer
[face_start
] == attrib_id
)
180 if (face_start
>= This
->numfaces
)
182 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
184 if (This
->attrib_buffer
[face_end
] != attrib_id
)
188 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
189 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
190 if (FAILED(hr
)) return hr
;
196 static DWORD WINAPI
ID3DXMeshImpl_GetNumFaces(ID3DXMesh
*iface
)
198 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
200 TRACE("(%p)\n", This
);
202 return This
->numfaces
;
205 static DWORD WINAPI
ID3DXMeshImpl_GetNumVertices(ID3DXMesh
*iface
)
207 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
209 TRACE("(%p)\n", This
);
211 return This
->numvertices
;
214 static DWORD WINAPI
ID3DXMeshImpl_GetFVF(ID3DXMesh
*iface
)
216 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
218 TRACE("(%p)\n", This
);
223 static void copy_declaration(D3DVERTEXELEMENT9
*dst
, const D3DVERTEXELEMENT9
*src
, UINT num_elem
)
225 memcpy(dst
, src
, num_elem
* sizeof(*src
));
228 static HRESULT WINAPI
ID3DXMeshImpl_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
230 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
232 TRACE("(%p)\n", This
);
234 if (declaration
== NULL
) return D3DERR_INVALIDCALL
;
236 copy_declaration(declaration
, This
->cached_declaration
, This
->num_elem
);
241 static DWORD WINAPI
ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh
*iface
)
243 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
245 TRACE("iface (%p)\n", This
);
247 return This
->vertex_declaration_size
;
250 static DWORD WINAPI
ID3DXMeshImpl_GetOptions(ID3DXMesh
*iface
)
252 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
254 TRACE("(%p)\n", This
);
256 return This
->options
;
259 static HRESULT WINAPI
ID3DXMeshImpl_GetDevice(struct ID3DXMesh
*iface
, struct IDirect3DDevice9
**device
)
261 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
263 TRACE("(%p)->(%p)\n", This
, device
);
265 if (device
== NULL
) return D3DERR_INVALIDCALL
;
266 *device
= This
->device
;
267 IDirect3DDevice9_AddRef(This
->device
);
272 static HRESULT WINAPI
ID3DXMeshImpl_CloneMeshFVF(struct ID3DXMesh
*iface
, DWORD options
, DWORD fvf
,
273 struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh
)
275 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
277 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
279 TRACE("(%p)->(%x,%x,%p,%p)\n", This
, options
, fvf
, device
, clone_mesh
);
281 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
282 if (FAILED(hr
)) return hr
;
284 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
287 static FLOAT
scale_clamp_ubyten(FLOAT value
)
289 value
= value
* UCHAR_MAX
;
297 if (value
> UCHAR_MAX
) /* Clamp at 255 */
304 static FLOAT
scale_clamp_shortn(FLOAT value
)
306 value
= value
* SHRT_MAX
;
308 /* The tests show that the range is SHRT_MIN + 1 to SHRT_MAX. */
309 if (value
<= SHRT_MIN
)
313 else if (value
> SHRT_MAX
)
323 static FLOAT
scale_clamp_ushortn(FLOAT value
)
325 value
= value
* USHRT_MAX
;
333 if (value
> USHRT_MAX
) /* Clamp at 65535 */
340 static INT
simple_round(FLOAT value
)
342 int res
= (INT
)(value
+ 0.5f
);
347 static void convert_float4(BYTE
*dst
, CONST D3DXVECTOR4
*src
, D3DDECLTYPE type_dst
)
349 BOOL fixme_once
= FALSE
;
353 case D3DDECLTYPE_FLOAT1
:
355 FLOAT
*dst_ptr
= (FLOAT
*)dst
;
359 case D3DDECLTYPE_FLOAT2
:
361 D3DXVECTOR2
*dst_ptr
= (D3DXVECTOR2
*)dst
;
366 case D3DDECLTYPE_FLOAT3
:
368 D3DXVECTOR3
*dst_ptr
= (D3DXVECTOR3
*)dst
;
374 case D3DDECLTYPE_FLOAT4
:
376 D3DXVECTOR4
*dst_ptr
= (D3DXVECTOR4
*)dst
;
383 case D3DDECLTYPE_D3DCOLOR
:
385 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
386 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
387 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
388 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
391 case D3DDECLTYPE_UBYTE4
:
393 dst
[0] = src
->x
< 0.0f
? 0 : (BYTE
)simple_round(src
->x
);
394 dst
[1] = src
->y
< 0.0f
? 0 : (BYTE
)simple_round(src
->y
);
395 dst
[2] = src
->z
< 0.0f
? 0 : (BYTE
)simple_round(src
->z
);
396 dst
[3] = src
->w
< 0.0f
? 0 : (BYTE
)simple_round(src
->w
);
399 case D3DDECLTYPE_SHORT2
:
401 SHORT
*dst_ptr
= (SHORT
*)dst
;
402 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
403 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
406 case D3DDECLTYPE_SHORT4
:
408 SHORT
*dst_ptr
= (SHORT
*)dst
;
409 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
410 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
411 dst_ptr
[2] = (SHORT
)simple_round(src
->z
);
412 dst_ptr
[3] = (SHORT
)simple_round(src
->w
);
415 case D3DDECLTYPE_UBYTE4N
:
417 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
418 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
419 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
420 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
423 case D3DDECLTYPE_SHORT2N
:
425 SHORT
*dst_ptr
= (SHORT
*)dst
;
426 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
427 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
430 case D3DDECLTYPE_SHORT4N
:
432 SHORT
*dst_ptr
= (SHORT
*)dst
;
433 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
434 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
435 dst_ptr
[2] = (SHORT
)simple_round(scale_clamp_shortn(src
->z
));
436 dst_ptr
[3] = (SHORT
)simple_round(scale_clamp_shortn(src
->w
));
439 case D3DDECLTYPE_USHORT2N
:
441 USHORT
*dst_ptr
= (USHORT
*)dst
;
442 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
443 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
446 case D3DDECLTYPE_USHORT4N
:
448 USHORT
*dst_ptr
= (USHORT
*)dst
;
449 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
450 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
451 dst_ptr
[2] = (USHORT
)simple_round(scale_clamp_ushortn(src
->z
));
452 dst_ptr
[3] = (USHORT
)simple_round(scale_clamp_ushortn(src
->w
));
455 case D3DDECLTYPE_FLOAT16_2
:
457 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 2);
460 case D3DDECLTYPE_FLOAT16_4
:
462 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 4);
467 FIXME("Conversion from D3DDECLTYPE_FLOAT4 to %d not implemented.\n", type_dst
);
472 static void convert_component(BYTE
*dst
, BYTE
*src
, D3DDECLTYPE type_dst
, D3DDECLTYPE type_src
)
474 BOOL fixme_once
= FALSE
;
478 case D3DDECLTYPE_FLOAT1
:
480 FLOAT
*src_ptr
= (FLOAT
*)src
;
481 D3DXVECTOR4 src_float4
= {*src_ptr
, 0.0f
, 0.0f
, 1.0f
};
482 convert_float4(dst
, &src_float4
, type_dst
);
485 case D3DDECLTYPE_FLOAT2
:
487 D3DXVECTOR2
*src_ptr
= (D3DXVECTOR2
*)src
;
488 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, 0.0f
, 1.0f
};
489 convert_float4(dst
, &src_float4
, type_dst
);
492 case D3DDECLTYPE_FLOAT3
:
494 D3DXVECTOR3
*src_ptr
= (D3DXVECTOR3
*)src
;
495 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, 1.0f
};
496 convert_float4(dst
, &src_float4
, type_dst
);
499 case D3DDECLTYPE_FLOAT4
:
501 D3DXVECTOR4
*src_ptr
= (D3DXVECTOR4
*)src
;
502 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, src_ptr
->w
};
503 convert_float4(dst
, &src_float4
, type_dst
);
506 case D3DDECLTYPE_D3DCOLOR
:
508 D3DXVECTOR4 src_float4
=
510 (FLOAT
)src
[2]/UCHAR_MAX
,
511 (FLOAT
)src
[1]/UCHAR_MAX
,
512 (FLOAT
)src
[0]/UCHAR_MAX
,
513 (FLOAT
)src
[3]/UCHAR_MAX
515 convert_float4(dst
, &src_float4
, type_dst
);
518 case D3DDECLTYPE_UBYTE4
:
520 D3DXVECTOR4 src_float4
= {src
[0], src
[1], src
[2], src
[3]};
521 convert_float4(dst
, &src_float4
, type_dst
);
524 case D3DDECLTYPE_SHORT2
:
526 SHORT
*src_ptr
= (SHORT
*)src
;
527 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], 0.0f
, 1.0f
};
528 convert_float4(dst
, &src_float4
, type_dst
);
531 case D3DDECLTYPE_SHORT4
:
533 SHORT
*src_ptr
= (SHORT
*)src
;
534 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], src_ptr
[2], src_ptr
[3]};
535 convert_float4(dst
, &src_float4
, type_dst
);
538 case D3DDECLTYPE_UBYTE4N
:
540 D3DXVECTOR4 src_float4
=
542 (FLOAT
)src
[0]/UCHAR_MAX
,
543 (FLOAT
)src
[1]/UCHAR_MAX
,
544 (FLOAT
)src
[2]/UCHAR_MAX
,
545 (FLOAT
)src
[3]/UCHAR_MAX
547 convert_float4(dst
, &src_float4
, type_dst
);
550 case D3DDECLTYPE_SHORT2N
:
552 SHORT
*src_ptr
= (SHORT
*)src
;
553 D3DXVECTOR4 src_float4
= {(FLOAT
)src_ptr
[0]/SHRT_MAX
, (FLOAT
)src_ptr
[1]/SHRT_MAX
, 0.0f
, 1.0f
};
554 convert_float4(dst
, &src_float4
, type_dst
);
557 case D3DDECLTYPE_SHORT4N
:
559 SHORT
*src_ptr
= (SHORT
*)src
;
560 D3DXVECTOR4 src_float4
=
562 (FLOAT
)src_ptr
[0]/SHRT_MAX
,
563 (FLOAT
)src_ptr
[1]/SHRT_MAX
,
564 (FLOAT
)src_ptr
[2]/SHRT_MAX
,
565 (FLOAT
)src_ptr
[3]/SHRT_MAX
567 convert_float4(dst
, &src_float4
, type_dst
);
570 case D3DDECLTYPE_FLOAT16_2
:
572 D3DXVECTOR4 src_float4
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
573 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 2);
574 convert_float4(dst
, &src_float4
, type_dst
);
577 case D3DDECLTYPE_FLOAT16_4
:
579 D3DXVECTOR4 src_float4
;
580 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 4);
581 convert_float4(dst
, &src_float4
, type_dst
);
586 FIXME("Conversion of D3DDECLTYPE %d to %d not implemented.\n", type_src
, type_dst
);
591 static INT
get_equivalent_declaration_index(D3DVERTEXELEMENT9 orig_declaration
, D3DVERTEXELEMENT9
*declaration
)
595 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
597 if (orig_declaration
.Usage
== declaration
[i
].Usage
598 && orig_declaration
.UsageIndex
== declaration
[i
].UsageIndex
)
607 static HRESULT
convert_vertex_buffer(ID3DXMesh
*mesh_dst
, ID3DXMesh
*mesh_src
)
610 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
611 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
615 UINT num_vertices
= mesh_src
->lpVtbl
->GetNumVertices(mesh_src
);
616 UINT dst_vertex_size
= mesh_dst
->lpVtbl
->GetNumBytesPerVertex(mesh_dst
);
617 UINT src_vertex_size
= mesh_src
->lpVtbl
->GetNumBytesPerVertex(mesh_src
);
619 hr
= mesh_src
->lpVtbl
->GetDeclaration(mesh_src
, orig_declaration
);
620 if (FAILED(hr
)) return hr
;
621 hr
= mesh_dst
->lpVtbl
->GetDeclaration(mesh_dst
, declaration
);
622 if (FAILED(hr
)) return hr
;
624 hr
= mesh_src
->lpVtbl
->LockVertexBuffer(mesh_src
, D3DLOCK_READONLY
, (void**)&vb_src
);
625 if (FAILED(hr
)) goto cleanup
;
626 hr
= mesh_dst
->lpVtbl
->LockVertexBuffer(mesh_dst
, 0, (void**)&vb_dst
);
627 if (FAILED(hr
)) goto cleanup
;
629 /* Clear all new fields by clearing the entire vertex buffer. */
630 memset(vb_dst
, 0, num_vertices
* dst_vertex_size
);
632 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++)
634 INT eq_idx
= get_equivalent_declaration_index(orig_declaration
[i
], declaration
);
639 for (j
= 0; j
< num_vertices
; j
++)
641 UINT idx_dst
= dst_vertex_size
* j
+ declaration
[eq_idx
].Offset
;
642 UINT idx_src
= src_vertex_size
* j
+ orig_declaration
[i
].Offset
;
643 UINT type_size
= d3dx_decltype_size
[orig_declaration
[i
].Type
];
645 if (orig_declaration
[i
].Type
== declaration
[eq_idx
].Type
)
646 memcpy(&vb_dst
[idx_dst
], &vb_src
[idx_src
], type_size
);
648 convert_component(&vb_dst
[idx_dst
], &vb_src
[idx_src
], declaration
[eq_idx
].Type
, orig_declaration
[i
].Type
);
655 if (vb_dst
) mesh_dst
->lpVtbl
->UnlockVertexBuffer(mesh_dst
);
656 if (vb_src
) mesh_src
->lpVtbl
->UnlockVertexBuffer(mesh_src
);
661 static BOOL
declaration_equals(CONST D3DVERTEXELEMENT9
*declaration1
, CONST D3DVERTEXELEMENT9
*declaration2
)
663 UINT size1
= 0, size2
= 0;
665 /* Find the size of each declaration */
666 while (declaration1
[size1
].Stream
!= 0xff) size1
++;
667 while (declaration2
[size2
].Stream
!= 0xff) size2
++;
669 /* If not same size then they are definitely not equal */
673 /* Check that all components are the same */
674 if (memcmp(declaration1
, declaration2
, size1
*sizeof(*declaration1
)) == 0)
680 static HRESULT WINAPI
ID3DXMeshImpl_CloneMesh(struct ID3DXMesh
*iface
, DWORD options
,
681 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh_out
)
683 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
684 ID3DXMeshImpl
*cloned_this
;
685 ID3DXMesh
*clone_mesh
;
686 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
687 void *data_in
, *data_out
;
690 BOOL same_declaration
;
692 TRACE("(%p)->(%x,%p,%p,%p)\n", This
, options
, declaration
, device
, clone_mesh_out
);
695 return D3DERR_INVALIDCALL
;
697 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
698 if (FAILED(hr
)) return hr
;
700 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
701 declaration
, device
, &clone_mesh
);
702 if (FAILED(hr
)) return hr
;
704 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
705 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
706 same_declaration
= declaration_equals(declaration
, orig_declaration
);
708 if (options
& D3DXMESH_VB_SHARE
) {
709 if (!same_declaration
) {
710 hr
= D3DERR_INVALIDCALL
;
713 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
714 /* FIXME: refactor to avoid creating a new vertex buffer */
715 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
716 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
717 } else if (same_declaration
) {
718 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
719 if (FAILED(hr
)) goto error
;
720 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, 0, &data_out
);
722 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
725 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
726 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
727 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
729 hr
= convert_vertex_buffer(clone_mesh
, iface
);
730 if (FAILED(hr
)) goto error
;
733 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
734 if (FAILED(hr
)) goto error
;
735 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, 0, &data_out
);
737 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
740 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
742 if (options
& D3DXMESH_32BIT
) {
743 for (i
= 0; i
< This
->numfaces
* 3; i
++)
744 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
746 for (i
= 0; i
< This
->numfaces
* 3; i
++)
747 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
750 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
752 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
753 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
755 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
757 if (This
->attrib_table_size
)
759 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
760 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
761 if (!cloned_this
->attrib_table
) {
765 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
768 *clone_mesh_out
= clone_mesh
;
772 IUnknown_Release(clone_mesh
);
776 static HRESULT WINAPI
ID3DXMeshImpl_GetVertexBuffer(struct ID3DXMesh
*iface
,
777 struct IDirect3DVertexBuffer9
**vertex_buffer
)
779 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
781 TRACE("(%p)->(%p)\n", This
, vertex_buffer
);
783 if (vertex_buffer
== NULL
) return D3DERR_INVALIDCALL
;
784 *vertex_buffer
= This
->vertex_buffer
;
785 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
790 static HRESULT WINAPI
ID3DXMeshImpl_GetIndexBuffer(struct ID3DXMesh
*iface
,
791 struct IDirect3DIndexBuffer9
**index_buffer
)
793 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
795 TRACE("(%p)->(%p)\n", This
, index_buffer
);
797 if (index_buffer
== NULL
) return D3DERR_INVALIDCALL
;
798 *index_buffer
= This
->index_buffer
;
799 IDirect3DIndexBuffer9_AddRef(This
->index_buffer
);
804 static HRESULT WINAPI
ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
806 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
808 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
810 return IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, data
, flags
);
813 static HRESULT WINAPI
ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh
*iface
)
815 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
817 TRACE("(%p)\n", This
);
819 return IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
822 static HRESULT WINAPI
ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
824 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
826 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
828 return IDirect3DIndexBuffer9_Lock(This
->index_buffer
, 0, 0, data
, flags
);
831 static HRESULT WINAPI
ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh
*iface
)
833 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
835 TRACE("(%p)\n", This
);
837 return IDirect3DIndexBuffer9_Unlock(This
->index_buffer
);
840 static HRESULT WINAPI
ID3DXMeshImpl_GetAttributeTable(ID3DXMesh
*iface
, D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
842 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
844 TRACE("(%p)->(%p,%p)\n", This
, attrib_table
, attrib_table_size
);
846 if (attrib_table_size
)
847 *attrib_table_size
= This
->attrib_table_size
;
850 CopyMemory(attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*attrib_table
));
865 struct edge_face
*entries
;
868 /* Builds up a map of which face a new edge belongs to. That way the adjacency
869 * of another edge can be looked up. An edge has an adjacent face if there
870 * is an edge going in the opposite direction in the map. For example if the
871 * edge (v1, v2) belongs to face 4, and there is a mapping (v2, v1)->7, then
872 * face 4 and 7 are adjacent.
874 * Each edge might have been replaced with another edge, or none at all. There
875 * is at most one edge to face mapping, i.e. an edge can only belong to one
878 static HRESULT
init_edge_face_map(struct edge_face_map
*edge_face_map
, CONST DWORD
*index_buffer
, CONST DWORD
*point_reps
, CONST 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
, CONST 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
ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
, CONST DWORD
*point_reps
, DWORD
*adjacency
)
950 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
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("(%p)->(%p,%p)\n", This
, 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
,
1051 CONST DWORD face
, CONST DWORD numfaces
)
1053 const unsigned int VERTS_PER_FACE
= 3;
1054 DWORD edge
, opp_edge
;
1055 DWORD face_base
= VERTS_PER_FACE
* face
;
1057 for (edge
= 0; edge
< VERTS_PER_FACE
; edge
++)
1059 DWORD adj_face
= adjacency
[face_base
+ edge
];
1060 DWORD adj_face_base
;
1062 if (adj_face
== -1) /* No adjacent face. */
1064 else if (adj_face
>= numfaces
)
1066 /* This throws exception on Windows */
1067 WARN("Index out of bounds. Got %d expected less than %d.\n",
1068 adj_face
, numfaces
);
1069 return D3DERR_INVALIDCALL
;
1071 adj_face_base
= 3 * adj_face
;
1073 /* Find opposite edge in adjacent face. */
1074 for (opp_edge
= 0; opp_edge
< VERTS_PER_FACE
; opp_edge
++)
1076 DWORD opp_edge_index
= adj_face_base
+ opp_edge
;
1077 if (adjacency
[opp_edge_index
] == face
)
1078 break; /* Found opposite edge. */
1081 /* Replaces vertices in opposite edge with vertices from current edge. */
1082 for (i
= 0; i
< 2; i
++)
1084 DWORD from
= face_base
+ (edge
+ (1 - i
)) % VERTS_PER_FACE
;
1085 DWORD to
= adj_face_base
+ (opp_edge
+ i
) % VERTS_PER_FACE
;
1087 /* Propagate lowest index. */
1088 if (new_indices
[to
] > new_indices
[from
])
1090 new_indices
[to
] = new_indices
[from
];
1091 point_reps
[indices
[to
]] = new_indices
[from
];
1099 static HRESULT WINAPI
ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
, CONST DWORD
*adjacency
, DWORD
*point_reps
)
1104 DWORD
*indices
= NULL
;
1105 WORD
*indices_16bit
= NULL
;
1106 DWORD
*new_indices
= NULL
;
1107 const unsigned int VERTS_PER_FACE
= 3;
1109 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1111 TRACE("(%p)->(%p,%p)\n", This
, adjacency
, point_reps
);
1115 WARN("NULL adjacency.\n");
1116 hr
= D3DERR_INVALIDCALL
;
1122 WARN("NULL point_reps.\n");
1123 hr
= D3DERR_INVALIDCALL
;
1127 /* Should never happen as CreateMesh does not allow meshes with 0 faces */
1128 if (This
->numfaces
== 0)
1130 ERR("Number of faces was zero.\n");
1131 hr
= D3DERR_INVALIDCALL
;
1135 new_indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1142 if (This
->options
& D3DXMESH_32BIT
)
1144 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1145 if (FAILED(hr
)) goto cleanup
;
1146 memcpy(new_indices
, indices
, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1150 /* Make a widening copy of indices_16bit into indices and new_indices
1151 * in order to re-use the helper function */
1152 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices_16bit
);
1153 if (FAILED(hr
)) goto cleanup
;
1154 indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1160 for (i
= 0; i
< VERTS_PER_FACE
* This
->numfaces
; i
++)
1162 new_indices
[i
] = indices_16bit
[i
];
1163 indices
[i
] = indices_16bit
[i
];
1167 /* Vertices are ordered sequentially in the point representation. */
1168 for (i
= 0; i
< This
->numvertices
; i
++)
1173 /* Propagate vertices with low indices so as few vertices as possible
1174 * are used in the mesh.
1176 for (face
= 0; face
< This
->numfaces
; face
++)
1178 hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
, face
, This
->numfaces
);
1179 if (FAILED(hr
)) goto cleanup
;
1181 /* Go in opposite direction to catch all face orderings */
1182 for (face
= 0; face
< This
->numfaces
; face
++)
1184 hr
= propagate_face_vertices(adjacency
, point_reps
,
1185 indices
, new_indices
,
1186 (This
->numfaces
- 1) - face
, This
->numfaces
);
1187 if (FAILED(hr
)) goto cleanup
;
1192 if (This
->options
& D3DXMESH_32BIT
)
1194 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1198 if (indices_16bit
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1199 HeapFree(GetProcessHeap(), 0, indices
);
1201 HeapFree(GetProcessHeap(), 0, new_indices
);
1205 struct vertex_metadata
{
1208 DWORD first_shared_index
;
1211 static int compare_vertex_keys(const void *a
, const void *b
)
1213 const struct vertex_metadata
*left
= a
;
1214 const struct vertex_metadata
*right
= b
;
1215 if (left
->key
== right
->key
)
1217 return left
->key
< right
->key
? -1 : 1;
1220 static HRESULT WINAPI
ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh
*iface
, FLOAT epsilon
, DWORD
*adjacency
)
1222 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1224 BYTE
*vertices
= NULL
;
1225 const DWORD
*indices
= NULL
;
1228 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
1229 struct vertex_metadata
*sorted_vertices
;
1230 /* shared_indices links together identical indices in the index buffer so
1231 * that adjacency checks can be limited to faces sharing a vertex */
1232 DWORD
*shared_indices
= NULL
;
1233 const FLOAT epsilon_sq
= epsilon
* epsilon
;
1236 TRACE("(%p)->(%f,%p)\n", This
, epsilon
, adjacency
);
1239 return D3DERR_INVALIDCALL
;
1241 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
1242 if (!(This
->options
& D3DXMESH_32BIT
))
1243 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
1244 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
1245 if (!shared_indices
)
1246 return E_OUTOFMEMORY
;
1247 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
1249 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
1250 if (FAILED(hr
)) goto cleanup
;
1251 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1252 if (FAILED(hr
)) goto cleanup
;
1254 if (!(This
->options
& D3DXMESH_32BIT
)) {
1255 const WORD
*word_indices
= (const WORD
*)indices
;
1256 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
1257 indices
= dword_indices
;
1258 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1259 *dword_indices
++ = *word_indices
++;
1262 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1263 for (i
= 0; i
< This
->numvertices
; i
++) {
1264 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
1265 sorted_vertices
[i
].first_shared_index
= -1;
1266 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
1267 sorted_vertices
[i
].vertex_index
= i
;
1269 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
1270 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
1271 shared_indices
[i
] = *first_shared_index
;
1272 *first_shared_index
= i
;
1275 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
1277 for (i
= 0; i
< This
->numvertices
; i
++) {
1278 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
1279 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
1280 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
1282 while (shared_index_a
!= -1) {
1284 DWORD shared_index_b
= shared_indices
[shared_index_a
];
1285 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
1288 while (shared_index_b
!= -1) {
1289 /* faces are adjacent if they have another coincident vertex */
1290 DWORD base_a
= (shared_index_a
/ 3) * 3;
1291 DWORD base_b
= (shared_index_b
/ 3) * 3;
1292 BOOL adjacent
= FALSE
;
1295 for (k
= 0; k
< 3; k
++) {
1296 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
1302 for (k
= 1; k
<= 2; k
++) {
1303 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
1304 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
1305 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
1306 if (!adjacent
&& epsilon
>= 0.0f
) {
1307 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
1310 D3DXVec3Subtract(&delta
,
1311 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
1312 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
1313 length_sq
= D3DXVec3LengthSq(&delta
);
1314 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
1317 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
1318 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
1319 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
1320 adjacency
[adj_a
] = base_b
/ 3;
1321 adjacency
[adj_b
] = base_a
/ 3;
1328 shared_index_b
= shared_indices
[shared_index_b
];
1330 while (++j
< This
->numvertices
) {
1331 D3DXVECTOR3
*vertex_b
;
1334 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
1335 /* no more coincident vertices to try */
1336 j
= This
->numvertices
;
1339 /* check for coincidence */
1340 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
1341 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
1342 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
1343 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
1348 if (j
>= This
->numvertices
)
1350 shared_index_b
= sorted_vertex_b
->first_shared_index
;
1353 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
1354 shared_index_a
= sorted_vertex_a
->first_shared_index
;
1360 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1361 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
1362 HeapFree(GetProcessHeap(), 0, shared_indices
);
1366 static HRESULT WINAPI
ID3DXMeshImpl_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1369 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1370 UINT vertex_declaration_size
;
1373 TRACE("(%p)->(%p)\n", This
, declaration
);
1377 WARN("Invalid declaration. Can't use NULL declaration.\n");
1378 return D3DERR_INVALIDCALL
;
1381 /* New declaration must be same size as original */
1382 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
1383 if (vertex_declaration_size
!= This
->vertex_declaration_size
)
1385 WARN("Invalid declaration. New vertex size does not match the original vertex size.\n");
1386 return D3DERR_INVALIDCALL
;
1389 /* New declaration must not contain non-zero Stream value */
1390 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1392 if (declaration
[i
].Stream
!= 0)
1394 WARN("Invalid declaration. New declaration contains non-zero Stream value.\n");
1395 return D3DERR_INVALIDCALL
;
1399 This
->num_elem
= i
+ 1;
1400 copy_declaration(This
->cached_declaration
, declaration
, This
->num_elem
);
1402 if (This
->vertex_declaration
)
1403 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
1405 /* An application can pass an invalid declaration to UpdateSemantics and
1406 * still expect D3D_OK (see tests). If the declaration is invalid, then
1407 * subsequent calls to DrawSubset will fail. This is handled by setting the
1408 * vertex declaration to NULL.
1409 * GetDeclaration, GetNumBytesPerVertex must, however, use the new
1410 * invalid declaration. This is handled by them using the cached vertex
1411 * declaration instead of the actual vertex declaration.
1413 hr
= IDirect3DDevice9_CreateVertexDeclaration(This
->device
,
1415 &This
->vertex_declaration
);
1418 WARN("Using invalid declaration. Calls to DrawSubset will fail.\n");
1419 This
->vertex_declaration
= NULL
;
1426 static HRESULT WINAPI
ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
1428 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1430 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
1432 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
1434 if (!(flags
& D3DLOCK_READONLY
)) {
1435 D3DXATTRIBUTERANGE
*attrib_table
= This
->attrib_table
;
1436 This
->attrib_table_size
= 0;
1437 This
->attrib_table
= NULL
;
1438 HeapFree(GetProcessHeap(), 0, attrib_table
);
1441 *data
= This
->attrib_buffer
;
1446 static HRESULT WINAPI
ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh
*iface
)
1448 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1451 TRACE("(%p)\n", This
);
1453 lock_count
= InterlockedDecrement(&This
->attrib_buffer_lock_count
);
1455 if (lock_count
< 0) {
1456 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
1457 return D3DERR_INVALIDCALL
;
1463 static HRESULT WINAPI
ID3DXMeshImpl_Optimize(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1464 DWORD
*adjacency_out
, DWORD
*face_remap
, ID3DXBuffer
**vertex_remap
, ID3DXMesh
**opt_mesh
)
1466 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1468 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
1469 ID3DXMesh
*optimized_mesh
;
1471 TRACE("(%p)->(%x,%p,%p,%p,%p,%p)\n", This
, 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 hr
= iface
->lpVtbl
->CloneMesh(iface
, This
->options
, declaration
, This
->device
, &optimized_mesh
);
1480 if (FAILED(hr
)) return hr
;
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(ID3DXMeshImpl
*This
, DWORD
*indices
, DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
1495 DWORD
*vertex_remap_ptr
;
1496 DWORD num_used_vertices
;
1499 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
1500 if (FAILED(hr
)) return hr
;
1501 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
1503 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1504 vertex_remap_ptr
[indices
[i
]] = 1;
1506 /* create old->new vertex mapping */
1507 num_used_vertices
= 0;
1508 for (i
= 0; i
< This
->numvertices
; i
++) {
1509 if (vertex_remap_ptr
[i
])
1510 vertex_remap_ptr
[i
] = num_used_vertices
++;
1512 vertex_remap_ptr
[i
] = -1;
1514 /* convert indices */
1515 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1516 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
1518 /* create new->old vertex mapping */
1519 num_used_vertices
= 0;
1520 for (i
= 0; i
< This
->numvertices
; i
++) {
1521 if (vertex_remap_ptr
[i
] != -1)
1522 vertex_remap_ptr
[num_used_vertices
++] = i
;
1524 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
1525 vertex_remap_ptr
[i
] = -1;
1527 *new_num_vertices
= num_used_vertices
;
1532 /* count the number of unique attribute values in a sorted attribute buffer */
1533 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
1535 DWORD last_attribute
= attrib_buffer
[0];
1536 DWORD attrib_table_size
= 1;
1538 for (i
= 1; i
< numfaces
; i
++) {
1539 if (attrib_buffer
[i
] != last_attribute
) {
1540 last_attribute
= attrib_buffer
[i
];
1541 attrib_table_size
++;
1544 return attrib_table_size
;
1547 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
1548 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
1550 DWORD attrib_table_size
= 0;
1551 DWORD last_attribute
= attrib_buffer
[0];
1552 DWORD min_vertex
, max_vertex
;
1555 attrib_table
[0].AttribId
= last_attribute
;
1556 attrib_table
[0].FaceStart
= 0;
1557 min_vertex
= (DWORD
)-1;
1559 for (i
= 0; i
< numfaces
; i
++) {
1562 if (attrib_buffer
[i
] != last_attribute
) {
1563 last_attribute
= attrib_buffer
[i
];
1564 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1565 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1566 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1567 attrib_table_size
++;
1568 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
1569 attrib_table
[attrib_table_size
].FaceStart
= i
;
1570 min_vertex
= (DWORD
)-1;
1573 for (j
= 0; j
< 3; j
++) {
1574 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
1575 if (vertex_index
< min_vertex
)
1576 min_vertex
= vertex_index
;
1577 if (vertex_index
> max_vertex
)
1578 max_vertex
= vertex_index
;
1581 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1582 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1583 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1584 attrib_table_size
++;
1587 static int attrib_entry_compare(const DWORD
**a
, const DWORD
**b
)
1589 const DWORD
*ptr_a
= *a
;
1590 const DWORD
*ptr_b
= *b
;
1591 int delta
= *ptr_a
- *ptr_b
;
1596 delta
= ptr_a
- ptr_b
; /* for stable sort */
1600 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
1601 static HRESULT
remap_faces_for_attrsort(ID3DXMeshImpl
*This
, const DWORD
*indices
,
1602 const DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
1604 const DWORD
**sorted_attrib_ptr_buffer
= NULL
;
1607 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
1608 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
1609 if (!*face_remap
|| !sorted_attrib_ptr_buffer
) {
1610 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
1611 return E_OUTOFMEMORY
;
1613 for (i
= 0; i
< This
->numfaces
; i
++)
1614 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
1615 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
),
1616 (int(*)(const void *, const void *))attrib_entry_compare
);
1618 for (i
= 0; i
< This
->numfaces
; i
++)
1620 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
1621 (*face_remap
)[old_face
] = i
;
1624 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
1625 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
1626 for (i
= 0; i
< This
->numfaces
; i
++)
1627 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
1632 static HRESULT WINAPI
ID3DXMeshImpl_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1633 DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
1635 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1636 void *indices
= NULL
;
1637 DWORD
*attrib_buffer
= NULL
;
1639 ID3DXBuffer
*vertex_remap
= NULL
;
1640 DWORD
*face_remap
= NULL
; /* old -> new mapping */
1641 DWORD
*dword_indices
= NULL
;
1642 DWORD new_num_vertices
= 0;
1643 DWORD new_num_alloc_vertices
= 0;
1644 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
1645 DWORD
*sorted_attrib_buffer
= NULL
;
1648 TRACE("(%p)->(%x,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
1651 return D3DERR_INVALIDCALL
;
1652 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
1653 return D3DERR_INVALIDCALL
;
1654 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1655 return D3DERR_INVALIDCALL
;
1657 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1659 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
1660 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
1661 if (flags
& D3DXMESHOPT_STRIPREORDER
)
1662 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
1666 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, &indices
);
1667 if (FAILED(hr
)) goto cleanup
;
1669 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
1670 if (!dword_indices
) return E_OUTOFMEMORY
;
1671 if (This
->options
& D3DXMESH_32BIT
) {
1672 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1674 WORD
*word_indices
= indices
;
1675 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1676 dword_indices
[i
] = *word_indices
++;
1679 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
1681 new_num_alloc_vertices
= This
->numvertices
;
1682 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
1683 if (FAILED(hr
)) goto cleanup
;
1684 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
1685 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
1687 FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
1692 hr
= iface
->lpVtbl
->LockAttributeBuffer(iface
, 0, &attrib_buffer
);
1693 if (FAILED(hr
)) goto cleanup
;
1695 hr
= remap_faces_for_attrsort(This
, dword_indices
, attrib_buffer
, &sorted_attrib_buffer
, &face_remap
);
1696 if (FAILED(hr
)) goto cleanup
;
1701 /* reorder the vertices using vertex_remap */
1702 D3DVERTEXBUFFER_DESC vertex_desc
;
1703 DWORD
*vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1704 DWORD vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1705 BYTE
*orig_vertices
;
1708 hr
= IDirect3DVertexBuffer9_GetDesc(This
->vertex_buffer
, &vertex_desc
);
1709 if (FAILED(hr
)) goto cleanup
;
1711 hr
= IDirect3DDevice9_CreateVertexBuffer(This
->device
, new_num_alloc_vertices
* vertex_size
,
1712 vertex_desc
.Usage
, This
->fvf
, vertex_desc
.Pool
, &vertex_buffer
, NULL
);
1713 if (FAILED(hr
)) goto cleanup
;
1715 hr
= IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, (void**)&orig_vertices
, D3DLOCK_READONLY
);
1716 if (FAILED(hr
)) goto cleanup
;
1718 hr
= IDirect3DVertexBuffer9_Lock(vertex_buffer
, 0, 0, (void**)&new_vertices
, 0);
1720 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1724 for (i
= 0; i
< new_num_vertices
; i
++)
1725 memcpy(new_vertices
+ i
* vertex_size
, orig_vertices
+ vertex_remap_ptr
[i
] * vertex_size
, vertex_size
);
1727 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1728 IDirect3DVertexBuffer9_Unlock(vertex_buffer
);
1729 } else if (vertex_remap_out
) {
1730 DWORD
*vertex_remap_ptr
;
1732 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), &vertex_remap
);
1733 if (FAILED(hr
)) goto cleanup
;
1734 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1735 for (i
= 0; i
< This
->numvertices
; i
++)
1736 *vertex_remap_ptr
++ = i
;
1739 if (flags
& D3DXMESHOPT_ATTRSORT
)
1741 D3DXATTRIBUTERANGE
*attrib_table
;
1742 DWORD attrib_table_size
;
1744 attrib_table_size
= count_attributes(sorted_attrib_buffer
, This
->numfaces
);
1745 attrib_table
= HeapAlloc(GetProcessHeap(), 0, attrib_table_size
* sizeof(*attrib_table
));
1746 if (!attrib_table
) {
1751 memcpy(attrib_buffer
, sorted_attrib_buffer
, This
->numfaces
* sizeof(*attrib_buffer
));
1753 /* reorder the indices using face_remap */
1754 if (This
->options
& D3DXMESH_32BIT
) {
1755 for (i
= 0; i
< This
->numfaces
; i
++)
1756 memcpy((DWORD
*)indices
+ face_remap
[i
] * 3, dword_indices
+ i
* 3, 3 * sizeof(DWORD
));
1758 WORD
*word_indices
= indices
;
1759 for (i
= 0; i
< This
->numfaces
; i
++) {
1760 DWORD new_pos
= face_remap
[i
] * 3;
1761 DWORD old_pos
= i
* 3;
1762 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1763 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1764 word_indices
[new_pos
] = dword_indices
[old_pos
];
1768 fill_attribute_table(attrib_buffer
, This
->numfaces
, indices
,
1769 This
->options
& D3DXMESH_32BIT
, attrib_table
);
1771 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1772 This
->attrib_table
= attrib_table
;
1773 This
->attrib_table_size
= attrib_table_size
;
1775 if (This
->options
& D3DXMESH_32BIT
) {
1776 memcpy(indices
, dword_indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1778 WORD
*word_indices
= indices
;
1779 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1780 *word_indices
++ = dword_indices
[i
];
1784 if (adjacency_out
) {
1786 for (i
= 0; i
< This
->numfaces
; i
++) {
1787 DWORD old_pos
= i
* 3;
1788 DWORD new_pos
= face_remap
[i
] * 3;
1789 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1790 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1791 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1794 memcpy(adjacency_out
, adjacency_in
, This
->numfaces
* 3 * sizeof(*adjacency_out
));
1797 if (face_remap_out
) {
1799 for (i
= 0; i
< This
->numfaces
; i
++)
1800 face_remap_out
[face_remap
[i
]] = i
;
1802 for (i
= 0; i
< This
->numfaces
; i
++)
1803 face_remap_out
[i
] = i
;
1806 if (vertex_remap_out
)
1807 *vertex_remap_out
= vertex_remap
;
1808 vertex_remap
= NULL
;
1810 if (vertex_buffer
) {
1811 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
1812 This
->vertex_buffer
= vertex_buffer
;
1813 vertex_buffer
= NULL
;
1814 This
->numvertices
= new_num_vertices
;
1819 HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer
);
1820 HeapFree(GetProcessHeap(), 0, face_remap
);
1821 HeapFree(GetProcessHeap(), 0, dword_indices
);
1822 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
1823 if (vertex_buffer
) IDirect3DVertexBuffer9_Release(vertex_buffer
);
1824 if (attrib_buffer
) iface
->lpVtbl
->UnlockAttributeBuffer(iface
);
1825 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1829 static HRESULT WINAPI
ID3DXMeshImpl_SetAttributeTable(ID3DXMesh
*iface
, CONST D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
1831 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1832 D3DXATTRIBUTERANGE
*new_table
= NULL
;
1834 TRACE("(%p)->(%p,%u)\n", This
, attrib_table
, attrib_table_size
);
1836 if (attrib_table_size
) {
1837 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
1839 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
1841 return E_OUTOFMEMORY
;
1843 CopyMemory(new_table
, attrib_table
, size
);
1844 } else if (attrib_table
) {
1845 return D3DERR_INVALIDCALL
;
1847 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1848 This
->attrib_table
= new_table
;
1849 This
->attrib_table_size
= attrib_table_size
;
1854 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
1856 /*** IUnknown methods ***/
1857 ID3DXMeshImpl_QueryInterface
,
1858 ID3DXMeshImpl_AddRef
,
1859 ID3DXMeshImpl_Release
,
1860 /*** ID3DXBaseMesh ***/
1861 ID3DXMeshImpl_DrawSubset
,
1862 ID3DXMeshImpl_GetNumFaces
,
1863 ID3DXMeshImpl_GetNumVertices
,
1864 ID3DXMeshImpl_GetFVF
,
1865 ID3DXMeshImpl_GetDeclaration
,
1866 ID3DXMeshImpl_GetNumBytesPerVertex
,
1867 ID3DXMeshImpl_GetOptions
,
1868 ID3DXMeshImpl_GetDevice
,
1869 ID3DXMeshImpl_CloneMeshFVF
,
1870 ID3DXMeshImpl_CloneMesh
,
1871 ID3DXMeshImpl_GetVertexBuffer
,
1872 ID3DXMeshImpl_GetIndexBuffer
,
1873 ID3DXMeshImpl_LockVertexBuffer
,
1874 ID3DXMeshImpl_UnlockVertexBuffer
,
1875 ID3DXMeshImpl_LockIndexBuffer
,
1876 ID3DXMeshImpl_UnlockIndexBuffer
,
1877 ID3DXMeshImpl_GetAttributeTable
,
1878 ID3DXMeshImpl_ConvertPointRepsToAdjacency
,
1879 ID3DXMeshImpl_ConvertAdjacencyToPointReps
,
1880 ID3DXMeshImpl_GenerateAdjacency
,
1881 ID3DXMeshImpl_UpdateSemantics
,
1883 ID3DXMeshImpl_LockAttributeBuffer
,
1884 ID3DXMeshImpl_UnlockAttributeBuffer
,
1885 ID3DXMeshImpl_Optimize
,
1886 ID3DXMeshImpl_OptimizeInplace
,
1887 ID3DXMeshImpl_SetAttributeTable
1890 /*************************************************************************
1893 BOOL WINAPI
D3DXBoxBoundProbe(CONST D3DXVECTOR3
*pmin
, CONST D3DXVECTOR3
*pmax
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
1895 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algorithm
1896 Amy Williams University of Utah
1897 Steve Barrus University of Utah
1898 R. Keith Morley University of Utah
1899 Peter Shirley University of Utah
1901 International Conference on Computer Graphics and Interactive Techniques archive
1902 ACM SIGGRAPH 2005 Courses
1903 Los Angeles, California
1905 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1907 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1908 against each slab, if there's anything left of the ray after we're
1909 done we've got an intersection of the ray with the box.
1913 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
1915 div
= 1.0f
/ praydirection
->x
;
1918 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
1919 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
1923 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
1924 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
1927 if ( tmax
< 0.0f
) return FALSE
;
1929 div
= 1.0f
/ praydirection
->y
;
1932 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
1933 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
1937 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
1938 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
1941 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
1943 if ( tymin
> tmin
) tmin
= tymin
;
1944 if ( tymax
< tmax
) tmax
= tymax
;
1946 div
= 1.0f
/ praydirection
->z
;
1949 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
1950 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
1954 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
1955 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
1958 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
1963 /*************************************************************************
1964 * D3DXComputeBoundingBox
1966 HRESULT WINAPI
D3DXComputeBoundingBox(CONST D3DXVECTOR3
*pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
1971 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
1973 *pmin
= *pfirstposition
;
1976 for(i
=0; i
<numvertices
; i
++)
1978 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
1980 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
1981 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
1983 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
1984 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
1986 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
1987 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
1993 /*************************************************************************
1994 * D3DXComputeBoundingSphere
1996 HRESULT WINAPI
D3DXComputeBoundingSphere(CONST D3DXVECTOR3
* pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, FLOAT
*pradius
)
2002 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
2009 for(i
=0; i
<numvertices
; i
++)
2010 D3DXVec3Add(&temp
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
2012 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/ numvertices
);
2014 for(i
=0; i
<numvertices
; i
++)
2016 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
2017 if ( d
> *pradius
) *pradius
= d
;
2022 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
2023 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
2025 declaration
[*idx
].Stream
= 0;
2026 declaration
[*idx
].Offset
= *offset
;
2027 declaration
[*idx
].Type
= type
;
2028 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
2029 declaration
[*idx
].Usage
= usage
;
2030 declaration
[*idx
].UsageIndex
= usage_idx
;
2032 *offset
+= d3dx_decltype_size
[type
];
2036 /*************************************************************************
2037 * D3DXDeclaratorFromFVF
2039 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
2041 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
2042 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2043 unsigned int offset
= 0;
2044 unsigned int idx
= 0;
2047 TRACE("fvf %#x, declaration %p.\n", fvf
, declaration
);
2049 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
2051 if (fvf
& D3DFVF_POSITION_MASK
)
2053 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
2054 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
2055 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
2057 if (has_blend_idx
) --blend_count
;
2059 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
2060 || (has_blend
&& blend_count
> 4))
2061 return D3DERR_INVALIDCALL
;
2063 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
2064 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
2066 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
2070 switch (blend_count
)
2075 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2078 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2081 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2084 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2087 ERR("Invalid blend count %u.\n", blend_count
);
2093 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
2094 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
2095 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
2096 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
2101 if (fvf
& D3DFVF_NORMAL
)
2102 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
2103 if (fvf
& D3DFVF_PSIZE
)
2104 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
2105 if (fvf
& D3DFVF_DIFFUSE
)
2106 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
2107 if (fvf
& D3DFVF_SPECULAR
)
2108 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
2110 for (i
= 0; i
< tex_count
; ++i
)
2112 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
2114 case D3DFVF_TEXTUREFORMAT1
:
2115 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
2117 case D3DFVF_TEXTUREFORMAT2
:
2118 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
2120 case D3DFVF_TEXTUREFORMAT3
:
2121 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
2123 case D3DFVF_TEXTUREFORMAT4
:
2124 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
2129 declaration
[idx
] = end_element
;
2134 /*************************************************************************
2135 * D3DXFVFFromDeclarator
2137 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
2139 unsigned int i
= 0, texture
, offset
;
2141 TRACE("(%p, %p)\n", declaration
, fvf
);
2144 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
2146 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2147 declaration
[1].UsageIndex
== 0) &&
2148 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
2149 declaration
[2].UsageIndex
== 0))
2151 return D3DERR_INVALIDCALL
;
2153 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2154 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
2156 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
2158 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
2162 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
2166 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2167 declaration
[1].UsageIndex
== 0)
2169 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2170 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
2172 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
2174 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
2178 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
2180 switch (declaration
[1].Type
)
2182 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
2183 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
2184 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
2185 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
2191 switch (declaration
[1].Type
)
2193 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
2194 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
2195 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
2196 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
2207 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
2208 declaration
[0].UsageIndex
== 0)
2210 *fvf
|= D3DFVF_XYZRHW
;
2214 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
2216 *fvf
|= D3DFVF_NORMAL
;
2219 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
2220 declaration
[i
].UsageIndex
== 0)
2222 *fvf
|= D3DFVF_PSIZE
;
2225 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2226 declaration
[i
].UsageIndex
== 0)
2228 *fvf
|= D3DFVF_DIFFUSE
;
2231 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2232 declaration
[i
].UsageIndex
== 1)
2234 *fvf
|= D3DFVF_SPECULAR
;
2238 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
2240 if (declaration
[i
].Stream
== 0xFF)
2244 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2245 declaration
[i
].UsageIndex
== texture
)
2247 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
2249 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2250 declaration
[i
].UsageIndex
== texture
)
2252 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
2254 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2255 declaration
[i
].UsageIndex
== texture
)
2257 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
2259 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2260 declaration
[i
].UsageIndex
== texture
)
2262 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
2266 return D3DERR_INVALIDCALL
;
2270 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
2272 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
2273 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
2275 if (declaration
[i
].Offset
!= offset
)
2277 return D3DERR_INVALIDCALL
;
2284 /*************************************************************************
2285 * D3DXGetFVFVertexSize
2287 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
2289 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
2292 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
2296 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2298 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
2299 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
2300 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
2301 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
2303 switch (FVF
& D3DFVF_POSITION_MASK
)
2305 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
2306 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
2307 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
2308 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
2309 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
2310 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
2311 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
2312 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
2315 for (i
= 0; i
< numTextures
; i
++)
2317 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
2323 /*************************************************************************
2324 * D3DXGetDeclVertexSize
2326 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
2328 const D3DVERTEXELEMENT9
*element
;
2331 TRACE("decl %p, stream_idx %u\n", decl
, stream_idx
);
2333 if (!decl
) return 0;
2335 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
2339 if (element
->Stream
!= stream_idx
) continue;
2341 if (element
->Type
>= sizeof(d3dx_decltype_size
) / sizeof(*d3dx_decltype_size
))
2343 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
2347 type_size
= d3dx_decltype_size
[element
->Type
];
2348 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
2354 /*************************************************************************
2357 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
2359 const D3DVERTEXELEMENT9
*element
;
2361 TRACE("decl %p\n", decl
);
2363 /* null decl results in exception on Windows XP */
2365 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
2367 return element
- decl
;
2370 /*************************************************************************
2373 BOOL WINAPI
D3DXIntersectTri(CONST D3DXVECTOR3
*p0
, CONST D3DXVECTOR3
*p1
, CONST D3DXVECTOR3
*p2
, CONST D3DXVECTOR3
*praypos
, CONST D3DXVECTOR3
*praydir
, FLOAT
*pu
, FLOAT
*pv
, FLOAT
*pdist
)
2378 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
2379 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
2380 m
.u
.m
[2][0] = -praydir
->x
;
2382 m
.u
.m
[0][1] = p1
->y
- p0
->z
;
2383 m
.u
.m
[1][1] = p2
->y
- p0
->z
;
2384 m
.u
.m
[2][1] = -praydir
->y
;
2386 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
2387 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
2388 m
.u
.m
[2][2] = -praydir
->z
;
2395 vec
.x
= praypos
->x
- p0
->x
;
2396 vec
.y
= praypos
->y
- p0
->y
;
2397 vec
.z
= praypos
->z
- p0
->z
;
2400 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
2402 D3DXVec4Transform(&vec
, &vec
, &m
);
2403 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
2407 *pdist
= fabs( vec
.z
);
2415 /*************************************************************************
2416 * D3DXSphereBoundProbe
2418 BOOL WINAPI
D3DXSphereBoundProbe(CONST D3DXVECTOR3
*pcenter
, FLOAT radius
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
2420 D3DXVECTOR3 difference
;
2423 a
= D3DXVec3LengthSq(praydirection
);
2424 if (!D3DXVec3Subtract(&difference
, prayposition
, pcenter
)) return FALSE
;
2425 b
= D3DXVec3Dot(&difference
, praydirection
);
2426 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
2429 if ( ( d
<= 0.0f
) || ( sqrt(d
) <= b
) ) return FALSE
;
2433 /*************************************************************************
2436 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2437 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2441 IDirect3DVertexDeclaration9
*vertex_declaration
;
2442 UINT vertex_declaration_size
;
2444 IDirect3DVertexBuffer9
*vertex_buffer
;
2445 IDirect3DIndexBuffer9
*index_buffer
;
2446 DWORD
*attrib_buffer
;
2447 ID3DXMeshImpl
*object
;
2448 DWORD index_usage
= 0;
2449 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
2450 D3DFORMAT index_format
= D3DFMT_INDEX16
;
2451 DWORD vertex_usage
= 0;
2452 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
2455 TRACE("(%d, %d, %x, %p, %p, %p)\n", numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2457 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
2458 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
2459 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
2461 return D3DERR_INVALIDCALL
;
2463 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
2464 if (declaration
[i
].Stream
!= 0)
2465 return D3DERR_INVALIDCALL
;
2468 if (options
& D3DXMESH_32BIT
)
2469 index_format
= D3DFMT_INDEX32
;
2471 if (options
& D3DXMESH_DONOTCLIP
) {
2472 index_usage
|= D3DUSAGE_DONOTCLIP
;
2473 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
2475 if (options
& D3DXMESH_POINTS
) {
2476 index_usage
|= D3DUSAGE_POINTS
;
2477 vertex_usage
|= D3DUSAGE_POINTS
;
2479 if (options
& D3DXMESH_RTPATCHES
) {
2480 index_usage
|= D3DUSAGE_RTPATCHES
;
2481 vertex_usage
|= D3DUSAGE_RTPATCHES
;
2483 if (options
& D3DXMESH_NPATCHES
) {
2484 index_usage
|= D3DUSAGE_NPATCHES
;
2485 vertex_usage
|= D3DUSAGE_NPATCHES
;
2488 if (options
& D3DXMESH_VB_SYSTEMMEM
)
2489 vertex_pool
= D3DPOOL_SYSTEMMEM
;
2490 else if (options
& D3DXMESH_VB_MANAGED
)
2491 vertex_pool
= D3DPOOL_MANAGED
;
2493 if (options
& D3DXMESH_VB_WRITEONLY
)
2494 vertex_usage
|= D3DUSAGE_WRITEONLY
;
2495 if (options
& D3DXMESH_VB_DYNAMIC
)
2496 vertex_usage
|= D3DUSAGE_DYNAMIC
;
2497 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
2498 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2500 if (options
& D3DXMESH_IB_SYSTEMMEM
)
2501 index_pool
= D3DPOOL_SYSTEMMEM
;
2502 else if (options
& D3DXMESH_IB_MANAGED
)
2503 index_pool
= D3DPOOL_MANAGED
;
2505 if (options
& D3DXMESH_IB_WRITEONLY
)
2506 index_usage
|= D3DUSAGE_WRITEONLY
;
2507 if (options
& D3DXMESH_IB_DYNAMIC
)
2508 index_usage
|= D3DUSAGE_DYNAMIC
;
2509 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
2510 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2512 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
2518 /* Create vertex declaration */
2519 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
2521 &vertex_declaration
);
2524 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
2527 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
2529 /* Create vertex buffer */
2530 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
2531 numvertices
* vertex_declaration_size
,
2539 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2540 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2544 /* Create index buffer */
2545 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
2546 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
2554 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2555 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2556 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2560 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
2561 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ID3DXMeshImpl
));
2562 if (object
== NULL
|| attrib_buffer
== NULL
)
2564 HeapFree(GetProcessHeap(), 0, object
);
2565 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
2566 IDirect3DIndexBuffer9_Release(index_buffer
);
2567 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2568 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2570 return E_OUTOFMEMORY
;
2572 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
2575 object
->numfaces
= numfaces
;
2576 object
->numvertices
= numvertices
;
2577 object
->options
= options
;
2579 object
->device
= device
;
2580 IDirect3DDevice9_AddRef(device
);
2582 copy_declaration(object
->cached_declaration
, declaration
, num_elem
);
2583 object
->vertex_declaration
= vertex_declaration
;
2584 object
->vertex_declaration_size
= vertex_declaration_size
;
2585 object
->num_elem
= num_elem
;
2586 object
->vertex_buffer
= vertex_buffer
;
2587 object
->index_buffer
= index_buffer
;
2588 object
->attrib_buffer
= attrib_buffer
;
2590 *mesh
= &object
->ID3DXMesh_iface
;
2595 /*************************************************************************
2598 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2599 DWORD fvf
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2602 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
2604 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
2606 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
2607 if (FAILED(hr
)) return hr
;
2609 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2615 DWORD num_poly_faces
;
2616 DWORD num_tri_faces
;
2617 D3DXVECTOR3
*vertices
;
2618 DWORD
*num_tri_per_face
;
2623 /* optional mesh data */
2626 D3DXVECTOR3
*normals
;
2627 DWORD
*normal_indices
;
2629 D3DXVECTOR2
*tex_coords
;
2631 DWORD
*vertex_colors
;
2633 DWORD num_materials
;
2634 D3DXMATERIAL
*materials
;
2635 DWORD
*material_indices
;
2637 struct ID3DXSkinInfo
*skin_info
;
2641 static HRESULT
parse_texture_filename(ID3DXFileData
*filedata
, LPSTR
*filename_out
)
2647 char *filename
= NULL
;
2649 /* template TextureFilename {
2654 HeapFree(GetProcessHeap(), 0, *filename_out
);
2655 *filename_out
= NULL
;
2657 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2658 if (FAILED(hr
)) return hr
;
2660 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
2661 if (data_size
< sizeof(LPSTR
)) {
2662 WARN("truncated data (%lu bytes)\n", data_size
);
2663 filedata
->lpVtbl
->Unlock(filedata
);
2666 filename_in
= *(LPSTR
*)data
;
2668 filename
= HeapAlloc(GetProcessHeap(), 0, strlen(filename_in
) + 1);
2670 filedata
->lpVtbl
->Unlock(filedata
);
2671 return E_OUTOFMEMORY
;
2674 strcpy(filename
, filename_in
);
2675 *filename_out
= filename
;
2677 filedata
->lpVtbl
->Unlock(filedata
);
2682 static HRESULT
parse_material(ID3DXFileData
*filedata
, D3DXMATERIAL
*material
)
2688 ID3DXFileData
*child
;
2692 material
->pTextureFilename
= NULL
;
2694 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2695 if (FAILED(hr
)) return hr
;
2698 * template ColorRGBA {
2704 * template ColorRGB {
2709 * template Material {
2710 * ColorRGBA faceColor;
2712 * ColorRGB specularColor;
2713 * ColorRGB emissiveColor;
2717 if (data_size
!= sizeof(FLOAT
) * 11) {
2718 WARN("incorrect data size (%ld bytes)\n", data_size
);
2719 filedata
->lpVtbl
->Unlock(filedata
);
2723 memcpy(&material
->MatD3D
.Diffuse
, data
, sizeof(D3DCOLORVALUE
));
2724 data
+= sizeof(D3DCOLORVALUE
);
2725 material
->MatD3D
.Power
= *(FLOAT
*)data
;
2726 data
+= sizeof(FLOAT
);
2727 memcpy(&material
->MatD3D
.Specular
, data
, sizeof(FLOAT
) * 3);
2728 material
->MatD3D
.Specular
.a
= 1.0f
;
2729 data
+= 3 * sizeof(FLOAT
);
2730 memcpy(&material
->MatD3D
.Emissive
, data
, sizeof(FLOAT
) * 3);
2731 material
->MatD3D
.Emissive
.a
= 1.0f
;
2732 material
->MatD3D
.Ambient
.r
= 0.0f
;
2733 material
->MatD3D
.Ambient
.g
= 0.0f
;
2734 material
->MatD3D
.Ambient
.b
= 0.0f
;
2735 material
->MatD3D
.Ambient
.a
= 1.0f
;
2737 filedata
->lpVtbl
->Unlock(filedata
);
2739 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2743 for (i
= 0; i
< nb_children
; i
++)
2745 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2748 hr
= child
->lpVtbl
->GetType(child
, &type
);
2752 if (IsEqualGUID(&type
, &TID_D3DRMTextureFilename
)) {
2753 hr
= parse_texture_filename(child
, &material
->pTextureFilename
);
2762 static void destroy_materials(struct mesh_data
*mesh
)
2765 for (i
= 0; i
< mesh
->num_materials
; i
++)
2766 HeapFree(GetProcessHeap(), 0, mesh
->materials
[i
].pTextureFilename
);
2767 HeapFree(GetProcessHeap(), 0, mesh
->materials
);
2768 HeapFree(GetProcessHeap(), 0, mesh
->material_indices
);
2769 mesh
->num_materials
= 0;
2770 mesh
->materials
= NULL
;
2771 mesh
->material_indices
= NULL
;
2774 static HRESULT
parse_material_list(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2778 const DWORD
*data
, *in_ptr
;
2780 ID3DXFileData
*child
;
2781 DWORD num_materials
;
2785 destroy_materials(mesh
);
2787 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2788 if (FAILED(hr
)) return hr
;
2790 /* template MeshMaterialList {
2792 * DWORD nFaceIndexes;
2793 * array DWORD faceIndexes[nFaceIndexes];
2801 if (data_size
< sizeof(DWORD
)) {
2802 WARN("truncated data (%ld bytes)\n", data_size
);
2805 num_materials
= *in_ptr
++;
2806 if (!num_materials
) {
2811 if (data_size
< 2 * sizeof(DWORD
)) {
2812 WARN("truncated data (%ld bytes)\n", data_size
);
2815 if (*in_ptr
++ != mesh
->num_poly_faces
) {
2816 WARN("number of material face indices (%u) doesn't match number of faces (%u)\n",
2817 *(in_ptr
- 1), mesh
->num_poly_faces
);
2820 if (data_size
< 2 * sizeof(DWORD
) + mesh
->num_poly_faces
* sizeof(DWORD
)) {
2821 WARN("truncated data (%ld bytes)\n", data_size
);
2824 for (i
= 0; i
< mesh
->num_poly_faces
; i
++) {
2825 if (*in_ptr
++ >= num_materials
) {
2826 WARN("face %u: reference to undefined material %u (only %u materials)\n",
2827 i
, *(in_ptr
- 1), num_materials
);
2832 mesh
->materials
= HeapAlloc(GetProcessHeap(), 0, num_materials
* sizeof(*mesh
->materials
));
2833 mesh
->material_indices
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_poly_faces
* sizeof(*mesh
->material_indices
));
2834 if (!mesh
->materials
|| !mesh
->material_indices
) {
2838 memcpy(mesh
->material_indices
, data
+ 2, mesh
->num_poly_faces
* sizeof(DWORD
));
2840 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2844 for (i
= 0; i
< nb_children
; i
++)
2846 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2849 hr
= child
->lpVtbl
->GetType(child
, &type
);
2853 if (IsEqualGUID(&type
, &TID_D3DRMMaterial
)) {
2854 if (mesh
->num_materials
>= num_materials
) {
2855 WARN("more materials defined than declared\n");
2859 hr
= parse_material(child
, &mesh
->materials
[mesh
->num_materials
++]);
2864 if (num_materials
!= mesh
->num_materials
) {
2865 WARN("only %u of %u materials defined\n", num_materials
, mesh
->num_materials
);
2870 filedata
->lpVtbl
->Unlock(filedata
);
2874 static HRESULT
parse_texture_coords(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2880 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2881 mesh
->tex_coords
= NULL
;
2883 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2884 if (FAILED(hr
)) return hr
;
2886 /* template Coords2d {
2890 * template MeshTextureCoords {
2891 * DWORD nTextureCoords;
2892 * array Coords2d textureCoords[nTextureCoords];
2898 if (data_size
< sizeof(DWORD
)) {
2899 WARN("truncated data (%ld bytes)\n", data_size
);
2902 if (*(DWORD
*)data
!= mesh
->num_vertices
) {
2903 WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2904 *(DWORD
*)data
, mesh
->num_vertices
);
2907 data
+= sizeof(DWORD
);
2908 if (data_size
< sizeof(DWORD
) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
)) {
2909 WARN("truncated data (%ld bytes)\n", data_size
);
2913 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2914 if (!mesh
->tex_coords
) {
2918 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2920 mesh
->fvf
|= D3DFVF_TEX1
;
2925 filedata
->lpVtbl
->Unlock(filedata
);
2929 static HRESULT
parse_vertex_colors(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2937 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2938 mesh
->vertex_colors
= NULL
;
2940 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2941 if (FAILED(hr
)) return hr
;
2943 /* template IndexedColor {
2945 * ColorRGBA indexColor;
2947 * template MeshVertexColors {
2948 * DWORD nVertexColors;
2949 * array IndexedColor vertexColors[nVertexColors];
2955 if (data_size
< sizeof(DWORD
)) {
2956 WARN("truncated data (%ld bytes)\n", data_size
);
2959 num_colors
= *(DWORD
*)data
;
2960 data
+= sizeof(DWORD
);
2961 if (data_size
< sizeof(DWORD
) + num_colors
* (sizeof(DWORD
) + sizeof(D3DCOLORVALUE
))) {
2962 WARN("truncated data (%ld bytes)\n", data_size
);
2966 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(DWORD
));
2967 if (!mesh
->vertex_colors
) {
2972 for (i
= 0; i
< mesh
->num_vertices
; i
++)
2973 mesh
->vertex_colors
[i
] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2974 for (i
= 0; i
< num_colors
; i
++)
2976 D3DCOLORVALUE color
;
2977 DWORD index
= *(DWORD
*)data
;
2978 data
+= sizeof(DWORD
);
2979 if (index
>= mesh
->num_vertices
) {
2980 WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2981 i
, index
, mesh
->num_vertices
);
2984 memcpy(&color
, data
, sizeof(color
));
2985 data
+= sizeof(color
);
2986 color
.r
= min(1.0f
, max(0.0f
, color
.r
));
2987 color
.g
= min(1.0f
, max(0.0f
, color
.g
));
2988 color
.b
= min(1.0f
, max(0.0f
, color
.b
));
2989 color
.a
= min(1.0f
, max(0.0f
, color
.a
));
2990 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
2991 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
2992 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
2993 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
2996 mesh
->fvf
|= D3DFVF_DIFFUSE
;
3001 filedata
->lpVtbl
->Unlock(filedata
);
3005 static HRESULT
parse_normals(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
3010 DWORD
*index_out_ptr
;
3012 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
3014 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
3015 mesh
->num_normals
= 0;
3016 mesh
->normals
= NULL
;
3017 mesh
->normal_indices
= NULL
;
3018 mesh
->fvf
|= D3DFVF_NORMAL
;
3020 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3021 if (FAILED(hr
)) return hr
;
3023 /* template Vector {
3028 * template MeshFace {
3029 * DWORD nFaceVertexIndices;
3030 * array DWORD faceVertexIndices[nFaceVertexIndices];
3032 * template MeshNormals {
3034 * array Vector normals[nNormals];
3035 * DWORD nFaceNormals;
3036 * array MeshFace faceNormals[nFaceNormals];
3042 if (data_size
< sizeof(DWORD
) * 2) {
3043 WARN("truncated data (%ld bytes)\n", data_size
);
3046 mesh
->num_normals
= *(DWORD
*)data
;
3047 data
+= sizeof(DWORD
);
3048 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
3049 num_face_indices
* sizeof(DWORD
)) {
3050 WARN("truncated data (%ld bytes)\n", data_size
);
3054 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3055 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
3056 if (!mesh
->normals
|| !mesh
->normal_indices
) {
3061 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3062 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
3063 for (i
= 0; i
< mesh
->num_normals
; i
++)
3064 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
3066 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
3067 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
3068 *(DWORD
*)data
, mesh
->num_poly_faces
);
3071 data
+= sizeof(DWORD
);
3072 index_out_ptr
= mesh
->normal_indices
;
3073 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
3076 DWORD count
= *(DWORD
*)data
;
3077 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
3078 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
3079 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
3082 data
+= sizeof(DWORD
);
3084 for (j
= 0; j
< count
; j
++) {
3085 DWORD normal_index
= *(DWORD
*)data
;
3086 if (normal_index
>= mesh
->num_normals
) {
3087 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
3088 i
, j
, normal_index
, mesh
->num_normals
);
3091 *index_out_ptr
++ = normal_index
;
3092 data
+= sizeof(DWORD
);
3099 filedata
->lpVtbl
->Unlock(filedata
);
3103 static HRESULT
parse_skin_mesh_info(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD index
)
3109 TRACE("(%p, %p, %u)\n", filedata
, mesh_data
, index
);
3111 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3112 if (FAILED(hr
)) return hr
;
3116 if (!mesh_data
->skin_info
) {
3117 if (data_size
< sizeof(WORD
) * 3) {
3118 WARN("truncated data (%ld bytes)\n", data_size
);
3121 /* Skip nMaxSkinWeightsPerVertex and nMaxSkinWeightsPerFace */
3122 data
+= 2 * sizeof(WORD
);
3123 mesh_data
->nb_bones
= *(WORD
*)data
;
3124 hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
, mesh_data
->nb_bones
, &mesh_data
->skin_info
);
3127 DWORD nb_influences
;
3129 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
3130 name
= *(const char**)data
;
3131 data
+= sizeof(char*);
3133 nb_influences
= *(DWORD
*)data
;
3134 data
+= sizeof(DWORD
);
3136 if (data_size
< (sizeof(char*) + sizeof(DWORD
) + nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
)) + 16 * sizeof(FLOAT
))) {
3137 WARN("truncated data (%ld bytes)\n", data_size
);
3141 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneName(mesh_data
->skin_info
, index
, name
);
3143 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneInfluence(mesh_data
->skin_info
, index
, nb_influences
,
3144 (const DWORD
*)data
, (const FLOAT
*)(data
+ nb_influences
* sizeof(DWORD
)));
3146 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneOffsetMatrix(mesh_data
->skin_info
, index
,
3147 (const D3DMATRIX
*)(data
+ nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
))));
3151 filedata
->lpVtbl
->Unlock(filedata
);
3155 /* for provide_flags parameters */
3156 #define PROVIDE_MATERIALS 0x1
3157 #define PROVIDE_SKININFO 0x2
3158 #define PROVIDE_ADJACENCY 0x4
3160 static HRESULT
parse_mesh(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
3164 const BYTE
*data
, *in_ptr
;
3165 DWORD
*index_out_ptr
;
3167 ID3DXFileData
*child
;
3170 DWORD nb_skin_weigths_info
= 0;
3175 * array Vector vertices[nVertices];
3177 * array MeshFace faces[nFaces];
3182 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3183 if (FAILED(hr
)) return hr
;
3188 if (data_size
< sizeof(DWORD
) * 2) {
3189 WARN("truncated data (%ld bytes)\n", data_size
);
3192 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
3193 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
)) {
3194 WARN("truncated data (%ld bytes)\n", data_size
);
3197 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
3199 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
3200 in_ptr
+= sizeof(DWORD
);
3202 mesh_data
->num_tri_faces
= 0;
3203 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3205 DWORD num_poly_vertices
;
3208 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
)) {
3209 WARN("truncated data (%ld bytes)\n", data_size
);
3212 num_poly_vertices
= *(DWORD
*)in_ptr
;
3213 in_ptr
+= sizeof(DWORD
);
3214 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
)) {
3215 WARN("truncated data (%ld bytes)\n", data_size
);
3218 if (num_poly_vertices
< 3) {
3219 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
3222 for (j
= 0; j
< num_poly_vertices
; j
++) {
3223 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
3224 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
3225 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
3228 in_ptr
+= sizeof(DWORD
);
3230 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
3233 mesh_data
->fvf
= D3DFVF_XYZ
;
3235 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
3236 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
3237 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
3238 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
3239 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
3240 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
3241 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
) {
3246 in_ptr
= data
+ sizeof(DWORD
);
3247 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
3248 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
3250 index_out_ptr
= mesh_data
->indices
;
3251 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3255 count
= *(DWORD
*)in_ptr
;
3256 in_ptr
+= sizeof(DWORD
);
3257 mesh_data
->num_tri_per_face
[i
] = count
- 2;
3260 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
3261 in_ptr
+= sizeof(DWORD
);
3265 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3269 for (i
= 0; i
< nb_children
; i
++)
3271 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3274 hr
= child
->lpVtbl
->GetType(child
, &type
);
3278 if (IsEqualGUID(&type
, &TID_D3DRMMeshNormals
)) {
3279 hr
= parse_normals(child
, mesh_data
);
3280 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshVertexColors
)) {
3281 hr
= parse_vertex_colors(child
, mesh_data
);
3282 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshTextureCoords
)) {
3283 hr
= parse_texture_coords(child
, mesh_data
);
3284 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3287 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshMaterialList
) &&
3288 (provide_flags
& PROVIDE_MATERIALS
))
3290 hr
= parse_material_list(child
, mesh_data
);
3291 } else if (provide_flags
& PROVIDE_SKININFO
) {
3292 if (IsEqualGUID(&type
, &DXFILEOBJ_XSkinMeshHeader
)) {
3293 if (mesh_data
->skin_info
) {
3294 WARN("Skin mesh header already encountered\n");
3298 hr
= parse_skin_mesh_info(child
, mesh_data
, 0);
3301 } else if (IsEqualGUID(&type
, &DXFILEOBJ_SkinWeights
)) {
3302 if (!mesh_data
->skin_info
) {
3303 WARN("Skin weigths found but skin mesh header not encountered yet\n");
3307 hr
= parse_skin_mesh_info(child
, mesh_data
, nb_skin_weigths_info
);
3310 nb_skin_weigths_info
++;
3317 if (mesh_data
->skin_info
&& (nb_skin_weigths_info
!= mesh_data
->nb_bones
)) {
3318 WARN("Mismatch between nb skin weights info %u encountered and nb bones %u from skin mesh header\n",
3319 nb_skin_weigths_info
, mesh_data
->nb_bones
);
3327 filedata
->lpVtbl
->Unlock(filedata
);
3331 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
3332 ID3DXBuffer
**effects
)
3335 D3DXEFFECTINSTANCE
*effect_ptr
;
3337 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3338 static const struct {
3339 const char *param_name
;
3343 } material_effects
[] = {
3344 #define EFFECT_TABLE_ENTRY(str, field) \
3345 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
3346 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
3347 EFFECT_TABLE_ENTRY("Power", Power
),
3348 EFFECT_TABLE_ENTRY("Specular", Specular
),
3349 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
3350 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
3351 #undef EFFECT_TABLE_ENTRY
3353 static const char texture_paramname
[] = "Texture0@Name";
3357 /* effects buffer layout:
3359 * D3DXEFFECTINSTANCE effects[num_materials];
3360 * for (effect in effects)
3362 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
3363 * for (default in defaults)
3365 * *default.pParamName;
3370 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
3371 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
3372 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
3373 buffer_size
+= material_effects
[i
].name_size
;
3374 buffer_size
+= material_effects
[i
].num_bytes
;
3376 buffer_size
*= num_materials
;
3377 for (i
= 0; i
< num_materials
; i
++) {
3378 if (material_ptr
[i
].pTextureFilename
) {
3379 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
3380 buffer_size
+= sizeof(texture_paramname
);
3381 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
3385 hr
= D3DXCreateBuffer(buffer_size
, effects
);
3386 if (FAILED(hr
)) return hr
;
3387 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
3388 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
3390 for (i
= 0; i
< num_materials
; i
++)
3393 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
3395 effect_ptr
->pDefaults
= defaults
;
3396 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
3397 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
3399 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
3401 defaults
->pParamName
= (LPSTR
)out_ptr
;
3402 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
3403 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
3404 defaults
->Type
= D3DXEDT_FLOATS
;
3405 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
3406 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
3407 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3411 if (material_ptr
->pTextureFilename
) {
3412 defaults
->pParamName
= (LPSTR
)out_ptr
;
3413 strcpy(defaults
->pParamName
, texture_paramname
);
3414 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
3415 defaults
->Type
= D3DXEDT_STRING
;
3416 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
3417 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
3418 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3423 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
3428 HRESULT WINAPI
D3DXLoadSkinMeshFromXof(struct ID3DXFileData
*filedata
, DWORD options
,
3429 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
3430 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXSkinInfo
**skin_info_out
,
3431 struct ID3DXMesh
**mesh_out
)
3434 DWORD
*index_in_ptr
;
3435 struct mesh_data mesh_data
;
3436 DWORD total_vertices
;
3437 ID3DXMesh
*d3dxmesh
= NULL
;
3438 ID3DXBuffer
*adjacency
= NULL
;
3439 ID3DXBuffer
*materials
= NULL
;
3440 ID3DXBuffer
*effects
= NULL
;
3441 struct vertex_duplication
{
3444 } *duplications
= NULL
;
3446 void *vertices
= NULL
;
3447 void *indices
= NULL
;
3449 DWORD provide_flags
= 0;
3451 TRACE("(%p, %x, %p, %p, %p, %p, %p, %p, %p)\n", filedata
, options
, device
, adjacency_out
, materials_out
,
3452 effects_out
, num_materials_out
, skin_info_out
, mesh_out
);
3454 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
3456 if (num_materials_out
|| materials_out
|| effects_out
)
3457 provide_flags
|= PROVIDE_MATERIALS
;
3459 provide_flags
|= PROVIDE_SKININFO
;
3461 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
3462 if (FAILED(hr
)) goto cleanup
;
3464 total_vertices
= mesh_data
.num_vertices
;
3465 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3466 /* duplicate vertices with multiple normals */
3467 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
3468 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
3469 if (!duplications
) {
3473 for (i
= 0; i
< total_vertices
; i
++)
3475 duplications
[i
].normal_index
= -1;
3476 list_init(&duplications
[i
].entry
);
3478 for (i
= 0; i
< num_face_indices
; i
++) {
3479 DWORD vertex_index
= mesh_data
.indices
[i
];
3480 DWORD normal_index
= mesh_data
.normal_indices
[i
];
3481 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
3483 if (dup_ptr
->normal_index
== -1) {
3484 dup_ptr
->normal_index
= normal_index
;
3486 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
3487 struct list
*dup_list
= &dup_ptr
->entry
;
3489 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
3490 if (new_normal
->x
== cur_normal
->x
&&
3491 new_normal
->y
== cur_normal
->y
&&
3492 new_normal
->z
== cur_normal
->z
)
3494 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3496 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
3497 dup_ptr
= &duplications
[total_vertices
++];
3498 dup_ptr
->normal_index
= normal_index
;
3499 list_add_tail(dup_list
, &dup_ptr
->entry
);
3500 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3503 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
3504 struct vertex_duplication
, entry
);
3511 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
3512 if (FAILED(hr
)) goto cleanup
;
3514 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, 0, &vertices
);
3515 if (FAILED(hr
)) goto cleanup
;
3518 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3519 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
3520 out_ptr
+= sizeof(D3DXVECTOR3
);
3521 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3522 if (duplications
[i
].normal_index
== -1)
3523 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
3525 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
3526 out_ptr
+= sizeof(D3DXVECTOR3
);
3528 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
3529 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
3530 out_ptr
+= sizeof(DWORD
);
3532 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
3533 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
3534 out_ptr
+= sizeof(D3DXVECTOR2
);
3537 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3538 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
3540 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3541 struct vertex_duplication
*dup_ptr
;
3542 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
3544 int j
= dup_ptr
- duplications
;
3545 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
3547 memcpy(dest_vertex
, out_ptr
, vertex_size
);
3548 dest_vertex
+= sizeof(D3DXVECTOR3
);
3549 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
3551 out_ptr
+= vertex_size
;
3554 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
3556 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, 0, &indices
);
3557 if (FAILED(hr
)) goto cleanup
;
3559 index_in_ptr
= mesh_data
.indices
;
3560 #define FILL_INDEX_BUFFER(indices_var) \
3561 for (i = 0; i < mesh_data.num_poly_faces; i++) \
3563 DWORD count = mesh_data.num_tri_per_face[i]; \
3564 WORD first_index = *index_in_ptr++; \
3566 *indices_var++ = first_index; \
3567 *indices_var++ = *index_in_ptr; \
3569 *indices_var++ = *index_in_ptr; \
3573 if (options
& D3DXMESH_32BIT
) {
3574 DWORD
*dword_indices
= indices
;
3575 FILL_INDEX_BUFFER(dword_indices
)
3577 WORD
*word_indices
= indices
;
3578 FILL_INDEX_BUFFER(word_indices
)
3580 #undef FILL_INDEX_BUFFER
3581 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
3583 if (mesh_data
.material_indices
) {
3584 DWORD
*attrib_buffer
= NULL
;
3585 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, 0, &attrib_buffer
);
3586 if (FAILED(hr
)) goto cleanup
;
3587 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
3589 DWORD count
= mesh_data
.num_tri_per_face
[i
];
3591 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
3593 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
3595 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
3596 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
3597 NULL
, NULL
, NULL
, NULL
);
3598 if (FAILED(hr
)) goto cleanup
;
3601 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
3602 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
3603 char *strings_out_ptr
;
3604 D3DXMATERIAL
*materials_ptr
;
3606 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3607 if (mesh_data
.materials
[i
].pTextureFilename
)
3608 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3611 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3612 if (FAILED(hr
)) goto cleanup
;
3614 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3615 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
3616 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
3617 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3618 if (materials_ptr
[i
].pTextureFilename
) {
3619 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
3620 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
3621 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3626 if (mesh_data
.num_materials
&& effects_out
) {
3627 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
3628 if (FAILED(hr
)) goto cleanup
;
3630 if (!materials_out
) {
3631 ID3DXBuffer_Release(materials
);
3636 if (adjacency_out
) {
3637 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
3638 if (FAILED(hr
)) goto cleanup
;
3639 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
3640 if (FAILED(hr
)) goto cleanup
;
3643 *mesh_out
= d3dxmesh
;
3644 if (adjacency_out
) *adjacency_out
= adjacency
;
3645 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
3646 if (materials_out
) *materials_out
= materials
;
3647 if (effects_out
) *effects_out
= effects
;
3648 if (skin_info_out
) *skin_info_out
= mesh_data
.skin_info
;
3653 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
3654 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3655 if (materials
) ID3DXBuffer_Release(materials
);
3656 if (effects
) ID3DXBuffer_Release(effects
);
3657 if (mesh_data
.skin_info
) mesh_data
.skin_info
->lpVtbl
->Release(mesh_data
.skin_info
);
3658 if (skin_info_out
) *skin_info_out
= NULL
;
3660 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
3661 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
3662 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
3663 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
3664 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
3665 destroy_materials(&mesh_data
);
3666 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
3667 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
3668 HeapFree(GetProcessHeap(), 0, duplications
);
3672 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3673 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3674 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3680 TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_a(filename
), options
,
3681 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3684 return D3DERR_INVALIDCALL
;
3686 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3687 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3688 if (!filenameW
) return E_OUTOFMEMORY
;
3689 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3691 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
3692 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3693 HeapFree(GetProcessHeap(), 0, filenameW
);
3698 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3699 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3700 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3706 TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_w(filename
), options
,
3707 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3710 return D3DERR_INVALIDCALL
;
3712 hr
= map_view_of_file(filename
, &buffer
, &size
);
3714 return D3DXERR_INVALIDDATA
;
3716 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
3717 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3719 UnmapViewOfFile(buffer
);
3724 static HRESULT
filedata_get_name(ID3DXFileData
*filedata
, char **name
)
3729 hr
= filedata
->lpVtbl
->GetName(filedata
, NULL
, &name_len
);
3730 if (FAILED(hr
)) return hr
;
3734 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
3735 if (!*name
) return E_OUTOFMEMORY
;
3737 hr
= filedata
->lpVtbl
->GetName(filedata
, *name
, &name_len
);
3739 HeapFree(GetProcessHeap(), 0, *name
);
3746 static HRESULT
load_mesh_container(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3747 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXMESHCONTAINER
**mesh_container
)
3750 ID3DXBuffer
*adjacency
= NULL
;
3751 ID3DXBuffer
*materials
= NULL
;
3752 ID3DXBuffer
*effects
= NULL
;
3753 ID3DXSkinInfo
*skin_info
= NULL
;
3754 D3DXMESHDATA mesh_data
;
3755 DWORD num_materials
= 0;
3758 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
3759 mesh_data
.u
.pMesh
= NULL
;
3761 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
3762 &adjacency
, &materials
, &effects
, &num_materials
,
3763 &skin_info
, &mesh_data
.u
.pMesh
);
3764 if (FAILED(hr
)) return hr
;
3766 hr
= filedata_get_name(filedata
, &name
);
3767 if (FAILED(hr
)) goto cleanup
;
3769 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
3770 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
3771 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
3773 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
3774 skin_info
, mesh_container
);
3777 if (materials
) ID3DXBuffer_Release(materials
);
3778 if (effects
) ID3DXBuffer_Release(effects
);
3779 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3780 if (skin_info
) IUnknown_Release(skin_info
);
3781 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
3782 HeapFree(GetProcessHeap(), 0, name
);
3786 static HRESULT
parse_transform_matrix(ID3DXFileData
*filedata
, D3DXMATRIX
*transform
)
3792 /* template Matrix4x4 {
3793 * array FLOAT matrix[16];
3795 * template FrameTransformMatrix {
3796 * Matrix4x4 frameMatrix;
3800 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3801 if (FAILED(hr
)) return hr
;
3803 if (data_size
!= sizeof(D3DXMATRIX
)) {
3804 WARN("incorrect data size (%ld bytes)\n", data_size
);
3805 filedata
->lpVtbl
->Unlock(filedata
);
3809 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
3811 filedata
->lpVtbl
->Unlock(filedata
);
3815 static HRESULT
load_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3816 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXFRAME
**frame_out
)
3820 ID3DXFileData
*child
;
3822 D3DXFRAME
*frame
= NULL
;
3823 D3DXMESHCONTAINER
**next_container
;
3824 D3DXFRAME
**next_child
;
3828 hr
= filedata_get_name(filedata
, &name
);
3829 if (FAILED(hr
)) return hr
;
3831 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
3832 HeapFree(GetProcessHeap(), 0, name
);
3833 if (FAILED(hr
)) return E_FAIL
;
3836 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
3837 next_child
= &frame
->pFrameFirstChild
;
3838 next_container
= &frame
->pMeshContainer
;
3840 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3844 for (i
= 0; i
< nb_children
; i
++)
3846 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3849 hr
= child
->lpVtbl
->GetType(child
, &type
);
3853 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
3854 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
3856 next_container
= &(*next_container
)->pNextMeshContainer
;
3857 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
3858 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
3859 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
3860 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
3862 next_child
= &(*next_child
)->pFrameSibling
;
3871 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
3872 struct IDirect3DDevice9
*device
, struct ID3DXAllocateHierarchy
*alloc_hier
,
3873 struct ID3DXLoadUserData
*load_user_data
, D3DXFRAME
**frame_hierarchy
,
3874 struct ID3DXAnimationController
**anim_controller
)
3877 ID3DXFile
*d3dxfile
= NULL
;
3878 ID3DXFileEnumObject
*enumobj
= NULL
;
3879 ID3DXFileData
*filedata
= NULL
;
3880 D3DXF_FILELOADMEMORY source
;
3881 D3DXFRAME
*first_frame
= NULL
;
3882 D3DXFRAME
**next_frame
= &first_frame
;
3887 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3888 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3890 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
3891 return D3DERR_INVALIDCALL
;
3892 if (load_user_data
|| anim_controller
) {
3894 FIXME("Loading user data not implemented\n");
3895 if (anim_controller
)
3896 FIXME("Animation controller creation not implemented\n");
3900 hr
= D3DXFileCreate(&d3dxfile
);
3901 if (FAILED(hr
)) goto cleanup
;
3903 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3904 if (FAILED(hr
)) goto cleanup
;
3906 source
.lpMemory
= (void*)memory
;
3907 source
.dSize
= memory_size
;
3908 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
3909 if (FAILED(hr
)) goto cleanup
;
3911 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
3915 for (i
= 0; i
< nb_children
; i
++)
3917 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
3921 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
3922 if (SUCCEEDED(hr
)) {
3923 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
3924 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
3930 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
3932 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
3933 if (FAILED(hr
)) goto cleanup
;
3934 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
3935 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
3936 if (FAILED(hr
)) goto cleanup
;
3939 next_frame
= &(*next_frame
)->pFrameSibling
;
3942 filedata
->lpVtbl
->Release(filedata
);
3950 } else if (first_frame
->pFrameSibling
) {
3951 D3DXFRAME
*root_frame
= NULL
;
3952 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
3957 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
3958 root_frame
->pFrameFirstChild
= first_frame
;
3959 *frame_hierarchy
= root_frame
;
3962 *frame_hierarchy
= first_frame
;
3967 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
3968 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
3969 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
3970 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
3974 HRESULT WINAPI
D3DXCleanMesh(D3DXCLEANTYPE clean_type
, ID3DXMesh
*mesh_in
, const DWORD
*adjacency_in
,
3975 ID3DXMesh
**mesh_out
, DWORD
*adjacency_out
, ID3DXBuffer
**errors_and_warnings
)
3977 FIXME("(%u, %p, %p, %p, %p, %p)\n", clean_type
, mesh_in
, adjacency_in
, mesh_out
, adjacency_out
, errors_and_warnings
);
3982 HRESULT WINAPI
D3DXFrameDestroy(D3DXFRAME
*frame
, ID3DXAllocateHierarchy
*alloc_hier
)
3987 TRACE("(%p, %p)\n", frame
, alloc_hier
);
3989 if (!frame
|| !alloc_hier
)
3990 return D3DERR_INVALIDCALL
;
3993 D3DXMESHCONTAINER
*container
;
3994 D3DXFRAME
*current_frame
;
3996 if (frame
->pFrameSibling
) {
3997 current_frame
= frame
->pFrameSibling
;
3998 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
3999 current_frame
->pFrameSibling
= NULL
;
4001 current_frame
= frame
;
4005 if (current_frame
->pFrameFirstChild
) {
4006 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
4007 if (FAILED(hr
)) return hr
;
4008 current_frame
->pFrameFirstChild
= NULL
;
4011 container
= current_frame
->pMeshContainer
;
4013 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
4014 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
4015 if (FAILED(hr
)) return hr
;
4016 container
= next_container
;
4018 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
4019 if (FAILED(hr
)) return hr
;
4024 HRESULT WINAPI
D3DXLoadMeshFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4025 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4026 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4032 TRACE("(%s, %x, %p, %p, %p, %p, %p, %p)\n", debugstr_a(filename
), options
,
4033 device
, adjacency
, materials
, effect_instances
, num_materials
, mesh
);
4036 return D3DERR_INVALIDCALL
;
4038 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
4039 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4040 if (!filenameW
) return E_OUTOFMEMORY
;
4041 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
4043 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
4044 effect_instances
, num_materials
, mesh
);
4045 HeapFree(GetProcessHeap(), 0, filenameW
);
4050 HRESULT WINAPI
D3DXLoadMeshFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4051 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4052 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4058 TRACE("(%s, %x, %p, %p, %p, %p, %p, %p)\n", debugstr_w(filename
), options
,
4059 device
, adjacency
, materials
, effect_instances
, num_materials
, mesh
);
4062 return D3DERR_INVALIDCALL
;
4064 hr
= map_view_of_file(filename
, &buffer
, &size
);
4066 return D3DXERR_INVALIDDATA
;
4068 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4069 materials
, effect_instances
, num_materials
, mesh
);
4071 UnmapViewOfFile(buffer
);
4076 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
, const char *name
, const char *type
, DWORD options
,
4077 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
,
4078 struct ID3DXBuffer
**effect_instances
, DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4085 TRACE("(%p, %s, %s, %x, %p, %p, %p, %p, %p, %p)\n",
4086 module
, debugstr_a(name
), debugstr_a(type
), options
, device
,
4087 adjacency
, materials
, effect_instances
, num_materials
, mesh
);
4089 resinfo
= FindResourceA(module
, name
, type
);
4090 if (!resinfo
) return D3DXERR_INVALIDDATA
;
4092 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
4093 if (FAILED(hr
)) return D3DXERR_INVALIDDATA
;
4095 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4096 materials
, effect_instances
, num_materials
, mesh
);
4099 struct mesh_container
4103 ID3DXBuffer
*adjacency
;
4104 ID3DXBuffer
*materials
;
4105 ID3DXBuffer
*effects
;
4106 DWORD num_materials
;
4107 D3DXMATRIX transform
;
4110 static HRESULT
parse_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
4111 const D3DXMATRIX
*parent_transform
, struct list
*container_list
, DWORD provide_flags
)
4114 D3DXMATRIX transform
= *parent_transform
;
4115 ID3DXFileData
*child
;
4120 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
4124 for (i
= 0; i
< nb_children
; i
++)
4126 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
4129 hr
= child
->lpVtbl
->GetType(child
, &type
);
4133 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
4134 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
4136 return E_OUTOFMEMORY
;
4137 list_add_tail(container_list
, &container
->entry
);
4138 container
->transform
= transform
;
4140 hr
= D3DXLoadSkinMeshFromXof(child
, options
, device
,
4141 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
4142 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
4143 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
4144 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
4145 D3DXMATRIX new_transform
;
4146 hr
= parse_transform_matrix(child
, &new_transform
);
4147 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
4148 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
4149 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
4158 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
4159 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
4160 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXMesh
**mesh_out
)
4163 ID3DXFile
*d3dxfile
= NULL
;
4164 ID3DXFileEnumObject
*enumobj
= NULL
;
4165 ID3DXFileData
*filedata
= NULL
;
4166 D3DXF_FILELOADMEMORY source
;
4167 ID3DXBuffer
*materials
= NULL
;
4168 ID3DXBuffer
*effects
= NULL
;
4169 ID3DXBuffer
*adjacency
= NULL
;
4170 struct list container_list
= LIST_INIT(container_list
);
4171 struct mesh_container
*container_ptr
, *next_container_ptr
;
4172 DWORD num_materials
;
4173 DWORD num_faces
, num_vertices
;
4174 D3DXMATRIX identity
;
4175 DWORD provide_flags
= 0;
4177 ID3DXMesh
*concat_mesh
= NULL
;
4178 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
4179 BYTE
*concat_vertices
= NULL
;
4180 void *concat_indices
= NULL
;
4182 DWORD concat_vertex_size
;
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
);
4518 HRESULT WINAPI
D3DXCreateBox(struct IDirect3DDevice9
*device
, float width
, float height
,
4519 float depth
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4521 FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device
, width
, height
, depth
, mesh
, adjacency
);
4528 D3DXVECTOR3 position
;
4532 typedef WORD face
[3];
4540 static void free_sincos_table(struct sincos_table
*sincos_table
)
4542 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
4543 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4546 /* pre compute sine and cosine tables; caller must free */
4547 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
4552 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
4553 if (!sincos_table
->sin
)
4557 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
4558 if (!sincos_table
->cos
)
4560 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4564 angle
= angle_start
;
4565 for (i
= 0; i
< n
; i
++)
4567 sincos_table
->sin
[i
] = sin(angle
);
4568 sincos_table
->cos
[i
] = cos(angle
);
4569 angle
+= angle_step
;
4575 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
4577 return stack
*slices
+slice
+1;
4580 HRESULT WINAPI
D3DXCreateSphere(struct IDirect3DDevice9
*device
, float radius
, UINT slices
,
4581 UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4583 DWORD number_of_vertices
, number_of_faces
;
4586 struct vertex
*vertices
;
4588 float phi_step
, phi_start
;
4589 struct sincos_table phi
;
4590 float theta_step
, theta
, sin_theta
, cos_theta
;
4591 DWORD vertex
, face
, stack
, slice
;
4593 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
4595 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
4597 return D3DERR_INVALIDCALL
;
4602 FIXME("Case of adjacency != NULL not implemented.\n");
4606 number_of_vertices
= 2 + slices
* (stacks
-1);
4607 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
4609 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4610 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
4616 hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, 0, (LPVOID
*)&vertices
);
4619 sphere
->lpVtbl
->Release(sphere
);
4623 hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, 0, (LPVOID
*)&faces
);
4626 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4627 sphere
->lpVtbl
->Release(sphere
);
4631 /* phi = angle on xz plane wrt z axis */
4632 phi_step
= -2 * M_PI
/ slices
;
4633 phi_start
= M_PI
/ 2;
4635 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
4637 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4638 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4639 sphere
->lpVtbl
->Release(sphere
);
4640 return E_OUTOFMEMORY
;
4643 /* theta = angle on xy plane wrt x axis */
4644 theta_step
= M_PI
/ stacks
;
4650 vertices
[vertex
].normal
.x
= 0.0f
;
4651 vertices
[vertex
].normal
.y
= 0.0f
;
4652 vertices
[vertex
].normal
.z
= 1.0f
;
4653 vertices
[vertex
].position
.x
= 0.0f
;
4654 vertices
[vertex
].position
.y
= 0.0f
;
4655 vertices
[vertex
].position
.z
= radius
;
4658 for (stack
= 0; stack
< stacks
- 1; stack
++)
4660 sin_theta
= sin(theta
);
4661 cos_theta
= cos(theta
);
4663 for (slice
= 0; slice
< slices
; slice
++)
4665 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
4666 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
4667 vertices
[vertex
].normal
.z
= cos_theta
;
4668 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
4669 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
4670 vertices
[vertex
].position
.z
= radius
* cos_theta
;
4677 /* top stack is triangle fan */
4679 faces
[face
][1] = slice
+ 1;
4680 faces
[face
][2] = slice
;
4685 /* stacks in between top and bottom are quad strips */
4686 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4687 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4688 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4691 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4692 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
4693 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4699 theta
+= theta_step
;
4705 faces
[face
][2] = slice
;
4710 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4711 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4712 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4715 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4716 faces
[face
][1] = vertex_index(slices
, 0, stack
);
4717 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4722 vertices
[vertex
].position
.x
= 0.0f
;
4723 vertices
[vertex
].position
.y
= 0.0f
;
4724 vertices
[vertex
].position
.z
= -radius
;
4725 vertices
[vertex
].normal
.x
= 0.0f
;
4726 vertices
[vertex
].normal
.y
= 0.0f
;
4727 vertices
[vertex
].normal
.z
= -1.0f
;
4729 /* bottom stack is triangle fan */
4730 for (slice
= 1; slice
< slices
; slice
++)
4732 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4733 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4734 faces
[face
][2] = vertex
;
4738 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4739 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4740 faces
[face
][2] = vertex
;
4742 free_sincos_table(&phi
);
4743 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4744 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4750 HRESULT WINAPI
D3DXCreateCylinder(struct IDirect3DDevice9
*device
, float radius1
, float radius2
,
4751 float length
, UINT slices
, UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4753 DWORD number_of_vertices
, number_of_faces
;
4755 ID3DXMesh
*cylinder
;
4756 struct vertex
*vertices
;
4758 float theta_step
, theta_start
;
4759 struct sincos_table theta
;
4760 float delta_radius
, radius
, radius_step
;
4761 float z
, z_step
, z_normal
;
4762 DWORD vertex
, face
, slice
, stack
;
4764 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
4766 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
4768 return D3DERR_INVALIDCALL
;
4773 FIXME("Case of adjacency != NULL not implemented.\n");
4777 number_of_vertices
= 2 + (slices
* (3 + stacks
));
4778 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
4780 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4781 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
4787 hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, 0, (LPVOID
*)&vertices
);
4790 cylinder
->lpVtbl
->Release(cylinder
);
4794 hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, 0, (LPVOID
*)&faces
);
4797 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4798 cylinder
->lpVtbl
->Release(cylinder
);
4802 /* theta = angle on xy plane wrt x axis */
4803 theta_step
= -2 * M_PI
/ slices
;
4804 theta_start
= M_PI
/ 2;
4806 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
4808 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
4809 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4810 cylinder
->lpVtbl
->Release(cylinder
);
4811 return E_OUTOFMEMORY
;
4817 delta_radius
= radius1
- radius2
;
4819 radius_step
= delta_radius
/ stacks
;
4822 z_step
= length
/ stacks
;
4823 z_normal
= delta_radius
/ length
;
4824 if (isnan(z_normal
))
4829 vertices
[vertex
].normal
.x
= 0.0f
;
4830 vertices
[vertex
].normal
.y
= 0.0f
;
4831 vertices
[vertex
].normal
.z
= -1.0f
;
4832 vertices
[vertex
].position
.x
= 0.0f
;
4833 vertices
[vertex
].position
.y
= 0.0f
;
4834 vertices
[vertex
++].position
.z
= z
;
4836 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4838 vertices
[vertex
].normal
.x
= 0.0f
;
4839 vertices
[vertex
].normal
.y
= 0.0f
;
4840 vertices
[vertex
].normal
.z
= -1.0f
;
4841 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4842 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4843 vertices
[vertex
].position
.z
= z
;
4848 faces
[face
][1] = slice
;
4849 faces
[face
++][2] = slice
+ 1;
4854 faces
[face
][1] = slice
;
4855 faces
[face
++][2] = 1;
4857 for (stack
= 1; stack
<= stacks
+1; stack
++)
4859 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4861 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
4862 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
4863 vertices
[vertex
].normal
.z
= z_normal
;
4864 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
4865 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4866 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4867 vertices
[vertex
].position
.z
= z
;
4869 if (stack
> 1 && slice
> 0)
4871 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4872 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4873 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
4875 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4876 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4877 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
4883 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4884 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4885 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
4887 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4888 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4889 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
4892 if (stack
< stacks
+ 1)
4895 radius
-= radius_step
;
4899 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4901 vertices
[vertex
].normal
.x
= 0.0f
;
4902 vertices
[vertex
].normal
.y
= 0.0f
;
4903 vertices
[vertex
].normal
.z
= 1.0f
;
4904 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4905 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4906 vertices
[vertex
].position
.z
= z
;
4910 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
4911 faces
[face
][1] = number_of_vertices
- 1;
4912 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
4916 vertices
[vertex
].position
.x
= 0.0f
;
4917 vertices
[vertex
].position
.y
= 0.0f
;
4918 vertices
[vertex
].position
.z
= z
;
4919 vertices
[vertex
].normal
.x
= 0.0f
;
4920 vertices
[vertex
].normal
.y
= 0.0f
;
4921 vertices
[vertex
].normal
.z
= 1.0f
;
4923 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
4924 faces
[face
][1] = number_of_vertices
- 1;
4925 faces
[face
][2] = vertex_index(slices
, 0, stack
);
4927 free_sincos_table(&theta
);
4928 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
4929 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4935 HRESULT WINAPI
D3DXCreateTeapot(struct IDirect3DDevice9
*device
,
4936 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4938 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
4943 HRESULT WINAPI
D3DXCreateTextA(struct IDirect3DDevice9
*device
, HDC hdc
, const char *text
, float deviation
,
4944 float extrusion
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
4950 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
4951 debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
4954 return D3DERR_INVALIDCALL
;
4956 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
4957 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4958 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
4960 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
4961 mesh
, adjacency
, glyphmetrics
);
4962 HeapFree(GetProcessHeap(), 0, textW
);
4968 POINTTYPE_CURVE
= 0,
4970 POINTTYPE_CURVE_START
,
4971 POINTTYPE_CURVE_END
,
4972 POINTTYPE_CURVE_MIDDLE
,
4978 enum pointtype corner
;
4981 struct dynamic_array
4983 int count
, capacity
;
4987 /* is a dynamic_array */
4990 int count
, capacity
;
4991 struct point2d
*items
;
4994 /* is a dynamic_array */
4995 struct outline_array
4997 int count
, capacity
;
4998 struct outline
*items
;
5007 struct point2d_index
5009 struct outline
*outline
;
5013 struct point2d_index_array
5016 struct point2d_index
*items
;
5021 struct outline_array outlines
;
5022 struct face_array faces
;
5023 struct point2d_index_array ordered_vertices
;
5027 /* is an dynamic_array */
5030 int count
, capacity
;
5034 /* complex polygons are split into monotone polygons, which have
5035 * at most 2 intersections with the vertical sweep line */
5036 struct triangulation
5038 struct word_array vertex_stack
;
5039 BOOL last_on_top
, merging
;
5042 /* is an dynamic_array */
5043 struct triangulation_array
5045 int count
, capacity
;
5046 struct triangulation
*items
;
5048 struct glyphinfo
*glyph
;
5051 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
5053 if (count
> array
->capacity
) {
5056 if (array
->items
&& array
->capacity
) {
5057 new_capacity
= max(array
->capacity
* 2, count
);
5058 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
5060 new_capacity
= max(16, count
);
5061 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
5065 array
->items
= new_buffer
;
5066 array
->capacity
= new_capacity
;
5071 static struct point2d
*add_points(struct outline
*array
, int num
)
5073 struct point2d
*item
;
5075 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
5078 item
= &array
->items
[array
->count
];
5079 array
->count
+= num
;
5083 static struct outline
*add_outline(struct outline_array
*array
)
5085 struct outline
*item
;
5087 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5090 item
= &array
->items
[array
->count
++];
5091 ZeroMemory(item
, sizeof(*item
));
5095 static inline face
*add_face(struct face_array
*array
)
5097 return &array
->items
[array
->count
++];
5100 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
5102 struct triangulation
*item
;
5104 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5107 item
= &array
->items
[array
->count
++];
5108 ZeroMemory(item
, sizeof(*item
));
5112 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
5114 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5115 return E_OUTOFMEMORY
;
5117 array
->items
[array
->count
++] = vertex_index
;
5121 /* assume fixed point numbers can be converted to float point in place */
5122 C_ASSERT(sizeof(FIXED
) == sizeof(float));
5123 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
5125 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, float emsquare
)
5127 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
5129 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
5130 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
5131 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
5137 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
5138 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
5139 float max_deviation_sq
)
5141 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
5144 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
5145 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
5146 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
5148 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
5149 if (deviation_sq
< max_deviation_sq
) {
5150 struct point2d
*pt
= add_points(outline
, 1);
5151 if (!pt
) return E_OUTOFMEMORY
;
5153 pt
->corner
= POINTTYPE_CURVE
;
5154 /* the end point is omitted because the end line merges into the next segment of
5155 * the split bezier curve, and the end of the split bezier curve is added outside
5156 * this recursive function. */
5158 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
5159 if (hr
!= S_OK
) return hr
;
5160 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
5161 if (hr
!= S_OK
) return hr
;
5167 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
5169 /* dot product = cos(theta) */
5170 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
5173 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
5175 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
5185 static BOOL
attempt_line_merge(struct outline
*outline
,
5187 const D3DXVECTOR2
*nextpt
,
5189 const struct cos_table
*table
)
5191 D3DXVECTOR2 curdir
, lastdir
;
5192 struct point2d
*prevpt
, *pt
;
5195 pt
= &outline
->items
[pt_index
];
5196 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5197 prevpt
= &outline
->items
[pt_index
];
5200 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
5202 if (outline
->count
< 2)
5205 /* remove last point if the next line continues the last line */
5206 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5207 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5208 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
5211 if (pt
->corner
== POINTTYPE_CURVE_END
)
5212 prevpt
->corner
= pt
->corner
;
5213 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
5214 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5218 if (outline
->count
< 2)
5221 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5222 prevpt
= &outline
->items
[pt_index
];
5223 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5224 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5229 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
5230 float max_deviation_sq
, float emsquare
, const struct cos_table
*cos_table
)
5232 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
5234 while ((char *)header
< (char *)raw_outline
+ datasize
)
5236 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
5237 struct point2d
*lastpt
, *pt
;
5238 D3DXVECTOR2 lastdir
;
5239 D3DXVECTOR2
*pt_flt
;
5241 struct outline
*outline
= add_outline(&glyph
->outlines
);
5244 return E_OUTOFMEMORY
;
5246 pt
= add_points(outline
, 1);
5248 return E_OUTOFMEMORY
;
5249 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
5251 pt
->corner
= POINTTYPE_CORNER
;
5253 if (header
->dwType
!= TT_POLYGON_TYPE
)
5254 FIXME("Unknown header type %d\n", header
->dwType
);
5256 while ((char *)curve
< (char *)header
+ header
->cb
)
5258 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
5259 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
5260 unsigned int j2
= 0;
5263 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5267 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
5269 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
5274 int count
= curve
->cpfx
;
5278 D3DXVECTOR2 bezier_end
;
5280 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j2
], &pt_flt
[j2
+1]), 0.5f
);
5281 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &bezier_end
, max_deviation_sq
);
5284 bezier_start
= bezier_end
;
5288 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &pt_flt
[j2
+1], max_deviation_sq
);
5292 pt
= add_points(outline
, 1);
5294 return E_OUTOFMEMORY
;
5296 pt
->pos
= pt_flt
[j2
];
5297 pt
->corner
= POINTTYPE_CURVE_END
;
5299 pt
= add_points(outline
, curve
->cpfx
);
5301 return E_OUTOFMEMORY
;
5302 for (j2
= 0; j2
< curve
->cpfx
; j2
++)
5304 pt
->pos
= pt_flt
[j2
];
5305 pt
->corner
= POINTTYPE_CORNER
;
5310 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5313 /* remove last point if the next line continues the last line */
5314 if (outline
->count
>= 3) {
5317 lastpt
= &outline
->items
[outline
->count
- 1];
5318 pt
= &outline
->items
[0];
5319 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
5320 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
5322 if (pt
->corner
== POINTTYPE_CURVE_START
)
5323 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5325 pt
->corner
= POINTTYPE_CURVE_END
;
5328 lastpt
= &outline
->items
[outline
->count
- 1];
5330 /* outline closed with a line from end to start point */
5331 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
5333 lastpt
= &outline
->items
[0];
5334 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
5335 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
5336 lastpt
->corner
= POINTTYPE_CORNER
;
5337 pt
= &outline
->items
[1];
5338 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
5339 *lastpt
= outline
->items
[outline
->count
];
5342 lastpt
= &outline
->items
[outline
->count
- 1];
5343 pt
= &outline
->items
[0];
5344 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
5345 for (j
= 0; j
< outline
->count
; j
++)
5350 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
5351 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
5353 switch (lastpt
->corner
)
5355 case POINTTYPE_CURVE_START
:
5356 case POINTTYPE_CURVE_END
:
5357 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
5358 lastpt
->corner
= POINTTYPE_CORNER
;
5360 case POINTTYPE_CURVE_MIDDLE
:
5361 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
5362 lastpt
->corner
= POINTTYPE_CORNER
;
5364 lastpt
->corner
= POINTTYPE_CURVE
;
5372 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
5377 /* Get the y-distance from a line to a point */
5378 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
5379 D3DXVECTOR2
*line_pt2
,
5382 D3DXVECTOR2 line_vec
= {0, 0};
5386 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
5387 line_pt_dx
= point
->x
- line_pt1
->x
;
5388 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
5389 return point
->y
- line_y
;
5392 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
5394 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
5397 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
5399 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
5402 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
5404 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
5405 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
5409 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
5410 struct triangulation_array
*triangulations
,
5414 struct glyphinfo
*glyph
= triangulations
->glyph
;
5415 struct triangulation
*t
= *t_ptr
;
5420 if (t
->last_on_top
) {
5428 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
5429 /* consume all vertices on the stack */
5430 WORD last_pt
= t
->vertex_stack
.items
[0];
5432 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
5434 face
= add_face(&glyph
->faces
);
5435 if (!face
) return E_OUTOFMEMORY
;
5436 (*face
)[0] = vtx_idx
;
5437 (*face
)[f1
] = last_pt
;
5438 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
5440 t
->vertex_stack
.items
[0] = last_pt
;
5441 t
->vertex_stack
.count
= 1;
5442 } else if (t
->vertex_stack
.count
> 1) {
5443 int i
= t
->vertex_stack
.count
- 1;
5444 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
5445 WORD top_idx
= t
->vertex_stack
.items
[i
--];
5446 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
5450 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
5451 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
5453 if (prev_pt
->x
!= top_pt
->x
&&
5454 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
5455 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
5458 face
= add_face(&glyph
->faces
);
5459 if (!face
) return E_OUTOFMEMORY
;
5460 (*face
)[0] = vtx_idx
;
5461 (*face
)[f1
] = prev_idx
;
5462 (*face
)[f2
] = top_idx
;
5466 t
->vertex_stack
.count
--;
5469 t
->last_on_top
= to_top
;
5471 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
5473 if (hr
== S_OK
&& t
->merging
) {
5474 struct triangulation
*t2
;
5476 t2
= to_top
? t
- 1 : t
+ 1;
5477 t2
->merging
= FALSE
;
5478 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
5479 if (hr
!= S_OK
) return hr
;
5480 remove_triangulation(triangulations
, t
);
5488 /* check if the point is next on the outline for either the top or bottom */
5489 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
5491 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
5492 WORD idx
= t
->vertex_stack
.items
[i
];
5493 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
5494 struct outline
*outline
= pt_idx
->outline
;
5497 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
5499 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
5501 return &outline
->items
[i
].pos
;
5504 static int compare_vertex_indices(const void *a
, const void *b
)
5506 const struct point2d_index
*idx1
= a
, *idx2
= b
;
5507 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
5508 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
5509 float diff
= p1
->x
- p2
->x
;
5512 diff
= p1
->y
- p2
->y
;
5514 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
5517 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
5521 struct glyphinfo
*glyph
= triangulations
->glyph
;
5522 int nb_vertices
= 0;
5524 struct point2d_index
*idx_ptr
;
5526 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5527 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
5529 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
5530 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
5531 if (!glyph
->ordered_vertices
.items
)
5532 return E_OUTOFMEMORY
;
5534 idx_ptr
= glyph
->ordered_vertices
.items
;
5535 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5537 struct outline
*outline
= &glyph
->outlines
.items
[i
];
5540 idx_ptr
->outline
= outline
;
5541 idx_ptr
->vertex
= 0;
5543 for (j
= outline
->count
- 1; j
> 0; j
--)
5545 idx_ptr
->outline
= outline
;
5546 idx_ptr
->vertex
= j
;
5550 glyph
->ordered_vertices
.count
= nb_vertices
;
5552 /* Native implementation seems to try to create a triangle fan from
5553 * the first outline point if the glyph only has one outline. */
5554 if (glyph
->outlines
.count
== 1)
5556 struct outline
*outline
= glyph
->outlines
.items
;
5557 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
5558 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
5561 for (i
= 2; i
< outline
->count
; i
++)
5563 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
5564 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
5565 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
5567 D3DXVec2Subtract(&v1
, base
, last
);
5568 D3DXVec2Subtract(&v2
, last
, next
);
5569 ccw
= D3DXVec2CCW(&v1
, &v2
);
5577 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5578 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
5579 if (!glyph
->faces
.items
)
5580 return E_OUTOFMEMORY
;
5582 glyph
->faces
.count
= outline
->count
- 2;
5583 for (i
= 0; i
< glyph
->faces
.count
; i
++)
5585 glyph
->faces
.items
[i
][0] = 0;
5586 glyph
->faces
.items
[i
][1] = i
+ 1;
5587 glyph
->faces
.items
[i
][2] = i
+ 2;
5593 /* Perform 2D polygon triangulation for complex glyphs.
5594 * Triangulation is performed using a sweep line concept, from right to left,
5595 * by processing vertices in sorted order. Complex polygons are split into
5596 * monotone polygons which are triangulated separately. */
5597 /* FIXME: The order of the faces is not consistent with the native implementation. */
5599 /* Reserve space for maximum possible faces from triangulation.
5600 * # faces for outer outlines = outline->count - 2
5601 * # faces for inner outlines = outline->count + 2
5602 * There must be at least 1 outer outline. */
5603 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5604 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
5605 if (!glyph
->faces
.items
)
5606 return E_OUTOFMEMORY
;
5608 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
5609 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
5610 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
5613 int end
= triangulations
->count
;
5617 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
5618 int current
= (start
+ end
) / 2;
5619 struct triangulation
*t
= &triangulations
->items
[current
];
5620 BOOL on_top_outline
= FALSE
;
5621 D3DXVECTOR2
*top_next
, *bottom_next
;
5622 WORD top_idx
, bottom_idx
;
5624 if (t
->merging
&& t
->last_on_top
)
5625 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
5627 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
5628 if (sweep_vtx
== top_next
)
5630 if (t
->merging
&& t
->last_on_top
)
5632 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
5633 if (hr
!= S_OK
) return hr
;
5635 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
5636 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
5638 /* point also on bottom outline of higher triangulation */
5639 struct triangulation
*t2
= t
+ 1;
5640 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
5641 if (hr
!= S_OK
) return hr
;
5646 on_top_outline
= TRUE
;
5649 if (t
->merging
&& !t
->last_on_top
)
5650 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
5652 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
5653 if (sweep_vtx
== bottom_next
)
5655 if (t
->merging
&& !t
->last_on_top
)
5657 if (on_top_outline
) {
5658 /* outline finished */
5659 remove_triangulation(triangulations
, t
);
5663 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
5664 if (hr
!= S_OK
) return hr
;
5666 if (t
> triangulations
->items
&&
5667 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
5669 struct triangulation
*t2
= t
- 1;
5670 /* point also on top outline of lower triangulation */
5671 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
5672 if (hr
!= S_OK
) return hr
;
5673 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
5683 if (t
->last_on_top
) {
5684 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
5685 bottom_idx
= t
->vertex_stack
.items
[0];
5687 top_idx
= t
->vertex_stack
.items
[0];
5688 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
5691 /* check if the point is inside or outside this polygon */
5692 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
5693 top_next
, sweep_vtx
) > 0)
5695 start
= current
+ 1;
5696 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
5697 bottom_next
, sweep_vtx
) < 0)
5700 } else if (t
->merging
) {
5701 /* inside, so cancel merging */
5702 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
5704 t2
->merging
= FALSE
;
5705 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
5706 if (hr
!= S_OK
) return hr
;
5707 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
5708 if (hr
!= S_OK
) return hr
;
5711 /* inside, so split polygon into two monotone parts */
5712 struct triangulation
*t2
= add_triangulation(triangulations
);
5713 if (!t2
) return E_OUTOFMEMORY
;
5714 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
5715 if (t
->last_on_top
) {
5722 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
5723 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
5724 if (hr
!= S_OK
) return hr
;
5725 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
5726 if (hr
!= S_OK
) return hr
;
5727 t2
->last_on_top
= !t
->last_on_top
;
5729 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
5730 if (hr
!= S_OK
) return hr
;
5736 struct triangulation
*t
;
5737 struct triangulation
*t2
= add_triangulation(triangulations
);
5738 if (!t2
) return E_OUTOFMEMORY
;
5739 t
= &triangulations
->items
[start
];
5740 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
5741 ZeroMemory(t
, sizeof(*t
));
5742 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
5743 if (hr
!= S_OK
) return hr
;
5749 HRESULT WINAPI
D3DXCreateTextW(struct IDirect3DDevice9
*device
, HDC hdc
, const WCHAR
*text
, float deviation
,
5750 float extrusion
, struct ID3DXMesh
**mesh_ptr
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5753 ID3DXMesh
*mesh
= NULL
;
5754 DWORD nb_vertices
, nb_faces
;
5755 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
5756 struct vertex
*vertices
= NULL
;
5761 OUTLINETEXTMETRICW otm
;
5762 HFONT font
= NULL
, oldfont
= NULL
;
5763 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
5764 void *raw_outline
= NULL
;
5766 struct glyphinfo
*glyphs
= NULL
;
5768 struct triangulation_array triangulations
= {0, 0, NULL
};
5770 struct vertex
*vertex_ptr
;
5772 float max_deviation_sq
;
5773 const struct cos_table cos_table
= {
5774 cos(D3DXToRadian(0.5f
)),
5775 cos(D3DXToRadian(45.0f
)),
5776 cos(D3DXToRadian(90.0f
)),
5780 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
5781 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
5783 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
5784 return D3DERR_INVALIDCALL
;
5788 FIXME("Case of adjacency != NULL not implemented.\n");
5792 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
5793 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
5795 return D3DERR_INVALIDCALL
;
5798 if (deviation
== 0.0f
)
5799 deviation
= 1.0f
/ otm
.otmEMSquare
;
5800 max_deviation_sq
= deviation
* deviation
;
5802 lf
.lfHeight
= otm
.otmEMSquare
;
5804 font
= CreateFontIndirectW(&lf
);
5809 oldfont
= SelectObject(hdc
, font
);
5811 textlen
= strlenW(text
);
5812 for (i
= 0; i
< textlen
; i
++)
5814 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
5816 return D3DERR_INVALIDCALL
;
5817 if (bufsize
< datasize
)
5820 if (!bufsize
) { /* e.g. text == " " */
5821 hr
= D3DERR_INVALIDCALL
;
5825 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
5826 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
5827 if (!glyphs
|| !raw_outline
) {
5833 for (i
= 0; i
< textlen
; i
++)
5835 /* get outline points from data returned from GetGlyphOutline */
5838 glyphs
[i
].offset_x
= offset_x
;
5840 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
5841 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
5842 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
5843 if (hr
!= S_OK
) goto error
;
5845 triangulations
.glyph
= &glyphs
[i
];
5846 hr
= triangulate(&triangulations
);
5847 if (hr
!= S_OK
) goto error
;
5848 if (triangulations
.count
) {
5849 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
5850 triangulations
.count
= 0;
5855 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
5856 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
5857 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
5858 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
5859 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
5860 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
5862 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
5865 /* corner points need an extra vertex for the different side faces normals */
5867 nb_outline_points
= 0;
5869 for (i
= 0; i
< textlen
; i
++)
5872 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
5873 nb_front_faces
+= glyphs
[i
].faces
.count
;
5874 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
5877 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
5878 nb_corners
++; /* first outline point always repeated as a corner */
5879 for (k
= 1; k
< outline
->count
; k
++)
5880 if (outline
->items
[k
].corner
)
5885 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
5886 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
5889 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
5890 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
5894 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (LPVOID
*)&vertices
);
5898 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, (LPVOID
*)&faces
);
5902 /* convert 2D vertices and faces into 3D mesh */
5903 vertex_ptr
= vertices
;
5905 if (extrusion
== 0.0f
) {
5912 for (i
= 0; i
< textlen
; i
++)
5916 struct vertex
*back_vertices
;
5919 /* side vertices and faces */
5920 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
5922 struct vertex
*outline_vertices
= vertex_ptr
;
5923 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
5925 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
5926 struct point2d
*pt
= &outline
->items
[0];
5928 for (k
= 1; k
<= outline
->count
; k
++)
5931 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
5932 WORD vtx_idx
= vertex_ptr
- vertices
;
5935 if (pt
->corner
== POINTTYPE_CURVE_START
)
5936 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
5937 else if (pt
->corner
)
5938 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
5940 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
5941 D3DXVec2Normalize(&vec
, &vec
);
5942 vtx
.normal
.x
= -vec
.y
;
5943 vtx
.normal
.y
= vec
.x
;
5946 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
5947 vtx
.position
.y
= pt
->pos
.y
;
5949 *vertex_ptr
++ = vtx
;
5951 vtx
.position
.z
= -extrusion
;
5952 *vertex_ptr
++ = vtx
;
5954 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
5955 vtx
.position
.y
= nextpt
->pos
.y
;
5956 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
5957 vtx
.position
.z
= -extrusion
;
5958 *vertex_ptr
++ = vtx
;
5960 *vertex_ptr
++ = vtx
;
5962 (*face_ptr
)[0] = vtx_idx
;
5963 (*face_ptr
)[1] = vtx_idx
+ 2;
5964 (*face_ptr
)[2] = vtx_idx
+ 1;
5967 (*face_ptr
)[0] = vtx_idx
;
5968 (*face_ptr
)[1] = vtx_idx
+ 3;
5969 (*face_ptr
)[2] = vtx_idx
+ 2;
5972 if (nextpt
->corner
) {
5973 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
5974 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
5975 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
5977 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
5979 D3DXVec2Normalize(&vec
, &vec
);
5980 vtx
.normal
.x
= -vec
.y
;
5981 vtx
.normal
.y
= vec
.x
;
5984 *vertex_ptr
++ = vtx
;
5985 vtx
.position
.z
= -extrusion
;
5986 *vertex_ptr
++ = vtx
;
5989 (*face_ptr
)[0] = vtx_idx
;
5990 (*face_ptr
)[1] = vtx_idx
+ 3;
5991 (*face_ptr
)[2] = vtx_idx
+ 1;
5994 (*face_ptr
)[0] = vtx_idx
;
5995 (*face_ptr
)[1] = vtx_idx
+ 2;
5996 (*face_ptr
)[2] = vtx_idx
+ 3;
6004 *vertex_ptr
++ = *outline_vertices
++;
6005 *vertex_ptr
++ = *outline_vertices
++;
6009 /* back vertices and faces */
6010 back_faces
= face_ptr
;
6011 back_vertices
= vertex_ptr
;
6012 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
6014 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
6015 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
6016 vertex_ptr
->position
.y
= pt
->y
;
6017 vertex_ptr
->position
.z
= 0;
6018 vertex_ptr
->normal
.x
= 0;
6019 vertex_ptr
->normal
.y
= 0;
6020 vertex_ptr
->normal
.z
= 1;
6023 count
= back_vertices
- vertices
;
6024 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
6026 face
*f
= &glyphs
[i
].faces
.items
[j
];
6027 (*face_ptr
)[0] = (*f
)[0] + count
;
6028 (*face_ptr
)[1] = (*f
)[1] + count
;
6029 (*face_ptr
)[2] = (*f
)[2] + count
;
6033 /* front vertices and faces */
6034 j
= count
= vertex_ptr
- back_vertices
;
6037 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
6038 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
6039 vertex_ptr
->position
.z
= -extrusion
;
6040 vertex_ptr
->normal
.x
= 0;
6041 vertex_ptr
->normal
.y
= 0;
6042 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
6046 j
= face_ptr
- back_faces
;
6049 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
6050 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
6051 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
6061 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6062 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6063 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
6066 for (i
= 0; i
< textlen
; i
++)
6069 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6070 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
6071 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
6072 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
6073 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
6075 HeapFree(GetProcessHeap(), 0, glyphs
);
6077 if (triangulations
.items
) {
6079 for (i
= 0; i
< triangulations
.count
; i
++)
6080 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
6081 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
6083 HeapFree(GetProcessHeap(), 0, raw_outline
);
6084 if (oldfont
) SelectObject(hdc
, oldfont
);
6085 if (font
) DeleteObject(font
);
6090 HRESULT WINAPI
D3DXValidMesh(ID3DXMesh
*mesh
, const DWORD
*adjacency
, ID3DXBuffer
**errors_and_warnings
)
6092 FIXME("(%p, %p, %p): stub\n", mesh
, adjacency
, *errors_and_warnings
);
6097 static BOOL
weld_float1(void *to
, void *from
, FLOAT epsilon
)
6102 if (fabsf(*v1
- *v2
) <= epsilon
)
6112 static BOOL
weld_float2(void *to
, void *from
, FLOAT epsilon
)
6114 D3DXVECTOR2
*v1
= to
;
6115 D3DXVECTOR2
*v2
= from
;
6116 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6117 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6118 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6120 if (max_abs_diff
<= epsilon
)
6122 memcpy(to
, from
, sizeof(D3DXVECTOR2
));
6130 static BOOL
weld_float3(void *to
, void *from
, FLOAT epsilon
)
6132 D3DXVECTOR3
*v1
= to
;
6133 D3DXVECTOR3
*v2
= from
;
6134 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6135 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6136 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6137 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6138 max_abs_diff
= max(diff_z
, max_abs_diff
);
6140 if (max_abs_diff
<= epsilon
)
6142 memcpy(to
, from
, sizeof(D3DXVECTOR3
));
6150 static BOOL
weld_float4(void *to
, void *from
, FLOAT epsilon
)
6152 D3DXVECTOR4
*v1
= to
;
6153 D3DXVECTOR4
*v2
= from
;
6154 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6155 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6156 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6157 FLOAT diff_w
= fabsf(v1
->w
- v2
->w
);
6158 FLOAT max_abs_diff
= fmax(diff_x
, diff_y
);
6159 max_abs_diff
= max(diff_z
, max_abs_diff
);
6160 max_abs_diff
= max(diff_w
, max_abs_diff
);
6162 if (max_abs_diff
<= epsilon
)
6164 memcpy(to
, from
, sizeof(D3DXVECTOR4
));
6172 static BOOL
weld_ubyte4(void *to
, void *from
, FLOAT epsilon
)
6176 BYTE truncated_epsilon
= (BYTE
)epsilon
;
6177 BYTE diff_x
= b1
[0] > b2
[0] ? b1
[0] - b2
[0] : b2
[0] - b1
[0];
6178 BYTE diff_y
= b1
[1] > b2
[1] ? b1
[1] - b2
[1] : b2
[1] - b1
[1];
6179 BYTE diff_z
= b1
[2] > b2
[2] ? b1
[2] - b2
[2] : b2
[2] - b1
[2];
6180 BYTE diff_w
= b1
[3] > b2
[3] ? b1
[3] - b2
[3] : b2
[3] - b1
[3];
6181 BYTE max_diff
= max(diff_x
, diff_y
);
6182 max_diff
= max(diff_z
, max_diff
);
6183 max_diff
= max(diff_w
, max_diff
);
6185 if (max_diff
<= truncated_epsilon
)
6187 memcpy(to
, from
, 4 * sizeof(BYTE
));
6195 static BOOL
weld_ubyte4n(void *to
, void *from
, FLOAT epsilon
)
6197 return weld_ubyte4(to
, from
, epsilon
* UCHAR_MAX
);
6200 static BOOL
weld_d3dcolor(void *to
, void *from
, FLOAT epsilon
)
6202 return weld_ubyte4n(to
, from
, epsilon
);
6205 static BOOL
weld_short2(void *to
, void *from
, FLOAT epsilon
)
6209 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6210 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6211 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6212 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6214 if (max_abs_diff
<= truncated_epsilon
)
6216 memcpy(to
, from
, 2 * sizeof(SHORT
));
6224 static BOOL
weld_short2n(void *to
, void *from
, FLOAT epsilon
)
6226 return weld_short2(to
, from
, epsilon
* SHRT_MAX
);
6229 static BOOL
weld_short4(void *to
, void *from
, FLOAT epsilon
)
6233 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6234 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6235 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6236 SHORT diff_z
= abs(s1
[2] - s2
[2]);
6237 SHORT diff_w
= abs(s1
[3] - s2
[3]);
6238 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6239 max_abs_diff
= max(diff_z
, max_abs_diff
);
6240 max_abs_diff
= max(diff_w
, max_abs_diff
);
6242 if (max_abs_diff
<= truncated_epsilon
)
6244 memcpy(to
, from
, 4 * sizeof(SHORT
));
6252 static BOOL
weld_short4n(void *to
, void *from
, FLOAT epsilon
)
6254 return weld_short4(to
, from
, epsilon
* SHRT_MAX
);
6257 static BOOL
weld_ushort2n(void *to
, void *from
, FLOAT epsilon
)
6261 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6262 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6263 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6264 USHORT max_diff
= max(diff_x
, diff_y
);
6266 if (max_diff
<= scaled_epsilon
)
6268 memcpy(to
, from
, 2 * sizeof(USHORT
));
6276 static BOOL
weld_ushort4n(void *to
, void *from
, FLOAT epsilon
)
6280 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6281 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6282 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6283 USHORT diff_z
= s1
[2] > s2
[2] ? s1
[2] - s2
[2] : s2
[2] - s1
[2];
6284 USHORT diff_w
= s1
[3] > s2
[3] ? s1
[3] - s2
[3] : s2
[3] - s1
[3];
6285 USHORT max_diff
= max(diff_x
, diff_y
);
6286 max_diff
= max(diff_z
, max_diff
);
6287 max_diff
= max(diff_w
, max_diff
);
6289 if (max_diff
<= scaled_epsilon
)
6291 memcpy(to
, from
, 4 * sizeof(USHORT
));
6307 static struct udec3
dword_to_udec3(DWORD d
)
6312 v
.y
= (d
& 0xffc00) >> 10;
6313 v
.z
= (d
& 0x3ff00000) >> 20;
6314 v
.w
= (d
& 0xc0000000) >> 30;
6319 static BOOL
weld_udec3(void *to
, void *from
, FLOAT epsilon
)
6323 struct udec3 v1
= dword_to_udec3(*d1
);
6324 struct udec3 v2
= dword_to_udec3(*d2
);
6325 UINT truncated_epsilon
= (UINT
)epsilon
;
6326 UINT diff_x
= v1
.x
> v2
.x
? v1
.x
- v2
.x
: v2
.x
- v1
.x
;
6327 UINT diff_y
= v1
.y
> v2
.y
? v1
.y
- v2
.y
: v2
.y
- v1
.y
;
6328 UINT diff_z
= v1
.z
> v2
.z
? v1
.z
- v2
.z
: v2
.z
- v1
.z
;
6329 UINT diff_w
= v1
.w
> v2
.w
? v1
.w
- v2
.w
: v2
.w
- v1
.w
;
6330 UINT max_diff
= max(diff_x
, diff_y
);
6331 max_diff
= max(diff_z
, max_diff
);
6332 max_diff
= max(diff_w
, max_diff
);
6334 if (max_diff
<= truncated_epsilon
)
6336 memcpy(to
, from
, sizeof(DWORD
));
6352 static struct dec3n
dword_to_dec3n(DWORD d
)
6357 v
.y
= (d
& 0xffc00) >> 10;
6358 v
.z
= (d
& 0x3ff00000) >> 20;
6359 v
.w
= (d
& 0xc0000000) >> 30;
6364 static BOOL
weld_dec3n(void *to
, void *from
, FLOAT epsilon
)
6366 const UINT MAX_DEC3N
= 511;
6369 struct dec3n v1
= dword_to_dec3n(*d1
);
6370 struct dec3n v2
= dword_to_dec3n(*d2
);
6371 INT scaled_epsilon
= (INT
)(epsilon
* MAX_DEC3N
);
6372 INT diff_x
= abs(v1
.x
- v2
.x
);
6373 INT diff_y
= abs(v1
.y
- v2
.y
);
6374 INT diff_z
= abs(v1
.z
- v2
.z
);
6375 INT diff_w
= abs(v1
.w
- v2
.w
);
6376 INT max_abs_diff
= max(diff_x
, diff_y
);
6377 max_abs_diff
= max(diff_z
, max_abs_diff
);
6378 max_abs_diff
= max(diff_w
, max_abs_diff
);
6380 if (max_abs_diff
<= scaled_epsilon
)
6382 memcpy(to
, from
, sizeof(DWORD
));
6390 static BOOL
weld_float16_2(void *to
, void *from
, FLOAT epsilon
)
6392 D3DXFLOAT16
*v1_float16
= to
;
6393 D3DXFLOAT16
*v2_float16
= from
;
6397 const UINT NUM_ELEM
= 2;
6401 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6402 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6404 diff_x
= fabsf(v1
[0] - v2
[0]);
6405 diff_y
= fabsf(v1
[1] - v2
[1]);
6406 max_abs_diff
= max(diff_x
, diff_y
);
6408 if (max_abs_diff
<= epsilon
)
6410 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6418 static BOOL
weld_float16_4(void *to
, void *from
, FLOAT epsilon
)
6420 D3DXFLOAT16
*v1_float16
= to
;
6421 D3DXFLOAT16
*v2_float16
= from
;
6427 const UINT NUM_ELEM
= 4;
6431 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6432 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6434 diff_x
= fabsf(v1
[0] - v2
[0]);
6435 diff_y
= fabsf(v1
[1] - v2
[1]);
6436 diff_z
= fabsf(v1
[2] - v2
[2]);
6437 diff_w
= fabsf(v1
[3] - v2
[3]);
6438 max_abs_diff
= max(diff_x
, diff_y
);
6439 max_abs_diff
= max(diff_z
, max_abs_diff
);
6440 max_abs_diff
= max(diff_w
, max_abs_diff
);
6442 if (max_abs_diff
<= epsilon
)
6444 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6452 /* Sets the vertex components to the same value if they are within epsilon. */
6453 static BOOL
weld_component(void *to
, void *from
, D3DDECLTYPE type
, FLOAT epsilon
)
6455 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6456 BOOL fixme_once_unused
= FALSE
;
6457 BOOL fixme_once_unknown
= FALSE
;
6461 case D3DDECLTYPE_FLOAT1
:
6462 return weld_float1(to
, from
, epsilon
);
6464 case D3DDECLTYPE_FLOAT2
:
6465 return weld_float2(to
, from
, epsilon
);
6467 case D3DDECLTYPE_FLOAT3
:
6468 return weld_float3(to
, from
, epsilon
);
6470 case D3DDECLTYPE_FLOAT4
:
6471 return weld_float4(to
, from
, epsilon
);
6473 case D3DDECLTYPE_D3DCOLOR
:
6474 return weld_d3dcolor(to
, from
, epsilon
);
6476 case D3DDECLTYPE_UBYTE4
:
6477 return weld_ubyte4(to
, from
, epsilon
);
6479 case D3DDECLTYPE_SHORT2
:
6480 return weld_short2(to
, from
, epsilon
);
6482 case D3DDECLTYPE_SHORT4
:
6483 return weld_short4(to
, from
, epsilon
);
6485 case D3DDECLTYPE_UBYTE4N
:
6486 return weld_ubyte4n(to
, from
, epsilon
);
6488 case D3DDECLTYPE_SHORT2N
:
6489 return weld_short2n(to
, from
, epsilon
);
6491 case D3DDECLTYPE_SHORT4N
:
6492 return weld_short4n(to
, from
, epsilon
);
6494 case D3DDECLTYPE_USHORT2N
:
6495 return weld_ushort2n(to
, from
, epsilon
);
6497 case D3DDECLTYPE_USHORT4N
:
6498 return weld_ushort4n(to
, from
, epsilon
);
6500 case D3DDECLTYPE_UDEC3
:
6501 return weld_udec3(to
, from
, epsilon
);
6503 case D3DDECLTYPE_DEC3N
:
6504 return weld_dec3n(to
, from
, epsilon
);
6506 case D3DDECLTYPE_FLOAT16_2
:
6507 return weld_float16_2(to
, from
, epsilon
);
6509 case D3DDECLTYPE_FLOAT16_4
:
6510 return weld_float16_4(to
, from
, epsilon
);
6512 case D3DDECLTYPE_UNUSED
:
6513 if (!fixme_once_unused
++)
6514 FIXME("D3DDECLTYPE_UNUSED welding not implemented.\n");
6518 if (!fixme_once_unknown
++)
6519 FIXME("Welding of unknown declaration type %d is not implemented.\n", type
);
6526 static FLOAT
get_component_epsilon(const D3DVERTEXELEMENT9
*decl_ptr
, const D3DXWELDEPSILONS
*epsilons
)
6528 FLOAT epsilon
= 0.0f
;
6529 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6530 static BOOL fixme_once_blendindices
= FALSE
;
6531 static BOOL fixme_once_positiont
= FALSE
;
6532 static BOOL fixme_once_fog
= FALSE
;
6533 static BOOL fixme_once_depth
= FALSE
;
6534 static BOOL fixme_once_sample
= FALSE
;
6535 static BOOL fixme_once_unknown
= FALSE
;
6537 switch (decl_ptr
->Usage
)
6539 case D3DDECLUSAGE_POSITION
:
6540 epsilon
= epsilons
->Position
;
6542 case D3DDECLUSAGE_BLENDWEIGHT
:
6543 epsilon
= epsilons
->BlendWeights
;
6545 case D3DDECLUSAGE_NORMAL
:
6546 epsilon
= epsilons
->Normals
;
6548 case D3DDECLUSAGE_PSIZE
:
6549 epsilon
= epsilons
->PSize
;
6551 case D3DDECLUSAGE_TEXCOORD
:
6553 BYTE usage_index
= decl_ptr
->UsageIndex
;
6554 if (usage_index
> 7)
6556 epsilon
= epsilons
->Texcoords
[usage_index
];
6559 case D3DDECLUSAGE_TANGENT
:
6560 epsilon
= epsilons
->Tangent
;
6562 case D3DDECLUSAGE_BINORMAL
:
6563 epsilon
= epsilons
->Binormal
;
6565 case D3DDECLUSAGE_TESSFACTOR
:
6566 epsilon
= epsilons
->TessFactor
;
6568 case D3DDECLUSAGE_COLOR
:
6569 if (decl_ptr
->UsageIndex
== 0)
6570 epsilon
= epsilons
->Diffuse
;
6571 else if (decl_ptr
->UsageIndex
== 1)
6572 epsilon
= epsilons
->Specular
;
6576 case D3DDECLUSAGE_BLENDINDICES
:
6577 if (!fixme_once_blendindices
++)
6578 FIXME("D3DDECLUSAGE_BLENDINDICES welding not implemented.\n");
6580 case D3DDECLUSAGE_POSITIONT
:
6581 if (!fixme_once_positiont
++)
6582 FIXME("D3DDECLUSAGE_POSITIONT welding not implemented.\n");
6584 case D3DDECLUSAGE_FOG
:
6585 if (!fixme_once_fog
++)
6586 FIXME("D3DDECLUSAGE_FOG welding not implemented.\n");
6588 case D3DDECLUSAGE_DEPTH
:
6589 if (!fixme_once_depth
++)
6590 FIXME("D3DDECLUSAGE_DEPTH welding not implemented.\n");
6592 case D3DDECLUSAGE_SAMPLE
:
6593 if (!fixme_once_sample
++)
6594 FIXME("D3DDECLUSAGE_SAMPLE welding not implemented.\n");
6597 if (!fixme_once_unknown
++)
6598 FIXME("Unknown usage %x\n", decl_ptr
->Usage
);
6605 /* Helper function for reading a 32-bit index buffer. */
6606 static inline DWORD
read_ib(void *index_buffer
, BOOL indices_are_32bit
,
6609 if (indices_are_32bit
)
6611 DWORD
*indices
= index_buffer
;
6612 return indices
[index
];
6616 WORD
*indices
= index_buffer
;
6617 return indices
[index
];
6621 /* Helper function for writing to a 32-bit index buffer. */
6622 static inline void write_ib(void *index_buffer
, BOOL indices_are_32bit
,
6623 DWORD index
, DWORD value
)
6625 if (indices_are_32bit
)
6627 DWORD
*indices
= index_buffer
;
6628 indices
[index
] = value
;
6632 WORD
*indices
= index_buffer
;
6633 indices
[index
] = value
;
6637 /*************************************************************************
6638 * D3DXWeldVertices (D3DX9_36.@)
6640 * Welds together similar vertices. The similarity between vert-
6641 * ices can be the position and other components such as
6645 * mesh [I] Mesh which vertices will be welded together.
6646 * flags [I] D3DXWELDEPSILONSFLAGS specifying how to weld.
6647 * epsilons [I] How similar a component needs to be for welding.
6648 * adjacency [I] Which faces are adjacent to other faces.
6649 * adjacency_out [O] Updated adjacency after welding.
6650 * face_remap_out [O] Which faces the old faces have been mapped to.
6651 * vertex_remap_out [O] Which vertices the old vertices have been mapped to.
6655 * Failure: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
6658 * Attribute sorting not implemented.
6661 HRESULT WINAPI
D3DXWeldVertices(ID3DXMesh
*mesh
, DWORD flags
, const D3DXWELDEPSILONS
*epsilons
,
6662 const DWORD
*adjacency
, DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
6664 DWORD
*adjacency_generated
= NULL
;
6665 const DWORD
*adjacency_ptr
;
6666 DWORD
*attributes
= NULL
;
6667 const FLOAT DEFAULT_EPSILON
= 1.0e-6f
;
6670 void *indices
= NULL
;
6671 BOOL indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
6672 DWORD optimize_flags
;
6673 DWORD
*point_reps
= NULL
;
6674 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(mesh
);
6675 DWORD
*vertex_face_map
= NULL
;
6676 ID3DXBuffer
*vertex_remap
= NULL
;
6677 BYTE
*vertices
= NULL
;
6679 TRACE("(%p, %x, %p, %p, %p, %p, %p)\n", mesh
, flags
, epsilons
,
6680 adjacency
, adjacency_out
, face_remap_out
, vertex_remap_out
);
6684 WARN("No flags is undefined. Using D3DXWELDEPSILONS_WELDPARTIALMATCHES instead.\n");
6685 flags
= D3DXWELDEPSILONS_WELDPARTIALMATCHES
;
6688 if (adjacency
) /* Use supplied adjacency. */
6690 adjacency_ptr
= adjacency
;
6692 else /* Adjacency has to be generated. */
6694 adjacency_generated
= HeapAlloc(GetProcessHeap(), 0, 3 * This
->numfaces
* sizeof(*adjacency_generated
));
6695 if (!adjacency_generated
)
6697 ERR("Couldn't allocate memory for adjacency_generated.\n");
6701 hr
= mesh
->lpVtbl
->GenerateAdjacency(mesh
, DEFAULT_EPSILON
, adjacency_generated
);
6704 ERR("Couldn't generate adjacency.\n");
6707 adjacency_ptr
= adjacency_generated
;
6710 /* Point representation says which vertices can be replaced. */
6711 point_reps
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*point_reps
));
6715 ERR("Couldn't allocate memory for point_reps.\n");
6718 hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency_ptr
, point_reps
);
6721 ERR("ConvertAdjacencyToPointReps failed.\n");
6725 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
);
6728 ERR("Couldn't lock index buffer.\n");
6732 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, 0, &attributes
);
6735 ERR("Couldn't lock attribute buffer.\n");
6738 vertex_face_map
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*vertex_face_map
));
6739 if (!vertex_face_map
)
6742 ERR("Couldn't allocate memory for vertex_face_map.\n");
6745 /* Build vertex face map, so that a vertex's face can be looked up. */
6746 for (i
= 0; i
< This
->numfaces
; i
++)
6749 for (j
= 0; j
< 3; j
++)
6751 DWORD index
= read_ib(indices
, indices_are_32bit
, 3*i
+ j
);
6752 vertex_face_map
[index
] = i
;
6756 if (flags
& D3DXWELDEPSILONS_WELDPARTIALMATCHES
)
6758 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void**)&vertices
);
6761 ERR("Couldn't lock vertex buffer.\n");
6764 /* For each vertex that can be removed, compare its vertex components
6765 * with the vertex components from the vertex that can replace it. A
6766 * vertex is only fully replaced if all the components match and the
6767 * flag D3DXWELDEPSILONS_DONOTREMOVEVERTICES is not set, and they
6768 * belong to the same attribute group. Otherwise the vertex components
6769 * that are within epsilon are set to the same value.
6771 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
6773 D3DVERTEXELEMENT9
*decl_ptr
;
6774 DWORD vertex_size
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
6775 DWORD num_vertex_components
;
6778 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
6780 for (decl_ptr
= This
->cached_declaration
, num_vertex_components
= 0; decl_ptr
->Stream
!= 0xFF; decl_ptr
++, num_vertex_components
++)
6782 BYTE
*to
= &vertices
[vertex_size
*index
+ decl_ptr
->Offset
];
6783 BYTE
*from
= &vertices
[vertex_size
*point_reps
[index
] + decl_ptr
->Offset
];
6784 FLOAT epsilon
= get_component_epsilon(decl_ptr
, epsilons
);
6786 /* Don't weld self */
6787 if (index
== point_reps
[index
])
6793 if (weld_component(to
, from
, decl_ptr
->Type
, epsilon
))
6797 all_match
= (num_vertex_components
== matches
);
6798 if (all_match
&& !(flags
& D3DXWELDEPSILONS_DONOTREMOVEVERTICES
))
6800 DWORD to_face
= vertex_face_map
[index
];
6801 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
6802 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
6804 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
6807 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6810 else if (flags
& D3DXWELDEPSILONS_WELDALL
)
6812 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
6814 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
6815 DWORD to_face
= vertex_face_map
[index
];
6816 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
6817 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
6819 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
6822 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
6824 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6827 /* Compact mesh using OptimizeInplace */
6828 optimize_flags
= D3DXMESHOPT_COMPACT
;
6829 hr
= mesh
->lpVtbl
->OptimizeInplace(mesh
, optimize_flags
, adjacency_ptr
, adjacency_out
, face_remap_out
, vertex_remap_out
);
6832 ERR("Couldn't compact mesh.\n");
6838 HeapFree(GetProcessHeap(), 0, adjacency_generated
);
6839 HeapFree(GetProcessHeap(), 0, point_reps
);
6840 HeapFree(GetProcessHeap(), 0, vertex_face_map
);
6841 if (attributes
) mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
6842 if (indices
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6843 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
6844 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6849 /*************************************************************************
6850 * D3DXOptimizeFaces (D3DX9_36.@)
6852 * Re-orders the faces so the vertex cache is used optimally.
6855 * indices [I] Pointer to an index buffer belonging to a mesh.
6856 * num_faces [I] Number of faces in the mesh.
6857 * num_vertices [I] Number of vertices in the mesh.
6858 * indices_are_32bit [I] Specifies whether indices are 32- or 16-bit.
6859 * face_remap [I/O] The new order the faces should be drawn in.
6863 * Failure: D3DERR_INVALIDCALL.
6866 * The face re-ordering does not use the vertex cache optimally.
6869 HRESULT WINAPI
D3DXOptimizeFaces(LPCVOID indices
,
6872 BOOL indices_are_32bit
,
6876 UINT j
= num_faces
- 1;
6877 UINT limit_16_bit
= 2 << 15; /* According to MSDN */
6878 HRESULT hr
= D3D_OK
;
6880 FIXME("(%p, %u, %u, %s, %p): semi-stub. Face order will not be optimal.\n",
6881 indices
, num_faces
, num_vertices
,
6882 indices_are_32bit
? "TRUE" : "FALSE", face_remap
);
6884 if (!indices_are_32bit
&& num_faces
>= limit_16_bit
)
6886 WARN("Number of faces must be less than %d when using 16-bit indices.\n",
6888 hr
= D3DERR_INVALIDCALL
;
6894 WARN("Face remap pointer is NULL.\n");
6895 hr
= D3DERR_INVALIDCALL
;
6899 /* The faces are drawn in reverse order for simple meshes. This ordering
6900 * is not optimal for complicated meshes, but will not break anything
6901 * either. The ordering should be changed to take advantage of the vertex
6902 * cache on the graphics card.
6904 * TODO Re-order to take advantage of vertex cache.
6906 for (i
= 0; i
< num_faces
; i
++)
6908 face_remap
[i
] = j
--;