2 * Mesh operations specific to D3DX9.
4 * Copyright (C) 2005 Henri Verbeet
5 * Copyright (C) 2006 Ivan Gyurdiev
6 * Copyright (C) 2009 David Adam
7 * Copyright (C) 2010 Tony Wasserka
8 * Copyright (C) 2011 Dylan Smith
9 * Copyright (C) 2011 Michael Mc Donnell
10 * Copyright (C) 2013 Christian Costa
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "d3dx9_36_private.h"
38 #include "wine/list.h"
40 #define fmax(a, b) ((a) > (b) ? (a) : (b))
42 typedef struct ID3DXMeshImpl
44 ID3DXMesh ID3DXMesh_iface
;
51 IDirect3DDevice9
*device
;
52 D3DVERTEXELEMENT9 cached_declaration
[MAX_FVF_DECL_SIZE
];
53 IDirect3DVertexDeclaration9
*vertex_declaration
;
54 UINT vertex_declaration_size
;
56 IDirect3DVertexBuffer9
*vertex_buffer
;
57 IDirect3DIndexBuffer9
*index_buffer
;
59 int attrib_buffer_lock_count
;
60 DWORD attrib_table_size
;
61 D3DXATTRIBUTERANGE
*attrib_table
;
64 const UINT d3dx_decltype_size
[] =
66 /* D3DDECLTYPE_FLOAT1 */ sizeof(FLOAT
),
67 /* D3DDECLTYPE_FLOAT2 */ sizeof(D3DXVECTOR2
),
68 /* D3DDECLTYPE_FLOAT3 */ sizeof(D3DXVECTOR3
),
69 /* D3DDECLTYPE_FLOAT4 */ sizeof(D3DXVECTOR4
),
70 /* D3DDECLTYPE_D3DCOLOR */ sizeof(D3DCOLOR
),
71 /* D3DDECLTYPE_UBYTE4 */ 4 * sizeof(BYTE
),
72 /* D3DDECLTYPE_SHORT2 */ 2 * sizeof(SHORT
),
73 /* D3DDECLTYPE_SHORT4 */ 4 * sizeof(SHORT
),
74 /* D3DDECLTYPE_UBYTE4N */ 4 * sizeof(BYTE
),
75 /* D3DDECLTYPE_SHORT2N */ 2 * sizeof(SHORT
),
76 /* D3DDECLTYPE_SHORT4N */ 4 * sizeof(SHORT
),
77 /* D3DDECLTYPE_USHORT2N */ 2 * sizeof(USHORT
),
78 /* D3DDECLTYPE_USHORT4N */ 4 * sizeof(USHORT
),
79 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
80 /* D3DDECLTYPE_DEC3N */ 4,
81 /* D3DDECLTYPE_FLOAT16_2 */ 2 * sizeof(D3DXFLOAT16
),
82 /* D3DDECLTYPE_FLOAT16_4 */ 4 * sizeof(D3DXFLOAT16
),
85 static inline ID3DXMeshImpl
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
87 return CONTAINING_RECORD(iface
, ID3DXMeshImpl
, ID3DXMesh_iface
);
90 static HRESULT WINAPI
ID3DXMeshImpl_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, LPVOID
*object
)
92 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), object
);
94 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
95 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
96 IsEqualGUID(riid
, &IID_ID3DXMesh
))
98 iface
->lpVtbl
->AddRef(iface
);
103 WARN("Interface %s not found.\n", debugstr_guid(riid
));
105 return E_NOINTERFACE
;
108 static ULONG WINAPI
ID3DXMeshImpl_AddRef(ID3DXMesh
*iface
)
110 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
112 TRACE("(%p)->(): AddRef from %d\n", This
, This
->ref
);
114 return InterlockedIncrement(&This
->ref
);
117 static ULONG WINAPI
ID3DXMeshImpl_Release(ID3DXMesh
*iface
)
119 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
120 ULONG ref
= InterlockedDecrement(&This
->ref
);
122 TRACE("(%p)->(): Release from %d\n", This
, ref
+ 1);
126 IDirect3DIndexBuffer9_Release(This
->index_buffer
);
127 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
128 if (This
->vertex_declaration
)
129 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
130 IDirect3DDevice9_Release(This
->device
);
131 HeapFree(GetProcessHeap(), 0, This
->attrib_buffer
);
132 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
133 HeapFree(GetProcessHeap(), 0, This
);
139 /*** ID3DXBaseMesh ***/
140 static HRESULT WINAPI
ID3DXMeshImpl_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
142 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
148 TRACE("(%p)->(%u)\n", This
, attrib_id
);
150 if (!This
->vertex_declaration
)
152 WARN("Can't draw a mesh with an invalid vertex declaration.\n");
156 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
158 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
159 if (FAILED(hr
)) return hr
;
160 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
161 if (FAILED(hr
)) return hr
;
162 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
163 if (FAILED(hr
)) return hr
;
165 while (face_end
< This
->numfaces
)
167 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
169 if (This
->attrib_buffer
[face_start
] == attrib_id
)
172 if (face_start
>= This
->numfaces
)
174 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
176 if (This
->attrib_buffer
[face_end
] != attrib_id
)
180 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
181 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
182 if (FAILED(hr
)) return hr
;
188 static DWORD WINAPI
ID3DXMeshImpl_GetNumFaces(ID3DXMesh
*iface
)
190 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
192 TRACE("(%p)\n", This
);
194 return This
->numfaces
;
197 static DWORD WINAPI
ID3DXMeshImpl_GetNumVertices(ID3DXMesh
*iface
)
199 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
201 TRACE("(%p)\n", This
);
203 return This
->numvertices
;
206 static DWORD WINAPI
ID3DXMeshImpl_GetFVF(ID3DXMesh
*iface
)
208 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
210 TRACE("(%p)\n", This
);
215 static void copy_declaration(D3DVERTEXELEMENT9
*dst
, const D3DVERTEXELEMENT9
*src
, UINT num_elem
)
217 memcpy(dst
, src
, num_elem
* sizeof(*src
));
220 static HRESULT WINAPI
ID3DXMeshImpl_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
222 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
224 TRACE("(%p)\n", This
);
226 if (declaration
== NULL
) return D3DERR_INVALIDCALL
;
228 copy_declaration(declaration
, This
->cached_declaration
, This
->num_elem
);
233 static DWORD WINAPI
ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh
*iface
)
235 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
237 TRACE("iface (%p)\n", This
);
239 return This
->vertex_declaration_size
;
242 static DWORD WINAPI
ID3DXMeshImpl_GetOptions(ID3DXMesh
*iface
)
244 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
246 TRACE("(%p)\n", This
);
248 return This
->options
;
251 static HRESULT WINAPI
ID3DXMeshImpl_GetDevice(struct ID3DXMesh
*iface
, struct IDirect3DDevice9
**device
)
253 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
255 TRACE("(%p)->(%p)\n", This
, device
);
257 if (device
== NULL
) return D3DERR_INVALIDCALL
;
258 *device
= This
->device
;
259 IDirect3DDevice9_AddRef(This
->device
);
264 static HRESULT WINAPI
ID3DXMeshImpl_CloneMeshFVF(struct ID3DXMesh
*iface
, DWORD options
, DWORD fvf
,
265 struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh
)
267 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
269 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
271 TRACE("(%p)->(%x,%x,%p,%p)\n", This
, options
, fvf
, device
, clone_mesh
);
273 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
274 if (FAILED(hr
)) return hr
;
276 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
279 static FLOAT
scale_clamp_ubyten(FLOAT value
)
281 value
= value
* UCHAR_MAX
;
289 if (value
> UCHAR_MAX
) /* Clamp at 255 */
296 static FLOAT
scale_clamp_shortn(FLOAT value
)
298 value
= value
* SHRT_MAX
;
300 /* The tests show that the range is SHRT_MIN + 1 to SHRT_MAX. */
301 if (value
<= SHRT_MIN
)
305 else if (value
> SHRT_MAX
)
315 static FLOAT
scale_clamp_ushortn(FLOAT value
)
317 value
= value
* USHRT_MAX
;
325 if (value
> USHRT_MAX
) /* Clamp at 65535 */
332 static INT
simple_round(FLOAT value
)
334 int res
= (INT
)(value
+ 0.5f
);
339 static void convert_float4(BYTE
*dst
, CONST D3DXVECTOR4
*src
, D3DDECLTYPE type_dst
)
341 BOOL fixme_once
= FALSE
;
345 case D3DDECLTYPE_FLOAT1
:
347 FLOAT
*dst_ptr
= (FLOAT
*)dst
;
351 case D3DDECLTYPE_FLOAT2
:
353 D3DXVECTOR2
*dst_ptr
= (D3DXVECTOR2
*)dst
;
358 case D3DDECLTYPE_FLOAT3
:
360 D3DXVECTOR3
*dst_ptr
= (D3DXVECTOR3
*)dst
;
366 case D3DDECLTYPE_FLOAT4
:
368 D3DXVECTOR4
*dst_ptr
= (D3DXVECTOR4
*)dst
;
375 case D3DDECLTYPE_D3DCOLOR
:
377 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
378 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
379 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
380 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
383 case D3DDECLTYPE_UBYTE4
:
385 dst
[0] = src
->x
< 0.0f
? 0 : (BYTE
)simple_round(src
->x
);
386 dst
[1] = src
->y
< 0.0f
? 0 : (BYTE
)simple_round(src
->y
);
387 dst
[2] = src
->z
< 0.0f
? 0 : (BYTE
)simple_round(src
->z
);
388 dst
[3] = src
->w
< 0.0f
? 0 : (BYTE
)simple_round(src
->w
);
391 case D3DDECLTYPE_SHORT2
:
393 SHORT
*dst_ptr
= (SHORT
*)dst
;
394 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
395 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
398 case D3DDECLTYPE_SHORT4
:
400 SHORT
*dst_ptr
= (SHORT
*)dst
;
401 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
402 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
403 dst_ptr
[2] = (SHORT
)simple_round(src
->z
);
404 dst_ptr
[3] = (SHORT
)simple_round(src
->w
);
407 case D3DDECLTYPE_UBYTE4N
:
409 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
410 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
411 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
412 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
415 case D3DDECLTYPE_SHORT2N
:
417 SHORT
*dst_ptr
= (SHORT
*)dst
;
418 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
419 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
422 case D3DDECLTYPE_SHORT4N
:
424 SHORT
*dst_ptr
= (SHORT
*)dst
;
425 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
426 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
427 dst_ptr
[2] = (SHORT
)simple_round(scale_clamp_shortn(src
->z
));
428 dst_ptr
[3] = (SHORT
)simple_round(scale_clamp_shortn(src
->w
));
431 case D3DDECLTYPE_USHORT2N
:
433 USHORT
*dst_ptr
= (USHORT
*)dst
;
434 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
435 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
438 case D3DDECLTYPE_USHORT4N
:
440 USHORT
*dst_ptr
= (USHORT
*)dst
;
441 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
442 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
443 dst_ptr
[2] = (USHORT
)simple_round(scale_clamp_ushortn(src
->z
));
444 dst_ptr
[3] = (USHORT
)simple_round(scale_clamp_ushortn(src
->w
));
447 case D3DDECLTYPE_FLOAT16_2
:
449 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 2);
452 case D3DDECLTYPE_FLOAT16_4
:
454 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 4);
459 FIXME("Conversion from D3DDECLTYPE_FLOAT4 to %d not implemented.\n", type_dst
);
464 static void convert_component(BYTE
*dst
, BYTE
*src
, D3DDECLTYPE type_dst
, D3DDECLTYPE type_src
)
466 BOOL fixme_once
= FALSE
;
470 case D3DDECLTYPE_FLOAT1
:
472 FLOAT
*src_ptr
= (FLOAT
*)src
;
473 D3DXVECTOR4 src_float4
= {*src_ptr
, 0.0f
, 0.0f
, 1.0f
};
474 convert_float4(dst
, &src_float4
, type_dst
);
477 case D3DDECLTYPE_FLOAT2
:
479 D3DXVECTOR2
*src_ptr
= (D3DXVECTOR2
*)src
;
480 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, 0.0f
, 1.0f
};
481 convert_float4(dst
, &src_float4
, type_dst
);
484 case D3DDECLTYPE_FLOAT3
:
486 D3DXVECTOR3
*src_ptr
= (D3DXVECTOR3
*)src
;
487 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, 1.0f
};
488 convert_float4(dst
, &src_float4
, type_dst
);
491 case D3DDECLTYPE_FLOAT4
:
493 D3DXVECTOR4
*src_ptr
= (D3DXVECTOR4
*)src
;
494 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, src_ptr
->w
};
495 convert_float4(dst
, &src_float4
, type_dst
);
498 case D3DDECLTYPE_D3DCOLOR
:
500 D3DXVECTOR4 src_float4
=
502 (FLOAT
)src
[2]/UCHAR_MAX
,
503 (FLOAT
)src
[1]/UCHAR_MAX
,
504 (FLOAT
)src
[0]/UCHAR_MAX
,
505 (FLOAT
)src
[3]/UCHAR_MAX
507 convert_float4(dst
, &src_float4
, type_dst
);
510 case D3DDECLTYPE_UBYTE4
:
512 D3DXVECTOR4 src_float4
= {src
[0], src
[1], src
[2], src
[3]};
513 convert_float4(dst
, &src_float4
, type_dst
);
516 case D3DDECLTYPE_SHORT2
:
518 SHORT
*src_ptr
= (SHORT
*)src
;
519 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], 0.0f
, 1.0f
};
520 convert_float4(dst
, &src_float4
, type_dst
);
523 case D3DDECLTYPE_SHORT4
:
525 SHORT
*src_ptr
= (SHORT
*)src
;
526 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], src_ptr
[2], src_ptr
[3]};
527 convert_float4(dst
, &src_float4
, type_dst
);
530 case D3DDECLTYPE_UBYTE4N
:
532 D3DXVECTOR4 src_float4
=
534 (FLOAT
)src
[0]/UCHAR_MAX
,
535 (FLOAT
)src
[1]/UCHAR_MAX
,
536 (FLOAT
)src
[2]/UCHAR_MAX
,
537 (FLOAT
)src
[3]/UCHAR_MAX
539 convert_float4(dst
, &src_float4
, type_dst
);
542 case D3DDECLTYPE_SHORT2N
:
544 SHORT
*src_ptr
= (SHORT
*)src
;
545 D3DXVECTOR4 src_float4
= {(FLOAT
)src_ptr
[0]/SHRT_MAX
, (FLOAT
)src_ptr
[1]/SHRT_MAX
, 0.0f
, 1.0f
};
546 convert_float4(dst
, &src_float4
, type_dst
);
549 case D3DDECLTYPE_SHORT4N
:
551 SHORT
*src_ptr
= (SHORT
*)src
;
552 D3DXVECTOR4 src_float4
=
554 (FLOAT
)src_ptr
[0]/SHRT_MAX
,
555 (FLOAT
)src_ptr
[1]/SHRT_MAX
,
556 (FLOAT
)src_ptr
[2]/SHRT_MAX
,
557 (FLOAT
)src_ptr
[3]/SHRT_MAX
559 convert_float4(dst
, &src_float4
, type_dst
);
562 case D3DDECLTYPE_FLOAT16_2
:
564 D3DXVECTOR4 src_float4
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
565 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 2);
566 convert_float4(dst
, &src_float4
, type_dst
);
569 case D3DDECLTYPE_FLOAT16_4
:
571 D3DXVECTOR4 src_float4
;
572 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 4);
573 convert_float4(dst
, &src_float4
, type_dst
);
578 FIXME("Conversion of D3DDECLTYPE %d to %d not implemented.\n", type_src
, type_dst
);
583 static INT
get_equivalent_declaration_index(D3DVERTEXELEMENT9 orig_declaration
, D3DVERTEXELEMENT9
*declaration
)
587 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
589 if (orig_declaration
.Usage
== declaration
[i
].Usage
590 && orig_declaration
.UsageIndex
== declaration
[i
].UsageIndex
)
599 static HRESULT
convert_vertex_buffer(ID3DXMesh
*mesh_dst
, ID3DXMesh
*mesh_src
)
602 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
603 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
607 UINT num_vertices
= mesh_src
->lpVtbl
->GetNumVertices(mesh_src
);
608 UINT dst_vertex_size
= mesh_dst
->lpVtbl
->GetNumBytesPerVertex(mesh_dst
);
609 UINT src_vertex_size
= mesh_src
->lpVtbl
->GetNumBytesPerVertex(mesh_src
);
611 hr
= mesh_src
->lpVtbl
->GetDeclaration(mesh_src
, orig_declaration
);
612 if (FAILED(hr
)) return hr
;
613 hr
= mesh_dst
->lpVtbl
->GetDeclaration(mesh_dst
, declaration
);
614 if (FAILED(hr
)) return hr
;
616 hr
= mesh_src
->lpVtbl
->LockVertexBuffer(mesh_src
, D3DLOCK_READONLY
, (void**)&vb_src
);
617 if (FAILED(hr
)) goto cleanup
;
618 hr
= mesh_dst
->lpVtbl
->LockVertexBuffer(mesh_dst
, 0, (void**)&vb_dst
);
619 if (FAILED(hr
)) goto cleanup
;
621 /* Clear all new fields by clearing the entire vertex buffer. */
622 memset(vb_dst
, 0, num_vertices
* dst_vertex_size
);
624 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++)
626 INT eq_idx
= get_equivalent_declaration_index(orig_declaration
[i
], declaration
);
631 for (j
= 0; j
< num_vertices
; j
++)
633 UINT idx_dst
= dst_vertex_size
* j
+ declaration
[eq_idx
].Offset
;
634 UINT idx_src
= src_vertex_size
* j
+ orig_declaration
[i
].Offset
;
635 UINT type_size
= d3dx_decltype_size
[orig_declaration
[i
].Type
];
637 if (orig_declaration
[i
].Type
== declaration
[eq_idx
].Type
)
638 memcpy(&vb_dst
[idx_dst
], &vb_src
[idx_src
], type_size
);
640 convert_component(&vb_dst
[idx_dst
], &vb_src
[idx_src
], declaration
[eq_idx
].Type
, orig_declaration
[i
].Type
);
647 if (vb_dst
) mesh_dst
->lpVtbl
->UnlockVertexBuffer(mesh_dst
);
648 if (vb_src
) mesh_src
->lpVtbl
->UnlockVertexBuffer(mesh_src
);
653 static BOOL
declaration_equals(CONST D3DVERTEXELEMENT9
*declaration1
, CONST D3DVERTEXELEMENT9
*declaration2
)
655 UINT size1
= 0, size2
= 0;
657 /* Find the size of each declaration */
658 while (declaration1
[size1
].Stream
!= 0xff) size1
++;
659 while (declaration2
[size2
].Stream
!= 0xff) size2
++;
661 /* If not same size then they are definitely not equal */
665 /* Check that all components are the same */
666 if (memcmp(declaration1
, declaration2
, size1
*sizeof(*declaration1
)) == 0)
672 static HRESULT WINAPI
ID3DXMeshImpl_CloneMesh(struct ID3DXMesh
*iface
, DWORD options
,
673 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh_out
)
675 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
676 ID3DXMeshImpl
*cloned_this
;
677 ID3DXMesh
*clone_mesh
;
678 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
679 void *data_in
, *data_out
;
682 BOOL same_declaration
;
684 TRACE("(%p)->(%x,%p,%p,%p)\n", This
, options
, declaration
, device
, clone_mesh_out
);
687 return D3DERR_INVALIDCALL
;
689 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
690 if (FAILED(hr
)) return hr
;
692 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
693 declaration
, device
, &clone_mesh
);
694 if (FAILED(hr
)) return hr
;
696 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
697 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
698 same_declaration
= declaration_equals(declaration
, orig_declaration
);
700 if (options
& D3DXMESH_VB_SHARE
) {
701 if (!same_declaration
) {
702 hr
= D3DERR_INVALIDCALL
;
705 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
706 /* FIXME: refactor to avoid creating a new vertex buffer */
707 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
708 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
709 } else if (same_declaration
) {
710 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
711 if (FAILED(hr
)) goto error
;
712 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, 0, &data_out
);
714 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
717 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
718 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
719 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
721 hr
= convert_vertex_buffer(clone_mesh
, iface
);
722 if (FAILED(hr
)) goto error
;
725 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
726 if (FAILED(hr
)) goto error
;
727 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, 0, &data_out
);
729 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
732 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
734 if (options
& D3DXMESH_32BIT
) {
735 for (i
= 0; i
< This
->numfaces
* 3; i
++)
736 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
738 for (i
= 0; i
< This
->numfaces
* 3; i
++)
739 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
742 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
744 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
745 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
747 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
749 if (This
->attrib_table_size
)
751 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
752 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
753 if (!cloned_this
->attrib_table
) {
757 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
760 *clone_mesh_out
= clone_mesh
;
764 IUnknown_Release(clone_mesh
);
768 static HRESULT WINAPI
ID3DXMeshImpl_GetVertexBuffer(struct ID3DXMesh
*iface
,
769 struct IDirect3DVertexBuffer9
**vertex_buffer
)
771 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
773 TRACE("(%p)->(%p)\n", This
, vertex_buffer
);
775 if (vertex_buffer
== NULL
) return D3DERR_INVALIDCALL
;
776 *vertex_buffer
= This
->vertex_buffer
;
777 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
782 static HRESULT WINAPI
ID3DXMeshImpl_GetIndexBuffer(struct ID3DXMesh
*iface
,
783 struct IDirect3DIndexBuffer9
**index_buffer
)
785 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
787 TRACE("(%p)->(%p)\n", This
, index_buffer
);
789 if (index_buffer
== NULL
) return D3DERR_INVALIDCALL
;
790 *index_buffer
= This
->index_buffer
;
791 IDirect3DIndexBuffer9_AddRef(This
->index_buffer
);
796 static HRESULT WINAPI
ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
798 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
800 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
802 return IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, data
, flags
);
805 static HRESULT WINAPI
ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh
*iface
)
807 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
809 TRACE("(%p)\n", This
);
811 return IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
814 static HRESULT WINAPI
ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
816 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
818 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
820 return IDirect3DIndexBuffer9_Lock(This
->index_buffer
, 0, 0, data
, flags
);
823 static HRESULT WINAPI
ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh
*iface
)
825 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
827 TRACE("(%p)\n", This
);
829 return IDirect3DIndexBuffer9_Unlock(This
->index_buffer
);
832 static HRESULT WINAPI
ID3DXMeshImpl_GetAttributeTable(ID3DXMesh
*iface
, D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
834 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
836 TRACE("(%p)->(%p,%p)\n", This
, attrib_table
, attrib_table_size
);
838 if (attrib_table_size
)
839 *attrib_table_size
= This
->attrib_table_size
;
842 CopyMemory(attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*attrib_table
));
857 struct edge_face
*entries
;
860 /* Builds up a map of which face a new edge belongs to. That way the adjacency
861 * of another edge can be looked up. An edge has an adjacent face if there
862 * is an edge going in the opposite direction in the map. For example if the
863 * edge (v1, v2) belongs to face 4, and there is a mapping (v2, v1)->7, then
864 * face 4 and 7 are adjacent.
866 * Each edge might have been replaced with another edge, or none at all. There
867 * is at most one edge to face mapping, i.e. an edge can only belong to one
870 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
)
875 edge_face_map
->lists
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->lists
));
876 if (!edge_face_map
->lists
) return E_OUTOFMEMORY
;
878 edge_face_map
->entries
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->entries
));
879 if (!edge_face_map
->entries
) return E_OUTOFMEMORY
;
882 /* Initialize all lists */
883 for (i
= 0; i
< 3 * num_faces
; i
++)
885 list_init(&edge_face_map
->lists
[i
]);
887 /* Build edge face mapping */
888 for (face
= 0; face
< num_faces
; face
++)
890 for (edge
= 0; edge
< 3; edge
++)
892 DWORD v1
= index_buffer
[3*face
+ edge
];
893 DWORD v2
= index_buffer
[3*face
+ (edge
+1)%3];
894 DWORD new_v1
= point_reps
[v1
]; /* What v1 has been replaced with */
895 DWORD new_v2
= point_reps
[v2
];
897 if (v1
!= v2
) /* Only map non-collapsed edges */
900 edge_face_map
->entries
[i
].v2
= new_v2
;
901 edge_face_map
->entries
[i
].face
= face
;
902 list_add_head(&edge_face_map
->lists
[new_v1
], &edge_face_map
->entries
[i
].entry
);
910 static DWORD
find_adjacent_face(struct edge_face_map
*edge_face_map
, DWORD vertex1
, DWORD vertex2
, CONST DWORD num_faces
)
912 struct edge_face
*edge_face_ptr
;
914 LIST_FOR_EACH_ENTRY(edge_face_ptr
, &edge_face_map
->lists
[vertex2
], struct edge_face
, entry
)
916 if (edge_face_ptr
->v2
== vertex1
)
917 return edge_face_ptr
->face
;
923 static DWORD
*generate_identity_point_reps(DWORD num_vertices
)
925 DWORD
*id_point_reps
;
928 id_point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*id_point_reps
));
932 for (i
= 0; i
< num_vertices
; i
++)
934 id_point_reps
[i
] = i
;
937 return id_point_reps
;
940 static HRESULT WINAPI
ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
, CONST DWORD
*point_reps
, DWORD
*adjacency
)
942 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
944 DWORD num_faces
= iface
->lpVtbl
->GetNumFaces(iface
);
945 DWORD num_vertices
= iface
->lpVtbl
->GetNumVertices(iface
);
946 DWORD options
= iface
->lpVtbl
->GetOptions(iface
);
947 BOOL indices_are_16_bit
= !(options
& D3DXMESH_32BIT
);
952 struct edge_face_map edge_face_map
= {0};
953 CONST DWORD
*point_reps_ptr
= NULL
;
954 DWORD
*id_point_reps
= NULL
;
956 TRACE("(%p)->(%p,%p)\n", This
, point_reps
, adjacency
);
958 if (!adjacency
) return D3DERR_INVALIDCALL
;
960 if (!point_reps
) /* Identity point reps */
962 id_point_reps
= generate_identity_point_reps(num_vertices
);
969 point_reps_ptr
= id_point_reps
;
973 point_reps_ptr
= point_reps
;
976 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &ib_ptr
);
977 if (FAILED(hr
)) goto cleanup
;
979 if (indices_are_16_bit
)
981 /* Widen 16 bit to 32 bit */
983 WORD
*ib_16bit
= ib_ptr
;
984 ib
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(DWORD
));
990 for (i
= 0; i
< 3 * num_faces
; i
++)
1000 hr
= init_edge_face_map(&edge_face_map
, ib
, point_reps_ptr
, num_faces
);
1001 if (FAILED(hr
)) goto cleanup
;
1003 /* Create adjacency */
1004 for (face
= 0; face
< num_faces
; face
++)
1006 for (edge
= 0; edge
< 3; edge
++)
1008 DWORD v1
= ib
[3*face
+ edge
];
1009 DWORD v2
= ib
[3*face
+ (edge
+1)%3];
1010 DWORD new_v1
= point_reps_ptr
[v1
];
1011 DWORD new_v2
= point_reps_ptr
[v2
];
1014 adj_face
= find_adjacent_face(&edge_face_map
, new_v1
, new_v2
, num_faces
);
1015 adjacency
[3*face
+ edge
] = adj_face
;
1021 HeapFree(GetProcessHeap(), 0, id_point_reps
);
1022 if (indices_are_16_bit
) HeapFree(GetProcessHeap(), 0, ib
);
1023 HeapFree(GetProcessHeap(), 0, edge_face_map
.lists
);
1024 HeapFree(GetProcessHeap(), 0, edge_face_map
.entries
);
1025 if(ib_ptr
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1029 /* ConvertAdjacencyToPointReps helper function.
1031 * Goes around the edges of each face and replaces the vertices in any adjacent
1032 * face's edge with its own vertices(if its vertices have a lower index). This
1033 * way as few as possible low index vertices are shared among the faces. The
1034 * re-ordered index buffer is stored in new_indices.
1036 * The vertices in a point representation must be ordered sequentially, e.g.
1037 * index 5 holds the index of the vertex that replaces vertex 5, i.e. if
1038 * vertex 5 is replaced by vertex 3 then index 5 would contain 3. If no vertex
1039 * replaces it, then it contains the same number as the index itself, e.g.
1040 * index 5 would contain 5. */
1041 static HRESULT
propagate_face_vertices(CONST DWORD
*adjacency
, DWORD
*point_reps
,
1042 CONST DWORD
*indices
, DWORD
*new_indices
,
1043 CONST DWORD face
, CONST DWORD numfaces
)
1045 const unsigned int VERTS_PER_FACE
= 3;
1046 DWORD edge
, opp_edge
;
1047 DWORD face_base
= VERTS_PER_FACE
* face
;
1049 for (edge
= 0; edge
< VERTS_PER_FACE
; edge
++)
1051 DWORD adj_face
= adjacency
[face_base
+ edge
];
1052 DWORD adj_face_base
;
1054 if (adj_face
== -1) /* No adjacent face. */
1056 else if (adj_face
>= numfaces
)
1058 /* This throws exception on Windows */
1059 WARN("Index out of bounds. Got %d expected less than %d.\n",
1060 adj_face
, numfaces
);
1061 return D3DERR_INVALIDCALL
;
1063 adj_face_base
= 3 * adj_face
;
1065 /* Find opposite edge in adjacent face. */
1066 for (opp_edge
= 0; opp_edge
< VERTS_PER_FACE
; opp_edge
++)
1068 DWORD opp_edge_index
= adj_face_base
+ opp_edge
;
1069 if (adjacency
[opp_edge_index
] == face
)
1070 break; /* Found opposite edge. */
1073 /* Replaces vertices in opposite edge with vertices from current edge. */
1074 for (i
= 0; i
< 2; i
++)
1076 DWORD from
= face_base
+ (edge
+ (1 - i
)) % VERTS_PER_FACE
;
1077 DWORD to
= adj_face_base
+ (opp_edge
+ i
) % VERTS_PER_FACE
;
1079 /* Propagate lowest index. */
1080 if (new_indices
[to
] > new_indices
[from
])
1082 new_indices
[to
] = new_indices
[from
];
1083 point_reps
[indices
[to
]] = new_indices
[from
];
1091 static HRESULT WINAPI
ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
, CONST DWORD
*adjacency
, DWORD
*point_reps
)
1096 DWORD
*indices
= NULL
;
1097 WORD
*indices_16bit
= NULL
;
1098 DWORD
*new_indices
= NULL
;
1099 const unsigned int VERTS_PER_FACE
= 3;
1101 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1103 TRACE("(%p)->(%p,%p)\n", This
, adjacency
, point_reps
);
1107 WARN("NULL adjacency.\n");
1108 hr
= D3DERR_INVALIDCALL
;
1114 WARN("NULL point_reps.\n");
1115 hr
= D3DERR_INVALIDCALL
;
1119 /* Should never happen as CreateMesh does not allow meshes with 0 faces */
1120 if (This
->numfaces
== 0)
1122 ERR("Number of faces was zero.\n");
1123 hr
= D3DERR_INVALIDCALL
;
1127 new_indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1134 if (This
->options
& D3DXMESH_32BIT
)
1136 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1137 if (FAILED(hr
)) goto cleanup
;
1138 memcpy(new_indices
, indices
, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1142 /* Make a widening copy of indices_16bit into indices and new_indices
1143 * in order to re-use the helper function */
1144 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices_16bit
);
1145 if (FAILED(hr
)) goto cleanup
;
1146 indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1152 for (i
= 0; i
< VERTS_PER_FACE
* This
->numfaces
; i
++)
1154 new_indices
[i
] = indices_16bit
[i
];
1155 indices
[i
] = indices_16bit
[i
];
1159 /* Vertices are ordered sequentially in the point representation. */
1160 for (i
= 0; i
< This
->numvertices
; i
++)
1165 /* Propagate vertices with low indices so as few vertices as possible
1166 * are used in the mesh.
1168 for (face
= 0; face
< This
->numfaces
; face
++)
1170 hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
, face
, This
->numfaces
);
1171 if (FAILED(hr
)) goto cleanup
;
1173 /* Go in opposite direction to catch all face orderings */
1174 for (face
= 0; face
< This
->numfaces
; face
++)
1176 hr
= propagate_face_vertices(adjacency
, point_reps
,
1177 indices
, new_indices
,
1178 (This
->numfaces
- 1) - face
, This
->numfaces
);
1179 if (FAILED(hr
)) goto cleanup
;
1184 if (This
->options
& D3DXMESH_32BIT
)
1186 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1190 if (indices_16bit
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1191 HeapFree(GetProcessHeap(), 0, indices
);
1193 HeapFree(GetProcessHeap(), 0, new_indices
);
1197 struct vertex_metadata
{
1200 DWORD first_shared_index
;
1203 static int compare_vertex_keys(const void *a
, const void *b
)
1205 const struct vertex_metadata
*left
= a
;
1206 const struct vertex_metadata
*right
= b
;
1207 if (left
->key
== right
->key
)
1209 return left
->key
< right
->key
? -1 : 1;
1212 static HRESULT WINAPI
ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh
*iface
, FLOAT epsilon
, DWORD
*adjacency
)
1214 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1216 BYTE
*vertices
= NULL
;
1217 const DWORD
*indices
= NULL
;
1220 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
1221 struct vertex_metadata
*sorted_vertices
;
1222 /* shared_indices links together identical indices in the index buffer so
1223 * that adjacency checks can be limited to faces sharing a vertex */
1224 DWORD
*shared_indices
= NULL
;
1225 const FLOAT epsilon_sq
= epsilon
* epsilon
;
1228 TRACE("(%p)->(%f,%p)\n", This
, epsilon
, adjacency
);
1231 return D3DERR_INVALIDCALL
;
1233 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
1234 if (!(This
->options
& D3DXMESH_32BIT
))
1235 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
1236 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
1237 if (!shared_indices
)
1238 return E_OUTOFMEMORY
;
1239 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
1241 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
1242 if (FAILED(hr
)) goto cleanup
;
1243 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1244 if (FAILED(hr
)) goto cleanup
;
1246 if (!(This
->options
& D3DXMESH_32BIT
)) {
1247 const WORD
*word_indices
= (const WORD
*)indices
;
1248 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
1249 indices
= dword_indices
;
1250 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1251 *dword_indices
++ = *word_indices
++;
1254 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1255 for (i
= 0; i
< This
->numvertices
; i
++) {
1256 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
1257 sorted_vertices
[i
].first_shared_index
= -1;
1258 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
1259 sorted_vertices
[i
].vertex_index
= i
;
1261 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
1262 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
1263 shared_indices
[i
] = *first_shared_index
;
1264 *first_shared_index
= i
;
1267 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
1269 for (i
= 0; i
< This
->numvertices
; i
++) {
1270 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
1271 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
1272 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
1274 while (shared_index_a
!= -1) {
1276 DWORD shared_index_b
= shared_indices
[shared_index_a
];
1277 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
1280 while (shared_index_b
!= -1) {
1281 /* faces are adjacent if they have another coincident vertex */
1282 DWORD base_a
= (shared_index_a
/ 3) * 3;
1283 DWORD base_b
= (shared_index_b
/ 3) * 3;
1284 BOOL adjacent
= FALSE
;
1287 for (k
= 0; k
< 3; k
++) {
1288 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
1294 for (k
= 1; k
<= 2; k
++) {
1295 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
1296 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
1297 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
1298 if (!adjacent
&& epsilon
>= 0.0f
) {
1299 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
1302 D3DXVec3Subtract(&delta
,
1303 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
1304 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
1305 length_sq
= D3DXVec3LengthSq(&delta
);
1306 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
1309 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
1310 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
1311 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
1312 adjacency
[adj_a
] = base_b
/ 3;
1313 adjacency
[adj_b
] = base_a
/ 3;
1320 shared_index_b
= shared_indices
[shared_index_b
];
1322 while (++j
< This
->numvertices
) {
1323 D3DXVECTOR3
*vertex_b
;
1326 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
1327 /* no more coincident vertices to try */
1328 j
= This
->numvertices
;
1331 /* check for coincidence */
1332 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
1333 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
1334 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
1335 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
1340 if (j
>= This
->numvertices
)
1342 shared_index_b
= sorted_vertex_b
->first_shared_index
;
1345 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
1346 shared_index_a
= sorted_vertex_a
->first_shared_index
;
1352 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1353 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
1354 HeapFree(GetProcessHeap(), 0, shared_indices
);
1358 static HRESULT WINAPI
ID3DXMeshImpl_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1361 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1362 UINT vertex_declaration_size
;
1365 TRACE("(%p)->(%p)\n", This
, declaration
);
1369 WARN("Invalid declaration. Can't use NULL declaration.\n");
1370 return D3DERR_INVALIDCALL
;
1373 /* New declaration must be same size as original */
1374 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
1375 if (vertex_declaration_size
!= This
->vertex_declaration_size
)
1377 WARN("Invalid declaration. New vertex size does not match the original vertex size.\n");
1378 return D3DERR_INVALIDCALL
;
1381 /* New declaration must not contain non-zero Stream value */
1382 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1384 if (declaration
[i
].Stream
!= 0)
1386 WARN("Invalid declaration. New declaration contains non-zero Stream value.\n");
1387 return D3DERR_INVALIDCALL
;
1391 This
->num_elem
= i
+ 1;
1392 copy_declaration(This
->cached_declaration
, declaration
, This
->num_elem
);
1394 if (This
->vertex_declaration
)
1395 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
1397 /* An application can pass an invalid declaration to UpdateSemantics and
1398 * still expect D3D_OK (see tests). If the declaration is invalid, then
1399 * subsequent calls to DrawSubset will fail. This is handled by setting the
1400 * vertex declaration to NULL.
1401 * GetDeclaration, GetNumBytesPerVertex must, however, use the new
1402 * invalid declaration. This is handled by them using the cached vertex
1403 * declaration instead of the actual vertex declaration.
1405 hr
= IDirect3DDevice9_CreateVertexDeclaration(This
->device
,
1407 &This
->vertex_declaration
);
1410 WARN("Using invalid declaration. Calls to DrawSubset will fail.\n");
1411 This
->vertex_declaration
= NULL
;
1418 static HRESULT WINAPI
ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
1420 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1422 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
1424 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
1426 if (!(flags
& D3DLOCK_READONLY
)) {
1427 D3DXATTRIBUTERANGE
*attrib_table
= This
->attrib_table
;
1428 This
->attrib_table_size
= 0;
1429 This
->attrib_table
= NULL
;
1430 HeapFree(GetProcessHeap(), 0, attrib_table
);
1433 *data
= This
->attrib_buffer
;
1438 static HRESULT WINAPI
ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh
*iface
)
1440 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1443 TRACE("(%p)\n", This
);
1445 lock_count
= InterlockedDecrement(&This
->attrib_buffer_lock_count
);
1447 if (lock_count
< 0) {
1448 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
1449 return D3DERR_INVALIDCALL
;
1455 static HRESULT WINAPI
ID3DXMeshImpl_Optimize(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1456 DWORD
*adjacency_out
, DWORD
*face_remap
, ID3DXBuffer
**vertex_remap
, ID3DXMesh
**opt_mesh
)
1458 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1460 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
1461 ID3DXMesh
*optimized_mesh
;
1463 TRACE("(%p)->(%x,%p,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
1466 return D3DERR_INVALIDCALL
;
1468 hr
= iface
->lpVtbl
->GetDeclaration(iface
, declaration
);
1469 if (FAILED(hr
)) return hr
;
1471 hr
= iface
->lpVtbl
->CloneMesh(iface
, This
->options
, declaration
, This
->device
, &optimized_mesh
);
1472 if (FAILED(hr
)) return hr
;
1474 hr
= optimized_mesh
->lpVtbl
->OptimizeInplace(optimized_mesh
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
);
1476 *opt_mesh
= optimized_mesh
;
1478 IUnknown_Release(optimized_mesh
);
1482 /* Creates a vertex_remap that removes unused vertices.
1483 * Indices are updated according to the vertex_remap. */
1484 static HRESULT
compact_mesh(ID3DXMeshImpl
*This
, DWORD
*indices
, DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
1487 DWORD
*vertex_remap_ptr
;
1488 DWORD num_used_vertices
;
1491 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
1492 if (FAILED(hr
)) return hr
;
1493 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
1495 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1496 vertex_remap_ptr
[indices
[i
]] = 1;
1498 /* create old->new vertex mapping */
1499 num_used_vertices
= 0;
1500 for (i
= 0; i
< This
->numvertices
; i
++) {
1501 if (vertex_remap_ptr
[i
])
1502 vertex_remap_ptr
[i
] = num_used_vertices
++;
1504 vertex_remap_ptr
[i
] = -1;
1506 /* convert indices */
1507 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1508 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
1510 /* create new->old vertex mapping */
1511 num_used_vertices
= 0;
1512 for (i
= 0; i
< This
->numvertices
; i
++) {
1513 if (vertex_remap_ptr
[i
] != -1)
1514 vertex_remap_ptr
[num_used_vertices
++] = i
;
1516 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
1517 vertex_remap_ptr
[i
] = -1;
1519 *new_num_vertices
= num_used_vertices
;
1524 /* count the number of unique attribute values in a sorted attribute buffer */
1525 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
1527 DWORD last_attribute
= attrib_buffer
[0];
1528 DWORD attrib_table_size
= 1;
1530 for (i
= 1; i
< numfaces
; i
++) {
1531 if (attrib_buffer
[i
] != last_attribute
) {
1532 last_attribute
= attrib_buffer
[i
];
1533 attrib_table_size
++;
1536 return attrib_table_size
;
1539 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
1540 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
1542 DWORD attrib_table_size
= 0;
1543 DWORD last_attribute
= attrib_buffer
[0];
1544 DWORD min_vertex
, max_vertex
;
1547 attrib_table
[0].AttribId
= last_attribute
;
1548 attrib_table
[0].FaceStart
= 0;
1549 min_vertex
= (DWORD
)-1;
1551 for (i
= 0; i
< numfaces
; i
++) {
1554 if (attrib_buffer
[i
] != last_attribute
) {
1555 last_attribute
= attrib_buffer
[i
];
1556 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1557 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1558 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1559 attrib_table_size
++;
1560 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
1561 attrib_table
[attrib_table_size
].FaceStart
= i
;
1562 min_vertex
= (DWORD
)-1;
1565 for (j
= 0; j
< 3; j
++) {
1566 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
1567 if (vertex_index
< min_vertex
)
1568 min_vertex
= vertex_index
;
1569 if (vertex_index
> max_vertex
)
1570 max_vertex
= vertex_index
;
1573 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1574 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1575 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1576 attrib_table_size
++;
1579 static int attrib_entry_compare(const DWORD
**a
, const DWORD
**b
)
1581 const DWORD
*ptr_a
= *a
;
1582 const DWORD
*ptr_b
= *b
;
1583 int delta
= *ptr_a
- *ptr_b
;
1588 delta
= ptr_a
- ptr_b
; /* for stable sort */
1592 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
1593 static HRESULT
remap_faces_for_attrsort(ID3DXMeshImpl
*This
, const DWORD
*indices
,
1594 const DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
1596 const DWORD
**sorted_attrib_ptr_buffer
= NULL
;
1599 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
1600 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
1601 if (!*face_remap
|| !sorted_attrib_ptr_buffer
) {
1602 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
1603 return E_OUTOFMEMORY
;
1605 for (i
= 0; i
< This
->numfaces
; i
++)
1606 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
1607 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
),
1608 (int(*)(const void *, const void *))attrib_entry_compare
);
1610 for (i
= 0; i
< This
->numfaces
; i
++)
1612 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
1613 (*face_remap
)[old_face
] = i
;
1616 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
1617 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
1618 for (i
= 0; i
< This
->numfaces
; i
++)
1619 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
1624 static HRESULT WINAPI
ID3DXMeshImpl_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1625 DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
1627 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1628 void *indices
= NULL
;
1629 DWORD
*attrib_buffer
= NULL
;
1631 ID3DXBuffer
*vertex_remap
= NULL
;
1632 DWORD
*face_remap
= NULL
; /* old -> new mapping */
1633 DWORD
*dword_indices
= NULL
;
1634 DWORD new_num_vertices
= 0;
1635 DWORD new_num_alloc_vertices
= 0;
1636 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
1637 DWORD
*sorted_attrib_buffer
= NULL
;
1640 TRACE("(%p)->(%x,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
1643 return D3DERR_INVALIDCALL
;
1644 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
1645 return D3DERR_INVALIDCALL
;
1646 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1647 return D3DERR_INVALIDCALL
;
1649 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1651 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
1652 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
1653 if (flags
& D3DXMESHOPT_STRIPREORDER
)
1654 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
1658 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, &indices
);
1659 if (FAILED(hr
)) goto cleanup
;
1661 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
1662 if (!dword_indices
) return E_OUTOFMEMORY
;
1663 if (This
->options
& D3DXMESH_32BIT
) {
1664 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1666 WORD
*word_indices
= indices
;
1667 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1668 dword_indices
[i
] = *word_indices
++;
1671 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
1673 new_num_alloc_vertices
= This
->numvertices
;
1674 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
1675 if (FAILED(hr
)) goto cleanup
;
1676 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
1677 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
1679 FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
1684 hr
= iface
->lpVtbl
->LockAttributeBuffer(iface
, 0, &attrib_buffer
);
1685 if (FAILED(hr
)) goto cleanup
;
1687 hr
= remap_faces_for_attrsort(This
, dword_indices
, attrib_buffer
, &sorted_attrib_buffer
, &face_remap
);
1688 if (FAILED(hr
)) goto cleanup
;
1693 /* reorder the vertices using vertex_remap */
1694 D3DVERTEXBUFFER_DESC vertex_desc
;
1695 DWORD
*vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1696 DWORD vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1697 BYTE
*orig_vertices
;
1700 hr
= IDirect3DVertexBuffer9_GetDesc(This
->vertex_buffer
, &vertex_desc
);
1701 if (FAILED(hr
)) goto cleanup
;
1703 hr
= IDirect3DDevice9_CreateVertexBuffer(This
->device
, new_num_alloc_vertices
* vertex_size
,
1704 vertex_desc
.Usage
, This
->fvf
, vertex_desc
.Pool
, &vertex_buffer
, NULL
);
1705 if (FAILED(hr
)) goto cleanup
;
1707 hr
= IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, (void**)&orig_vertices
, D3DLOCK_READONLY
);
1708 if (FAILED(hr
)) goto cleanup
;
1710 hr
= IDirect3DVertexBuffer9_Lock(vertex_buffer
, 0, 0, (void**)&new_vertices
, 0);
1712 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1716 for (i
= 0; i
< new_num_vertices
; i
++)
1717 memcpy(new_vertices
+ i
* vertex_size
, orig_vertices
+ vertex_remap_ptr
[i
] * vertex_size
, vertex_size
);
1719 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1720 IDirect3DVertexBuffer9_Unlock(vertex_buffer
);
1721 } else if (vertex_remap_out
) {
1722 DWORD
*vertex_remap_ptr
;
1724 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), &vertex_remap
);
1725 if (FAILED(hr
)) goto cleanup
;
1726 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1727 for (i
= 0; i
< This
->numvertices
; i
++)
1728 *vertex_remap_ptr
++ = i
;
1731 if (flags
& D3DXMESHOPT_ATTRSORT
)
1733 D3DXATTRIBUTERANGE
*attrib_table
;
1734 DWORD attrib_table_size
;
1736 attrib_table_size
= count_attributes(sorted_attrib_buffer
, This
->numfaces
);
1737 attrib_table
= HeapAlloc(GetProcessHeap(), 0, attrib_table_size
* sizeof(*attrib_table
));
1738 if (!attrib_table
) {
1743 memcpy(attrib_buffer
, sorted_attrib_buffer
, This
->numfaces
* sizeof(*attrib_buffer
));
1745 /* reorder the indices using face_remap */
1746 if (This
->options
& D3DXMESH_32BIT
) {
1747 for (i
= 0; i
< This
->numfaces
; i
++)
1748 memcpy((DWORD
*)indices
+ face_remap
[i
] * 3, dword_indices
+ i
* 3, 3 * sizeof(DWORD
));
1750 WORD
*word_indices
= indices
;
1751 for (i
= 0; i
< This
->numfaces
; i
++) {
1752 DWORD new_pos
= face_remap
[i
] * 3;
1753 DWORD old_pos
= i
* 3;
1754 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1755 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1756 word_indices
[new_pos
] = dword_indices
[old_pos
];
1760 fill_attribute_table(attrib_buffer
, This
->numfaces
, indices
,
1761 This
->options
& D3DXMESH_32BIT
, attrib_table
);
1763 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1764 This
->attrib_table
= attrib_table
;
1765 This
->attrib_table_size
= attrib_table_size
;
1767 if (This
->options
& D3DXMESH_32BIT
) {
1768 memcpy(indices
, dword_indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1770 WORD
*word_indices
= indices
;
1771 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1772 *word_indices
++ = dword_indices
[i
];
1776 if (adjacency_out
) {
1778 for (i
= 0; i
< This
->numfaces
; i
++) {
1779 DWORD old_pos
= i
* 3;
1780 DWORD new_pos
= face_remap
[i
] * 3;
1781 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1782 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1783 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1786 memcpy(adjacency_out
, adjacency_in
, This
->numfaces
* 3 * sizeof(*adjacency_out
));
1789 if (face_remap_out
) {
1791 for (i
= 0; i
< This
->numfaces
; i
++)
1792 face_remap_out
[face_remap
[i
]] = i
;
1794 for (i
= 0; i
< This
->numfaces
; i
++)
1795 face_remap_out
[i
] = i
;
1798 if (vertex_remap_out
)
1799 *vertex_remap_out
= vertex_remap
;
1800 vertex_remap
= NULL
;
1802 if (vertex_buffer
) {
1803 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
1804 This
->vertex_buffer
= vertex_buffer
;
1805 vertex_buffer
= NULL
;
1806 This
->numvertices
= new_num_vertices
;
1811 HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer
);
1812 HeapFree(GetProcessHeap(), 0, face_remap
);
1813 HeapFree(GetProcessHeap(), 0, dword_indices
);
1814 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
1815 if (vertex_buffer
) IDirect3DVertexBuffer9_Release(vertex_buffer
);
1816 if (attrib_buffer
) iface
->lpVtbl
->UnlockAttributeBuffer(iface
);
1817 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1821 static HRESULT WINAPI
ID3DXMeshImpl_SetAttributeTable(ID3DXMesh
*iface
, CONST D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
1823 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1824 D3DXATTRIBUTERANGE
*new_table
= NULL
;
1826 TRACE("(%p)->(%p,%u)\n", This
, attrib_table
, attrib_table_size
);
1828 if (attrib_table_size
) {
1829 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
1831 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
1833 return E_OUTOFMEMORY
;
1835 CopyMemory(new_table
, attrib_table
, size
);
1836 } else if (attrib_table
) {
1837 return D3DERR_INVALIDCALL
;
1839 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1840 This
->attrib_table
= new_table
;
1841 This
->attrib_table_size
= attrib_table_size
;
1846 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
1848 /*** IUnknown methods ***/
1849 ID3DXMeshImpl_QueryInterface
,
1850 ID3DXMeshImpl_AddRef
,
1851 ID3DXMeshImpl_Release
,
1852 /*** ID3DXBaseMesh ***/
1853 ID3DXMeshImpl_DrawSubset
,
1854 ID3DXMeshImpl_GetNumFaces
,
1855 ID3DXMeshImpl_GetNumVertices
,
1856 ID3DXMeshImpl_GetFVF
,
1857 ID3DXMeshImpl_GetDeclaration
,
1858 ID3DXMeshImpl_GetNumBytesPerVertex
,
1859 ID3DXMeshImpl_GetOptions
,
1860 ID3DXMeshImpl_GetDevice
,
1861 ID3DXMeshImpl_CloneMeshFVF
,
1862 ID3DXMeshImpl_CloneMesh
,
1863 ID3DXMeshImpl_GetVertexBuffer
,
1864 ID3DXMeshImpl_GetIndexBuffer
,
1865 ID3DXMeshImpl_LockVertexBuffer
,
1866 ID3DXMeshImpl_UnlockVertexBuffer
,
1867 ID3DXMeshImpl_LockIndexBuffer
,
1868 ID3DXMeshImpl_UnlockIndexBuffer
,
1869 ID3DXMeshImpl_GetAttributeTable
,
1870 ID3DXMeshImpl_ConvertPointRepsToAdjacency
,
1871 ID3DXMeshImpl_ConvertAdjacencyToPointReps
,
1872 ID3DXMeshImpl_GenerateAdjacency
,
1873 ID3DXMeshImpl_UpdateSemantics
,
1875 ID3DXMeshImpl_LockAttributeBuffer
,
1876 ID3DXMeshImpl_UnlockAttributeBuffer
,
1877 ID3DXMeshImpl_Optimize
,
1878 ID3DXMeshImpl_OptimizeInplace
,
1879 ID3DXMeshImpl_SetAttributeTable
1882 /*************************************************************************
1885 BOOL WINAPI
D3DXBoxBoundProbe(CONST D3DXVECTOR3
*pmin
, CONST D3DXVECTOR3
*pmax
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
1887 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algorithm
1888 Amy Williams University of Utah
1889 Steve Barrus University of Utah
1890 R. Keith Morley University of Utah
1891 Peter Shirley University of Utah
1893 International Conference on Computer Graphics and Interactive Techniques archive
1894 ACM SIGGRAPH 2005 Courses
1895 Los Angeles, California
1897 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1899 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1900 against each slab, if there's anything left of the ray after we're
1901 done we've got an intersection of the ray with the box.
1905 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
1907 div
= 1.0f
/ praydirection
->x
;
1910 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
1911 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
1915 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
1916 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
1919 if ( tmax
< 0.0f
) return FALSE
;
1921 div
= 1.0f
/ praydirection
->y
;
1924 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
1925 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
1929 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
1930 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
1933 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
1935 if ( tymin
> tmin
) tmin
= tymin
;
1936 if ( tymax
< tmax
) tmax
= tymax
;
1938 div
= 1.0f
/ praydirection
->z
;
1941 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
1942 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
1946 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
1947 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
1950 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
1955 /*************************************************************************
1956 * D3DXComputeBoundingBox
1958 HRESULT WINAPI
D3DXComputeBoundingBox(CONST D3DXVECTOR3
*pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
1963 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
1965 *pmin
= *pfirstposition
;
1968 for(i
=0; i
<numvertices
; i
++)
1970 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
1972 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
1973 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
1975 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
1976 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
1978 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
1979 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
1985 /*************************************************************************
1986 * D3DXComputeBoundingSphere
1988 HRESULT WINAPI
D3DXComputeBoundingSphere(CONST D3DXVECTOR3
* pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, FLOAT
*pradius
)
1994 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
2001 for(i
=0; i
<numvertices
; i
++)
2002 D3DXVec3Add(&temp
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
2004 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/ numvertices
);
2006 for(i
=0; i
<numvertices
; i
++)
2008 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
2009 if ( d
> *pradius
) *pradius
= d
;
2014 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
2015 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
2017 declaration
[*idx
].Stream
= 0;
2018 declaration
[*idx
].Offset
= *offset
;
2019 declaration
[*idx
].Type
= type
;
2020 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
2021 declaration
[*idx
].Usage
= usage
;
2022 declaration
[*idx
].UsageIndex
= usage_idx
;
2024 *offset
+= d3dx_decltype_size
[type
];
2028 /*************************************************************************
2029 * D3DXDeclaratorFromFVF
2031 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
2033 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
2034 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2035 unsigned int offset
= 0;
2036 unsigned int idx
= 0;
2039 TRACE("fvf %#x, declaration %p.\n", fvf
, declaration
);
2041 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
2043 if (fvf
& D3DFVF_POSITION_MASK
)
2045 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
2046 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
2047 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
2049 if (has_blend_idx
) --blend_count
;
2051 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
2052 || (has_blend
&& blend_count
> 4))
2053 return D3DERR_INVALIDCALL
;
2055 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
2056 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
2058 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
2062 switch (blend_count
)
2067 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2070 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2073 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2076 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2079 ERR("Invalid blend count %u.\n", blend_count
);
2085 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
2086 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
2087 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
2088 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
2093 if (fvf
& D3DFVF_NORMAL
)
2094 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
2095 if (fvf
& D3DFVF_PSIZE
)
2096 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
2097 if (fvf
& D3DFVF_DIFFUSE
)
2098 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
2099 if (fvf
& D3DFVF_SPECULAR
)
2100 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
2102 for (i
= 0; i
< tex_count
; ++i
)
2104 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
2106 case D3DFVF_TEXTUREFORMAT1
:
2107 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
2109 case D3DFVF_TEXTUREFORMAT2
:
2110 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
2112 case D3DFVF_TEXTUREFORMAT3
:
2113 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
2115 case D3DFVF_TEXTUREFORMAT4
:
2116 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
2121 declaration
[idx
] = end_element
;
2126 /*************************************************************************
2127 * D3DXFVFFromDeclarator
2129 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
2131 unsigned int i
= 0, texture
, offset
;
2133 TRACE("(%p, %p)\n", declaration
, fvf
);
2136 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
2138 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2139 declaration
[1].UsageIndex
== 0) &&
2140 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
2141 declaration
[2].UsageIndex
== 0))
2143 return D3DERR_INVALIDCALL
;
2145 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2146 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
2148 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
2150 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
2154 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
2158 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2159 declaration
[1].UsageIndex
== 0)
2161 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2162 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
2164 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
2166 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
2170 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
2172 switch (declaration
[1].Type
)
2174 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
2175 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
2176 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
2177 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
2183 switch (declaration
[1].Type
)
2185 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
2186 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
2187 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
2188 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
2199 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
2200 declaration
[0].UsageIndex
== 0)
2202 *fvf
|= D3DFVF_XYZRHW
;
2206 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
2208 *fvf
|= D3DFVF_NORMAL
;
2211 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
2212 declaration
[i
].UsageIndex
== 0)
2214 *fvf
|= D3DFVF_PSIZE
;
2217 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2218 declaration
[i
].UsageIndex
== 0)
2220 *fvf
|= D3DFVF_DIFFUSE
;
2223 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2224 declaration
[i
].UsageIndex
== 1)
2226 *fvf
|= D3DFVF_SPECULAR
;
2230 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
2232 if (declaration
[i
].Stream
== 0xFF)
2236 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2237 declaration
[i
].UsageIndex
== texture
)
2239 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
2241 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2242 declaration
[i
].UsageIndex
== texture
)
2244 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
2246 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2247 declaration
[i
].UsageIndex
== texture
)
2249 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
2251 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2252 declaration
[i
].UsageIndex
== texture
)
2254 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
2258 return D3DERR_INVALIDCALL
;
2262 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
2264 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
2265 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
2267 if (declaration
[i
].Offset
!= offset
)
2269 return D3DERR_INVALIDCALL
;
2276 /*************************************************************************
2277 * D3DXGetFVFVertexSize
2279 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
2281 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
2284 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
2288 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2290 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
2291 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
2292 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
2293 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
2295 switch (FVF
& D3DFVF_POSITION_MASK
)
2297 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
2298 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
2299 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
2300 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
2301 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
2302 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
2303 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
2304 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
2307 for (i
= 0; i
< numTextures
; i
++)
2309 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
2315 /*************************************************************************
2316 * D3DXGetDeclVertexSize
2318 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
2320 const D3DVERTEXELEMENT9
*element
;
2323 TRACE("decl %p, stream_idx %u\n", decl
, stream_idx
);
2325 if (!decl
) return 0;
2327 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
2331 if (element
->Stream
!= stream_idx
) continue;
2333 if (element
->Type
>= sizeof(d3dx_decltype_size
) / sizeof(*d3dx_decltype_size
))
2335 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
2339 type_size
= d3dx_decltype_size
[element
->Type
];
2340 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
2346 /*************************************************************************
2349 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
2351 const D3DVERTEXELEMENT9
*element
;
2353 TRACE("decl %p\n", decl
);
2355 /* null decl results in exception on Windows XP */
2357 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
2359 return element
- decl
;
2362 /*************************************************************************
2365 BOOL WINAPI
D3DXIntersectTri(CONST D3DXVECTOR3
*p0
, CONST D3DXVECTOR3
*p1
, CONST D3DXVECTOR3
*p2
, CONST D3DXVECTOR3
*praypos
, CONST D3DXVECTOR3
*praydir
, FLOAT
*pu
, FLOAT
*pv
, FLOAT
*pdist
)
2370 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
2371 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
2372 m
.u
.m
[2][0] = -praydir
->x
;
2374 m
.u
.m
[0][1] = p1
->y
- p0
->z
;
2375 m
.u
.m
[1][1] = p2
->y
- p0
->z
;
2376 m
.u
.m
[2][1] = -praydir
->y
;
2378 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
2379 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
2380 m
.u
.m
[2][2] = -praydir
->z
;
2387 vec
.x
= praypos
->x
- p0
->x
;
2388 vec
.y
= praypos
->y
- p0
->y
;
2389 vec
.z
= praypos
->z
- p0
->z
;
2392 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
2394 D3DXVec4Transform(&vec
, &vec
, &m
);
2395 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
2399 *pdist
= fabs( vec
.z
);
2407 /*************************************************************************
2408 * D3DXSphereBoundProbe
2410 BOOL WINAPI
D3DXSphereBoundProbe(CONST D3DXVECTOR3
*pcenter
, FLOAT radius
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
2412 D3DXVECTOR3 difference
;
2415 a
= D3DXVec3LengthSq(praydirection
);
2416 if (!D3DXVec3Subtract(&difference
, prayposition
, pcenter
)) return FALSE
;
2417 b
= D3DXVec3Dot(&difference
, praydirection
);
2418 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
2421 if ( ( d
<= 0.0f
) || ( sqrt(d
) <= b
) ) return FALSE
;
2425 /*************************************************************************
2428 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2429 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2433 IDirect3DVertexDeclaration9
*vertex_declaration
;
2434 UINT vertex_declaration_size
;
2436 IDirect3DVertexBuffer9
*vertex_buffer
;
2437 IDirect3DIndexBuffer9
*index_buffer
;
2438 DWORD
*attrib_buffer
;
2439 ID3DXMeshImpl
*object
;
2440 DWORD index_usage
= 0;
2441 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
2442 D3DFORMAT index_format
= D3DFMT_INDEX16
;
2443 DWORD vertex_usage
= 0;
2444 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
2447 TRACE("(%d, %d, %x, %p, %p, %p)\n", numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2449 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
2450 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
2451 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
2453 return D3DERR_INVALIDCALL
;
2455 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
2456 if (declaration
[i
].Stream
!= 0)
2457 return D3DERR_INVALIDCALL
;
2460 if (options
& D3DXMESH_32BIT
)
2461 index_format
= D3DFMT_INDEX32
;
2463 if (options
& D3DXMESH_DONOTCLIP
) {
2464 index_usage
|= D3DUSAGE_DONOTCLIP
;
2465 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
2467 if (options
& D3DXMESH_POINTS
) {
2468 index_usage
|= D3DUSAGE_POINTS
;
2469 vertex_usage
|= D3DUSAGE_POINTS
;
2471 if (options
& D3DXMESH_RTPATCHES
) {
2472 index_usage
|= D3DUSAGE_RTPATCHES
;
2473 vertex_usage
|= D3DUSAGE_RTPATCHES
;
2475 if (options
& D3DXMESH_NPATCHES
) {
2476 index_usage
|= D3DUSAGE_NPATCHES
;
2477 vertex_usage
|= D3DUSAGE_NPATCHES
;
2480 if (options
& D3DXMESH_VB_SYSTEMMEM
)
2481 vertex_pool
= D3DPOOL_SYSTEMMEM
;
2482 else if (options
& D3DXMESH_VB_MANAGED
)
2483 vertex_pool
= D3DPOOL_MANAGED
;
2485 if (options
& D3DXMESH_VB_WRITEONLY
)
2486 vertex_usage
|= D3DUSAGE_WRITEONLY
;
2487 if (options
& D3DXMESH_VB_DYNAMIC
)
2488 vertex_usage
|= D3DUSAGE_DYNAMIC
;
2489 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
2490 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2492 if (options
& D3DXMESH_IB_SYSTEMMEM
)
2493 index_pool
= D3DPOOL_SYSTEMMEM
;
2494 else if (options
& D3DXMESH_IB_MANAGED
)
2495 index_pool
= D3DPOOL_MANAGED
;
2497 if (options
& D3DXMESH_IB_WRITEONLY
)
2498 index_usage
|= D3DUSAGE_WRITEONLY
;
2499 if (options
& D3DXMESH_IB_DYNAMIC
)
2500 index_usage
|= D3DUSAGE_DYNAMIC
;
2501 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
2502 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2504 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
2510 /* Create vertex declaration */
2511 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
2513 &vertex_declaration
);
2516 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
2519 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
2521 /* Create vertex buffer */
2522 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
2523 numvertices
* vertex_declaration_size
,
2531 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2532 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2536 /* Create index buffer */
2537 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
2538 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
2546 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2547 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2548 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2552 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
2553 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ID3DXMeshImpl
));
2554 if (object
== NULL
|| attrib_buffer
== NULL
)
2556 HeapFree(GetProcessHeap(), 0, object
);
2557 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
2558 IDirect3DIndexBuffer9_Release(index_buffer
);
2559 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2560 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2562 return E_OUTOFMEMORY
;
2564 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
2567 object
->numfaces
= numfaces
;
2568 object
->numvertices
= numvertices
;
2569 object
->options
= options
;
2571 object
->device
= device
;
2572 IDirect3DDevice9_AddRef(device
);
2574 copy_declaration(object
->cached_declaration
, declaration
, num_elem
);
2575 object
->vertex_declaration
= vertex_declaration
;
2576 object
->vertex_declaration_size
= vertex_declaration_size
;
2577 object
->num_elem
= num_elem
;
2578 object
->vertex_buffer
= vertex_buffer
;
2579 object
->index_buffer
= index_buffer
;
2580 object
->attrib_buffer
= attrib_buffer
;
2582 *mesh
= &object
->ID3DXMesh_iface
;
2587 /*************************************************************************
2590 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2591 DWORD fvf
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2594 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
2596 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
2598 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
2599 if (FAILED(hr
)) return hr
;
2601 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2607 DWORD num_poly_faces
;
2608 DWORD num_tri_faces
;
2609 D3DXVECTOR3
*vertices
;
2610 DWORD
*num_tri_per_face
;
2615 /* optional mesh data */
2618 D3DXVECTOR3
*normals
;
2619 DWORD
*normal_indices
;
2621 D3DXVECTOR2
*tex_coords
;
2623 DWORD
*vertex_colors
;
2625 DWORD num_materials
;
2626 D3DXMATERIAL
*materials
;
2627 DWORD
*material_indices
;
2629 struct ID3DXSkinInfo
*skin_info
;
2633 static HRESULT
parse_texture_filename(ID3DXFileData
*filedata
, LPSTR
*filename_out
)
2639 char *filename
= NULL
;
2641 /* template TextureFilename {
2646 HeapFree(GetProcessHeap(), 0, *filename_out
);
2647 *filename_out
= NULL
;
2649 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2650 if (FAILED(hr
)) return hr
;
2652 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
2653 if (data_size
< sizeof(LPSTR
)) {
2654 WARN("truncated data (%lu bytes)\n", data_size
);
2655 filedata
->lpVtbl
->Unlock(filedata
);
2658 filename_in
= *(LPSTR
*)data
;
2660 filename
= HeapAlloc(GetProcessHeap(), 0, strlen(filename_in
) + 1);
2662 filedata
->lpVtbl
->Unlock(filedata
);
2663 return E_OUTOFMEMORY
;
2666 strcpy(filename
, filename_in
);
2667 *filename_out
= filename
;
2669 filedata
->lpVtbl
->Unlock(filedata
);
2674 static HRESULT
parse_material(ID3DXFileData
*filedata
, D3DXMATERIAL
*material
)
2680 ID3DXFileData
*child
;
2684 material
->pTextureFilename
= NULL
;
2686 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2687 if (FAILED(hr
)) return hr
;
2690 * template ColorRGBA {
2696 * template ColorRGB {
2701 * template Material {
2702 * ColorRGBA faceColor;
2704 * ColorRGB specularColor;
2705 * ColorRGB emissiveColor;
2709 if (data_size
!= sizeof(FLOAT
) * 11) {
2710 WARN("incorrect data size (%ld bytes)\n", data_size
);
2711 filedata
->lpVtbl
->Unlock(filedata
);
2715 memcpy(&material
->MatD3D
.Diffuse
, data
, sizeof(D3DCOLORVALUE
));
2716 data
+= sizeof(D3DCOLORVALUE
);
2717 material
->MatD3D
.Power
= *(FLOAT
*)data
;
2718 data
+= sizeof(FLOAT
);
2719 memcpy(&material
->MatD3D
.Specular
, data
, sizeof(FLOAT
) * 3);
2720 material
->MatD3D
.Specular
.a
= 1.0f
;
2721 data
+= 3 * sizeof(FLOAT
);
2722 memcpy(&material
->MatD3D
.Emissive
, data
, sizeof(FLOAT
) * 3);
2723 material
->MatD3D
.Emissive
.a
= 1.0f
;
2724 material
->MatD3D
.Ambient
.r
= 0.0f
;
2725 material
->MatD3D
.Ambient
.g
= 0.0f
;
2726 material
->MatD3D
.Ambient
.b
= 0.0f
;
2727 material
->MatD3D
.Ambient
.a
= 1.0f
;
2729 filedata
->lpVtbl
->Unlock(filedata
);
2731 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2735 for (i
= 0; i
< nb_children
; i
++)
2737 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2740 hr
= child
->lpVtbl
->GetType(child
, &type
);
2744 if (IsEqualGUID(&type
, &TID_D3DRMTextureFilename
)) {
2745 hr
= parse_texture_filename(child
, &material
->pTextureFilename
);
2754 static void destroy_materials(struct mesh_data
*mesh
)
2757 for (i
= 0; i
< mesh
->num_materials
; i
++)
2758 HeapFree(GetProcessHeap(), 0, mesh
->materials
[i
].pTextureFilename
);
2759 HeapFree(GetProcessHeap(), 0, mesh
->materials
);
2760 HeapFree(GetProcessHeap(), 0, mesh
->material_indices
);
2761 mesh
->num_materials
= 0;
2762 mesh
->materials
= NULL
;
2763 mesh
->material_indices
= NULL
;
2766 static HRESULT
parse_material_list(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2770 const DWORD
*data
, *in_ptr
;
2772 ID3DXFileData
*child
;
2773 DWORD num_materials
;
2777 destroy_materials(mesh
);
2779 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2780 if (FAILED(hr
)) return hr
;
2782 /* template MeshMaterialList {
2784 * DWORD nFaceIndexes;
2785 * array DWORD faceIndexes[nFaceIndexes];
2793 if (data_size
< sizeof(DWORD
)) {
2794 WARN("truncated data (%ld bytes)\n", data_size
);
2797 num_materials
= *in_ptr
++;
2798 if (!num_materials
) {
2803 if (data_size
< 2 * sizeof(DWORD
)) {
2804 WARN("truncated data (%ld bytes)\n", data_size
);
2807 if (*in_ptr
++ != mesh
->num_poly_faces
) {
2808 WARN("number of material face indices (%u) doesn't match number of faces (%u)\n",
2809 *(in_ptr
- 1), mesh
->num_poly_faces
);
2812 if (data_size
< 2 * sizeof(DWORD
) + mesh
->num_poly_faces
* sizeof(DWORD
)) {
2813 WARN("truncated data (%ld bytes)\n", data_size
);
2816 for (i
= 0; i
< mesh
->num_poly_faces
; i
++) {
2817 if (*in_ptr
++ >= num_materials
) {
2818 WARN("face %u: reference to undefined material %u (only %u materials)\n",
2819 i
, *(in_ptr
- 1), num_materials
);
2824 mesh
->materials
= HeapAlloc(GetProcessHeap(), 0, num_materials
* sizeof(*mesh
->materials
));
2825 mesh
->material_indices
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_poly_faces
* sizeof(*mesh
->material_indices
));
2826 if (!mesh
->materials
|| !mesh
->material_indices
) {
2830 memcpy(mesh
->material_indices
, data
+ 2, mesh
->num_poly_faces
* sizeof(DWORD
));
2832 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2836 for (i
= 0; i
< nb_children
; i
++)
2838 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2841 hr
= child
->lpVtbl
->GetType(child
, &type
);
2845 if (IsEqualGUID(&type
, &TID_D3DRMMaterial
)) {
2846 if (mesh
->num_materials
>= num_materials
) {
2847 WARN("more materials defined than declared\n");
2851 hr
= parse_material(child
, &mesh
->materials
[mesh
->num_materials
++]);
2856 if (num_materials
!= mesh
->num_materials
) {
2857 WARN("only %u of %u materials defined\n", num_materials
, mesh
->num_materials
);
2862 filedata
->lpVtbl
->Unlock(filedata
);
2866 static HRESULT
parse_texture_coords(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2872 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2873 mesh
->tex_coords
= NULL
;
2875 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2876 if (FAILED(hr
)) return hr
;
2878 /* template Coords2d {
2882 * template MeshTextureCoords {
2883 * DWORD nTextureCoords;
2884 * array Coords2d textureCoords[nTextureCoords];
2890 if (data_size
< sizeof(DWORD
)) {
2891 WARN("truncated data (%ld bytes)\n", data_size
);
2894 if (*(DWORD
*)data
!= mesh
->num_vertices
) {
2895 WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2896 *(DWORD
*)data
, mesh
->num_vertices
);
2899 data
+= sizeof(DWORD
);
2900 if (data_size
< sizeof(DWORD
) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
)) {
2901 WARN("truncated data (%ld bytes)\n", data_size
);
2905 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2906 if (!mesh
->tex_coords
) {
2910 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2912 mesh
->fvf
|= D3DFVF_TEX1
;
2917 filedata
->lpVtbl
->Unlock(filedata
);
2921 static HRESULT
parse_vertex_colors(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2929 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2930 mesh
->vertex_colors
= NULL
;
2932 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2933 if (FAILED(hr
)) return hr
;
2935 /* template IndexedColor {
2937 * ColorRGBA indexColor;
2939 * template MeshVertexColors {
2940 * DWORD nVertexColors;
2941 * array IndexedColor vertexColors[nVertexColors];
2947 if (data_size
< sizeof(DWORD
)) {
2948 WARN("truncated data (%ld bytes)\n", data_size
);
2951 num_colors
= *(DWORD
*)data
;
2952 data
+= sizeof(DWORD
);
2953 if (data_size
< sizeof(DWORD
) + num_colors
* (sizeof(DWORD
) + sizeof(D3DCOLORVALUE
))) {
2954 WARN("truncated data (%ld bytes)\n", data_size
);
2958 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(DWORD
));
2959 if (!mesh
->vertex_colors
) {
2964 for (i
= 0; i
< mesh
->num_vertices
; i
++)
2965 mesh
->vertex_colors
[i
] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2966 for (i
= 0; i
< num_colors
; i
++)
2968 D3DCOLORVALUE color
;
2969 DWORD index
= *(DWORD
*)data
;
2970 data
+= sizeof(DWORD
);
2971 if (index
>= mesh
->num_vertices
) {
2972 WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2973 i
, index
, mesh
->num_vertices
);
2976 memcpy(&color
, data
, sizeof(color
));
2977 data
+= sizeof(color
);
2978 color
.r
= min(1.0f
, max(0.0f
, color
.r
));
2979 color
.g
= min(1.0f
, max(0.0f
, color
.g
));
2980 color
.b
= min(1.0f
, max(0.0f
, color
.b
));
2981 color
.a
= min(1.0f
, max(0.0f
, color
.a
));
2982 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
2983 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
2984 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
2985 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
2988 mesh
->fvf
|= D3DFVF_DIFFUSE
;
2993 filedata
->lpVtbl
->Unlock(filedata
);
2997 static HRESULT
parse_normals(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
3002 DWORD
*index_out_ptr
;
3004 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
3006 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
3007 mesh
->num_normals
= 0;
3008 mesh
->normals
= NULL
;
3009 mesh
->normal_indices
= NULL
;
3010 mesh
->fvf
|= D3DFVF_NORMAL
;
3012 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3013 if (FAILED(hr
)) return hr
;
3015 /* template Vector {
3020 * template MeshFace {
3021 * DWORD nFaceVertexIndices;
3022 * array DWORD faceVertexIndices[nFaceVertexIndices];
3024 * template MeshNormals {
3026 * array Vector normals[nNormals];
3027 * DWORD nFaceNormals;
3028 * array MeshFace faceNormals[nFaceNormals];
3034 if (data_size
< sizeof(DWORD
) * 2) {
3035 WARN("truncated data (%ld bytes)\n", data_size
);
3038 mesh
->num_normals
= *(DWORD
*)data
;
3039 data
+= sizeof(DWORD
);
3040 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
3041 num_face_indices
* sizeof(DWORD
)) {
3042 WARN("truncated data (%ld bytes)\n", data_size
);
3046 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3047 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
3048 if (!mesh
->normals
|| !mesh
->normal_indices
) {
3053 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3054 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
3055 for (i
= 0; i
< mesh
->num_normals
; i
++)
3056 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
3058 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
3059 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
3060 *(DWORD
*)data
, mesh
->num_poly_faces
);
3063 data
+= sizeof(DWORD
);
3064 index_out_ptr
= mesh
->normal_indices
;
3065 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
3068 DWORD count
= *(DWORD
*)data
;
3069 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
3070 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
3071 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
3074 data
+= sizeof(DWORD
);
3076 for (j
= 0; j
< count
; j
++) {
3077 DWORD normal_index
= *(DWORD
*)data
;
3078 if (normal_index
>= mesh
->num_normals
) {
3079 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
3080 i
, j
, normal_index
, mesh
->num_normals
);
3083 *index_out_ptr
++ = normal_index
;
3084 data
+= sizeof(DWORD
);
3091 filedata
->lpVtbl
->Unlock(filedata
);
3095 static HRESULT
parse_skin_mesh_info(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD index
)
3101 TRACE("(%p, %p, %u)\n", filedata
, mesh_data
, index
);
3103 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3104 if (FAILED(hr
)) return hr
;
3108 if (!mesh_data
->skin_info
) {
3109 if (data_size
< sizeof(WORD
) * 3) {
3110 WARN("truncated data (%ld bytes)\n", data_size
);
3113 /* Skip nMaxSkinWeightsPerVertex and nMaxSkinWeightsPerFace */
3114 data
+= 2 * sizeof(WORD
);
3115 mesh_data
->nb_bones
= *(WORD
*)data
;
3116 hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
, mesh_data
->nb_bones
, &mesh_data
->skin_info
);
3119 DWORD nb_influences
;
3121 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
3122 name
= *(const char**)data
;
3123 data
+= sizeof(char*);
3125 nb_influences
= *(DWORD
*)data
;
3126 data
+= sizeof(DWORD
);
3128 if (data_size
< (sizeof(char*) + sizeof(DWORD
) + nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
)) + 16 * sizeof(FLOAT
))) {
3129 WARN("truncated data (%ld bytes)\n", data_size
);
3133 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneName(mesh_data
->skin_info
, index
, name
);
3135 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneInfluence(mesh_data
->skin_info
, index
, nb_influences
,
3136 (const DWORD
*)data
, (const FLOAT
*)(data
+ nb_influences
* sizeof(DWORD
)));
3138 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneOffsetMatrix(mesh_data
->skin_info
, index
,
3139 (const D3DMATRIX
*)(data
+ nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
))));
3143 filedata
->lpVtbl
->Unlock(filedata
);
3147 /* for provide_flags parameters */
3148 #define PROVIDE_MATERIALS 0x1
3149 #define PROVIDE_SKININFO 0x2
3150 #define PROVIDE_ADJACENCY 0x4
3152 static HRESULT
parse_mesh(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
3156 const BYTE
*data
, *in_ptr
;
3157 DWORD
*index_out_ptr
;
3159 ID3DXFileData
*child
;
3162 DWORD nb_skin_weigths_info
= 0;
3167 * array Vector vertices[nVertices];
3169 * array MeshFace faces[nFaces];
3174 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3175 if (FAILED(hr
)) return hr
;
3180 if (data_size
< sizeof(DWORD
) * 2) {
3181 WARN("truncated data (%ld bytes)\n", data_size
);
3184 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
3185 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
)) {
3186 WARN("truncated data (%ld bytes)\n", data_size
);
3189 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
3191 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
3192 in_ptr
+= sizeof(DWORD
);
3194 mesh_data
->num_tri_faces
= 0;
3195 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3197 DWORD num_poly_vertices
;
3200 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
)) {
3201 WARN("truncated data (%ld bytes)\n", data_size
);
3204 num_poly_vertices
= *(DWORD
*)in_ptr
;
3205 in_ptr
+= sizeof(DWORD
);
3206 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
)) {
3207 WARN("truncated data (%ld bytes)\n", data_size
);
3210 if (num_poly_vertices
< 3) {
3211 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
3214 for (j
= 0; j
< num_poly_vertices
; j
++) {
3215 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
3216 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
3217 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
3220 in_ptr
+= sizeof(DWORD
);
3222 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
3225 mesh_data
->fvf
= D3DFVF_XYZ
;
3227 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
3228 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
3229 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
3230 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
3231 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
3232 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
3233 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
) {
3238 in_ptr
= data
+ sizeof(DWORD
);
3239 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
3240 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
3242 index_out_ptr
= mesh_data
->indices
;
3243 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3247 count
= *(DWORD
*)in_ptr
;
3248 in_ptr
+= sizeof(DWORD
);
3249 mesh_data
->num_tri_per_face
[i
] = count
- 2;
3252 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
3253 in_ptr
+= sizeof(DWORD
);
3257 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3261 for (i
= 0; i
< nb_children
; i
++)
3263 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3266 hr
= child
->lpVtbl
->GetType(child
, &type
);
3270 if (IsEqualGUID(&type
, &TID_D3DRMMeshNormals
)) {
3271 hr
= parse_normals(child
, mesh_data
);
3272 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshVertexColors
)) {
3273 hr
= parse_vertex_colors(child
, mesh_data
);
3274 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshTextureCoords
)) {
3275 hr
= parse_texture_coords(child
, mesh_data
);
3276 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3279 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshMaterialList
) &&
3280 (provide_flags
& PROVIDE_MATERIALS
))
3282 hr
= parse_material_list(child
, mesh_data
);
3283 } else if (provide_flags
& PROVIDE_SKININFO
) {
3284 if (IsEqualGUID(&type
, &DXFILEOBJ_XSkinMeshHeader
)) {
3285 if (mesh_data
->skin_info
) {
3286 WARN("Skin mesh header already encountered\n");
3290 hr
= parse_skin_mesh_info(child
, mesh_data
, 0);
3293 } else if (IsEqualGUID(&type
, &DXFILEOBJ_SkinWeights
)) {
3294 if (!mesh_data
->skin_info
) {
3295 WARN("Skin weigths found but skin mesh header not encountered yet\n");
3299 hr
= parse_skin_mesh_info(child
, mesh_data
, nb_skin_weigths_info
);
3302 nb_skin_weigths_info
++;
3309 if (mesh_data
->skin_info
&& (nb_skin_weigths_info
!= mesh_data
->nb_bones
)) {
3310 WARN("Mismatch between nb skin weights info %u encountered and nb bones %u from skin mesh header\n",
3311 nb_skin_weigths_info
, mesh_data
->nb_bones
);
3319 filedata
->lpVtbl
->Unlock(filedata
);
3323 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
3324 ID3DXBuffer
**effects
)
3327 D3DXEFFECTINSTANCE
*effect_ptr
;
3329 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3330 static const struct {
3331 const char *param_name
;
3335 } material_effects
[] = {
3336 #define EFFECT_TABLE_ENTRY(str, field) \
3337 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
3338 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
3339 EFFECT_TABLE_ENTRY("Power", Power
),
3340 EFFECT_TABLE_ENTRY("Specular", Specular
),
3341 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
3342 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
3343 #undef EFFECT_TABLE_ENTRY
3345 static const char texture_paramname
[] = "Texture0@Name";
3349 /* effects buffer layout:
3351 * D3DXEFFECTINSTANCE effects[num_materials];
3352 * for (effect in effects)
3354 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
3355 * for (default in defaults)
3357 * *default.pParamName;
3362 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
3363 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
3364 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
3365 buffer_size
+= material_effects
[i
].name_size
;
3366 buffer_size
+= material_effects
[i
].num_bytes
;
3368 buffer_size
*= num_materials
;
3369 for (i
= 0; i
< num_materials
; i
++) {
3370 if (material_ptr
[i
].pTextureFilename
) {
3371 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
3372 buffer_size
+= sizeof(texture_paramname
);
3373 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
3377 hr
= D3DXCreateBuffer(buffer_size
, effects
);
3378 if (FAILED(hr
)) return hr
;
3379 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
3380 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
3382 for (i
= 0; i
< num_materials
; i
++)
3385 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
3387 effect_ptr
->pDefaults
= defaults
;
3388 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
3389 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
3391 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
3393 defaults
->pParamName
= (LPSTR
)out_ptr
;
3394 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
3395 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
3396 defaults
->Type
= D3DXEDT_FLOATS
;
3397 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
3398 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
3399 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3403 if (material_ptr
->pTextureFilename
) {
3404 defaults
->pParamName
= (LPSTR
)out_ptr
;
3405 strcpy(defaults
->pParamName
, texture_paramname
);
3406 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
3407 defaults
->Type
= D3DXEDT_STRING
;
3408 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
3409 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
3410 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3415 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
3420 HRESULT WINAPI
D3DXLoadSkinMeshFromXof(struct ID3DXFileData
*filedata
, DWORD options
,
3421 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
3422 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXSkinInfo
**skin_info_out
,
3423 struct ID3DXMesh
**mesh_out
)
3426 DWORD
*index_in_ptr
;
3427 struct mesh_data mesh_data
;
3428 DWORD total_vertices
;
3429 ID3DXMesh
*d3dxmesh
= NULL
;
3430 ID3DXBuffer
*adjacency
= NULL
;
3431 ID3DXBuffer
*materials
= NULL
;
3432 ID3DXBuffer
*effects
= NULL
;
3433 struct vertex_duplication
{
3436 } *duplications
= NULL
;
3438 void *vertices
= NULL
;
3439 void *indices
= NULL
;
3441 DWORD provide_flags
= 0;
3443 TRACE("(%p, %x, %p, %p, %p, %p, %p, %p, %p)\n", filedata
, options
, device
, adjacency_out
, materials_out
,
3444 effects_out
, num_materials_out
, skin_info_out
, mesh_out
);
3446 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
3448 if (num_materials_out
|| materials_out
|| effects_out
)
3449 provide_flags
|= PROVIDE_MATERIALS
;
3451 provide_flags
|= PROVIDE_SKININFO
;
3453 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
3454 if (FAILED(hr
)) goto cleanup
;
3456 total_vertices
= mesh_data
.num_vertices
;
3457 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3458 /* duplicate vertices with multiple normals */
3459 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
3460 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
3461 if (!duplications
) {
3465 for (i
= 0; i
< total_vertices
; i
++)
3467 duplications
[i
].normal_index
= -1;
3468 list_init(&duplications
[i
].entry
);
3470 for (i
= 0; i
< num_face_indices
; i
++) {
3471 DWORD vertex_index
= mesh_data
.indices
[i
];
3472 DWORD normal_index
= mesh_data
.normal_indices
[i
];
3473 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
3475 if (dup_ptr
->normal_index
== -1) {
3476 dup_ptr
->normal_index
= normal_index
;
3478 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
3479 struct list
*dup_list
= &dup_ptr
->entry
;
3481 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
3482 if (new_normal
->x
== cur_normal
->x
&&
3483 new_normal
->y
== cur_normal
->y
&&
3484 new_normal
->z
== cur_normal
->z
)
3486 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3488 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
3489 dup_ptr
= &duplications
[total_vertices
++];
3490 dup_ptr
->normal_index
= normal_index
;
3491 list_add_tail(dup_list
, &dup_ptr
->entry
);
3492 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3495 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
3496 struct vertex_duplication
, entry
);
3503 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
3504 if (FAILED(hr
)) goto cleanup
;
3506 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, 0, &vertices
);
3507 if (FAILED(hr
)) goto cleanup
;
3510 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3511 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
3512 out_ptr
+= sizeof(D3DXVECTOR3
);
3513 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3514 if (duplications
[i
].normal_index
== -1)
3515 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
3517 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
3518 out_ptr
+= sizeof(D3DXVECTOR3
);
3520 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
3521 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
3522 out_ptr
+= sizeof(DWORD
);
3524 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
3525 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
3526 out_ptr
+= sizeof(D3DXVECTOR2
);
3529 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3530 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
3532 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3533 struct vertex_duplication
*dup_ptr
;
3534 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
3536 int j
= dup_ptr
- duplications
;
3537 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
3539 memcpy(dest_vertex
, out_ptr
, vertex_size
);
3540 dest_vertex
+= sizeof(D3DXVECTOR3
);
3541 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
3543 out_ptr
+= vertex_size
;
3546 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
3548 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, 0, &indices
);
3549 if (FAILED(hr
)) goto cleanup
;
3551 index_in_ptr
= mesh_data
.indices
;
3552 #define FILL_INDEX_BUFFER(indices_var) \
3553 for (i = 0; i < mesh_data.num_poly_faces; i++) \
3555 DWORD count = mesh_data.num_tri_per_face[i]; \
3556 WORD first_index = *index_in_ptr++; \
3558 *indices_var++ = first_index; \
3559 *indices_var++ = *index_in_ptr; \
3561 *indices_var++ = *index_in_ptr; \
3565 if (options
& D3DXMESH_32BIT
) {
3566 DWORD
*dword_indices
= indices
;
3567 FILL_INDEX_BUFFER(dword_indices
)
3569 WORD
*word_indices
= indices
;
3570 FILL_INDEX_BUFFER(word_indices
)
3572 #undef FILL_INDEX_BUFFER
3573 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
3575 if (mesh_data
.material_indices
) {
3576 DWORD
*attrib_buffer
= NULL
;
3577 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, 0, &attrib_buffer
);
3578 if (FAILED(hr
)) goto cleanup
;
3579 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
3581 DWORD count
= mesh_data
.num_tri_per_face
[i
];
3583 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
3585 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
3587 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
3588 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
3589 NULL
, NULL
, NULL
, NULL
);
3590 if (FAILED(hr
)) goto cleanup
;
3593 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
3594 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
3595 char *strings_out_ptr
;
3596 D3DXMATERIAL
*materials_ptr
;
3598 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3599 if (mesh_data
.materials
[i
].pTextureFilename
)
3600 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3603 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3604 if (FAILED(hr
)) goto cleanup
;
3606 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3607 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
3608 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
3609 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3610 if (materials_ptr
[i
].pTextureFilename
) {
3611 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
3612 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
3613 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3618 if (mesh_data
.num_materials
&& effects_out
) {
3619 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
3620 if (FAILED(hr
)) goto cleanup
;
3622 if (!materials_out
) {
3623 ID3DXBuffer_Release(materials
);
3628 if (adjacency_out
) {
3629 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
3630 if (FAILED(hr
)) goto cleanup
;
3631 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
3632 if (FAILED(hr
)) goto cleanup
;
3635 *mesh_out
= d3dxmesh
;
3636 if (adjacency_out
) *adjacency_out
= adjacency
;
3637 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
3638 if (materials_out
) *materials_out
= materials
;
3639 if (effects_out
) *effects_out
= effects
;
3640 if (skin_info_out
) *skin_info_out
= mesh_data
.skin_info
;
3645 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
3646 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3647 if (materials
) ID3DXBuffer_Release(materials
);
3648 if (effects
) ID3DXBuffer_Release(effects
);
3649 if (mesh_data
.skin_info
) mesh_data
.skin_info
->lpVtbl
->Release(mesh_data
.skin_info
);
3650 if (skin_info_out
) *skin_info_out
= NULL
;
3652 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
3653 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
3654 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
3655 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
3656 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
3657 destroy_materials(&mesh_data
);
3658 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
3659 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
3660 HeapFree(GetProcessHeap(), 0, duplications
);
3664 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3665 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3666 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3672 TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_a(filename
), options
,
3673 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3676 return D3DERR_INVALIDCALL
;
3678 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3679 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3680 if (!filenameW
) return E_OUTOFMEMORY
;
3681 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3683 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
3684 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3685 HeapFree(GetProcessHeap(), 0, filenameW
);
3690 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3691 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3692 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3698 TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_w(filename
), options
,
3699 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3702 return D3DERR_INVALIDCALL
;
3704 hr
= map_view_of_file(filename
, &buffer
, &size
);
3706 return D3DXERR_INVALIDDATA
;
3708 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
3709 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3711 UnmapViewOfFile(buffer
);
3716 static HRESULT
filedata_get_name(ID3DXFileData
*filedata
, char **name
)
3721 hr
= filedata
->lpVtbl
->GetName(filedata
, NULL
, &name_len
);
3722 if (FAILED(hr
)) return hr
;
3726 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
3727 if (!*name
) return E_OUTOFMEMORY
;
3729 hr
= filedata
->lpVtbl
->GetName(filedata
, *name
, &name_len
);
3731 HeapFree(GetProcessHeap(), 0, *name
);
3738 static HRESULT
load_mesh_container(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3739 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXMESHCONTAINER
**mesh_container
)
3742 ID3DXBuffer
*adjacency
= NULL
;
3743 ID3DXBuffer
*materials
= NULL
;
3744 ID3DXBuffer
*effects
= NULL
;
3745 ID3DXSkinInfo
*skin_info
= NULL
;
3746 D3DXMESHDATA mesh_data
;
3747 DWORD num_materials
= 0;
3750 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
3751 mesh_data
.u
.pMesh
= NULL
;
3753 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
3754 &adjacency
, &materials
, &effects
, &num_materials
,
3755 &skin_info
, &mesh_data
.u
.pMesh
);
3756 if (FAILED(hr
)) return hr
;
3758 hr
= filedata_get_name(filedata
, &name
);
3759 if (FAILED(hr
)) goto cleanup
;
3761 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
3762 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
3763 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
3765 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
3766 skin_info
, mesh_container
);
3769 if (materials
) ID3DXBuffer_Release(materials
);
3770 if (effects
) ID3DXBuffer_Release(effects
);
3771 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3772 if (skin_info
) IUnknown_Release(skin_info
);
3773 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
3774 HeapFree(GetProcessHeap(), 0, name
);
3778 static HRESULT
parse_transform_matrix(ID3DXFileData
*filedata
, D3DXMATRIX
*transform
)
3784 /* template Matrix4x4 {
3785 * array FLOAT matrix[16];
3787 * template FrameTransformMatrix {
3788 * Matrix4x4 frameMatrix;
3792 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3793 if (FAILED(hr
)) return hr
;
3795 if (data_size
!= sizeof(D3DXMATRIX
)) {
3796 WARN("incorrect data size (%ld bytes)\n", data_size
);
3797 filedata
->lpVtbl
->Unlock(filedata
);
3801 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
3803 filedata
->lpVtbl
->Unlock(filedata
);
3807 static HRESULT
load_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3808 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXFRAME
**frame_out
)
3812 ID3DXFileData
*child
;
3814 D3DXFRAME
*frame
= NULL
;
3815 D3DXMESHCONTAINER
**next_container
;
3816 D3DXFRAME
**next_child
;
3820 hr
= filedata_get_name(filedata
, &name
);
3821 if (FAILED(hr
)) return hr
;
3823 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
3824 HeapFree(GetProcessHeap(), 0, name
);
3825 if (FAILED(hr
)) return E_FAIL
;
3828 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
3829 next_child
= &frame
->pFrameFirstChild
;
3830 next_container
= &frame
->pMeshContainer
;
3832 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3836 for (i
= 0; i
< nb_children
; i
++)
3838 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3841 hr
= child
->lpVtbl
->GetType(child
, &type
);
3845 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
3846 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
3848 next_container
= &(*next_container
)->pNextMeshContainer
;
3849 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
3850 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
3851 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
3852 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
3854 next_child
= &(*next_child
)->pFrameSibling
;
3863 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
3864 struct IDirect3DDevice9
*device
, struct ID3DXAllocateHierarchy
*alloc_hier
,
3865 struct ID3DXLoadUserData
*load_user_data
, D3DXFRAME
**frame_hierarchy
,
3866 struct ID3DXAnimationController
**anim_controller
)
3869 ID3DXFile
*d3dxfile
= NULL
;
3870 ID3DXFileEnumObject
*enumobj
= NULL
;
3871 ID3DXFileData
*filedata
= NULL
;
3872 D3DXF_FILELOADMEMORY source
;
3873 D3DXFRAME
*first_frame
= NULL
;
3874 D3DXFRAME
**next_frame
= &first_frame
;
3879 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3880 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3882 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
3883 return D3DERR_INVALIDCALL
;
3884 if (load_user_data
|| anim_controller
) {
3886 FIXME("Loading user data not implemented\n");
3887 if (anim_controller
)
3888 FIXME("Animation controller creation not implemented\n");
3892 hr
= D3DXFileCreate(&d3dxfile
);
3893 if (FAILED(hr
)) goto cleanup
;
3895 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3896 if (FAILED(hr
)) goto cleanup
;
3898 source
.lpMemory
= (void*)memory
;
3899 source
.dSize
= memory_size
;
3900 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
3901 if (FAILED(hr
)) goto cleanup
;
3903 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
3907 for (i
= 0; i
< nb_children
; i
++)
3909 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
3913 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
3914 if (SUCCEEDED(hr
)) {
3915 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
3916 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
3922 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
3924 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
3925 if (FAILED(hr
)) goto cleanup
;
3926 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
3927 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
3928 if (FAILED(hr
)) goto cleanup
;
3931 next_frame
= &(*next_frame
)->pFrameSibling
;
3934 filedata
->lpVtbl
->Release(filedata
);
3942 } else if (first_frame
->pFrameSibling
) {
3943 D3DXFRAME
*root_frame
= NULL
;
3944 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
3949 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
3950 root_frame
->pFrameFirstChild
= first_frame
;
3951 *frame_hierarchy
= root_frame
;
3954 *frame_hierarchy
= first_frame
;
3959 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
3960 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
3961 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
3962 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
3966 HRESULT WINAPI
D3DXCleanMesh(D3DXCLEANTYPE clean_type
, ID3DXMesh
*mesh_in
, const DWORD
*adjacency_in
,
3967 ID3DXMesh
**mesh_out
, DWORD
*adjacency_out
, ID3DXBuffer
**errors_and_warnings
)
3969 FIXME("(%u, %p, %p, %p, %p, %p)\n", clean_type
, mesh_in
, adjacency_in
, mesh_out
, adjacency_out
, errors_and_warnings
);
3974 HRESULT WINAPI
D3DXFrameDestroy(D3DXFRAME
*frame
, ID3DXAllocateHierarchy
*alloc_hier
)
3979 TRACE("(%p, %p)\n", frame
, alloc_hier
);
3981 if (!frame
|| !alloc_hier
)
3982 return D3DERR_INVALIDCALL
;
3985 D3DXMESHCONTAINER
*container
;
3986 D3DXFRAME
*current_frame
;
3988 if (frame
->pFrameSibling
) {
3989 current_frame
= frame
->pFrameSibling
;
3990 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
3991 current_frame
->pFrameSibling
= NULL
;
3993 current_frame
= frame
;
3997 if (current_frame
->pFrameFirstChild
) {
3998 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
3999 if (FAILED(hr
)) return hr
;
4000 current_frame
->pFrameFirstChild
= NULL
;
4003 container
= current_frame
->pMeshContainer
;
4005 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
4006 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
4007 if (FAILED(hr
)) return hr
;
4008 container
= next_container
;
4010 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
4011 if (FAILED(hr
)) return hr
;
4016 HRESULT WINAPI
D3DXLoadMeshFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4017 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4018 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4024 TRACE("(%s, %x, %p, %p, %p, %p, %p, %p)\n", debugstr_a(filename
), options
,
4025 device
, adjacency
, materials
, effect_instances
, num_materials
, mesh
);
4028 return D3DERR_INVALIDCALL
;
4030 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
4031 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4032 if (!filenameW
) return E_OUTOFMEMORY
;
4033 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
4035 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
4036 effect_instances
, num_materials
, mesh
);
4037 HeapFree(GetProcessHeap(), 0, filenameW
);
4042 HRESULT WINAPI
D3DXLoadMeshFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4043 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4044 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4050 TRACE("(%s, %x, %p, %p, %p, %p, %p, %p)\n", debugstr_w(filename
), options
,
4051 device
, adjacency
, materials
, effect_instances
, num_materials
, mesh
);
4054 return D3DERR_INVALIDCALL
;
4056 hr
= map_view_of_file(filename
, &buffer
, &size
);
4058 return D3DXERR_INVALIDDATA
;
4060 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4061 materials
, effect_instances
, num_materials
, mesh
);
4063 UnmapViewOfFile(buffer
);
4068 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
, const char *name
, const char *type
, DWORD options
,
4069 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
,
4070 struct ID3DXBuffer
**effect_instances
, DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4077 TRACE("(%p, %s, %s, %x, %p, %p, %p, %p, %p, %p)\n",
4078 module
, debugstr_a(name
), debugstr_a(type
), options
, device
,
4079 adjacency
, materials
, effect_instances
, num_materials
, mesh
);
4081 resinfo
= FindResourceA(module
, name
, type
);
4082 if (!resinfo
) return D3DXERR_INVALIDDATA
;
4084 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
4085 if (FAILED(hr
)) return D3DXERR_INVALIDDATA
;
4087 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4088 materials
, effect_instances
, num_materials
, mesh
);
4091 struct mesh_container
4095 ID3DXBuffer
*adjacency
;
4096 ID3DXBuffer
*materials
;
4097 ID3DXBuffer
*effects
;
4098 DWORD num_materials
;
4099 D3DXMATRIX transform
;
4102 static HRESULT
parse_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
4103 const D3DXMATRIX
*parent_transform
, struct list
*container_list
, DWORD provide_flags
)
4106 D3DXMATRIX transform
= *parent_transform
;
4107 ID3DXFileData
*child
;
4112 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
4116 for (i
= 0; i
< nb_children
; i
++)
4118 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
4121 hr
= child
->lpVtbl
->GetType(child
, &type
);
4125 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
4126 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
4128 return E_OUTOFMEMORY
;
4129 list_add_tail(container_list
, &container
->entry
);
4130 container
->transform
= transform
;
4132 hr
= D3DXLoadSkinMeshFromXof(child
, options
, device
,
4133 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
4134 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
4135 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
4136 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
4137 D3DXMATRIX new_transform
;
4138 hr
= parse_transform_matrix(child
, &new_transform
);
4139 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
4140 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
4141 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
4150 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
4151 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
4152 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXMesh
**mesh_out
)
4155 ID3DXFile
*d3dxfile
= NULL
;
4156 ID3DXFileEnumObject
*enumobj
= NULL
;
4157 ID3DXFileData
*filedata
= NULL
;
4158 D3DXF_FILELOADMEMORY source
;
4159 ID3DXBuffer
*materials
= NULL
;
4160 ID3DXBuffer
*effects
= NULL
;
4161 ID3DXBuffer
*adjacency
= NULL
;
4162 struct list container_list
= LIST_INIT(container_list
);
4163 struct mesh_container
*container_ptr
, *next_container_ptr
;
4164 DWORD num_materials
;
4165 DWORD num_faces
, num_vertices
;
4166 D3DXMATRIX identity
;
4167 DWORD provide_flags
= 0;
4169 ID3DXMesh
*concat_mesh
= NULL
;
4170 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
4171 BYTE
*concat_vertices
= NULL
;
4172 void *concat_indices
= NULL
;
4174 DWORD concat_vertex_size
;
4179 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
4180 device
, adjacency_out
, materials_out
, effects_out
, num_materials_out
, mesh_out
);
4182 if (!memory
|| !memory_size
|| !device
|| !mesh_out
)
4183 return D3DERR_INVALIDCALL
;
4185 hr
= D3DXFileCreate(&d3dxfile
);
4186 if (FAILED(hr
)) goto cleanup
;
4188 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
4189 if (FAILED(hr
)) goto cleanup
;
4191 source
.lpMemory
= (void*)memory
;
4192 source
.dSize
= memory_size
;
4193 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
4194 if (FAILED(hr
)) goto cleanup
;
4196 D3DXMatrixIdentity(&identity
);
4197 if (adjacency_out
) provide_flags
|= PROVIDE_ADJACENCY
;
4198 if (materials_out
|| effects_out
) provide_flags
|= PROVIDE_MATERIALS
;
4200 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
4204 for (i
= 0; i
< nb_children
; i
++)
4206 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
4210 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
4211 if (SUCCEEDED(hr
)) {
4212 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
4213 container_ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container_ptr
));
4214 if (!container_ptr
) {
4218 list_add_tail(&container_list
, &container_ptr
->entry
);
4219 D3DXMatrixIdentity(&container_ptr
->transform
);
4221 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
4222 (provide_flags
& PROVIDE_ADJACENCY
) ? &container_ptr
->adjacency
: NULL
,
4223 (provide_flags
& PROVIDE_MATERIALS
) ? &container_ptr
->materials
: NULL
,
4224 NULL
, &container_ptr
->num_materials
, NULL
, &container_ptr
->mesh
);
4225 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
4226 hr
= parse_frame(filedata
, options
, device
, &identity
, &container_list
, provide_flags
);
4228 if (FAILED(hr
)) goto cleanup
;
4230 filedata
->lpVtbl
->Release(filedata
);
4236 enumobj
->lpVtbl
->Release(enumobj
);
4238 d3dxfile
->lpVtbl
->Release(d3dxfile
);
4241 if (list_empty(&container_list
)) {
4250 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4252 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4253 fvf
|= mesh
->lpVtbl
->GetFVF(mesh
);
4254 num_faces
+= mesh
->lpVtbl
->GetNumFaces(mesh
);
4255 num_vertices
+= mesh
->lpVtbl
->GetNumVertices(mesh
);
4256 num_materials
+= container_ptr
->num_materials
;
4259 hr
= D3DXCreateMeshFVF(num_faces
, num_vertices
, options
, fvf
, device
, &concat_mesh
);
4260 if (FAILED(hr
)) goto cleanup
;
4262 hr
= concat_mesh
->lpVtbl
->GetDeclaration(concat_mesh
, concat_decl
);
4263 if (FAILED(hr
)) goto cleanup
;
4265 concat_vertex_size
= D3DXGetDeclVertexSize(concat_decl
, 0);
4267 hr
= concat_mesh
->lpVtbl
->LockVertexBuffer(concat_mesh
, 0, (void**)&concat_vertices
);
4268 if (FAILED(hr
)) goto cleanup
;
4270 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4272 D3DVERTEXELEMENT9 mesh_decl
[MAX_FVF_DECL_SIZE
];
4273 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4274 DWORD num_mesh_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
4275 DWORD mesh_vertex_size
;
4276 const BYTE
*mesh_vertices
;
4279 hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, mesh_decl
);
4280 if (FAILED(hr
)) goto cleanup
;
4282 mesh_vertex_size
= D3DXGetDeclVertexSize(mesh_decl
, 0);
4284 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_vertices
);
4285 if (FAILED(hr
)) goto cleanup
;
4287 for (i
= 0; i
< num_mesh_vertices
; i
++) {
4291 D3DXVec3TransformCoord((D3DXVECTOR3
*)concat_vertices
,
4292 (D3DXVECTOR3
*)mesh_vertices
,
4293 &container_ptr
->transform
);
4294 for (j
= 1; concat_decl
[j
].Stream
!= 0xff; j
++)
4296 if (concat_decl
[j
].Usage
== mesh_decl
[k
].Usage
&&
4297 concat_decl
[j
].UsageIndex
== mesh_decl
[k
].UsageIndex
)
4299 if (concat_decl
[j
].Usage
== D3DDECLUSAGE_NORMAL
) {
4300 D3DXVec3TransformCoord((D3DXVECTOR3
*)(concat_vertices
+ concat_decl
[j
].Offset
),
4301 (D3DXVECTOR3
*)(mesh_vertices
+ mesh_decl
[k
].Offset
),
4302 &container_ptr
->transform
);
4304 memcpy(concat_vertices
+ concat_decl
[j
].Offset
,
4305 mesh_vertices
+ mesh_decl
[k
].Offset
,
4306 d3dx_decltype_size
[mesh_decl
[k
].Type
]);
4311 mesh_vertices
+= mesh_vertex_size
;
4312 concat_vertices
+= concat_vertex_size
;
4315 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
4318 concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4319 concat_vertices
= NULL
;
4321 hr
= concat_mesh
->lpVtbl
->LockIndexBuffer(concat_mesh
, 0, &concat_indices
);
4322 if (FAILED(hr
)) goto cleanup
;
4325 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4327 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4328 const void *mesh_indices
;
4329 DWORD num_mesh_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4332 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_indices
);
4333 if (FAILED(hr
)) goto cleanup
;
4335 if (options
& D3DXMESH_32BIT
) {
4336 DWORD
*dest
= concat_indices
;
4337 const DWORD
*src
= mesh_indices
;
4338 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4339 *dest
++ = index_offset
+ *src
++;
4340 concat_indices
= dest
;
4342 WORD
*dest
= concat_indices
;
4343 const WORD
*src
= mesh_indices
;
4344 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4345 *dest
++ = index_offset
+ *src
++;
4346 concat_indices
= dest
;
4348 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
4350 index_offset
+= num_mesh_faces
* 3;
4353 concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4354 concat_indices
= NULL
;
4356 if (num_materials
) {
4357 DWORD
*concat_attrib_buffer
= NULL
;
4360 hr
= concat_mesh
->lpVtbl
->LockAttributeBuffer(concat_mesh
, 0, &concat_attrib_buffer
);
4361 if (FAILED(hr
)) goto cleanup
;
4363 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4365 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4366 const DWORD
*mesh_attrib_buffer
= NULL
;
4367 DWORD count
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4369 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, D3DLOCK_READONLY
, (DWORD
**)&mesh_attrib_buffer
);
4371 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4376 *concat_attrib_buffer
++ = offset
+ *mesh_attrib_buffer
++;
4378 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
4379 offset
+= container_ptr
->num_materials
;
4381 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4384 if (materials_out
|| effects_out
) {
4385 D3DXMATERIAL
*out_ptr
;
4386 if (!num_materials
) {
4387 /* create default material */
4388 hr
= D3DXCreateBuffer(sizeof(D3DXMATERIAL
), &materials
);
4389 if (FAILED(hr
)) goto cleanup
;
4391 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4392 out_ptr
->MatD3D
.Diffuse
.r
= 0.5f
;
4393 out_ptr
->MatD3D
.Diffuse
.g
= 0.5f
;
4394 out_ptr
->MatD3D
.Diffuse
.b
= 0.5f
;
4395 out_ptr
->MatD3D
.Specular
.r
= 0.5f
;
4396 out_ptr
->MatD3D
.Specular
.g
= 0.5f
;
4397 out_ptr
->MatD3D
.Specular
.b
= 0.5f
;
4398 /* D3DXCreateBuffer initializes the rest to zero */
4400 DWORD buffer_size
= num_materials
* sizeof(D3DXMATERIAL
);
4401 char *strings_out_ptr
;
4403 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4405 if (container_ptr
->materials
) {
4407 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4408 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4410 if (in_ptr
->pTextureFilename
)
4411 buffer_size
+= strlen(in_ptr
->pTextureFilename
) + 1;
4417 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
4418 if (FAILED(hr
)) goto cleanup
;
4419 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4420 strings_out_ptr
= (char*)(out_ptr
+ num_materials
);
4422 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4424 if (container_ptr
->materials
) {
4426 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4427 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4429 out_ptr
->MatD3D
= in_ptr
->MatD3D
;
4430 if (in_ptr
->pTextureFilename
) {
4431 out_ptr
->pTextureFilename
= strings_out_ptr
;
4432 strcpy(out_ptr
->pTextureFilename
, in_ptr
->pTextureFilename
);
4433 strings_out_ptr
+= strlen(in_ptr
->pTextureFilename
) + 1;
4446 generate_effects(materials
, num_materials
, &effects
);
4447 if (!materials_out
) {
4448 ID3DXBuffer_Release(materials
);
4453 if (adjacency_out
) {
4454 if (!list_next(&container_list
, list_head(&container_list
))) {
4455 container_ptr
= LIST_ENTRY(list_head(&container_list
), struct mesh_container
, entry
);
4456 adjacency
= container_ptr
->adjacency
;
4457 container_ptr
->adjacency
= NULL
;
4462 hr
= D3DXCreateBuffer(num_faces
* 3 * sizeof(DWORD
), &adjacency
);
4463 if (FAILED(hr
)) goto cleanup
;
4465 out_ptr
= ID3DXBuffer_GetBufferPointer(adjacency
);
4466 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4469 DWORD count
= 3 * container_ptr
->mesh
->lpVtbl
->GetNumFaces(container_ptr
->mesh
);
4470 DWORD
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->adjacency
);
4472 for (i
= 0; i
< count
; i
++)
4473 *out_ptr
++ = offset
+ *in_ptr
++;
4480 *mesh_out
= concat_mesh
;
4481 if (adjacency_out
) *adjacency_out
= adjacency
;
4482 if (materials_out
) *materials_out
= materials
;
4483 if (effects_out
) *effects_out
= effects
;
4484 if (num_materials_out
) *num_materials_out
= num_materials
;
4488 if (concat_indices
) concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4489 if (concat_vertices
) concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4490 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
4491 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
4492 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4494 if (concat_mesh
) IUnknown_Release(concat_mesh
);
4495 if (materials
) ID3DXBuffer_Release(materials
);
4496 if (effects
) ID3DXBuffer_Release(effects
);
4497 if (adjacency
) ID3DXBuffer_Release(adjacency
);
4499 LIST_FOR_EACH_ENTRY_SAFE(container_ptr
, next_container_ptr
, &container_list
, struct mesh_container
, entry
)
4501 if (container_ptr
->mesh
) IUnknown_Release(container_ptr
->mesh
);
4502 if (container_ptr
->adjacency
) ID3DXBuffer_Release(container_ptr
->adjacency
);
4503 if (container_ptr
->materials
) ID3DXBuffer_Release(container_ptr
->materials
);
4504 if (container_ptr
->effects
) ID3DXBuffer_Release(container_ptr
->effects
);
4505 HeapFree(GetProcessHeap(), 0, container_ptr
);
4510 HRESULT WINAPI
D3DXCreateBox(struct IDirect3DDevice9
*device
, float width
, float height
,
4511 float depth
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4513 FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device
, width
, height
, depth
, mesh
, adjacency
);
4520 D3DXVECTOR3 position
;
4524 typedef WORD face
[3];
4532 static void free_sincos_table(struct sincos_table
*sincos_table
)
4534 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
4535 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4538 /* pre compute sine and cosine tables; caller must free */
4539 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
4544 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
4545 if (!sincos_table
->sin
)
4549 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
4550 if (!sincos_table
->cos
)
4552 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4556 angle
= angle_start
;
4557 for (i
= 0; i
< n
; i
++)
4559 sincos_table
->sin
[i
] = sin(angle
);
4560 sincos_table
->cos
[i
] = cos(angle
);
4561 angle
+= angle_step
;
4567 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
4569 return stack
*slices
+slice
+1;
4572 HRESULT WINAPI
D3DXCreateSphere(struct IDirect3DDevice9
*device
, float radius
, UINT slices
,
4573 UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4575 DWORD number_of_vertices
, number_of_faces
;
4578 struct vertex
*vertices
;
4580 float phi_step
, phi_start
;
4581 struct sincos_table phi
;
4582 float theta_step
, theta
, sin_theta
, cos_theta
;
4583 DWORD vertex
, face
, stack
, slice
;
4585 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
4587 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
4589 return D3DERR_INVALIDCALL
;
4594 FIXME("Case of adjacency != NULL not implemented.\n");
4598 number_of_vertices
= 2 + slices
* (stacks
-1);
4599 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
4601 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4602 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
4608 hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, 0, (LPVOID
*)&vertices
);
4611 sphere
->lpVtbl
->Release(sphere
);
4615 hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, 0, (LPVOID
*)&faces
);
4618 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4619 sphere
->lpVtbl
->Release(sphere
);
4623 /* phi = angle on xz plane wrt z axis */
4624 phi_step
= -2 * M_PI
/ slices
;
4625 phi_start
= M_PI
/ 2;
4627 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
4629 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4630 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4631 sphere
->lpVtbl
->Release(sphere
);
4632 return E_OUTOFMEMORY
;
4635 /* theta = angle on xy plane wrt x axis */
4636 theta_step
= M_PI
/ stacks
;
4642 vertices
[vertex
].normal
.x
= 0.0f
;
4643 vertices
[vertex
].normal
.y
= 0.0f
;
4644 vertices
[vertex
].normal
.z
= 1.0f
;
4645 vertices
[vertex
].position
.x
= 0.0f
;
4646 vertices
[vertex
].position
.y
= 0.0f
;
4647 vertices
[vertex
].position
.z
= radius
;
4650 for (stack
= 0; stack
< stacks
- 1; stack
++)
4652 sin_theta
= sin(theta
);
4653 cos_theta
= cos(theta
);
4655 for (slice
= 0; slice
< slices
; slice
++)
4657 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
4658 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
4659 vertices
[vertex
].normal
.z
= cos_theta
;
4660 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
4661 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
4662 vertices
[vertex
].position
.z
= radius
* cos_theta
;
4669 /* top stack is triangle fan */
4671 faces
[face
][1] = slice
+ 1;
4672 faces
[face
][2] = slice
;
4677 /* stacks in between top and bottom are quad strips */
4678 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4679 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4680 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4683 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4684 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
4685 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4691 theta
+= theta_step
;
4697 faces
[face
][2] = slice
;
4702 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4703 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4704 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4707 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4708 faces
[face
][1] = vertex_index(slices
, 0, stack
);
4709 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4714 vertices
[vertex
].position
.x
= 0.0f
;
4715 vertices
[vertex
].position
.y
= 0.0f
;
4716 vertices
[vertex
].position
.z
= -radius
;
4717 vertices
[vertex
].normal
.x
= 0.0f
;
4718 vertices
[vertex
].normal
.y
= 0.0f
;
4719 vertices
[vertex
].normal
.z
= -1.0f
;
4721 /* bottom stack is triangle fan */
4722 for (slice
= 1; slice
< slices
; slice
++)
4724 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4725 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4726 faces
[face
][2] = vertex
;
4730 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4731 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4732 faces
[face
][2] = vertex
;
4734 free_sincos_table(&phi
);
4735 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4736 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4742 HRESULT WINAPI
D3DXCreateCylinder(struct IDirect3DDevice9
*device
, float radius1
, float radius2
,
4743 float length
, UINT slices
, UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4745 DWORD number_of_vertices
, number_of_faces
;
4747 ID3DXMesh
*cylinder
;
4748 struct vertex
*vertices
;
4750 float theta_step
, theta_start
;
4751 struct sincos_table theta
;
4752 float delta_radius
, radius
, radius_step
;
4753 float z
, z_step
, z_normal
;
4754 DWORD vertex
, face
, slice
, stack
;
4756 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
4758 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
4760 return D3DERR_INVALIDCALL
;
4765 FIXME("Case of adjacency != NULL not implemented.\n");
4769 number_of_vertices
= 2 + (slices
* (3 + stacks
));
4770 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
4772 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4773 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
4779 hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, 0, (LPVOID
*)&vertices
);
4782 cylinder
->lpVtbl
->Release(cylinder
);
4786 hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, 0, (LPVOID
*)&faces
);
4789 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4790 cylinder
->lpVtbl
->Release(cylinder
);
4794 /* theta = angle on xy plane wrt x axis */
4795 theta_step
= -2 * M_PI
/ slices
;
4796 theta_start
= M_PI
/ 2;
4798 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
4800 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
4801 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4802 cylinder
->lpVtbl
->Release(cylinder
);
4803 return E_OUTOFMEMORY
;
4809 delta_radius
= radius1
- radius2
;
4811 radius_step
= delta_radius
/ stacks
;
4814 z_step
= length
/ stacks
;
4815 z_normal
= delta_radius
/ length
;
4816 if (isnan(z_normal
))
4821 vertices
[vertex
].normal
.x
= 0.0f
;
4822 vertices
[vertex
].normal
.y
= 0.0f
;
4823 vertices
[vertex
].normal
.z
= -1.0f
;
4824 vertices
[vertex
].position
.x
= 0.0f
;
4825 vertices
[vertex
].position
.y
= 0.0f
;
4826 vertices
[vertex
++].position
.z
= z
;
4828 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4830 vertices
[vertex
].normal
.x
= 0.0f
;
4831 vertices
[vertex
].normal
.y
= 0.0f
;
4832 vertices
[vertex
].normal
.z
= -1.0f
;
4833 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4834 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4835 vertices
[vertex
].position
.z
= z
;
4840 faces
[face
][1] = slice
;
4841 faces
[face
++][2] = slice
+ 1;
4846 faces
[face
][1] = slice
;
4847 faces
[face
++][2] = 1;
4849 for (stack
= 1; stack
<= stacks
+1; stack
++)
4851 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4853 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
4854 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
4855 vertices
[vertex
].normal
.z
= z_normal
;
4856 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
4857 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4858 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4859 vertices
[vertex
].position
.z
= z
;
4861 if (stack
> 1 && slice
> 0)
4863 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4864 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4865 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
4867 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4868 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4869 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
4875 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4876 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4877 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
4879 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4880 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4881 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
4884 if (stack
< stacks
+ 1)
4887 radius
-= radius_step
;
4891 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4893 vertices
[vertex
].normal
.x
= 0.0f
;
4894 vertices
[vertex
].normal
.y
= 0.0f
;
4895 vertices
[vertex
].normal
.z
= 1.0f
;
4896 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4897 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4898 vertices
[vertex
].position
.z
= z
;
4902 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
4903 faces
[face
][1] = number_of_vertices
- 1;
4904 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
4908 vertices
[vertex
].position
.x
= 0.0f
;
4909 vertices
[vertex
].position
.y
= 0.0f
;
4910 vertices
[vertex
].position
.z
= z
;
4911 vertices
[vertex
].normal
.x
= 0.0f
;
4912 vertices
[vertex
].normal
.y
= 0.0f
;
4913 vertices
[vertex
].normal
.z
= 1.0f
;
4915 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
4916 faces
[face
][1] = number_of_vertices
- 1;
4917 faces
[face
][2] = vertex_index(slices
, 0, stack
);
4919 free_sincos_table(&theta
);
4920 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
4921 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4927 HRESULT WINAPI
D3DXCreateTeapot(struct IDirect3DDevice9
*device
,
4928 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4930 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
4935 HRESULT WINAPI
D3DXCreateTextA(struct IDirect3DDevice9
*device
, HDC hdc
, const char *text
, float deviation
,
4936 float extrusion
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
4942 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
4943 debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
4946 return D3DERR_INVALIDCALL
;
4948 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
4949 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4950 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
4952 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
4953 mesh
, adjacency
, glyphmetrics
);
4954 HeapFree(GetProcessHeap(), 0, textW
);
4960 POINTTYPE_CURVE
= 0,
4962 POINTTYPE_CURVE_START
,
4963 POINTTYPE_CURVE_END
,
4964 POINTTYPE_CURVE_MIDDLE
,
4970 enum pointtype corner
;
4973 struct dynamic_array
4975 int count
, capacity
;
4979 /* is a dynamic_array */
4982 int count
, capacity
;
4983 struct point2d
*items
;
4986 /* is a dynamic_array */
4987 struct outline_array
4989 int count
, capacity
;
4990 struct outline
*items
;
4999 struct point2d_index
5001 struct outline
*outline
;
5005 struct point2d_index_array
5008 struct point2d_index
*items
;
5013 struct outline_array outlines
;
5014 struct face_array faces
;
5015 struct point2d_index_array ordered_vertices
;
5019 /* is an dynamic_array */
5022 int count
, capacity
;
5026 /* complex polygons are split into monotone polygons, which have
5027 * at most 2 intersections with the vertical sweep line */
5028 struct triangulation
5030 struct word_array vertex_stack
;
5031 BOOL last_on_top
, merging
;
5034 /* is an dynamic_array */
5035 struct triangulation_array
5037 int count
, capacity
;
5038 struct triangulation
*items
;
5040 struct glyphinfo
*glyph
;
5043 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
5045 if (count
> array
->capacity
) {
5048 if (array
->items
&& array
->capacity
) {
5049 new_capacity
= max(array
->capacity
* 2, count
);
5050 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
5052 new_capacity
= max(16, count
);
5053 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
5057 array
->items
= new_buffer
;
5058 array
->capacity
= new_capacity
;
5063 static struct point2d
*add_points(struct outline
*array
, int num
)
5065 struct point2d
*item
;
5067 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
5070 item
= &array
->items
[array
->count
];
5071 array
->count
+= num
;
5075 static struct outline
*add_outline(struct outline_array
*array
)
5077 struct outline
*item
;
5079 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5082 item
= &array
->items
[array
->count
++];
5083 ZeroMemory(item
, sizeof(*item
));
5087 static inline face
*add_face(struct face_array
*array
)
5089 return &array
->items
[array
->count
++];
5092 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
5094 struct triangulation
*item
;
5096 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5099 item
= &array
->items
[array
->count
++];
5100 ZeroMemory(item
, sizeof(*item
));
5104 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
5106 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5107 return E_OUTOFMEMORY
;
5109 array
->items
[array
->count
++] = vertex_index
;
5113 /* assume fixed point numbers can be converted to float point in place */
5114 C_ASSERT(sizeof(FIXED
) == sizeof(float));
5115 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
5117 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, float emsquare
)
5119 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
5121 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
5122 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
5123 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
5129 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
5130 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
5131 float max_deviation_sq
)
5133 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
5136 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
5137 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
5138 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
5140 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
5141 if (deviation_sq
< max_deviation_sq
) {
5142 struct point2d
*pt
= add_points(outline
, 1);
5143 if (!pt
) return E_OUTOFMEMORY
;
5145 pt
->corner
= POINTTYPE_CURVE
;
5146 /* the end point is omitted because the end line merges into the next segment of
5147 * the split bezier curve, and the end of the split bezier curve is added outside
5148 * this recursive function. */
5150 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
5151 if (hr
!= S_OK
) return hr
;
5152 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
5153 if (hr
!= S_OK
) return hr
;
5159 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
5161 /* dot product = cos(theta) */
5162 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
5165 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
5167 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
5177 static BOOL
attempt_line_merge(struct outline
*outline
,
5179 const D3DXVECTOR2
*nextpt
,
5181 const struct cos_table
*table
)
5183 D3DXVECTOR2 curdir
, lastdir
;
5184 struct point2d
*prevpt
, *pt
;
5187 pt
= &outline
->items
[pt_index
];
5188 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5189 prevpt
= &outline
->items
[pt_index
];
5192 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
5194 if (outline
->count
< 2)
5197 /* remove last point if the next line continues the last line */
5198 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5199 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5200 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
5203 if (pt
->corner
== POINTTYPE_CURVE_END
)
5204 prevpt
->corner
= pt
->corner
;
5205 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
5206 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5210 if (outline
->count
< 2)
5213 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5214 prevpt
= &outline
->items
[pt_index
];
5215 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5216 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5221 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
5222 float max_deviation_sq
, float emsquare
, const struct cos_table
*cos_table
)
5224 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
5226 while ((char *)header
< (char *)raw_outline
+ datasize
)
5228 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
5229 struct point2d
*lastpt
, *pt
;
5230 D3DXVECTOR2 lastdir
;
5231 D3DXVECTOR2
*pt_flt
;
5233 struct outline
*outline
= add_outline(&glyph
->outlines
);
5236 return E_OUTOFMEMORY
;
5238 pt
= add_points(outline
, 1);
5240 return E_OUTOFMEMORY
;
5241 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
5243 pt
->corner
= POINTTYPE_CORNER
;
5245 if (header
->dwType
!= TT_POLYGON_TYPE
)
5246 FIXME("Unknown header type %d\n", header
->dwType
);
5248 while ((char *)curve
< (char *)header
+ header
->cb
)
5250 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
5251 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
5252 unsigned int j2
= 0;
5255 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5259 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
5261 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
5266 int count
= curve
->cpfx
;
5270 D3DXVECTOR2 bezier_end
;
5272 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j2
], &pt_flt
[j2
+1]), 0.5f
);
5273 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &bezier_end
, max_deviation_sq
);
5276 bezier_start
= bezier_end
;
5280 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &pt_flt
[j2
+1], max_deviation_sq
);
5284 pt
= add_points(outline
, 1);
5286 return E_OUTOFMEMORY
;
5288 pt
->pos
= pt_flt
[j2
];
5289 pt
->corner
= POINTTYPE_CURVE_END
;
5291 pt
= add_points(outline
, curve
->cpfx
);
5293 return E_OUTOFMEMORY
;
5294 for (j2
= 0; j2
< curve
->cpfx
; j2
++)
5296 pt
->pos
= pt_flt
[j2
];
5297 pt
->corner
= POINTTYPE_CORNER
;
5302 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5305 /* remove last point if the next line continues the last line */
5306 if (outline
->count
>= 3) {
5309 lastpt
= &outline
->items
[outline
->count
- 1];
5310 pt
= &outline
->items
[0];
5311 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
5312 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
5314 if (pt
->corner
== POINTTYPE_CURVE_START
)
5315 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5317 pt
->corner
= POINTTYPE_CURVE_END
;
5320 lastpt
= &outline
->items
[outline
->count
- 1];
5322 /* outline closed with a line from end to start point */
5323 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
5325 lastpt
= &outline
->items
[0];
5326 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
5327 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
5328 lastpt
->corner
= POINTTYPE_CORNER
;
5329 pt
= &outline
->items
[1];
5330 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
5331 *lastpt
= outline
->items
[outline
->count
];
5334 lastpt
= &outline
->items
[outline
->count
- 1];
5335 pt
= &outline
->items
[0];
5336 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
5337 for (j
= 0; j
< outline
->count
; j
++)
5342 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
5343 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
5345 switch (lastpt
->corner
)
5347 case POINTTYPE_CURVE_START
:
5348 case POINTTYPE_CURVE_END
:
5349 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
5350 lastpt
->corner
= POINTTYPE_CORNER
;
5352 case POINTTYPE_CURVE_MIDDLE
:
5353 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
5354 lastpt
->corner
= POINTTYPE_CORNER
;
5356 lastpt
->corner
= POINTTYPE_CURVE
;
5364 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
5369 /* Get the y-distance from a line to a point */
5370 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
5371 D3DXVECTOR2
*line_pt2
,
5374 D3DXVECTOR2 line_vec
= {0, 0};
5378 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
5379 line_pt_dx
= point
->x
- line_pt1
->x
;
5380 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
5381 return point
->y
- line_y
;
5384 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
5386 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
5389 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
5391 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
5394 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
5396 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
5397 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
5401 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
5402 struct triangulation_array
*triangulations
,
5406 struct glyphinfo
*glyph
= triangulations
->glyph
;
5407 struct triangulation
*t
= *t_ptr
;
5412 if (t
->last_on_top
) {
5420 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
5421 /* consume all vertices on the stack */
5422 WORD last_pt
= t
->vertex_stack
.items
[0];
5424 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
5426 face
= add_face(&glyph
->faces
);
5427 if (!face
) return E_OUTOFMEMORY
;
5428 (*face
)[0] = vtx_idx
;
5429 (*face
)[f1
] = last_pt
;
5430 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
5432 t
->vertex_stack
.items
[0] = last_pt
;
5433 t
->vertex_stack
.count
= 1;
5434 } else if (t
->vertex_stack
.count
> 1) {
5435 int i
= t
->vertex_stack
.count
- 1;
5436 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
5437 WORD top_idx
= t
->vertex_stack
.items
[i
--];
5438 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
5442 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
5443 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
5445 if (prev_pt
->x
!= top_pt
->x
&&
5446 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
5447 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
5450 face
= add_face(&glyph
->faces
);
5451 if (!face
) return E_OUTOFMEMORY
;
5452 (*face
)[0] = vtx_idx
;
5453 (*face
)[f1
] = prev_idx
;
5454 (*face
)[f2
] = top_idx
;
5458 t
->vertex_stack
.count
--;
5461 t
->last_on_top
= to_top
;
5463 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
5465 if (hr
== S_OK
&& t
->merging
) {
5466 struct triangulation
*t2
;
5468 t2
= to_top
? t
- 1 : t
+ 1;
5469 t2
->merging
= FALSE
;
5470 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
5471 if (hr
!= S_OK
) return hr
;
5472 remove_triangulation(triangulations
, t
);
5480 /* check if the point is next on the outline for either the top or bottom */
5481 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
5483 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
5484 WORD idx
= t
->vertex_stack
.items
[i
];
5485 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
5486 struct outline
*outline
= pt_idx
->outline
;
5489 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
5491 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
5493 return &outline
->items
[i
].pos
;
5496 static int compare_vertex_indices(const void *a
, const void *b
)
5498 const struct point2d_index
*idx1
= a
, *idx2
= b
;
5499 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
5500 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
5501 float diff
= p1
->x
- p2
->x
;
5504 diff
= p1
->y
- p2
->y
;
5506 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
5509 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
5513 struct glyphinfo
*glyph
= triangulations
->glyph
;
5514 int nb_vertices
= 0;
5516 struct point2d_index
*idx_ptr
;
5518 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5519 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
5521 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
5522 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
5523 if (!glyph
->ordered_vertices
.items
)
5524 return E_OUTOFMEMORY
;
5526 idx_ptr
= glyph
->ordered_vertices
.items
;
5527 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5529 struct outline
*outline
= &glyph
->outlines
.items
[i
];
5532 idx_ptr
->outline
= outline
;
5533 idx_ptr
->vertex
= 0;
5535 for (j
= outline
->count
- 1; j
> 0; j
--)
5537 idx_ptr
->outline
= outline
;
5538 idx_ptr
->vertex
= j
;
5542 glyph
->ordered_vertices
.count
= nb_vertices
;
5544 /* Native implementation seems to try to create a triangle fan from
5545 * the first outline point if the glyph only has one outline. */
5546 if (glyph
->outlines
.count
== 1)
5548 struct outline
*outline
= glyph
->outlines
.items
;
5549 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
5550 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
5553 for (i
= 2; i
< outline
->count
; i
++)
5555 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
5556 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
5557 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
5559 D3DXVec2Subtract(&v1
, base
, last
);
5560 D3DXVec2Subtract(&v2
, last
, next
);
5561 ccw
= D3DXVec2CCW(&v1
, &v2
);
5569 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5570 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
5571 if (!glyph
->faces
.items
)
5572 return E_OUTOFMEMORY
;
5574 glyph
->faces
.count
= outline
->count
- 2;
5575 for (i
= 0; i
< glyph
->faces
.count
; i
++)
5577 glyph
->faces
.items
[i
][0] = 0;
5578 glyph
->faces
.items
[i
][1] = i
+ 1;
5579 glyph
->faces
.items
[i
][2] = i
+ 2;
5585 /* Perform 2D polygon triangulation for complex glyphs.
5586 * Triangulation is performed using a sweep line concept, from right to left,
5587 * by processing vertices in sorted order. Complex polygons are split into
5588 * monotone polygons which are triangulated separately. */
5589 /* FIXME: The order of the faces is not consistent with the native implementation. */
5591 /* Reserve space for maximum possible faces from triangulation.
5592 * # faces for outer outlines = outline->count - 2
5593 * # faces for inner outlines = outline->count + 2
5594 * There must be at least 1 outer outline. */
5595 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5596 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
5597 if (!glyph
->faces
.items
)
5598 return E_OUTOFMEMORY
;
5600 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
5601 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
5602 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
5605 int end
= triangulations
->count
;
5609 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
5610 int current
= (start
+ end
) / 2;
5611 struct triangulation
*t
= &triangulations
->items
[current
];
5612 BOOL on_top_outline
= FALSE
;
5613 D3DXVECTOR2
*top_next
, *bottom_next
;
5614 WORD top_idx
, bottom_idx
;
5616 if (t
->merging
&& t
->last_on_top
)
5617 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
5619 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
5620 if (sweep_vtx
== top_next
)
5622 if (t
->merging
&& t
->last_on_top
)
5624 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
5625 if (hr
!= S_OK
) return hr
;
5627 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
5628 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
5630 /* point also on bottom outline of higher triangulation */
5631 struct triangulation
*t2
= t
+ 1;
5632 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
5633 if (hr
!= S_OK
) return hr
;
5638 on_top_outline
= TRUE
;
5641 if (t
->merging
&& !t
->last_on_top
)
5642 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
5644 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
5645 if (sweep_vtx
== bottom_next
)
5647 if (t
->merging
&& !t
->last_on_top
)
5649 if (on_top_outline
) {
5650 /* outline finished */
5651 remove_triangulation(triangulations
, t
);
5655 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
5656 if (hr
!= S_OK
) return hr
;
5658 if (t
> triangulations
->items
&&
5659 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
5661 struct triangulation
*t2
= t
- 1;
5662 /* point also on top outline of lower triangulation */
5663 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
5664 if (hr
!= S_OK
) return hr
;
5665 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
5675 if (t
->last_on_top
) {
5676 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
5677 bottom_idx
= t
->vertex_stack
.items
[0];
5679 top_idx
= t
->vertex_stack
.items
[0];
5680 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
5683 /* check if the point is inside or outside this polygon */
5684 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
5685 top_next
, sweep_vtx
) > 0)
5687 start
= current
+ 1;
5688 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
5689 bottom_next
, sweep_vtx
) < 0)
5692 } else if (t
->merging
) {
5693 /* inside, so cancel merging */
5694 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
5696 t2
->merging
= FALSE
;
5697 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
5698 if (hr
!= S_OK
) return hr
;
5699 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
5700 if (hr
!= S_OK
) return hr
;
5703 /* inside, so split polygon into two monotone parts */
5704 struct triangulation
*t2
= add_triangulation(triangulations
);
5705 if (!t2
) return E_OUTOFMEMORY
;
5706 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
5707 if (t
->last_on_top
) {
5714 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
5715 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
5716 if (hr
!= S_OK
) return hr
;
5717 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
5718 if (hr
!= S_OK
) return hr
;
5719 t2
->last_on_top
= !t
->last_on_top
;
5721 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
5722 if (hr
!= S_OK
) return hr
;
5728 struct triangulation
*t
;
5729 struct triangulation
*t2
= add_triangulation(triangulations
);
5730 if (!t2
) return E_OUTOFMEMORY
;
5731 t
= &triangulations
->items
[start
];
5732 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
5733 ZeroMemory(t
, sizeof(*t
));
5734 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
5735 if (hr
!= S_OK
) return hr
;
5741 HRESULT WINAPI
D3DXCreateTextW(struct IDirect3DDevice9
*device
, HDC hdc
, const WCHAR
*text
, float deviation
,
5742 float extrusion
, struct ID3DXMesh
**mesh_ptr
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5745 ID3DXMesh
*mesh
= NULL
;
5746 DWORD nb_vertices
, nb_faces
;
5747 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
5748 struct vertex
*vertices
= NULL
;
5753 OUTLINETEXTMETRICW otm
;
5754 HFONT font
= NULL
, oldfont
= NULL
;
5755 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
5756 void *raw_outline
= NULL
;
5758 struct glyphinfo
*glyphs
= NULL
;
5760 struct triangulation_array triangulations
= {0, 0, NULL
};
5762 struct vertex
*vertex_ptr
;
5764 float max_deviation_sq
;
5765 const struct cos_table cos_table
= {
5766 cos(D3DXToRadian(0.5f
)),
5767 cos(D3DXToRadian(45.0f
)),
5768 cos(D3DXToRadian(90.0f
)),
5772 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
5773 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
5775 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
5776 return D3DERR_INVALIDCALL
;
5780 FIXME("Case of adjacency != NULL not implemented.\n");
5784 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
5785 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
5787 return D3DERR_INVALIDCALL
;
5790 if (deviation
== 0.0f
)
5791 deviation
= 1.0f
/ otm
.otmEMSquare
;
5792 max_deviation_sq
= deviation
* deviation
;
5794 lf
.lfHeight
= otm
.otmEMSquare
;
5796 font
= CreateFontIndirectW(&lf
);
5801 oldfont
= SelectObject(hdc
, font
);
5803 textlen
= strlenW(text
);
5804 for (i
= 0; i
< textlen
; i
++)
5806 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
5808 return D3DERR_INVALIDCALL
;
5809 if (bufsize
< datasize
)
5812 if (!bufsize
) { /* e.g. text == " " */
5813 hr
= D3DERR_INVALIDCALL
;
5817 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
5818 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
5819 if (!glyphs
|| !raw_outline
) {
5825 for (i
= 0; i
< textlen
; i
++)
5827 /* get outline points from data returned from GetGlyphOutline */
5830 glyphs
[i
].offset_x
= offset_x
;
5832 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
5833 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
5834 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
5835 if (hr
!= S_OK
) goto error
;
5837 triangulations
.glyph
= &glyphs
[i
];
5838 hr
= triangulate(&triangulations
);
5839 if (hr
!= S_OK
) goto error
;
5840 if (triangulations
.count
) {
5841 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
5842 triangulations
.count
= 0;
5847 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
5848 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
5849 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
5850 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
5851 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
5852 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
5854 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
5857 /* corner points need an extra vertex for the different side faces normals */
5859 nb_outline_points
= 0;
5861 for (i
= 0; i
< textlen
; i
++)
5864 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
5865 nb_front_faces
+= glyphs
[i
].faces
.count
;
5866 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
5869 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
5870 nb_corners
++; /* first outline point always repeated as a corner */
5871 for (k
= 1; k
< outline
->count
; k
++)
5872 if (outline
->items
[k
].corner
)
5877 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
5878 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
5881 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
5882 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
5886 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (LPVOID
*)&vertices
);
5890 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, (LPVOID
*)&faces
);
5894 /* convert 2D vertices and faces into 3D mesh */
5895 vertex_ptr
= vertices
;
5897 if (extrusion
== 0.0f
) {
5904 for (i
= 0; i
< textlen
; i
++)
5908 struct vertex
*back_vertices
;
5911 /* side vertices and faces */
5912 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
5914 struct vertex
*outline_vertices
= vertex_ptr
;
5915 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
5917 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
5918 struct point2d
*pt
= &outline
->items
[0];
5920 for (k
= 1; k
<= outline
->count
; k
++)
5923 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
5924 WORD vtx_idx
= vertex_ptr
- vertices
;
5927 if (pt
->corner
== POINTTYPE_CURVE_START
)
5928 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
5929 else if (pt
->corner
)
5930 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
5932 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
5933 D3DXVec2Normalize(&vec
, &vec
);
5934 vtx
.normal
.x
= -vec
.y
;
5935 vtx
.normal
.y
= vec
.x
;
5938 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
5939 vtx
.position
.y
= pt
->pos
.y
;
5941 *vertex_ptr
++ = vtx
;
5943 vtx
.position
.z
= -extrusion
;
5944 *vertex_ptr
++ = vtx
;
5946 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
5947 vtx
.position
.y
= nextpt
->pos
.y
;
5948 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
5949 vtx
.position
.z
= -extrusion
;
5950 *vertex_ptr
++ = vtx
;
5952 *vertex_ptr
++ = vtx
;
5954 (*face_ptr
)[0] = vtx_idx
;
5955 (*face_ptr
)[1] = vtx_idx
+ 2;
5956 (*face_ptr
)[2] = vtx_idx
+ 1;
5959 (*face_ptr
)[0] = vtx_idx
;
5960 (*face_ptr
)[1] = vtx_idx
+ 3;
5961 (*face_ptr
)[2] = vtx_idx
+ 2;
5964 if (nextpt
->corner
) {
5965 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
5966 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
5967 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
5969 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
5971 D3DXVec2Normalize(&vec
, &vec
);
5972 vtx
.normal
.x
= -vec
.y
;
5973 vtx
.normal
.y
= vec
.x
;
5976 *vertex_ptr
++ = vtx
;
5977 vtx
.position
.z
= -extrusion
;
5978 *vertex_ptr
++ = vtx
;
5981 (*face_ptr
)[0] = vtx_idx
;
5982 (*face_ptr
)[1] = vtx_idx
+ 3;
5983 (*face_ptr
)[2] = vtx_idx
+ 1;
5986 (*face_ptr
)[0] = vtx_idx
;
5987 (*face_ptr
)[1] = vtx_idx
+ 2;
5988 (*face_ptr
)[2] = vtx_idx
+ 3;
5996 *vertex_ptr
++ = *outline_vertices
++;
5997 *vertex_ptr
++ = *outline_vertices
++;
6001 /* back vertices and faces */
6002 back_faces
= face_ptr
;
6003 back_vertices
= vertex_ptr
;
6004 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
6006 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
6007 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
6008 vertex_ptr
->position
.y
= pt
->y
;
6009 vertex_ptr
->position
.z
= 0;
6010 vertex_ptr
->normal
.x
= 0;
6011 vertex_ptr
->normal
.y
= 0;
6012 vertex_ptr
->normal
.z
= 1;
6015 count
= back_vertices
- vertices
;
6016 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
6018 face
*f
= &glyphs
[i
].faces
.items
[j
];
6019 (*face_ptr
)[0] = (*f
)[0] + count
;
6020 (*face_ptr
)[1] = (*f
)[1] + count
;
6021 (*face_ptr
)[2] = (*f
)[2] + count
;
6025 /* front vertices and faces */
6026 j
= count
= vertex_ptr
- back_vertices
;
6029 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
6030 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
6031 vertex_ptr
->position
.z
= -extrusion
;
6032 vertex_ptr
->normal
.x
= 0;
6033 vertex_ptr
->normal
.y
= 0;
6034 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
6038 j
= face_ptr
- back_faces
;
6041 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
6042 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
6043 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
6053 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6054 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6055 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
6058 for (i
= 0; i
< textlen
; i
++)
6061 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6062 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
6063 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
6064 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
6065 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
6067 HeapFree(GetProcessHeap(), 0, glyphs
);
6069 if (triangulations
.items
) {
6071 for (i
= 0; i
< triangulations
.count
; i
++)
6072 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
6073 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
6075 HeapFree(GetProcessHeap(), 0, raw_outline
);
6076 if (oldfont
) SelectObject(hdc
, oldfont
);
6077 if (font
) DeleteObject(font
);
6082 HRESULT WINAPI
D3DXValidMesh(ID3DXMesh
*mesh
, const DWORD
*adjacency
, ID3DXBuffer
**errors_and_warnings
)
6084 FIXME("(%p, %p, %p): stub\n", mesh
, adjacency
, *errors_and_warnings
);
6089 static BOOL
weld_float1(void *to
, void *from
, FLOAT epsilon
)
6094 if (fabsf(*v1
- *v2
) <= epsilon
)
6104 static BOOL
weld_float2(void *to
, void *from
, FLOAT epsilon
)
6106 D3DXVECTOR2
*v1
= to
;
6107 D3DXVECTOR2
*v2
= from
;
6108 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6109 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6110 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6112 if (max_abs_diff
<= epsilon
)
6114 memcpy(to
, from
, sizeof(D3DXVECTOR2
));
6122 static BOOL
weld_float3(void *to
, void *from
, FLOAT epsilon
)
6124 D3DXVECTOR3
*v1
= to
;
6125 D3DXVECTOR3
*v2
= from
;
6126 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6127 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6128 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6129 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6130 max_abs_diff
= max(diff_z
, max_abs_diff
);
6132 if (max_abs_diff
<= epsilon
)
6134 memcpy(to
, from
, sizeof(D3DXVECTOR3
));
6142 static BOOL
weld_float4(void *to
, void *from
, FLOAT epsilon
)
6144 D3DXVECTOR4
*v1
= to
;
6145 D3DXVECTOR4
*v2
= from
;
6146 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6147 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6148 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6149 FLOAT diff_w
= fabsf(v1
->w
- v2
->w
);
6150 FLOAT max_abs_diff
= fmax(diff_x
, diff_y
);
6151 max_abs_diff
= max(diff_z
, max_abs_diff
);
6152 max_abs_diff
= max(diff_w
, max_abs_diff
);
6154 if (max_abs_diff
<= epsilon
)
6156 memcpy(to
, from
, sizeof(D3DXVECTOR4
));
6164 static BOOL
weld_ubyte4(void *to
, void *from
, FLOAT epsilon
)
6168 BYTE truncated_epsilon
= (BYTE
)epsilon
;
6169 BYTE diff_x
= b1
[0] > b2
[0] ? b1
[0] - b2
[0] : b2
[0] - b1
[0];
6170 BYTE diff_y
= b1
[1] > b2
[1] ? b1
[1] - b2
[1] : b2
[1] - b1
[1];
6171 BYTE diff_z
= b1
[2] > b2
[2] ? b1
[2] - b2
[2] : b2
[2] - b1
[2];
6172 BYTE diff_w
= b1
[3] > b2
[3] ? b1
[3] - b2
[3] : b2
[3] - b1
[3];
6173 BYTE max_diff
= max(diff_x
, diff_y
);
6174 max_diff
= max(diff_z
, max_diff
);
6175 max_diff
= max(diff_w
, max_diff
);
6177 if (max_diff
<= truncated_epsilon
)
6179 memcpy(to
, from
, 4 * sizeof(BYTE
));
6187 static BOOL
weld_ubyte4n(void *to
, void *from
, FLOAT epsilon
)
6189 return weld_ubyte4(to
, from
, epsilon
* UCHAR_MAX
);
6192 static BOOL
weld_d3dcolor(void *to
, void *from
, FLOAT epsilon
)
6194 return weld_ubyte4n(to
, from
, epsilon
);
6197 static BOOL
weld_short2(void *to
, void *from
, FLOAT epsilon
)
6201 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6202 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6203 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6204 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6206 if (max_abs_diff
<= truncated_epsilon
)
6208 memcpy(to
, from
, 2 * sizeof(SHORT
));
6216 static BOOL
weld_short2n(void *to
, void *from
, FLOAT epsilon
)
6218 return weld_short2(to
, from
, epsilon
* SHRT_MAX
);
6221 static BOOL
weld_short4(void *to
, void *from
, FLOAT epsilon
)
6225 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6226 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6227 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6228 SHORT diff_z
= abs(s1
[2] - s2
[2]);
6229 SHORT diff_w
= abs(s1
[3] - s2
[3]);
6230 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6231 max_abs_diff
= max(diff_z
, max_abs_diff
);
6232 max_abs_diff
= max(diff_w
, max_abs_diff
);
6234 if (max_abs_diff
<= truncated_epsilon
)
6236 memcpy(to
, from
, 4 * sizeof(SHORT
));
6244 static BOOL
weld_short4n(void *to
, void *from
, FLOAT epsilon
)
6246 return weld_short4(to
, from
, epsilon
* SHRT_MAX
);
6249 static BOOL
weld_ushort2n(void *to
, void *from
, FLOAT epsilon
)
6253 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6254 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6255 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6256 USHORT max_diff
= max(diff_x
, diff_y
);
6258 if (max_diff
<= scaled_epsilon
)
6260 memcpy(to
, from
, 2 * sizeof(USHORT
));
6268 static BOOL
weld_ushort4n(void *to
, void *from
, FLOAT epsilon
)
6272 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6273 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6274 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6275 USHORT diff_z
= s1
[2] > s2
[2] ? s1
[2] - s2
[2] : s2
[2] - s1
[2];
6276 USHORT diff_w
= s1
[3] > s2
[3] ? s1
[3] - s2
[3] : s2
[3] - s1
[3];
6277 USHORT max_diff
= max(diff_x
, diff_y
);
6278 max_diff
= max(diff_z
, max_diff
);
6279 max_diff
= max(diff_w
, max_diff
);
6281 if (max_diff
<= scaled_epsilon
)
6283 memcpy(to
, from
, 4 * sizeof(USHORT
));
6299 static struct udec3
dword_to_udec3(DWORD d
)
6304 v
.y
= (d
& 0xffc00) >> 10;
6305 v
.z
= (d
& 0x3ff00000) >> 20;
6306 v
.w
= (d
& 0xc0000000) >> 30;
6311 static BOOL
weld_udec3(void *to
, void *from
, FLOAT epsilon
)
6315 struct udec3 v1
= dword_to_udec3(*d1
);
6316 struct udec3 v2
= dword_to_udec3(*d2
);
6317 UINT truncated_epsilon
= (UINT
)epsilon
;
6318 UINT diff_x
= v1
.x
> v2
.x
? v1
.x
- v2
.x
: v2
.x
- v1
.x
;
6319 UINT diff_y
= v1
.y
> v2
.y
? v1
.y
- v2
.y
: v2
.y
- v1
.y
;
6320 UINT diff_z
= v1
.z
> v2
.z
? v1
.z
- v2
.z
: v2
.z
- v1
.z
;
6321 UINT diff_w
= v1
.w
> v2
.w
? v1
.w
- v2
.w
: v2
.w
- v1
.w
;
6322 UINT max_diff
= max(diff_x
, diff_y
);
6323 max_diff
= max(diff_z
, max_diff
);
6324 max_diff
= max(diff_w
, max_diff
);
6326 if (max_diff
<= truncated_epsilon
)
6328 memcpy(to
, from
, sizeof(DWORD
));
6344 static struct dec3n
dword_to_dec3n(DWORD d
)
6349 v
.y
= (d
& 0xffc00) >> 10;
6350 v
.z
= (d
& 0x3ff00000) >> 20;
6351 v
.w
= (d
& 0xc0000000) >> 30;
6356 static BOOL
weld_dec3n(void *to
, void *from
, FLOAT epsilon
)
6358 const UINT MAX_DEC3N
= 511;
6361 struct dec3n v1
= dword_to_dec3n(*d1
);
6362 struct dec3n v2
= dword_to_dec3n(*d2
);
6363 INT scaled_epsilon
= (INT
)(epsilon
* MAX_DEC3N
);
6364 INT diff_x
= abs(v1
.x
- v2
.x
);
6365 INT diff_y
= abs(v1
.y
- v2
.y
);
6366 INT diff_z
= abs(v1
.z
- v2
.z
);
6367 INT diff_w
= abs(v1
.w
- v2
.w
);
6368 INT max_abs_diff
= max(diff_x
, diff_y
);
6369 max_abs_diff
= max(diff_z
, max_abs_diff
);
6370 max_abs_diff
= max(diff_w
, max_abs_diff
);
6372 if (max_abs_diff
<= scaled_epsilon
)
6374 memcpy(to
, from
, sizeof(DWORD
));
6382 static BOOL
weld_float16_2(void *to
, void *from
, FLOAT epsilon
)
6384 D3DXFLOAT16
*v1_float16
= to
;
6385 D3DXFLOAT16
*v2_float16
= from
;
6389 const UINT NUM_ELEM
= 2;
6393 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6394 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6396 diff_x
= fabsf(v1
[0] - v2
[0]);
6397 diff_y
= fabsf(v1
[1] - v2
[1]);
6398 max_abs_diff
= max(diff_x
, diff_y
);
6400 if (max_abs_diff
<= epsilon
)
6402 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6410 static BOOL
weld_float16_4(void *to
, void *from
, FLOAT epsilon
)
6412 D3DXFLOAT16
*v1_float16
= to
;
6413 D3DXFLOAT16
*v2_float16
= from
;
6419 const UINT NUM_ELEM
= 4;
6423 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6424 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6426 diff_x
= fabsf(v1
[0] - v2
[0]);
6427 diff_y
= fabsf(v1
[1] - v2
[1]);
6428 diff_z
= fabsf(v1
[2] - v2
[2]);
6429 diff_w
= fabsf(v1
[3] - v2
[3]);
6430 max_abs_diff
= max(diff_x
, diff_y
);
6431 max_abs_diff
= max(diff_z
, max_abs_diff
);
6432 max_abs_diff
= max(diff_w
, max_abs_diff
);
6434 if (max_abs_diff
<= epsilon
)
6436 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6444 /* Sets the vertex components to the same value if they are within epsilon. */
6445 static BOOL
weld_component(void *to
, void *from
, D3DDECLTYPE type
, FLOAT epsilon
)
6447 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6448 BOOL fixme_once_unused
= FALSE
;
6449 BOOL fixme_once_unknown
= FALSE
;
6453 case D3DDECLTYPE_FLOAT1
:
6454 return weld_float1(to
, from
, epsilon
);
6456 case D3DDECLTYPE_FLOAT2
:
6457 return weld_float2(to
, from
, epsilon
);
6459 case D3DDECLTYPE_FLOAT3
:
6460 return weld_float3(to
, from
, epsilon
);
6462 case D3DDECLTYPE_FLOAT4
:
6463 return weld_float4(to
, from
, epsilon
);
6465 case D3DDECLTYPE_D3DCOLOR
:
6466 return weld_d3dcolor(to
, from
, epsilon
);
6468 case D3DDECLTYPE_UBYTE4
:
6469 return weld_ubyte4(to
, from
, epsilon
);
6471 case D3DDECLTYPE_SHORT2
:
6472 return weld_short2(to
, from
, epsilon
);
6474 case D3DDECLTYPE_SHORT4
:
6475 return weld_short4(to
, from
, epsilon
);
6477 case D3DDECLTYPE_UBYTE4N
:
6478 return weld_ubyte4n(to
, from
, epsilon
);
6480 case D3DDECLTYPE_SHORT2N
:
6481 return weld_short2n(to
, from
, epsilon
);
6483 case D3DDECLTYPE_SHORT4N
:
6484 return weld_short4n(to
, from
, epsilon
);
6486 case D3DDECLTYPE_USHORT2N
:
6487 return weld_ushort2n(to
, from
, epsilon
);
6489 case D3DDECLTYPE_USHORT4N
:
6490 return weld_ushort4n(to
, from
, epsilon
);
6492 case D3DDECLTYPE_UDEC3
:
6493 return weld_udec3(to
, from
, epsilon
);
6495 case D3DDECLTYPE_DEC3N
:
6496 return weld_dec3n(to
, from
, epsilon
);
6498 case D3DDECLTYPE_FLOAT16_2
:
6499 return weld_float16_2(to
, from
, epsilon
);
6501 case D3DDECLTYPE_FLOAT16_4
:
6502 return weld_float16_4(to
, from
, epsilon
);
6504 case D3DDECLTYPE_UNUSED
:
6505 if (!fixme_once_unused
++)
6506 FIXME("D3DDECLTYPE_UNUSED welding not implemented.\n");
6510 if (!fixme_once_unknown
++)
6511 FIXME("Welding of unknown declaration type %d is not implemented.\n", type
);
6518 static FLOAT
get_component_epsilon(const D3DVERTEXELEMENT9
*decl_ptr
, const D3DXWELDEPSILONS
*epsilons
)
6520 FLOAT epsilon
= 0.0f
;
6521 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6522 static BOOL fixme_once_blendindices
= FALSE
;
6523 static BOOL fixme_once_positiont
= FALSE
;
6524 static BOOL fixme_once_fog
= FALSE
;
6525 static BOOL fixme_once_depth
= FALSE
;
6526 static BOOL fixme_once_sample
= FALSE
;
6527 static BOOL fixme_once_unknown
= FALSE
;
6529 switch (decl_ptr
->Usage
)
6531 case D3DDECLUSAGE_POSITION
:
6532 epsilon
= epsilons
->Position
;
6534 case D3DDECLUSAGE_BLENDWEIGHT
:
6535 epsilon
= epsilons
->BlendWeights
;
6537 case D3DDECLUSAGE_NORMAL
:
6538 epsilon
= epsilons
->Normals
;
6540 case D3DDECLUSAGE_PSIZE
:
6541 epsilon
= epsilons
->PSize
;
6543 case D3DDECLUSAGE_TEXCOORD
:
6545 BYTE usage_index
= decl_ptr
->UsageIndex
;
6546 if (usage_index
> 7)
6548 epsilon
= epsilons
->Texcoords
[usage_index
];
6551 case D3DDECLUSAGE_TANGENT
:
6552 epsilon
= epsilons
->Tangent
;
6554 case D3DDECLUSAGE_BINORMAL
:
6555 epsilon
= epsilons
->Binormal
;
6557 case D3DDECLUSAGE_TESSFACTOR
:
6558 epsilon
= epsilons
->TessFactor
;
6560 case D3DDECLUSAGE_COLOR
:
6561 if (decl_ptr
->UsageIndex
== 0)
6562 epsilon
= epsilons
->Diffuse
;
6563 else if (decl_ptr
->UsageIndex
== 1)
6564 epsilon
= epsilons
->Specular
;
6568 case D3DDECLUSAGE_BLENDINDICES
:
6569 if (!fixme_once_blendindices
++)
6570 FIXME("D3DDECLUSAGE_BLENDINDICES welding not implemented.\n");
6572 case D3DDECLUSAGE_POSITIONT
:
6573 if (!fixme_once_positiont
++)
6574 FIXME("D3DDECLUSAGE_POSITIONT welding not implemented.\n");
6576 case D3DDECLUSAGE_FOG
:
6577 if (!fixme_once_fog
++)
6578 FIXME("D3DDECLUSAGE_FOG welding not implemented.\n");
6580 case D3DDECLUSAGE_DEPTH
:
6581 if (!fixme_once_depth
++)
6582 FIXME("D3DDECLUSAGE_DEPTH welding not implemented.\n");
6584 case D3DDECLUSAGE_SAMPLE
:
6585 if (!fixme_once_sample
++)
6586 FIXME("D3DDECLUSAGE_SAMPLE welding not implemented.\n");
6589 if (!fixme_once_unknown
++)
6590 FIXME("Unknown usage %x\n", decl_ptr
->Usage
);
6597 /* Helper function for reading a 32-bit index buffer. */
6598 static inline DWORD
read_ib(void *index_buffer
, BOOL indices_are_32bit
,
6601 if (indices_are_32bit
)
6603 DWORD
*indices
= index_buffer
;
6604 return indices
[index
];
6608 WORD
*indices
= index_buffer
;
6609 return indices
[index
];
6613 /* Helper function for writing to a 32-bit index buffer. */
6614 static inline void write_ib(void *index_buffer
, BOOL indices_are_32bit
,
6615 DWORD index
, DWORD value
)
6617 if (indices_are_32bit
)
6619 DWORD
*indices
= index_buffer
;
6620 indices
[index
] = value
;
6624 WORD
*indices
= index_buffer
;
6625 indices
[index
] = value
;
6629 /*************************************************************************
6630 * D3DXWeldVertices (D3DX9_36.@)
6632 * Welds together similar vertices. The similarity between vert-
6633 * ices can be the position and other components such as
6637 * mesh [I] Mesh which vertices will be welded together.
6638 * flags [I] D3DXWELDEPSILONSFLAGS specifying how to weld.
6639 * epsilons [I] How similar a component needs to be for welding.
6640 * adjacency [I] Which faces are adjacent to other faces.
6641 * adjacency_out [O] Updated adjacency after welding.
6642 * face_remap_out [O] Which faces the old faces have been mapped to.
6643 * vertex_remap_out [O] Which vertices the old vertices have been mapped to.
6647 * Failure: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
6650 * Attribute sorting not implemented.
6653 HRESULT WINAPI
D3DXWeldVertices(ID3DXMesh
*mesh
, DWORD flags
, const D3DXWELDEPSILONS
*epsilons
,
6654 const DWORD
*adjacency
, DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
6656 DWORD
*adjacency_generated
= NULL
;
6657 const DWORD
*adjacency_ptr
;
6658 DWORD
*attributes
= NULL
;
6659 const FLOAT DEFAULT_EPSILON
= 1.0e-6f
;
6662 void *indices
= NULL
;
6663 BOOL indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
6664 DWORD optimize_flags
;
6665 DWORD
*point_reps
= NULL
;
6666 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(mesh
);
6667 DWORD
*vertex_face_map
= NULL
;
6668 ID3DXBuffer
*vertex_remap
= NULL
;
6669 BYTE
*vertices
= NULL
;
6671 TRACE("(%p, %x, %p, %p, %p, %p, %p)\n", mesh
, flags
, epsilons
,
6672 adjacency
, adjacency_out
, face_remap_out
, vertex_remap_out
);
6676 WARN("No flags is undefined. Using D3DXWELDEPSILONS_WELDPARTIALMATCHES instead.\n");
6677 flags
= D3DXWELDEPSILONS_WELDPARTIALMATCHES
;
6680 if (adjacency
) /* Use supplied adjacency. */
6682 adjacency_ptr
= adjacency
;
6684 else /* Adjacency has to be generated. */
6686 adjacency_generated
= HeapAlloc(GetProcessHeap(), 0, 3 * This
->numfaces
* sizeof(*adjacency_generated
));
6687 if (!adjacency_generated
)
6689 ERR("Couldn't allocate memory for adjacency_generated.\n");
6693 hr
= mesh
->lpVtbl
->GenerateAdjacency(mesh
, DEFAULT_EPSILON
, adjacency_generated
);
6696 ERR("Couldn't generate adjacency.\n");
6699 adjacency_ptr
= adjacency_generated
;
6702 /* Point representation says which vertices can be replaced. */
6703 point_reps
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*point_reps
));
6707 ERR("Couldn't allocate memory for point_reps.\n");
6710 hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency_ptr
, point_reps
);
6713 ERR("ConvertAdjacencyToPointReps failed.\n");
6717 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
);
6720 ERR("Couldn't lock index buffer.\n");
6724 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, 0, &attributes
);
6727 ERR("Couldn't lock attribute buffer.\n");
6730 vertex_face_map
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*vertex_face_map
));
6731 if (!vertex_face_map
)
6734 ERR("Couldn't allocate memory for vertex_face_map.\n");
6737 /* Build vertex face map, so that a vertex's face can be looked up. */
6738 for (i
= 0; i
< This
->numfaces
; i
++)
6741 for (j
= 0; j
< 3; j
++)
6743 DWORD index
= read_ib(indices
, indices_are_32bit
, 3*i
+ j
);
6744 vertex_face_map
[index
] = i
;
6748 if (flags
& D3DXWELDEPSILONS_WELDPARTIALMATCHES
)
6750 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void**)&vertices
);
6753 ERR("Couldn't lock vertex buffer.\n");
6756 /* For each vertex that can be removed, compare its vertex components
6757 * with the vertex components from the vertex that can replace it. A
6758 * vertex is only fully replaced if all the components match and the
6759 * flag D3DXWELDEPSILONS_DONOTREMOVEVERTICES is not set, and they
6760 * belong to the same attribute group. Otherwise the vertex components
6761 * that are within epsilon are set to the same value.
6763 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
6765 D3DVERTEXELEMENT9
*decl_ptr
;
6766 DWORD vertex_size
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
6767 DWORD num_vertex_components
;
6770 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
6772 for (decl_ptr
= This
->cached_declaration
, num_vertex_components
= 0; decl_ptr
->Stream
!= 0xFF; decl_ptr
++, num_vertex_components
++)
6774 BYTE
*to
= &vertices
[vertex_size
*index
+ decl_ptr
->Offset
];
6775 BYTE
*from
= &vertices
[vertex_size
*point_reps
[index
] + decl_ptr
->Offset
];
6776 FLOAT epsilon
= get_component_epsilon(decl_ptr
, epsilons
);
6778 /* Don't weld self */
6779 if (index
== point_reps
[index
])
6785 if (weld_component(to
, from
, decl_ptr
->Type
, epsilon
))
6789 all_match
= (num_vertex_components
== matches
);
6790 if (all_match
&& !(flags
& D3DXWELDEPSILONS_DONOTREMOVEVERTICES
))
6792 DWORD to_face
= vertex_face_map
[index
];
6793 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
6794 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
6796 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
6799 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6802 else if (flags
& D3DXWELDEPSILONS_WELDALL
)
6804 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
6806 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
6807 DWORD to_face
= vertex_face_map
[index
];
6808 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
6809 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
6811 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
6814 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
6816 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6819 /* Compact mesh using OptimizeInplace */
6820 optimize_flags
= D3DXMESHOPT_COMPACT
;
6821 hr
= mesh
->lpVtbl
->OptimizeInplace(mesh
, optimize_flags
, adjacency_ptr
, adjacency_out
, face_remap_out
, vertex_remap_out
);
6824 ERR("Couldn't compact mesh.\n");
6830 HeapFree(GetProcessHeap(), 0, adjacency_generated
);
6831 HeapFree(GetProcessHeap(), 0, point_reps
);
6832 HeapFree(GetProcessHeap(), 0, vertex_face_map
);
6833 if (attributes
) mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
6834 if (indices
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6835 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
6836 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6841 /*************************************************************************
6842 * D3DXOptimizeFaces (D3DX9_36.@)
6844 * Re-orders the faces so the vertex cache is used optimally.
6847 * indices [I] Pointer to an index buffer belonging to a mesh.
6848 * num_faces [I] Number of faces in the mesh.
6849 * num_vertices [I] Number of vertices in the mesh.
6850 * indices_are_32bit [I] Specifies whether indices are 32- or 16-bit.
6851 * face_remap [I/O] The new order the faces should be drawn in.
6855 * Failure: D3DERR_INVALIDCALL.
6858 * The face re-ordering does not use the vertex cache optimally.
6861 HRESULT WINAPI
D3DXOptimizeFaces(LPCVOID indices
,
6864 BOOL indices_are_32bit
,
6868 UINT j
= num_faces
- 1;
6869 UINT limit_16_bit
= 2 << 15; /* According to MSDN */
6870 HRESULT hr
= D3D_OK
;
6872 FIXME("(%p, %u, %u, %s, %p): semi-stub. Face order will not be optimal.\n",
6873 indices
, num_faces
, num_vertices
,
6874 indices_are_32bit
? "TRUE" : "FALSE", face_remap
);
6876 if (!indices_are_32bit
&& num_faces
>= limit_16_bit
)
6878 WARN("Number of faces must be less than %d when using 16-bit indices.\n",
6880 hr
= D3DERR_INVALIDCALL
;
6886 WARN("Face remap pointer is NULL.\n");
6887 hr
= D3DERR_INVALIDCALL
;
6891 /* The faces are drawn in reverse order for simple meshes. This ordering
6892 * is not optimal for complicated meshes, but will not break anything
6893 * either. The ordering should be changed to take advantage of the vertex
6894 * cache on the graphics card.
6896 * TODO Re-order to take advantage of vertex cache.
6898 for (i
= 0; i
< num_faces
; i
++)
6900 face_remap
[i
] = j
--;