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
31 #include "d3dx9_private.h"
36 #include "wine/list.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
42 ID3DXMesh ID3DXMesh_iface
;
49 IDirect3DDevice9
*device
;
50 D3DVERTEXELEMENT9 cached_declaration
[MAX_FVF_DECL_SIZE
];
51 IDirect3DVertexDeclaration9
*vertex_declaration
;
52 UINT vertex_declaration_size
;
54 IDirect3DVertexBuffer9
*vertex_buffer
;
55 IDirect3DIndexBuffer9
*index_buffer
;
57 LONG attrib_buffer_lock_count
;
58 DWORD attrib_table_size
;
59 D3DXATTRIBUTERANGE
*attrib_table
;
62 static const UINT d3dx_decltype_size
[] =
64 /* D3DDECLTYPE_FLOAT1 */ sizeof(FLOAT
),
65 /* D3DDECLTYPE_FLOAT2 */ sizeof(D3DXVECTOR2
),
66 /* D3DDECLTYPE_FLOAT3 */ sizeof(D3DXVECTOR3
),
67 /* D3DDECLTYPE_FLOAT4 */ sizeof(D3DXVECTOR4
),
68 /* D3DDECLTYPE_D3DCOLOR */ sizeof(D3DCOLOR
),
69 /* D3DDECLTYPE_UBYTE4 */ 4 * sizeof(BYTE
),
70 /* D3DDECLTYPE_SHORT2 */ 2 * sizeof(SHORT
),
71 /* D3DDECLTYPE_SHORT4 */ 4 * sizeof(SHORT
),
72 /* D3DDECLTYPE_UBYTE4N */ 4 * sizeof(BYTE
),
73 /* D3DDECLTYPE_SHORT2N */ 2 * sizeof(SHORT
),
74 /* D3DDECLTYPE_SHORT4N */ 4 * sizeof(SHORT
),
75 /* D3DDECLTYPE_USHORT2N */ 2 * sizeof(USHORT
),
76 /* D3DDECLTYPE_USHORT4N */ 4 * sizeof(USHORT
),
77 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
78 /* D3DDECLTYPE_DEC3N */ 4,
79 /* D3DDECLTYPE_FLOAT16_2 */ 2 * sizeof(D3DXFLOAT16
),
80 /* D3DDECLTYPE_FLOAT16_4 */ 4 * sizeof(D3DXFLOAT16
),
83 static inline struct d3dx9_mesh
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
85 return CONTAINING_RECORD(iface
, struct d3dx9_mesh
, ID3DXMesh_iface
);
88 static HRESULT WINAPI
d3dx9_mesh_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, void **out
)
90 TRACE("iface %p, riid %s, out %p.\n", iface
, debugstr_guid(riid
), out
);
92 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
93 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
94 IsEqualGUID(riid
, &IID_ID3DXMesh
))
96 iface
->lpVtbl
->AddRef(iface
);
101 WARN("Interface %s not found.\n", debugstr_guid(riid
));
103 return E_NOINTERFACE
;
106 static ULONG WINAPI
d3dx9_mesh_AddRef(ID3DXMesh
*iface
)
108 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
109 ULONG refcount
= InterlockedIncrement(&mesh
->ref
);
111 TRACE("%p increasing refcount to %lu.\n", mesh
, refcount
);
116 static ULONG WINAPI
d3dx9_mesh_Release(ID3DXMesh
*iface
)
118 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
119 ULONG refcount
= InterlockedDecrement(&mesh
->ref
);
121 TRACE("%p decreasing refcount to %lu.\n", mesh
, refcount
);
125 IDirect3DIndexBuffer9_Release(mesh
->index_buffer
);
126 IDirect3DVertexBuffer9_Release(mesh
->vertex_buffer
);
127 if (mesh
->vertex_declaration
)
128 IDirect3DVertexDeclaration9_Release(mesh
->vertex_declaration
);
129 IDirect3DDevice9_Release(mesh
->device
);
130 HeapFree(GetProcessHeap(), 0, mesh
->attrib_buffer
);
131 HeapFree(GetProcessHeap(), 0, mesh
->attrib_table
);
132 HeapFree(GetProcessHeap(), 0, mesh
);
138 static HRESULT WINAPI
d3dx9_mesh_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
140 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
146 TRACE("iface %p, attrib_id %lu.\n", iface
, attrib_id
);
148 if (!This
->vertex_declaration
)
150 WARN("Can't draw a mesh with an invalid vertex declaration.\n");
154 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
156 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
157 if (FAILED(hr
)) return hr
;
158 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
159 if (FAILED(hr
)) return hr
;
160 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
161 if (FAILED(hr
)) return hr
;
163 while (face_end
< This
->numfaces
)
165 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
167 if (This
->attrib_buffer
[face_start
] == attrib_id
)
170 if (face_start
>= This
->numfaces
)
172 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
174 if (This
->attrib_buffer
[face_end
] != attrib_id
)
178 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
179 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
180 if (FAILED(hr
)) return hr
;
186 static DWORD WINAPI
d3dx9_mesh_GetNumFaces(ID3DXMesh
*iface
)
188 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
190 TRACE("iface %p.\n", iface
);
192 return mesh
->numfaces
;
195 static DWORD WINAPI
d3dx9_mesh_GetNumVertices(ID3DXMesh
*iface
)
197 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
199 TRACE("iface %p.\n", iface
);
201 return mesh
->numvertices
;
204 static DWORD WINAPI
d3dx9_mesh_GetFVF(ID3DXMesh
*iface
)
206 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
208 TRACE("iface %p.\n", iface
);
213 static void copy_declaration(D3DVERTEXELEMENT9
*dst
, const D3DVERTEXELEMENT9
*src
, UINT num_elem
)
215 memcpy(dst
, src
, num_elem
* sizeof(*src
));
218 static HRESULT WINAPI
d3dx9_mesh_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
220 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
222 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
225 return D3DERR_INVALIDCALL
;
227 copy_declaration(declaration
, mesh
->cached_declaration
, mesh
->num_elem
);
232 static DWORD WINAPI
d3dx9_mesh_GetNumBytesPerVertex(ID3DXMesh
*iface
)
234 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
236 TRACE("iface %p.\n", iface
);
238 return mesh
->vertex_declaration_size
;
241 static DWORD WINAPI
d3dx9_mesh_GetOptions(ID3DXMesh
*iface
)
243 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
245 TRACE("iface %p.\n", iface
);
247 return mesh
->options
;
250 static HRESULT WINAPI
d3dx9_mesh_GetDevice(struct ID3DXMesh
*iface
, struct IDirect3DDevice9
**device
)
252 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
254 TRACE("iface %p, device %p.\n", iface
, device
);
257 return D3DERR_INVALIDCALL
;
258 *device
= mesh
->device
;
259 IDirect3DDevice9_AddRef(mesh
->device
);
264 static HRESULT WINAPI
d3dx9_mesh_CloneMeshFVF(struct ID3DXMesh
*iface
, DWORD options
, DWORD fvf
,
265 struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh
)
268 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
270 TRACE("iface %p, options %#lx, fvf %#lx, device %p, clone_mesh %p.\n",
271 iface
, options
, fvf
, device
, clone_mesh
);
273 if (FAILED(hr
= D3DXDeclaratorFromFVF(fvf
, declaration
)))
276 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
279 static FLOAT
scale_clamp_ubyten(FLOAT value
)
281 value
= value
* UCHAR_MAX
;
289 if (value
> UCHAR_MAX
) /* Clamp at 255 */
296 static FLOAT
scale_clamp_shortn(FLOAT value
)
298 value
= value
* SHRT_MAX
;
300 /* The tests show that the range is SHRT_MIN + 1 to SHRT_MAX. */
301 if (value
<= SHRT_MIN
)
305 else if (value
> SHRT_MAX
)
315 static FLOAT
scale_clamp_ushortn(FLOAT value
)
317 value
= value
* USHRT_MAX
;
325 if (value
> USHRT_MAX
) /* Clamp at 65535 */
332 static INT
simple_round(FLOAT value
)
334 int res
= (INT
)(value
+ 0.5f
);
339 static void convert_float4(BYTE
*dst
, const D3DXVECTOR4
*src
, D3DDECLTYPE type_dst
)
341 BOOL fixme_once
= FALSE
;
345 case D3DDECLTYPE_FLOAT1
:
347 FLOAT
*dst_ptr
= (FLOAT
*)dst
;
351 case D3DDECLTYPE_FLOAT2
:
353 D3DXVECTOR2
*dst_ptr
= (D3DXVECTOR2
*)dst
;
358 case D3DDECLTYPE_FLOAT3
:
360 D3DXVECTOR3
*dst_ptr
= (D3DXVECTOR3
*)dst
;
366 case D3DDECLTYPE_FLOAT4
:
368 D3DXVECTOR4
*dst_ptr
= (D3DXVECTOR4
*)dst
;
375 case D3DDECLTYPE_D3DCOLOR
:
377 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
378 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
379 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
380 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
383 case D3DDECLTYPE_UBYTE4
:
385 dst
[0] = src
->x
< 0.0f
? 0 : (BYTE
)simple_round(src
->x
);
386 dst
[1] = src
->y
< 0.0f
? 0 : (BYTE
)simple_round(src
->y
);
387 dst
[2] = src
->z
< 0.0f
? 0 : (BYTE
)simple_round(src
->z
);
388 dst
[3] = src
->w
< 0.0f
? 0 : (BYTE
)simple_round(src
->w
);
391 case D3DDECLTYPE_SHORT2
:
393 SHORT
*dst_ptr
= (SHORT
*)dst
;
394 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
395 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
398 case D3DDECLTYPE_SHORT4
:
400 SHORT
*dst_ptr
= (SHORT
*)dst
;
401 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
402 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
403 dst_ptr
[2] = (SHORT
)simple_round(src
->z
);
404 dst_ptr
[3] = (SHORT
)simple_round(src
->w
);
407 case D3DDECLTYPE_UBYTE4N
:
409 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
410 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
411 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
412 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
415 case D3DDECLTYPE_SHORT2N
:
417 SHORT
*dst_ptr
= (SHORT
*)dst
;
418 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
419 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
422 case D3DDECLTYPE_SHORT4N
:
424 SHORT
*dst_ptr
= (SHORT
*)dst
;
425 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
426 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
427 dst_ptr
[2] = (SHORT
)simple_round(scale_clamp_shortn(src
->z
));
428 dst_ptr
[3] = (SHORT
)simple_round(scale_clamp_shortn(src
->w
));
431 case D3DDECLTYPE_USHORT2N
:
433 USHORT
*dst_ptr
= (USHORT
*)dst
;
434 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
435 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
438 case D3DDECLTYPE_USHORT4N
:
440 USHORT
*dst_ptr
= (USHORT
*)dst
;
441 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
442 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
443 dst_ptr
[2] = (USHORT
)simple_round(scale_clamp_ushortn(src
->z
));
444 dst_ptr
[3] = (USHORT
)simple_round(scale_clamp_ushortn(src
->w
));
447 case D3DDECLTYPE_FLOAT16_2
:
449 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 2);
452 case D3DDECLTYPE_FLOAT16_4
:
454 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 4);
459 FIXME("Conversion from D3DDECLTYPE_FLOAT4 to %d not implemented.\n", type_dst
);
464 static void convert_component(BYTE
*dst
, BYTE
*src
, D3DDECLTYPE type_dst
, D3DDECLTYPE type_src
)
466 BOOL fixme_once
= FALSE
;
470 case D3DDECLTYPE_FLOAT1
:
472 FLOAT
*src_ptr
= (FLOAT
*)src
;
473 D3DXVECTOR4 src_float4
= {*src_ptr
, 0.0f
, 0.0f
, 1.0f
};
474 convert_float4(dst
, &src_float4
, type_dst
);
477 case D3DDECLTYPE_FLOAT2
:
479 D3DXVECTOR2
*src_ptr
= (D3DXVECTOR2
*)src
;
480 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, 0.0f
, 1.0f
};
481 convert_float4(dst
, &src_float4
, type_dst
);
484 case D3DDECLTYPE_FLOAT3
:
486 D3DXVECTOR3
*src_ptr
= (D3DXVECTOR3
*)src
;
487 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, 1.0f
};
488 convert_float4(dst
, &src_float4
, type_dst
);
491 case D3DDECLTYPE_FLOAT4
:
493 D3DXVECTOR4
*src_ptr
= (D3DXVECTOR4
*)src
;
494 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, src_ptr
->w
};
495 convert_float4(dst
, &src_float4
, type_dst
);
498 case D3DDECLTYPE_D3DCOLOR
:
500 D3DXVECTOR4 src_float4
=
502 (FLOAT
)src
[2]/UCHAR_MAX
,
503 (FLOAT
)src
[1]/UCHAR_MAX
,
504 (FLOAT
)src
[0]/UCHAR_MAX
,
505 (FLOAT
)src
[3]/UCHAR_MAX
507 convert_float4(dst
, &src_float4
, type_dst
);
510 case D3DDECLTYPE_UBYTE4
:
512 D3DXVECTOR4 src_float4
= {src
[0], src
[1], src
[2], src
[3]};
513 convert_float4(dst
, &src_float4
, type_dst
);
516 case D3DDECLTYPE_SHORT2
:
518 SHORT
*src_ptr
= (SHORT
*)src
;
519 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], 0.0f
, 1.0f
};
520 convert_float4(dst
, &src_float4
, type_dst
);
523 case D3DDECLTYPE_SHORT4
:
525 SHORT
*src_ptr
= (SHORT
*)src
;
526 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], src_ptr
[2], src_ptr
[3]};
527 convert_float4(dst
, &src_float4
, type_dst
);
530 case D3DDECLTYPE_UBYTE4N
:
532 D3DXVECTOR4 src_float4
=
534 (FLOAT
)src
[0]/UCHAR_MAX
,
535 (FLOAT
)src
[1]/UCHAR_MAX
,
536 (FLOAT
)src
[2]/UCHAR_MAX
,
537 (FLOAT
)src
[3]/UCHAR_MAX
539 convert_float4(dst
, &src_float4
, type_dst
);
542 case D3DDECLTYPE_SHORT2N
:
544 SHORT
*src_ptr
= (SHORT
*)src
;
545 D3DXVECTOR4 src_float4
= {(FLOAT
)src_ptr
[0]/SHRT_MAX
, (FLOAT
)src_ptr
[1]/SHRT_MAX
, 0.0f
, 1.0f
};
546 convert_float4(dst
, &src_float4
, type_dst
);
549 case D3DDECLTYPE_SHORT4N
:
551 SHORT
*src_ptr
= (SHORT
*)src
;
552 D3DXVECTOR4 src_float4
=
554 (FLOAT
)src_ptr
[0]/SHRT_MAX
,
555 (FLOAT
)src_ptr
[1]/SHRT_MAX
,
556 (FLOAT
)src_ptr
[2]/SHRT_MAX
,
557 (FLOAT
)src_ptr
[3]/SHRT_MAX
559 convert_float4(dst
, &src_float4
, type_dst
);
562 case D3DDECLTYPE_FLOAT16_2
:
564 D3DXVECTOR4 src_float4
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
565 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 2);
566 convert_float4(dst
, &src_float4
, type_dst
);
569 case D3DDECLTYPE_FLOAT16_4
:
571 D3DXVECTOR4 src_float4
;
572 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 4);
573 convert_float4(dst
, &src_float4
, type_dst
);
578 FIXME("Conversion of D3DDECLTYPE %d to %d not implemented.\n", type_src
, type_dst
);
583 static INT
get_equivalent_declaration_index(D3DVERTEXELEMENT9 orig_declaration
, D3DVERTEXELEMENT9
*declaration
)
587 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
589 if (orig_declaration
.Usage
== declaration
[i
].Usage
590 && orig_declaration
.UsageIndex
== declaration
[i
].UsageIndex
)
599 static HRESULT
convert_vertex_buffer(ID3DXMesh
*mesh_dst
, ID3DXMesh
*mesh_src
)
602 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
603 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
607 UINT num_vertices
= mesh_src
->lpVtbl
->GetNumVertices(mesh_src
);
608 UINT dst_vertex_size
= mesh_dst
->lpVtbl
->GetNumBytesPerVertex(mesh_dst
);
609 UINT src_vertex_size
= mesh_src
->lpVtbl
->GetNumBytesPerVertex(mesh_src
);
611 hr
= mesh_src
->lpVtbl
->GetDeclaration(mesh_src
, orig_declaration
);
612 if (FAILED(hr
)) return hr
;
613 hr
= mesh_dst
->lpVtbl
->GetDeclaration(mesh_dst
, declaration
);
614 if (FAILED(hr
)) return hr
;
616 hr
= mesh_src
->lpVtbl
->LockVertexBuffer(mesh_src
, D3DLOCK_READONLY
, (void**)&vb_src
);
617 if (FAILED(hr
)) goto cleanup
;
618 hr
= mesh_dst
->lpVtbl
->LockVertexBuffer(mesh_dst
, 0, (void**)&vb_dst
);
619 if (FAILED(hr
)) goto cleanup
;
621 /* Clear all new fields by clearing the entire vertex buffer. */
622 memset(vb_dst
, 0, num_vertices
* dst_vertex_size
);
624 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++)
626 INT eq_idx
= get_equivalent_declaration_index(orig_declaration
[i
], declaration
);
631 for (j
= 0; j
< num_vertices
; j
++)
633 UINT idx_dst
= dst_vertex_size
* j
+ declaration
[eq_idx
].Offset
;
634 UINT idx_src
= src_vertex_size
* j
+ orig_declaration
[i
].Offset
;
635 UINT type_size
= d3dx_decltype_size
[orig_declaration
[i
].Type
];
637 if (orig_declaration
[i
].Type
== declaration
[eq_idx
].Type
)
638 memcpy(&vb_dst
[idx_dst
], &vb_src
[idx_src
], type_size
);
640 convert_component(&vb_dst
[idx_dst
], &vb_src
[idx_src
], declaration
[eq_idx
].Type
, orig_declaration
[i
].Type
);
647 if (vb_dst
) mesh_dst
->lpVtbl
->UnlockVertexBuffer(mesh_dst
);
648 if (vb_src
) mesh_src
->lpVtbl
->UnlockVertexBuffer(mesh_src
);
653 static BOOL
declaration_equals(const D3DVERTEXELEMENT9
*declaration1
, const D3DVERTEXELEMENT9
*declaration2
)
655 UINT size1
= 0, size2
= 0;
657 /* Find the size of each declaration */
658 while (declaration1
[size1
].Stream
!= 0xff) size1
++;
659 while (declaration2
[size2
].Stream
!= 0xff) size2
++;
661 /* If not same size then they are definitely not equal */
665 /* Check that all components are the same */
666 if (memcmp(declaration1
, declaration2
, size1
*sizeof(*declaration1
)) == 0)
672 static HRESULT WINAPI
d3dx9_mesh_CloneMesh(struct ID3DXMesh
*iface
, DWORD options
,
673 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh_out
)
675 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
676 struct d3dx9_mesh
*cloned_this
;
677 ID3DXMesh
*clone_mesh
;
678 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
679 void *data_in
, *data_out
;
682 BOOL same_declaration
;
684 TRACE("iface %p, options %#lx, declaration %p, device %p, clone_mesh_out %p.\n",
685 iface
, options
, declaration
, device
, clone_mesh_out
);
688 return D3DERR_INVALIDCALL
;
690 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
691 if (FAILED(hr
)) return hr
;
693 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
694 declaration
, device
, &clone_mesh
);
695 if (FAILED(hr
)) return hr
;
697 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
698 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
699 same_declaration
= declaration_equals(declaration
, orig_declaration
);
701 if (options
& D3DXMESH_VB_SHARE
) {
702 if (!same_declaration
) {
703 hr
= D3DERR_INVALIDCALL
;
706 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
707 /* FIXME: refactor to avoid creating a new vertex buffer */
708 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
709 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
710 } else if (same_declaration
) {
711 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
712 if (FAILED(hr
)) goto error
;
713 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, 0, &data_out
);
715 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
718 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
719 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
720 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
722 hr
= convert_vertex_buffer(clone_mesh
, iface
);
723 if (FAILED(hr
)) goto error
;
726 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
727 if (FAILED(hr
)) goto error
;
728 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, 0, &data_out
);
730 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
733 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
735 if (options
& D3DXMESH_32BIT
) {
736 for (i
= 0; i
< This
->numfaces
* 3; i
++)
737 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
739 for (i
= 0; i
< This
->numfaces
* 3; i
++)
740 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
743 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
745 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
746 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
748 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
750 if (This
->attrib_table_size
)
752 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
753 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
754 if (!cloned_this
->attrib_table
) {
758 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
761 *clone_mesh_out
= clone_mesh
;
765 IUnknown_Release(clone_mesh
);
769 static HRESULT WINAPI
d3dx9_mesh_GetVertexBuffer(struct ID3DXMesh
*iface
,
770 struct IDirect3DVertexBuffer9
**vertex_buffer
)
772 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
774 TRACE("iface %p, vertex_buffer %p.\n", iface
, vertex_buffer
);
777 return D3DERR_INVALIDCALL
;
778 *vertex_buffer
= mesh
->vertex_buffer
;
779 IDirect3DVertexBuffer9_AddRef(mesh
->vertex_buffer
);
784 static HRESULT WINAPI
d3dx9_mesh_GetIndexBuffer(struct ID3DXMesh
*iface
,
785 struct IDirect3DIndexBuffer9
**index_buffer
)
787 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
789 TRACE("iface %p, index_buffer %p.\n", iface
, index_buffer
);
792 return D3DERR_INVALIDCALL
;
793 *index_buffer
= mesh
->index_buffer
;
794 IDirect3DIndexBuffer9_AddRef(mesh
->index_buffer
);
799 static HRESULT WINAPI
d3dx9_mesh_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
801 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
803 TRACE("iface %p, flags %#lx, data %p.\n", iface
, flags
, data
);
805 return IDirect3DVertexBuffer9_Lock(mesh
->vertex_buffer
, 0, 0, data
, flags
);
808 static HRESULT WINAPI
d3dx9_mesh_UnlockVertexBuffer(ID3DXMesh
*iface
)
810 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
812 TRACE("iface %p.\n", iface
);
814 return IDirect3DVertexBuffer9_Unlock(mesh
->vertex_buffer
);
817 static HRESULT WINAPI
d3dx9_mesh_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
819 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
821 TRACE("iface %p, flags %#lx, data %p.\n", iface
, flags
, data
);
823 return IDirect3DIndexBuffer9_Lock(mesh
->index_buffer
, 0, 0, data
, flags
);
826 static HRESULT WINAPI
d3dx9_mesh_UnlockIndexBuffer(ID3DXMesh
*iface
)
828 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
830 TRACE("iface %p.\n", iface
);
832 return IDirect3DIndexBuffer9_Unlock(mesh
->index_buffer
);
835 /* FIXME: This looks just wrong, we never check *attrib_table_size before
836 * copying the data. */
837 static HRESULT WINAPI
d3dx9_mesh_GetAttributeTable(ID3DXMesh
*iface
,
838 D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
840 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
842 TRACE("iface %p, attrib_table %p, attrib_table_size %p.\n",
843 iface
, attrib_table
, attrib_table_size
);
845 if (attrib_table_size
)
846 *attrib_table_size
= mesh
->attrib_table_size
;
849 memcpy(attrib_table
, mesh
->attrib_table
, mesh
->attrib_table_size
* sizeof(*attrib_table
));
864 struct edge_face
*entries
;
867 /* Builds up a map of which face a new edge belongs to. That way the adjacency
868 * of another edge can be looked up. An edge has an adjacent face if there
869 * is an edge going in the opposite direction in the map. For example if the
870 * edge (v1, v2) belongs to face 4, and there is a mapping (v2, v1)->7, then
871 * face 4 and 7 are adjacent.
873 * Each edge might have been replaced with another edge, or none at all. There
874 * is at most one edge to face mapping, i.e. an edge can only belong to one
877 static HRESULT
init_edge_face_map(struct edge_face_map
*edge_face_map
, const DWORD
*index_buffer
,
878 const DWORD
*point_reps
, DWORD num_faces
)
883 edge_face_map
->lists
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->lists
));
884 if (!edge_face_map
->lists
) return E_OUTOFMEMORY
;
886 edge_face_map
->entries
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->entries
));
887 if (!edge_face_map
->entries
) return E_OUTOFMEMORY
;
890 /* Initialize all lists */
891 for (i
= 0; i
< 3 * num_faces
; i
++)
893 list_init(&edge_face_map
->lists
[i
]);
895 /* Build edge face mapping */
896 for (face
= 0; face
< num_faces
; face
++)
898 for (edge
= 0; edge
< 3; edge
++)
900 DWORD v1
= index_buffer
[3*face
+ edge
];
901 DWORD v2
= index_buffer
[3*face
+ (edge
+1)%3];
902 DWORD new_v1
= point_reps
[v1
]; /* What v1 has been replaced with */
903 DWORD new_v2
= point_reps
[v2
];
905 if (v1
!= v2
) /* Only map non-collapsed edges */
908 edge_face_map
->entries
[i
].v2
= new_v2
;
909 edge_face_map
->entries
[i
].face
= face
;
910 list_add_head(&edge_face_map
->lists
[new_v1
], &edge_face_map
->entries
[i
].entry
);
918 static DWORD
find_adjacent_face(struct edge_face_map
*edge_face_map
, DWORD vertex1
, DWORD vertex2
, DWORD num_faces
)
920 struct edge_face
*edge_face_ptr
;
922 LIST_FOR_EACH_ENTRY(edge_face_ptr
, &edge_face_map
->lists
[vertex2
], struct edge_face
, entry
)
924 if (edge_face_ptr
->v2
== vertex1
)
925 return edge_face_ptr
->face
;
931 static DWORD
*generate_identity_point_reps(DWORD num_vertices
)
933 DWORD
*id_point_reps
;
936 id_point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*id_point_reps
));
940 for (i
= 0; i
< num_vertices
; i
++)
942 id_point_reps
[i
] = i
;
945 return id_point_reps
;
948 static HRESULT WINAPI
d3dx9_mesh_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
,
949 const DWORD
*point_reps
, DWORD
*adjacency
)
952 DWORD num_faces
= iface
->lpVtbl
->GetNumFaces(iface
);
953 DWORD num_vertices
= iface
->lpVtbl
->GetNumVertices(iface
);
954 DWORD options
= iface
->lpVtbl
->GetOptions(iface
);
955 BOOL indices_are_16_bit
= !(options
& D3DXMESH_32BIT
);
960 struct edge_face_map edge_face_map
= {0};
961 const DWORD
*point_reps_ptr
= NULL
;
962 DWORD
*id_point_reps
= NULL
;
964 TRACE("iface %p, point_reps %p, adjacency %p.\n", iface
, point_reps
, adjacency
);
966 if (!adjacency
) return D3DERR_INVALIDCALL
;
968 if (!point_reps
) /* Identity point reps */
970 id_point_reps
= generate_identity_point_reps(num_vertices
);
977 point_reps_ptr
= id_point_reps
;
981 point_reps_ptr
= point_reps
;
984 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &ib_ptr
);
985 if (FAILED(hr
)) goto cleanup
;
987 if (indices_are_16_bit
)
989 /* Widen 16 bit to 32 bit */
991 WORD
*ib_16bit
= ib_ptr
;
992 ib
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(DWORD
));
998 for (i
= 0; i
< 3 * num_faces
; i
++)
1000 ib
[i
] = ib_16bit
[i
];
1008 hr
= init_edge_face_map(&edge_face_map
, ib
, point_reps_ptr
, num_faces
);
1009 if (FAILED(hr
)) goto cleanup
;
1011 /* Create adjacency */
1012 for (face
= 0; face
< num_faces
; face
++)
1014 for (edge
= 0; edge
< 3; edge
++)
1016 DWORD v1
= ib
[3*face
+ edge
];
1017 DWORD v2
= ib
[3*face
+ (edge
+1)%3];
1018 DWORD new_v1
= point_reps_ptr
[v1
];
1019 DWORD new_v2
= point_reps_ptr
[v2
];
1022 adj_face
= find_adjacent_face(&edge_face_map
, new_v1
, new_v2
, num_faces
);
1023 adjacency
[3*face
+ edge
] = adj_face
;
1029 HeapFree(GetProcessHeap(), 0, id_point_reps
);
1030 if (indices_are_16_bit
) HeapFree(GetProcessHeap(), 0, ib
);
1031 HeapFree(GetProcessHeap(), 0, edge_face_map
.lists
);
1032 HeapFree(GetProcessHeap(), 0, edge_face_map
.entries
);
1033 if(ib_ptr
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1037 /* ConvertAdjacencyToPointReps helper function.
1039 * Goes around the edges of each face and replaces the vertices in any adjacent
1040 * face's edge with its own vertices(if its vertices have a lower index). This
1041 * way as few as possible low index vertices are shared among the faces. The
1042 * re-ordered index buffer is stored in new_indices.
1044 * The vertices in a point representation must be ordered sequentially, e.g.
1045 * index 5 holds the index of the vertex that replaces vertex 5, i.e. if
1046 * vertex 5 is replaced by vertex 3 then index 5 would contain 3. If no vertex
1047 * replaces it, then it contains the same number as the index itself, e.g.
1048 * index 5 would contain 5. */
1049 static HRESULT
propagate_face_vertices(const DWORD
*adjacency
, DWORD
*point_reps
,
1050 const uint32_t *indices
, uint32_t *new_indices
, unsigned int face_idx
, unsigned int face_count
)
1052 unsigned int face_base
= 3 * face_idx
;
1053 unsigned int edge
, opp_edge
;
1055 for (edge
= 0; edge
< 3; ++edge
)
1057 unsigned int adj_face
= adjacency
[face_base
+ edge
];
1058 unsigned int adj_face_base
;
1061 if (adj_face
== ~0u) /* No adjacent face. */
1063 else if (adj_face
>= face_count
)
1065 /* This crashes on Windows. */
1066 WARN("Index out of bounds. Got %u, expected less than %u.\n", adj_face
, face_count
);
1067 return D3DERR_INVALIDCALL
;
1069 adj_face_base
= 3 * adj_face
;
1071 /* Find opposite edge in adjacent face. */
1072 for (opp_edge
= 0; opp_edge
< 3; ++opp_edge
)
1074 unsigned int opp_edge_index
= adj_face_base
+ opp_edge
;
1076 if (adjacency
[opp_edge_index
] == face_idx
)
1077 break; /* Found opposite edge. */
1080 /* Replaces vertices in opposite edge with vertices from current edge. */
1081 for (i
= 0; i
< 2; ++i
)
1083 unsigned int from
= face_base
+ (edge
+ (1 - i
)) % 3;
1084 unsigned int to
= adj_face_base
+ (opp_edge
+ i
) % 3;
1086 /* Propagate lowest index. */
1087 if (new_indices
[to
] > new_indices
[from
])
1089 new_indices
[to
] = new_indices
[from
];
1090 point_reps
[indices
[to
]] = new_indices
[from
];
1098 static HRESULT WINAPI
d3dx9_mesh_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
,
1099 const DWORD
*adjacency
, DWORD
*point_reps
)
1101 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1102 uint16_t *indices_16bit
= NULL
;
1103 uint32_t *new_indices
= NULL
;
1104 uint32_t *indices
= NULL
;
1105 unsigned int face
, i
;
1108 TRACE("iface %p, adjacency %p, point_reps %p.\n", iface
, adjacency
, point_reps
);
1112 WARN("NULL adjacency.\n");
1113 return D3DERR_INVALIDCALL
;
1118 WARN("NULL point_reps.\n");
1119 return D3DERR_INVALIDCALL
;
1122 /* Should never happen as CreateMesh does not allow meshes with 0 faces. */
1123 if (!mesh
->numfaces
)
1125 ERR("Number of faces was zero.\n");
1126 return D3DERR_INVALIDCALL
;
1129 if (!(new_indices
= HeapAlloc(GetProcessHeap(), 0, 3 * mesh
->numfaces
* sizeof(*indices
))))
1130 return E_OUTOFMEMORY
;
1132 if (mesh
->options
& D3DXMESH_32BIT
)
1134 if (FAILED(hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void **)&indices
)))
1136 memcpy(new_indices
, indices
, 3 * mesh
->numfaces
* sizeof(*indices
));
1140 /* Make a widening copy of indices_16bit into indices and new_indices
1141 * in order to re-use the helper function. */
1142 if (FAILED(hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void **)&indices_16bit
)))
1145 if (!(indices
= HeapAlloc(GetProcessHeap(), 0, 3 * mesh
->numfaces
* sizeof(*indices
))))
1150 for (i
= 0; i
< 3 * mesh
->numfaces
; ++i
)
1152 new_indices
[i
] = indices_16bit
[i
];
1153 indices
[i
] = indices_16bit
[i
];
1157 /* Vertices are ordered sequentially in the point representation. */
1158 for (i
= 0; i
< mesh
->numvertices
; ++i
)
1161 /* Propagate vertices with low indices so as few vertices as possible are
1162 * used in the mesh. */
1163 for (face
= 0; face
< mesh
->numfaces
; ++face
)
1165 if (FAILED(hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
, face
, mesh
->numfaces
)))
1168 /* Go in opposite direction to catch all face orderings. */
1169 for (face
= 0; face
< mesh
->numfaces
; ++face
)
1171 if (FAILED(hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
,
1172 (mesh
->numfaces
- 1) - face
, mesh
->numfaces
)))
1179 if (mesh
->options
& D3DXMESH_32BIT
)
1182 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1187 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1188 HeapFree(GetProcessHeap(), 0, indices
);
1190 HeapFree(GetProcessHeap(), 0, new_indices
);
1194 struct vertex_metadata
{
1197 DWORD first_shared_index
;
1200 static int __cdecl
compare_vertex_keys(const void *a
, const void *b
)
1202 const struct vertex_metadata
*left
= a
;
1203 const struct vertex_metadata
*right
= b
;
1204 if (left
->key
== right
->key
)
1206 return left
->key
< right
->key
? -1 : 1;
1209 static HRESULT WINAPI
d3dx9_mesh_GenerateAdjacency(ID3DXMesh
*iface
, float epsilon
, DWORD
*adjacency
)
1211 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1213 BYTE
*vertices
= NULL
;
1214 const DWORD
*indices
= NULL
;
1217 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
1218 struct vertex_metadata
*sorted_vertices
;
1219 /* shared_indices links together identical indices in the index buffer so
1220 * that adjacency checks can be limited to faces sharing a vertex */
1221 DWORD
*shared_indices
= NULL
;
1222 const FLOAT epsilon_sq
= epsilon
* epsilon
;
1225 TRACE("iface %p, epsilon %.8e, adjacency %p.\n", iface
, epsilon
, adjacency
);
1228 return D3DERR_INVALIDCALL
;
1230 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
1231 if (!(This
->options
& D3DXMESH_32BIT
))
1232 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
1233 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
1234 if (!shared_indices
)
1235 return E_OUTOFMEMORY
;
1236 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
1238 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
1239 if (FAILED(hr
)) goto cleanup
;
1240 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1241 if (FAILED(hr
)) goto cleanup
;
1243 if (!(This
->options
& D3DXMESH_32BIT
)) {
1244 const WORD
*word_indices
= (const WORD
*)indices
;
1245 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
1246 indices
= dword_indices
;
1247 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1248 *dword_indices
++ = *word_indices
++;
1251 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1252 for (i
= 0; i
< This
->numvertices
; i
++) {
1253 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
1254 sorted_vertices
[i
].first_shared_index
= -1;
1255 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
1256 sorted_vertices
[i
].vertex_index
= i
;
1258 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
1259 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
1260 shared_indices
[i
] = *first_shared_index
;
1261 *first_shared_index
= i
;
1264 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
1266 for (i
= 0; i
< This
->numvertices
; i
++) {
1267 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
1268 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
1269 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
1271 while (shared_index_a
!= -1) {
1273 DWORD shared_index_b
= shared_indices
[shared_index_a
];
1274 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
1277 while (shared_index_b
!= -1) {
1278 /* faces are adjacent if they have another coincident vertex */
1279 DWORD base_a
= (shared_index_a
/ 3) * 3;
1280 DWORD base_b
= (shared_index_b
/ 3) * 3;
1281 BOOL adjacent
= FALSE
;
1284 for (k
= 0; k
< 3; k
++) {
1285 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
1291 for (k
= 1; k
<= 2; k
++) {
1292 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
1293 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
1294 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
1295 if (!adjacent
&& epsilon
>= 0.0f
) {
1296 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
1299 D3DXVec3Subtract(&delta
,
1300 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
1301 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
1302 length_sq
= D3DXVec3LengthSq(&delta
);
1303 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
1306 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
1307 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
1308 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
1309 adjacency
[adj_a
] = base_b
/ 3;
1310 adjacency
[adj_b
] = base_a
/ 3;
1317 shared_index_b
= shared_indices
[shared_index_b
];
1319 while (++j
< This
->numvertices
) {
1320 D3DXVECTOR3
*vertex_b
;
1323 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
1324 /* no more coincident vertices to try */
1325 j
= This
->numvertices
;
1328 /* check for coincidence */
1329 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
1330 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
1331 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
1332 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
1337 if (j
>= This
->numvertices
)
1339 shared_index_b
= sorted_vertex_b
->first_shared_index
;
1342 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
1343 shared_index_a
= sorted_vertex_a
->first_shared_index
;
1349 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1350 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
1351 HeapFree(GetProcessHeap(), 0, shared_indices
);
1355 static HRESULT WINAPI
d3dx9_mesh_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1357 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1359 UINT vertex_declaration_size
;
1362 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
1366 WARN("Invalid declaration. Can't use NULL declaration.\n");
1367 return D3DERR_INVALIDCALL
;
1370 /* New declaration must be same size as original */
1371 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
1372 if (vertex_declaration_size
!= This
->vertex_declaration_size
)
1374 WARN("Invalid declaration. New vertex size does not match the original vertex size.\n");
1375 return D3DERR_INVALIDCALL
;
1378 /* New declaration must not contain non-zero Stream value */
1379 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1381 if (declaration
[i
].Stream
!= 0)
1383 WARN("Invalid declaration. New declaration contains non-zero Stream value.\n");
1384 return D3DERR_INVALIDCALL
;
1388 This
->num_elem
= i
+ 1;
1389 copy_declaration(This
->cached_declaration
, declaration
, This
->num_elem
);
1391 if (This
->vertex_declaration
)
1392 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
1394 /* An application can pass an invalid declaration to UpdateSemantics and
1395 * still expect D3D_OK (see tests). If the declaration is invalid, then
1396 * subsequent calls to DrawSubset will fail. This is handled by setting the
1397 * vertex declaration to NULL.
1398 * GetDeclaration, GetNumBytesPerVertex must, however, use the new
1399 * invalid declaration. This is handled by them using the cached vertex
1400 * declaration instead of the actual vertex declaration.
1402 hr
= IDirect3DDevice9_CreateVertexDeclaration(This
->device
,
1404 &This
->vertex_declaration
);
1407 WARN("Using invalid declaration. Calls to DrawSubset will fail.\n");
1408 This
->vertex_declaration
= NULL
;
1414 static HRESULT WINAPI
d3dx9_mesh_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
1416 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1418 TRACE("iface %p, flags %#lx, data %p.\n", iface
, flags
, data
);
1420 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1422 if (!(flags
& D3DLOCK_READONLY
))
1424 D3DXATTRIBUTERANGE
*attrib_table
= mesh
->attrib_table
;
1425 mesh
->attrib_table_size
= 0;
1426 mesh
->attrib_table
= NULL
;
1427 HeapFree(GetProcessHeap(), 0, attrib_table
);
1430 *data
= mesh
->attrib_buffer
;
1435 static HRESULT WINAPI
d3dx9_mesh_UnlockAttributeBuffer(ID3DXMesh
*iface
)
1437 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1440 TRACE("iface %p.\n", iface
);
1442 lock_count
= InterlockedDecrement(&mesh
->attrib_buffer_lock_count
);
1445 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1446 return D3DERR_INVALIDCALL
;
1452 static HRESULT WINAPI
d3dx9_mesh_Optimize(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1453 DWORD
*adjacency_out
, DWORD
*face_remap
, ID3DXBuffer
**vertex_remap
, ID3DXMesh
**opt_mesh
)
1455 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1457 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
1458 ID3DXMesh
*optimized_mesh
;
1460 TRACE("iface %p, flags %#lx, adjacency_in %p, adjacency_out %p, face_remap %p, vertex_remap %p, opt_mesh %p.\n",
1461 iface
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
1464 return D3DERR_INVALIDCALL
;
1466 hr
= iface
->lpVtbl
->GetDeclaration(iface
, declaration
);
1467 if (FAILED(hr
)) return hr
;
1469 if (FAILED(hr
= iface
->lpVtbl
->CloneMesh(iface
, mesh
->options
, declaration
, mesh
->device
, &optimized_mesh
)))
1472 hr
= optimized_mesh
->lpVtbl
->OptimizeInplace(optimized_mesh
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
);
1474 *opt_mesh
= optimized_mesh
;
1476 IUnknown_Release(optimized_mesh
);
1480 /* Creates a vertex_remap that removes unused vertices.
1481 * Indices are updated according to the vertex_remap. */
1482 static HRESULT
compact_mesh(struct d3dx9_mesh
*This
, DWORD
*indices
,
1483 DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
1486 DWORD
*vertex_remap_ptr
;
1487 DWORD num_used_vertices
;
1490 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
1491 if (FAILED(hr
)) return hr
;
1492 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
1494 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1495 vertex_remap_ptr
[indices
[i
]] = 1;
1497 /* create old->new vertex mapping */
1498 num_used_vertices
= 0;
1499 for (i
= 0; i
< This
->numvertices
; i
++) {
1500 if (vertex_remap_ptr
[i
])
1501 vertex_remap_ptr
[i
] = num_used_vertices
++;
1503 vertex_remap_ptr
[i
] = -1;
1505 /* convert indices */
1506 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1507 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
1509 /* create new->old vertex mapping */
1510 num_used_vertices
= 0;
1511 for (i
= 0; i
< This
->numvertices
; i
++) {
1512 if (vertex_remap_ptr
[i
] != -1)
1513 vertex_remap_ptr
[num_used_vertices
++] = i
;
1515 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
1516 vertex_remap_ptr
[i
] = -1;
1518 *new_num_vertices
= num_used_vertices
;
1523 /* count the number of unique attribute values in a sorted attribute buffer */
1524 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
1526 DWORD last_attribute
= attrib_buffer
[0];
1527 DWORD attrib_table_size
= 1;
1529 for (i
= 1; i
< numfaces
; i
++) {
1530 if (attrib_buffer
[i
] != last_attribute
) {
1531 last_attribute
= attrib_buffer
[i
];
1532 attrib_table_size
++;
1535 return attrib_table_size
;
1538 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
1539 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
1541 DWORD attrib_table_size
= 0;
1542 DWORD last_attribute
= attrib_buffer
[0];
1543 DWORD min_vertex
, max_vertex
;
1546 attrib_table
[0].AttribId
= last_attribute
;
1547 attrib_table
[0].FaceStart
= 0;
1548 min_vertex
= (DWORD
)-1;
1550 for (i
= 0; i
< numfaces
; i
++) {
1553 if (attrib_buffer
[i
] != last_attribute
) {
1554 last_attribute
= attrib_buffer
[i
];
1555 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1556 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1557 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1558 attrib_table_size
++;
1559 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
1560 attrib_table
[attrib_table_size
].FaceStart
= i
;
1561 min_vertex
= (DWORD
)-1;
1564 for (j
= 0; j
< 3; j
++) {
1565 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
1566 if (vertex_index
< min_vertex
)
1567 min_vertex
= vertex_index
;
1568 if (vertex_index
> max_vertex
)
1569 max_vertex
= vertex_index
;
1572 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1573 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1574 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1575 attrib_table_size
++;
1578 static int __cdecl
attrib_entry_compare(const void *a
, const void *b
)
1580 const DWORD
*ptr_a
= *(const DWORD
**)a
;
1581 const DWORD
*ptr_b
= *(const DWORD
**)b
;
1582 int delta
= *ptr_a
- *ptr_b
;
1587 delta
= ptr_a
- ptr_b
; /* for stable sort */
1591 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
1592 static HRESULT
remap_faces_for_attrsort(struct d3dx9_mesh
*This
, const DWORD
*indices
,
1593 DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
1595 DWORD
**sorted_attrib_ptr_buffer
= NULL
;
1598 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
1599 if (!sorted_attrib_ptr_buffer
)
1600 return E_OUTOFMEMORY
;
1602 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
1605 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
1606 return E_OUTOFMEMORY
;
1609 for (i
= 0; i
< This
->numfaces
; i
++)
1610 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
1611 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
), attrib_entry_compare
);
1613 for (i
= 0; i
< This
->numfaces
; i
++)
1615 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
1616 (*face_remap
)[old_face
] = i
;
1619 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
1620 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
1621 for (i
= 0; i
< This
->numfaces
; i
++)
1622 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
1627 static HRESULT WINAPI
d3dx9_mesh_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1628 DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
1630 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1631 void *indices
= NULL
;
1632 DWORD
*attrib_buffer
= NULL
;
1634 ID3DXBuffer
*vertex_remap
= NULL
;
1635 DWORD
*face_remap
= NULL
; /* old -> new mapping */
1636 DWORD
*dword_indices
= NULL
;
1637 DWORD new_num_vertices
= 0;
1638 DWORD new_num_alloc_vertices
= 0;
1639 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
1640 DWORD
*sorted_attrib_buffer
= NULL
;
1643 TRACE("iface %p, flags %#lx, adjacency_in %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
1644 iface
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
1647 return D3DERR_INVALIDCALL
;
1648 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
1649 return D3DERR_INVALIDCALL
;
1650 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1651 return D3DERR_INVALIDCALL
;
1653 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1655 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
1656 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
1657 if (flags
& D3DXMESHOPT_STRIPREORDER
)
1658 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
1662 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, &indices
);
1663 if (FAILED(hr
)) goto cleanup
;
1665 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
1666 if (!dword_indices
) return E_OUTOFMEMORY
;
1667 if (This
->options
& D3DXMESH_32BIT
) {
1668 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1670 WORD
*word_indices
= indices
;
1671 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1672 dword_indices
[i
] = *word_indices
++;
1675 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
1677 new_num_alloc_vertices
= This
->numvertices
;
1678 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
1679 if (FAILED(hr
)) goto cleanup
;
1680 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
1681 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
1682 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
d3dx9_mesh_SetAttributeTable(ID3DXMesh
*iface
,
1822 const D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
1824 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1825 D3DXATTRIBUTERANGE
*new_table
= NULL
;
1827 TRACE("iface %p, attrib_table %p, attrib_table_size %lu.\n", iface
, attrib_table
, attrib_table_size
);
1829 if (attrib_table_size
) {
1830 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
1832 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
1834 return E_OUTOFMEMORY
;
1836 CopyMemory(new_table
, attrib_table
, size
);
1837 } else if (attrib_table
) {
1838 return D3DERR_INVALIDCALL
;
1840 HeapFree(GetProcessHeap(), 0, mesh
->attrib_table
);
1841 mesh
->attrib_table
= new_table
;
1842 mesh
->attrib_table_size
= attrib_table_size
;
1847 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
1849 d3dx9_mesh_QueryInterface
,
1852 d3dx9_mesh_DrawSubset
,
1853 d3dx9_mesh_GetNumFaces
,
1854 d3dx9_mesh_GetNumVertices
,
1856 d3dx9_mesh_GetDeclaration
,
1857 d3dx9_mesh_GetNumBytesPerVertex
,
1858 d3dx9_mesh_GetOptions
,
1859 d3dx9_mesh_GetDevice
,
1860 d3dx9_mesh_CloneMeshFVF
,
1861 d3dx9_mesh_CloneMesh
,
1862 d3dx9_mesh_GetVertexBuffer
,
1863 d3dx9_mesh_GetIndexBuffer
,
1864 d3dx9_mesh_LockVertexBuffer
,
1865 d3dx9_mesh_UnlockVertexBuffer
,
1866 d3dx9_mesh_LockIndexBuffer
,
1867 d3dx9_mesh_UnlockIndexBuffer
,
1868 d3dx9_mesh_GetAttributeTable
,
1869 d3dx9_mesh_ConvertPointRepsToAdjacency
,
1870 d3dx9_mesh_ConvertAdjacencyToPointReps
,
1871 d3dx9_mesh_GenerateAdjacency
,
1872 d3dx9_mesh_UpdateSemantics
,
1873 d3dx9_mesh_LockAttributeBuffer
,
1874 d3dx9_mesh_UnlockAttributeBuffer
,
1875 d3dx9_mesh_Optimize
,
1876 d3dx9_mesh_OptimizeInplace
,
1877 d3dx9_mesh_SetAttributeTable
,
1881 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algorithm
1882 Amy Williams University of Utah
1883 Steve Barrus University of Utah
1884 R. Keith Morley University of Utah
1885 Peter Shirley University of Utah
1887 International Conference on Computer Graphics and Interactive Techniques archive
1888 ACM SIGGRAPH 2005 Courses
1889 Los Angeles, California
1891 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1893 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1894 against each slab, if there's anything left of the ray after we're
1895 done we've got an intersection of the ray with the box. */
1896 BOOL WINAPI
D3DXBoxBoundProbe(const D3DXVECTOR3
*pmin
, const D3DXVECTOR3
*pmax
,
1897 const D3DXVECTOR3
*prayposition
, const D3DXVECTOR3
*praydirection
)
1899 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
1901 div
= 1.0f
/ praydirection
->x
;
1904 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
1905 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
1909 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
1910 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
1913 if ( tmax
< 0.0f
) return FALSE
;
1915 div
= 1.0f
/ praydirection
->y
;
1918 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
1919 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
1923 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
1924 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
1927 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
1929 if ( tymin
> tmin
) tmin
= tymin
;
1930 if ( tymax
< tmax
) tmax
= tymax
;
1932 div
= 1.0f
/ praydirection
->z
;
1935 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
1936 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
1940 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
1941 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
1944 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
1949 HRESULT WINAPI
D3DXComputeBoundingBox(const D3DXVECTOR3
*pfirstposition
,
1950 DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
1955 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
1957 *pmin
= *pfirstposition
;
1960 for(i
=0; i
<numvertices
; i
++)
1962 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
1964 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
1965 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
1967 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
1968 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
1970 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
1971 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
1977 HRESULT WINAPI
D3DXComputeBoundingSphere(const D3DXVECTOR3
*pfirstposition
,
1978 DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, float *pradius
)
1984 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
1991 for(i
=0; i
<numvertices
; i
++)
1992 D3DXVec3Add(&temp
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
1994 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/ numvertices
);
1996 for(i
=0; i
<numvertices
; i
++)
1998 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
1999 if ( d
> *pradius
) *pradius
= d
;
2004 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
2005 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
2007 declaration
[*idx
].Stream
= 0;
2008 declaration
[*idx
].Offset
= *offset
;
2009 declaration
[*idx
].Type
= type
;
2010 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
2011 declaration
[*idx
].Usage
= usage
;
2012 declaration
[*idx
].UsageIndex
= usage_idx
;
2014 *offset
+= d3dx_decltype_size
[type
];
2018 /*************************************************************************
2019 * D3DXDeclaratorFromFVF
2021 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
2023 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
2024 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2025 unsigned int offset
= 0;
2026 unsigned int idx
= 0;
2029 TRACE("fvf %#lx, declaration %p.\n", fvf
, declaration
);
2031 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
2033 if (fvf
& D3DFVF_POSITION_MASK
)
2035 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
2036 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
2037 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
2039 if (has_blend_idx
) --blend_count
;
2041 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
2042 || (has_blend
&& blend_count
> 4))
2043 return D3DERR_INVALIDCALL
;
2045 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
2046 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
2048 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
2052 switch (blend_count
)
2057 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2060 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2063 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2066 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2069 ERR("Invalid blend count %lu.\n", blend_count
);
2075 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
2076 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
2077 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
2078 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
2083 if (fvf
& D3DFVF_NORMAL
)
2084 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
2085 if (fvf
& D3DFVF_PSIZE
)
2086 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
2087 if (fvf
& D3DFVF_DIFFUSE
)
2088 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
2089 if (fvf
& D3DFVF_SPECULAR
)
2090 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
2092 for (i
= 0; i
< tex_count
; ++i
)
2094 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
2096 case D3DFVF_TEXTUREFORMAT1
:
2097 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
2099 case D3DFVF_TEXTUREFORMAT2
:
2100 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
2102 case D3DFVF_TEXTUREFORMAT3
:
2103 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
2105 case D3DFVF_TEXTUREFORMAT4
:
2106 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
2111 declaration
[idx
] = end_element
;
2116 /*************************************************************************
2117 * D3DXFVFFromDeclarator
2119 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
2121 unsigned int i
= 0, texture
, offset
;
2123 TRACE("(%p, %p)\n", declaration
, fvf
);
2126 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
2128 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2129 declaration
[1].UsageIndex
== 0) &&
2130 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
2131 declaration
[2].UsageIndex
== 0))
2133 return D3DERR_INVALIDCALL
;
2135 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2136 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
2138 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
2140 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
2144 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
2148 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2149 declaration
[1].UsageIndex
== 0)
2151 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2152 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
2154 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
2156 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
2160 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
2162 switch (declaration
[1].Type
)
2164 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
2165 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
2166 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
2167 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
2173 switch (declaration
[1].Type
)
2175 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
2176 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
2177 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
2178 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
2189 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
2190 declaration
[0].UsageIndex
== 0)
2192 *fvf
|= D3DFVF_XYZRHW
;
2196 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
2198 *fvf
|= D3DFVF_NORMAL
;
2201 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
2202 declaration
[i
].UsageIndex
== 0)
2204 *fvf
|= D3DFVF_PSIZE
;
2207 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2208 declaration
[i
].UsageIndex
== 0)
2210 *fvf
|= D3DFVF_DIFFUSE
;
2213 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2214 declaration
[i
].UsageIndex
== 1)
2216 *fvf
|= D3DFVF_SPECULAR
;
2220 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
2222 if (declaration
[i
].Stream
== 0xFF)
2226 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2227 declaration
[i
].UsageIndex
== texture
)
2229 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
2231 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2232 declaration
[i
].UsageIndex
== texture
)
2234 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
2236 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2237 declaration
[i
].UsageIndex
== texture
)
2239 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
2241 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2242 declaration
[i
].UsageIndex
== texture
)
2244 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
2248 return D3DERR_INVALIDCALL
;
2252 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
2254 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
2255 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
2257 if (declaration
[i
].Offset
!= offset
)
2259 return D3DERR_INVALIDCALL
;
2266 /*************************************************************************
2267 * D3DXGetFVFVertexSize
2269 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
2271 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
2274 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
2278 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2280 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
2281 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
2282 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
2283 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
2285 switch (FVF
& D3DFVF_POSITION_MASK
)
2287 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
2288 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
2289 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
2290 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
2291 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
2292 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
2293 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
2294 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
2297 for (i
= 0; i
< numTextures
; i
++)
2299 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
2305 /*************************************************************************
2306 * D3DXGetDeclVertexSize
2308 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
2310 const D3DVERTEXELEMENT9
*element
;
2313 TRACE("decl %p, stream_idx %lu.\n", decl
, stream_idx
);
2315 if (!decl
) return 0;
2317 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
2321 if (element
->Stream
!= stream_idx
) continue;
2323 if (element
->Type
>= ARRAY_SIZE(d3dx_decltype_size
))
2325 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
2329 type_size
= d3dx_decltype_size
[element
->Type
];
2330 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
2336 /*************************************************************************
2339 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
2341 const D3DVERTEXELEMENT9
*element
;
2343 TRACE("decl %p\n", decl
);
2345 /* null decl results in exception on Windows XP */
2347 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
2349 return element
- decl
;
2352 BOOL WINAPI
D3DXIntersectTri(const D3DXVECTOR3
*p0
, const D3DXVECTOR3
*p1
, const D3DXVECTOR3
*p2
,
2353 const D3DXVECTOR3
*praypos
, const D3DXVECTOR3
*praydir
, float *pu
, float *pv
, float *pdist
)
2358 TRACE("p0 %p, p1 %p, p2 %p, praypos %p, praydir %p, pu %p, pv %p, pdist %p.\n",
2359 p0
, p1
, p2
, praypos
, praydir
, pu
, pv
, pdist
);
2361 m
.m
[0][0] = p1
->x
- p0
->x
;
2362 m
.m
[1][0] = p2
->x
- p0
->x
;
2363 m
.m
[2][0] = -praydir
->x
;
2365 m
.m
[0][1] = p1
->y
- p0
->y
;
2366 m
.m
[1][1] = p2
->y
- p0
->y
;
2367 m
.m
[2][1] = -praydir
->y
;
2369 m
.m
[0][2] = p1
->z
- p0
->z
;
2370 m
.m
[1][2] = p2
->z
- p0
->z
;
2371 m
.m
[2][2] = -praydir
->z
;
2378 vec
.x
= praypos
->x
- p0
->x
;
2379 vec
.y
= praypos
->y
- p0
->y
;
2380 vec
.z
= praypos
->z
- p0
->z
;
2383 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
2385 D3DXVec4Transform(&vec
, &vec
, &m
);
2386 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
2388 if (pu
) *pu
= vec
.x
;
2389 if (pv
) *pv
= vec
.y
;
2390 if (pdist
) *pdist
= fabsf( vec
.z
);
2398 BOOL WINAPI
D3DXSphereBoundProbe(const D3DXVECTOR3
*center
, float radius
,
2399 const D3DXVECTOR3
*ray_position
, const D3DXVECTOR3
*ray_direction
)
2401 D3DXVECTOR3 difference
= {0};
2404 D3DXVec3Subtract(&difference
, ray_position
, center
);
2405 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
2408 a
= D3DXVec3LengthSq(ray_direction
);
2409 b
= D3DXVec3Dot(&difference
, ray_direction
);
2412 return d
>= 0.0f
&& (b
<= 0.0f
|| d
> b
* b
);
2415 /*************************************************************************
2418 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2419 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2423 IDirect3DVertexDeclaration9
*vertex_declaration
;
2424 UINT vertex_declaration_size
;
2426 IDirect3DVertexBuffer9
*vertex_buffer
;
2427 IDirect3DIndexBuffer9
*index_buffer
;
2428 DWORD
*attrib_buffer
;
2429 struct d3dx9_mesh
*object
;
2430 DWORD index_usage
= 0;
2431 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
2432 D3DFORMAT index_format
= D3DFMT_INDEX16
;
2433 DWORD vertex_usage
= 0;
2434 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
2437 TRACE("numfaces %lu, numvertices %lu, options %#lx, declaration %p, device %p, mesh %p.\n",
2438 numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2440 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
2441 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
2442 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
2444 return D3DERR_INVALIDCALL
;
2446 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
2447 if (declaration
[i
].Stream
!= 0)
2448 return D3DERR_INVALIDCALL
;
2451 if (options
& D3DXMESH_32BIT
)
2452 index_format
= D3DFMT_INDEX32
;
2454 if (options
& D3DXMESH_DONOTCLIP
) {
2455 index_usage
|= D3DUSAGE_DONOTCLIP
;
2456 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
2458 if (options
& D3DXMESH_POINTS
) {
2459 index_usage
|= D3DUSAGE_POINTS
;
2460 vertex_usage
|= D3DUSAGE_POINTS
;
2462 if (options
& D3DXMESH_RTPATCHES
) {
2463 index_usage
|= D3DUSAGE_RTPATCHES
;
2464 vertex_usage
|= D3DUSAGE_RTPATCHES
;
2466 if (options
& D3DXMESH_NPATCHES
) {
2467 index_usage
|= D3DUSAGE_NPATCHES
;
2468 vertex_usage
|= D3DUSAGE_NPATCHES
;
2471 if (options
& D3DXMESH_VB_SYSTEMMEM
)
2472 vertex_pool
= D3DPOOL_SYSTEMMEM
;
2473 else if (options
& D3DXMESH_VB_MANAGED
)
2474 vertex_pool
= D3DPOOL_MANAGED
;
2476 if (options
& D3DXMESH_VB_WRITEONLY
)
2477 vertex_usage
|= D3DUSAGE_WRITEONLY
;
2478 if (options
& D3DXMESH_VB_DYNAMIC
)
2479 vertex_usage
|= D3DUSAGE_DYNAMIC
;
2480 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
2481 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2483 if (options
& D3DXMESH_IB_SYSTEMMEM
)
2484 index_pool
= D3DPOOL_SYSTEMMEM
;
2485 else if (options
& D3DXMESH_IB_MANAGED
)
2486 index_pool
= D3DPOOL_MANAGED
;
2488 if (options
& D3DXMESH_IB_WRITEONLY
)
2489 index_usage
|= D3DUSAGE_WRITEONLY
;
2490 if (options
& D3DXMESH_IB_DYNAMIC
)
2491 index_usage
|= D3DUSAGE_DYNAMIC
;
2492 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
2493 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2495 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
2501 if (FAILED(hr
= IDirect3DDevice9_CreateVertexDeclaration(device
, declaration
, &vertex_declaration
)))
2503 WARN("Failed to create vertex declaration, hr %#lx.\n", hr
);
2506 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
2508 if (FAILED(hr
= IDirect3DDevice9_CreateVertexBuffer(device
, numvertices
* vertex_declaration_size
,
2509 vertex_usage
, fvf
, vertex_pool
, &vertex_buffer
, NULL
)))
2511 WARN("Failed to create vertex buffer, hr %#lx.\n", hr
);
2512 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2516 if (FAILED(hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
2517 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4), index_usage
, index_format
,
2518 index_pool
, &index_buffer
, NULL
)))
2520 WARN("Failed to create index buffer, hr %#lx.\n", hr
);
2521 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2522 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2526 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
2527 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2528 if (object
== NULL
|| attrib_buffer
== NULL
)
2530 HeapFree(GetProcessHeap(), 0, object
);
2531 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
2532 IDirect3DIndexBuffer9_Release(index_buffer
);
2533 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2534 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2536 return E_OUTOFMEMORY
;
2538 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
2541 object
->numfaces
= numfaces
;
2542 object
->numvertices
= numvertices
;
2543 object
->options
= options
;
2545 object
->device
= device
;
2546 IDirect3DDevice9_AddRef(device
);
2548 copy_declaration(object
->cached_declaration
, declaration
, num_elem
);
2549 object
->vertex_declaration
= vertex_declaration
;
2550 object
->vertex_declaration_size
= vertex_declaration_size
;
2551 object
->num_elem
= num_elem
;
2552 object
->vertex_buffer
= vertex_buffer
;
2553 object
->index_buffer
= index_buffer
;
2554 object
->attrib_buffer
= attrib_buffer
;
2556 *mesh
= &object
->ID3DXMesh_iface
;
2561 /*************************************************************************
2564 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD face_count
, DWORD vertex_count
, DWORD options
,
2565 DWORD fvf
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2568 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
2570 TRACE("face_count %lu, vertex_count %lu, options %#lx, fvf %#lx, device %p, mesh %p.\n",
2571 face_count
, vertex_count
, options
, fvf
, device
, mesh
);
2573 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
2574 if (FAILED(hr
)) return hr
;
2576 return D3DXCreateMesh(face_count
, vertex_count
, options
, declaration
, device
, mesh
);
2581 unsigned int num_vertices
;
2582 unsigned int num_poly_faces
;
2583 unsigned int num_tri_faces
;
2584 D3DXVECTOR3
*vertices
;
2585 unsigned int *num_tri_per_face
;
2590 /* optional mesh data */
2592 unsigned int num_normals
;
2593 D3DXVECTOR3
*normals
;
2594 DWORD
*normal_indices
;
2596 D3DXVECTOR2
*tex_coords
;
2598 DWORD
*vertex_colors
;
2600 unsigned int num_materials
;
2601 D3DXMATERIAL
*materials
;
2602 DWORD
*material_indices
;
2604 struct ID3DXSkinInfo
*skin_info
;
2605 unsigned int bone_count
;
2608 static HRESULT
parse_texture_filename(ID3DXFileData
*filedata
, char **filename_out
)
2614 char *filename
= NULL
;
2616 /* template TextureFilename {
2621 HeapFree(GetProcessHeap(), 0, *filename_out
);
2622 *filename_out
= NULL
;
2624 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2625 if (FAILED(hr
)) return hr
;
2627 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
2628 if (data_size
< sizeof(filename_in
))
2630 WARN("Truncated data (%Iu bytes).\n", data_size
);
2631 filedata
->lpVtbl
->Unlock(filedata
);
2634 filename_in
= *(char **)data
;
2636 filename
= HeapAlloc(GetProcessHeap(), 0, strlen(filename_in
) + 1);
2638 filedata
->lpVtbl
->Unlock(filedata
);
2639 return E_OUTOFMEMORY
;
2642 strcpy(filename
, filename_in
);
2643 *filename_out
= filename
;
2645 filedata
->lpVtbl
->Unlock(filedata
);
2650 static HRESULT
parse_material(ID3DXFileData
*filedata
, D3DXMATERIAL
*material
)
2656 ID3DXFileData
*child
;
2657 SIZE_T i
, nb_children
;
2659 material
->pTextureFilename
= NULL
;
2661 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2662 if (FAILED(hr
)) return hr
;
2665 * template ColorRGBA {
2671 * template ColorRGB {
2676 * template Material {
2677 * ColorRGBA faceColor;
2679 * ColorRGB specularColor;
2680 * ColorRGB emissiveColor;
2684 if (data_size
!= sizeof(float) * 11)
2686 WARN("Incorrect data size (%Id bytes).\n", data_size
);
2687 filedata
->lpVtbl
->Unlock(filedata
);
2691 memcpy(&material
->MatD3D
.Diffuse
, data
, sizeof(D3DCOLORVALUE
));
2692 data
+= sizeof(D3DCOLORVALUE
);
2693 material
->MatD3D
.Power
= *(FLOAT
*)data
;
2694 data
+= sizeof(FLOAT
);
2695 memcpy(&material
->MatD3D
.Specular
, data
, sizeof(FLOAT
) * 3);
2696 material
->MatD3D
.Specular
.a
= 1.0f
;
2697 data
+= 3 * sizeof(FLOAT
);
2698 memcpy(&material
->MatD3D
.Emissive
, data
, sizeof(FLOAT
) * 3);
2699 material
->MatD3D
.Emissive
.a
= 1.0f
;
2700 material
->MatD3D
.Ambient
.r
= 0.0f
;
2701 material
->MatD3D
.Ambient
.g
= 0.0f
;
2702 material
->MatD3D
.Ambient
.b
= 0.0f
;
2703 material
->MatD3D
.Ambient
.a
= 1.0f
;
2705 filedata
->lpVtbl
->Unlock(filedata
);
2707 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2711 for (i
= 0; i
< nb_children
; i
++)
2713 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2716 hr
= child
->lpVtbl
->GetType(child
, &type
);
2720 if (IsEqualGUID(&type
, &TID_D3DRMTextureFilename
)) {
2721 hr
= parse_texture_filename(child
, &material
->pTextureFilename
);
2725 IUnknown_Release(child
);
2730 IUnknown_Release(child
);
2734 static void destroy_materials(struct mesh_data
*mesh
)
2738 for (i
= 0; i
< mesh
->num_materials
; ++i
)
2739 HeapFree(GetProcessHeap(), 0, mesh
->materials
[i
].pTextureFilename
);
2740 HeapFree(GetProcessHeap(), 0, mesh
->materials
);
2741 HeapFree(GetProcessHeap(), 0, mesh
->material_indices
);
2742 mesh
->num_materials
= 0;
2743 mesh
->materials
= NULL
;
2744 mesh
->material_indices
= NULL
;
2747 static HRESULT
parse_material_list(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2749 ID3DXFileData
*child
= NULL
;
2750 unsigned int material_count
;
2751 const uint32_t *in_ptr
;
2759 destroy_materials(mesh
);
2761 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, &data
);
2762 if (FAILED(hr
)) return hr
;
2764 /* template MeshMaterialList {
2766 * DWORD nFaceIndexes;
2767 * array DWORD faceIndexes[nFaceIndexes];
2775 if (data_size
< sizeof(uint32_t))
2777 WARN("Truncated data (%Id bytes).\n", data_size
);
2780 material_count
= *in_ptr
++;
2781 if (!material_count
) {
2786 if (data_size
< 2 * sizeof(uint32_t))
2788 WARN("Truncated data (%Id bytes).\n", data_size
);
2791 if (*in_ptr
++ != mesh
->num_poly_faces
)
2793 WARN("Number of material face indices (%u) doesn't match number of faces (%u).\n",
2794 *(in_ptr
- 1), mesh
->num_poly_faces
);
2797 if (data_size
< 2 * sizeof(uint32_t) + mesh
->num_poly_faces
* sizeof(uint32_t))
2799 WARN("Truncated data (%Id bytes).\n", data_size
);
2802 for (i
= 0; i
< mesh
->num_poly_faces
; ++i
)
2804 if (*in_ptr
++ >= material_count
)
2806 WARN("Face %u: reference to undefined material %u (only %u materials).\n",
2807 i
, *(in_ptr
- 1), material_count
);
2812 mesh
->materials
= HeapAlloc(GetProcessHeap(), 0, material_count
* sizeof(*mesh
->materials
));
2813 mesh
->material_indices
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_poly_faces
* sizeof(*mesh
->material_indices
));
2814 if (!mesh
->materials
|| !mesh
->material_indices
) {
2818 memcpy(mesh
->material_indices
, (const uint32_t *)data
+ 2, mesh
->num_poly_faces
* sizeof(uint32_t));
2820 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2824 for (i
= 0; i
< nb_children
; i
++)
2826 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2829 hr
= child
->lpVtbl
->GetType(child
, &type
);
2833 if (IsEqualGUID(&type
, &TID_D3DRMMaterial
))
2835 if (mesh
->num_materials
>= material_count
)
2837 WARN("%u materials defined, only %u declared.\n", mesh
->num_materials
, material_count
);
2841 hr
= parse_material(child
, &mesh
->materials
[mesh
->num_materials
++]);
2846 IUnknown_Release(child
);
2849 if (material_count
!= mesh
->num_materials
)
2851 WARN("Only %u of %u materials defined.\n", material_count
, mesh
->num_materials
);
2857 IUnknown_Release(child
);
2858 filedata
->lpVtbl
->Unlock(filedata
);
2862 static HRESULT
parse_texture_coords(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2864 const uint32_t *data
;
2868 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2869 mesh
->tex_coords
= NULL
;
2871 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void **)&data
);
2872 if (FAILED(hr
)) return hr
;
2874 /* template Coords2d {
2878 * template MeshTextureCoords {
2879 * DWORD nTextureCoords;
2880 * array Coords2d textureCoords[nTextureCoords];
2886 if (data_size
< sizeof(uint32_t))
2888 WARN("Truncated data (%Id bytes).\n", data_size
);
2891 if (*data
!= mesh
->num_vertices
)
2893 WARN("Number of texture coordinates (%u) doesn't match number of vertices (%u).\n",
2894 *data
, mesh
->num_vertices
);
2898 if (data_size
< sizeof(uint32_t) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
))
2900 WARN("Truncated data (%Id bytes).\n", data_size
);
2904 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2905 if (!mesh
->tex_coords
) {
2909 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2911 mesh
->fvf
|= D3DFVF_TEX1
;
2916 filedata
->lpVtbl
->Unlock(filedata
);
2920 static HRESULT
parse_vertex_colors(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2922 unsigned int color_count
, i
;
2923 const uint32_t *data
;
2927 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2928 mesh
->vertex_colors
= NULL
;
2930 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void **)&data
);
2931 if (FAILED(hr
)) return hr
;
2933 /* template IndexedColor {
2935 * ColorRGBA indexColor;
2937 * template MeshVertexColors {
2938 * DWORD nVertexColors;
2939 * array IndexedColor vertexColors[nVertexColors];
2945 if (data_size
< sizeof(uint32_t))
2947 WARN("Truncated data (%Id bytes).\n", data_size
);
2950 color_count
= *data
;
2952 if (data_size
< sizeof(uint32_t) + color_count
* (sizeof(uint32_t) + sizeof(D3DCOLORVALUE
)))
2954 WARN("Truncated data (%Id bytes).\n", data_size
);
2958 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(uint32_t));
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
< color_count
; ++i
)
2968 D3DCOLORVALUE color
;
2969 unsigned int index
= *data
;
2972 if (index
>= mesh
->num_vertices
)
2974 WARN("Vertex color %u references undefined vertex %u (only %u vertices).\n",
2975 i
, index
, mesh
->num_vertices
);
2978 memcpy(&color
, data
, sizeof(color
));
2979 data
+= sizeof(color
) / sizeof(*data
);
2980 color
.r
= min(1.0f
, max(0.0f
, color
.r
));
2981 color
.g
= min(1.0f
, max(0.0f
, color
.g
));
2982 color
.b
= min(1.0f
, max(0.0f
, color
.b
));
2983 color
.a
= min(1.0f
, max(0.0f
, color
.a
));
2984 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
2985 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
2986 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
2987 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
2990 mesh
->fvf
|= D3DFVF_DIFFUSE
;
2995 filedata
->lpVtbl
->Unlock(filedata
);
2999 static HRESULT
parse_normals(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
3001 unsigned int num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
3002 DWORD
*index_out_ptr
;
3008 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
3009 mesh
->num_normals
= 0;
3010 mesh
->normals
= NULL
;
3011 mesh
->normal_indices
= NULL
;
3012 mesh
->fvf
|= D3DFVF_NORMAL
;
3014 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void **)&data
);
3015 if (FAILED(hr
)) return hr
;
3017 /* template Vector {
3022 * template MeshFace {
3023 * DWORD nFaceVertexIndices;
3024 * array DWORD faceVertexIndices[nFaceVertexIndices];
3026 * template MeshNormals {
3028 * array Vector normals[nNormals];
3029 * DWORD nFaceNormals;
3030 * array MeshFace faceNormals[nFaceNormals];
3036 if (data_size
< sizeof(uint32_t) * 2)
3038 WARN("Truncated data (%Id bytes).\n", data_size
);
3041 mesh
->num_normals
= *(uint32_t *)data
;
3042 data
+= sizeof(uint32_t);
3043 if (data_size
< sizeof(uint32_t) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
3044 num_face_indices
* sizeof(uint32_t))
3046 WARN("Truncated data (%Id bytes).\n", data_size
);
3050 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3051 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(uint32_t));
3052 if (!mesh
->normals
|| !mesh
->normal_indices
) {
3057 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3058 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
3059 for (i
= 0; i
< mesh
->num_normals
; i
++)
3060 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
3062 if (*(uint32_t *)data
!= mesh
->num_poly_faces
)
3064 WARN("Number of face normals (%u) doesn't match number of faces (%u).\n",
3065 *(uint32_t *)data
, mesh
->num_poly_faces
);
3068 data
+= sizeof(uint32_t);
3069 index_out_ptr
= mesh
->normal_indices
;
3070 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
3072 unsigned int count
= *(uint32_t *)data
;
3075 if (count
!= mesh
->num_tri_per_face
[i
] + 2)
3077 WARN("Face %u: number of normals (%u) doesn't match number of vertices (%u).\n",
3078 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
3081 data
+= sizeof(uint32_t);
3083 for (j
= 0; j
< count
; j
++)
3085 uint32_t normal_index
= *(uint32_t *)data
;
3087 if (normal_index
>= mesh
->num_normals
)
3089 WARN("Face %u, normal index %u: reference to undefined normal %u (only %u normals).\n",
3090 i
, j
, normal_index
, mesh
->num_normals
);
3093 *index_out_ptr
++ = normal_index
;
3094 data
+= sizeof(uint32_t);
3101 filedata
->lpVtbl
->Unlock(filedata
);
3105 static HRESULT
parse_skin_mesh_header(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
)
3111 TRACE("filedata %p, mesh_data %p.\n", filedata
, mesh_data
);
3113 if (FAILED(hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void **)&data
)))
3116 if (data_size
< sizeof(WORD
) * 3)
3118 WARN("Truncated data (%Id bytes).\n", data_size
);
3119 filedata
->lpVtbl
->Unlock(filedata
);
3122 /* Skip nMaxSkinWeightsPerVertex and nMaxSkinWeightsPerFace */
3123 data
+= 2 * sizeof(WORD
);
3124 mesh_data
->bone_count
= *(WORD
*)data
;
3125 hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
, mesh_data
->bone_count
,
3126 &mesh_data
->skin_info
);
3131 static HRESULT
parse_skin_weights_info(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, unsigned int index
)
3133 unsigned int influence_count
;
3139 TRACE("filedata %p, mesh_data %p, index %u.\n", filedata
, mesh_data
, index
);
3141 if (FAILED(hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void **)&data
)))
3144 /* FIXME: String will have to be retrieved directly instead of through a
3145 * pointer once our ID3DXFileData implementation is fixed. */
3146 name
= *(const char **)data
;
3147 data
+= sizeof(char *);
3149 influence_count
= *(uint32_t *)data
;
3150 data
+= sizeof(uint32_t);
3152 if (data_size
< (sizeof(char *) + sizeof(uint32_t) + influence_count
* (sizeof(uint32_t) + sizeof(float))
3153 + 16 * sizeof(float)))
3155 WARN("Truncated data (%Id bytes).\n", data_size
);
3156 filedata
->lpVtbl
->Unlock(filedata
);
3160 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneName(mesh_data
->skin_info
, index
, name
);
3162 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneInfluence(mesh_data
->skin_info
, index
, influence_count
,
3163 (const DWORD
*)data
, (const float *)(data
+ influence_count
* sizeof(uint32_t)));
3165 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneOffsetMatrix(mesh_data
->skin_info
, index
,
3166 (const D3DMATRIX
*)(data
+ influence_count
* (sizeof(uint32_t) + sizeof(float))));
3171 /* for provide_flags parameters */
3172 #define PROVIDE_MATERIALS 0x1
3173 #define PROVIDE_SKININFO 0x2
3174 #define PROVIDE_ADJACENCY 0x4
3176 static HRESULT
parse_mesh(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
3178 unsigned int skin_weights_info_count
= 0;
3179 ID3DXFileData
*child
= NULL
;
3180 const BYTE
*data
, *in_ptr
;
3181 DWORD
*index_out_ptr
;
3191 * array Vector vertices[nVertices];
3193 * array MeshFace faces[nFaces];
3198 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void **)&data
);
3199 if (FAILED(hr
)) return hr
;
3204 if (data_size
< sizeof(uint32_t) * 2)
3206 WARN("Truncated data (%Id bytes).\n", data_size
);
3209 mesh_data
->num_vertices
= *(uint32_t *)in_ptr
;
3210 if (data_size
< sizeof(uint32_t) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
))
3212 WARN("Truncated data (%Id bytes).\n", data_size
);
3215 in_ptr
+= sizeof(uint32_t) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
3217 mesh_data
->num_poly_faces
= *(uint32_t *)in_ptr
;
3218 in_ptr
+= sizeof(uint32_t);
3220 mesh_data
->num_tri_faces
= 0;
3221 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3223 unsigned int poly_vertices_count
;
3226 if (data_size
- (in_ptr
- data
) < sizeof(uint32_t))
3228 WARN("Truncated data (%Id bytes).\n", data_size
);
3231 poly_vertices_count
= *(uint32_t *)in_ptr
;
3232 in_ptr
+= sizeof(uint32_t);
3233 if (data_size
- (in_ptr
- data
) < poly_vertices_count
* sizeof(uint32_t))
3235 WARN("Truncated data (%Id bytes).\n", data_size
);
3238 if (poly_vertices_count
< 3)
3240 WARN("Face %u has only %u vertices.\n", i
, poly_vertices_count
);
3243 for (j
= 0; j
< poly_vertices_count
; j
++)
3245 if (*(uint32_t *)in_ptr
>= mesh_data
->num_vertices
)
3247 WARN("Face %u, index %u: undefined vertex %u (only %u vertices).\n",
3248 i
, j
, *(uint32_t *)in_ptr
, mesh_data
->num_vertices
);
3251 in_ptr
+= sizeof(uint32_t);
3253 mesh_data
->num_tri_faces
+= poly_vertices_count
- 2;
3256 mesh_data
->fvf
= D3DFVF_XYZ
;
3258 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
3259 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
3260 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
3261 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
3262 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
3263 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
3264 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
) {
3269 in_ptr
= data
+ sizeof(uint32_t);
3270 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
3271 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(uint32_t);
3273 index_out_ptr
= mesh_data
->indices
;
3274 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3278 count
= *(uint32_t *)in_ptr
;
3279 in_ptr
+= sizeof(uint32_t);
3280 mesh_data
->num_tri_per_face
[i
] = count
- 2;
3284 *index_out_ptr
++ = *(uint32_t *)in_ptr
;
3285 in_ptr
+= sizeof(uint32_t);
3289 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &child_count
);
3293 for (i
= 0; i
< child_count
; i
++)
3295 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3298 hr
= child
->lpVtbl
->GetType(child
, &type
);
3302 if (IsEqualGUID(&type
, &TID_D3DRMMeshNormals
)) {
3303 hr
= parse_normals(child
, mesh_data
);
3304 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshVertexColors
)) {
3305 hr
= parse_vertex_colors(child
, mesh_data
);
3306 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshTextureCoords
)) {
3307 hr
= parse_texture_coords(child
, mesh_data
);
3308 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshMaterialList
) &&
3309 (provide_flags
& PROVIDE_MATERIALS
))
3311 hr
= parse_material_list(child
, mesh_data
);
3312 } else if (provide_flags
& PROVIDE_SKININFO
) {
3313 if (IsEqualGUID(&type
, &DXFILEOBJ_XSkinMeshHeader
)) {
3314 if (mesh_data
->skin_info
) {
3315 WARN("Skin mesh header already encountered\n");
3319 hr
= parse_skin_mesh_header(child
, mesh_data
);
3322 } else if (IsEqualGUID(&type
, &DXFILEOBJ_SkinWeights
)) {
3323 if (!mesh_data
->skin_info
) {
3324 WARN("Skin weights found but skin mesh header not encountered yet\n");
3328 hr
= parse_skin_weights_info(child
, mesh_data
, skin_weights_info_count
);
3331 skin_weights_info_count
++;
3337 IUnknown_Release(child
);
3341 if (mesh_data
->skin_info
&& (skin_weights_info_count
!= mesh_data
->bone_count
))
3343 WARN("Mismatch between skin weights info count %u and bones count %u from skin mesh header.\n",
3344 skin_weights_info_count
, mesh_data
->bone_count
);
3349 if ((provide_flags
& PROVIDE_SKININFO
) && !mesh_data
->skin_info
)
3351 if (FAILED(hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
,
3352 mesh_data
->bone_count
, &mesh_data
->skin_info
)))
3360 IUnknown_Release(child
);
3361 filedata
->lpVtbl
->Unlock(filedata
);
3365 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
3366 ID3DXBuffer
**effects
)
3369 D3DXEFFECTINSTANCE
*effect_ptr
;
3371 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3372 static const struct {
3373 const char *param_name
;
3377 } material_effects
[] = {
3378 #define EFFECT_TABLE_ENTRY(str, field) \
3379 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
3380 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
3381 EFFECT_TABLE_ENTRY("Power", Power
),
3382 EFFECT_TABLE_ENTRY("Specular", Specular
),
3383 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
3384 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
3385 #undef EFFECT_TABLE_ENTRY
3387 static const char texture_paramname
[] = "Texture0@Name";
3391 /* effects buffer layout:
3393 * D3DXEFFECTINSTANCE effects[num_materials];
3394 * for (effect in effects)
3396 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
3397 * for (default in defaults)
3399 * *default.pParamName;
3404 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
3405 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
3406 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
3407 buffer_size
+= material_effects
[i
].name_size
;
3408 buffer_size
+= material_effects
[i
].num_bytes
;
3410 buffer_size
*= num_materials
;
3411 for (i
= 0; i
< num_materials
; i
++) {
3412 if (material_ptr
[i
].pTextureFilename
) {
3413 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
3414 buffer_size
+= sizeof(texture_paramname
);
3415 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
3419 hr
= D3DXCreateBuffer(buffer_size
, effects
);
3420 if (FAILED(hr
)) return hr
;
3421 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
3422 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
3424 for (i
= 0; i
< num_materials
; i
++)
3427 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
3429 effect_ptr
->pDefaults
= defaults
;
3430 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
3431 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
3433 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
3435 defaults
->pParamName
= (char *)out_ptr
;
3436 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
3437 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
3438 defaults
->Type
= D3DXEDT_FLOATS
;
3439 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
3440 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
3441 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3445 if (material_ptr
->pTextureFilename
)
3447 defaults
->pParamName
= (char *)out_ptr
;
3448 strcpy(defaults
->pParamName
, texture_paramname
);
3449 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
3450 defaults
->Type
= D3DXEDT_STRING
;
3451 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
3452 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
3453 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3458 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
3463 HRESULT WINAPI
D3DXLoadSkinMeshFromXof(struct ID3DXFileData
*filedata
, DWORD options
,
3464 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
3465 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXSkinInfo
**skin_info_out
,
3466 struct ID3DXMesh
**mesh_out
)
3469 DWORD
*index_in_ptr
;
3470 struct mesh_data mesh_data
;
3471 DWORD total_vertices
;
3472 ID3DXMesh
*d3dxmesh
= NULL
;
3473 ID3DXBuffer
*adjacency
= NULL
;
3474 ID3DXBuffer
*materials
= NULL
;
3475 ID3DXBuffer
*effects
= NULL
;
3476 struct vertex_duplication
{
3479 } *duplications
= NULL
;
3481 void *vertices
= NULL
;
3482 void *indices
= NULL
;
3484 DWORD provide_flags
= 0;
3486 TRACE("filedata %p, options %#lx, device %p, adjacency_out %p, materials_out %p, "
3487 "effects_out %p, num_materials_out %p, skin_info_out %p, mesh_out %p.\n",
3488 filedata
, options
, device
, adjacency_out
, materials_out
,
3489 effects_out
, num_materials_out
, skin_info_out
, mesh_out
);
3491 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
3493 if (num_materials_out
|| materials_out
|| effects_out
)
3494 provide_flags
|= PROVIDE_MATERIALS
;
3496 provide_flags
|= PROVIDE_SKININFO
;
3498 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
3499 if (FAILED(hr
)) goto cleanup
;
3501 total_vertices
= mesh_data
.num_vertices
;
3502 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3503 /* duplicate vertices with multiple normals */
3504 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
3505 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
3506 if (!duplications
) {
3510 for (i
= 0; i
< total_vertices
; i
++)
3512 duplications
[i
].normal_index
= -1;
3513 list_init(&duplications
[i
].entry
);
3515 for (i
= 0; i
< num_face_indices
; i
++) {
3516 DWORD vertex_index
= mesh_data
.indices
[i
];
3517 DWORD normal_index
= mesh_data
.normal_indices
[i
];
3518 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
3520 if (dup_ptr
->normal_index
== -1) {
3521 dup_ptr
->normal_index
= normal_index
;
3523 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
3524 struct list
*dup_list
= &dup_ptr
->entry
;
3526 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
3527 if (new_normal
->x
== cur_normal
->x
&&
3528 new_normal
->y
== cur_normal
->y
&&
3529 new_normal
->z
== cur_normal
->z
)
3531 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3533 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
3534 dup_ptr
= &duplications
[total_vertices
++];
3535 dup_ptr
->normal_index
= normal_index
;
3536 list_add_tail(dup_list
, &dup_ptr
->entry
);
3537 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3540 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
3541 struct vertex_duplication
, entry
);
3548 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
3549 if (FAILED(hr
)) goto cleanup
;
3551 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, 0, &vertices
);
3552 if (FAILED(hr
)) goto cleanup
;
3555 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3556 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
3557 out_ptr
+= sizeof(D3DXVECTOR3
);
3558 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3559 if (duplications
[i
].normal_index
== -1)
3560 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
3562 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
3563 out_ptr
+= sizeof(D3DXVECTOR3
);
3565 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
3566 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
3567 out_ptr
+= sizeof(DWORD
);
3569 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
3570 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
3571 out_ptr
+= sizeof(D3DXVECTOR2
);
3574 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3575 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
3577 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3578 struct vertex_duplication
*dup_ptr
;
3579 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
3581 int j
= dup_ptr
- duplications
;
3582 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
3584 memcpy(dest_vertex
, out_ptr
, vertex_size
);
3585 dest_vertex
+= sizeof(D3DXVECTOR3
);
3586 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
3588 out_ptr
+= vertex_size
;
3591 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
3593 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, 0, &indices
);
3594 if (FAILED(hr
)) goto cleanup
;
3596 index_in_ptr
= mesh_data
.indices
;
3597 #define FILL_INDEX_BUFFER(indices_var) \
3598 for (i = 0; i < mesh_data.num_poly_faces; i++) \
3600 DWORD count = mesh_data.num_tri_per_face[i]; \
3601 WORD first_index = *index_in_ptr++; \
3603 *indices_var++ = first_index; \
3604 *indices_var++ = *index_in_ptr; \
3606 *indices_var++ = *index_in_ptr; \
3610 if (options
& D3DXMESH_32BIT
) {
3611 DWORD
*dword_indices
= indices
;
3612 FILL_INDEX_BUFFER(dword_indices
)
3614 WORD
*word_indices
= indices
;
3615 FILL_INDEX_BUFFER(word_indices
)
3617 #undef FILL_INDEX_BUFFER
3618 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
3620 if (mesh_data
.material_indices
) {
3621 DWORD
*attrib_buffer
= NULL
;
3622 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, 0, &attrib_buffer
);
3623 if (FAILED(hr
)) goto cleanup
;
3624 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
3626 DWORD count
= mesh_data
.num_tri_per_face
[i
];
3628 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
3630 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
3632 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
3633 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
3634 NULL
, NULL
, NULL
, NULL
);
3635 if (FAILED(hr
)) goto cleanup
;
3638 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
3639 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
3640 char *strings_out_ptr
;
3641 D3DXMATERIAL
*materials_ptr
;
3643 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3644 if (mesh_data
.materials
[i
].pTextureFilename
)
3645 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3648 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3649 if (FAILED(hr
)) goto cleanup
;
3651 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3652 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
3653 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
3654 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3655 if (materials_ptr
[i
].pTextureFilename
) {
3656 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
3657 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
3658 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3663 if (mesh_data
.num_materials
&& effects_out
) {
3664 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
3665 if (FAILED(hr
)) goto cleanup
;
3667 if (!materials_out
) {
3668 ID3DXBuffer_Release(materials
);
3673 if (adjacency_out
) {
3674 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
3675 if (FAILED(hr
)) goto cleanup
;
3676 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
3677 if (FAILED(hr
)) goto cleanup
;
3680 *mesh_out
= d3dxmesh
;
3681 if (adjacency_out
) *adjacency_out
= adjacency
;
3682 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
3683 if (materials_out
) *materials_out
= materials
;
3684 if (effects_out
) *effects_out
= effects
;
3685 if (skin_info_out
) *skin_info_out
= mesh_data
.skin_info
;
3690 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
3691 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3692 if (materials
) ID3DXBuffer_Release(materials
);
3693 if (effects
) ID3DXBuffer_Release(effects
);
3694 if (mesh_data
.skin_info
) mesh_data
.skin_info
->lpVtbl
->Release(mesh_data
.skin_info
);
3695 if (skin_info_out
) *skin_info_out
= NULL
;
3697 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
3698 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
3699 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
3700 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
3701 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
3702 destroy_materials(&mesh_data
);
3703 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
3704 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
3705 HeapFree(GetProcessHeap(), 0, duplications
);
3709 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3710 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3711 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3717 TRACE("filename %s, options %#lx, device %p, alloc_hier %p, "
3718 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3719 debugstr_a(filename
), options
, device
, alloc_hier
,
3720 load_user_data
, frame_hierarchy
, anim_controller
);
3723 return D3DERR_INVALIDCALL
;
3725 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3726 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3727 if (!filenameW
) return E_OUTOFMEMORY
;
3728 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3730 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
3731 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3732 HeapFree(GetProcessHeap(), 0, filenameW
);
3737 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3738 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3739 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3745 TRACE("filename %s, options %#lx, device %p, alloc_hier %p, "
3746 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3747 debugstr_w(filename
), options
, device
, alloc_hier
,
3748 load_user_data
, frame_hierarchy
, anim_controller
);
3751 return D3DERR_INVALIDCALL
;
3753 hr
= map_view_of_file(filename
, &buffer
, &size
);
3755 return D3DXERR_INVALIDDATA
;
3757 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
3758 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3760 UnmapViewOfFile(buffer
);
3765 static HRESULT
filedata_get_name(ID3DXFileData
*filedata
, char **name
)
3770 hr
= filedata
->lpVtbl
->GetName(filedata
, NULL
, &name_len
);
3771 if (FAILED(hr
)) return hr
;
3775 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
3776 if (!*name
) return E_OUTOFMEMORY
;
3778 hr
= filedata
->lpVtbl
->GetName(filedata
, *name
, &name_len
);
3780 HeapFree(GetProcessHeap(), 0, *name
);
3787 static HRESULT
load_mesh_container(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3788 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXMESHCONTAINER
**mesh_container
)
3791 ID3DXBuffer
*adjacency
= NULL
;
3792 ID3DXBuffer
*materials
= NULL
;
3793 ID3DXBuffer
*effects
= NULL
;
3794 ID3DXSkinInfo
*skin_info
= NULL
;
3795 D3DXMESHDATA mesh_data
;
3796 DWORD num_materials
= 0;
3799 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
3800 mesh_data
.pMesh
= NULL
;
3802 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
3803 &adjacency
, &materials
, &effects
, &num_materials
,
3804 &skin_info
, &mesh_data
.pMesh
);
3805 if (FAILED(hr
)) return hr
;
3807 hr
= filedata_get_name(filedata
, &name
);
3808 if (FAILED(hr
)) goto cleanup
;
3810 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
3811 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
3812 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
3814 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
3815 skin_info
, mesh_container
);
3818 if (materials
) ID3DXBuffer_Release(materials
);
3819 if (effects
) ID3DXBuffer_Release(effects
);
3820 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3821 if (skin_info
) IUnknown_Release(skin_info
);
3822 if (mesh_data
.pMesh
) IUnknown_Release(mesh_data
.pMesh
);
3823 HeapFree(GetProcessHeap(), 0, name
);
3827 static HRESULT
parse_transform_matrix(ID3DXFileData
*filedata
, D3DXMATRIX
*transform
)
3833 /* template Matrix4x4 {
3834 * array FLOAT matrix[16];
3836 * template FrameTransformMatrix {
3837 * Matrix4x4 frameMatrix;
3841 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void **)&data
);
3845 if (data_size
!= sizeof(D3DXMATRIX
))
3847 WARN("Incorrect data size (%Id bytes).\n", data_size
);
3848 filedata
->lpVtbl
->Unlock(filedata
);
3852 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
3854 filedata
->lpVtbl
->Unlock(filedata
);
3858 static HRESULT
load_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3859 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXFRAME
**frame_out
)
3863 ID3DXFileData
*child
;
3865 D3DXFRAME
*frame
= NULL
;
3866 D3DXMESHCONTAINER
**next_container
;
3867 D3DXFRAME
**next_child
;
3868 SIZE_T i
, nb_children
;
3870 hr
= filedata_get_name(filedata
, &name
);
3871 if (FAILED(hr
)) return hr
;
3873 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
3874 HeapFree(GetProcessHeap(), 0, name
);
3875 if (FAILED(hr
)) return E_FAIL
;
3878 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
3879 next_child
= &frame
->pFrameFirstChild
;
3880 next_container
= &frame
->pMeshContainer
;
3882 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3886 for (i
= 0; i
< nb_children
; i
++)
3888 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3891 hr
= child
->lpVtbl
->GetType(child
, &type
);
3895 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
3896 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
3898 next_container
= &(*next_container
)->pNextMeshContainer
;
3899 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
3900 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
3901 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
3902 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
3904 next_child
= &(*next_child
)->pFrameSibling
;
3909 IUnknown_Release(child
);
3914 IUnknown_Release(child
);
3918 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
3919 struct IDirect3DDevice9
*device
, struct ID3DXAllocateHierarchy
*alloc_hier
,
3920 struct ID3DXLoadUserData
*load_user_data
, D3DXFRAME
**frame_hierarchy
,
3921 struct ID3DXAnimationController
**anim_controller
)
3924 ID3DXFile
*d3dxfile
= NULL
;
3925 ID3DXFileEnumObject
*enumobj
= NULL
;
3926 ID3DXFileData
*filedata
= NULL
;
3927 D3DXF_FILELOADMEMORY source
;
3928 D3DXFRAME
*first_frame
= NULL
;
3929 D3DXFRAME
**next_frame
= &first_frame
;
3930 SIZE_T i
, nb_children
;
3933 TRACE("memory %p, memory_size %lu, options %#lx, device %p, alloc_hier %p, load_user_data %p, "
3934 "frame_hierarchy %p, anim_controller %p.\n", memory
, memory_size
, options
,
3935 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3937 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
3938 return D3DERR_INVALIDCALL
;
3941 FIXME("Loading user data not implemented.\n");
3945 hr
= D3DXFileCreate(&d3dxfile
);
3946 if (FAILED(hr
)) goto cleanup
;
3948 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3949 if (FAILED(hr
)) goto cleanup
;
3951 source
.lpMemory
= (void*)memory
;
3952 source
.dSize
= memory_size
;
3953 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
3954 if (FAILED(hr
)) goto cleanup
;
3956 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
3960 for (i
= 0; i
< nb_children
; i
++)
3962 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
3966 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
3967 if (SUCCEEDED(hr
)) {
3968 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
3969 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
3975 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
3977 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
3978 if (FAILED(hr
)) goto cleanup
;
3979 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
3980 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
3981 if (FAILED(hr
)) goto cleanup
;
3984 next_frame
= &(*next_frame
)->pFrameSibling
;
3987 filedata
->lpVtbl
->Release(filedata
);
3995 } else if (first_frame
->pFrameSibling
) {
3996 D3DXFRAME
*root_frame
= NULL
;
3997 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
4002 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
4003 root_frame
->pFrameFirstChild
= first_frame
;
4004 *frame_hierarchy
= root_frame
;
4007 *frame_hierarchy
= first_frame
;
4011 if (anim_controller
)
4013 *anim_controller
= NULL
;
4014 FIXME("Animation controller creation not implemented.\n");
4018 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
4019 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
4020 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
4021 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4025 HRESULT WINAPI
D3DXCleanMesh(D3DXCLEANTYPE clean_type
, ID3DXMesh
*mesh_in
, const DWORD
*adjacency_in
,
4026 ID3DXMesh
**mesh_out
, DWORD
*adjacency_out
, ID3DXBuffer
**errors_and_warnings
)
4028 FIXME("(%u, %p, %p, %p, %p, %p)\n", clean_type
, mesh_in
, adjacency_in
, mesh_out
, adjacency_out
, errors_and_warnings
);
4033 HRESULT WINAPI
D3DXFrameDestroy(D3DXFRAME
*frame
, ID3DXAllocateHierarchy
*alloc_hier
)
4038 TRACE("(%p, %p)\n", frame
, alloc_hier
);
4040 if (!frame
|| !alloc_hier
)
4041 return D3DERR_INVALIDCALL
;
4044 D3DXMESHCONTAINER
*container
;
4045 D3DXFRAME
*current_frame
;
4047 if (frame
->pFrameSibling
) {
4048 current_frame
= frame
->pFrameSibling
;
4049 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
4050 current_frame
->pFrameSibling
= NULL
;
4052 current_frame
= frame
;
4056 if (current_frame
->pFrameFirstChild
) {
4057 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
4058 if (FAILED(hr
)) return hr
;
4059 current_frame
->pFrameFirstChild
= NULL
;
4062 container
= current_frame
->pMeshContainer
;
4064 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
4065 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
4066 if (FAILED(hr
)) return hr
;
4067 container
= next_container
;
4069 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
4070 if (FAILED(hr
)) return hr
;
4075 HRESULT WINAPI
D3DXLoadMeshFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4076 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4077 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4083 TRACE("filename %s, options %#lx, device %p, adjacency %p, materials %p, "
4084 "effect_instances %p, num_materials %p, mesh %p.\n",
4085 debugstr_a(filename
), options
, device
, adjacency
, materials
,
4086 effect_instances
, num_materials
, mesh
);
4089 return D3DERR_INVALIDCALL
;
4091 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
4092 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4093 if (!filenameW
) return E_OUTOFMEMORY
;
4094 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
4096 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
4097 effect_instances
, num_materials
, mesh
);
4098 HeapFree(GetProcessHeap(), 0, filenameW
);
4103 HRESULT WINAPI
D3DXLoadMeshFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4104 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4105 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4111 TRACE("filename %s, options %#lx, device %p, adjacency %p, materials %p, "
4112 "effect_instances %p, num_materials %p, mesh %p.\n",
4113 debugstr_w(filename
), options
, device
, adjacency
, materials
,
4114 effect_instances
, num_materials
, mesh
);
4117 return D3DERR_INVALIDCALL
;
4119 hr
= map_view_of_file(filename
, &buffer
, &size
);
4121 return D3DXERR_INVALIDDATA
;
4123 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4124 materials
, effect_instances
, num_materials
, mesh
);
4126 UnmapViewOfFile(buffer
);
4131 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
, const char *name
, const char *type
, DWORD options
,
4132 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
,
4133 struct ID3DXBuffer
**effect_instances
, DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4140 TRACE("module %p, name %s, type %s, options %#lx, device %p, adjacency %p, "
4141 "materials %p, effect_instances %p, num_materials %p, mesh %p.\n",
4142 module
, debugstr_a(name
), debugstr_a(type
), options
, device
, adjacency
,
4143 materials
, effect_instances
, num_materials
, mesh
);
4145 resinfo
= FindResourceA(module
, name
, type
);
4146 if (!resinfo
) return D3DXERR_INVALIDDATA
;
4148 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
4149 if (FAILED(hr
)) return D3DXERR_INVALIDDATA
;
4151 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4152 materials
, effect_instances
, num_materials
, mesh
);
4155 struct mesh_container
4159 ID3DXBuffer
*adjacency
;
4160 ID3DXBuffer
*materials
;
4161 ID3DXBuffer
*effects
;
4162 DWORD num_materials
;
4163 D3DXMATRIX transform
;
4166 static HRESULT
parse_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
4167 const D3DXMATRIX
*parent_transform
, struct list
*container_list
, DWORD provide_flags
)
4170 D3DXMATRIX transform
= *parent_transform
;
4171 ID3DXFileData
*child
;
4173 SIZE_T i
, nb_children
;
4175 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
4179 for (i
= 0; i
< nb_children
; i
++)
4181 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
4184 hr
= child
->lpVtbl
->GetType(child
, &type
);
4188 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
4189 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
4195 list_add_tail(container_list
, &container
->entry
);
4196 container
->transform
= transform
;
4198 hr
= D3DXLoadSkinMeshFromXof(child
, options
, device
,
4199 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
4200 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
4201 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
4202 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
4203 D3DXMATRIX new_transform
;
4204 hr
= parse_transform_matrix(child
, &new_transform
);
4205 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
4206 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
4207 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
4212 IUnknown_Release(child
);
4217 IUnknown_Release(child
);
4221 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
4222 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
4223 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXMesh
**mesh_out
)
4226 ID3DXFile
*d3dxfile
= NULL
;
4227 ID3DXFileEnumObject
*enumobj
= NULL
;
4228 ID3DXFileData
*filedata
= NULL
;
4229 D3DXF_FILELOADMEMORY source
;
4230 ID3DXBuffer
*materials
= NULL
;
4231 ID3DXBuffer
*effects
= NULL
;
4232 ID3DXBuffer
*adjacency
= NULL
;
4233 struct list container_list
= LIST_INIT(container_list
);
4234 struct mesh_container
*container_ptr
, *next_container_ptr
;
4235 DWORD num_materials
;
4236 DWORD num_faces
, num_vertices
;
4237 D3DXMATRIX identity
;
4238 DWORD provide_flags
= 0;
4240 ID3DXMesh
*concat_mesh
= NULL
;
4241 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
4242 BYTE
*concat_vertices
= NULL
;
4243 void *concat_indices
= NULL
;
4245 DWORD concat_vertex_size
;
4246 SIZE_T i
, nb_children
;
4249 TRACE("memory %p, memory_size %lu, options %#lx, device %p, adjacency_out %p, materials_out %p, "
4250 "effects_out %p, num_materials_out %p, mesh_out %p.\n", memory
, memory_size
, options
,
4251 device
, adjacency_out
, materials_out
, effects_out
, num_materials_out
, mesh_out
);
4253 if (!memory
|| !memory_size
|| !device
|| !mesh_out
)
4254 return D3DERR_INVALIDCALL
;
4256 hr
= D3DXFileCreate(&d3dxfile
);
4257 if (FAILED(hr
)) goto cleanup
;
4259 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
4260 if (FAILED(hr
)) goto cleanup
;
4262 source
.lpMemory
= (void*)memory
;
4263 source
.dSize
= memory_size
;
4264 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
4265 if (FAILED(hr
)) goto cleanup
;
4267 D3DXMatrixIdentity(&identity
);
4268 if (adjacency_out
) provide_flags
|= PROVIDE_ADJACENCY
;
4269 if (materials_out
|| effects_out
) provide_flags
|= PROVIDE_MATERIALS
;
4271 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
4275 for (i
= 0; i
< nb_children
; i
++)
4277 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
4281 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
4282 if (SUCCEEDED(hr
)) {
4283 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
4284 container_ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container_ptr
));
4285 if (!container_ptr
) {
4289 list_add_tail(&container_list
, &container_ptr
->entry
);
4290 D3DXMatrixIdentity(&container_ptr
->transform
);
4292 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
4293 (provide_flags
& PROVIDE_ADJACENCY
) ? &container_ptr
->adjacency
: NULL
,
4294 (provide_flags
& PROVIDE_MATERIALS
) ? &container_ptr
->materials
: NULL
,
4295 NULL
, &container_ptr
->num_materials
, NULL
, &container_ptr
->mesh
);
4296 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
4297 hr
= parse_frame(filedata
, options
, device
, &identity
, &container_list
, provide_flags
);
4299 if (FAILED(hr
)) goto cleanup
;
4301 filedata
->lpVtbl
->Release(filedata
);
4307 enumobj
->lpVtbl
->Release(enumobj
);
4309 d3dxfile
->lpVtbl
->Release(d3dxfile
);
4312 if (list_empty(&container_list
)) {
4321 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4323 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4324 fvf
|= mesh
->lpVtbl
->GetFVF(mesh
);
4325 num_faces
+= mesh
->lpVtbl
->GetNumFaces(mesh
);
4326 num_vertices
+= mesh
->lpVtbl
->GetNumVertices(mesh
);
4327 num_materials
+= container_ptr
->num_materials
;
4330 hr
= D3DXCreateMeshFVF(num_faces
, num_vertices
, options
, fvf
, device
, &concat_mesh
);
4331 if (FAILED(hr
)) goto cleanup
;
4333 hr
= concat_mesh
->lpVtbl
->GetDeclaration(concat_mesh
, concat_decl
);
4334 if (FAILED(hr
)) goto cleanup
;
4336 concat_vertex_size
= D3DXGetDeclVertexSize(concat_decl
, 0);
4338 hr
= concat_mesh
->lpVtbl
->LockVertexBuffer(concat_mesh
, 0, (void**)&concat_vertices
);
4339 if (FAILED(hr
)) goto cleanup
;
4341 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4343 D3DVERTEXELEMENT9 mesh_decl
[MAX_FVF_DECL_SIZE
];
4344 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4345 DWORD num_mesh_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
4346 DWORD mesh_vertex_size
;
4347 const BYTE
*mesh_vertices
;
4350 hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, mesh_decl
);
4351 if (FAILED(hr
)) goto cleanup
;
4353 mesh_vertex_size
= D3DXGetDeclVertexSize(mesh_decl
, 0);
4355 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_vertices
);
4356 if (FAILED(hr
)) goto cleanup
;
4358 for (i
= 0; i
< num_mesh_vertices
; i
++) {
4362 D3DXVec3TransformCoord((D3DXVECTOR3
*)concat_vertices
,
4363 (D3DXVECTOR3
*)mesh_vertices
,
4364 &container_ptr
->transform
);
4365 for (j
= 1; concat_decl
[j
].Stream
!= 0xff; j
++)
4367 if (concat_decl
[j
].Usage
== mesh_decl
[k
].Usage
&&
4368 concat_decl
[j
].UsageIndex
== mesh_decl
[k
].UsageIndex
)
4370 if (concat_decl
[j
].Usage
== D3DDECLUSAGE_NORMAL
) {
4371 D3DXVec3TransformCoord((D3DXVECTOR3
*)(concat_vertices
+ concat_decl
[j
].Offset
),
4372 (D3DXVECTOR3
*)(mesh_vertices
+ mesh_decl
[k
].Offset
),
4373 &container_ptr
->transform
);
4375 memcpy(concat_vertices
+ concat_decl
[j
].Offset
,
4376 mesh_vertices
+ mesh_decl
[k
].Offset
,
4377 d3dx_decltype_size
[mesh_decl
[k
].Type
]);
4382 mesh_vertices
+= mesh_vertex_size
;
4383 concat_vertices
+= concat_vertex_size
;
4386 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
4389 concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4390 concat_vertices
= NULL
;
4392 hr
= concat_mesh
->lpVtbl
->LockIndexBuffer(concat_mesh
, 0, &concat_indices
);
4393 if (FAILED(hr
)) goto cleanup
;
4396 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4398 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4399 const void *mesh_indices
;
4400 DWORD num_mesh_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4403 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_indices
);
4404 if (FAILED(hr
)) goto cleanup
;
4406 if (options
& D3DXMESH_32BIT
) {
4407 DWORD
*dest
= concat_indices
;
4408 const DWORD
*src
= mesh_indices
;
4409 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4410 *dest
++ = index_offset
+ *src
++;
4411 concat_indices
= dest
;
4413 WORD
*dest
= concat_indices
;
4414 const WORD
*src
= mesh_indices
;
4415 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4416 *dest
++ = index_offset
+ *src
++;
4417 concat_indices
= dest
;
4419 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
4421 index_offset
+= num_mesh_faces
* 3;
4424 concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4425 concat_indices
= NULL
;
4427 if (num_materials
) {
4428 DWORD
*concat_attrib_buffer
= NULL
;
4431 hr
= concat_mesh
->lpVtbl
->LockAttributeBuffer(concat_mesh
, 0, &concat_attrib_buffer
);
4432 if (FAILED(hr
)) goto cleanup
;
4434 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4436 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4437 const DWORD
*mesh_attrib_buffer
= NULL
;
4438 DWORD count
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4440 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, D3DLOCK_READONLY
, (DWORD
**)&mesh_attrib_buffer
);
4442 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4447 *concat_attrib_buffer
++ = offset
+ *mesh_attrib_buffer
++;
4449 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
4450 offset
+= container_ptr
->num_materials
;
4452 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4455 if (materials_out
|| effects_out
) {
4456 D3DXMATERIAL
*out_ptr
;
4457 if (!num_materials
) {
4458 /* create default material */
4459 hr
= D3DXCreateBuffer(sizeof(D3DXMATERIAL
), &materials
);
4460 if (FAILED(hr
)) goto cleanup
;
4462 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4463 out_ptr
->MatD3D
.Diffuse
.r
= 0.5f
;
4464 out_ptr
->MatD3D
.Diffuse
.g
= 0.5f
;
4465 out_ptr
->MatD3D
.Diffuse
.b
= 0.5f
;
4466 out_ptr
->MatD3D
.Specular
.r
= 0.5f
;
4467 out_ptr
->MatD3D
.Specular
.g
= 0.5f
;
4468 out_ptr
->MatD3D
.Specular
.b
= 0.5f
;
4469 /* D3DXCreateBuffer initializes the rest to zero */
4471 DWORD buffer_size
= num_materials
* sizeof(D3DXMATERIAL
);
4472 char *strings_out_ptr
;
4474 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4476 if (container_ptr
->materials
) {
4478 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4479 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4481 if (in_ptr
->pTextureFilename
)
4482 buffer_size
+= strlen(in_ptr
->pTextureFilename
) + 1;
4488 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
4489 if (FAILED(hr
)) goto cleanup
;
4490 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4491 strings_out_ptr
= (char*)(out_ptr
+ num_materials
);
4493 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4495 if (container_ptr
->materials
) {
4497 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4498 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4500 out_ptr
->MatD3D
= in_ptr
->MatD3D
;
4501 if (in_ptr
->pTextureFilename
) {
4502 out_ptr
->pTextureFilename
= strings_out_ptr
;
4503 strcpy(out_ptr
->pTextureFilename
, in_ptr
->pTextureFilename
);
4504 strings_out_ptr
+= strlen(in_ptr
->pTextureFilename
) + 1;
4517 generate_effects(materials
, num_materials
, &effects
);
4518 if (!materials_out
) {
4519 ID3DXBuffer_Release(materials
);
4524 if (adjacency_out
) {
4525 if (!list_next(&container_list
, list_head(&container_list
))) {
4526 container_ptr
= LIST_ENTRY(list_head(&container_list
), struct mesh_container
, entry
);
4527 adjacency
= container_ptr
->adjacency
;
4528 container_ptr
->adjacency
= NULL
;
4533 hr
= D3DXCreateBuffer(num_faces
* 3 * sizeof(DWORD
), &adjacency
);
4534 if (FAILED(hr
)) goto cleanup
;
4536 out_ptr
= ID3DXBuffer_GetBufferPointer(adjacency
);
4537 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4540 DWORD count
= 3 * container_ptr
->mesh
->lpVtbl
->GetNumFaces(container_ptr
->mesh
);
4541 DWORD
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->adjacency
);
4543 for (i
= 0; i
< count
; i
++)
4544 *out_ptr
++ = offset
+ *in_ptr
++;
4551 *mesh_out
= concat_mesh
;
4552 if (adjacency_out
) *adjacency_out
= adjacency
;
4553 if (materials_out
) *materials_out
= materials
;
4554 if (effects_out
) *effects_out
= effects
;
4555 if (num_materials_out
) *num_materials_out
= num_materials
;
4559 if (concat_indices
) concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4560 if (concat_vertices
) concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4561 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
4562 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
4563 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4565 if (concat_mesh
) IUnknown_Release(concat_mesh
);
4566 if (materials
) ID3DXBuffer_Release(materials
);
4567 if (effects
) ID3DXBuffer_Release(effects
);
4568 if (adjacency
) ID3DXBuffer_Release(adjacency
);
4570 LIST_FOR_EACH_ENTRY_SAFE(container_ptr
, next_container_ptr
, &container_list
, struct mesh_container
, entry
)
4572 if (container_ptr
->mesh
) IUnknown_Release(container_ptr
->mesh
);
4573 if (container_ptr
->adjacency
) ID3DXBuffer_Release(container_ptr
->adjacency
);
4574 if (container_ptr
->materials
) ID3DXBuffer_Release(container_ptr
->materials
);
4575 if (container_ptr
->effects
) ID3DXBuffer_Release(container_ptr
->effects
);
4576 HeapFree(GetProcessHeap(), 0, container_ptr
);
4583 D3DXVECTOR3 position
;
4587 HRESULT WINAPI
D3DXCreatePolygon(struct IDirect3DDevice9
*device
, float length
, UINT sides
,
4588 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4592 struct vertex
*vertices
;
4594 DWORD (*adjacency_buf
)[3];
4598 TRACE("device %p, length %f, sides %u, mesh %p, adjacency %p.\n",
4599 device
, length
, sides
, mesh
, adjacency
);
4601 if (!device
|| length
< 0.0f
|| sides
< 3 || !mesh
)
4602 return D3DERR_INVALIDCALL
;
4604 if (FAILED(hr
= D3DXCreateMeshFVF(sides
, sides
+ 1, D3DXMESH_MANAGED
,
4605 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &polygon
)))
4610 if (FAILED(hr
= polygon
->lpVtbl
->LockVertexBuffer(polygon
, 0, (void **)&vertices
)))
4612 polygon
->lpVtbl
->Release(polygon
);
4616 if (FAILED(hr
= polygon
->lpVtbl
->LockIndexBuffer(polygon
, 0, (void **)&faces
)))
4618 polygon
->lpVtbl
->UnlockVertexBuffer(polygon
);
4619 polygon
->lpVtbl
->Release(polygon
);
4623 angle
= D3DX_PI
/ sides
;
4624 scale
= 0.5f
* length
/ sinf(angle
);
4627 vertices
[0].position
.x
= 0.0f
;
4628 vertices
[0].position
.y
= 0.0f
;
4629 vertices
[0].position
.z
= 0.0f
;
4630 vertices
[0].normal
.x
= 0.0f
;
4631 vertices
[0].normal
.y
= 0.0f
;
4632 vertices
[0].normal
.z
= 1.0f
;
4634 for (i
= 0; i
< sides
; ++i
)
4636 vertices
[i
+ 1].position
.x
= cosf(angle
* i
) * scale
;
4637 vertices
[i
+ 1].position
.y
= sinf(angle
* i
) * scale
;
4638 vertices
[i
+ 1].position
.z
= 0.0f
;
4639 vertices
[i
+ 1].normal
.x
= 0.0f
;
4640 vertices
[i
+ 1].normal
.y
= 0.0f
;
4641 vertices
[i
+ 1].normal
.z
= 1.0f
;
4644 faces
[i
][1] = i
+ 1;
4645 faces
[i
][2] = i
+ 2;
4648 faces
[sides
- 1][2] = 1;
4650 polygon
->lpVtbl
->UnlockVertexBuffer(polygon
);
4651 polygon
->lpVtbl
->UnlockIndexBuffer(polygon
);
4655 if (FAILED(hr
= D3DXCreateBuffer(sides
* sizeof(DWORD
) * 3, adjacency
)))
4657 polygon
->lpVtbl
->Release(polygon
);
4661 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4662 for (i
= 0; i
< sides
; ++i
)
4664 adjacency_buf
[i
][0] = i
- 1;
4665 adjacency_buf
[i
][1] = ~0U;
4666 adjacency_buf
[i
][2] = i
+ 1;
4668 adjacency_buf
[0][0] = sides
- 1;
4669 adjacency_buf
[sides
- 1][2] = 0;
4677 HRESULT WINAPI
D3DXCreateBox(struct IDirect3DDevice9
*device
, float width
, float height
,
4678 float depth
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4682 struct vertex
*vertices
;
4684 DWORD
*adjacency_buf
;
4685 unsigned int i
, face
;
4686 static const D3DXVECTOR3 unit_box
[] =
4688 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, -0.5f
},
4689 {-0.5f
, 0.5f
, -0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, -0.5f
},
4690 { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, -0.5f
},
4691 {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, 0.5f
},
4692 {-0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
},
4693 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}
4695 static const D3DXVECTOR3 normals
[] =
4697 {-1.0f
, 0.0f
, 0.0f
}, { 0.0f
, 1.0f
, 0.0f
}, { 1.0f
, 0.0f
, 0.0f
},
4698 { 0.0f
, -1.0f
, 0.0f
}, { 0.0f
, 0.0f
, 1.0f
}, { 0.0f
, 0.0f
, -1.0f
}
4700 static const DWORD adjacency_table
[] =
4702 6, 9, 1, 2, 10, 0, 1, 9, 3, 4, 10, 2,
4703 3, 8, 5, 7, 11, 4, 0, 11, 7, 5, 8, 6,
4704 7, 4, 9, 2, 0, 8, 1, 3, 11, 5, 6, 10
4707 TRACE("device %p, width %f, height %f, depth %f, mesh %p, adjacency %p\n",
4708 device
, width
, height
, depth
, mesh
, adjacency
);
4710 if (!device
|| width
< 0.0f
|| height
< 0.0f
|| depth
< 0.0f
|| !mesh
)
4712 return D3DERR_INVALIDCALL
;
4715 if (FAILED(hr
= D3DXCreateMeshFVF(12, 24, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &box
)))
4720 if (FAILED(hr
= box
->lpVtbl
->LockVertexBuffer(box
, 0, (void **)&vertices
)))
4722 box
->lpVtbl
->Release(box
);
4726 if (FAILED(hr
= box
->lpVtbl
->LockIndexBuffer(box
, 0, (void **)&faces
)))
4728 box
->lpVtbl
->UnlockVertexBuffer(box
);
4729 box
->lpVtbl
->Release(box
);
4733 for (i
= 0; i
< 24; i
++)
4735 vertices
[i
].position
.x
= width
* unit_box
[i
].x
;
4736 vertices
[i
].position
.y
= height
* unit_box
[i
].y
;
4737 vertices
[i
].position
.z
= depth
* unit_box
[i
].z
;
4738 vertices
[i
].normal
.x
= normals
[i
/ 4].x
;
4739 vertices
[i
].normal
.y
= normals
[i
/ 4].y
;
4740 vertices
[i
].normal
.z
= normals
[i
/ 4].z
;
4744 for (i
= 0; i
< 12; i
++)
4746 faces
[i
][0] = face
++;
4747 faces
[i
][1] = face
++;
4748 faces
[i
][2] = (i
% 2) ? face
- 4 : face
;
4751 box
->lpVtbl
->UnlockIndexBuffer(box
);
4752 box
->lpVtbl
->UnlockVertexBuffer(box
);
4756 if (FAILED(hr
= D3DXCreateBuffer(sizeof(adjacency_table
), adjacency
)))
4758 box
->lpVtbl
->Release(box
);
4762 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4763 memcpy(adjacency_buf
, adjacency_table
, sizeof(adjacency_table
));
4771 typedef WORD face
[3];
4779 static void free_sincos_table(struct sincos_table
*sincos_table
)
4781 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
4782 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4785 /* pre compute sine and cosine tables; caller must free */
4786 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
4791 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
4792 if (!sincos_table
->sin
)
4796 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
4797 if (!sincos_table
->cos
)
4799 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4803 angle
= angle_start
;
4804 for (i
= 0; i
< n
; i
++)
4806 sincos_table
->sin
[i
] = sinf(angle
);
4807 sincos_table
->cos
[i
] = cosf(angle
);
4808 angle
+= angle_step
;
4814 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
4816 return stack
*slices
+slice
+1;
4819 HRESULT WINAPI
D3DXCreateSphere(struct IDirect3DDevice9
*device
, float radius
, UINT slices
,
4820 UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4822 DWORD number_of_vertices
, number_of_faces
;
4825 struct vertex
*vertices
;
4827 float phi_step
, phi_start
;
4828 struct sincos_table phi
;
4829 float theta_step
, theta
, sin_theta
, cos_theta
;
4830 DWORD vertex
, face
, stack
, slice
;
4832 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
4834 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
4836 return D3DERR_INVALIDCALL
;
4839 number_of_vertices
= 2 + slices
* (stacks
-1);
4840 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
4842 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4843 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
4849 if (FAILED(hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, 0, (void **)&vertices
)))
4851 sphere
->lpVtbl
->Release(sphere
);
4855 if (FAILED(hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, 0, (void **)&faces
)))
4857 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4858 sphere
->lpVtbl
->Release(sphere
);
4862 /* phi = angle on xz plane wrt z axis */
4863 phi_step
= -2.0f
* D3DX_PI
/ slices
;
4864 phi_start
= D3DX_PI
/ 2.0f
;
4866 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
4868 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4869 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4870 sphere
->lpVtbl
->Release(sphere
);
4871 return E_OUTOFMEMORY
;
4874 /* theta = angle on xy plane wrt x axis */
4875 theta_step
= D3DX_PI
/ stacks
;
4881 vertices
[vertex
].normal
.x
= 0.0f
;
4882 vertices
[vertex
].normal
.y
= 0.0f
;
4883 vertices
[vertex
].normal
.z
= 1.0f
;
4884 vertices
[vertex
].position
.x
= 0.0f
;
4885 vertices
[vertex
].position
.y
= 0.0f
;
4886 vertices
[vertex
].position
.z
= radius
;
4889 for (stack
= 0; stack
< stacks
- 1; stack
++)
4891 sin_theta
= sinf(theta
);
4892 cos_theta
= cosf(theta
);
4894 for (slice
= 0; slice
< slices
; slice
++)
4896 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
4897 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
4898 vertices
[vertex
].normal
.z
= cos_theta
;
4899 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
4900 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
4901 vertices
[vertex
].position
.z
= radius
* cos_theta
;
4908 /* top stack is triangle fan */
4910 faces
[face
][1] = slice
+ 1;
4911 faces
[face
][2] = slice
;
4916 /* stacks in between top and bottom are quad strips */
4917 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4918 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4919 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4922 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4923 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
4924 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4930 theta
+= theta_step
;
4936 faces
[face
][2] = slice
;
4941 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4942 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4943 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4946 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4947 faces
[face
][1] = vertex_index(slices
, 0, stack
);
4948 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4953 vertices
[vertex
].position
.x
= 0.0f
;
4954 vertices
[vertex
].position
.y
= 0.0f
;
4955 vertices
[vertex
].position
.z
= -radius
;
4956 vertices
[vertex
].normal
.x
= 0.0f
;
4957 vertices
[vertex
].normal
.y
= 0.0f
;
4958 vertices
[vertex
].normal
.z
= -1.0f
;
4960 /* bottom stack is triangle fan */
4961 for (slice
= 1; slice
< slices
; slice
++)
4963 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4964 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4965 faces
[face
][2] = vertex
;
4969 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4970 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4971 faces
[face
][2] = vertex
;
4973 free_sincos_table(&phi
);
4974 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4975 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4980 if (FAILED(hr
= D3DXCreateBuffer(number_of_faces
* sizeof(DWORD
) * 3, adjacency
)))
4982 sphere
->lpVtbl
->Release(sphere
);
4986 if (FAILED(hr
= sphere
->lpVtbl
->GenerateAdjacency(sphere
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
4988 (*adjacency
)->lpVtbl
->Release(*adjacency
);
4989 sphere
->lpVtbl
->Release(sphere
);
4999 HRESULT WINAPI
D3DXCreateCylinder(struct IDirect3DDevice9
*device
, float radius1
, float radius2
,
5000 float length
, UINT slices
, UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
5002 DWORD number_of_vertices
, number_of_faces
;
5004 ID3DXMesh
*cylinder
;
5005 struct vertex
*vertices
;
5007 float theta_step
, theta_start
;
5008 struct sincos_table theta
;
5009 float delta_radius
, radius
, radius_step
;
5010 float z
, z_step
, z_normal
;
5011 DWORD vertex
, face
, slice
, stack
;
5013 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
5015 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
5017 return D3DERR_INVALIDCALL
;
5020 number_of_vertices
= 2 + (slices
* (3 + stacks
));
5021 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
5023 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
5024 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
5030 if (FAILED(hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, 0, (void **)&vertices
)))
5032 cylinder
->lpVtbl
->Release(cylinder
);
5036 if (FAILED(hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, 0, (void **)&faces
)))
5038 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5039 cylinder
->lpVtbl
->Release(cylinder
);
5043 /* theta = angle on xy plane wrt x axis */
5044 theta_step
= -2.0f
* D3DX_PI
/ slices
;
5045 theta_start
= D3DX_PI
/ 2.0f
;
5047 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
5049 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5050 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5051 cylinder
->lpVtbl
->Release(cylinder
);
5052 return E_OUTOFMEMORY
;
5058 delta_radius
= radius1
- radius2
;
5060 radius_step
= delta_radius
/ stacks
;
5063 z_step
= length
/ stacks
;
5064 z_normal
= delta_radius
/ length
;
5065 if (isnan(z_normal
))
5070 vertices
[vertex
].normal
.x
= 0.0f
;
5071 vertices
[vertex
].normal
.y
= 0.0f
;
5072 vertices
[vertex
].normal
.z
= -1.0f
;
5073 vertices
[vertex
].position
.x
= 0.0f
;
5074 vertices
[vertex
].position
.y
= 0.0f
;
5075 vertices
[vertex
++].position
.z
= z
;
5077 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5079 vertices
[vertex
].normal
.x
= 0.0f
;
5080 vertices
[vertex
].normal
.y
= 0.0f
;
5081 vertices
[vertex
].normal
.z
= -1.0f
;
5082 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5083 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5084 vertices
[vertex
].position
.z
= z
;
5089 faces
[face
][1] = slice
;
5090 faces
[face
++][2] = slice
+ 1;
5095 faces
[face
][1] = slice
;
5096 faces
[face
++][2] = 1;
5098 for (stack
= 1; stack
<= stacks
+1; stack
++)
5100 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5102 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
5103 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
5104 vertices
[vertex
].normal
.z
= z_normal
;
5105 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
5106 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5107 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5108 vertices
[vertex
].position
.z
= z
;
5110 if (stack
> 1 && slice
> 0)
5112 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
5113 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5114 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
5116 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
5117 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5118 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5124 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
5125 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5126 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
5128 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
5129 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5130 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
5133 if (stack
< stacks
+ 1)
5136 radius
-= radius_step
;
5140 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5142 vertices
[vertex
].normal
.x
= 0.0f
;
5143 vertices
[vertex
].normal
.y
= 0.0f
;
5144 vertices
[vertex
].normal
.z
= 1.0f
;
5145 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5146 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5147 vertices
[vertex
].position
.z
= z
;
5151 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5152 faces
[face
][1] = number_of_vertices
- 1;
5153 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5157 vertices
[vertex
].position
.x
= 0.0f
;
5158 vertices
[vertex
].position
.y
= 0.0f
;
5159 vertices
[vertex
].position
.z
= z
;
5160 vertices
[vertex
].normal
.x
= 0.0f
;
5161 vertices
[vertex
].normal
.y
= 0.0f
;
5162 vertices
[vertex
].normal
.z
= 1.0f
;
5164 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5165 faces
[face
][1] = number_of_vertices
- 1;
5166 faces
[face
][2] = vertex_index(slices
, 0, stack
);
5168 free_sincos_table(&theta
);
5169 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5170 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5174 if (FAILED(hr
= D3DXCreateBuffer(number_of_faces
* sizeof(DWORD
) * 3, adjacency
)))
5176 cylinder
->lpVtbl
->Release(cylinder
);
5180 if (FAILED(hr
= cylinder
->lpVtbl
->GenerateAdjacency(cylinder
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
5182 (*adjacency
)->lpVtbl
->Release(*adjacency
);
5183 cylinder
->lpVtbl
->Release(cylinder
);
5193 HRESULT WINAPI
D3DXCreateTeapot(struct IDirect3DDevice9
*device
,
5194 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
5196 FIXME("device %p, mesh %p, adjacency %p semi-stub.\n", device
, mesh
, adjacency
);
5198 return D3DXCreateSphere(device
, 1.0f
, 4, 4, mesh
, adjacency
);
5201 HRESULT WINAPI
D3DXCreateTextA(struct IDirect3DDevice9
*device
, HDC hdc
, const char *text
, float deviation
,
5202 float extrusion
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5208 TRACE("device %p, hdc %p, text %s, deviation %.8e, extrusion %.8e, mesh %p, adjacency %p, glyphmetrics %p.\n",
5209 device
, hdc
, debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
5212 return D3DERR_INVALIDCALL
;
5214 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
5215 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5216 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
5218 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
5219 mesh
, adjacency
, glyphmetrics
);
5220 HeapFree(GetProcessHeap(), 0, textW
);
5225 HRESULT WINAPI
D3DXCreateTorus(struct IDirect3DDevice9
*device
,
5226 float innerradius
, float outerradius
, UINT sides
, UINT rings
, struct ID3DXMesh
**mesh
, ID3DXBuffer
**adjacency
)
5231 struct vertex
*vertices
;
5232 float phi
, phi_step
, sin_phi
, cos_phi
;
5233 float theta
, theta_step
, sin_theta
, cos_theta
;
5234 unsigned int i
, j
, numvert
, numfaces
;
5236 TRACE("device %p, innerradius %.8e, outerradius %.8e, sides %u, rings %u, mesh %p, adjacency %p.\n",
5237 device
, innerradius
, outerradius
, sides
, rings
, mesh
, adjacency
);
5239 numvert
= sides
* rings
;
5240 numfaces
= numvert
* 2;
5242 if (!device
|| innerradius
< 0.0f
|| outerradius
< 0.0f
|| sides
< 3 || rings
< 3 || !mesh
)
5244 WARN("Invalid arguments.\n");
5245 return D3DERR_INVALIDCALL
;
5248 if (FAILED(hr
= D3DXCreateMeshFVF(numfaces
, numvert
, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &torus
)))
5251 if (FAILED(hr
= torus
->lpVtbl
->LockVertexBuffer(torus
, 0, (void **)&vertices
)))
5253 torus
->lpVtbl
->Release(torus
);
5257 if (FAILED(hr
= torus
->lpVtbl
->LockIndexBuffer(torus
, 0, (void **)&faces
)))
5259 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5260 torus
->lpVtbl
->Release(torus
);
5264 phi_step
= D3DX_PI
/ sides
* 2.0f
;
5265 theta_step
= D3DX_PI
/ rings
* -2.0f
;
5269 for (i
= 0; i
< rings
; ++i
)
5273 sin_theta
= sinf(theta
);
5274 cos_theta
= cosf(theta
);
5276 for (j
= 0; j
< sides
; ++j
)
5278 sin_phi
= sinf(phi
);
5279 cos_phi
= cosf(phi
);
5281 vertices
[i
* sides
+ j
].position
.x
= (innerradius
* cos_phi
+ outerradius
) * cos_theta
;
5282 vertices
[i
* sides
+ j
].position
.y
= (innerradius
* cos_phi
+ outerradius
) * sin_theta
;
5283 vertices
[i
* sides
+ j
].position
.z
= innerradius
* sin_phi
;
5284 vertices
[i
* sides
+ j
].normal
.x
= cos_phi
* cos_theta
;
5285 vertices
[i
* sides
+ j
].normal
.y
= cos_phi
* sin_theta
;
5286 vertices
[i
* sides
+ j
].normal
.z
= sin_phi
;
5291 theta
+= theta_step
;
5294 for (i
= 0; i
< numfaces
- sides
* 2; ++i
)
5296 faces
[i
][0] = i
% 2 ? i
/ 2 + sides
: i
/ 2;
5297 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5298 faces
[i
][2] = (i
+ 1) % (sides
* 2) ? (i
+ 1) / 2 + sides
: (i
+ 1) / 2;
5301 for (j
= 0; i
< numfaces
; ++i
, ++j
)
5303 faces
[i
][0] = i
% 2 ? j
/ 2 : i
/ 2;
5304 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5305 faces
[i
][2] = i
== numfaces
- 1 ? 0 : (j
+ 1) / 2;
5308 torus
->lpVtbl
->UnlockIndexBuffer(torus
);
5309 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5313 if (FAILED(hr
= D3DXCreateBuffer(numfaces
* sizeof(DWORD
) * 3, adjacency
)))
5315 torus
->lpVtbl
->Release(torus
);
5319 if (FAILED(hr
= torus
->lpVtbl
->GenerateAdjacency(torus
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
5321 (*adjacency
)->lpVtbl
->Release(*adjacency
);
5322 torus
->lpVtbl
->Release(torus
);
5333 POINTTYPE_CURVE
= 0,
5335 POINTTYPE_CURVE_START
,
5336 POINTTYPE_CURVE_END
,
5337 POINTTYPE_CURVE_MIDDLE
,
5343 enum pointtype corner
;
5346 struct dynamic_array
5348 int count
, capacity
;
5352 /* is a dynamic_array */
5355 int count
, capacity
;
5356 struct point2d
*items
;
5359 /* is a dynamic_array */
5360 struct outline_array
5362 int count
, capacity
;
5363 struct outline
*items
;
5372 struct point2d_index
5374 struct outline
*outline
;
5378 struct point2d_index_array
5381 struct point2d_index
*items
;
5386 struct outline_array outlines
;
5387 struct face_array faces
;
5388 struct point2d_index_array ordered_vertices
;
5392 /* is an dynamic_array */
5395 int count
, capacity
;
5399 /* complex polygons are split into monotone polygons, which have
5400 * at most 2 intersections with the vertical sweep line */
5401 struct triangulation
5403 struct word_array vertex_stack
;
5404 BOOL last_on_top
, merging
;
5407 /* is an dynamic_array */
5408 struct triangulation_array
5410 int count
, capacity
;
5411 struct triangulation
*items
;
5413 struct glyphinfo
*glyph
;
5416 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
5418 if (count
> array
->capacity
) {
5421 if (array
->items
&& array
->capacity
) {
5422 new_capacity
= max(array
->capacity
* 2, count
);
5423 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
5425 new_capacity
= max(16, count
);
5426 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
5430 array
->items
= new_buffer
;
5431 array
->capacity
= new_capacity
;
5436 static struct point2d
*add_points(struct outline
*array
, int num
)
5438 struct point2d
*item
;
5440 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
5443 item
= &array
->items
[array
->count
];
5444 array
->count
+= num
;
5448 static struct outline
*add_outline(struct outline_array
*array
)
5450 struct outline
*item
;
5452 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5455 item
= &array
->items
[array
->count
++];
5456 ZeroMemory(item
, sizeof(*item
));
5460 static inline face
*add_face(struct face_array
*array
)
5462 return &array
->items
[array
->count
++];
5465 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
5467 struct triangulation
*item
;
5469 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5472 item
= &array
->items
[array
->count
++];
5473 ZeroMemory(item
, sizeof(*item
));
5477 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
5479 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5480 return E_OUTOFMEMORY
;
5482 array
->items
[array
->count
++] = vertex_index
;
5486 /* assume fixed point numbers can be converted to float point in place */
5487 C_ASSERT(sizeof(FIXED
) == sizeof(float));
5488 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
5490 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, unsigned int emsquare
)
5492 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
5494 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
5495 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
5496 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
5502 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
5503 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
5504 float max_deviation_sq
)
5506 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
5509 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
5510 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
5511 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
5513 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
5514 if (deviation_sq
< max_deviation_sq
) {
5515 struct point2d
*pt
= add_points(outline
, 1);
5516 if (!pt
) return E_OUTOFMEMORY
;
5518 pt
->corner
= POINTTYPE_CURVE
;
5519 /* the end point is omitted because the end line merges into the next segment of
5520 * the split bezier curve, and the end of the split bezier curve is added outside
5521 * this recursive function. */
5523 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
5524 if (hr
!= S_OK
) return hr
;
5525 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
5526 if (hr
!= S_OK
) return hr
;
5532 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
5534 /* dot product = cos(theta) */
5535 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
5538 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
5540 return D3DXVec2Normalize(dir
, D3DXVec2Subtract(dir
, pt2
, pt1
));
5550 static BOOL
attempt_line_merge(struct outline
*outline
,
5552 const D3DXVECTOR2
*nextpt
,
5554 const struct cos_table
*table
)
5556 D3DXVECTOR2 curdir
, lastdir
;
5557 struct point2d
*prevpt
, *pt
;
5560 pt
= &outline
->items
[pt_index
];
5561 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5562 prevpt
= &outline
->items
[pt_index
];
5565 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
5567 if (outline
->count
< 2)
5570 /* remove last point if the next line continues the last line */
5571 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5572 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5573 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
5576 if (pt
->corner
== POINTTYPE_CURVE_END
)
5577 prevpt
->corner
= pt
->corner
;
5578 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
5579 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5583 if (outline
->count
< 2)
5586 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5587 prevpt
= &outline
->items
[pt_index
];
5588 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5589 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5594 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
5595 float max_deviation_sq
, unsigned int emsquare
,
5596 const struct cos_table
*cos_table
)
5598 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
5600 while ((char *)header
< (char *)raw_outline
+ datasize
)
5602 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
5603 struct point2d
*lastpt
, *pt
;
5604 D3DXVECTOR2 lastdir
;
5605 D3DXVECTOR2
*pt_flt
;
5607 struct outline
*outline
= add_outline(&glyph
->outlines
);
5610 return E_OUTOFMEMORY
;
5612 pt
= add_points(outline
, 1);
5614 return E_OUTOFMEMORY
;
5615 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
5617 pt
->corner
= POINTTYPE_CORNER
;
5619 if (header
->dwType
!= TT_POLYGON_TYPE
)
5620 FIXME("Unknown header type %lu.\n", header
->dwType
);
5622 while ((char *)curve
< (char *)header
+ header
->cb
)
5624 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
5625 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
5626 unsigned int j2
= 0;
5629 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5633 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
5635 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
5640 int count
= curve
->cpfx
;
5644 D3DXVECTOR2 bezier_end
;
5646 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j2
], &pt_flt
[j2
+1]), 0.5f
);
5647 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &bezier_end
, max_deviation_sq
);
5650 bezier_start
= bezier_end
;
5654 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &pt_flt
[j2
+1], max_deviation_sq
);
5658 pt
= add_points(outline
, 1);
5660 return E_OUTOFMEMORY
;
5662 pt
->pos
= pt_flt
[j2
];
5663 pt
->corner
= POINTTYPE_CURVE_END
;
5665 pt
= add_points(outline
, curve
->cpfx
);
5667 return E_OUTOFMEMORY
;
5668 for (j2
= 0; j2
< curve
->cpfx
; j2
++)
5670 pt
->pos
= pt_flt
[j2
];
5671 pt
->corner
= POINTTYPE_CORNER
;
5676 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5679 /* remove last point if the next line continues the last line */
5680 if (outline
->count
>= 3) {
5683 lastpt
= &outline
->items
[outline
->count
- 1];
5684 pt
= &outline
->items
[0];
5685 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
5686 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
5688 if (pt
->corner
== POINTTYPE_CURVE_START
)
5689 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5691 pt
->corner
= POINTTYPE_CURVE_END
;
5695 /* outline closed with a line from end to start point */
5696 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
5698 lastpt
= &outline
->items
[0];
5699 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
5700 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
5701 lastpt
->corner
= POINTTYPE_CORNER
;
5702 pt
= &outline
->items
[1];
5703 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
5704 *lastpt
= outline
->items
[outline
->count
];
5707 lastpt
= &outline
->items
[outline
->count
- 1];
5708 pt
= &outline
->items
[0];
5709 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
5710 for (j
= 0; j
< outline
->count
; j
++)
5715 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
5716 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
5718 switch (lastpt
->corner
)
5720 case POINTTYPE_CURVE_START
:
5721 case POINTTYPE_CURVE_END
:
5722 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
5723 lastpt
->corner
= POINTTYPE_CORNER
;
5725 case POINTTYPE_CURVE_MIDDLE
:
5726 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
5727 lastpt
->corner
= POINTTYPE_CORNER
;
5729 lastpt
->corner
= POINTTYPE_CURVE
;
5737 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
5742 /* Get the y-distance from a line to a point */
5743 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
5744 D3DXVECTOR2
*line_pt2
,
5747 D3DXVECTOR2 line_vec
= {0, 0};
5751 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
5752 line_pt_dx
= point
->x
- line_pt1
->x
;
5753 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
5754 return point
->y
- line_y
;
5757 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
5759 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
5762 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
5764 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
5767 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
5769 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
5770 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
5774 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
5775 struct triangulation_array
*triangulations
,
5779 struct glyphinfo
*glyph
= triangulations
->glyph
;
5780 struct triangulation
*t
= *t_ptr
;
5785 if (t
->last_on_top
) {
5793 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
5794 /* consume all vertices on the stack */
5795 WORD last_pt
= t
->vertex_stack
.items
[0];
5797 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
5799 face
= add_face(&glyph
->faces
);
5800 if (!face
) return E_OUTOFMEMORY
;
5801 (*face
)[0] = vtx_idx
;
5802 (*face
)[f1
] = last_pt
;
5803 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
5805 t
->vertex_stack
.items
[0] = last_pt
;
5806 t
->vertex_stack
.count
= 1;
5807 } else if (t
->vertex_stack
.count
> 1) {
5808 int i
= t
->vertex_stack
.count
- 1;
5809 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
5810 WORD top_idx
= t
->vertex_stack
.items
[i
--];
5811 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
5815 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
5816 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
5818 if (prev_pt
->x
!= top_pt
->x
&&
5819 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
5820 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
5823 face
= add_face(&glyph
->faces
);
5824 if (!face
) return E_OUTOFMEMORY
;
5825 (*face
)[0] = vtx_idx
;
5826 (*face
)[f1
] = prev_idx
;
5827 (*face
)[f2
] = top_idx
;
5831 t
->vertex_stack
.count
--;
5834 t
->last_on_top
= to_top
;
5836 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
5838 if (hr
== S_OK
&& t
->merging
) {
5839 struct triangulation
*t2
;
5841 t2
= to_top
? t
- 1 : t
+ 1;
5842 t2
->merging
= FALSE
;
5843 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
5844 if (hr
!= S_OK
) return hr
;
5845 remove_triangulation(triangulations
, t
);
5853 /* check if the point is next on the outline for either the top or bottom */
5854 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
5856 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
5857 WORD idx
= t
->vertex_stack
.items
[i
];
5858 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
5859 struct outline
*outline
= pt_idx
->outline
;
5862 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
5864 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
5866 return &outline
->items
[i
].pos
;
5869 static int __cdecl
compare_vertex_indices(const void *a
, const void *b
)
5871 const struct point2d_index
*idx1
= a
, *idx2
= b
;
5872 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
5873 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
5874 float diff
= p1
->x
- p2
->x
;
5877 diff
= p1
->y
- p2
->y
;
5879 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
5882 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
5886 struct glyphinfo
*glyph
= triangulations
->glyph
;
5887 int nb_vertices
= 0;
5889 struct point2d_index
*idx_ptr
;
5891 /* Glyphs without outlines do not generate any vertices. */
5892 if (!glyph
->outlines
.count
)
5895 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5896 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
5898 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
5899 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
5900 if (!glyph
->ordered_vertices
.items
)
5901 return E_OUTOFMEMORY
;
5903 idx_ptr
= glyph
->ordered_vertices
.items
;
5904 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5906 struct outline
*outline
= &glyph
->outlines
.items
[i
];
5909 idx_ptr
->outline
= outline
;
5910 idx_ptr
->vertex
= 0;
5912 for (j
= outline
->count
- 1; j
> 0; j
--)
5914 idx_ptr
->outline
= outline
;
5915 idx_ptr
->vertex
= j
;
5919 glyph
->ordered_vertices
.count
= nb_vertices
;
5921 /* Native implementation seems to try to create a triangle fan from
5922 * the first outline point if the glyph only has one outline. */
5923 if (glyph
->outlines
.count
== 1)
5925 struct outline
*outline
= glyph
->outlines
.items
;
5926 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
5927 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
5930 for (i
= 2; i
< outline
->count
; i
++)
5932 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
5933 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
5934 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
5936 D3DXVec2Subtract(&v1
, base
, last
);
5937 D3DXVec2Subtract(&v2
, last
, next
);
5938 ccw
= D3DXVec2CCW(&v1
, &v2
);
5946 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5947 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
5948 if (!glyph
->faces
.items
)
5949 return E_OUTOFMEMORY
;
5951 glyph
->faces
.count
= outline
->count
- 2;
5952 for (i
= 0; i
< glyph
->faces
.count
; i
++)
5954 glyph
->faces
.items
[i
][0] = 0;
5955 glyph
->faces
.items
[i
][1] = i
+ 1;
5956 glyph
->faces
.items
[i
][2] = i
+ 2;
5962 /* Perform 2D polygon triangulation for complex glyphs.
5963 * Triangulation is performed using a sweep line concept, from right to left,
5964 * by processing vertices in sorted order. Complex polygons are split into
5965 * monotone polygons which are triangulated separately. */
5966 /* FIXME: The order of the faces is not consistent with the native implementation. */
5968 /* Reserve space for maximum possible faces from triangulation.
5969 * # faces for outer outlines = outline->count - 2
5970 * # faces for inner outlines = outline->count + 2
5971 * There must be at least 1 outer outline. */
5972 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5973 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
5974 if (!glyph
->faces
.items
)
5975 return E_OUTOFMEMORY
;
5977 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
5978 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
5979 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
5982 int end
= triangulations
->count
;
5986 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
5987 int current
= (start
+ end
) / 2;
5988 struct triangulation
*t
= &triangulations
->items
[current
];
5989 BOOL on_top_outline
= FALSE
;
5990 D3DXVECTOR2
*top_next
, *bottom_next
;
5991 WORD top_idx
, bottom_idx
;
5993 if (t
->merging
&& t
->last_on_top
)
5994 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
5996 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
5997 if (sweep_vtx
== top_next
)
5999 if (t
->merging
&& t
->last_on_top
)
6001 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
6002 if (hr
!= S_OK
) return hr
;
6004 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
6005 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
6007 /* point also on bottom outline of higher triangulation */
6008 struct triangulation
*t2
= t
+ 1;
6009 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
6010 if (hr
!= S_OK
) return hr
;
6015 on_top_outline
= TRUE
;
6018 if (t
->merging
&& !t
->last_on_top
)
6019 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
6021 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
6022 if (sweep_vtx
== bottom_next
)
6024 if (t
->merging
&& !t
->last_on_top
)
6026 if (on_top_outline
) {
6027 /* outline finished */
6028 remove_triangulation(triangulations
, t
);
6032 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
6033 if (hr
!= S_OK
) return hr
;
6035 if (t
> triangulations
->items
&&
6036 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
6038 struct triangulation
*t2
= t
- 1;
6039 /* point also on top outline of lower triangulation */
6040 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
6041 if (hr
!= S_OK
) return hr
;
6042 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
6052 if (t
->last_on_top
) {
6053 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
6054 bottom_idx
= t
->vertex_stack
.items
[0];
6056 top_idx
= t
->vertex_stack
.items
[0];
6057 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
6060 /* check if the point is inside or outside this polygon */
6061 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
6062 top_next
, sweep_vtx
) > 0)
6064 start
= current
+ 1;
6065 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
6066 bottom_next
, sweep_vtx
) < 0)
6069 } else if (t
->merging
) {
6070 /* inside, so cancel merging */
6071 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
6073 t2
->merging
= FALSE
;
6074 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
6075 if (hr
!= S_OK
) return hr
;
6076 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
6077 if (hr
!= S_OK
) return hr
;
6080 /* inside, so split polygon into two monotone parts */
6081 struct triangulation
*t2
= add_triangulation(triangulations
);
6082 if (!t2
) return E_OUTOFMEMORY
;
6083 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
6084 if (t
->last_on_top
) {
6091 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
6092 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
6093 if (hr
!= S_OK
) return hr
;
6094 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
6095 if (hr
!= S_OK
) return hr
;
6096 t2
->last_on_top
= !t
->last_on_top
;
6098 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
6099 if (hr
!= S_OK
) return hr
;
6105 struct triangulation
*t
;
6106 struct triangulation
*t2
= add_triangulation(triangulations
);
6107 if (!t2
) return E_OUTOFMEMORY
;
6108 t
= &triangulations
->items
[start
];
6109 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
6110 ZeroMemory(t
, sizeof(*t
));
6111 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
6112 if (hr
!= S_OK
) return hr
;
6118 HRESULT WINAPI
D3DXCreateTextW(struct IDirect3DDevice9
*device
, HDC hdc
, const WCHAR
*text
, float deviation
,
6119 float extrusion
, struct ID3DXMesh
**mesh_ptr
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
6122 ID3DXMesh
*mesh
= NULL
;
6123 DWORD nb_vertices
, nb_faces
;
6124 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
6125 struct vertex
*vertices
= NULL
;
6130 OUTLINETEXTMETRICW otm
;
6131 HFONT font
= NULL
, oldfont
= NULL
;
6132 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
6133 void *raw_outline
= NULL
;
6135 struct glyphinfo
*glyphs
= NULL
;
6137 struct triangulation_array triangulations
= {0, 0, NULL
};
6139 struct vertex
*vertex_ptr
;
6141 float max_deviation_sq
;
6142 const struct cos_table cos_table
= {
6143 cosf(D3DXToRadian(0.5f
)),
6144 cosf(D3DXToRadian(45.0f
)),
6145 cosf(D3DXToRadian(90.0f
)),
6149 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
6150 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
6152 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
6153 return D3DERR_INVALIDCALL
;
6157 FIXME("Case of adjacency != NULL not implemented.\n");
6161 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
6162 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
6164 return D3DERR_INVALIDCALL
;
6167 if (deviation
== 0.0f
)
6168 deviation
= 1.0f
/ otm
.otmEMSquare
;
6169 max_deviation_sq
= deviation
* deviation
;
6171 lf
.lfHeight
= otm
.otmEMSquare
;
6173 font
= CreateFontIndirectW(&lf
);
6178 oldfont
= SelectObject(hdc
, font
);
6180 textlen
= lstrlenW(text
);
6181 for (i
= 0; i
< textlen
; i
++)
6183 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
6185 return D3DERR_INVALIDCALL
;
6186 if (bufsize
< datasize
)
6189 if (!bufsize
) { /* e.g. text == " " */
6190 hr
= D3DERR_INVALIDCALL
;
6194 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
6195 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
6196 if (!glyphs
|| !raw_outline
) {
6202 for (i
= 0; i
< textlen
; i
++)
6204 /* get outline points from data returned from GetGlyphOutline */
6207 glyphs
[i
].offset_x
= offset_x
;
6209 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
6210 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
6211 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
6212 if (hr
!= S_OK
) goto error
;
6214 triangulations
.glyph
= &glyphs
[i
];
6215 hr
= triangulate(&triangulations
);
6216 if (hr
!= S_OK
) goto error
;
6217 if (triangulations
.count
) {
6218 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
6219 triangulations
.count
= 0;
6224 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
6225 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
6226 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
6227 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
6228 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6229 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
6231 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6234 /* corner points need an extra vertex for the different side faces normals */
6236 nb_outline_points
= 0;
6238 for (i
= 0; i
< textlen
; i
++)
6241 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
6242 nb_front_faces
+= glyphs
[i
].faces
.count
;
6243 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6246 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6247 nb_corners
++; /* first outline point always repeated as a corner */
6248 for (k
= 1; k
< outline
->count
; k
++)
6249 if (outline
->items
[k
].corner
)
6254 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
6255 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
6258 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
6259 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
6263 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
6266 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, (void **)&faces
)))
6269 /* convert 2D vertices and faces into 3D mesh */
6270 vertex_ptr
= vertices
;
6272 if (extrusion
== 0.0f
) {
6279 for (i
= 0; i
< textlen
; i
++)
6283 struct vertex
*back_vertices
;
6286 /* side vertices and faces */
6287 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6289 struct vertex
*outline_vertices
= vertex_ptr
;
6290 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6292 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
6293 struct point2d
*pt
= &outline
->items
[0];
6295 for (k
= 1; k
<= outline
->count
; k
++)
6298 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
6299 WORD vtx_idx
= vertex_ptr
- vertices
;
6302 if (pt
->corner
== POINTTYPE_CURVE_START
)
6303 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
6304 else if (pt
->corner
)
6305 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6307 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
6308 D3DXVec2Normalize(&vec
, &vec
);
6309 vtx
.normal
.x
= -vec
.y
;
6310 vtx
.normal
.y
= vec
.x
;
6313 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
6314 vtx
.position
.y
= pt
->pos
.y
;
6316 *vertex_ptr
++ = vtx
;
6318 vtx
.position
.z
= -extrusion
;
6319 *vertex_ptr
++ = vtx
;
6321 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
6322 vtx
.position
.y
= nextpt
->pos
.y
;
6323 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
6324 vtx
.position
.z
= -extrusion
;
6325 *vertex_ptr
++ = vtx
;
6327 *vertex_ptr
++ = vtx
;
6329 (*face_ptr
)[0] = vtx_idx
;
6330 (*face_ptr
)[1] = vtx_idx
+ 2;
6331 (*face_ptr
)[2] = vtx_idx
+ 1;
6334 (*face_ptr
)[0] = vtx_idx
;
6335 (*face_ptr
)[1] = vtx_idx
+ 3;
6336 (*face_ptr
)[2] = vtx_idx
+ 2;
6339 if (nextpt
->corner
) {
6340 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
6341 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
6342 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
6344 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6346 D3DXVec2Normalize(&vec
, &vec
);
6347 vtx
.normal
.x
= -vec
.y
;
6348 vtx
.normal
.y
= vec
.x
;
6351 *vertex_ptr
++ = vtx
;
6352 vtx
.position
.z
= -extrusion
;
6353 *vertex_ptr
++ = vtx
;
6356 (*face_ptr
)[0] = vtx_idx
;
6357 (*face_ptr
)[1] = vtx_idx
+ 3;
6358 (*face_ptr
)[2] = vtx_idx
+ 1;
6361 (*face_ptr
)[0] = vtx_idx
;
6362 (*face_ptr
)[1] = vtx_idx
+ 2;
6363 (*face_ptr
)[2] = vtx_idx
+ 3;
6371 *vertex_ptr
++ = *outline_vertices
++;
6372 *vertex_ptr
++ = *outline_vertices
++;
6376 /* back vertices and faces */
6377 back_faces
= face_ptr
;
6378 back_vertices
= vertex_ptr
;
6379 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
6381 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
6382 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
6383 vertex_ptr
->position
.y
= pt
->y
;
6384 vertex_ptr
->position
.z
= 0;
6385 vertex_ptr
->normal
.x
= 0;
6386 vertex_ptr
->normal
.y
= 0;
6387 vertex_ptr
->normal
.z
= 1;
6390 count
= back_vertices
- vertices
;
6391 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
6393 face
*f
= &glyphs
[i
].faces
.items
[j
];
6394 (*face_ptr
)[0] = (*f
)[0] + count
;
6395 (*face_ptr
)[1] = (*f
)[1] + count
;
6396 (*face_ptr
)[2] = (*f
)[2] + count
;
6400 /* front vertices and faces */
6401 j
= count
= vertex_ptr
- back_vertices
;
6404 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
6405 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
6406 vertex_ptr
->position
.z
= -extrusion
;
6407 vertex_ptr
->normal
.x
= 0;
6408 vertex_ptr
->normal
.y
= 0;
6409 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
6413 j
= face_ptr
- back_faces
;
6416 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
6417 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
6418 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
6428 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6429 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6430 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
6433 for (i
= 0; i
< textlen
; i
++)
6436 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6437 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
6438 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
6439 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
6440 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
6442 HeapFree(GetProcessHeap(), 0, glyphs
);
6444 if (triangulations
.items
) {
6446 for (i
= 0; i
< triangulations
.count
; i
++)
6447 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
6448 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
6450 HeapFree(GetProcessHeap(), 0, raw_outline
);
6451 if (oldfont
) SelectObject(hdc
, oldfont
);
6452 if (font
) DeleteObject(font
);
6457 HRESULT WINAPI
D3DXValidMesh(ID3DXMesh
*mesh
, const DWORD
*adjacency
, ID3DXBuffer
**errors_and_warnings
)
6459 FIXME("(%p, %p, %p): stub\n", mesh
, adjacency
, *errors_and_warnings
);
6464 static BOOL
weld_float1(void *to
, void *from
, FLOAT epsilon
)
6469 if (fabsf(*v1
- *v2
) <= epsilon
)
6479 static BOOL
weld_float2(void *to
, void *from
, FLOAT epsilon
)
6481 D3DXVECTOR2
*v1
= to
;
6482 D3DXVECTOR2
*v2
= from
;
6483 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6484 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6485 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6487 if (max_abs_diff
<= epsilon
)
6489 memcpy(to
, from
, sizeof(D3DXVECTOR2
));
6497 static BOOL
weld_float3(void *to
, void *from
, FLOAT epsilon
)
6499 D3DXVECTOR3
*v1
= to
;
6500 D3DXVECTOR3
*v2
= from
;
6501 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6502 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6503 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6504 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6505 max_abs_diff
= max(diff_z
, max_abs_diff
);
6507 if (max_abs_diff
<= epsilon
)
6509 memcpy(to
, from
, sizeof(D3DXVECTOR3
));
6517 static BOOL
weld_float4(void *to
, void *from
, FLOAT epsilon
)
6519 D3DXVECTOR4
*v1
= to
;
6520 D3DXVECTOR4
*v2
= from
;
6521 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6522 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6523 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6524 FLOAT diff_w
= fabsf(v1
->w
- v2
->w
);
6525 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6526 max_abs_diff
= max(diff_z
, max_abs_diff
);
6527 max_abs_diff
= max(diff_w
, max_abs_diff
);
6529 if (max_abs_diff
<= epsilon
)
6531 memcpy(to
, from
, sizeof(D3DXVECTOR4
));
6539 static BOOL
weld_ubyte4(void *to
, void *from
, FLOAT epsilon
)
6543 BYTE truncated_epsilon
= (BYTE
)epsilon
;
6544 BYTE diff_x
= b1
[0] > b2
[0] ? b1
[0] - b2
[0] : b2
[0] - b1
[0];
6545 BYTE diff_y
= b1
[1] > b2
[1] ? b1
[1] - b2
[1] : b2
[1] - b1
[1];
6546 BYTE diff_z
= b1
[2] > b2
[2] ? b1
[2] - b2
[2] : b2
[2] - b1
[2];
6547 BYTE diff_w
= b1
[3] > b2
[3] ? b1
[3] - b2
[3] : b2
[3] - b1
[3];
6548 BYTE max_diff
= max(diff_x
, diff_y
);
6549 max_diff
= max(diff_z
, max_diff
);
6550 max_diff
= max(diff_w
, max_diff
);
6552 if (max_diff
<= truncated_epsilon
)
6554 memcpy(to
, from
, 4 * sizeof(BYTE
));
6562 static BOOL
weld_ubyte4n(void *to
, void *from
, FLOAT epsilon
)
6564 return weld_ubyte4(to
, from
, epsilon
* UCHAR_MAX
);
6567 static BOOL
weld_d3dcolor(void *to
, void *from
, FLOAT epsilon
)
6569 return weld_ubyte4n(to
, from
, epsilon
);
6572 static BOOL
weld_short2(void *to
, void *from
, FLOAT epsilon
)
6576 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6577 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6578 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6579 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6581 if (max_abs_diff
<= truncated_epsilon
)
6583 memcpy(to
, from
, 2 * sizeof(SHORT
));
6591 static BOOL
weld_short2n(void *to
, void *from
, FLOAT epsilon
)
6593 return weld_short2(to
, from
, epsilon
* SHRT_MAX
);
6596 static BOOL
weld_short4(void *to
, void *from
, FLOAT epsilon
)
6600 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6601 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6602 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6603 SHORT diff_z
= abs(s1
[2] - s2
[2]);
6604 SHORT diff_w
= abs(s1
[3] - s2
[3]);
6605 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6606 max_abs_diff
= max(diff_z
, max_abs_diff
);
6607 max_abs_diff
= max(diff_w
, max_abs_diff
);
6609 if (max_abs_diff
<= truncated_epsilon
)
6611 memcpy(to
, from
, 4 * sizeof(SHORT
));
6619 static BOOL
weld_short4n(void *to
, void *from
, FLOAT epsilon
)
6621 return weld_short4(to
, from
, epsilon
* SHRT_MAX
);
6624 static BOOL
weld_ushort2n(void *to
, void *from
, FLOAT epsilon
)
6628 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6629 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6630 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6631 USHORT max_diff
= max(diff_x
, diff_y
);
6633 if (max_diff
<= scaled_epsilon
)
6635 memcpy(to
, from
, 2 * sizeof(USHORT
));
6643 static BOOL
weld_ushort4n(void *to
, void *from
, FLOAT epsilon
)
6647 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6648 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6649 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6650 USHORT diff_z
= s1
[2] > s2
[2] ? s1
[2] - s2
[2] : s2
[2] - s1
[2];
6651 USHORT diff_w
= s1
[3] > s2
[3] ? s1
[3] - s2
[3] : s2
[3] - s1
[3];
6652 USHORT max_diff
= max(diff_x
, diff_y
);
6653 max_diff
= max(diff_z
, max_diff
);
6654 max_diff
= max(diff_w
, max_diff
);
6656 if (max_diff
<= scaled_epsilon
)
6658 memcpy(to
, from
, 4 * sizeof(USHORT
));
6674 static struct udec3
dword_to_udec3(DWORD d
)
6679 v
.y
= (d
& 0xffc00) >> 10;
6680 v
.z
= (d
& 0x3ff00000) >> 20;
6681 v
.w
= (d
& 0xc0000000) >> 30;
6686 static BOOL
weld_udec3(void *to
, void *from
, FLOAT epsilon
)
6690 struct udec3 v1
= dword_to_udec3(*d1
);
6691 struct udec3 v2
= dword_to_udec3(*d2
);
6692 UINT truncated_epsilon
= (UINT
)epsilon
;
6693 UINT diff_x
= v1
.x
> v2
.x
? v1
.x
- v2
.x
: v2
.x
- v1
.x
;
6694 UINT diff_y
= v1
.y
> v2
.y
? v1
.y
- v2
.y
: v2
.y
- v1
.y
;
6695 UINT diff_z
= v1
.z
> v2
.z
? v1
.z
- v2
.z
: v2
.z
- v1
.z
;
6696 UINT diff_w
= v1
.w
> v2
.w
? v1
.w
- v2
.w
: v2
.w
- v1
.w
;
6697 UINT max_diff
= max(diff_x
, diff_y
);
6698 max_diff
= max(diff_z
, max_diff
);
6699 max_diff
= max(diff_w
, max_diff
);
6701 if (max_diff
<= truncated_epsilon
)
6703 memcpy(to
, from
, sizeof(DWORD
));
6719 static struct dec3n
dword_to_dec3n(DWORD d
)
6724 v
.y
= (d
& 0xffc00) >> 10;
6725 v
.z
= (d
& 0x3ff00000) >> 20;
6726 v
.w
= (d
& 0xc0000000) >> 30;
6731 static BOOL
weld_dec3n(void *to
, void *from
, FLOAT epsilon
)
6733 const UINT MAX_DEC3N
= 511;
6736 struct dec3n v1
= dword_to_dec3n(*d1
);
6737 struct dec3n v2
= dword_to_dec3n(*d2
);
6738 INT scaled_epsilon
= (INT
)(epsilon
* MAX_DEC3N
);
6739 INT diff_x
= abs(v1
.x
- v2
.x
);
6740 INT diff_y
= abs(v1
.y
- v2
.y
);
6741 INT diff_z
= abs(v1
.z
- v2
.z
);
6742 INT diff_w
= abs(v1
.w
- v2
.w
);
6743 INT max_abs_diff
= max(diff_x
, diff_y
);
6744 max_abs_diff
= max(diff_z
, max_abs_diff
);
6745 max_abs_diff
= max(diff_w
, max_abs_diff
);
6747 if (max_abs_diff
<= scaled_epsilon
)
6749 memcpy(to
, from
, sizeof(DWORD
));
6757 static BOOL
weld_float16_2(void *to
, void *from
, FLOAT epsilon
)
6759 D3DXFLOAT16
*v1_float16
= to
;
6760 D3DXFLOAT16
*v2_float16
= from
;
6768 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6769 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6771 diff_x
= fabsf(v1
[0] - v2
[0]);
6772 diff_y
= fabsf(v1
[1] - v2
[1]);
6773 max_abs_diff
= max(diff_x
, diff_y
);
6775 if (max_abs_diff
<= epsilon
)
6777 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6786 static BOOL
weld_float16_4(void *to
, void *from
, FLOAT epsilon
)
6788 D3DXFLOAT16
*v1_float16
= to
;
6789 D3DXFLOAT16
*v2_float16
= from
;
6799 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6800 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6802 diff_x
= fabsf(v1
[0] - v2
[0]);
6803 diff_y
= fabsf(v1
[1] - v2
[1]);
6804 diff_z
= fabsf(v1
[2] - v2
[2]);
6805 diff_w
= fabsf(v1
[3] - v2
[3]);
6806 max_abs_diff
= max(diff_x
, diff_y
);
6807 max_abs_diff
= max(diff_z
, max_abs_diff
);
6808 max_abs_diff
= max(diff_w
, max_abs_diff
);
6810 if (max_abs_diff
<= epsilon
)
6812 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6821 /* Sets the vertex components to the same value if they are within epsilon. */
6822 static BOOL
weld_component(void *to
, void *from
, D3DDECLTYPE type
, FLOAT epsilon
)
6824 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6825 BOOL fixme_once_unused
= FALSE
;
6826 BOOL fixme_once_unknown
= FALSE
;
6830 case D3DDECLTYPE_FLOAT1
:
6831 return weld_float1(to
, from
, epsilon
);
6833 case D3DDECLTYPE_FLOAT2
:
6834 return weld_float2(to
, from
, epsilon
);
6836 case D3DDECLTYPE_FLOAT3
:
6837 return weld_float3(to
, from
, epsilon
);
6839 case D3DDECLTYPE_FLOAT4
:
6840 return weld_float4(to
, from
, epsilon
);
6842 case D3DDECLTYPE_D3DCOLOR
:
6843 return weld_d3dcolor(to
, from
, epsilon
);
6845 case D3DDECLTYPE_UBYTE4
:
6846 return weld_ubyte4(to
, from
, epsilon
);
6848 case D3DDECLTYPE_SHORT2
:
6849 return weld_short2(to
, from
, epsilon
);
6851 case D3DDECLTYPE_SHORT4
:
6852 return weld_short4(to
, from
, epsilon
);
6854 case D3DDECLTYPE_UBYTE4N
:
6855 return weld_ubyte4n(to
, from
, epsilon
);
6857 case D3DDECLTYPE_SHORT2N
:
6858 return weld_short2n(to
, from
, epsilon
);
6860 case D3DDECLTYPE_SHORT4N
:
6861 return weld_short4n(to
, from
, epsilon
);
6863 case D3DDECLTYPE_USHORT2N
:
6864 return weld_ushort2n(to
, from
, epsilon
);
6866 case D3DDECLTYPE_USHORT4N
:
6867 return weld_ushort4n(to
, from
, epsilon
);
6869 case D3DDECLTYPE_UDEC3
:
6870 return weld_udec3(to
, from
, epsilon
);
6872 case D3DDECLTYPE_DEC3N
:
6873 return weld_dec3n(to
, from
, epsilon
);
6875 case D3DDECLTYPE_FLOAT16_2
:
6876 return weld_float16_2(to
, from
, epsilon
);
6878 case D3DDECLTYPE_FLOAT16_4
:
6879 return weld_float16_4(to
, from
, epsilon
);
6881 case D3DDECLTYPE_UNUSED
:
6882 if (!fixme_once_unused
++)
6883 FIXME("D3DDECLTYPE_UNUSED welding not implemented.\n");
6887 if (!fixme_once_unknown
++)
6888 FIXME("Welding of unknown declaration type %d is not implemented.\n", type
);
6895 static FLOAT
get_component_epsilon(const D3DVERTEXELEMENT9
*decl_ptr
, const D3DXWELDEPSILONS
*epsilons
)
6897 FLOAT epsilon
= 0.0f
;
6898 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6899 static BOOL fixme_once_blendindices
= FALSE
;
6900 static BOOL fixme_once_positiont
= FALSE
;
6901 static BOOL fixme_once_fog
= FALSE
;
6902 static BOOL fixme_once_depth
= FALSE
;
6903 static BOOL fixme_once_sample
= FALSE
;
6904 static BOOL fixme_once_unknown
= FALSE
;
6906 switch (decl_ptr
->Usage
)
6908 case D3DDECLUSAGE_POSITION
:
6909 epsilon
= epsilons
->Position
;
6911 case D3DDECLUSAGE_BLENDWEIGHT
:
6912 epsilon
= epsilons
->BlendWeights
;
6914 case D3DDECLUSAGE_NORMAL
:
6915 epsilon
= epsilons
->Normals
;
6917 case D3DDECLUSAGE_PSIZE
:
6918 epsilon
= epsilons
->PSize
;
6920 case D3DDECLUSAGE_TEXCOORD
:
6922 BYTE usage_index
= decl_ptr
->UsageIndex
;
6923 if (usage_index
> 7)
6925 epsilon
= epsilons
->Texcoords
[usage_index
];
6928 case D3DDECLUSAGE_TANGENT
:
6929 epsilon
= epsilons
->Tangent
;
6931 case D3DDECLUSAGE_BINORMAL
:
6932 epsilon
= epsilons
->Binormal
;
6934 case D3DDECLUSAGE_TESSFACTOR
:
6935 epsilon
= epsilons
->TessFactor
;
6937 case D3DDECLUSAGE_COLOR
:
6938 if (decl_ptr
->UsageIndex
== 0)
6939 epsilon
= epsilons
->Diffuse
;
6940 else if (decl_ptr
->UsageIndex
== 1)
6941 epsilon
= epsilons
->Specular
;
6945 case D3DDECLUSAGE_BLENDINDICES
:
6946 if (!fixme_once_blendindices
++)
6947 FIXME("D3DDECLUSAGE_BLENDINDICES welding not implemented.\n");
6949 case D3DDECLUSAGE_POSITIONT
:
6950 if (!fixme_once_positiont
++)
6951 FIXME("D3DDECLUSAGE_POSITIONT welding not implemented.\n");
6953 case D3DDECLUSAGE_FOG
:
6954 if (!fixme_once_fog
++)
6955 FIXME("D3DDECLUSAGE_FOG welding not implemented.\n");
6957 case D3DDECLUSAGE_DEPTH
:
6958 if (!fixme_once_depth
++)
6959 FIXME("D3DDECLUSAGE_DEPTH welding not implemented.\n");
6961 case D3DDECLUSAGE_SAMPLE
:
6962 if (!fixme_once_sample
++)
6963 FIXME("D3DDECLUSAGE_SAMPLE welding not implemented.\n");
6966 if (!fixme_once_unknown
++)
6967 FIXME("Unknown usage %x\n", decl_ptr
->Usage
);
6974 /* Helper function for reading a 32-bit index buffer. */
6975 static inline DWORD
read_ib(void *index_buffer
, BOOL indices_are_32bit
,
6978 if (indices_are_32bit
)
6980 DWORD
*indices
= index_buffer
;
6981 return indices
[index
];
6985 WORD
*indices
= index_buffer
;
6986 return indices
[index
];
6990 /* Helper function for writing to a 32-bit index buffer. */
6991 static inline void write_ib(void *index_buffer
, BOOL indices_are_32bit
,
6992 DWORD index
, DWORD value
)
6994 if (indices_are_32bit
)
6996 DWORD
*indices
= index_buffer
;
6997 indices
[index
] = value
;
7001 WORD
*indices
= index_buffer
;
7002 indices
[index
] = value
;
7006 /*************************************************************************
7007 * D3DXWeldVertices (D3DX9_36.@)
7009 * Welds together similar vertices. The similarity between vert-
7010 * ices can be the position and other components such as
7014 * mesh [I] Mesh which vertices will be welded together.
7015 * flags [I] D3DXWELDEPSILONSFLAGS specifying how to weld.
7016 * epsilons [I] How similar a component needs to be for welding.
7017 * adjacency [I] Which faces are adjacent to other faces.
7018 * adjacency_out [O] Updated adjacency after welding.
7019 * face_remap_out [O] Which faces the old faces have been mapped to.
7020 * vertex_remap_out [O] Which vertices the old vertices have been mapped to.
7024 * Failure: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
7027 * Attribute sorting not implemented.
7030 HRESULT WINAPI
D3DXWeldVertices(ID3DXMesh
*mesh
, DWORD flags
, const D3DXWELDEPSILONS
*epsilons
,
7031 const DWORD
*adjacency
, DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
7033 DWORD
*adjacency_generated
= NULL
;
7034 const DWORD
*adjacency_ptr
;
7035 DWORD
*attributes
= NULL
;
7036 const FLOAT DEFAULT_EPSILON
= 1.0e-6f
;
7039 void *indices
= NULL
;
7040 BOOL indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
7041 DWORD optimize_flags
;
7042 DWORD
*point_reps
= NULL
;
7043 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(mesh
);
7044 DWORD
*vertex_face_map
= NULL
;
7045 BYTE
*vertices
= NULL
;
7047 TRACE("mesh %p, flags %#lx, epsilons %p, adjacency %p, adjacency_out %p, face_remap_out %p, "
7048 "vertex_remap_out %p.\n",
7049 mesh
, flags
, epsilons
, adjacency
, adjacency_out
, face_remap_out
, vertex_remap_out
);
7053 WARN("No flags are undefined. Using D3DXWELDEPSILONS_WELDPARTIALMATCHES instead.\n");
7054 flags
= D3DXWELDEPSILONS_WELDPARTIALMATCHES
;
7057 if (adjacency
) /* Use supplied adjacency. */
7059 adjacency_ptr
= adjacency
;
7061 else /* Adjacency has to be generated. */
7063 adjacency_generated
= HeapAlloc(GetProcessHeap(), 0, 3 * This
->numfaces
* sizeof(*adjacency_generated
));
7064 if (!adjacency_generated
)
7066 ERR("Couldn't allocate memory for adjacency_generated.\n");
7070 hr
= mesh
->lpVtbl
->GenerateAdjacency(mesh
, DEFAULT_EPSILON
, adjacency_generated
);
7073 ERR("Couldn't generate adjacency.\n");
7076 adjacency_ptr
= adjacency_generated
;
7079 /* Point representation says which vertices can be replaced. */
7080 point_reps
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*point_reps
));
7084 ERR("Couldn't allocate memory for point_reps.\n");
7087 hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency_ptr
, point_reps
);
7090 ERR("ConvertAdjacencyToPointReps failed.\n");
7094 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
);
7097 ERR("Couldn't lock index buffer.\n");
7101 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, 0, &attributes
);
7104 ERR("Couldn't lock attribute buffer.\n");
7107 vertex_face_map
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*vertex_face_map
));
7108 if (!vertex_face_map
)
7111 ERR("Couldn't allocate memory for vertex_face_map.\n");
7114 /* Build vertex face map, so that a vertex's face can be looked up. */
7115 for (i
= 0; i
< This
->numfaces
; i
++)
7118 for (j
= 0; j
< 3; j
++)
7120 DWORD index
= read_ib(indices
, indices_are_32bit
, 3*i
+ j
);
7121 vertex_face_map
[index
] = i
;
7125 if (flags
& D3DXWELDEPSILONS_WELDPARTIALMATCHES
)
7127 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void**)&vertices
);
7130 ERR("Couldn't lock vertex buffer.\n");
7133 /* For each vertex that can be removed, compare its vertex components
7134 * with the vertex components from the vertex that can replace it. A
7135 * vertex is only fully replaced if all the components match and the
7136 * flag D3DXWELDEPSILONS_DONOTREMOVEVERTICES is not set, and they
7137 * belong to the same attribute group. Otherwise the vertex components
7138 * that are within epsilon are set to the same value.
7140 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
7142 D3DVERTEXELEMENT9
*decl_ptr
;
7143 DWORD vertex_size
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
7144 DWORD num_vertex_components
;
7147 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7149 for (decl_ptr
= This
->cached_declaration
, num_vertex_components
= 0; decl_ptr
->Stream
!= 0xFF; decl_ptr
++, num_vertex_components
++)
7151 BYTE
*to
= &vertices
[vertex_size
*index
+ decl_ptr
->Offset
];
7152 BYTE
*from
= &vertices
[vertex_size
*point_reps
[index
] + decl_ptr
->Offset
];
7153 FLOAT epsilon
= get_component_epsilon(decl_ptr
, epsilons
);
7155 /* Don't weld self */
7156 if (index
== point_reps
[index
])
7162 if (weld_component(to
, from
, decl_ptr
->Type
, epsilon
))
7166 all_match
= (num_vertex_components
== matches
);
7167 if (all_match
&& !(flags
& D3DXWELDEPSILONS_DONOTREMOVEVERTICES
))
7169 DWORD to_face
= vertex_face_map
[index
];
7170 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7171 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7173 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7176 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7179 else if (flags
& D3DXWELDEPSILONS_WELDALL
)
7181 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
7183 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7184 DWORD to_face
= vertex_face_map
[index
];
7185 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7186 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7188 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7191 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7193 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7196 /* Compact mesh using OptimizeInplace */
7197 optimize_flags
= D3DXMESHOPT_COMPACT
;
7198 hr
= mesh
->lpVtbl
->OptimizeInplace(mesh
, optimize_flags
, adjacency_ptr
, adjacency_out
, face_remap_out
, vertex_remap_out
);
7201 ERR("Couldn't compact mesh.\n");
7207 HeapFree(GetProcessHeap(), 0, adjacency_generated
);
7208 HeapFree(GetProcessHeap(), 0, point_reps
);
7209 HeapFree(GetProcessHeap(), 0, vertex_face_map
);
7210 if (attributes
) mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7211 if (indices
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7212 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7217 /*************************************************************************
7218 * D3DXOptimizeFaces (D3DX9_36.@)
7220 * Re-orders the faces so the vertex cache is used optimally.
7223 * indices [I] Pointer to an index buffer belonging to a mesh.
7224 * num_faces [I] Number of faces in the mesh.
7225 * num_vertices [I] Number of vertices in the mesh.
7226 * indices_are_32bit [I] Specifies whether indices are 32- or 16-bit.
7227 * face_remap [I/O] The new order the faces should be drawn in.
7231 * Failure: D3DERR_INVALIDCALL.
7234 * The face re-ordering does not use the vertex cache optimally.
7237 HRESULT WINAPI
D3DXOptimizeFaces(const void *indices
, UINT num_faces
,
7238 UINT num_vertices
, BOOL indices_are_32bit
, DWORD
*face_remap
)
7241 UINT j
= num_faces
- 1;
7242 UINT limit_16_bit
= 2 << 15; /* According to MSDN */
7243 HRESULT hr
= D3D_OK
;
7245 FIXME("indices %p, num_faces %u, num_vertices %u, indices_are_32bit %#x, face_remap %p semi-stub. "
7246 "Face order will not be optimal.\n",
7247 indices
, num_faces
, num_vertices
, indices_are_32bit
, face_remap
);
7249 if (!indices_are_32bit
&& num_faces
>= limit_16_bit
)
7251 WARN("Number of faces must be less than %d when using 16-bit indices.\n",
7253 hr
= D3DERR_INVALIDCALL
;
7259 WARN("Face remap pointer is NULL.\n");
7260 hr
= D3DERR_INVALIDCALL
;
7264 /* The faces are drawn in reverse order for simple meshes. This ordering
7265 * is not optimal for complicated meshes, but will not break anything
7266 * either. The ordering should be changed to take advantage of the vertex
7267 * cache on the graphics card.
7269 * TODO Re-order to take advantage of vertex cache.
7271 for (i
= 0; i
< num_faces
; i
++)
7273 face_remap
[i
] = j
--;
7282 static D3DXVECTOR3
*vertex_element_vec3(BYTE
*vertices
, const D3DVERTEXELEMENT9
*declaration
,
7283 DWORD vertex_stride
, DWORD index
)
7285 return (D3DXVECTOR3
*)(vertices
+ declaration
->Offset
+ index
* vertex_stride
);
7288 static D3DXVECTOR3
read_vec3(BYTE
*vertices
, const D3DVERTEXELEMENT9
*declaration
,
7289 DWORD vertex_stride
, DWORD index
)
7291 D3DXVECTOR3 vec3
= {0};
7292 const D3DXVECTOR3
*src
= vertex_element_vec3(vertices
, declaration
, vertex_stride
, index
);
7294 switch (declaration
->Type
)
7296 case D3DDECLTYPE_FLOAT1
:
7299 case D3DDECLTYPE_FLOAT2
:
7303 case D3DDECLTYPE_FLOAT3
:
7304 case D3DDECLTYPE_FLOAT4
:
7308 ERR("Cannot read vec3\n");
7315 /*************************************************************************
7316 * D3DXComputeTangentFrameEx (D3DX9_36.@)
7318 HRESULT WINAPI
D3DXComputeTangentFrameEx(ID3DXMesh
*mesh
, DWORD texture_in_semantic
, DWORD texture_in_index
,
7319 DWORD u_partial_out_semantic
, DWORD u_partial_out_index
, DWORD v_partial_out_semantic
,
7320 DWORD v_partial_out_index
, DWORD normal_out_semantic
, DWORD normal_out_index
, DWORD options
,
7321 const DWORD
*adjacency
, float partial_edge_threshold
, float singular_point_threshold
,
7322 float normal_edge_threshold
, ID3DXMesh
**mesh_out
, ID3DXBuffer
**vertex_mapping
)
7325 void *indices
= NULL
;
7326 BYTE
*vertices
= NULL
;
7327 DWORD
*point_reps
= NULL
;
7329 BOOL indices_are_32bit
;
7330 DWORD i
, j
, num_faces
, num_vertices
, vertex_stride
;
7331 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
7332 D3DVERTEXELEMENT9
*position_declaration
= NULL
, *normal_declaration
= NULL
;
7333 DWORD weighting_method
= options
& (D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
);
7335 TRACE("mesh %p, texture_in_semantic %lu, texture_in_index %lu, u_partial_out_semantic %lu, "
7336 "u_partial_out_index %lu, v_partial_out_semantic %lu, v_partial_out_index %lu, "
7337 "normal_out_semantic %lu, normal_out_index %lu, options %#lx, adjacency %p, "
7338 "partial_edge_threshold %.8e, singular_point_threshold %.8e, normal_edge_threshold %.8e, "
7339 "mesh_out %p, vertex_mapping %p.\n",
7340 mesh
, texture_in_semantic
, texture_in_index
, u_partial_out_semantic
, u_partial_out_index
,
7341 v_partial_out_semantic
, v_partial_out_index
, normal_out_semantic
, normal_out_index
,
7342 options
, adjacency
, partial_edge_threshold
, singular_point_threshold
,
7343 normal_edge_threshold
, mesh_out
, vertex_mapping
);
7347 WARN("mesh is NULL\n");
7348 return D3DERR_INVALIDCALL
;
7351 if (weighting_method
== (D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
))
7353 WARN("D3DXTANGENT_WEIGHT_BY_AREA and D3DXTANGENT_WEIGHT_EQUAL are mutally exclusive\n");
7354 return D3DERR_INVALIDCALL
;
7357 if (u_partial_out_semantic
!= D3DX_DEFAULT
)
7359 FIXME("tangent vectors computation is not supported\n");
7363 if (v_partial_out_semantic
!= D3DX_DEFAULT
)
7365 FIXME("binormal vectors computation is not supported\n");
7369 if (options
& ~(D3DXTANGENT_GENERATE_IN_PLACE
| D3DXTANGENT_CALCULATE_NORMALS
7370 | D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
))
7372 FIXME("Unsupported options %#lx.\n", options
);
7376 if (!(options
& D3DXTANGENT_CALCULATE_NORMALS
))
7378 FIXME("only normals computation is supported\n");
7382 if (!(options
& D3DXTANGENT_GENERATE_IN_PLACE
) || mesh_out
|| vertex_mapping
)
7384 FIXME("only D3DXTANGENT_GENERATE_IN_PLACE is supported\n");
7388 if (FAILED(hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, declaration
)))
7391 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
7393 if (declaration
[i
].Usage
== D3DDECLUSAGE_POSITION
&& !declaration
[i
].UsageIndex
)
7394 position_declaration
= &declaration
[i
];
7395 if (declaration
[i
].Usage
== normal_out_semantic
&& declaration
[i
].UsageIndex
== normal_out_index
)
7396 normal_declaration
= &declaration
[i
];
7399 if (!position_declaration
|| !normal_declaration
)
7400 return D3DERR_INVALIDCALL
;
7402 if (normal_declaration
->Type
== D3DDECLTYPE_FLOAT3
)
7404 normal_size
= sizeof(D3DXVECTOR3
);
7406 else if (normal_declaration
->Type
== D3DDECLTYPE_FLOAT4
)
7408 normal_size
= sizeof(D3DXVECTOR4
);
7412 WARN("unsupported normals type %u\n", normal_declaration
->Type
);
7413 return D3DERR_INVALIDCALL
;
7416 num_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
7417 num_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
7418 vertex_stride
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
7419 indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
7421 point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*point_reps
));
7430 if (FAILED(hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency
, point_reps
)))
7435 for (i
= 0; i
< num_vertices
; i
++)
7439 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
)))
7442 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
7445 for (i
= 0; i
< num_vertices
; i
++)
7447 static const D3DXVECTOR4 default_vector
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
7448 void *normal
= vertices
+ normal_declaration
->Offset
+ i
* vertex_stride
;
7450 memcpy(normal
, &default_vector
, normal_size
);
7453 for (i
= 0; i
< num_faces
; i
++)
7455 float denominator
, weights
[3];
7456 D3DXVECTOR3 a
, b
, cross
, face_normal
;
7457 const DWORD face_indices
[3] =
7459 read_ib(indices
, indices_are_32bit
, 3 * i
+ 0),
7460 read_ib(indices
, indices_are_32bit
, 3 * i
+ 1),
7461 read_ib(indices
, indices_are_32bit
, 3 * i
+ 2)
7463 const D3DXVECTOR3 v0
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[0]);
7464 const D3DXVECTOR3 v1
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[1]);
7465 const D3DXVECTOR3 v2
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[2]);
7467 D3DXVec3Cross(&cross
, D3DXVec3Subtract(&a
, &v0
, &v1
), D3DXVec3Subtract(&b
, &v0
, &v2
));
7469 switch (weighting_method
)
7471 case D3DXTANGENT_WEIGHT_EQUAL
:
7472 weights
[0] = weights
[1] = weights
[2] = 1.0f
;
7474 case D3DXTANGENT_WEIGHT_BY_AREA
:
7475 weights
[0] = weights
[1] = weights
[2] = D3DXVec3Length(&cross
);
7478 /* weight by angle */
7479 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7483 weights
[0] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7485 D3DXVec3Subtract(&a
, &v1
, &v0
);
7486 D3DXVec3Subtract(&b
, &v1
, &v2
);
7487 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7491 weights
[1] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7493 D3DXVec3Subtract(&a
, &v2
, &v0
);
7494 D3DXVec3Subtract(&b
, &v2
, &v1
);
7495 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7499 weights
[2] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7504 D3DXVec3Normalize(&face_normal
, &cross
);
7506 for (j
= 0; j
< 3; j
++)
7509 DWORD rep_index
= point_reps
[face_indices
[j
]];
7510 D3DXVECTOR3
*rep_normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, rep_index
);
7512 D3DXVec3Scale(&normal
, &face_normal
, weights
[j
]);
7513 D3DXVec3Add(rep_normal
, rep_normal
, &normal
);
7517 for (i
= 0; i
< num_vertices
; i
++)
7519 DWORD rep_index
= point_reps
[i
];
7520 D3DXVECTOR3
*normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, i
);
7521 D3DXVECTOR3
*rep_normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, rep_index
);
7524 D3DXVec3Normalize(rep_normal
, rep_normal
);
7526 *normal
= *rep_normal
;
7533 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7536 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7538 HeapFree(GetProcessHeap(), 0, point_reps
);
7543 /*************************************************************************
7544 * D3DXComputeNormals (D3DX9_36.@)
7546 HRESULT WINAPI
D3DXComputeNormals(struct ID3DXBaseMesh
*mesh
, const DWORD
*adjacency
)
7548 TRACE("mesh %p, adjacency %p\n", mesh
, adjacency
);
7550 if (mesh
&& (ID3DXMeshVtbl
*)mesh
->lpVtbl
!= &D3DXMesh_Vtbl
)
7552 ERR("Invalid virtual table\n");
7553 return D3DERR_INVALIDCALL
;
7556 return D3DXComputeTangentFrameEx((ID3DXMesh
*)mesh
, D3DX_DEFAULT
, 0,
7557 D3DX_DEFAULT
, 0, D3DX_DEFAULT
, 0, D3DDECLUSAGE_NORMAL
, 0,
7558 D3DXTANGENT_GENERATE_IN_PLACE
| D3DXTANGENT_CALCULATE_NORMALS
,
7559 adjacency
, -1.01f
, -0.01f
, -1.01f
, NULL
, NULL
);
7562 /*************************************************************************
7563 * D3DXIntersect (D3DX9_36.@)
7565 HRESULT WINAPI
D3DXIntersect(ID3DXBaseMesh
*mesh
, const D3DXVECTOR3
*ray_pos
, const D3DXVECTOR3
*ray_dir
,
7566 BOOL
*hit
, DWORD
*face_index
, float *u
, float *v
, float *distance
, ID3DXBuffer
**all_hits
, DWORD
*count_of_hits
)
7568 FIXME("mesh %p, ray_pos %p, ray_dir %p, hit %p, face_index %p, u %p, v %p, distance %p, all_hits %p, "
7569 "count_of_hits %p stub!\n", mesh
, ray_pos
, ray_dir
, hit
, face_index
, u
, v
, distance
, all_hits
, count_of_hits
);
7574 HRESULT WINAPI
D3DXTessellateNPatches(ID3DXMesh
*mesh
, const DWORD
*adjacency_in
, float num_segs
,
7575 BOOL quadratic_normals
, ID3DXMesh
**mesh_out
, ID3DXBuffer
**adjacency_out
)
7577 FIXME("mesh %p, adjacency_in %p, num_segs %f, quadratic_normals %d, mesh_out %p, adjacency_out %p stub.\n",
7578 mesh
, adjacency_in
, num_segs
, quadratic_normals
, mesh_out
, adjacency_out
);
7583 HRESULT WINAPI
D3DXConvertMeshSubsetToSingleStrip(struct ID3DXBaseMesh
*mesh_in
, DWORD attribute_id
,
7584 DWORD ib_flags
, struct IDirect3DIndexBuffer9
**index_buffer
, DWORD
*index_count
)
7586 FIXME("mesh_in %p, attribute_id %lu, ib_flags %#lx, index_buffer %p, index_count %p stub.\n",
7587 mesh_in
, attribute_id
, ib_flags
, index_buffer
, index_count
);
7598 static BOOL
queue_frame_node(struct list
*queue
, D3DXFRAME
*frame
)
7600 struct frame_node
*node
;
7602 if (!frame
->pFrameFirstChild
)
7605 node
= HeapAlloc(GetProcessHeap(), 0, sizeof(*node
));
7609 node
->frame
= frame
;
7610 list_add_tail(queue
, &node
->entry
);
7615 static void empty_frame_queue(struct list
*queue
)
7617 struct frame_node
*cur
, *cur2
;
7618 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, queue
, struct frame_node
, entry
)
7620 list_remove(&cur
->entry
);
7621 HeapFree(GetProcessHeap(), 0, cur
);
7625 D3DXFRAME
* WINAPI
D3DXFrameFind(const D3DXFRAME
*root
, const char *name
)
7627 D3DXFRAME
*found
= NULL
, *frame
;
7630 TRACE("root frame %p, name %s.\n", root
, debugstr_a(name
));
7637 frame
= (D3DXFRAME
*)root
;
7641 struct frame_node
*node
;
7645 if ((name
&& frame
->Name
&& !strcmp(frame
->Name
, name
)) || (!name
&& !frame
->Name
))
7651 if (!queue_frame_node(&queue
, frame
))
7654 frame
= frame
->pFrameSibling
;
7657 if (list_empty(&queue
))
7660 node
= LIST_ENTRY(list_head(&queue
), struct frame_node
, entry
);
7661 list_remove(&node
->entry
);
7662 frame
= node
->frame
->pFrameFirstChild
;
7663 HeapFree(GetProcessHeap(), 0, node
);
7667 empty_frame_queue(&queue
);