2 * Mesh operations specific to D3DX9.
4 * Copyright (C) 2005 Henri Verbeet
5 * Copyright (C) 2006 Ivan Gyurdiev
6 * Copyright (C) 2009 David Adam
7 * Copyright (C) 2010 Tony Wasserka
8 * Copyright (C) 2011 Dylan Smith
9 * Copyright (C) 2011 Michael Mc Donnell
10 * Copyright (C) 2013 Christian Costa
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
35 #include "d3dx9_private.h"
40 #include "wine/unicode.h"
41 #include "wine/list.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
47 ID3DXMesh ID3DXMesh_iface
;
54 IDirect3DDevice9
*device
;
55 D3DVERTEXELEMENT9 cached_declaration
[MAX_FVF_DECL_SIZE
];
56 IDirect3DVertexDeclaration9
*vertex_declaration
;
57 UINT vertex_declaration_size
;
59 IDirect3DVertexBuffer9
*vertex_buffer
;
60 IDirect3DIndexBuffer9
*index_buffer
;
62 int attrib_buffer_lock_count
;
63 DWORD attrib_table_size
;
64 D3DXATTRIBUTERANGE
*attrib_table
;
67 static const UINT d3dx_decltype_size
[] =
69 /* D3DDECLTYPE_FLOAT1 */ sizeof(FLOAT
),
70 /* D3DDECLTYPE_FLOAT2 */ sizeof(D3DXVECTOR2
),
71 /* D3DDECLTYPE_FLOAT3 */ sizeof(D3DXVECTOR3
),
72 /* D3DDECLTYPE_FLOAT4 */ sizeof(D3DXVECTOR4
),
73 /* D3DDECLTYPE_D3DCOLOR */ sizeof(D3DCOLOR
),
74 /* D3DDECLTYPE_UBYTE4 */ 4 * sizeof(BYTE
),
75 /* D3DDECLTYPE_SHORT2 */ 2 * sizeof(SHORT
),
76 /* D3DDECLTYPE_SHORT4 */ 4 * sizeof(SHORT
),
77 /* D3DDECLTYPE_UBYTE4N */ 4 * sizeof(BYTE
),
78 /* D3DDECLTYPE_SHORT2N */ 2 * sizeof(SHORT
),
79 /* D3DDECLTYPE_SHORT4N */ 4 * sizeof(SHORT
),
80 /* D3DDECLTYPE_USHORT2N */ 2 * sizeof(USHORT
),
81 /* D3DDECLTYPE_USHORT4N */ 4 * sizeof(USHORT
),
82 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
83 /* D3DDECLTYPE_DEC3N */ 4,
84 /* D3DDECLTYPE_FLOAT16_2 */ 2 * sizeof(D3DXFLOAT16
),
85 /* D3DDECLTYPE_FLOAT16_4 */ 4 * sizeof(D3DXFLOAT16
),
88 static inline struct d3dx9_mesh
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
90 return CONTAINING_RECORD(iface
, struct d3dx9_mesh
, ID3DXMesh_iface
);
93 static HRESULT WINAPI
d3dx9_mesh_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, void **out
)
95 TRACE("iface %p, riid %s, out %p.\n", iface
, debugstr_guid(riid
), out
);
97 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
98 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
99 IsEqualGUID(riid
, &IID_ID3DXMesh
))
101 iface
->lpVtbl
->AddRef(iface
);
106 WARN("Interface %s not found.\n", debugstr_guid(riid
));
108 return E_NOINTERFACE
;
111 static ULONG WINAPI
d3dx9_mesh_AddRef(ID3DXMesh
*iface
)
113 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
114 ULONG refcount
= InterlockedIncrement(&mesh
->ref
);
116 TRACE("%p increasing refcount to %u.\n", mesh
, refcount
);
121 static ULONG WINAPI
d3dx9_mesh_Release(ID3DXMesh
*iface
)
123 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
124 ULONG refcount
= InterlockedDecrement(&mesh
->ref
);
126 TRACE("%p decreasing refcount to %u.\n", mesh
, refcount
);
130 IDirect3DIndexBuffer9_Release(mesh
->index_buffer
);
131 IDirect3DVertexBuffer9_Release(mesh
->vertex_buffer
);
132 if (mesh
->vertex_declaration
)
133 IDirect3DVertexDeclaration9_Release(mesh
->vertex_declaration
);
134 IDirect3DDevice9_Release(mesh
->device
);
135 HeapFree(GetProcessHeap(), 0, mesh
->attrib_buffer
);
136 HeapFree(GetProcessHeap(), 0, mesh
->attrib_table
);
137 HeapFree(GetProcessHeap(), 0, mesh
);
143 static HRESULT WINAPI
d3dx9_mesh_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
145 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
151 TRACE("iface %p, attrib_id %u.\n", iface
, attrib_id
);
153 if (!This
->vertex_declaration
)
155 WARN("Can't draw a mesh with an invalid vertex declaration.\n");
159 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
161 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
162 if (FAILED(hr
)) return hr
;
163 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
164 if (FAILED(hr
)) return hr
;
165 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
166 if (FAILED(hr
)) return hr
;
168 while (face_end
< This
->numfaces
)
170 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
172 if (This
->attrib_buffer
[face_start
] == attrib_id
)
175 if (face_start
>= This
->numfaces
)
177 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
179 if (This
->attrib_buffer
[face_end
] != attrib_id
)
183 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
184 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
185 if (FAILED(hr
)) return hr
;
191 static DWORD WINAPI
d3dx9_mesh_GetNumFaces(ID3DXMesh
*iface
)
193 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
195 TRACE("iface %p.\n", iface
);
197 return mesh
->numfaces
;
200 static DWORD WINAPI
d3dx9_mesh_GetNumVertices(ID3DXMesh
*iface
)
202 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
204 TRACE("iface %p.\n", iface
);
206 return mesh
->numvertices
;
209 static DWORD WINAPI
d3dx9_mesh_GetFVF(ID3DXMesh
*iface
)
211 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
213 TRACE("iface %p.\n", iface
);
218 static void copy_declaration(D3DVERTEXELEMENT9
*dst
, const D3DVERTEXELEMENT9
*src
, UINT num_elem
)
220 memcpy(dst
, src
, num_elem
* sizeof(*src
));
223 static HRESULT WINAPI
d3dx9_mesh_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
225 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
227 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
230 return D3DERR_INVALIDCALL
;
232 copy_declaration(declaration
, mesh
->cached_declaration
, mesh
->num_elem
);
237 static DWORD WINAPI
d3dx9_mesh_GetNumBytesPerVertex(ID3DXMesh
*iface
)
239 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
241 TRACE("iface %p.\n", iface
);
243 return mesh
->vertex_declaration_size
;
246 static DWORD WINAPI
d3dx9_mesh_GetOptions(ID3DXMesh
*iface
)
248 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
250 TRACE("iface %p.\n", iface
);
252 return mesh
->options
;
255 static HRESULT WINAPI
d3dx9_mesh_GetDevice(struct ID3DXMesh
*iface
, struct IDirect3DDevice9
**device
)
257 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
259 TRACE("iface %p, device %p.\n", iface
, device
);
262 return D3DERR_INVALIDCALL
;
263 *device
= mesh
->device
;
264 IDirect3DDevice9_AddRef(mesh
->device
);
269 static HRESULT WINAPI
d3dx9_mesh_CloneMeshFVF(struct ID3DXMesh
*iface
, DWORD options
, DWORD fvf
,
270 struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh
)
273 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
275 TRACE("iface %p, options %#x, fvf %#x, device %p, clone_mesh %p.\n",
276 iface
, options
, fvf
, device
, clone_mesh
);
278 if (FAILED(hr
= D3DXDeclaratorFromFVF(fvf
, declaration
)))
281 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
284 static FLOAT
scale_clamp_ubyten(FLOAT value
)
286 value
= value
* UCHAR_MAX
;
294 if (value
> UCHAR_MAX
) /* Clamp at 255 */
301 static FLOAT
scale_clamp_shortn(FLOAT value
)
303 value
= value
* SHRT_MAX
;
305 /* The tests show that the range is SHRT_MIN + 1 to SHRT_MAX. */
306 if (value
<= SHRT_MIN
)
310 else if (value
> SHRT_MAX
)
320 static FLOAT
scale_clamp_ushortn(FLOAT value
)
322 value
= value
* USHRT_MAX
;
330 if (value
> USHRT_MAX
) /* Clamp at 65535 */
337 static INT
simple_round(FLOAT value
)
339 int res
= (INT
)(value
+ 0.5f
);
344 static void convert_float4(BYTE
*dst
, const D3DXVECTOR4
*src
, D3DDECLTYPE type_dst
)
346 BOOL fixme_once
= FALSE
;
350 case D3DDECLTYPE_FLOAT1
:
352 FLOAT
*dst_ptr
= (FLOAT
*)dst
;
356 case D3DDECLTYPE_FLOAT2
:
358 D3DXVECTOR2
*dst_ptr
= (D3DXVECTOR2
*)dst
;
363 case D3DDECLTYPE_FLOAT3
:
365 D3DXVECTOR3
*dst_ptr
= (D3DXVECTOR3
*)dst
;
371 case D3DDECLTYPE_FLOAT4
:
373 D3DXVECTOR4
*dst_ptr
= (D3DXVECTOR4
*)dst
;
380 case D3DDECLTYPE_D3DCOLOR
:
382 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
383 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
384 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
385 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
388 case D3DDECLTYPE_UBYTE4
:
390 dst
[0] = src
->x
< 0.0f
? 0 : (BYTE
)simple_round(src
->x
);
391 dst
[1] = src
->y
< 0.0f
? 0 : (BYTE
)simple_round(src
->y
);
392 dst
[2] = src
->z
< 0.0f
? 0 : (BYTE
)simple_round(src
->z
);
393 dst
[3] = src
->w
< 0.0f
? 0 : (BYTE
)simple_round(src
->w
);
396 case D3DDECLTYPE_SHORT2
:
398 SHORT
*dst_ptr
= (SHORT
*)dst
;
399 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
400 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
403 case D3DDECLTYPE_SHORT4
:
405 SHORT
*dst_ptr
= (SHORT
*)dst
;
406 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
407 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
408 dst_ptr
[2] = (SHORT
)simple_round(src
->z
);
409 dst_ptr
[3] = (SHORT
)simple_round(src
->w
);
412 case D3DDECLTYPE_UBYTE4N
:
414 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
415 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
416 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
417 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
420 case D3DDECLTYPE_SHORT2N
:
422 SHORT
*dst_ptr
= (SHORT
*)dst
;
423 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
424 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
427 case D3DDECLTYPE_SHORT4N
:
429 SHORT
*dst_ptr
= (SHORT
*)dst
;
430 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
431 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
432 dst_ptr
[2] = (SHORT
)simple_round(scale_clamp_shortn(src
->z
));
433 dst_ptr
[3] = (SHORT
)simple_round(scale_clamp_shortn(src
->w
));
436 case D3DDECLTYPE_USHORT2N
:
438 USHORT
*dst_ptr
= (USHORT
*)dst
;
439 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
440 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
443 case D3DDECLTYPE_USHORT4N
:
445 USHORT
*dst_ptr
= (USHORT
*)dst
;
446 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
447 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
448 dst_ptr
[2] = (USHORT
)simple_round(scale_clamp_ushortn(src
->z
));
449 dst_ptr
[3] = (USHORT
)simple_round(scale_clamp_ushortn(src
->w
));
452 case D3DDECLTYPE_FLOAT16_2
:
454 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 2);
457 case D3DDECLTYPE_FLOAT16_4
:
459 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 4);
464 FIXME("Conversion from D3DDECLTYPE_FLOAT4 to %d not implemented.\n", type_dst
);
469 static void convert_component(BYTE
*dst
, BYTE
*src
, D3DDECLTYPE type_dst
, D3DDECLTYPE type_src
)
471 BOOL fixme_once
= FALSE
;
475 case D3DDECLTYPE_FLOAT1
:
477 FLOAT
*src_ptr
= (FLOAT
*)src
;
478 D3DXVECTOR4 src_float4
= {*src_ptr
, 0.0f
, 0.0f
, 1.0f
};
479 convert_float4(dst
, &src_float4
, type_dst
);
482 case D3DDECLTYPE_FLOAT2
:
484 D3DXVECTOR2
*src_ptr
= (D3DXVECTOR2
*)src
;
485 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, 0.0f
, 1.0f
};
486 convert_float4(dst
, &src_float4
, type_dst
);
489 case D3DDECLTYPE_FLOAT3
:
491 D3DXVECTOR3
*src_ptr
= (D3DXVECTOR3
*)src
;
492 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, 1.0f
};
493 convert_float4(dst
, &src_float4
, type_dst
);
496 case D3DDECLTYPE_FLOAT4
:
498 D3DXVECTOR4
*src_ptr
= (D3DXVECTOR4
*)src
;
499 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, src_ptr
->w
};
500 convert_float4(dst
, &src_float4
, type_dst
);
503 case D3DDECLTYPE_D3DCOLOR
:
505 D3DXVECTOR4 src_float4
=
507 (FLOAT
)src
[2]/UCHAR_MAX
,
508 (FLOAT
)src
[1]/UCHAR_MAX
,
509 (FLOAT
)src
[0]/UCHAR_MAX
,
510 (FLOAT
)src
[3]/UCHAR_MAX
512 convert_float4(dst
, &src_float4
, type_dst
);
515 case D3DDECLTYPE_UBYTE4
:
517 D3DXVECTOR4 src_float4
= {src
[0], src
[1], src
[2], src
[3]};
518 convert_float4(dst
, &src_float4
, type_dst
);
521 case D3DDECLTYPE_SHORT2
:
523 SHORT
*src_ptr
= (SHORT
*)src
;
524 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], 0.0f
, 1.0f
};
525 convert_float4(dst
, &src_float4
, type_dst
);
528 case D3DDECLTYPE_SHORT4
:
530 SHORT
*src_ptr
= (SHORT
*)src
;
531 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], src_ptr
[2], src_ptr
[3]};
532 convert_float4(dst
, &src_float4
, type_dst
);
535 case D3DDECLTYPE_UBYTE4N
:
537 D3DXVECTOR4 src_float4
=
539 (FLOAT
)src
[0]/UCHAR_MAX
,
540 (FLOAT
)src
[1]/UCHAR_MAX
,
541 (FLOAT
)src
[2]/UCHAR_MAX
,
542 (FLOAT
)src
[3]/UCHAR_MAX
544 convert_float4(dst
, &src_float4
, type_dst
);
547 case D3DDECLTYPE_SHORT2N
:
549 SHORT
*src_ptr
= (SHORT
*)src
;
550 D3DXVECTOR4 src_float4
= {(FLOAT
)src_ptr
[0]/SHRT_MAX
, (FLOAT
)src_ptr
[1]/SHRT_MAX
, 0.0f
, 1.0f
};
551 convert_float4(dst
, &src_float4
, type_dst
);
554 case D3DDECLTYPE_SHORT4N
:
556 SHORT
*src_ptr
= (SHORT
*)src
;
557 D3DXVECTOR4 src_float4
=
559 (FLOAT
)src_ptr
[0]/SHRT_MAX
,
560 (FLOAT
)src_ptr
[1]/SHRT_MAX
,
561 (FLOAT
)src_ptr
[2]/SHRT_MAX
,
562 (FLOAT
)src_ptr
[3]/SHRT_MAX
564 convert_float4(dst
, &src_float4
, type_dst
);
567 case D3DDECLTYPE_FLOAT16_2
:
569 D3DXVECTOR4 src_float4
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
570 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 2);
571 convert_float4(dst
, &src_float4
, type_dst
);
574 case D3DDECLTYPE_FLOAT16_4
:
576 D3DXVECTOR4 src_float4
;
577 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 4);
578 convert_float4(dst
, &src_float4
, type_dst
);
583 FIXME("Conversion of D3DDECLTYPE %d to %d not implemented.\n", type_src
, type_dst
);
588 static INT
get_equivalent_declaration_index(D3DVERTEXELEMENT9 orig_declaration
, D3DVERTEXELEMENT9
*declaration
)
592 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
594 if (orig_declaration
.Usage
== declaration
[i
].Usage
595 && orig_declaration
.UsageIndex
== declaration
[i
].UsageIndex
)
604 static HRESULT
convert_vertex_buffer(ID3DXMesh
*mesh_dst
, ID3DXMesh
*mesh_src
)
607 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
608 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
612 UINT num_vertices
= mesh_src
->lpVtbl
->GetNumVertices(mesh_src
);
613 UINT dst_vertex_size
= mesh_dst
->lpVtbl
->GetNumBytesPerVertex(mesh_dst
);
614 UINT src_vertex_size
= mesh_src
->lpVtbl
->GetNumBytesPerVertex(mesh_src
);
616 hr
= mesh_src
->lpVtbl
->GetDeclaration(mesh_src
, orig_declaration
);
617 if (FAILED(hr
)) return hr
;
618 hr
= mesh_dst
->lpVtbl
->GetDeclaration(mesh_dst
, declaration
);
619 if (FAILED(hr
)) return hr
;
621 hr
= mesh_src
->lpVtbl
->LockVertexBuffer(mesh_src
, D3DLOCK_READONLY
, (void**)&vb_src
);
622 if (FAILED(hr
)) goto cleanup
;
623 hr
= mesh_dst
->lpVtbl
->LockVertexBuffer(mesh_dst
, 0, (void**)&vb_dst
);
624 if (FAILED(hr
)) goto cleanup
;
626 /* Clear all new fields by clearing the entire vertex buffer. */
627 memset(vb_dst
, 0, num_vertices
* dst_vertex_size
);
629 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++)
631 INT eq_idx
= get_equivalent_declaration_index(orig_declaration
[i
], declaration
);
636 for (j
= 0; j
< num_vertices
; j
++)
638 UINT idx_dst
= dst_vertex_size
* j
+ declaration
[eq_idx
].Offset
;
639 UINT idx_src
= src_vertex_size
* j
+ orig_declaration
[i
].Offset
;
640 UINT type_size
= d3dx_decltype_size
[orig_declaration
[i
].Type
];
642 if (orig_declaration
[i
].Type
== declaration
[eq_idx
].Type
)
643 memcpy(&vb_dst
[idx_dst
], &vb_src
[idx_src
], type_size
);
645 convert_component(&vb_dst
[idx_dst
], &vb_src
[idx_src
], declaration
[eq_idx
].Type
, orig_declaration
[i
].Type
);
652 if (vb_dst
) mesh_dst
->lpVtbl
->UnlockVertexBuffer(mesh_dst
);
653 if (vb_src
) mesh_src
->lpVtbl
->UnlockVertexBuffer(mesh_src
);
658 static BOOL
declaration_equals(const D3DVERTEXELEMENT9
*declaration1
, const D3DVERTEXELEMENT9
*declaration2
)
660 UINT size1
= 0, size2
= 0;
662 /* Find the size of each declaration */
663 while (declaration1
[size1
].Stream
!= 0xff) size1
++;
664 while (declaration2
[size2
].Stream
!= 0xff) size2
++;
666 /* If not same size then they are definitely not equal */
670 /* Check that all components are the same */
671 if (memcmp(declaration1
, declaration2
, size1
*sizeof(*declaration1
)) == 0)
677 static HRESULT WINAPI
d3dx9_mesh_CloneMesh(struct ID3DXMesh
*iface
, DWORD options
,
678 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh_out
)
680 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
681 struct d3dx9_mesh
*cloned_this
;
682 ID3DXMesh
*clone_mesh
;
683 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
684 void *data_in
, *data_out
;
687 BOOL same_declaration
;
689 TRACE("iface %p, options %#x, declaration %p, device %p, clone_mesh_out %p.\n",
690 iface
, options
, declaration
, device
, clone_mesh_out
);
693 return D3DERR_INVALIDCALL
;
695 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
696 if (FAILED(hr
)) return hr
;
698 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
699 declaration
, device
, &clone_mesh
);
700 if (FAILED(hr
)) return hr
;
702 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
703 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
704 same_declaration
= declaration_equals(declaration
, orig_declaration
);
706 if (options
& D3DXMESH_VB_SHARE
) {
707 if (!same_declaration
) {
708 hr
= D3DERR_INVALIDCALL
;
711 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
712 /* FIXME: refactor to avoid creating a new vertex buffer */
713 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
714 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
715 } else if (same_declaration
) {
716 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
717 if (FAILED(hr
)) goto error
;
718 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, 0, &data_out
);
720 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
723 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
724 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
725 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
727 hr
= convert_vertex_buffer(clone_mesh
, iface
);
728 if (FAILED(hr
)) goto error
;
731 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
732 if (FAILED(hr
)) goto error
;
733 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, 0, &data_out
);
735 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
738 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
740 if (options
& D3DXMESH_32BIT
) {
741 for (i
= 0; i
< This
->numfaces
* 3; i
++)
742 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
744 for (i
= 0; i
< This
->numfaces
* 3; i
++)
745 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
748 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
750 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
751 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
753 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
755 if (This
->attrib_table_size
)
757 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
758 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
759 if (!cloned_this
->attrib_table
) {
763 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
766 *clone_mesh_out
= clone_mesh
;
770 IUnknown_Release(clone_mesh
);
774 static HRESULT WINAPI
d3dx9_mesh_GetVertexBuffer(struct ID3DXMesh
*iface
,
775 struct IDirect3DVertexBuffer9
**vertex_buffer
)
777 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
779 TRACE("iface %p, vertex_buffer %p.\n", iface
, vertex_buffer
);
782 return D3DERR_INVALIDCALL
;
783 *vertex_buffer
= mesh
->vertex_buffer
;
784 IDirect3DVertexBuffer9_AddRef(mesh
->vertex_buffer
);
789 static HRESULT WINAPI
d3dx9_mesh_GetIndexBuffer(struct ID3DXMesh
*iface
,
790 struct IDirect3DIndexBuffer9
**index_buffer
)
792 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
794 TRACE("iface %p, index_buffer %p.\n", iface
, index_buffer
);
797 return D3DERR_INVALIDCALL
;
798 *index_buffer
= mesh
->index_buffer
;
799 IDirect3DIndexBuffer9_AddRef(mesh
->index_buffer
);
804 static HRESULT WINAPI
d3dx9_mesh_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
806 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
808 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
810 return IDirect3DVertexBuffer9_Lock(mesh
->vertex_buffer
, 0, 0, data
, flags
);
813 static HRESULT WINAPI
d3dx9_mesh_UnlockVertexBuffer(ID3DXMesh
*iface
)
815 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
817 TRACE("iface %p.\n", iface
);
819 return IDirect3DVertexBuffer9_Unlock(mesh
->vertex_buffer
);
822 static HRESULT WINAPI
d3dx9_mesh_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
824 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
826 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
828 return IDirect3DIndexBuffer9_Lock(mesh
->index_buffer
, 0, 0, data
, flags
);
831 static HRESULT WINAPI
d3dx9_mesh_UnlockIndexBuffer(ID3DXMesh
*iface
)
833 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
835 TRACE("iface %p.\n", iface
);
837 return IDirect3DIndexBuffer9_Unlock(mesh
->index_buffer
);
840 /* FIXME: This looks just wrong, we never check *attrib_table_size before
841 * copying the data. */
842 static HRESULT WINAPI
d3dx9_mesh_GetAttributeTable(ID3DXMesh
*iface
,
843 D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
845 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
847 TRACE("iface %p, attrib_table %p, attrib_table_size %p.\n",
848 iface
, attrib_table
, attrib_table_size
);
850 if (attrib_table_size
)
851 *attrib_table_size
= mesh
->attrib_table_size
;
854 memcpy(attrib_table
, mesh
->attrib_table
, mesh
->attrib_table_size
* sizeof(*attrib_table
));
869 struct edge_face
*entries
;
872 /* Builds up a map of which face a new edge belongs to. That way the adjacency
873 * of another edge can be looked up. An edge has an adjacent face if there
874 * is an edge going in the opposite direction in the map. For example if the
875 * edge (v1, v2) belongs to face 4, and there is a mapping (v2, v1)->7, then
876 * face 4 and 7 are adjacent.
878 * Each edge might have been replaced with another edge, or none at all. There
879 * is at most one edge to face mapping, i.e. an edge can only belong to one
882 static HRESULT
init_edge_face_map(struct edge_face_map
*edge_face_map
, const DWORD
*index_buffer
,
883 const DWORD
*point_reps
, DWORD num_faces
)
888 edge_face_map
->lists
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->lists
));
889 if (!edge_face_map
->lists
) return E_OUTOFMEMORY
;
891 edge_face_map
->entries
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->entries
));
892 if (!edge_face_map
->entries
) return E_OUTOFMEMORY
;
895 /* Initialize all lists */
896 for (i
= 0; i
< 3 * num_faces
; i
++)
898 list_init(&edge_face_map
->lists
[i
]);
900 /* Build edge face mapping */
901 for (face
= 0; face
< num_faces
; face
++)
903 for (edge
= 0; edge
< 3; edge
++)
905 DWORD v1
= index_buffer
[3*face
+ edge
];
906 DWORD v2
= index_buffer
[3*face
+ (edge
+1)%3];
907 DWORD new_v1
= point_reps
[v1
]; /* What v1 has been replaced with */
908 DWORD new_v2
= point_reps
[v2
];
910 if (v1
!= v2
) /* Only map non-collapsed edges */
913 edge_face_map
->entries
[i
].v2
= new_v2
;
914 edge_face_map
->entries
[i
].face
= face
;
915 list_add_head(&edge_face_map
->lists
[new_v1
], &edge_face_map
->entries
[i
].entry
);
923 static DWORD
find_adjacent_face(struct edge_face_map
*edge_face_map
, DWORD vertex1
, DWORD vertex2
, DWORD num_faces
)
925 struct edge_face
*edge_face_ptr
;
927 LIST_FOR_EACH_ENTRY(edge_face_ptr
, &edge_face_map
->lists
[vertex2
], struct edge_face
, entry
)
929 if (edge_face_ptr
->v2
== vertex1
)
930 return edge_face_ptr
->face
;
936 static DWORD
*generate_identity_point_reps(DWORD num_vertices
)
938 DWORD
*id_point_reps
;
941 id_point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*id_point_reps
));
945 for (i
= 0; i
< num_vertices
; i
++)
947 id_point_reps
[i
] = i
;
950 return id_point_reps
;
953 static HRESULT WINAPI
d3dx9_mesh_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
,
954 const DWORD
*point_reps
, DWORD
*adjacency
)
957 DWORD num_faces
= iface
->lpVtbl
->GetNumFaces(iface
);
958 DWORD num_vertices
= iface
->lpVtbl
->GetNumVertices(iface
);
959 DWORD options
= iface
->lpVtbl
->GetOptions(iface
);
960 BOOL indices_are_16_bit
= !(options
& D3DXMESH_32BIT
);
965 struct edge_face_map edge_face_map
= {0};
966 const DWORD
*point_reps_ptr
= NULL
;
967 DWORD
*id_point_reps
= NULL
;
969 TRACE("iface %p, point_reps %p, adjacency %p.\n", iface
, point_reps
, adjacency
);
971 if (!adjacency
) return D3DERR_INVALIDCALL
;
973 if (!point_reps
) /* Identity point reps */
975 id_point_reps
= generate_identity_point_reps(num_vertices
);
982 point_reps_ptr
= id_point_reps
;
986 point_reps_ptr
= point_reps
;
989 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &ib_ptr
);
990 if (FAILED(hr
)) goto cleanup
;
992 if (indices_are_16_bit
)
994 /* Widen 16 bit to 32 bit */
996 WORD
*ib_16bit
= ib_ptr
;
997 ib
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(DWORD
));
1003 for (i
= 0; i
< 3 * num_faces
; i
++)
1005 ib
[i
] = ib_16bit
[i
];
1013 hr
= init_edge_face_map(&edge_face_map
, ib
, point_reps_ptr
, num_faces
);
1014 if (FAILED(hr
)) goto cleanup
;
1016 /* Create adjacency */
1017 for (face
= 0; face
< num_faces
; face
++)
1019 for (edge
= 0; edge
< 3; edge
++)
1021 DWORD v1
= ib
[3*face
+ edge
];
1022 DWORD v2
= ib
[3*face
+ (edge
+1)%3];
1023 DWORD new_v1
= point_reps_ptr
[v1
];
1024 DWORD new_v2
= point_reps_ptr
[v2
];
1027 adj_face
= find_adjacent_face(&edge_face_map
, new_v1
, new_v2
, num_faces
);
1028 adjacency
[3*face
+ edge
] = adj_face
;
1034 HeapFree(GetProcessHeap(), 0, id_point_reps
);
1035 if (indices_are_16_bit
) HeapFree(GetProcessHeap(), 0, ib
);
1036 HeapFree(GetProcessHeap(), 0, edge_face_map
.lists
);
1037 HeapFree(GetProcessHeap(), 0, edge_face_map
.entries
);
1038 if(ib_ptr
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1042 /* ConvertAdjacencyToPointReps helper function.
1044 * Goes around the edges of each face and replaces the vertices in any adjacent
1045 * face's edge with its own vertices(if its vertices have a lower index). This
1046 * way as few as possible low index vertices are shared among the faces. The
1047 * re-ordered index buffer is stored in new_indices.
1049 * The vertices in a point representation must be ordered sequentially, e.g.
1050 * index 5 holds the index of the vertex that replaces vertex 5, i.e. if
1051 * vertex 5 is replaced by vertex 3 then index 5 would contain 3. If no vertex
1052 * replaces it, then it contains the same number as the index itself, e.g.
1053 * index 5 would contain 5. */
1054 static HRESULT
propagate_face_vertices(const DWORD
*adjacency
, DWORD
*point_reps
,
1055 const DWORD
*indices
, DWORD
*new_indices
, DWORD face
, DWORD numfaces
)
1057 const unsigned int VERTS_PER_FACE
= 3;
1058 DWORD edge
, opp_edge
;
1059 DWORD face_base
= VERTS_PER_FACE
* face
;
1061 for (edge
= 0; edge
< VERTS_PER_FACE
; edge
++)
1063 DWORD adj_face
= adjacency
[face_base
+ edge
];
1064 DWORD adj_face_base
;
1066 if (adj_face
== -1) /* No adjacent face. */
1068 else if (adj_face
>= numfaces
)
1070 /* This throws exception on Windows */
1071 WARN("Index out of bounds. Got %d expected less than %d.\n",
1072 adj_face
, numfaces
);
1073 return D3DERR_INVALIDCALL
;
1075 adj_face_base
= 3 * adj_face
;
1077 /* Find opposite edge in adjacent face. */
1078 for (opp_edge
= 0; opp_edge
< VERTS_PER_FACE
; opp_edge
++)
1080 DWORD opp_edge_index
= adj_face_base
+ opp_edge
;
1081 if (adjacency
[opp_edge_index
] == face
)
1082 break; /* Found opposite edge. */
1085 /* Replaces vertices in opposite edge with vertices from current edge. */
1086 for (i
= 0; i
< 2; i
++)
1088 DWORD from
= face_base
+ (edge
+ (1 - i
)) % VERTS_PER_FACE
;
1089 DWORD to
= adj_face_base
+ (opp_edge
+ i
) % VERTS_PER_FACE
;
1091 /* Propagate lowest index. */
1092 if (new_indices
[to
] > new_indices
[from
])
1094 new_indices
[to
] = new_indices
[from
];
1095 point_reps
[indices
[to
]] = new_indices
[from
];
1103 static HRESULT WINAPI
d3dx9_mesh_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
,
1104 const DWORD
*adjacency
, DWORD
*point_reps
)
1106 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1110 DWORD
*indices
= NULL
;
1111 WORD
*indices_16bit
= NULL
;
1112 DWORD
*new_indices
= NULL
;
1113 const unsigned int VERTS_PER_FACE
= 3;
1115 TRACE("iface %p, adjacency %p, point_reps %p.\n", iface
, adjacency
, point_reps
);
1119 WARN("NULL adjacency.\n");
1120 hr
= D3DERR_INVALIDCALL
;
1126 WARN("NULL point_reps.\n");
1127 hr
= D3DERR_INVALIDCALL
;
1131 /* Should never happen as CreateMesh does not allow meshes with 0 faces */
1132 if (This
->numfaces
== 0)
1134 ERR("Number of faces was zero.\n");
1135 hr
= D3DERR_INVALIDCALL
;
1139 new_indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1146 if (This
->options
& D3DXMESH_32BIT
)
1148 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1149 if (FAILED(hr
)) goto cleanup
;
1150 memcpy(new_indices
, indices
, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1154 /* Make a widening copy of indices_16bit into indices and new_indices
1155 * in order to re-use the helper function */
1156 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices_16bit
);
1157 if (FAILED(hr
)) goto cleanup
;
1158 indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1164 for (i
= 0; i
< VERTS_PER_FACE
* This
->numfaces
; i
++)
1166 new_indices
[i
] = indices_16bit
[i
];
1167 indices
[i
] = indices_16bit
[i
];
1171 /* Vertices are ordered sequentially in the point representation. */
1172 for (i
= 0; i
< This
->numvertices
; i
++)
1177 /* Propagate vertices with low indices so as few vertices as possible
1178 * are used in the mesh.
1180 for (face
= 0; face
< This
->numfaces
; face
++)
1182 hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
, face
, This
->numfaces
);
1183 if (FAILED(hr
)) goto cleanup
;
1185 /* Go in opposite direction to catch all face orderings */
1186 for (face
= 0; face
< This
->numfaces
; face
++)
1188 hr
= propagate_face_vertices(adjacency
, point_reps
,
1189 indices
, new_indices
,
1190 (This
->numfaces
- 1) - face
, This
->numfaces
);
1191 if (FAILED(hr
)) goto cleanup
;
1196 if (This
->options
& D3DXMESH_32BIT
)
1198 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1202 if (indices_16bit
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1203 HeapFree(GetProcessHeap(), 0, indices
);
1205 HeapFree(GetProcessHeap(), 0, new_indices
);
1209 struct vertex_metadata
{
1212 DWORD first_shared_index
;
1215 static int compare_vertex_keys(const void *a
, const void *b
)
1217 const struct vertex_metadata
*left
= a
;
1218 const struct vertex_metadata
*right
= b
;
1219 if (left
->key
== right
->key
)
1221 return left
->key
< right
->key
? -1 : 1;
1224 static HRESULT WINAPI
d3dx9_mesh_GenerateAdjacency(ID3DXMesh
*iface
, float epsilon
, DWORD
*adjacency
)
1226 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1228 BYTE
*vertices
= NULL
;
1229 const DWORD
*indices
= NULL
;
1232 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
1233 struct vertex_metadata
*sorted_vertices
;
1234 /* shared_indices links together identical indices in the index buffer so
1235 * that adjacency checks can be limited to faces sharing a vertex */
1236 DWORD
*shared_indices
= NULL
;
1237 const FLOAT epsilon_sq
= epsilon
* epsilon
;
1240 TRACE("iface %p, epsilon %.8e, adjacency %p.\n", iface
, epsilon
, adjacency
);
1243 return D3DERR_INVALIDCALL
;
1245 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
1246 if (!(This
->options
& D3DXMESH_32BIT
))
1247 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
1248 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
1249 if (!shared_indices
)
1250 return E_OUTOFMEMORY
;
1251 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
1253 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
1254 if (FAILED(hr
)) goto cleanup
;
1255 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1256 if (FAILED(hr
)) goto cleanup
;
1258 if (!(This
->options
& D3DXMESH_32BIT
)) {
1259 const WORD
*word_indices
= (const WORD
*)indices
;
1260 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
1261 indices
= dword_indices
;
1262 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1263 *dword_indices
++ = *word_indices
++;
1266 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1267 for (i
= 0; i
< This
->numvertices
; i
++) {
1268 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
1269 sorted_vertices
[i
].first_shared_index
= -1;
1270 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
1271 sorted_vertices
[i
].vertex_index
= i
;
1273 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
1274 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
1275 shared_indices
[i
] = *first_shared_index
;
1276 *first_shared_index
= i
;
1279 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
1281 for (i
= 0; i
< This
->numvertices
; i
++) {
1282 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
1283 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
1284 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
1286 while (shared_index_a
!= -1) {
1288 DWORD shared_index_b
= shared_indices
[shared_index_a
];
1289 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
1292 while (shared_index_b
!= -1) {
1293 /* faces are adjacent if they have another coincident vertex */
1294 DWORD base_a
= (shared_index_a
/ 3) * 3;
1295 DWORD base_b
= (shared_index_b
/ 3) * 3;
1296 BOOL adjacent
= FALSE
;
1299 for (k
= 0; k
< 3; k
++) {
1300 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
1306 for (k
= 1; k
<= 2; k
++) {
1307 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
1308 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
1309 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
1310 if (!adjacent
&& epsilon
>= 0.0f
) {
1311 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
1314 D3DXVec3Subtract(&delta
,
1315 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
1316 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
1317 length_sq
= D3DXVec3LengthSq(&delta
);
1318 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
1321 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
1322 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
1323 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
1324 adjacency
[adj_a
] = base_b
/ 3;
1325 adjacency
[adj_b
] = base_a
/ 3;
1332 shared_index_b
= shared_indices
[shared_index_b
];
1334 while (++j
< This
->numvertices
) {
1335 D3DXVECTOR3
*vertex_b
;
1338 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
1339 /* no more coincident vertices to try */
1340 j
= This
->numvertices
;
1343 /* check for coincidence */
1344 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
1345 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
1346 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
1347 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
1352 if (j
>= This
->numvertices
)
1354 shared_index_b
= sorted_vertex_b
->first_shared_index
;
1357 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
1358 shared_index_a
= sorted_vertex_a
->first_shared_index
;
1364 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1365 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
1366 HeapFree(GetProcessHeap(), 0, shared_indices
);
1370 static HRESULT WINAPI
d3dx9_mesh_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1372 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1374 UINT vertex_declaration_size
;
1377 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
1381 WARN("Invalid declaration. Can't use NULL declaration.\n");
1382 return D3DERR_INVALIDCALL
;
1385 /* New declaration must be same size as original */
1386 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
1387 if (vertex_declaration_size
!= This
->vertex_declaration_size
)
1389 WARN("Invalid declaration. New vertex size does not match the original vertex size.\n");
1390 return D3DERR_INVALIDCALL
;
1393 /* New declaration must not contain non-zero Stream value */
1394 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1396 if (declaration
[i
].Stream
!= 0)
1398 WARN("Invalid declaration. New declaration contains non-zero Stream value.\n");
1399 return D3DERR_INVALIDCALL
;
1403 This
->num_elem
= i
+ 1;
1404 copy_declaration(This
->cached_declaration
, declaration
, This
->num_elem
);
1406 if (This
->vertex_declaration
)
1407 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
1409 /* An application can pass an invalid declaration to UpdateSemantics and
1410 * still expect D3D_OK (see tests). If the declaration is invalid, then
1411 * subsequent calls to DrawSubset will fail. This is handled by setting the
1412 * vertex declaration to NULL.
1413 * GetDeclaration, GetNumBytesPerVertex must, however, use the new
1414 * invalid declaration. This is handled by them using the cached vertex
1415 * declaration instead of the actual vertex declaration.
1417 hr
= IDirect3DDevice9_CreateVertexDeclaration(This
->device
,
1419 &This
->vertex_declaration
);
1422 WARN("Using invalid declaration. Calls to DrawSubset will fail.\n");
1423 This
->vertex_declaration
= NULL
;
1429 static HRESULT WINAPI
d3dx9_mesh_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
1431 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1433 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
1435 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1437 if (!(flags
& D3DLOCK_READONLY
))
1439 D3DXATTRIBUTERANGE
*attrib_table
= mesh
->attrib_table
;
1440 mesh
->attrib_table_size
= 0;
1441 mesh
->attrib_table
= NULL
;
1442 HeapFree(GetProcessHeap(), 0, attrib_table
);
1445 *data
= mesh
->attrib_buffer
;
1450 static HRESULT WINAPI
d3dx9_mesh_UnlockAttributeBuffer(ID3DXMesh
*iface
)
1452 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1455 TRACE("iface %p.\n", iface
);
1457 lock_count
= InterlockedDecrement(&mesh
->attrib_buffer_lock_count
);
1460 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1461 return D3DERR_INVALIDCALL
;
1467 static HRESULT WINAPI
d3dx9_mesh_Optimize(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1468 DWORD
*adjacency_out
, DWORD
*face_remap
, ID3DXBuffer
**vertex_remap
, ID3DXMesh
**opt_mesh
)
1470 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1472 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
1473 ID3DXMesh
*optimized_mesh
;
1475 TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap %p, vertex_remap %p, opt_mesh %p.\n",
1476 iface
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
1479 return D3DERR_INVALIDCALL
;
1481 hr
= iface
->lpVtbl
->GetDeclaration(iface
, declaration
);
1482 if (FAILED(hr
)) return hr
;
1484 if (FAILED(hr
= iface
->lpVtbl
->CloneMesh(iface
, mesh
->options
, declaration
, mesh
->device
, &optimized_mesh
)))
1487 hr
= optimized_mesh
->lpVtbl
->OptimizeInplace(optimized_mesh
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
);
1489 *opt_mesh
= optimized_mesh
;
1491 IUnknown_Release(optimized_mesh
);
1495 /* Creates a vertex_remap that removes unused vertices.
1496 * Indices are updated according to the vertex_remap. */
1497 static HRESULT
compact_mesh(struct d3dx9_mesh
*This
, DWORD
*indices
,
1498 DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
1501 DWORD
*vertex_remap_ptr
;
1502 DWORD num_used_vertices
;
1505 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
1506 if (FAILED(hr
)) return hr
;
1507 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
1509 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1510 vertex_remap_ptr
[indices
[i
]] = 1;
1512 /* create old->new vertex mapping */
1513 num_used_vertices
= 0;
1514 for (i
= 0; i
< This
->numvertices
; i
++) {
1515 if (vertex_remap_ptr
[i
])
1516 vertex_remap_ptr
[i
] = num_used_vertices
++;
1518 vertex_remap_ptr
[i
] = -1;
1520 /* convert indices */
1521 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1522 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
1524 /* create new->old vertex mapping */
1525 num_used_vertices
= 0;
1526 for (i
= 0; i
< This
->numvertices
; i
++) {
1527 if (vertex_remap_ptr
[i
] != -1)
1528 vertex_remap_ptr
[num_used_vertices
++] = i
;
1530 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
1531 vertex_remap_ptr
[i
] = -1;
1533 *new_num_vertices
= num_used_vertices
;
1538 /* count the number of unique attribute values in a sorted attribute buffer */
1539 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
1541 DWORD last_attribute
= attrib_buffer
[0];
1542 DWORD attrib_table_size
= 1;
1544 for (i
= 1; i
< numfaces
; i
++) {
1545 if (attrib_buffer
[i
] != last_attribute
) {
1546 last_attribute
= attrib_buffer
[i
];
1547 attrib_table_size
++;
1550 return attrib_table_size
;
1553 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
1554 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
1556 DWORD attrib_table_size
= 0;
1557 DWORD last_attribute
= attrib_buffer
[0];
1558 DWORD min_vertex
, max_vertex
;
1561 attrib_table
[0].AttribId
= last_attribute
;
1562 attrib_table
[0].FaceStart
= 0;
1563 min_vertex
= (DWORD
)-1;
1565 for (i
= 0; i
< numfaces
; i
++) {
1568 if (attrib_buffer
[i
] != last_attribute
) {
1569 last_attribute
= attrib_buffer
[i
];
1570 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1571 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1572 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1573 attrib_table_size
++;
1574 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
1575 attrib_table
[attrib_table_size
].FaceStart
= i
;
1576 min_vertex
= (DWORD
)-1;
1579 for (j
= 0; j
< 3; j
++) {
1580 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
1581 if (vertex_index
< min_vertex
)
1582 min_vertex
= vertex_index
;
1583 if (vertex_index
> max_vertex
)
1584 max_vertex
= vertex_index
;
1587 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1588 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1589 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1590 attrib_table_size
++;
1593 static int attrib_entry_compare(const DWORD
**a
, const DWORD
**b
)
1595 const DWORD
*ptr_a
= *a
;
1596 const DWORD
*ptr_b
= *b
;
1597 int delta
= *ptr_a
- *ptr_b
;
1602 delta
= ptr_a
- ptr_b
; /* for stable sort */
1606 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
1607 static HRESULT
remap_faces_for_attrsort(struct d3dx9_mesh
*This
, const DWORD
*indices
,
1608 DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
1610 DWORD
**sorted_attrib_ptr_buffer
= NULL
;
1613 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
1614 if (!sorted_attrib_ptr_buffer
)
1615 return E_OUTOFMEMORY
;
1617 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
1620 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
1621 return E_OUTOFMEMORY
;
1624 for (i
= 0; i
< This
->numfaces
; i
++)
1625 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
1626 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
),
1627 (int(*)(const void *, const void *))attrib_entry_compare
);
1629 for (i
= 0; i
< This
->numfaces
; i
++)
1631 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
1632 (*face_remap
)[old_face
] = i
;
1635 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
1636 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
1637 for (i
= 0; i
< This
->numfaces
; i
++)
1638 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
1643 static HRESULT WINAPI
d3dx9_mesh_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1644 DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
1646 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1647 void *indices
= NULL
;
1648 DWORD
*attrib_buffer
= NULL
;
1650 ID3DXBuffer
*vertex_remap
= NULL
;
1651 DWORD
*face_remap
= NULL
; /* old -> new mapping */
1652 DWORD
*dword_indices
= NULL
;
1653 DWORD new_num_vertices
= 0;
1654 DWORD new_num_alloc_vertices
= 0;
1655 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
1656 DWORD
*sorted_attrib_buffer
= NULL
;
1659 TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
1660 iface
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
1663 return D3DERR_INVALIDCALL
;
1664 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
1665 return D3DERR_INVALIDCALL
;
1666 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1667 return D3DERR_INVALIDCALL
;
1669 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1671 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
1672 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
1673 if (flags
& D3DXMESHOPT_STRIPREORDER
)
1674 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
1678 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, &indices
);
1679 if (FAILED(hr
)) goto cleanup
;
1681 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
1682 if (!dword_indices
) return E_OUTOFMEMORY
;
1683 if (This
->options
& D3DXMESH_32BIT
) {
1684 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1686 WORD
*word_indices
= indices
;
1687 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1688 dword_indices
[i
] = *word_indices
++;
1691 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
1693 new_num_alloc_vertices
= This
->numvertices
;
1694 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
1695 if (FAILED(hr
)) goto cleanup
;
1696 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
1697 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
1699 FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
1704 hr
= iface
->lpVtbl
->LockAttributeBuffer(iface
, 0, &attrib_buffer
);
1705 if (FAILED(hr
)) goto cleanup
;
1707 hr
= remap_faces_for_attrsort(This
, dword_indices
, attrib_buffer
, &sorted_attrib_buffer
, &face_remap
);
1708 if (FAILED(hr
)) goto cleanup
;
1713 /* reorder the vertices using vertex_remap */
1714 D3DVERTEXBUFFER_DESC vertex_desc
;
1715 DWORD
*vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1716 DWORD vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1717 BYTE
*orig_vertices
;
1720 hr
= IDirect3DVertexBuffer9_GetDesc(This
->vertex_buffer
, &vertex_desc
);
1721 if (FAILED(hr
)) goto cleanup
;
1723 hr
= IDirect3DDevice9_CreateVertexBuffer(This
->device
, new_num_alloc_vertices
* vertex_size
,
1724 vertex_desc
.Usage
, This
->fvf
, vertex_desc
.Pool
, &vertex_buffer
, NULL
);
1725 if (FAILED(hr
)) goto cleanup
;
1727 hr
= IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, (void**)&orig_vertices
, D3DLOCK_READONLY
);
1728 if (FAILED(hr
)) goto cleanup
;
1730 hr
= IDirect3DVertexBuffer9_Lock(vertex_buffer
, 0, 0, (void**)&new_vertices
, 0);
1732 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1736 for (i
= 0; i
< new_num_vertices
; i
++)
1737 memcpy(new_vertices
+ i
* vertex_size
, orig_vertices
+ vertex_remap_ptr
[i
] * vertex_size
, vertex_size
);
1739 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1740 IDirect3DVertexBuffer9_Unlock(vertex_buffer
);
1741 } else if (vertex_remap_out
) {
1742 DWORD
*vertex_remap_ptr
;
1744 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), &vertex_remap
);
1745 if (FAILED(hr
)) goto cleanup
;
1746 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1747 for (i
= 0; i
< This
->numvertices
; i
++)
1748 *vertex_remap_ptr
++ = i
;
1751 if (flags
& D3DXMESHOPT_ATTRSORT
)
1753 D3DXATTRIBUTERANGE
*attrib_table
;
1754 DWORD attrib_table_size
;
1756 attrib_table_size
= count_attributes(sorted_attrib_buffer
, This
->numfaces
);
1757 attrib_table
= HeapAlloc(GetProcessHeap(), 0, attrib_table_size
* sizeof(*attrib_table
));
1758 if (!attrib_table
) {
1763 memcpy(attrib_buffer
, sorted_attrib_buffer
, This
->numfaces
* sizeof(*attrib_buffer
));
1765 /* reorder the indices using face_remap */
1766 if (This
->options
& D3DXMESH_32BIT
) {
1767 for (i
= 0; i
< This
->numfaces
; i
++)
1768 memcpy((DWORD
*)indices
+ face_remap
[i
] * 3, dword_indices
+ i
* 3, 3 * sizeof(DWORD
));
1770 WORD
*word_indices
= indices
;
1771 for (i
= 0; i
< This
->numfaces
; i
++) {
1772 DWORD new_pos
= face_remap
[i
] * 3;
1773 DWORD old_pos
= i
* 3;
1774 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1775 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1776 word_indices
[new_pos
] = dword_indices
[old_pos
];
1780 fill_attribute_table(attrib_buffer
, This
->numfaces
, indices
,
1781 This
->options
& D3DXMESH_32BIT
, attrib_table
);
1783 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1784 This
->attrib_table
= attrib_table
;
1785 This
->attrib_table_size
= attrib_table_size
;
1787 if (This
->options
& D3DXMESH_32BIT
) {
1788 memcpy(indices
, dword_indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1790 WORD
*word_indices
= indices
;
1791 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1792 *word_indices
++ = dword_indices
[i
];
1796 if (adjacency_out
) {
1798 for (i
= 0; i
< This
->numfaces
; i
++) {
1799 DWORD old_pos
= i
* 3;
1800 DWORD new_pos
= face_remap
[i
] * 3;
1801 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1802 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1803 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1806 memcpy(adjacency_out
, adjacency_in
, This
->numfaces
* 3 * sizeof(*adjacency_out
));
1809 if (face_remap_out
) {
1811 for (i
= 0; i
< This
->numfaces
; i
++)
1812 face_remap_out
[face_remap
[i
]] = i
;
1814 for (i
= 0; i
< This
->numfaces
; i
++)
1815 face_remap_out
[i
] = i
;
1818 if (vertex_remap_out
)
1819 *vertex_remap_out
= vertex_remap
;
1820 vertex_remap
= NULL
;
1822 if (vertex_buffer
) {
1823 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
1824 This
->vertex_buffer
= vertex_buffer
;
1825 vertex_buffer
= NULL
;
1826 This
->numvertices
= new_num_vertices
;
1831 HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer
);
1832 HeapFree(GetProcessHeap(), 0, face_remap
);
1833 HeapFree(GetProcessHeap(), 0, dword_indices
);
1834 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
1835 if (vertex_buffer
) IDirect3DVertexBuffer9_Release(vertex_buffer
);
1836 if (attrib_buffer
) iface
->lpVtbl
->UnlockAttributeBuffer(iface
);
1837 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1841 static HRESULT WINAPI
d3dx9_mesh_SetAttributeTable(ID3DXMesh
*iface
,
1842 const D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
1844 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1845 D3DXATTRIBUTERANGE
*new_table
= NULL
;
1847 TRACE("iface %p, attrib_table %p, attrib_table_size %u.\n", iface
, attrib_table
, attrib_table_size
);
1849 if (attrib_table_size
) {
1850 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
1852 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
1854 return E_OUTOFMEMORY
;
1856 CopyMemory(new_table
, attrib_table
, size
);
1857 } else if (attrib_table
) {
1858 return D3DERR_INVALIDCALL
;
1860 HeapFree(GetProcessHeap(), 0, mesh
->attrib_table
);
1861 mesh
->attrib_table
= new_table
;
1862 mesh
->attrib_table_size
= attrib_table_size
;
1867 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
1869 d3dx9_mesh_QueryInterface
,
1872 d3dx9_mesh_DrawSubset
,
1873 d3dx9_mesh_GetNumFaces
,
1874 d3dx9_mesh_GetNumVertices
,
1876 d3dx9_mesh_GetDeclaration
,
1877 d3dx9_mesh_GetNumBytesPerVertex
,
1878 d3dx9_mesh_GetOptions
,
1879 d3dx9_mesh_GetDevice
,
1880 d3dx9_mesh_CloneMeshFVF
,
1881 d3dx9_mesh_CloneMesh
,
1882 d3dx9_mesh_GetVertexBuffer
,
1883 d3dx9_mesh_GetIndexBuffer
,
1884 d3dx9_mesh_LockVertexBuffer
,
1885 d3dx9_mesh_UnlockVertexBuffer
,
1886 d3dx9_mesh_LockIndexBuffer
,
1887 d3dx9_mesh_UnlockIndexBuffer
,
1888 d3dx9_mesh_GetAttributeTable
,
1889 d3dx9_mesh_ConvertPointRepsToAdjacency
,
1890 d3dx9_mesh_ConvertAdjacencyToPointReps
,
1891 d3dx9_mesh_GenerateAdjacency
,
1892 d3dx9_mesh_UpdateSemantics
,
1893 d3dx9_mesh_LockAttributeBuffer
,
1894 d3dx9_mesh_UnlockAttributeBuffer
,
1895 d3dx9_mesh_Optimize
,
1896 d3dx9_mesh_OptimizeInplace
,
1897 d3dx9_mesh_SetAttributeTable
,
1901 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algorithm
1902 Amy Williams University of Utah
1903 Steve Barrus University of Utah
1904 R. Keith Morley University of Utah
1905 Peter Shirley University of Utah
1907 International Conference on Computer Graphics and Interactive Techniques archive
1908 ACM SIGGRAPH 2005 Courses
1909 Los Angeles, California
1911 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1913 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1914 against each slab, if there's anything left of the ray after we're
1915 done we've got an intersection of the ray with the box. */
1916 BOOL WINAPI
D3DXBoxBoundProbe(const D3DXVECTOR3
*pmin
, const D3DXVECTOR3
*pmax
,
1917 const D3DXVECTOR3
*prayposition
, const D3DXVECTOR3
*praydirection
)
1919 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
1921 div
= 1.0f
/ praydirection
->x
;
1924 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
1925 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
1929 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
1930 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
1933 if ( tmax
< 0.0f
) return FALSE
;
1935 div
= 1.0f
/ praydirection
->y
;
1938 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
1939 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
1943 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
1944 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
1947 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
1949 if ( tymin
> tmin
) tmin
= tymin
;
1950 if ( tymax
< tmax
) tmax
= tymax
;
1952 div
= 1.0f
/ praydirection
->z
;
1955 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
1956 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
1960 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
1961 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
1964 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
1969 HRESULT WINAPI
D3DXComputeBoundingBox(const D3DXVECTOR3
*pfirstposition
,
1970 DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
1975 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
1977 *pmin
= *pfirstposition
;
1980 for(i
=0; i
<numvertices
; i
++)
1982 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
1984 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
1985 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
1987 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
1988 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
1990 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
1991 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
1997 HRESULT WINAPI
D3DXComputeBoundingSphere(const D3DXVECTOR3
*pfirstposition
,
1998 DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, float *pradius
)
2004 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
2011 for(i
=0; i
<numvertices
; i
++)
2012 D3DXVec3Add(&temp
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
2014 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/ numvertices
);
2016 for(i
=0; i
<numvertices
; i
++)
2018 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
2019 if ( d
> *pradius
) *pradius
= d
;
2024 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
2025 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
2027 declaration
[*idx
].Stream
= 0;
2028 declaration
[*idx
].Offset
= *offset
;
2029 declaration
[*idx
].Type
= type
;
2030 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
2031 declaration
[*idx
].Usage
= usage
;
2032 declaration
[*idx
].UsageIndex
= usage_idx
;
2034 *offset
+= d3dx_decltype_size
[type
];
2038 /*************************************************************************
2039 * D3DXDeclaratorFromFVF
2041 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
2043 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
2044 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2045 unsigned int offset
= 0;
2046 unsigned int idx
= 0;
2049 TRACE("fvf %#x, declaration %p.\n", fvf
, declaration
);
2051 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
2053 if (fvf
& D3DFVF_POSITION_MASK
)
2055 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
2056 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
2057 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
2059 if (has_blend_idx
) --blend_count
;
2061 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
2062 || (has_blend
&& blend_count
> 4))
2063 return D3DERR_INVALIDCALL
;
2065 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
2066 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
2068 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
2072 switch (blend_count
)
2077 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2080 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2083 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2086 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2089 ERR("Invalid blend count %u.\n", blend_count
);
2095 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
2096 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
2097 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
2098 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
2103 if (fvf
& D3DFVF_NORMAL
)
2104 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
2105 if (fvf
& D3DFVF_PSIZE
)
2106 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
2107 if (fvf
& D3DFVF_DIFFUSE
)
2108 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
2109 if (fvf
& D3DFVF_SPECULAR
)
2110 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
2112 for (i
= 0; i
< tex_count
; ++i
)
2114 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
2116 case D3DFVF_TEXTUREFORMAT1
:
2117 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
2119 case D3DFVF_TEXTUREFORMAT2
:
2120 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
2122 case D3DFVF_TEXTUREFORMAT3
:
2123 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
2125 case D3DFVF_TEXTUREFORMAT4
:
2126 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
2131 declaration
[idx
] = end_element
;
2136 /*************************************************************************
2137 * D3DXFVFFromDeclarator
2139 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
2141 unsigned int i
= 0, texture
, offset
;
2143 TRACE("(%p, %p)\n", declaration
, fvf
);
2146 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
2148 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2149 declaration
[1].UsageIndex
== 0) &&
2150 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
2151 declaration
[2].UsageIndex
== 0))
2153 return D3DERR_INVALIDCALL
;
2155 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2156 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
2158 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
2160 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
2164 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
2168 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2169 declaration
[1].UsageIndex
== 0)
2171 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2172 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
2174 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
2176 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
2180 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
2182 switch (declaration
[1].Type
)
2184 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
2185 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
2186 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
2187 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
2193 switch (declaration
[1].Type
)
2195 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
2196 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
2197 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
2198 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
2209 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
2210 declaration
[0].UsageIndex
== 0)
2212 *fvf
|= D3DFVF_XYZRHW
;
2216 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
2218 *fvf
|= D3DFVF_NORMAL
;
2221 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
2222 declaration
[i
].UsageIndex
== 0)
2224 *fvf
|= D3DFVF_PSIZE
;
2227 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2228 declaration
[i
].UsageIndex
== 0)
2230 *fvf
|= D3DFVF_DIFFUSE
;
2233 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2234 declaration
[i
].UsageIndex
== 1)
2236 *fvf
|= D3DFVF_SPECULAR
;
2240 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
2242 if (declaration
[i
].Stream
== 0xFF)
2246 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2247 declaration
[i
].UsageIndex
== texture
)
2249 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
2251 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2252 declaration
[i
].UsageIndex
== texture
)
2254 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
2256 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2257 declaration
[i
].UsageIndex
== texture
)
2259 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
2261 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2262 declaration
[i
].UsageIndex
== texture
)
2264 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
2268 return D3DERR_INVALIDCALL
;
2272 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
2274 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
2275 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
2277 if (declaration
[i
].Offset
!= offset
)
2279 return D3DERR_INVALIDCALL
;
2286 /*************************************************************************
2287 * D3DXGetFVFVertexSize
2289 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
2291 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
2294 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
2298 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2300 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
2301 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
2302 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
2303 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
2305 switch (FVF
& D3DFVF_POSITION_MASK
)
2307 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
2308 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
2309 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
2310 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
2311 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
2312 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
2313 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
2314 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
2317 for (i
= 0; i
< numTextures
; i
++)
2319 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
2325 /*************************************************************************
2326 * D3DXGetDeclVertexSize
2328 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
2330 const D3DVERTEXELEMENT9
*element
;
2333 TRACE("decl %p, stream_idx %u\n", decl
, stream_idx
);
2335 if (!decl
) return 0;
2337 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
2341 if (element
->Stream
!= stream_idx
) continue;
2343 if (element
->Type
>= sizeof(d3dx_decltype_size
) / sizeof(*d3dx_decltype_size
))
2345 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
2349 type_size
= d3dx_decltype_size
[element
->Type
];
2350 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
2356 /*************************************************************************
2359 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
2361 const D3DVERTEXELEMENT9
*element
;
2363 TRACE("decl %p\n", decl
);
2365 /* null decl results in exception on Windows XP */
2367 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
2369 return element
- decl
;
2372 BOOL WINAPI
D3DXIntersectTri(const D3DXVECTOR3
*p0
, const D3DXVECTOR3
*p1
, const D3DXVECTOR3
*p2
,
2373 const D3DXVECTOR3
*praypos
, const D3DXVECTOR3
*praydir
, float *pu
, float *pv
, float *pdist
)
2378 TRACE("p0 %p, p1 %p, p2 %p, praypos %p, praydir %p, pu %p, pv %p, pdist %p.\n",
2379 p0
, p1
, p2
, praypos
, praydir
, pu
, pv
, pdist
);
2381 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
2382 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
2383 m
.u
.m
[2][0] = -praydir
->x
;
2385 m
.u
.m
[0][1] = p1
->y
- p0
->y
;
2386 m
.u
.m
[1][1] = p2
->y
- p0
->y
;
2387 m
.u
.m
[2][1] = -praydir
->y
;
2389 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
2390 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
2391 m
.u
.m
[2][2] = -praydir
->z
;
2398 vec
.x
= praypos
->x
- p0
->x
;
2399 vec
.y
= praypos
->y
- p0
->y
;
2400 vec
.z
= praypos
->z
- p0
->z
;
2403 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
2405 D3DXVec4Transform(&vec
, &vec
, &m
);
2406 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
2408 if (pu
) *pu
= vec
.x
;
2409 if (pv
) *pv
= vec
.y
;
2410 if (pdist
) *pdist
= fabsf( vec
.z
);
2418 BOOL WINAPI
D3DXSphereBoundProbe(const D3DXVECTOR3
*pcenter
, float radius
,
2419 const D3DXVECTOR3
*prayposition
, const D3DXVECTOR3
*praydirection
)
2421 D3DXVECTOR3 difference
;
2424 a
= D3DXVec3LengthSq(praydirection
);
2425 if (!D3DXVec3Subtract(&difference
, prayposition
, pcenter
)) return FALSE
;
2426 b
= D3DXVec3Dot(&difference
, praydirection
);
2427 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
2430 if ( ( d
<= 0.0f
) || ( sqrt(d
) <= b
) ) return FALSE
;
2434 /*************************************************************************
2437 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2438 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2442 IDirect3DVertexDeclaration9
*vertex_declaration
;
2443 UINT vertex_declaration_size
;
2445 IDirect3DVertexBuffer9
*vertex_buffer
;
2446 IDirect3DIndexBuffer9
*index_buffer
;
2447 DWORD
*attrib_buffer
;
2448 struct d3dx9_mesh
*object
;
2449 DWORD index_usage
= 0;
2450 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
2451 D3DFORMAT index_format
= D3DFMT_INDEX16
;
2452 DWORD vertex_usage
= 0;
2453 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
2456 TRACE("numfaces %u, numvertices %u, options %#x, declaration %p, device %p, mesh %p.\n",
2457 numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2459 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
2460 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
2461 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
2463 return D3DERR_INVALIDCALL
;
2465 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
2466 if (declaration
[i
].Stream
!= 0)
2467 return D3DERR_INVALIDCALL
;
2470 if (options
& D3DXMESH_32BIT
)
2471 index_format
= D3DFMT_INDEX32
;
2473 if (options
& D3DXMESH_DONOTCLIP
) {
2474 index_usage
|= D3DUSAGE_DONOTCLIP
;
2475 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
2477 if (options
& D3DXMESH_POINTS
) {
2478 index_usage
|= D3DUSAGE_POINTS
;
2479 vertex_usage
|= D3DUSAGE_POINTS
;
2481 if (options
& D3DXMESH_RTPATCHES
) {
2482 index_usage
|= D3DUSAGE_RTPATCHES
;
2483 vertex_usage
|= D3DUSAGE_RTPATCHES
;
2485 if (options
& D3DXMESH_NPATCHES
) {
2486 index_usage
|= D3DUSAGE_NPATCHES
;
2487 vertex_usage
|= D3DUSAGE_NPATCHES
;
2490 if (options
& D3DXMESH_VB_SYSTEMMEM
)
2491 vertex_pool
= D3DPOOL_SYSTEMMEM
;
2492 else if (options
& D3DXMESH_VB_MANAGED
)
2493 vertex_pool
= D3DPOOL_MANAGED
;
2495 if (options
& D3DXMESH_VB_WRITEONLY
)
2496 vertex_usage
|= D3DUSAGE_WRITEONLY
;
2497 if (options
& D3DXMESH_VB_DYNAMIC
)
2498 vertex_usage
|= D3DUSAGE_DYNAMIC
;
2499 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
2500 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2502 if (options
& D3DXMESH_IB_SYSTEMMEM
)
2503 index_pool
= D3DPOOL_SYSTEMMEM
;
2504 else if (options
& D3DXMESH_IB_MANAGED
)
2505 index_pool
= D3DPOOL_MANAGED
;
2507 if (options
& D3DXMESH_IB_WRITEONLY
)
2508 index_usage
|= D3DUSAGE_WRITEONLY
;
2509 if (options
& D3DXMESH_IB_DYNAMIC
)
2510 index_usage
|= D3DUSAGE_DYNAMIC
;
2511 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
2512 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2514 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
2520 /* Create vertex declaration */
2521 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
2523 &vertex_declaration
);
2526 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
2529 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
2531 /* Create vertex buffer */
2532 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
2533 numvertices
* vertex_declaration_size
,
2541 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2542 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2546 /* Create index buffer */
2547 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
2548 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
2556 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2557 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2558 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2562 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
2563 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2564 if (object
== NULL
|| attrib_buffer
== NULL
)
2566 HeapFree(GetProcessHeap(), 0, object
);
2567 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
2568 IDirect3DIndexBuffer9_Release(index_buffer
);
2569 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2570 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2572 return E_OUTOFMEMORY
;
2574 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
2577 object
->numfaces
= numfaces
;
2578 object
->numvertices
= numvertices
;
2579 object
->options
= options
;
2581 object
->device
= device
;
2582 IDirect3DDevice9_AddRef(device
);
2584 copy_declaration(object
->cached_declaration
, declaration
, num_elem
);
2585 object
->vertex_declaration
= vertex_declaration
;
2586 object
->vertex_declaration_size
= vertex_declaration_size
;
2587 object
->num_elem
= num_elem
;
2588 object
->vertex_buffer
= vertex_buffer
;
2589 object
->index_buffer
= index_buffer
;
2590 object
->attrib_buffer
= attrib_buffer
;
2592 *mesh
= &object
->ID3DXMesh_iface
;
2597 /*************************************************************************
2600 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2601 DWORD fvf
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2604 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
2606 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
2608 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
2609 if (FAILED(hr
)) return hr
;
2611 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2617 DWORD num_poly_faces
;
2618 DWORD num_tri_faces
;
2619 D3DXVECTOR3
*vertices
;
2620 DWORD
*num_tri_per_face
;
2625 /* optional mesh data */
2628 D3DXVECTOR3
*normals
;
2629 DWORD
*normal_indices
;
2631 D3DXVECTOR2
*tex_coords
;
2633 DWORD
*vertex_colors
;
2635 DWORD num_materials
;
2636 D3DXMATERIAL
*materials
;
2637 DWORD
*material_indices
;
2639 struct ID3DXSkinInfo
*skin_info
;
2643 static HRESULT
parse_texture_filename(ID3DXFileData
*filedata
, char **filename_out
)
2649 char *filename
= NULL
;
2651 /* template TextureFilename {
2656 HeapFree(GetProcessHeap(), 0, *filename_out
);
2657 *filename_out
= NULL
;
2659 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2660 if (FAILED(hr
)) return hr
;
2662 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
2663 if (data_size
< sizeof(filename_in
))
2665 WARN("truncated data (%lu bytes)\n", data_size
);
2666 filedata
->lpVtbl
->Unlock(filedata
);
2669 filename_in
= *(char **)data
;
2671 filename
= HeapAlloc(GetProcessHeap(), 0, strlen(filename_in
) + 1);
2673 filedata
->lpVtbl
->Unlock(filedata
);
2674 return E_OUTOFMEMORY
;
2677 strcpy(filename
, filename_in
);
2678 *filename_out
= filename
;
2680 filedata
->lpVtbl
->Unlock(filedata
);
2685 static HRESULT
parse_material(ID3DXFileData
*filedata
, D3DXMATERIAL
*material
)
2691 ID3DXFileData
*child
;
2692 SIZE_T i
, nb_children
;
2694 material
->pTextureFilename
= NULL
;
2696 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2697 if (FAILED(hr
)) return hr
;
2700 * template ColorRGBA {
2706 * template ColorRGB {
2711 * template Material {
2712 * ColorRGBA faceColor;
2714 * ColorRGB specularColor;
2715 * ColorRGB emissiveColor;
2719 if (data_size
!= sizeof(FLOAT
) * 11) {
2720 WARN("incorrect data size (%ld bytes)\n", data_size
);
2721 filedata
->lpVtbl
->Unlock(filedata
);
2725 memcpy(&material
->MatD3D
.Diffuse
, data
, sizeof(D3DCOLORVALUE
));
2726 data
+= sizeof(D3DCOLORVALUE
);
2727 material
->MatD3D
.Power
= *(FLOAT
*)data
;
2728 data
+= sizeof(FLOAT
);
2729 memcpy(&material
->MatD3D
.Specular
, data
, sizeof(FLOAT
) * 3);
2730 material
->MatD3D
.Specular
.a
= 1.0f
;
2731 data
+= 3 * sizeof(FLOAT
);
2732 memcpy(&material
->MatD3D
.Emissive
, data
, sizeof(FLOAT
) * 3);
2733 material
->MatD3D
.Emissive
.a
= 1.0f
;
2734 material
->MatD3D
.Ambient
.r
= 0.0f
;
2735 material
->MatD3D
.Ambient
.g
= 0.0f
;
2736 material
->MatD3D
.Ambient
.b
= 0.0f
;
2737 material
->MatD3D
.Ambient
.a
= 1.0f
;
2739 filedata
->lpVtbl
->Unlock(filedata
);
2741 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2745 for (i
= 0; i
< nb_children
; i
++)
2747 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2750 hr
= child
->lpVtbl
->GetType(child
, &type
);
2754 if (IsEqualGUID(&type
, &TID_D3DRMTextureFilename
)) {
2755 hr
= parse_texture_filename(child
, &material
->pTextureFilename
);
2759 IUnknown_Release(child
);
2764 IUnknown_Release(child
);
2768 static void destroy_materials(struct mesh_data
*mesh
)
2771 for (i
= 0; i
< mesh
->num_materials
; i
++)
2772 HeapFree(GetProcessHeap(), 0, mesh
->materials
[i
].pTextureFilename
);
2773 HeapFree(GetProcessHeap(), 0, mesh
->materials
);
2774 HeapFree(GetProcessHeap(), 0, mesh
->material_indices
);
2775 mesh
->num_materials
= 0;
2776 mesh
->materials
= NULL
;
2777 mesh
->material_indices
= NULL
;
2780 static HRESULT
parse_material_list(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2784 const DWORD
*data
, *in_ptr
;
2786 ID3DXFileData
*child
= NULL
;
2787 DWORD num_materials
;
2791 destroy_materials(mesh
);
2793 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2794 if (FAILED(hr
)) return hr
;
2796 /* template MeshMaterialList {
2798 * DWORD nFaceIndexes;
2799 * array DWORD faceIndexes[nFaceIndexes];
2807 if (data_size
< sizeof(DWORD
)) {
2808 WARN("truncated data (%ld bytes)\n", data_size
);
2811 num_materials
= *in_ptr
++;
2812 if (!num_materials
) {
2817 if (data_size
< 2 * sizeof(DWORD
)) {
2818 WARN("truncated data (%ld bytes)\n", data_size
);
2821 if (*in_ptr
++ != mesh
->num_poly_faces
) {
2822 WARN("number of material face indices (%u) doesn't match number of faces (%u)\n",
2823 *(in_ptr
- 1), mesh
->num_poly_faces
);
2826 if (data_size
< 2 * sizeof(DWORD
) + mesh
->num_poly_faces
* sizeof(DWORD
)) {
2827 WARN("truncated data (%ld bytes)\n", data_size
);
2830 for (i
= 0; i
< mesh
->num_poly_faces
; i
++) {
2831 if (*in_ptr
++ >= num_materials
) {
2832 WARN("face %u: reference to undefined material %u (only %u materials)\n",
2833 i
, *(in_ptr
- 1), num_materials
);
2838 mesh
->materials
= HeapAlloc(GetProcessHeap(), 0, num_materials
* sizeof(*mesh
->materials
));
2839 mesh
->material_indices
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_poly_faces
* sizeof(*mesh
->material_indices
));
2840 if (!mesh
->materials
|| !mesh
->material_indices
) {
2844 memcpy(mesh
->material_indices
, data
+ 2, mesh
->num_poly_faces
* sizeof(DWORD
));
2846 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2850 for (i
= 0; i
< nb_children
; i
++)
2852 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2855 hr
= child
->lpVtbl
->GetType(child
, &type
);
2859 if (IsEqualGUID(&type
, &TID_D3DRMMaterial
)) {
2860 if (mesh
->num_materials
>= num_materials
) {
2861 WARN("more materials defined than declared\n");
2865 hr
= parse_material(child
, &mesh
->materials
[mesh
->num_materials
++]);
2870 IUnknown_Release(child
);
2873 if (num_materials
!= mesh
->num_materials
) {
2874 WARN("only %u of %u materials defined\n", num_materials
, mesh
->num_materials
);
2880 IUnknown_Release(child
);
2881 filedata
->lpVtbl
->Unlock(filedata
);
2885 static HRESULT
parse_texture_coords(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2891 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2892 mesh
->tex_coords
= NULL
;
2894 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2895 if (FAILED(hr
)) return hr
;
2897 /* template Coords2d {
2901 * template MeshTextureCoords {
2902 * DWORD nTextureCoords;
2903 * array Coords2d textureCoords[nTextureCoords];
2909 if (data_size
< sizeof(DWORD
)) {
2910 WARN("truncated data (%ld bytes)\n", data_size
);
2913 if (*(DWORD
*)data
!= mesh
->num_vertices
) {
2914 WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2915 *(DWORD
*)data
, mesh
->num_vertices
);
2918 data
+= sizeof(DWORD
);
2919 if (data_size
< sizeof(DWORD
) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
)) {
2920 WARN("truncated data (%ld bytes)\n", data_size
);
2924 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2925 if (!mesh
->tex_coords
) {
2929 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2931 mesh
->fvf
|= D3DFVF_TEX1
;
2936 filedata
->lpVtbl
->Unlock(filedata
);
2940 static HRESULT
parse_vertex_colors(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2948 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2949 mesh
->vertex_colors
= NULL
;
2951 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2952 if (FAILED(hr
)) return hr
;
2954 /* template IndexedColor {
2956 * ColorRGBA indexColor;
2958 * template MeshVertexColors {
2959 * DWORD nVertexColors;
2960 * array IndexedColor vertexColors[nVertexColors];
2966 if (data_size
< sizeof(DWORD
)) {
2967 WARN("truncated data (%ld bytes)\n", data_size
);
2970 num_colors
= *(DWORD
*)data
;
2971 data
+= sizeof(DWORD
);
2972 if (data_size
< sizeof(DWORD
) + num_colors
* (sizeof(DWORD
) + sizeof(D3DCOLORVALUE
))) {
2973 WARN("truncated data (%ld bytes)\n", data_size
);
2977 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(DWORD
));
2978 if (!mesh
->vertex_colors
) {
2983 for (i
= 0; i
< mesh
->num_vertices
; i
++)
2984 mesh
->vertex_colors
[i
] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2985 for (i
= 0; i
< num_colors
; i
++)
2987 D3DCOLORVALUE color
;
2988 DWORD index
= *(DWORD
*)data
;
2989 data
+= sizeof(DWORD
);
2990 if (index
>= mesh
->num_vertices
) {
2991 WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2992 i
, index
, mesh
->num_vertices
);
2995 memcpy(&color
, data
, sizeof(color
));
2996 data
+= sizeof(color
);
2997 color
.r
= min(1.0f
, max(0.0f
, color
.r
));
2998 color
.g
= min(1.0f
, max(0.0f
, color
.g
));
2999 color
.b
= min(1.0f
, max(0.0f
, color
.b
));
3000 color
.a
= min(1.0f
, max(0.0f
, color
.a
));
3001 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
3002 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
3003 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
3004 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
3007 mesh
->fvf
|= D3DFVF_DIFFUSE
;
3012 filedata
->lpVtbl
->Unlock(filedata
);
3016 static HRESULT
parse_normals(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
3021 DWORD
*index_out_ptr
;
3023 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
3025 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
3026 mesh
->num_normals
= 0;
3027 mesh
->normals
= NULL
;
3028 mesh
->normal_indices
= NULL
;
3029 mesh
->fvf
|= D3DFVF_NORMAL
;
3031 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3032 if (FAILED(hr
)) return hr
;
3034 /* template Vector {
3039 * template MeshFace {
3040 * DWORD nFaceVertexIndices;
3041 * array DWORD faceVertexIndices[nFaceVertexIndices];
3043 * template MeshNormals {
3045 * array Vector normals[nNormals];
3046 * DWORD nFaceNormals;
3047 * array MeshFace faceNormals[nFaceNormals];
3053 if (data_size
< sizeof(DWORD
) * 2) {
3054 WARN("truncated data (%ld bytes)\n", data_size
);
3057 mesh
->num_normals
= *(DWORD
*)data
;
3058 data
+= sizeof(DWORD
);
3059 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
3060 num_face_indices
* sizeof(DWORD
)) {
3061 WARN("truncated data (%ld bytes)\n", data_size
);
3065 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3066 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
3067 if (!mesh
->normals
|| !mesh
->normal_indices
) {
3072 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3073 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
3074 for (i
= 0; i
< mesh
->num_normals
; i
++)
3075 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
3077 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
3078 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
3079 *(DWORD
*)data
, mesh
->num_poly_faces
);
3082 data
+= sizeof(DWORD
);
3083 index_out_ptr
= mesh
->normal_indices
;
3084 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
3087 DWORD count
= *(DWORD
*)data
;
3088 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
3089 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
3090 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
3093 data
+= sizeof(DWORD
);
3095 for (j
= 0; j
< count
; j
++) {
3096 DWORD normal_index
= *(DWORD
*)data
;
3097 if (normal_index
>= mesh
->num_normals
) {
3098 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
3099 i
, j
, normal_index
, mesh
->num_normals
);
3102 *index_out_ptr
++ = normal_index
;
3103 data
+= sizeof(DWORD
);
3110 filedata
->lpVtbl
->Unlock(filedata
);
3114 static HRESULT
parse_skin_mesh_info(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD index
)
3120 TRACE("(%p, %p, %u)\n", filedata
, mesh_data
, index
);
3122 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3123 if (FAILED(hr
)) return hr
;
3127 if (!mesh_data
->skin_info
) {
3128 if (data_size
< sizeof(WORD
) * 3) {
3129 WARN("truncated data (%ld bytes)\n", data_size
);
3132 /* Skip nMaxSkinWeightsPerVertex and nMaxSkinWeightsPerFace */
3133 data
+= 2 * sizeof(WORD
);
3134 mesh_data
->nb_bones
= *(WORD
*)data
;
3135 hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
, mesh_data
->nb_bones
, &mesh_data
->skin_info
);
3138 DWORD nb_influences
;
3140 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
3141 name
= *(const char**)data
;
3142 data
+= sizeof(char*);
3144 nb_influences
= *(DWORD
*)data
;
3145 data
+= sizeof(DWORD
);
3147 if (data_size
< (sizeof(char*) + sizeof(DWORD
) + nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
)) + 16 * sizeof(FLOAT
))) {
3148 WARN("truncated data (%ld bytes)\n", data_size
);
3152 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneName(mesh_data
->skin_info
, index
, name
);
3154 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneInfluence(mesh_data
->skin_info
, index
, nb_influences
,
3155 (const DWORD
*)data
, (const FLOAT
*)(data
+ nb_influences
* sizeof(DWORD
)));
3157 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneOffsetMatrix(mesh_data
->skin_info
, index
,
3158 (const D3DMATRIX
*)(data
+ nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
))));
3162 filedata
->lpVtbl
->Unlock(filedata
);
3166 /* for provide_flags parameters */
3167 #define PROVIDE_MATERIALS 0x1
3168 #define PROVIDE_SKININFO 0x2
3169 #define PROVIDE_ADJACENCY 0x4
3171 static HRESULT
parse_mesh(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
3175 const BYTE
*data
, *in_ptr
;
3176 DWORD
*index_out_ptr
;
3178 ID3DXFileData
*child
= NULL
;
3181 DWORD nb_skin_weights_info
= 0;
3186 * array Vector vertices[nVertices];
3188 * array MeshFace faces[nFaces];
3193 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3194 if (FAILED(hr
)) return hr
;
3199 if (data_size
< sizeof(DWORD
) * 2) {
3200 WARN("truncated data (%ld bytes)\n", data_size
);
3203 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
3204 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
)) {
3205 WARN("truncated data (%ld bytes)\n", data_size
);
3208 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
3210 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
3211 in_ptr
+= sizeof(DWORD
);
3213 mesh_data
->num_tri_faces
= 0;
3214 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3216 DWORD num_poly_vertices
;
3219 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
)) {
3220 WARN("truncated data (%ld bytes)\n", data_size
);
3223 num_poly_vertices
= *(DWORD
*)in_ptr
;
3224 in_ptr
+= sizeof(DWORD
);
3225 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
)) {
3226 WARN("truncated data (%ld bytes)\n", data_size
);
3229 if (num_poly_vertices
< 3) {
3230 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
3233 for (j
= 0; j
< num_poly_vertices
; j
++) {
3234 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
3235 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
3236 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
3239 in_ptr
+= sizeof(DWORD
);
3241 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
3244 mesh_data
->fvf
= D3DFVF_XYZ
;
3246 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
3247 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
3248 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
3249 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
3250 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
3251 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
3252 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
) {
3257 in_ptr
= data
+ sizeof(DWORD
);
3258 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
3259 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
3261 index_out_ptr
= mesh_data
->indices
;
3262 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3266 count
= *(DWORD
*)in_ptr
;
3267 in_ptr
+= sizeof(DWORD
);
3268 mesh_data
->num_tri_per_face
[i
] = count
- 2;
3271 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
3272 in_ptr
+= sizeof(DWORD
);
3276 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3280 for (i
= 0; i
< nb_children
; i
++)
3282 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3285 hr
= child
->lpVtbl
->GetType(child
, &type
);
3289 if (IsEqualGUID(&type
, &TID_D3DRMMeshNormals
)) {
3290 hr
= parse_normals(child
, mesh_data
);
3291 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshVertexColors
)) {
3292 hr
= parse_vertex_colors(child
, mesh_data
);
3293 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshTextureCoords
)) {
3294 hr
= parse_texture_coords(child
, mesh_data
);
3295 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshMaterialList
) &&
3296 (provide_flags
& PROVIDE_MATERIALS
))
3298 hr
= parse_material_list(child
, mesh_data
);
3299 } else if (provide_flags
& PROVIDE_SKININFO
) {
3300 if (IsEqualGUID(&type
, &DXFILEOBJ_XSkinMeshHeader
)) {
3301 if (mesh_data
->skin_info
) {
3302 WARN("Skin mesh header already encountered\n");
3306 hr
= parse_skin_mesh_info(child
, mesh_data
, 0);
3309 } else if (IsEqualGUID(&type
, &DXFILEOBJ_SkinWeights
)) {
3310 if (!mesh_data
->skin_info
) {
3311 WARN("Skin weights found but skin mesh header not encountered yet\n");
3315 hr
= parse_skin_mesh_info(child
, mesh_data
, nb_skin_weights_info
);
3318 nb_skin_weights_info
++;
3324 IUnknown_Release(child
);
3328 if (mesh_data
->skin_info
&& (nb_skin_weights_info
!= mesh_data
->nb_bones
)) {
3329 WARN("Mismatch between nb skin weights info %u encountered and nb bones %u from skin mesh header\n",
3330 nb_skin_weights_info
, mesh_data
->nb_bones
);
3339 IUnknown_Release(child
);
3340 filedata
->lpVtbl
->Unlock(filedata
);
3344 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
3345 ID3DXBuffer
**effects
)
3348 D3DXEFFECTINSTANCE
*effect_ptr
;
3350 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3351 static const struct {
3352 const char *param_name
;
3356 } material_effects
[] = {
3357 #define EFFECT_TABLE_ENTRY(str, field) \
3358 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
3359 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
3360 EFFECT_TABLE_ENTRY("Power", Power
),
3361 EFFECT_TABLE_ENTRY("Specular", Specular
),
3362 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
3363 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
3364 #undef EFFECT_TABLE_ENTRY
3366 static const char texture_paramname
[] = "Texture0@Name";
3370 /* effects buffer layout:
3372 * D3DXEFFECTINSTANCE effects[num_materials];
3373 * for (effect in effects)
3375 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
3376 * for (default in defaults)
3378 * *default.pParamName;
3383 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
3384 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
3385 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
3386 buffer_size
+= material_effects
[i
].name_size
;
3387 buffer_size
+= material_effects
[i
].num_bytes
;
3389 buffer_size
*= num_materials
;
3390 for (i
= 0; i
< num_materials
; i
++) {
3391 if (material_ptr
[i
].pTextureFilename
) {
3392 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
3393 buffer_size
+= sizeof(texture_paramname
);
3394 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
3398 hr
= D3DXCreateBuffer(buffer_size
, effects
);
3399 if (FAILED(hr
)) return hr
;
3400 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
3401 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
3403 for (i
= 0; i
< num_materials
; i
++)
3406 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
3408 effect_ptr
->pDefaults
= defaults
;
3409 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
3410 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
3412 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
3414 defaults
->pParamName
= (char *)out_ptr
;
3415 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
3416 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
3417 defaults
->Type
= D3DXEDT_FLOATS
;
3418 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
3419 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
3420 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3424 if (material_ptr
->pTextureFilename
)
3426 defaults
->pParamName
= (char *)out_ptr
;
3427 strcpy(defaults
->pParamName
, texture_paramname
);
3428 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
3429 defaults
->Type
= D3DXEDT_STRING
;
3430 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
3431 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
3432 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3437 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
3442 HRESULT WINAPI
D3DXLoadSkinMeshFromXof(struct ID3DXFileData
*filedata
, DWORD options
,
3443 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
3444 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXSkinInfo
**skin_info_out
,
3445 struct ID3DXMesh
**mesh_out
)
3448 DWORD
*index_in_ptr
;
3449 struct mesh_data mesh_data
;
3450 DWORD total_vertices
;
3451 ID3DXMesh
*d3dxmesh
= NULL
;
3452 ID3DXBuffer
*adjacency
= NULL
;
3453 ID3DXBuffer
*materials
= NULL
;
3454 ID3DXBuffer
*effects
= NULL
;
3455 struct vertex_duplication
{
3458 } *duplications
= NULL
;
3460 void *vertices
= NULL
;
3461 void *indices
= NULL
;
3463 DWORD provide_flags
= 0;
3465 TRACE("(%p, %x, %p, %p, %p, %p, %p, %p, %p)\n", filedata
, options
, device
, adjacency_out
, materials_out
,
3466 effects_out
, num_materials_out
, skin_info_out
, mesh_out
);
3468 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
3470 if (num_materials_out
|| materials_out
|| effects_out
)
3471 provide_flags
|= PROVIDE_MATERIALS
;
3473 provide_flags
|= PROVIDE_SKININFO
;
3475 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
3476 if (FAILED(hr
)) goto cleanup
;
3478 total_vertices
= mesh_data
.num_vertices
;
3479 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3480 /* duplicate vertices with multiple normals */
3481 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
3482 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
3483 if (!duplications
) {
3487 for (i
= 0; i
< total_vertices
; i
++)
3489 duplications
[i
].normal_index
= -1;
3490 list_init(&duplications
[i
].entry
);
3492 for (i
= 0; i
< num_face_indices
; i
++) {
3493 DWORD vertex_index
= mesh_data
.indices
[i
];
3494 DWORD normal_index
= mesh_data
.normal_indices
[i
];
3495 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
3497 if (dup_ptr
->normal_index
== -1) {
3498 dup_ptr
->normal_index
= normal_index
;
3500 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
3501 struct list
*dup_list
= &dup_ptr
->entry
;
3503 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
3504 if (new_normal
->x
== cur_normal
->x
&&
3505 new_normal
->y
== cur_normal
->y
&&
3506 new_normal
->z
== cur_normal
->z
)
3508 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3510 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
3511 dup_ptr
= &duplications
[total_vertices
++];
3512 dup_ptr
->normal_index
= normal_index
;
3513 list_add_tail(dup_list
, &dup_ptr
->entry
);
3514 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3517 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
3518 struct vertex_duplication
, entry
);
3525 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
3526 if (FAILED(hr
)) goto cleanup
;
3528 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, 0, &vertices
);
3529 if (FAILED(hr
)) goto cleanup
;
3532 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3533 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
3534 out_ptr
+= sizeof(D3DXVECTOR3
);
3535 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3536 if (duplications
[i
].normal_index
== -1)
3537 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
3539 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
3540 out_ptr
+= sizeof(D3DXVECTOR3
);
3542 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
3543 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
3544 out_ptr
+= sizeof(DWORD
);
3546 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
3547 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
3548 out_ptr
+= sizeof(D3DXVECTOR2
);
3551 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3552 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
3554 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3555 struct vertex_duplication
*dup_ptr
;
3556 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
3558 int j
= dup_ptr
- duplications
;
3559 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
3561 memcpy(dest_vertex
, out_ptr
, vertex_size
);
3562 dest_vertex
+= sizeof(D3DXVECTOR3
);
3563 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
3565 out_ptr
+= vertex_size
;
3568 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
3570 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, 0, &indices
);
3571 if (FAILED(hr
)) goto cleanup
;
3573 index_in_ptr
= mesh_data
.indices
;
3574 #define FILL_INDEX_BUFFER(indices_var) \
3575 for (i = 0; i < mesh_data.num_poly_faces; i++) \
3577 DWORD count = mesh_data.num_tri_per_face[i]; \
3578 WORD first_index = *index_in_ptr++; \
3580 *indices_var++ = first_index; \
3581 *indices_var++ = *index_in_ptr; \
3583 *indices_var++ = *index_in_ptr; \
3587 if (options
& D3DXMESH_32BIT
) {
3588 DWORD
*dword_indices
= indices
;
3589 FILL_INDEX_BUFFER(dword_indices
)
3591 WORD
*word_indices
= indices
;
3592 FILL_INDEX_BUFFER(word_indices
)
3594 #undef FILL_INDEX_BUFFER
3595 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
3597 if (mesh_data
.material_indices
) {
3598 DWORD
*attrib_buffer
= NULL
;
3599 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, 0, &attrib_buffer
);
3600 if (FAILED(hr
)) goto cleanup
;
3601 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
3603 DWORD count
= mesh_data
.num_tri_per_face
[i
];
3605 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
3607 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
3609 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
3610 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
3611 NULL
, NULL
, NULL
, NULL
);
3612 if (FAILED(hr
)) goto cleanup
;
3615 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
3616 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
3617 char *strings_out_ptr
;
3618 D3DXMATERIAL
*materials_ptr
;
3620 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3621 if (mesh_data
.materials
[i
].pTextureFilename
)
3622 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3625 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3626 if (FAILED(hr
)) goto cleanup
;
3628 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3629 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
3630 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
3631 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3632 if (materials_ptr
[i
].pTextureFilename
) {
3633 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
3634 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
3635 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3640 if (mesh_data
.num_materials
&& effects_out
) {
3641 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
3642 if (FAILED(hr
)) goto cleanup
;
3644 if (!materials_out
) {
3645 ID3DXBuffer_Release(materials
);
3650 if (adjacency_out
) {
3651 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
3652 if (FAILED(hr
)) goto cleanup
;
3653 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
3654 if (FAILED(hr
)) goto cleanup
;
3657 *mesh_out
= d3dxmesh
;
3658 if (adjacency_out
) *adjacency_out
= adjacency
;
3659 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
3660 if (materials_out
) *materials_out
= materials
;
3661 if (effects_out
) *effects_out
= effects
;
3662 if (skin_info_out
) *skin_info_out
= mesh_data
.skin_info
;
3667 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
3668 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3669 if (materials
) ID3DXBuffer_Release(materials
);
3670 if (effects
) ID3DXBuffer_Release(effects
);
3671 if (mesh_data
.skin_info
) mesh_data
.skin_info
->lpVtbl
->Release(mesh_data
.skin_info
);
3672 if (skin_info_out
) *skin_info_out
= NULL
;
3674 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
3675 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
3676 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
3677 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
3678 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
3679 destroy_materials(&mesh_data
);
3680 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
3681 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
3682 HeapFree(GetProcessHeap(), 0, duplications
);
3686 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3687 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3688 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3694 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3695 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3696 debugstr_a(filename
), options
, device
, alloc_hier
,
3697 load_user_data
, frame_hierarchy
, anim_controller
);
3700 return D3DERR_INVALIDCALL
;
3702 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3703 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3704 if (!filenameW
) return E_OUTOFMEMORY
;
3705 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3707 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
3708 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3709 HeapFree(GetProcessHeap(), 0, filenameW
);
3714 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3715 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3716 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3722 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3723 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3724 debugstr_w(filename
), options
, device
, alloc_hier
,
3725 load_user_data
, frame_hierarchy
, anim_controller
);
3728 return D3DERR_INVALIDCALL
;
3730 hr
= map_view_of_file(filename
, &buffer
, &size
);
3732 return D3DXERR_INVALIDDATA
;
3734 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
3735 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3737 UnmapViewOfFile(buffer
);
3742 static HRESULT
filedata_get_name(ID3DXFileData
*filedata
, char **name
)
3747 hr
= filedata
->lpVtbl
->GetName(filedata
, NULL
, &name_len
);
3748 if (FAILED(hr
)) return hr
;
3752 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
3753 if (!*name
) return E_OUTOFMEMORY
;
3755 hr
= filedata
->lpVtbl
->GetName(filedata
, *name
, &name_len
);
3757 HeapFree(GetProcessHeap(), 0, *name
);
3764 static HRESULT
load_mesh_container(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3765 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXMESHCONTAINER
**mesh_container
)
3768 ID3DXBuffer
*adjacency
= NULL
;
3769 ID3DXBuffer
*materials
= NULL
;
3770 ID3DXBuffer
*effects
= NULL
;
3771 ID3DXSkinInfo
*skin_info
= NULL
;
3772 D3DXMESHDATA mesh_data
;
3773 DWORD num_materials
= 0;
3776 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
3777 mesh_data
.u
.pMesh
= NULL
;
3779 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
3780 &adjacency
, &materials
, &effects
, &num_materials
,
3781 &skin_info
, &mesh_data
.u
.pMesh
);
3782 if (FAILED(hr
)) return hr
;
3784 hr
= filedata_get_name(filedata
, &name
);
3785 if (FAILED(hr
)) goto cleanup
;
3787 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
3788 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
3789 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
3791 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
3792 skin_info
, mesh_container
);
3795 if (materials
) ID3DXBuffer_Release(materials
);
3796 if (effects
) ID3DXBuffer_Release(effects
);
3797 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3798 if (skin_info
) IUnknown_Release(skin_info
);
3799 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
3800 HeapFree(GetProcessHeap(), 0, name
);
3804 static HRESULT
parse_transform_matrix(ID3DXFileData
*filedata
, D3DXMATRIX
*transform
)
3810 /* template Matrix4x4 {
3811 * array FLOAT matrix[16];
3813 * template FrameTransformMatrix {
3814 * Matrix4x4 frameMatrix;
3818 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3819 if (FAILED(hr
)) return hr
;
3821 if (data_size
!= sizeof(D3DXMATRIX
)) {
3822 WARN("incorrect data size (%ld bytes)\n", data_size
);
3823 filedata
->lpVtbl
->Unlock(filedata
);
3827 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
3829 filedata
->lpVtbl
->Unlock(filedata
);
3833 static HRESULT
load_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3834 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXFRAME
**frame_out
)
3838 ID3DXFileData
*child
;
3840 D3DXFRAME
*frame
= NULL
;
3841 D3DXMESHCONTAINER
**next_container
;
3842 D3DXFRAME
**next_child
;
3843 SIZE_T i
, nb_children
;
3845 hr
= filedata_get_name(filedata
, &name
);
3846 if (FAILED(hr
)) return hr
;
3848 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
3849 HeapFree(GetProcessHeap(), 0, name
);
3850 if (FAILED(hr
)) return E_FAIL
;
3853 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
3854 next_child
= &frame
->pFrameFirstChild
;
3855 next_container
= &frame
->pMeshContainer
;
3857 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3861 for (i
= 0; i
< nb_children
; i
++)
3863 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3866 hr
= child
->lpVtbl
->GetType(child
, &type
);
3870 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
3871 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
3873 next_container
= &(*next_container
)->pNextMeshContainer
;
3874 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
3875 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
3876 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
3877 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
3879 next_child
= &(*next_child
)->pFrameSibling
;
3884 IUnknown_Release(child
);
3889 IUnknown_Release(child
);
3893 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
3894 struct IDirect3DDevice9
*device
, struct ID3DXAllocateHierarchy
*alloc_hier
,
3895 struct ID3DXLoadUserData
*load_user_data
, D3DXFRAME
**frame_hierarchy
,
3896 struct ID3DXAnimationController
**anim_controller
)
3899 ID3DXFile
*d3dxfile
= NULL
;
3900 ID3DXFileEnumObject
*enumobj
= NULL
;
3901 ID3DXFileData
*filedata
= NULL
;
3902 D3DXF_FILELOADMEMORY source
;
3903 D3DXFRAME
*first_frame
= NULL
;
3904 D3DXFRAME
**next_frame
= &first_frame
;
3905 SIZE_T i
, nb_children
;
3908 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3909 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3911 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
3912 return D3DERR_INVALIDCALL
;
3915 FIXME("Loading user data not implemented.\n");
3919 hr
= D3DXFileCreate(&d3dxfile
);
3920 if (FAILED(hr
)) goto cleanup
;
3922 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3923 if (FAILED(hr
)) goto cleanup
;
3925 source
.lpMemory
= (void*)memory
;
3926 source
.dSize
= memory_size
;
3927 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
3928 if (FAILED(hr
)) goto cleanup
;
3930 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
3934 for (i
= 0; i
< nb_children
; i
++)
3936 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
3940 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
3941 if (SUCCEEDED(hr
)) {
3942 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
3943 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
3949 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
3951 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
3952 if (FAILED(hr
)) goto cleanup
;
3953 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
3954 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
3955 if (FAILED(hr
)) goto cleanup
;
3958 next_frame
= &(*next_frame
)->pFrameSibling
;
3961 filedata
->lpVtbl
->Release(filedata
);
3969 } else if (first_frame
->pFrameSibling
) {
3970 D3DXFRAME
*root_frame
= NULL
;
3971 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
3976 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
3977 root_frame
->pFrameFirstChild
= first_frame
;
3978 *frame_hierarchy
= root_frame
;
3981 *frame_hierarchy
= first_frame
;
3985 if (anim_controller
)
3987 *anim_controller
= NULL
;
3988 FIXME("Animation controller creation not implemented.\n");
3992 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
3993 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
3994 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
3995 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
3999 HRESULT WINAPI
D3DXCleanMesh(D3DXCLEANTYPE clean_type
, ID3DXMesh
*mesh_in
, const DWORD
*adjacency_in
,
4000 ID3DXMesh
**mesh_out
, DWORD
*adjacency_out
, ID3DXBuffer
**errors_and_warnings
)
4002 FIXME("(%u, %p, %p, %p, %p, %p)\n", clean_type
, mesh_in
, adjacency_in
, mesh_out
, adjacency_out
, errors_and_warnings
);
4007 HRESULT WINAPI
D3DXFrameDestroy(D3DXFRAME
*frame
, ID3DXAllocateHierarchy
*alloc_hier
)
4012 TRACE("(%p, %p)\n", frame
, alloc_hier
);
4014 if (!frame
|| !alloc_hier
)
4015 return D3DERR_INVALIDCALL
;
4018 D3DXMESHCONTAINER
*container
;
4019 D3DXFRAME
*current_frame
;
4021 if (frame
->pFrameSibling
) {
4022 current_frame
= frame
->pFrameSibling
;
4023 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
4024 current_frame
->pFrameSibling
= NULL
;
4026 current_frame
= frame
;
4030 if (current_frame
->pFrameFirstChild
) {
4031 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
4032 if (FAILED(hr
)) return hr
;
4033 current_frame
->pFrameFirstChild
= NULL
;
4036 container
= current_frame
->pMeshContainer
;
4038 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
4039 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
4040 if (FAILED(hr
)) return hr
;
4041 container
= next_container
;
4043 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
4044 if (FAILED(hr
)) return hr
;
4049 HRESULT WINAPI
D3DXLoadMeshFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4050 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4051 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4057 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4058 "effect_instances %p, num_materials %p, mesh %p.\n",
4059 debugstr_a(filename
), options
, device
, adjacency
, materials
,
4060 effect_instances
, num_materials
, mesh
);
4063 return D3DERR_INVALIDCALL
;
4065 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
4066 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4067 if (!filenameW
) return E_OUTOFMEMORY
;
4068 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
4070 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
4071 effect_instances
, num_materials
, mesh
);
4072 HeapFree(GetProcessHeap(), 0, filenameW
);
4077 HRESULT WINAPI
D3DXLoadMeshFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4078 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4079 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4085 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4086 "effect_instances %p, num_materials %p, mesh %p.\n",
4087 debugstr_w(filename
), options
, device
, adjacency
, materials
,
4088 effect_instances
, num_materials
, mesh
);
4091 return D3DERR_INVALIDCALL
;
4093 hr
= map_view_of_file(filename
, &buffer
, &size
);
4095 return D3DXERR_INVALIDDATA
;
4097 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4098 materials
, effect_instances
, num_materials
, mesh
);
4100 UnmapViewOfFile(buffer
);
4105 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
, const char *name
, const char *type
, DWORD options
,
4106 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
,
4107 struct ID3DXBuffer
**effect_instances
, DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4114 TRACE("module %p, name %s, type %s, options %#x, device %p, adjacency %p, "
4115 "materials %p, effect_instances %p, num_materials %p, mesh %p.\n",
4116 module
, debugstr_a(name
), debugstr_a(type
), options
, device
, adjacency
,
4117 materials
, effect_instances
, num_materials
, mesh
);
4119 resinfo
= FindResourceA(module
, name
, type
);
4120 if (!resinfo
) return D3DXERR_INVALIDDATA
;
4122 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
4123 if (FAILED(hr
)) return D3DXERR_INVALIDDATA
;
4125 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4126 materials
, effect_instances
, num_materials
, mesh
);
4129 struct mesh_container
4133 ID3DXBuffer
*adjacency
;
4134 ID3DXBuffer
*materials
;
4135 ID3DXBuffer
*effects
;
4136 DWORD num_materials
;
4137 D3DXMATRIX transform
;
4140 static HRESULT
parse_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
4141 const D3DXMATRIX
*parent_transform
, struct list
*container_list
, DWORD provide_flags
)
4144 D3DXMATRIX transform
= *parent_transform
;
4145 ID3DXFileData
*child
;
4147 SIZE_T i
, nb_children
;
4149 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
4153 for (i
= 0; i
< nb_children
; i
++)
4155 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
4158 hr
= child
->lpVtbl
->GetType(child
, &type
);
4162 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
4163 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
4169 list_add_tail(container_list
, &container
->entry
);
4170 container
->transform
= transform
;
4172 hr
= D3DXLoadSkinMeshFromXof(child
, options
, device
,
4173 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
4174 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
4175 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
4176 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
4177 D3DXMATRIX new_transform
;
4178 hr
= parse_transform_matrix(child
, &new_transform
);
4179 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
4180 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
4181 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
4186 IUnknown_Release(child
);
4191 IUnknown_Release(child
);
4195 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
4196 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
4197 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXMesh
**mesh_out
)
4200 ID3DXFile
*d3dxfile
= NULL
;
4201 ID3DXFileEnumObject
*enumobj
= NULL
;
4202 ID3DXFileData
*filedata
= NULL
;
4203 D3DXF_FILELOADMEMORY source
;
4204 ID3DXBuffer
*materials
= NULL
;
4205 ID3DXBuffer
*effects
= NULL
;
4206 ID3DXBuffer
*adjacency
= NULL
;
4207 struct list container_list
= LIST_INIT(container_list
);
4208 struct mesh_container
*container_ptr
, *next_container_ptr
;
4209 DWORD num_materials
;
4210 DWORD num_faces
, num_vertices
;
4211 D3DXMATRIX identity
;
4212 DWORD provide_flags
= 0;
4214 ID3DXMesh
*concat_mesh
= NULL
;
4215 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
4216 BYTE
*concat_vertices
= NULL
;
4217 void *concat_indices
= NULL
;
4219 DWORD concat_vertex_size
;
4220 SIZE_T i
, nb_children
;
4223 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
4224 device
, adjacency_out
, materials_out
, effects_out
, num_materials_out
, mesh_out
);
4226 if (!memory
|| !memory_size
|| !device
|| !mesh_out
)
4227 return D3DERR_INVALIDCALL
;
4229 hr
= D3DXFileCreate(&d3dxfile
);
4230 if (FAILED(hr
)) goto cleanup
;
4232 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
4233 if (FAILED(hr
)) goto cleanup
;
4235 source
.lpMemory
= (void*)memory
;
4236 source
.dSize
= memory_size
;
4237 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
4238 if (FAILED(hr
)) goto cleanup
;
4240 D3DXMatrixIdentity(&identity
);
4241 if (adjacency_out
) provide_flags
|= PROVIDE_ADJACENCY
;
4242 if (materials_out
|| effects_out
) provide_flags
|= PROVIDE_MATERIALS
;
4244 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
4248 for (i
= 0; i
< nb_children
; i
++)
4250 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
4254 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
4255 if (SUCCEEDED(hr
)) {
4256 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
4257 container_ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container_ptr
));
4258 if (!container_ptr
) {
4262 list_add_tail(&container_list
, &container_ptr
->entry
);
4263 D3DXMatrixIdentity(&container_ptr
->transform
);
4265 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
4266 (provide_flags
& PROVIDE_ADJACENCY
) ? &container_ptr
->adjacency
: NULL
,
4267 (provide_flags
& PROVIDE_MATERIALS
) ? &container_ptr
->materials
: NULL
,
4268 NULL
, &container_ptr
->num_materials
, NULL
, &container_ptr
->mesh
);
4269 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
4270 hr
= parse_frame(filedata
, options
, device
, &identity
, &container_list
, provide_flags
);
4272 if (FAILED(hr
)) goto cleanup
;
4274 filedata
->lpVtbl
->Release(filedata
);
4280 enumobj
->lpVtbl
->Release(enumobj
);
4282 d3dxfile
->lpVtbl
->Release(d3dxfile
);
4285 if (list_empty(&container_list
)) {
4294 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4296 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4297 fvf
|= mesh
->lpVtbl
->GetFVF(mesh
);
4298 num_faces
+= mesh
->lpVtbl
->GetNumFaces(mesh
);
4299 num_vertices
+= mesh
->lpVtbl
->GetNumVertices(mesh
);
4300 num_materials
+= container_ptr
->num_materials
;
4303 hr
= D3DXCreateMeshFVF(num_faces
, num_vertices
, options
, fvf
, device
, &concat_mesh
);
4304 if (FAILED(hr
)) goto cleanup
;
4306 hr
= concat_mesh
->lpVtbl
->GetDeclaration(concat_mesh
, concat_decl
);
4307 if (FAILED(hr
)) goto cleanup
;
4309 concat_vertex_size
= D3DXGetDeclVertexSize(concat_decl
, 0);
4311 hr
= concat_mesh
->lpVtbl
->LockVertexBuffer(concat_mesh
, 0, (void**)&concat_vertices
);
4312 if (FAILED(hr
)) goto cleanup
;
4314 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4316 D3DVERTEXELEMENT9 mesh_decl
[MAX_FVF_DECL_SIZE
];
4317 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4318 DWORD num_mesh_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
4319 DWORD mesh_vertex_size
;
4320 const BYTE
*mesh_vertices
;
4323 hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, mesh_decl
);
4324 if (FAILED(hr
)) goto cleanup
;
4326 mesh_vertex_size
= D3DXGetDeclVertexSize(mesh_decl
, 0);
4328 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_vertices
);
4329 if (FAILED(hr
)) goto cleanup
;
4331 for (i
= 0; i
< num_mesh_vertices
; i
++) {
4335 D3DXVec3TransformCoord((D3DXVECTOR3
*)concat_vertices
,
4336 (D3DXVECTOR3
*)mesh_vertices
,
4337 &container_ptr
->transform
);
4338 for (j
= 1; concat_decl
[j
].Stream
!= 0xff; j
++)
4340 if (concat_decl
[j
].Usage
== mesh_decl
[k
].Usage
&&
4341 concat_decl
[j
].UsageIndex
== mesh_decl
[k
].UsageIndex
)
4343 if (concat_decl
[j
].Usage
== D3DDECLUSAGE_NORMAL
) {
4344 D3DXVec3TransformCoord((D3DXVECTOR3
*)(concat_vertices
+ concat_decl
[j
].Offset
),
4345 (D3DXVECTOR3
*)(mesh_vertices
+ mesh_decl
[k
].Offset
),
4346 &container_ptr
->transform
);
4348 memcpy(concat_vertices
+ concat_decl
[j
].Offset
,
4349 mesh_vertices
+ mesh_decl
[k
].Offset
,
4350 d3dx_decltype_size
[mesh_decl
[k
].Type
]);
4355 mesh_vertices
+= mesh_vertex_size
;
4356 concat_vertices
+= concat_vertex_size
;
4359 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
4362 concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4363 concat_vertices
= NULL
;
4365 hr
= concat_mesh
->lpVtbl
->LockIndexBuffer(concat_mesh
, 0, &concat_indices
);
4366 if (FAILED(hr
)) goto cleanup
;
4369 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4371 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4372 const void *mesh_indices
;
4373 DWORD num_mesh_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4376 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_indices
);
4377 if (FAILED(hr
)) goto cleanup
;
4379 if (options
& D3DXMESH_32BIT
) {
4380 DWORD
*dest
= concat_indices
;
4381 const DWORD
*src
= mesh_indices
;
4382 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4383 *dest
++ = index_offset
+ *src
++;
4384 concat_indices
= dest
;
4386 WORD
*dest
= concat_indices
;
4387 const WORD
*src
= mesh_indices
;
4388 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4389 *dest
++ = index_offset
+ *src
++;
4390 concat_indices
= dest
;
4392 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
4394 index_offset
+= num_mesh_faces
* 3;
4397 concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4398 concat_indices
= NULL
;
4400 if (num_materials
) {
4401 DWORD
*concat_attrib_buffer
= NULL
;
4404 hr
= concat_mesh
->lpVtbl
->LockAttributeBuffer(concat_mesh
, 0, &concat_attrib_buffer
);
4405 if (FAILED(hr
)) goto cleanup
;
4407 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4409 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4410 const DWORD
*mesh_attrib_buffer
= NULL
;
4411 DWORD count
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4413 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, D3DLOCK_READONLY
, (DWORD
**)&mesh_attrib_buffer
);
4415 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4420 *concat_attrib_buffer
++ = offset
+ *mesh_attrib_buffer
++;
4422 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
4423 offset
+= container_ptr
->num_materials
;
4425 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4428 if (materials_out
|| effects_out
) {
4429 D3DXMATERIAL
*out_ptr
;
4430 if (!num_materials
) {
4431 /* create default material */
4432 hr
= D3DXCreateBuffer(sizeof(D3DXMATERIAL
), &materials
);
4433 if (FAILED(hr
)) goto cleanup
;
4435 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4436 out_ptr
->MatD3D
.Diffuse
.r
= 0.5f
;
4437 out_ptr
->MatD3D
.Diffuse
.g
= 0.5f
;
4438 out_ptr
->MatD3D
.Diffuse
.b
= 0.5f
;
4439 out_ptr
->MatD3D
.Specular
.r
= 0.5f
;
4440 out_ptr
->MatD3D
.Specular
.g
= 0.5f
;
4441 out_ptr
->MatD3D
.Specular
.b
= 0.5f
;
4442 /* D3DXCreateBuffer initializes the rest to zero */
4444 DWORD buffer_size
= num_materials
* sizeof(D3DXMATERIAL
);
4445 char *strings_out_ptr
;
4447 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4449 if (container_ptr
->materials
) {
4451 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4452 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4454 if (in_ptr
->pTextureFilename
)
4455 buffer_size
+= strlen(in_ptr
->pTextureFilename
) + 1;
4461 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
4462 if (FAILED(hr
)) goto cleanup
;
4463 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4464 strings_out_ptr
= (char*)(out_ptr
+ num_materials
);
4466 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4468 if (container_ptr
->materials
) {
4470 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4471 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4473 out_ptr
->MatD3D
= in_ptr
->MatD3D
;
4474 if (in_ptr
->pTextureFilename
) {
4475 out_ptr
->pTextureFilename
= strings_out_ptr
;
4476 strcpy(out_ptr
->pTextureFilename
, in_ptr
->pTextureFilename
);
4477 strings_out_ptr
+= strlen(in_ptr
->pTextureFilename
) + 1;
4490 generate_effects(materials
, num_materials
, &effects
);
4491 if (!materials_out
) {
4492 ID3DXBuffer_Release(materials
);
4497 if (adjacency_out
) {
4498 if (!list_next(&container_list
, list_head(&container_list
))) {
4499 container_ptr
= LIST_ENTRY(list_head(&container_list
), struct mesh_container
, entry
);
4500 adjacency
= container_ptr
->adjacency
;
4501 container_ptr
->adjacency
= NULL
;
4506 hr
= D3DXCreateBuffer(num_faces
* 3 * sizeof(DWORD
), &adjacency
);
4507 if (FAILED(hr
)) goto cleanup
;
4509 out_ptr
= ID3DXBuffer_GetBufferPointer(adjacency
);
4510 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4513 DWORD count
= 3 * container_ptr
->mesh
->lpVtbl
->GetNumFaces(container_ptr
->mesh
);
4514 DWORD
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->adjacency
);
4516 for (i
= 0; i
< count
; i
++)
4517 *out_ptr
++ = offset
+ *in_ptr
++;
4524 *mesh_out
= concat_mesh
;
4525 if (adjacency_out
) *adjacency_out
= adjacency
;
4526 if (materials_out
) *materials_out
= materials
;
4527 if (effects_out
) *effects_out
= effects
;
4528 if (num_materials_out
) *num_materials_out
= num_materials
;
4532 if (concat_indices
) concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4533 if (concat_vertices
) concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4534 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
4535 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
4536 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4538 if (concat_mesh
) IUnknown_Release(concat_mesh
);
4539 if (materials
) ID3DXBuffer_Release(materials
);
4540 if (effects
) ID3DXBuffer_Release(effects
);
4541 if (adjacency
) ID3DXBuffer_Release(adjacency
);
4543 LIST_FOR_EACH_ENTRY_SAFE(container_ptr
, next_container_ptr
, &container_list
, struct mesh_container
, entry
)
4545 if (container_ptr
->mesh
) IUnknown_Release(container_ptr
->mesh
);
4546 if (container_ptr
->adjacency
) ID3DXBuffer_Release(container_ptr
->adjacency
);
4547 if (container_ptr
->materials
) ID3DXBuffer_Release(container_ptr
->materials
);
4548 if (container_ptr
->effects
) ID3DXBuffer_Release(container_ptr
->effects
);
4549 HeapFree(GetProcessHeap(), 0, container_ptr
);
4556 D3DXVECTOR3 position
;
4560 HRESULT WINAPI
D3DXCreatePolygon(struct IDirect3DDevice9
*device
, float length
, UINT sides
,
4561 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4565 struct vertex
*vertices
;
4567 DWORD (*adjacency_buf
)[3];
4571 TRACE("device %p, length %f, sides %u, mesh %p, adjacency %p.\n",
4572 device
, length
, sides
, mesh
, adjacency
);
4574 if (!device
|| length
< 0.0f
|| sides
< 3 || !mesh
)
4575 return D3DERR_INVALIDCALL
;
4577 if (FAILED(hr
= D3DXCreateMeshFVF(sides
, sides
+ 1, D3DXMESH_MANAGED
,
4578 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &polygon
)))
4583 if (FAILED(hr
= polygon
->lpVtbl
->LockVertexBuffer(polygon
, 0, (void **)&vertices
)))
4585 polygon
->lpVtbl
->Release(polygon
);
4589 if (FAILED(hr
= polygon
->lpVtbl
->LockIndexBuffer(polygon
, 0, (void **)&faces
)))
4591 polygon
->lpVtbl
->UnlockVertexBuffer(polygon
);
4592 polygon
->lpVtbl
->Release(polygon
);
4596 scale
= 0.5f
* length
/ sinf(D3DX_PI
/ sides
);
4598 vertices
[0].position
.x
= 0.0f
;
4599 vertices
[0].position
.y
= 0.0f
;
4600 vertices
[0].position
.z
= 0.0f
;
4601 vertices
[0].normal
.x
= 0.0f
;
4602 vertices
[0].normal
.y
= 0.0f
;
4603 vertices
[0].normal
.z
= 1.0f
;
4605 for (i
= 0; i
< sides
; ++i
)
4607 vertices
[i
+ 1].position
.x
= cosf(2.0f
* D3DX_PI
* i
/ sides
) * scale
;
4608 vertices
[i
+ 1].position
.y
= sinf(2.0f
* D3DX_PI
* i
/ sides
) * scale
;
4609 vertices
[i
+ 1].position
.z
= 0.0f
;
4610 vertices
[i
+ 1].normal
.x
= 0.0f
;
4611 vertices
[i
+ 1].normal
.y
= 0.0f
;
4612 vertices
[i
+ 1].normal
.z
= 1.0f
;
4615 faces
[i
][1] = i
+ 1;
4616 faces
[i
][2] = i
+ 2;
4619 faces
[sides
- 1][2] = 1;
4621 polygon
->lpVtbl
->UnlockVertexBuffer(polygon
);
4622 polygon
->lpVtbl
->UnlockIndexBuffer(polygon
);
4626 if (FAILED(hr
= D3DXCreateBuffer(sides
* sizeof(DWORD
) * 3, adjacency
)))
4628 polygon
->lpVtbl
->Release(polygon
);
4632 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4633 for (i
= 0; i
< sides
; ++i
)
4635 adjacency_buf
[i
][0] = i
- 1;
4636 adjacency_buf
[i
][1] = ~0U;
4637 adjacency_buf
[i
][2] = i
+ 1;
4639 adjacency_buf
[0][0] = sides
- 1;
4640 adjacency_buf
[sides
- 1][2] = 0;
4648 HRESULT WINAPI
D3DXCreateBox(struct IDirect3DDevice9
*device
, float width
, float height
,
4649 float depth
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4653 struct vertex
*vertices
;
4655 DWORD
*adjacency_buf
;
4656 unsigned int i
, face
;
4657 static const D3DXVECTOR3 unit_box
[] =
4659 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, -0.5f
},
4660 {-0.5f
, 0.5f
, -0.5f
}, {-0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, 0.5f
, -0.5f
},
4661 { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, -0.5f
},
4662 {-0.5f
, -0.5f
, 0.5f
}, {-0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}, { 0.5f
, -0.5f
, 0.5f
},
4663 {-0.5f
, -0.5f
, 0.5f
}, { 0.5f
, -0.5f
, 0.5f
}, { 0.5f
, 0.5f
, 0.5f
}, {-0.5f
, 0.5f
, 0.5f
},
4664 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}
4666 static const D3DXVECTOR3 normals
[] =
4668 {-1.0f
, 0.0f
, 0.0f
}, { 0.0f
, 1.0f
, 0.0f
}, { 1.0f
, 0.0f
, 0.0f
},
4669 { 0.0f
, -1.0f
, 0.0f
}, { 0.0f
, 0.0f
, 1.0f
}, { 0.0f
, 0.0f
, -1.0f
}
4671 static const DWORD adjacency_table
[] =
4673 6, 9, 1, 2, 10, 0, 1, 9, 3, 4, 10, 2,
4674 3, 8, 5, 7, 11, 4, 0, 11, 7, 5, 8, 6,
4675 7, 4, 9, 2, 0, 8, 1, 3, 11, 5, 6, 10
4678 TRACE("device %p, width %f, height %f, depth %f, mesh %p, adjacency %p\n",
4679 device
, width
, height
, depth
, mesh
, adjacency
);
4681 if (!device
|| width
< 0.0f
|| height
< 0.0f
|| depth
< 0.0f
|| !mesh
)
4683 return D3DERR_INVALIDCALL
;
4686 if (FAILED(hr
= D3DXCreateMeshFVF(12, 24, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &box
)))
4691 if (FAILED(hr
= box
->lpVtbl
->LockVertexBuffer(box
, 0, (void **)&vertices
)))
4693 box
->lpVtbl
->Release(box
);
4697 if (FAILED(hr
= box
->lpVtbl
->LockIndexBuffer(box
, 0, (void **)&faces
)))
4699 box
->lpVtbl
->UnlockVertexBuffer(box
);
4700 box
->lpVtbl
->Release(box
);
4704 for (i
= 0; i
< 24; i
++)
4706 vertices
[i
].position
.x
= width
* unit_box
[i
].x
;
4707 vertices
[i
].position
.y
= height
* unit_box
[i
].y
;
4708 vertices
[i
].position
.z
= depth
* unit_box
[i
].z
;
4709 vertices
[i
].normal
.x
= normals
[i
/ 4].x
;
4710 vertices
[i
].normal
.y
= normals
[i
/ 4].y
;
4711 vertices
[i
].normal
.z
= normals
[i
/ 4].z
;
4715 for (i
= 0; i
< 12; i
++)
4717 faces
[i
][0] = face
++;
4718 faces
[i
][1] = face
++;
4719 faces
[i
][2] = (i
% 2) ? face
- 4 : face
;
4722 box
->lpVtbl
->UnlockIndexBuffer(box
);
4723 box
->lpVtbl
->UnlockVertexBuffer(box
);
4727 if (FAILED(hr
= D3DXCreateBuffer(sizeof(adjacency_table
), adjacency
)))
4729 box
->lpVtbl
->Release(box
);
4733 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4734 memcpy(adjacency_buf
, adjacency_table
, sizeof(adjacency_table
));
4742 typedef WORD face
[3];
4750 static void free_sincos_table(struct sincos_table
*sincos_table
)
4752 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
4753 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4756 /* pre compute sine and cosine tables; caller must free */
4757 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
4762 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
4763 if (!sincos_table
->sin
)
4767 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
4768 if (!sincos_table
->cos
)
4770 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4774 angle
= angle_start
;
4775 for (i
= 0; i
< n
; i
++)
4777 sincos_table
->sin
[i
] = sinf(angle
);
4778 sincos_table
->cos
[i
] = cosf(angle
);
4779 angle
+= angle_step
;
4785 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
4787 return stack
*slices
+slice
+1;
4790 HRESULT WINAPI
D3DXCreateSphere(struct IDirect3DDevice9
*device
, float radius
, UINT slices
,
4791 UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4793 DWORD number_of_vertices
, number_of_faces
;
4796 struct vertex
*vertices
;
4798 float phi_step
, phi_start
;
4799 struct sincos_table phi
;
4800 float theta_step
, theta
, sin_theta
, cos_theta
;
4801 DWORD vertex
, face
, stack
, slice
;
4803 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
4805 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
4807 return D3DERR_INVALIDCALL
;
4810 number_of_vertices
= 2 + slices
* (stacks
-1);
4811 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
4813 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4814 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
4820 if (FAILED(hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, 0, (void **)&vertices
)))
4822 sphere
->lpVtbl
->Release(sphere
);
4826 if (FAILED(hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, 0, (void **)&faces
)))
4828 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4829 sphere
->lpVtbl
->Release(sphere
);
4833 /* phi = angle on xz plane wrt z axis */
4834 phi_step
= -2.0f
* D3DX_PI
/ slices
;
4835 phi_start
= D3DX_PI
/ 2.0f
;
4837 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
4839 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4840 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4841 sphere
->lpVtbl
->Release(sphere
);
4842 return E_OUTOFMEMORY
;
4845 /* theta = angle on xy plane wrt x axis */
4846 theta_step
= D3DX_PI
/ stacks
;
4852 vertices
[vertex
].normal
.x
= 0.0f
;
4853 vertices
[vertex
].normal
.y
= 0.0f
;
4854 vertices
[vertex
].normal
.z
= 1.0f
;
4855 vertices
[vertex
].position
.x
= 0.0f
;
4856 vertices
[vertex
].position
.y
= 0.0f
;
4857 vertices
[vertex
].position
.z
= radius
;
4860 for (stack
= 0; stack
< stacks
- 1; stack
++)
4862 sin_theta
= sinf(theta
);
4863 cos_theta
= cosf(theta
);
4865 for (slice
= 0; slice
< slices
; slice
++)
4867 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
4868 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
4869 vertices
[vertex
].normal
.z
= cos_theta
;
4870 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
4871 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
4872 vertices
[vertex
].position
.z
= radius
* cos_theta
;
4879 /* top stack is triangle fan */
4881 faces
[face
][1] = slice
+ 1;
4882 faces
[face
][2] = slice
;
4887 /* stacks in between top and bottom are quad strips */
4888 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4889 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4890 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4893 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4894 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
4895 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4901 theta
+= theta_step
;
4907 faces
[face
][2] = slice
;
4912 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4913 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4914 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4917 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4918 faces
[face
][1] = vertex_index(slices
, 0, stack
);
4919 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4924 vertices
[vertex
].position
.x
= 0.0f
;
4925 vertices
[vertex
].position
.y
= 0.0f
;
4926 vertices
[vertex
].position
.z
= -radius
;
4927 vertices
[vertex
].normal
.x
= 0.0f
;
4928 vertices
[vertex
].normal
.y
= 0.0f
;
4929 vertices
[vertex
].normal
.z
= -1.0f
;
4931 /* bottom stack is triangle fan */
4932 for (slice
= 1; slice
< slices
; slice
++)
4934 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4935 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4936 faces
[face
][2] = vertex
;
4940 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4941 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4942 faces
[face
][2] = vertex
;
4944 free_sincos_table(&phi
);
4945 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4946 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4951 if (FAILED(hr
= D3DXCreateBuffer(number_of_faces
* sizeof(DWORD
) * 3, adjacency
)))
4953 sphere
->lpVtbl
->Release(sphere
);
4957 if (FAILED(hr
= sphere
->lpVtbl
->GenerateAdjacency(sphere
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
4959 (*adjacency
)->lpVtbl
->Release(*adjacency
);
4960 sphere
->lpVtbl
->Release(sphere
);
4970 HRESULT WINAPI
D3DXCreateCylinder(struct IDirect3DDevice9
*device
, float radius1
, float radius2
,
4971 float length
, UINT slices
, UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4973 DWORD number_of_vertices
, number_of_faces
;
4975 ID3DXMesh
*cylinder
;
4976 struct vertex
*vertices
;
4978 float theta_step
, theta_start
;
4979 struct sincos_table theta
;
4980 float delta_radius
, radius
, radius_step
;
4981 float z
, z_step
, z_normal
;
4982 DWORD vertex
, face
, slice
, stack
;
4984 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
4986 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
4988 return D3DERR_INVALIDCALL
;
4991 number_of_vertices
= 2 + (slices
* (3 + stacks
));
4992 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
4994 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4995 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
5001 if (FAILED(hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, 0, (void **)&vertices
)))
5003 cylinder
->lpVtbl
->Release(cylinder
);
5007 if (FAILED(hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, 0, (void **)&faces
)))
5009 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5010 cylinder
->lpVtbl
->Release(cylinder
);
5014 /* theta = angle on xy plane wrt x axis */
5015 theta_step
= -2.0f
* D3DX_PI
/ slices
;
5016 theta_start
= D3DX_PI
/ 2.0f
;
5018 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
5020 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5021 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5022 cylinder
->lpVtbl
->Release(cylinder
);
5023 return E_OUTOFMEMORY
;
5029 delta_radius
= radius1
- radius2
;
5031 radius_step
= delta_radius
/ stacks
;
5034 z_step
= length
/ stacks
;
5035 z_normal
= delta_radius
/ length
;
5036 if (isnan(z_normal
))
5041 vertices
[vertex
].normal
.x
= 0.0f
;
5042 vertices
[vertex
].normal
.y
= 0.0f
;
5043 vertices
[vertex
].normal
.z
= -1.0f
;
5044 vertices
[vertex
].position
.x
= 0.0f
;
5045 vertices
[vertex
].position
.y
= 0.0f
;
5046 vertices
[vertex
++].position
.z
= z
;
5048 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5050 vertices
[vertex
].normal
.x
= 0.0f
;
5051 vertices
[vertex
].normal
.y
= 0.0f
;
5052 vertices
[vertex
].normal
.z
= -1.0f
;
5053 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5054 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5055 vertices
[vertex
].position
.z
= z
;
5060 faces
[face
][1] = slice
;
5061 faces
[face
++][2] = slice
+ 1;
5066 faces
[face
][1] = slice
;
5067 faces
[face
++][2] = 1;
5069 for (stack
= 1; stack
<= stacks
+1; stack
++)
5071 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5073 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
5074 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
5075 vertices
[vertex
].normal
.z
= z_normal
;
5076 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
5077 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5078 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5079 vertices
[vertex
].position
.z
= z
;
5081 if (stack
> 1 && slice
> 0)
5083 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
5084 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5085 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
5087 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
5088 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5089 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5095 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
5096 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5097 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
5099 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
5100 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5101 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
5104 if (stack
< stacks
+ 1)
5107 radius
-= radius_step
;
5111 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5113 vertices
[vertex
].normal
.x
= 0.0f
;
5114 vertices
[vertex
].normal
.y
= 0.0f
;
5115 vertices
[vertex
].normal
.z
= 1.0f
;
5116 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5117 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5118 vertices
[vertex
].position
.z
= z
;
5122 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5123 faces
[face
][1] = number_of_vertices
- 1;
5124 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5128 vertices
[vertex
].position
.x
= 0.0f
;
5129 vertices
[vertex
].position
.y
= 0.0f
;
5130 vertices
[vertex
].position
.z
= z
;
5131 vertices
[vertex
].normal
.x
= 0.0f
;
5132 vertices
[vertex
].normal
.y
= 0.0f
;
5133 vertices
[vertex
].normal
.z
= 1.0f
;
5135 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5136 faces
[face
][1] = number_of_vertices
- 1;
5137 faces
[face
][2] = vertex_index(slices
, 0, stack
);
5139 free_sincos_table(&theta
);
5140 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5141 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5145 if (FAILED(hr
= D3DXCreateBuffer(number_of_faces
* sizeof(DWORD
) * 3, adjacency
)))
5147 cylinder
->lpVtbl
->Release(cylinder
);
5151 if (FAILED(hr
= cylinder
->lpVtbl
->GenerateAdjacency(cylinder
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
5153 (*adjacency
)->lpVtbl
->Release(*adjacency
);
5154 cylinder
->lpVtbl
->Release(cylinder
);
5164 HRESULT WINAPI
D3DXCreateTeapot(struct IDirect3DDevice9
*device
,
5165 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
5167 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
5172 HRESULT WINAPI
D3DXCreateTextA(struct IDirect3DDevice9
*device
, HDC hdc
, const char *text
, float deviation
,
5173 float extrusion
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5179 TRACE("device %p, hdc %p, text %s, deviation %.8e, extrusion %.8e, mesh %p, adjacency %p, glyphmetrics %p.\n",
5180 device
, hdc
, debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
5183 return D3DERR_INVALIDCALL
;
5185 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
5186 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5187 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
5189 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
5190 mesh
, adjacency
, glyphmetrics
);
5191 HeapFree(GetProcessHeap(), 0, textW
);
5196 HRESULT WINAPI
D3DXCreateTorus(struct IDirect3DDevice9
*device
,
5197 float innerradius
, float outerradius
, UINT sides
, UINT rings
, struct ID3DXMesh
**mesh
, ID3DXBuffer
**adjacency
)
5202 struct vertex
*vertices
;
5203 float phi
, phi_step
, sin_phi
, cos_phi
;
5204 float theta
, theta_step
, sin_theta
, cos_theta
;
5205 unsigned int i
, j
, numvert
, numfaces
;
5207 TRACE("device %p, innerradius %.8e, outerradius %.8e, sides %u, rings %u, mesh %p, adjacency %p.\n",
5208 device
, innerradius
, outerradius
, sides
, rings
, mesh
, adjacency
);
5210 numvert
= sides
* rings
;
5211 numfaces
= numvert
* 2;
5213 if (!device
|| innerradius
< 0.0f
|| outerradius
< 0.0f
|| sides
< 3 || rings
< 3 || !mesh
)
5215 WARN("Invalid arguments.\n");
5216 return D3DERR_INVALIDCALL
;
5219 if (FAILED(hr
= D3DXCreateMeshFVF(numfaces
, numvert
, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &torus
)))
5222 if (FAILED(hr
= torus
->lpVtbl
->LockVertexBuffer(torus
, 0, (void **)&vertices
)))
5224 torus
->lpVtbl
->Release(torus
);
5228 if (FAILED(hr
= torus
->lpVtbl
->LockIndexBuffer(torus
, 0, (void **)&faces
)))
5230 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5231 torus
->lpVtbl
->Release(torus
);
5235 phi_step
= D3DX_PI
/ sides
* 2.0f
;
5236 theta_step
= D3DX_PI
/ rings
* -2.0f
;
5240 for (i
= 0; i
< rings
; ++i
)
5244 sin_theta
= sinf(theta
);
5245 cos_theta
= cosf(theta
);
5247 for (j
= 0; j
< sides
; ++j
)
5249 sin_phi
= sinf(phi
);
5250 cos_phi
= cosf(phi
);
5252 vertices
[i
* sides
+ j
].position
.x
= (innerradius
* cos_phi
+ outerradius
) * cos_theta
;
5253 vertices
[i
* sides
+ j
].position
.y
= (innerradius
* cos_phi
+ outerradius
) * sin_theta
;
5254 vertices
[i
* sides
+ j
].position
.z
= innerradius
* sin_phi
;
5255 vertices
[i
* sides
+ j
].normal
.x
= cos_phi
* cos_theta
;
5256 vertices
[i
* sides
+ j
].normal
.y
= cos_phi
* sin_theta
;
5257 vertices
[i
* sides
+ j
].normal
.z
= sin_phi
;
5262 theta
+= theta_step
;
5265 for (i
= 0; i
< numfaces
- sides
* 2; ++i
)
5267 faces
[i
][0] = i
% 2 ? i
/ 2 + sides
: i
/ 2;
5268 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5269 faces
[i
][2] = (i
+ 1) % (sides
* 2) ? (i
+ 1) / 2 + sides
: (i
+ 1) / 2;
5272 for (j
= 0; i
< numfaces
; ++i
, ++j
)
5274 faces
[i
][0] = i
% 2 ? j
/ 2 : i
/ 2;
5275 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5276 faces
[i
][2] = i
== numfaces
- 1 ? 0 : (j
+ 1) / 2;
5279 torus
->lpVtbl
->UnlockIndexBuffer(torus
);
5280 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5284 if (FAILED(hr
= D3DXCreateBuffer(numfaces
* sizeof(DWORD
) * 3, adjacency
)))
5286 torus
->lpVtbl
->Release(torus
);
5290 if (FAILED(hr
= torus
->lpVtbl
->GenerateAdjacency(torus
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
5292 (*adjacency
)->lpVtbl
->Release(*adjacency
);
5293 torus
->lpVtbl
->Release(torus
);
5304 POINTTYPE_CURVE
= 0,
5306 POINTTYPE_CURVE_START
,
5307 POINTTYPE_CURVE_END
,
5308 POINTTYPE_CURVE_MIDDLE
,
5314 enum pointtype corner
;
5317 struct dynamic_array
5319 int count
, capacity
;
5323 /* is a dynamic_array */
5326 int count
, capacity
;
5327 struct point2d
*items
;
5330 /* is a dynamic_array */
5331 struct outline_array
5333 int count
, capacity
;
5334 struct outline
*items
;
5343 struct point2d_index
5345 struct outline
*outline
;
5349 struct point2d_index_array
5352 struct point2d_index
*items
;
5357 struct outline_array outlines
;
5358 struct face_array faces
;
5359 struct point2d_index_array ordered_vertices
;
5363 /* is an dynamic_array */
5366 int count
, capacity
;
5370 /* complex polygons are split into monotone polygons, which have
5371 * at most 2 intersections with the vertical sweep line */
5372 struct triangulation
5374 struct word_array vertex_stack
;
5375 BOOL last_on_top
, merging
;
5378 /* is an dynamic_array */
5379 struct triangulation_array
5381 int count
, capacity
;
5382 struct triangulation
*items
;
5384 struct glyphinfo
*glyph
;
5387 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
5389 if (count
> array
->capacity
) {
5392 if (array
->items
&& array
->capacity
) {
5393 new_capacity
= max(array
->capacity
* 2, count
);
5394 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
5396 new_capacity
= max(16, count
);
5397 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
5401 array
->items
= new_buffer
;
5402 array
->capacity
= new_capacity
;
5407 static struct point2d
*add_points(struct outline
*array
, int num
)
5409 struct point2d
*item
;
5411 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
5414 item
= &array
->items
[array
->count
];
5415 array
->count
+= num
;
5419 static struct outline
*add_outline(struct outline_array
*array
)
5421 struct outline
*item
;
5423 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5426 item
= &array
->items
[array
->count
++];
5427 ZeroMemory(item
, sizeof(*item
));
5431 static inline face
*add_face(struct face_array
*array
)
5433 return &array
->items
[array
->count
++];
5436 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
5438 struct triangulation
*item
;
5440 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5443 item
= &array
->items
[array
->count
++];
5444 ZeroMemory(item
, sizeof(*item
));
5448 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
5450 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5451 return E_OUTOFMEMORY
;
5453 array
->items
[array
->count
++] = vertex_index
;
5457 /* assume fixed point numbers can be converted to float point in place */
5458 C_ASSERT(sizeof(FIXED
) == sizeof(float));
5459 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
5461 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, unsigned int emsquare
)
5463 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
5465 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
5466 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
5467 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
5473 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
5474 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
5475 float max_deviation_sq
)
5477 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
5480 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
5481 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
5482 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
5484 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
5485 if (deviation_sq
< max_deviation_sq
) {
5486 struct point2d
*pt
= add_points(outline
, 1);
5487 if (!pt
) return E_OUTOFMEMORY
;
5489 pt
->corner
= POINTTYPE_CURVE
;
5490 /* the end point is omitted because the end line merges into the next segment of
5491 * the split bezier curve, and the end of the split bezier curve is added outside
5492 * this recursive function. */
5494 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
5495 if (hr
!= S_OK
) return hr
;
5496 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
5497 if (hr
!= S_OK
) return hr
;
5503 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
5505 /* dot product = cos(theta) */
5506 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
5509 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
5511 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
5521 static BOOL
attempt_line_merge(struct outline
*outline
,
5523 const D3DXVECTOR2
*nextpt
,
5525 const struct cos_table
*table
)
5527 D3DXVECTOR2 curdir
, lastdir
;
5528 struct point2d
*prevpt
, *pt
;
5531 pt
= &outline
->items
[pt_index
];
5532 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5533 prevpt
= &outline
->items
[pt_index
];
5536 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
5538 if (outline
->count
< 2)
5541 /* remove last point if the next line continues the last line */
5542 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5543 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5544 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
5547 if (pt
->corner
== POINTTYPE_CURVE_END
)
5548 prevpt
->corner
= pt
->corner
;
5549 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
5550 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5554 if (outline
->count
< 2)
5557 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5558 prevpt
= &outline
->items
[pt_index
];
5559 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5560 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5565 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
5566 float max_deviation_sq
, unsigned int emsquare
,
5567 const struct cos_table
*cos_table
)
5569 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
5571 while ((char *)header
< (char *)raw_outline
+ datasize
)
5573 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
5574 struct point2d
*lastpt
, *pt
;
5575 D3DXVECTOR2 lastdir
;
5576 D3DXVECTOR2
*pt_flt
;
5578 struct outline
*outline
= add_outline(&glyph
->outlines
);
5581 return E_OUTOFMEMORY
;
5583 pt
= add_points(outline
, 1);
5585 return E_OUTOFMEMORY
;
5586 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
5588 pt
->corner
= POINTTYPE_CORNER
;
5590 if (header
->dwType
!= TT_POLYGON_TYPE
)
5591 FIXME("Unknown header type %d\n", header
->dwType
);
5593 while ((char *)curve
< (char *)header
+ header
->cb
)
5595 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
5596 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
5597 unsigned int j2
= 0;
5600 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5604 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
5606 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
5611 int count
= curve
->cpfx
;
5615 D3DXVECTOR2 bezier_end
;
5617 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j2
], &pt_flt
[j2
+1]), 0.5f
);
5618 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &bezier_end
, max_deviation_sq
);
5621 bezier_start
= bezier_end
;
5625 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &pt_flt
[j2
+1], max_deviation_sq
);
5629 pt
= add_points(outline
, 1);
5631 return E_OUTOFMEMORY
;
5633 pt
->pos
= pt_flt
[j2
];
5634 pt
->corner
= POINTTYPE_CURVE_END
;
5636 pt
= add_points(outline
, curve
->cpfx
);
5638 return E_OUTOFMEMORY
;
5639 for (j2
= 0; j2
< curve
->cpfx
; j2
++)
5641 pt
->pos
= pt_flt
[j2
];
5642 pt
->corner
= POINTTYPE_CORNER
;
5647 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5650 /* remove last point if the next line continues the last line */
5651 if (outline
->count
>= 3) {
5654 lastpt
= &outline
->items
[outline
->count
- 1];
5655 pt
= &outline
->items
[0];
5656 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
5657 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
5659 if (pt
->corner
== POINTTYPE_CURVE_START
)
5660 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5662 pt
->corner
= POINTTYPE_CURVE_END
;
5666 /* outline closed with a line from end to start point */
5667 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
5669 lastpt
= &outline
->items
[0];
5670 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
5671 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
5672 lastpt
->corner
= POINTTYPE_CORNER
;
5673 pt
= &outline
->items
[1];
5674 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
5675 *lastpt
= outline
->items
[outline
->count
];
5678 lastpt
= &outline
->items
[outline
->count
- 1];
5679 pt
= &outline
->items
[0];
5680 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
5681 for (j
= 0; j
< outline
->count
; j
++)
5686 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
5687 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
5689 switch (lastpt
->corner
)
5691 case POINTTYPE_CURVE_START
:
5692 case POINTTYPE_CURVE_END
:
5693 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
5694 lastpt
->corner
= POINTTYPE_CORNER
;
5696 case POINTTYPE_CURVE_MIDDLE
:
5697 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
5698 lastpt
->corner
= POINTTYPE_CORNER
;
5700 lastpt
->corner
= POINTTYPE_CURVE
;
5708 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
5713 /* Get the y-distance from a line to a point */
5714 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
5715 D3DXVECTOR2
*line_pt2
,
5718 D3DXVECTOR2 line_vec
= {0, 0};
5722 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
5723 line_pt_dx
= point
->x
- line_pt1
->x
;
5724 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
5725 return point
->y
- line_y
;
5728 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
5730 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
5733 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
5735 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
5738 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
5740 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
5741 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
5745 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
5746 struct triangulation_array
*triangulations
,
5750 struct glyphinfo
*glyph
= triangulations
->glyph
;
5751 struct triangulation
*t
= *t_ptr
;
5756 if (t
->last_on_top
) {
5764 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
5765 /* consume all vertices on the stack */
5766 WORD last_pt
= t
->vertex_stack
.items
[0];
5768 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
5770 face
= add_face(&glyph
->faces
);
5771 if (!face
) return E_OUTOFMEMORY
;
5772 (*face
)[0] = vtx_idx
;
5773 (*face
)[f1
] = last_pt
;
5774 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
5776 t
->vertex_stack
.items
[0] = last_pt
;
5777 t
->vertex_stack
.count
= 1;
5778 } else if (t
->vertex_stack
.count
> 1) {
5779 int i
= t
->vertex_stack
.count
- 1;
5780 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
5781 WORD top_idx
= t
->vertex_stack
.items
[i
--];
5782 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
5786 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
5787 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
5789 if (prev_pt
->x
!= top_pt
->x
&&
5790 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
5791 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
5794 face
= add_face(&glyph
->faces
);
5795 if (!face
) return E_OUTOFMEMORY
;
5796 (*face
)[0] = vtx_idx
;
5797 (*face
)[f1
] = prev_idx
;
5798 (*face
)[f2
] = top_idx
;
5802 t
->vertex_stack
.count
--;
5805 t
->last_on_top
= to_top
;
5807 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
5809 if (hr
== S_OK
&& t
->merging
) {
5810 struct triangulation
*t2
;
5812 t2
= to_top
? t
- 1 : t
+ 1;
5813 t2
->merging
= FALSE
;
5814 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
5815 if (hr
!= S_OK
) return hr
;
5816 remove_triangulation(triangulations
, t
);
5824 /* check if the point is next on the outline for either the top or bottom */
5825 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
5827 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
5828 WORD idx
= t
->vertex_stack
.items
[i
];
5829 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
5830 struct outline
*outline
= pt_idx
->outline
;
5833 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
5835 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
5837 return &outline
->items
[i
].pos
;
5840 static int compare_vertex_indices(const void *a
, const void *b
)
5842 const struct point2d_index
*idx1
= a
, *idx2
= b
;
5843 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
5844 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
5845 float diff
= p1
->x
- p2
->x
;
5848 diff
= p1
->y
- p2
->y
;
5850 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
5853 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
5857 struct glyphinfo
*glyph
= triangulations
->glyph
;
5858 int nb_vertices
= 0;
5860 struct point2d_index
*idx_ptr
;
5862 /* Glyphs without outlines do not generate any vertices. */
5863 if (!glyph
->outlines
.count
)
5866 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5867 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
5869 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
5870 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
5871 if (!glyph
->ordered_vertices
.items
)
5872 return E_OUTOFMEMORY
;
5874 idx_ptr
= glyph
->ordered_vertices
.items
;
5875 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5877 struct outline
*outline
= &glyph
->outlines
.items
[i
];
5880 idx_ptr
->outline
= outline
;
5881 idx_ptr
->vertex
= 0;
5883 for (j
= outline
->count
- 1; j
> 0; j
--)
5885 idx_ptr
->outline
= outline
;
5886 idx_ptr
->vertex
= j
;
5890 glyph
->ordered_vertices
.count
= nb_vertices
;
5892 /* Native implementation seems to try to create a triangle fan from
5893 * the first outline point if the glyph only has one outline. */
5894 if (glyph
->outlines
.count
== 1)
5896 struct outline
*outline
= glyph
->outlines
.items
;
5897 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
5898 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
5901 for (i
= 2; i
< outline
->count
; i
++)
5903 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
5904 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
5905 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
5907 D3DXVec2Subtract(&v1
, base
, last
);
5908 D3DXVec2Subtract(&v2
, last
, next
);
5909 ccw
= D3DXVec2CCW(&v1
, &v2
);
5917 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5918 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
5919 if (!glyph
->faces
.items
)
5920 return E_OUTOFMEMORY
;
5922 glyph
->faces
.count
= outline
->count
- 2;
5923 for (i
= 0; i
< glyph
->faces
.count
; i
++)
5925 glyph
->faces
.items
[i
][0] = 0;
5926 glyph
->faces
.items
[i
][1] = i
+ 1;
5927 glyph
->faces
.items
[i
][2] = i
+ 2;
5933 /* Perform 2D polygon triangulation for complex glyphs.
5934 * Triangulation is performed using a sweep line concept, from right to left,
5935 * by processing vertices in sorted order. Complex polygons are split into
5936 * monotone polygons which are triangulated separately. */
5937 /* FIXME: The order of the faces is not consistent with the native implementation. */
5939 /* Reserve space for maximum possible faces from triangulation.
5940 * # faces for outer outlines = outline->count - 2
5941 * # faces for inner outlines = outline->count + 2
5942 * There must be at least 1 outer outline. */
5943 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5944 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
5945 if (!glyph
->faces
.items
)
5946 return E_OUTOFMEMORY
;
5948 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
5949 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
5950 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
5953 int end
= triangulations
->count
;
5957 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
5958 int current
= (start
+ end
) / 2;
5959 struct triangulation
*t
= &triangulations
->items
[current
];
5960 BOOL on_top_outline
= FALSE
;
5961 D3DXVECTOR2
*top_next
, *bottom_next
;
5962 WORD top_idx
, bottom_idx
;
5964 if (t
->merging
&& t
->last_on_top
)
5965 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
5967 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
5968 if (sweep_vtx
== top_next
)
5970 if (t
->merging
&& t
->last_on_top
)
5972 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
5973 if (hr
!= S_OK
) return hr
;
5975 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
5976 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
5978 /* point also on bottom outline of higher triangulation */
5979 struct triangulation
*t2
= t
+ 1;
5980 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
5981 if (hr
!= S_OK
) return hr
;
5986 on_top_outline
= TRUE
;
5989 if (t
->merging
&& !t
->last_on_top
)
5990 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
5992 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
5993 if (sweep_vtx
== bottom_next
)
5995 if (t
->merging
&& !t
->last_on_top
)
5997 if (on_top_outline
) {
5998 /* outline finished */
5999 remove_triangulation(triangulations
, t
);
6003 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
6004 if (hr
!= S_OK
) return hr
;
6006 if (t
> triangulations
->items
&&
6007 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
6009 struct triangulation
*t2
= t
- 1;
6010 /* point also on top outline of lower triangulation */
6011 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
6012 if (hr
!= S_OK
) return hr
;
6013 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
6023 if (t
->last_on_top
) {
6024 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
6025 bottom_idx
= t
->vertex_stack
.items
[0];
6027 top_idx
= t
->vertex_stack
.items
[0];
6028 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
6031 /* check if the point is inside or outside this polygon */
6032 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
6033 top_next
, sweep_vtx
) > 0)
6035 start
= current
+ 1;
6036 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
6037 bottom_next
, sweep_vtx
) < 0)
6040 } else if (t
->merging
) {
6041 /* inside, so cancel merging */
6042 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
6044 t2
->merging
= FALSE
;
6045 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
6046 if (hr
!= S_OK
) return hr
;
6047 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
6048 if (hr
!= S_OK
) return hr
;
6051 /* inside, so split polygon into two monotone parts */
6052 struct triangulation
*t2
= add_triangulation(triangulations
);
6053 if (!t2
) return E_OUTOFMEMORY
;
6054 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
6055 if (t
->last_on_top
) {
6062 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
6063 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
6064 if (hr
!= S_OK
) return hr
;
6065 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
6066 if (hr
!= S_OK
) return hr
;
6067 t2
->last_on_top
= !t
->last_on_top
;
6069 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
6070 if (hr
!= S_OK
) return hr
;
6076 struct triangulation
*t
;
6077 struct triangulation
*t2
= add_triangulation(triangulations
);
6078 if (!t2
) return E_OUTOFMEMORY
;
6079 t
= &triangulations
->items
[start
];
6080 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
6081 ZeroMemory(t
, sizeof(*t
));
6082 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
6083 if (hr
!= S_OK
) return hr
;
6089 HRESULT WINAPI
D3DXCreateTextW(struct IDirect3DDevice9
*device
, HDC hdc
, const WCHAR
*text
, float deviation
,
6090 float extrusion
, struct ID3DXMesh
**mesh_ptr
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
6093 ID3DXMesh
*mesh
= NULL
;
6094 DWORD nb_vertices
, nb_faces
;
6095 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
6096 struct vertex
*vertices
= NULL
;
6101 OUTLINETEXTMETRICW otm
;
6102 HFONT font
= NULL
, oldfont
= NULL
;
6103 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
6104 void *raw_outline
= NULL
;
6106 struct glyphinfo
*glyphs
= NULL
;
6108 struct triangulation_array triangulations
= {0, 0, NULL
};
6110 struct vertex
*vertex_ptr
;
6112 float max_deviation_sq
;
6113 const struct cos_table cos_table
= {
6114 cosf(D3DXToRadian(0.5f
)),
6115 cosf(D3DXToRadian(45.0f
)),
6116 cosf(D3DXToRadian(90.0f
)),
6120 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
6121 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
6123 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
6124 return D3DERR_INVALIDCALL
;
6128 FIXME("Case of adjacency != NULL not implemented.\n");
6132 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
6133 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
6135 return D3DERR_INVALIDCALL
;
6138 if (deviation
== 0.0f
)
6139 deviation
= 1.0f
/ otm
.otmEMSquare
;
6140 max_deviation_sq
= deviation
* deviation
;
6142 lf
.lfHeight
= otm
.otmEMSquare
;
6144 font
= CreateFontIndirectW(&lf
);
6149 oldfont
= SelectObject(hdc
, font
);
6151 textlen
= strlenW(text
);
6152 for (i
= 0; i
< textlen
; i
++)
6154 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
6156 return D3DERR_INVALIDCALL
;
6157 if (bufsize
< datasize
)
6160 if (!bufsize
) { /* e.g. text == " " */
6161 hr
= D3DERR_INVALIDCALL
;
6165 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
6166 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
6167 if (!glyphs
|| !raw_outline
) {
6173 for (i
= 0; i
< textlen
; i
++)
6175 /* get outline points from data returned from GetGlyphOutline */
6178 glyphs
[i
].offset_x
= offset_x
;
6180 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
6181 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
6182 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
6183 if (hr
!= S_OK
) goto error
;
6185 triangulations
.glyph
= &glyphs
[i
];
6186 hr
= triangulate(&triangulations
);
6187 if (hr
!= S_OK
) goto error
;
6188 if (triangulations
.count
) {
6189 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
6190 triangulations
.count
= 0;
6195 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
6196 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
6197 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
6198 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
6199 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6200 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
6202 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6205 /* corner points need an extra vertex for the different side faces normals */
6207 nb_outline_points
= 0;
6209 for (i
= 0; i
< textlen
; i
++)
6212 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
6213 nb_front_faces
+= glyphs
[i
].faces
.count
;
6214 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6217 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6218 nb_corners
++; /* first outline point always repeated as a corner */
6219 for (k
= 1; k
< outline
->count
; k
++)
6220 if (outline
->items
[k
].corner
)
6225 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
6226 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
6229 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
6230 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
6234 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
6237 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, (void **)&faces
)))
6240 /* convert 2D vertices and faces into 3D mesh */
6241 vertex_ptr
= vertices
;
6243 if (extrusion
== 0.0f
) {
6250 for (i
= 0; i
< textlen
; i
++)
6254 struct vertex
*back_vertices
;
6257 /* side vertices and faces */
6258 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6260 struct vertex
*outline_vertices
= vertex_ptr
;
6261 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6263 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
6264 struct point2d
*pt
= &outline
->items
[0];
6266 for (k
= 1; k
<= outline
->count
; k
++)
6269 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
6270 WORD vtx_idx
= vertex_ptr
- vertices
;
6273 if (pt
->corner
== POINTTYPE_CURVE_START
)
6274 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
6275 else if (pt
->corner
)
6276 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6278 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
6279 D3DXVec2Normalize(&vec
, &vec
);
6280 vtx
.normal
.x
= -vec
.y
;
6281 vtx
.normal
.y
= vec
.x
;
6284 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
6285 vtx
.position
.y
= pt
->pos
.y
;
6287 *vertex_ptr
++ = vtx
;
6289 vtx
.position
.z
= -extrusion
;
6290 *vertex_ptr
++ = vtx
;
6292 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
6293 vtx
.position
.y
= nextpt
->pos
.y
;
6294 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
6295 vtx
.position
.z
= -extrusion
;
6296 *vertex_ptr
++ = vtx
;
6298 *vertex_ptr
++ = vtx
;
6300 (*face_ptr
)[0] = vtx_idx
;
6301 (*face_ptr
)[1] = vtx_idx
+ 2;
6302 (*face_ptr
)[2] = vtx_idx
+ 1;
6305 (*face_ptr
)[0] = vtx_idx
;
6306 (*face_ptr
)[1] = vtx_idx
+ 3;
6307 (*face_ptr
)[2] = vtx_idx
+ 2;
6310 if (nextpt
->corner
) {
6311 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
6312 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
6313 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
6315 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6317 D3DXVec2Normalize(&vec
, &vec
);
6318 vtx
.normal
.x
= -vec
.y
;
6319 vtx
.normal
.y
= vec
.x
;
6322 *vertex_ptr
++ = vtx
;
6323 vtx
.position
.z
= -extrusion
;
6324 *vertex_ptr
++ = vtx
;
6327 (*face_ptr
)[0] = vtx_idx
;
6328 (*face_ptr
)[1] = vtx_idx
+ 3;
6329 (*face_ptr
)[2] = vtx_idx
+ 1;
6332 (*face_ptr
)[0] = vtx_idx
;
6333 (*face_ptr
)[1] = vtx_idx
+ 2;
6334 (*face_ptr
)[2] = vtx_idx
+ 3;
6342 *vertex_ptr
++ = *outline_vertices
++;
6343 *vertex_ptr
++ = *outline_vertices
++;
6347 /* back vertices and faces */
6348 back_faces
= face_ptr
;
6349 back_vertices
= vertex_ptr
;
6350 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
6352 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
6353 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
6354 vertex_ptr
->position
.y
= pt
->y
;
6355 vertex_ptr
->position
.z
= 0;
6356 vertex_ptr
->normal
.x
= 0;
6357 vertex_ptr
->normal
.y
= 0;
6358 vertex_ptr
->normal
.z
= 1;
6361 count
= back_vertices
- vertices
;
6362 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
6364 face
*f
= &glyphs
[i
].faces
.items
[j
];
6365 (*face_ptr
)[0] = (*f
)[0] + count
;
6366 (*face_ptr
)[1] = (*f
)[1] + count
;
6367 (*face_ptr
)[2] = (*f
)[2] + count
;
6371 /* front vertices and faces */
6372 j
= count
= vertex_ptr
- back_vertices
;
6375 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
6376 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
6377 vertex_ptr
->position
.z
= -extrusion
;
6378 vertex_ptr
->normal
.x
= 0;
6379 vertex_ptr
->normal
.y
= 0;
6380 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
6384 j
= face_ptr
- back_faces
;
6387 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
6388 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
6389 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
6399 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6400 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6401 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
6404 for (i
= 0; i
< textlen
; i
++)
6407 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6408 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
6409 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
6410 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
6411 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
6413 HeapFree(GetProcessHeap(), 0, glyphs
);
6415 if (triangulations
.items
) {
6417 for (i
= 0; i
< triangulations
.count
; i
++)
6418 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
6419 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
6421 HeapFree(GetProcessHeap(), 0, raw_outline
);
6422 if (oldfont
) SelectObject(hdc
, oldfont
);
6423 if (font
) DeleteObject(font
);
6428 HRESULT WINAPI
D3DXValidMesh(ID3DXMesh
*mesh
, const DWORD
*adjacency
, ID3DXBuffer
**errors_and_warnings
)
6430 FIXME("(%p, %p, %p): stub\n", mesh
, adjacency
, *errors_and_warnings
);
6435 static BOOL
weld_float1(void *to
, void *from
, FLOAT epsilon
)
6440 if (fabsf(*v1
- *v2
) <= epsilon
)
6450 static BOOL
weld_float2(void *to
, void *from
, FLOAT epsilon
)
6452 D3DXVECTOR2
*v1
= to
;
6453 D3DXVECTOR2
*v2
= from
;
6454 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6455 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6456 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6458 if (max_abs_diff
<= epsilon
)
6460 memcpy(to
, from
, sizeof(D3DXVECTOR2
));
6468 static BOOL
weld_float3(void *to
, void *from
, FLOAT epsilon
)
6470 D3DXVECTOR3
*v1
= to
;
6471 D3DXVECTOR3
*v2
= from
;
6472 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6473 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6474 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6475 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6476 max_abs_diff
= max(diff_z
, max_abs_diff
);
6478 if (max_abs_diff
<= epsilon
)
6480 memcpy(to
, from
, sizeof(D3DXVECTOR3
));
6488 static BOOL
weld_float4(void *to
, void *from
, FLOAT epsilon
)
6490 D3DXVECTOR4
*v1
= to
;
6491 D3DXVECTOR4
*v2
= from
;
6492 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6493 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6494 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6495 FLOAT diff_w
= fabsf(v1
->w
- v2
->w
);
6496 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6497 max_abs_diff
= max(diff_z
, max_abs_diff
);
6498 max_abs_diff
= max(diff_w
, max_abs_diff
);
6500 if (max_abs_diff
<= epsilon
)
6502 memcpy(to
, from
, sizeof(D3DXVECTOR4
));
6510 static BOOL
weld_ubyte4(void *to
, void *from
, FLOAT epsilon
)
6514 BYTE truncated_epsilon
= (BYTE
)epsilon
;
6515 BYTE diff_x
= b1
[0] > b2
[0] ? b1
[0] - b2
[0] : b2
[0] - b1
[0];
6516 BYTE diff_y
= b1
[1] > b2
[1] ? b1
[1] - b2
[1] : b2
[1] - b1
[1];
6517 BYTE diff_z
= b1
[2] > b2
[2] ? b1
[2] - b2
[2] : b2
[2] - b1
[2];
6518 BYTE diff_w
= b1
[3] > b2
[3] ? b1
[3] - b2
[3] : b2
[3] - b1
[3];
6519 BYTE max_diff
= max(diff_x
, diff_y
);
6520 max_diff
= max(diff_z
, max_diff
);
6521 max_diff
= max(diff_w
, max_diff
);
6523 if (max_diff
<= truncated_epsilon
)
6525 memcpy(to
, from
, 4 * sizeof(BYTE
));
6533 static BOOL
weld_ubyte4n(void *to
, void *from
, FLOAT epsilon
)
6535 return weld_ubyte4(to
, from
, epsilon
* UCHAR_MAX
);
6538 static BOOL
weld_d3dcolor(void *to
, void *from
, FLOAT epsilon
)
6540 return weld_ubyte4n(to
, from
, epsilon
);
6543 static BOOL
weld_short2(void *to
, void *from
, FLOAT epsilon
)
6547 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6548 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6549 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6550 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6552 if (max_abs_diff
<= truncated_epsilon
)
6554 memcpy(to
, from
, 2 * sizeof(SHORT
));
6562 static BOOL
weld_short2n(void *to
, void *from
, FLOAT epsilon
)
6564 return weld_short2(to
, from
, epsilon
* SHRT_MAX
);
6567 static BOOL
weld_short4(void *to
, void *from
, FLOAT epsilon
)
6571 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6572 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6573 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6574 SHORT diff_z
= abs(s1
[2] - s2
[2]);
6575 SHORT diff_w
= abs(s1
[3] - s2
[3]);
6576 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6577 max_abs_diff
= max(diff_z
, max_abs_diff
);
6578 max_abs_diff
= max(diff_w
, max_abs_diff
);
6580 if (max_abs_diff
<= truncated_epsilon
)
6582 memcpy(to
, from
, 4 * sizeof(SHORT
));
6590 static BOOL
weld_short4n(void *to
, void *from
, FLOAT epsilon
)
6592 return weld_short4(to
, from
, epsilon
* SHRT_MAX
);
6595 static BOOL
weld_ushort2n(void *to
, void *from
, FLOAT epsilon
)
6599 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6600 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6601 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6602 USHORT max_diff
= max(diff_x
, diff_y
);
6604 if (max_diff
<= scaled_epsilon
)
6606 memcpy(to
, from
, 2 * sizeof(USHORT
));
6614 static BOOL
weld_ushort4n(void *to
, void *from
, FLOAT epsilon
)
6618 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6619 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6620 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6621 USHORT diff_z
= s1
[2] > s2
[2] ? s1
[2] - s2
[2] : s2
[2] - s1
[2];
6622 USHORT diff_w
= s1
[3] > s2
[3] ? s1
[3] - s2
[3] : s2
[3] - s1
[3];
6623 USHORT max_diff
= max(diff_x
, diff_y
);
6624 max_diff
= max(diff_z
, max_diff
);
6625 max_diff
= max(diff_w
, max_diff
);
6627 if (max_diff
<= scaled_epsilon
)
6629 memcpy(to
, from
, 4 * sizeof(USHORT
));
6645 static struct udec3
dword_to_udec3(DWORD d
)
6650 v
.y
= (d
& 0xffc00) >> 10;
6651 v
.z
= (d
& 0x3ff00000) >> 20;
6652 v
.w
= (d
& 0xc0000000) >> 30;
6657 static BOOL
weld_udec3(void *to
, void *from
, FLOAT epsilon
)
6661 struct udec3 v1
= dword_to_udec3(*d1
);
6662 struct udec3 v2
= dword_to_udec3(*d2
);
6663 UINT truncated_epsilon
= (UINT
)epsilon
;
6664 UINT diff_x
= v1
.x
> v2
.x
? v1
.x
- v2
.x
: v2
.x
- v1
.x
;
6665 UINT diff_y
= v1
.y
> v2
.y
? v1
.y
- v2
.y
: v2
.y
- v1
.y
;
6666 UINT diff_z
= v1
.z
> v2
.z
? v1
.z
- v2
.z
: v2
.z
- v1
.z
;
6667 UINT diff_w
= v1
.w
> v2
.w
? v1
.w
- v2
.w
: v2
.w
- v1
.w
;
6668 UINT max_diff
= max(diff_x
, diff_y
);
6669 max_diff
= max(diff_z
, max_diff
);
6670 max_diff
= max(diff_w
, max_diff
);
6672 if (max_diff
<= truncated_epsilon
)
6674 memcpy(to
, from
, sizeof(DWORD
));
6690 static struct dec3n
dword_to_dec3n(DWORD d
)
6695 v
.y
= (d
& 0xffc00) >> 10;
6696 v
.z
= (d
& 0x3ff00000) >> 20;
6697 v
.w
= (d
& 0xc0000000) >> 30;
6702 static BOOL
weld_dec3n(void *to
, void *from
, FLOAT epsilon
)
6704 const UINT MAX_DEC3N
= 511;
6707 struct dec3n v1
= dword_to_dec3n(*d1
);
6708 struct dec3n v2
= dword_to_dec3n(*d2
);
6709 INT scaled_epsilon
= (INT
)(epsilon
* MAX_DEC3N
);
6710 INT diff_x
= abs(v1
.x
- v2
.x
);
6711 INT diff_y
= abs(v1
.y
- v2
.y
);
6712 INT diff_z
= abs(v1
.z
- v2
.z
);
6713 INT diff_w
= abs(v1
.w
- v2
.w
);
6714 INT max_abs_diff
= max(diff_x
, diff_y
);
6715 max_abs_diff
= max(diff_z
, max_abs_diff
);
6716 max_abs_diff
= max(diff_w
, max_abs_diff
);
6718 if (max_abs_diff
<= scaled_epsilon
)
6720 memcpy(to
, from
, sizeof(DWORD
));
6728 static BOOL
weld_float16_2(void *to
, void *from
, FLOAT epsilon
)
6730 D3DXFLOAT16
*v1_float16
= to
;
6731 D3DXFLOAT16
*v2_float16
= from
;
6739 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6740 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6742 diff_x
= fabsf(v1
[0] - v2
[0]);
6743 diff_y
= fabsf(v1
[1] - v2
[1]);
6744 max_abs_diff
= max(diff_x
, diff_y
);
6746 if (max_abs_diff
<= epsilon
)
6748 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6757 static BOOL
weld_float16_4(void *to
, void *from
, FLOAT epsilon
)
6759 D3DXFLOAT16
*v1_float16
= to
;
6760 D3DXFLOAT16
*v2_float16
= from
;
6770 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6771 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6773 diff_x
= fabsf(v1
[0] - v2
[0]);
6774 diff_y
= fabsf(v1
[1] - v2
[1]);
6775 diff_z
= fabsf(v1
[2] - v2
[2]);
6776 diff_w
= fabsf(v1
[3] - v2
[3]);
6777 max_abs_diff
= max(diff_x
, diff_y
);
6778 max_abs_diff
= max(diff_z
, max_abs_diff
);
6779 max_abs_diff
= max(diff_w
, max_abs_diff
);
6781 if (max_abs_diff
<= epsilon
)
6783 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6792 /* Sets the vertex components to the same value if they are within epsilon. */
6793 static BOOL
weld_component(void *to
, void *from
, D3DDECLTYPE type
, FLOAT epsilon
)
6795 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6796 BOOL fixme_once_unused
= FALSE
;
6797 BOOL fixme_once_unknown
= FALSE
;
6801 case D3DDECLTYPE_FLOAT1
:
6802 return weld_float1(to
, from
, epsilon
);
6804 case D3DDECLTYPE_FLOAT2
:
6805 return weld_float2(to
, from
, epsilon
);
6807 case D3DDECLTYPE_FLOAT3
:
6808 return weld_float3(to
, from
, epsilon
);
6810 case D3DDECLTYPE_FLOAT4
:
6811 return weld_float4(to
, from
, epsilon
);
6813 case D3DDECLTYPE_D3DCOLOR
:
6814 return weld_d3dcolor(to
, from
, epsilon
);
6816 case D3DDECLTYPE_UBYTE4
:
6817 return weld_ubyte4(to
, from
, epsilon
);
6819 case D3DDECLTYPE_SHORT2
:
6820 return weld_short2(to
, from
, epsilon
);
6822 case D3DDECLTYPE_SHORT4
:
6823 return weld_short4(to
, from
, epsilon
);
6825 case D3DDECLTYPE_UBYTE4N
:
6826 return weld_ubyte4n(to
, from
, epsilon
);
6828 case D3DDECLTYPE_SHORT2N
:
6829 return weld_short2n(to
, from
, epsilon
);
6831 case D3DDECLTYPE_SHORT4N
:
6832 return weld_short4n(to
, from
, epsilon
);
6834 case D3DDECLTYPE_USHORT2N
:
6835 return weld_ushort2n(to
, from
, epsilon
);
6837 case D3DDECLTYPE_USHORT4N
:
6838 return weld_ushort4n(to
, from
, epsilon
);
6840 case D3DDECLTYPE_UDEC3
:
6841 return weld_udec3(to
, from
, epsilon
);
6843 case D3DDECLTYPE_DEC3N
:
6844 return weld_dec3n(to
, from
, epsilon
);
6846 case D3DDECLTYPE_FLOAT16_2
:
6847 return weld_float16_2(to
, from
, epsilon
);
6849 case D3DDECLTYPE_FLOAT16_4
:
6850 return weld_float16_4(to
, from
, epsilon
);
6852 case D3DDECLTYPE_UNUSED
:
6853 if (!fixme_once_unused
++)
6854 FIXME("D3DDECLTYPE_UNUSED welding not implemented.\n");
6858 if (!fixme_once_unknown
++)
6859 FIXME("Welding of unknown declaration type %d is not implemented.\n", type
);
6866 static FLOAT
get_component_epsilon(const D3DVERTEXELEMENT9
*decl_ptr
, const D3DXWELDEPSILONS
*epsilons
)
6868 FLOAT epsilon
= 0.0f
;
6869 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6870 static BOOL fixme_once_blendindices
= FALSE
;
6871 static BOOL fixme_once_positiont
= FALSE
;
6872 static BOOL fixme_once_fog
= FALSE
;
6873 static BOOL fixme_once_depth
= FALSE
;
6874 static BOOL fixme_once_sample
= FALSE
;
6875 static BOOL fixme_once_unknown
= FALSE
;
6877 switch (decl_ptr
->Usage
)
6879 case D3DDECLUSAGE_POSITION
:
6880 epsilon
= epsilons
->Position
;
6882 case D3DDECLUSAGE_BLENDWEIGHT
:
6883 epsilon
= epsilons
->BlendWeights
;
6885 case D3DDECLUSAGE_NORMAL
:
6886 epsilon
= epsilons
->Normals
;
6888 case D3DDECLUSAGE_PSIZE
:
6889 epsilon
= epsilons
->PSize
;
6891 case D3DDECLUSAGE_TEXCOORD
:
6893 BYTE usage_index
= decl_ptr
->UsageIndex
;
6894 if (usage_index
> 7)
6896 epsilon
= epsilons
->Texcoords
[usage_index
];
6899 case D3DDECLUSAGE_TANGENT
:
6900 epsilon
= epsilons
->Tangent
;
6902 case D3DDECLUSAGE_BINORMAL
:
6903 epsilon
= epsilons
->Binormal
;
6905 case D3DDECLUSAGE_TESSFACTOR
:
6906 epsilon
= epsilons
->TessFactor
;
6908 case D3DDECLUSAGE_COLOR
:
6909 if (decl_ptr
->UsageIndex
== 0)
6910 epsilon
= epsilons
->Diffuse
;
6911 else if (decl_ptr
->UsageIndex
== 1)
6912 epsilon
= epsilons
->Specular
;
6916 case D3DDECLUSAGE_BLENDINDICES
:
6917 if (!fixme_once_blendindices
++)
6918 FIXME("D3DDECLUSAGE_BLENDINDICES welding not implemented.\n");
6920 case D3DDECLUSAGE_POSITIONT
:
6921 if (!fixme_once_positiont
++)
6922 FIXME("D3DDECLUSAGE_POSITIONT welding not implemented.\n");
6924 case D3DDECLUSAGE_FOG
:
6925 if (!fixme_once_fog
++)
6926 FIXME("D3DDECLUSAGE_FOG welding not implemented.\n");
6928 case D3DDECLUSAGE_DEPTH
:
6929 if (!fixme_once_depth
++)
6930 FIXME("D3DDECLUSAGE_DEPTH welding not implemented.\n");
6932 case D3DDECLUSAGE_SAMPLE
:
6933 if (!fixme_once_sample
++)
6934 FIXME("D3DDECLUSAGE_SAMPLE welding not implemented.\n");
6937 if (!fixme_once_unknown
++)
6938 FIXME("Unknown usage %x\n", decl_ptr
->Usage
);
6945 /* Helper function for reading a 32-bit index buffer. */
6946 static inline DWORD
read_ib(void *index_buffer
, BOOL indices_are_32bit
,
6949 if (indices_are_32bit
)
6951 DWORD
*indices
= index_buffer
;
6952 return indices
[index
];
6956 WORD
*indices
= index_buffer
;
6957 return indices
[index
];
6961 /* Helper function for writing to a 32-bit index buffer. */
6962 static inline void write_ib(void *index_buffer
, BOOL indices_are_32bit
,
6963 DWORD index
, DWORD value
)
6965 if (indices_are_32bit
)
6967 DWORD
*indices
= index_buffer
;
6968 indices
[index
] = value
;
6972 WORD
*indices
= index_buffer
;
6973 indices
[index
] = value
;
6977 /*************************************************************************
6978 * D3DXWeldVertices (D3DX9_36.@)
6980 * Welds together similar vertices. The similarity between vert-
6981 * ices can be the position and other components such as
6985 * mesh [I] Mesh which vertices will be welded together.
6986 * flags [I] D3DXWELDEPSILONSFLAGS specifying how to weld.
6987 * epsilons [I] How similar a component needs to be for welding.
6988 * adjacency [I] Which faces are adjacent to other faces.
6989 * adjacency_out [O] Updated adjacency after welding.
6990 * face_remap_out [O] Which faces the old faces have been mapped to.
6991 * vertex_remap_out [O] Which vertices the old vertices have been mapped to.
6995 * Failure: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
6998 * Attribute sorting not implemented.
7001 HRESULT WINAPI
D3DXWeldVertices(ID3DXMesh
*mesh
, DWORD flags
, const D3DXWELDEPSILONS
*epsilons
,
7002 const DWORD
*adjacency
, DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
7004 DWORD
*adjacency_generated
= NULL
;
7005 const DWORD
*adjacency_ptr
;
7006 DWORD
*attributes
= NULL
;
7007 const FLOAT DEFAULT_EPSILON
= 1.0e-6f
;
7010 void *indices
= NULL
;
7011 BOOL indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
7012 DWORD optimize_flags
;
7013 DWORD
*point_reps
= NULL
;
7014 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(mesh
);
7015 DWORD
*vertex_face_map
= NULL
;
7016 BYTE
*vertices
= NULL
;
7018 TRACE("mesh %p, flags %#x, epsilons %p, adjacency %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
7019 mesh
, flags
, epsilons
, adjacency
, adjacency_out
, face_remap_out
, vertex_remap_out
);
7023 WARN("No flags are undefined. Using D3DXWELDEPSILONS_WELDPARTIALMATCHES instead.\n");
7024 flags
= D3DXWELDEPSILONS_WELDPARTIALMATCHES
;
7027 if (adjacency
) /* Use supplied adjacency. */
7029 adjacency_ptr
= adjacency
;
7031 else /* Adjacency has to be generated. */
7033 adjacency_generated
= HeapAlloc(GetProcessHeap(), 0, 3 * This
->numfaces
* sizeof(*adjacency_generated
));
7034 if (!adjacency_generated
)
7036 ERR("Couldn't allocate memory for adjacency_generated.\n");
7040 hr
= mesh
->lpVtbl
->GenerateAdjacency(mesh
, DEFAULT_EPSILON
, adjacency_generated
);
7043 ERR("Couldn't generate adjacency.\n");
7046 adjacency_ptr
= adjacency_generated
;
7049 /* Point representation says which vertices can be replaced. */
7050 point_reps
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*point_reps
));
7054 ERR("Couldn't allocate memory for point_reps.\n");
7057 hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency_ptr
, point_reps
);
7060 ERR("ConvertAdjacencyToPointReps failed.\n");
7064 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
);
7067 ERR("Couldn't lock index buffer.\n");
7071 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, 0, &attributes
);
7074 ERR("Couldn't lock attribute buffer.\n");
7077 vertex_face_map
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*vertex_face_map
));
7078 if (!vertex_face_map
)
7081 ERR("Couldn't allocate memory for vertex_face_map.\n");
7084 /* Build vertex face map, so that a vertex's face can be looked up. */
7085 for (i
= 0; i
< This
->numfaces
; i
++)
7088 for (j
= 0; j
< 3; j
++)
7090 DWORD index
= read_ib(indices
, indices_are_32bit
, 3*i
+ j
);
7091 vertex_face_map
[index
] = i
;
7095 if (flags
& D3DXWELDEPSILONS_WELDPARTIALMATCHES
)
7097 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void**)&vertices
);
7100 ERR("Couldn't lock vertex buffer.\n");
7103 /* For each vertex that can be removed, compare its vertex components
7104 * with the vertex components from the vertex that can replace it. A
7105 * vertex is only fully replaced if all the components match and the
7106 * flag D3DXWELDEPSILONS_DONOTREMOVEVERTICES is not set, and they
7107 * belong to the same attribute group. Otherwise the vertex components
7108 * that are within epsilon are set to the same value.
7110 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
7112 D3DVERTEXELEMENT9
*decl_ptr
;
7113 DWORD vertex_size
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
7114 DWORD num_vertex_components
;
7117 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7119 for (decl_ptr
= This
->cached_declaration
, num_vertex_components
= 0; decl_ptr
->Stream
!= 0xFF; decl_ptr
++, num_vertex_components
++)
7121 BYTE
*to
= &vertices
[vertex_size
*index
+ decl_ptr
->Offset
];
7122 BYTE
*from
= &vertices
[vertex_size
*point_reps
[index
] + decl_ptr
->Offset
];
7123 FLOAT epsilon
= get_component_epsilon(decl_ptr
, epsilons
);
7125 /* Don't weld self */
7126 if (index
== point_reps
[index
])
7132 if (weld_component(to
, from
, decl_ptr
->Type
, epsilon
))
7136 all_match
= (num_vertex_components
== matches
);
7137 if (all_match
&& !(flags
& D3DXWELDEPSILONS_DONOTREMOVEVERTICES
))
7139 DWORD to_face
= vertex_face_map
[index
];
7140 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7141 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7143 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7146 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7149 else if (flags
& D3DXWELDEPSILONS_WELDALL
)
7151 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
7153 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7154 DWORD to_face
= vertex_face_map
[index
];
7155 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7156 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7158 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7161 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7163 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7166 /* Compact mesh using OptimizeInplace */
7167 optimize_flags
= D3DXMESHOPT_COMPACT
;
7168 hr
= mesh
->lpVtbl
->OptimizeInplace(mesh
, optimize_flags
, adjacency_ptr
, adjacency_out
, face_remap_out
, vertex_remap_out
);
7171 ERR("Couldn't compact mesh.\n");
7177 HeapFree(GetProcessHeap(), 0, adjacency_generated
);
7178 HeapFree(GetProcessHeap(), 0, point_reps
);
7179 HeapFree(GetProcessHeap(), 0, vertex_face_map
);
7180 if (attributes
) mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7181 if (indices
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7182 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7187 /*************************************************************************
7188 * D3DXOptimizeFaces (D3DX9_36.@)
7190 * Re-orders the faces so the vertex cache is used optimally.
7193 * indices [I] Pointer to an index buffer belonging to a mesh.
7194 * num_faces [I] Number of faces in the mesh.
7195 * num_vertices [I] Number of vertices in the mesh.
7196 * indices_are_32bit [I] Specifies whether indices are 32- or 16-bit.
7197 * face_remap [I/O] The new order the faces should be drawn in.
7201 * Failure: D3DERR_INVALIDCALL.
7204 * The face re-ordering does not use the vertex cache optimally.
7207 HRESULT WINAPI
D3DXOptimizeFaces(const void *indices
, UINT num_faces
,
7208 UINT num_vertices
, BOOL indices_are_32bit
, DWORD
*face_remap
)
7211 UINT j
= num_faces
- 1;
7212 UINT limit_16_bit
= 2 << 15; /* According to MSDN */
7213 HRESULT hr
= D3D_OK
;
7215 FIXME("indices %p, num_faces %u, num_vertices %u, indices_are_32bit %#x, face_remap %p semi-stub. "
7216 "Face order will not be optimal.\n",
7217 indices
, num_faces
, num_vertices
, indices_are_32bit
, face_remap
);
7219 if (!indices_are_32bit
&& num_faces
>= limit_16_bit
)
7221 WARN("Number of faces must be less than %d when using 16-bit indices.\n",
7223 hr
= D3DERR_INVALIDCALL
;
7229 WARN("Face remap pointer is NULL.\n");
7230 hr
= D3DERR_INVALIDCALL
;
7234 /* The faces are drawn in reverse order for simple meshes. This ordering
7235 * is not optimal for complicated meshes, but will not break anything
7236 * either. The ordering should be changed to take advantage of the vertex
7237 * cache on the graphics card.
7239 * TODO Re-order to take advantage of vertex cache.
7241 for (i
= 0; i
< num_faces
; i
++)
7243 face_remap
[i
] = j
--;
7252 static D3DXVECTOR3
*vertex_element_vec3(BYTE
*vertices
, const D3DVERTEXELEMENT9
*declaration
,
7253 DWORD vertex_stride
, DWORD index
)
7255 return (D3DXVECTOR3
*)(vertices
+ declaration
->Offset
+ index
* vertex_stride
);
7258 static D3DXVECTOR3
read_vec3(BYTE
*vertices
, const D3DVERTEXELEMENT9
*declaration
,
7259 DWORD vertex_stride
, DWORD index
)
7261 D3DXVECTOR3 vec3
= {0};
7262 const D3DXVECTOR3
*src
= vertex_element_vec3(vertices
, declaration
, vertex_stride
, index
);
7264 switch (declaration
->Type
)
7266 case D3DDECLTYPE_FLOAT1
:
7269 case D3DDECLTYPE_FLOAT2
:
7273 case D3DDECLTYPE_FLOAT3
:
7274 case D3DDECLTYPE_FLOAT4
:
7278 ERR("Cannot read vec3\n");
7285 /*************************************************************************
7286 * D3DXComputeTangentFrameEx (D3DX9_36.@)
7288 HRESULT WINAPI
D3DXComputeTangentFrameEx(ID3DXMesh
*mesh
, DWORD texture_in_semantic
, DWORD texture_in_index
,
7289 DWORD u_partial_out_semantic
, DWORD u_partial_out_index
, DWORD v_partial_out_semantic
,
7290 DWORD v_partial_out_index
, DWORD normal_out_semantic
, DWORD normal_out_index
, DWORD options
,
7291 const DWORD
*adjacency
, float partial_edge_threshold
, float singular_point_threshold
,
7292 float normal_edge_threshold
, ID3DXMesh
**mesh_out
, ID3DXBuffer
**vertex_mapping
)
7295 void *indices
= NULL
;
7296 BYTE
*vertices
= NULL
;
7297 DWORD
*point_reps
= NULL
;
7299 BOOL indices_are_32bit
;
7300 DWORD i
, j
, num_faces
, num_vertices
, vertex_stride
;
7301 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
7302 D3DVERTEXELEMENT9
*position_declaration
= NULL
, *normal_declaration
= NULL
;
7303 DWORD weighting_method
= options
& (D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
);
7305 TRACE("mesh %p, texture_in_semantic %u, texture_in_index %u, u_partial_out_semantic %u, u_partial_out_index %u, "
7306 "v_partial_out_semantic %u, v_partial_out_index %u, normal_out_semantic %u, normal_out_index %u, "
7307 "options %#x, adjacency %p, partial_edge_threshold %f, singular_point_threshold %f, "
7308 "normal_edge_threshold %f, mesh_out %p, vertex_mapping %p\n",
7309 mesh
, texture_in_semantic
, texture_in_index
, u_partial_out_semantic
, u_partial_out_index
,
7310 v_partial_out_semantic
, v_partial_out_index
, normal_out_semantic
, normal_out_index
, options
, adjacency
,
7311 partial_edge_threshold
, singular_point_threshold
, normal_edge_threshold
, mesh_out
, vertex_mapping
);
7315 WARN("mesh is NULL\n");
7316 return D3DERR_INVALIDCALL
;
7319 if (weighting_method
== (D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
))
7321 WARN("D3DXTANGENT_WEIGHT_BY_AREA and D3DXTANGENT_WEIGHT_EQUAL are mutally exclusive\n");
7322 return D3DERR_INVALIDCALL
;
7325 if (u_partial_out_semantic
!= D3DX_DEFAULT
)
7327 FIXME("tangent vectors computation is not supported\n");
7331 if (v_partial_out_semantic
!= D3DX_DEFAULT
)
7333 FIXME("binormal vectors computation is not supported\n");
7337 if (options
& ~(D3DXTANGENT_GENERATE_IN_PLACE
| D3DXTANGENT_CALCULATE_NORMALS
| D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
))
7339 FIXME("unsupported options %#x\n", options
);
7343 if (!(options
& D3DXTANGENT_CALCULATE_NORMALS
))
7345 FIXME("only normals computation is supported\n");
7349 if (!(options
& D3DXTANGENT_GENERATE_IN_PLACE
) || mesh_out
|| vertex_mapping
)
7351 FIXME("only D3DXTANGENT_GENERATE_IN_PLACE is supported\n");
7355 if (FAILED(hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, declaration
)))
7358 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
7360 if (declaration
[i
].Usage
== D3DDECLUSAGE_POSITION
&& !declaration
[i
].UsageIndex
)
7361 position_declaration
= &declaration
[i
];
7362 if (declaration
[i
].Usage
== normal_out_semantic
&& declaration
[i
].UsageIndex
== normal_out_index
)
7363 normal_declaration
= &declaration
[i
];
7366 if (!position_declaration
|| !normal_declaration
)
7367 return D3DERR_INVALIDCALL
;
7369 if (normal_declaration
->Type
== D3DDECLTYPE_FLOAT3
)
7371 normal_size
= sizeof(D3DXVECTOR3
);
7373 else if (normal_declaration
->Type
== D3DDECLTYPE_FLOAT4
)
7375 normal_size
= sizeof(D3DXVECTOR4
);
7379 WARN("unsupported normals type %u\n", normal_declaration
->Type
);
7380 return D3DERR_INVALIDCALL
;
7383 num_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
7384 num_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
7385 vertex_stride
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
7386 indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
7388 point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*point_reps
));
7397 if (FAILED(hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency
, point_reps
)))
7402 for (i
= 0; i
< num_vertices
; i
++)
7406 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
)))
7409 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
7412 for (i
= 0; i
< num_vertices
; i
++)
7414 static const D3DXVECTOR4 default_vector
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
7415 void *normal
= vertices
+ normal_declaration
->Offset
+ i
* vertex_stride
;
7417 memcpy(normal
, &default_vector
, normal_size
);
7420 for (i
= 0; i
< num_faces
; i
++)
7422 float denominator
, weights
[3];
7423 D3DXVECTOR3 a
, b
, cross
, face_normal
;
7424 const DWORD face_indices
[3] =
7426 read_ib(indices
, indices_are_32bit
, 3 * i
+ 0),
7427 read_ib(indices
, indices_are_32bit
, 3 * i
+ 1),
7428 read_ib(indices
, indices_are_32bit
, 3 * i
+ 2)
7430 const D3DXVECTOR3 v0
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[0]);
7431 const D3DXVECTOR3 v1
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[1]);
7432 const D3DXVECTOR3 v2
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[2]);
7434 D3DXVec3Cross(&cross
, D3DXVec3Subtract(&a
, &v0
, &v1
), D3DXVec3Subtract(&b
, &v0
, &v2
));
7436 switch (weighting_method
)
7438 case D3DXTANGENT_WEIGHT_EQUAL
:
7439 weights
[0] = weights
[1] = weights
[2] = 1.0f
;
7441 case D3DXTANGENT_WEIGHT_BY_AREA
:
7442 weights
[0] = weights
[1] = weights
[2] = D3DXVec3Length(&cross
);
7445 /* weight by angle */
7446 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7450 weights
[0] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7452 D3DXVec3Subtract(&a
, &v1
, &v0
);
7453 D3DXVec3Subtract(&b
, &v1
, &v2
);
7454 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7458 weights
[1] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7460 D3DXVec3Subtract(&a
, &v2
, &v0
);
7461 D3DXVec3Subtract(&b
, &v2
, &v1
);
7462 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7466 weights
[2] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7471 D3DXVec3Normalize(&face_normal
, &cross
);
7473 for (j
= 0; j
< 3; j
++)
7476 DWORD rep_index
= point_reps
[face_indices
[j
]];
7477 D3DXVECTOR3
*rep_normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, rep_index
);
7479 D3DXVec3Scale(&normal
, &face_normal
, weights
[j
]);
7480 D3DXVec3Add(rep_normal
, rep_normal
, &normal
);
7484 for (i
= 0; i
< num_vertices
; i
++)
7486 DWORD rep_index
= point_reps
[i
];
7487 D3DXVECTOR3
*normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, i
);
7488 D3DXVECTOR3
*rep_normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, rep_index
);
7491 D3DXVec3Normalize(rep_normal
, rep_normal
);
7493 *normal
= *rep_normal
;
7500 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7503 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7505 HeapFree(GetProcessHeap(), 0, point_reps
);
7510 /*************************************************************************
7511 * D3DXComputeNormals (D3DX9_36.@)
7513 HRESULT WINAPI
D3DXComputeNormals(struct ID3DXBaseMesh
*mesh
, const DWORD
*adjacency
)
7515 TRACE("mesh %p, adjacency %p\n", mesh
, adjacency
);
7517 if (mesh
&& (ID3DXMeshVtbl
*)mesh
->lpVtbl
!= &D3DXMesh_Vtbl
)
7519 ERR("Invalid virtual table\n");
7520 return D3DERR_INVALIDCALL
;
7523 return D3DXComputeTangentFrameEx((ID3DXMesh
*)mesh
, D3DX_DEFAULT
, 0,
7524 D3DX_DEFAULT
, 0, D3DX_DEFAULT
, 0, D3DDECLUSAGE_NORMAL
, 0,
7525 D3DXTANGENT_GENERATE_IN_PLACE
| D3DXTANGENT_CALCULATE_NORMALS
,
7526 adjacency
, -1.01f
, -0.01f
, -1.01f
, NULL
, NULL
);
7529 /*************************************************************************
7530 * D3DXIntersect (D3DX9_36.@)
7532 HRESULT WINAPI
D3DXIntersect(ID3DXBaseMesh
*mesh
, const D3DXVECTOR3
*ray_pos
, const D3DXVECTOR3
*ray_dir
,
7533 BOOL
*hit
, DWORD
*face_index
, float *u
, float *v
, float *distance
, ID3DXBuffer
**all_hits
, DWORD
*count_of_hits
)
7535 FIXME("mesh %p, ray_pos %p, ray_dir %p, hit %p, face_index %p, u %p, v %p, distance %p, all_hits %p, "
7536 "count_of_hits %p stub!\n", mesh
, ray_pos
, ray_dir
, hit
, face_index
, u
, v
, distance
, all_hits
, count_of_hits
);
7541 HRESULT WINAPI
D3DXTessellateNPatches(ID3DXMesh
*mesh
, const DWORD
*adjacency_in
, float num_segs
,
7542 BOOL quadratic_normals
, ID3DXMesh
**mesh_out
, ID3DXBuffer
**adjacency_out
)
7544 FIXME("mesh %p, adjacency_in %p, num_segs %f, quadratic_normals %d, mesh_out %p, adjacency_out %p stub.\n",
7545 mesh
, adjacency_in
, num_segs
, quadratic_normals
, mesh_out
, adjacency_out
);
7550 HRESULT WINAPI
D3DXConvertMeshSubsetToSingleStrip(struct ID3DXBaseMesh
*mesh_in
, DWORD attribute_id
,
7551 DWORD ib_flags
, struct IDirect3DIndexBuffer9
**index_buffer
, DWORD
*index_count
)
7553 FIXME("mesh_in %p, attribute_id %u, ib_flags %u, index_buffer %p, index_count %p stub.\n",
7554 mesh_in
, attribute_id
, ib_flags
, index_buffer
, index_count
);