2 * Mesh operations specific to D3DX9.
4 * Copyright (C) 2005 Henri Verbeet
5 * Copyright (C) 2006 Ivan Gyurdiev
6 * Copyright (C) 2009 David Adam
7 * Copyright (C) 2010 Tony Wasserka
8 * Copyright (C) 2011 Dylan Smith
9 * Copyright (C) 2011 Michael Mc Donnell
10 * Copyright (C) 2013 Christian Costa
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
31 #define NONAMELESSUNION
43 #include "wine/debug.h"
44 #include "wine/unicode.h"
45 #include "wine/list.h"
46 #include "d3dx9_36_private.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
52 ID3DXMesh ID3DXMesh_iface
;
59 IDirect3DDevice9
*device
;
60 D3DVERTEXELEMENT9 cached_declaration
[MAX_FVF_DECL_SIZE
];
61 IDirect3DVertexDeclaration9
*vertex_declaration
;
62 UINT vertex_declaration_size
;
64 IDirect3DVertexBuffer9
*vertex_buffer
;
65 IDirect3DIndexBuffer9
*index_buffer
;
67 int attrib_buffer_lock_count
;
68 DWORD attrib_table_size
;
69 D3DXATTRIBUTERANGE
*attrib_table
;
72 static const UINT d3dx_decltype_size
[] =
74 /* D3DDECLTYPE_FLOAT1 */ sizeof(FLOAT
),
75 /* D3DDECLTYPE_FLOAT2 */ sizeof(D3DXVECTOR2
),
76 /* D3DDECLTYPE_FLOAT3 */ sizeof(D3DXVECTOR3
),
77 /* D3DDECLTYPE_FLOAT4 */ sizeof(D3DXVECTOR4
),
78 /* D3DDECLTYPE_D3DCOLOR */ sizeof(D3DCOLOR
),
79 /* D3DDECLTYPE_UBYTE4 */ 4 * sizeof(BYTE
),
80 /* D3DDECLTYPE_SHORT2 */ 2 * sizeof(SHORT
),
81 /* D3DDECLTYPE_SHORT4 */ 4 * sizeof(SHORT
),
82 /* D3DDECLTYPE_UBYTE4N */ 4 * sizeof(BYTE
),
83 /* D3DDECLTYPE_SHORT2N */ 2 * sizeof(SHORT
),
84 /* D3DDECLTYPE_SHORT4N */ 4 * sizeof(SHORT
),
85 /* D3DDECLTYPE_USHORT2N */ 2 * sizeof(USHORT
),
86 /* D3DDECLTYPE_USHORT4N */ 4 * sizeof(USHORT
),
87 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
88 /* D3DDECLTYPE_DEC3N */ 4,
89 /* D3DDECLTYPE_FLOAT16_2 */ 2 * sizeof(D3DXFLOAT16
),
90 /* D3DDECLTYPE_FLOAT16_4 */ 4 * sizeof(D3DXFLOAT16
),
93 static inline struct d3dx9_mesh
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
95 return CONTAINING_RECORD(iface
, struct d3dx9_mesh
, ID3DXMesh_iface
);
98 static HRESULT WINAPI
d3dx9_mesh_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, void **out
)
100 TRACE("iface %p, riid %s, out %p.\n", iface
, debugstr_guid(riid
), out
);
102 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
103 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
104 IsEqualGUID(riid
, &IID_ID3DXMesh
))
106 iface
->lpVtbl
->AddRef(iface
);
111 WARN("Interface %s not found.\n", debugstr_guid(riid
));
113 return E_NOINTERFACE
;
116 static ULONG WINAPI
d3dx9_mesh_AddRef(ID3DXMesh
*iface
)
118 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
119 ULONG refcount
= InterlockedIncrement(&mesh
->ref
);
121 TRACE("%p increasing refcount to %u.\n", mesh
, refcount
);
126 static ULONG WINAPI
d3dx9_mesh_Release(ID3DXMesh
*iface
)
128 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
129 ULONG refcount
= InterlockedDecrement(&mesh
->ref
);
131 TRACE("%p decreasing refcount to %u.\n", mesh
, refcount
);
135 IDirect3DIndexBuffer9_Release(mesh
->index_buffer
);
136 IDirect3DVertexBuffer9_Release(mesh
->vertex_buffer
);
137 if (mesh
->vertex_declaration
)
138 IDirect3DVertexDeclaration9_Release(mesh
->vertex_declaration
);
139 IDirect3DDevice9_Release(mesh
->device
);
140 HeapFree(GetProcessHeap(), 0, mesh
->attrib_buffer
);
141 HeapFree(GetProcessHeap(), 0, mesh
->attrib_table
);
142 HeapFree(GetProcessHeap(), 0, mesh
);
148 static HRESULT WINAPI
d3dx9_mesh_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
150 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
156 TRACE("iface %p, attrib_id %u.\n", iface
, attrib_id
);
158 if (!This
->vertex_declaration
)
160 WARN("Can't draw a mesh with an invalid vertex declaration.\n");
164 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
166 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
167 if (FAILED(hr
)) return hr
;
168 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
169 if (FAILED(hr
)) return hr
;
170 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
171 if (FAILED(hr
)) return hr
;
173 while (face_end
< This
->numfaces
)
175 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
177 if (This
->attrib_buffer
[face_start
] == attrib_id
)
180 if (face_start
>= This
->numfaces
)
182 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
184 if (This
->attrib_buffer
[face_end
] != attrib_id
)
188 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
189 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
190 if (FAILED(hr
)) return hr
;
196 static DWORD WINAPI
d3dx9_mesh_GetNumFaces(ID3DXMesh
*iface
)
198 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
200 TRACE("iface %p.\n", iface
);
202 return mesh
->numfaces
;
205 static DWORD WINAPI
d3dx9_mesh_GetNumVertices(ID3DXMesh
*iface
)
207 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
209 TRACE("iface %p.\n", iface
);
211 return mesh
->numvertices
;
214 static DWORD WINAPI
d3dx9_mesh_GetFVF(ID3DXMesh
*iface
)
216 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
218 TRACE("iface %p.\n", iface
);
223 static void copy_declaration(D3DVERTEXELEMENT9
*dst
, const D3DVERTEXELEMENT9
*src
, UINT num_elem
)
225 memcpy(dst
, src
, num_elem
* sizeof(*src
));
228 static HRESULT WINAPI
d3dx9_mesh_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
230 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
232 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
235 return D3DERR_INVALIDCALL
;
237 copy_declaration(declaration
, mesh
->cached_declaration
, mesh
->num_elem
);
242 static DWORD WINAPI
d3dx9_mesh_GetNumBytesPerVertex(ID3DXMesh
*iface
)
244 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
246 TRACE("iface %p.\n", iface
);
248 return mesh
->vertex_declaration_size
;
251 static DWORD WINAPI
d3dx9_mesh_GetOptions(ID3DXMesh
*iface
)
253 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
255 TRACE("iface %p.\n", iface
);
257 return mesh
->options
;
260 static HRESULT WINAPI
d3dx9_mesh_GetDevice(struct ID3DXMesh
*iface
, struct IDirect3DDevice9
**device
)
262 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
264 TRACE("iface %p, device %p.\n", iface
, device
);
267 return D3DERR_INVALIDCALL
;
268 *device
= mesh
->device
;
269 IDirect3DDevice9_AddRef(mesh
->device
);
274 static HRESULT WINAPI
d3dx9_mesh_CloneMeshFVF(struct ID3DXMesh
*iface
, DWORD options
, DWORD fvf
,
275 struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh
)
278 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
280 TRACE("iface %p, options %#x, fvf %#x, device %p, clone_mesh %p.\n",
281 iface
, options
, fvf
, device
, clone_mesh
);
283 if (FAILED(hr
= D3DXDeclaratorFromFVF(fvf
, declaration
)))
286 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
289 static FLOAT
scale_clamp_ubyten(FLOAT value
)
291 value
= value
* UCHAR_MAX
;
299 if (value
> UCHAR_MAX
) /* Clamp at 255 */
306 static FLOAT
scale_clamp_shortn(FLOAT value
)
308 value
= value
* SHRT_MAX
;
310 /* The tests show that the range is SHRT_MIN + 1 to SHRT_MAX. */
311 if (value
<= SHRT_MIN
)
315 else if (value
> SHRT_MAX
)
325 static FLOAT
scale_clamp_ushortn(FLOAT value
)
327 value
= value
* USHRT_MAX
;
335 if (value
> USHRT_MAX
) /* Clamp at 65535 */
342 static INT
simple_round(FLOAT value
)
344 int res
= (INT
)(value
+ 0.5f
);
349 static void convert_float4(BYTE
*dst
, const D3DXVECTOR4
*src
, D3DDECLTYPE type_dst
)
351 BOOL fixme_once
= FALSE
;
355 case D3DDECLTYPE_FLOAT1
:
357 FLOAT
*dst_ptr
= (FLOAT
*)dst
;
361 case D3DDECLTYPE_FLOAT2
:
363 D3DXVECTOR2
*dst_ptr
= (D3DXVECTOR2
*)dst
;
368 case D3DDECLTYPE_FLOAT3
:
370 D3DXVECTOR3
*dst_ptr
= (D3DXVECTOR3
*)dst
;
376 case D3DDECLTYPE_FLOAT4
:
378 D3DXVECTOR4
*dst_ptr
= (D3DXVECTOR4
*)dst
;
385 case D3DDECLTYPE_D3DCOLOR
:
387 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
388 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
389 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
390 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
393 case D3DDECLTYPE_UBYTE4
:
395 dst
[0] = src
->x
< 0.0f
? 0 : (BYTE
)simple_round(src
->x
);
396 dst
[1] = src
->y
< 0.0f
? 0 : (BYTE
)simple_round(src
->y
);
397 dst
[2] = src
->z
< 0.0f
? 0 : (BYTE
)simple_round(src
->z
);
398 dst
[3] = src
->w
< 0.0f
? 0 : (BYTE
)simple_round(src
->w
);
401 case D3DDECLTYPE_SHORT2
:
403 SHORT
*dst_ptr
= (SHORT
*)dst
;
404 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
405 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
408 case D3DDECLTYPE_SHORT4
:
410 SHORT
*dst_ptr
= (SHORT
*)dst
;
411 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
412 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
413 dst_ptr
[2] = (SHORT
)simple_round(src
->z
);
414 dst_ptr
[3] = (SHORT
)simple_round(src
->w
);
417 case D3DDECLTYPE_UBYTE4N
:
419 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
420 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
421 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
422 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
425 case D3DDECLTYPE_SHORT2N
:
427 SHORT
*dst_ptr
= (SHORT
*)dst
;
428 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
429 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
432 case D3DDECLTYPE_SHORT4N
:
434 SHORT
*dst_ptr
= (SHORT
*)dst
;
435 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
436 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
437 dst_ptr
[2] = (SHORT
)simple_round(scale_clamp_shortn(src
->z
));
438 dst_ptr
[3] = (SHORT
)simple_round(scale_clamp_shortn(src
->w
));
441 case D3DDECLTYPE_USHORT2N
:
443 USHORT
*dst_ptr
= (USHORT
*)dst
;
444 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
445 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
448 case D3DDECLTYPE_USHORT4N
:
450 USHORT
*dst_ptr
= (USHORT
*)dst
;
451 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
452 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
453 dst_ptr
[2] = (USHORT
)simple_round(scale_clamp_ushortn(src
->z
));
454 dst_ptr
[3] = (USHORT
)simple_round(scale_clamp_ushortn(src
->w
));
457 case D3DDECLTYPE_FLOAT16_2
:
459 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 2);
462 case D3DDECLTYPE_FLOAT16_4
:
464 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 4);
469 FIXME("Conversion from D3DDECLTYPE_FLOAT4 to %d not implemented.\n", type_dst
);
474 static void convert_component(BYTE
*dst
, BYTE
*src
, D3DDECLTYPE type_dst
, D3DDECLTYPE type_src
)
476 BOOL fixme_once
= FALSE
;
480 case D3DDECLTYPE_FLOAT1
:
482 FLOAT
*src_ptr
= (FLOAT
*)src
;
483 D3DXVECTOR4 src_float4
= {*src_ptr
, 0.0f
, 0.0f
, 1.0f
};
484 convert_float4(dst
, &src_float4
, type_dst
);
487 case D3DDECLTYPE_FLOAT2
:
489 D3DXVECTOR2
*src_ptr
= (D3DXVECTOR2
*)src
;
490 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, 0.0f
, 1.0f
};
491 convert_float4(dst
, &src_float4
, type_dst
);
494 case D3DDECLTYPE_FLOAT3
:
496 D3DXVECTOR3
*src_ptr
= (D3DXVECTOR3
*)src
;
497 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, 1.0f
};
498 convert_float4(dst
, &src_float4
, type_dst
);
501 case D3DDECLTYPE_FLOAT4
:
503 D3DXVECTOR4
*src_ptr
= (D3DXVECTOR4
*)src
;
504 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, src_ptr
->w
};
505 convert_float4(dst
, &src_float4
, type_dst
);
508 case D3DDECLTYPE_D3DCOLOR
:
510 D3DXVECTOR4 src_float4
=
512 (FLOAT
)src
[2]/UCHAR_MAX
,
513 (FLOAT
)src
[1]/UCHAR_MAX
,
514 (FLOAT
)src
[0]/UCHAR_MAX
,
515 (FLOAT
)src
[3]/UCHAR_MAX
517 convert_float4(dst
, &src_float4
, type_dst
);
520 case D3DDECLTYPE_UBYTE4
:
522 D3DXVECTOR4 src_float4
= {src
[0], src
[1], src
[2], src
[3]};
523 convert_float4(dst
, &src_float4
, type_dst
);
526 case D3DDECLTYPE_SHORT2
:
528 SHORT
*src_ptr
= (SHORT
*)src
;
529 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], 0.0f
, 1.0f
};
530 convert_float4(dst
, &src_float4
, type_dst
);
533 case D3DDECLTYPE_SHORT4
:
535 SHORT
*src_ptr
= (SHORT
*)src
;
536 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], src_ptr
[2], src_ptr
[3]};
537 convert_float4(dst
, &src_float4
, type_dst
);
540 case D3DDECLTYPE_UBYTE4N
:
542 D3DXVECTOR4 src_float4
=
544 (FLOAT
)src
[0]/UCHAR_MAX
,
545 (FLOAT
)src
[1]/UCHAR_MAX
,
546 (FLOAT
)src
[2]/UCHAR_MAX
,
547 (FLOAT
)src
[3]/UCHAR_MAX
549 convert_float4(dst
, &src_float4
, type_dst
);
552 case D3DDECLTYPE_SHORT2N
:
554 SHORT
*src_ptr
= (SHORT
*)src
;
555 D3DXVECTOR4 src_float4
= {(FLOAT
)src_ptr
[0]/SHRT_MAX
, (FLOAT
)src_ptr
[1]/SHRT_MAX
, 0.0f
, 1.0f
};
556 convert_float4(dst
, &src_float4
, type_dst
);
559 case D3DDECLTYPE_SHORT4N
:
561 SHORT
*src_ptr
= (SHORT
*)src
;
562 D3DXVECTOR4 src_float4
=
564 (FLOAT
)src_ptr
[0]/SHRT_MAX
,
565 (FLOAT
)src_ptr
[1]/SHRT_MAX
,
566 (FLOAT
)src_ptr
[2]/SHRT_MAX
,
567 (FLOAT
)src_ptr
[3]/SHRT_MAX
569 convert_float4(dst
, &src_float4
, type_dst
);
572 case D3DDECLTYPE_FLOAT16_2
:
574 D3DXVECTOR4 src_float4
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
575 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 2);
576 convert_float4(dst
, &src_float4
, type_dst
);
579 case D3DDECLTYPE_FLOAT16_4
:
581 D3DXVECTOR4 src_float4
;
582 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 4);
583 convert_float4(dst
, &src_float4
, type_dst
);
588 FIXME("Conversion of D3DDECLTYPE %d to %d not implemented.\n", type_src
, type_dst
);
593 static INT
get_equivalent_declaration_index(D3DVERTEXELEMENT9 orig_declaration
, D3DVERTEXELEMENT9
*declaration
)
597 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
599 if (orig_declaration
.Usage
== declaration
[i
].Usage
600 && orig_declaration
.UsageIndex
== declaration
[i
].UsageIndex
)
609 static HRESULT
convert_vertex_buffer(ID3DXMesh
*mesh_dst
, ID3DXMesh
*mesh_src
)
612 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
613 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
617 UINT num_vertices
= mesh_src
->lpVtbl
->GetNumVertices(mesh_src
);
618 UINT dst_vertex_size
= mesh_dst
->lpVtbl
->GetNumBytesPerVertex(mesh_dst
);
619 UINT src_vertex_size
= mesh_src
->lpVtbl
->GetNumBytesPerVertex(mesh_src
);
621 hr
= mesh_src
->lpVtbl
->GetDeclaration(mesh_src
, orig_declaration
);
622 if (FAILED(hr
)) return hr
;
623 hr
= mesh_dst
->lpVtbl
->GetDeclaration(mesh_dst
, declaration
);
624 if (FAILED(hr
)) return hr
;
626 hr
= mesh_src
->lpVtbl
->LockVertexBuffer(mesh_src
, D3DLOCK_READONLY
, (void**)&vb_src
);
627 if (FAILED(hr
)) goto cleanup
;
628 hr
= mesh_dst
->lpVtbl
->LockVertexBuffer(mesh_dst
, 0, (void**)&vb_dst
);
629 if (FAILED(hr
)) goto cleanup
;
631 /* Clear all new fields by clearing the entire vertex buffer. */
632 memset(vb_dst
, 0, num_vertices
* dst_vertex_size
);
634 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++)
636 INT eq_idx
= get_equivalent_declaration_index(orig_declaration
[i
], declaration
);
641 for (j
= 0; j
< num_vertices
; j
++)
643 UINT idx_dst
= dst_vertex_size
* j
+ declaration
[eq_idx
].Offset
;
644 UINT idx_src
= src_vertex_size
* j
+ orig_declaration
[i
].Offset
;
645 UINT type_size
= d3dx_decltype_size
[orig_declaration
[i
].Type
];
647 if (orig_declaration
[i
].Type
== declaration
[eq_idx
].Type
)
648 memcpy(&vb_dst
[idx_dst
], &vb_src
[idx_src
], type_size
);
650 convert_component(&vb_dst
[idx_dst
], &vb_src
[idx_src
], declaration
[eq_idx
].Type
, orig_declaration
[i
].Type
);
657 if (vb_dst
) mesh_dst
->lpVtbl
->UnlockVertexBuffer(mesh_dst
);
658 if (vb_src
) mesh_src
->lpVtbl
->UnlockVertexBuffer(mesh_src
);
663 static BOOL
declaration_equals(const D3DVERTEXELEMENT9
*declaration1
, const D3DVERTEXELEMENT9
*declaration2
)
665 UINT size1
= 0, size2
= 0;
667 /* Find the size of each declaration */
668 while (declaration1
[size1
].Stream
!= 0xff) size1
++;
669 while (declaration2
[size2
].Stream
!= 0xff) size2
++;
671 /* If not same size then they are definitely not equal */
675 /* Check that all components are the same */
676 if (memcmp(declaration1
, declaration2
, size1
*sizeof(*declaration1
)) == 0)
682 static HRESULT WINAPI
d3dx9_mesh_CloneMesh(struct ID3DXMesh
*iface
, DWORD options
,
683 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh_out
)
685 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
686 struct d3dx9_mesh
*cloned_this
;
687 ID3DXMesh
*clone_mesh
;
688 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
689 void *data_in
, *data_out
;
692 BOOL same_declaration
;
694 TRACE("iface %p, options %#x, declaration %p, device %p, clone_mesh_out %p.\n",
695 iface
, options
, declaration
, device
, clone_mesh_out
);
698 return D3DERR_INVALIDCALL
;
700 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
701 if (FAILED(hr
)) return hr
;
703 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
704 declaration
, device
, &clone_mesh
);
705 if (FAILED(hr
)) return hr
;
707 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
708 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
709 same_declaration
= declaration_equals(declaration
, orig_declaration
);
711 if (options
& D3DXMESH_VB_SHARE
) {
712 if (!same_declaration
) {
713 hr
= D3DERR_INVALIDCALL
;
716 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
717 /* FIXME: refactor to avoid creating a new vertex buffer */
718 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
719 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
720 } else if (same_declaration
) {
721 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
722 if (FAILED(hr
)) goto error
;
723 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, 0, &data_out
);
725 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
728 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
729 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
730 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
732 hr
= convert_vertex_buffer(clone_mesh
, iface
);
733 if (FAILED(hr
)) goto error
;
736 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
737 if (FAILED(hr
)) goto error
;
738 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, 0, &data_out
);
740 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
743 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
745 if (options
& D3DXMESH_32BIT
) {
746 for (i
= 0; i
< This
->numfaces
* 3; i
++)
747 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
749 for (i
= 0; i
< This
->numfaces
* 3; i
++)
750 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
753 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
755 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
756 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
758 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
760 if (This
->attrib_table_size
)
762 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
763 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
764 if (!cloned_this
->attrib_table
) {
768 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
771 *clone_mesh_out
= clone_mesh
;
775 IUnknown_Release(clone_mesh
);
779 static HRESULT WINAPI
d3dx9_mesh_GetVertexBuffer(struct ID3DXMesh
*iface
,
780 struct IDirect3DVertexBuffer9
**vertex_buffer
)
782 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
784 TRACE("iface %p, vertex_buffer %p.\n", iface
, vertex_buffer
);
787 return D3DERR_INVALIDCALL
;
788 *vertex_buffer
= mesh
->vertex_buffer
;
789 IDirect3DVertexBuffer9_AddRef(mesh
->vertex_buffer
);
794 static HRESULT WINAPI
d3dx9_mesh_GetIndexBuffer(struct ID3DXMesh
*iface
,
795 struct IDirect3DIndexBuffer9
**index_buffer
)
797 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
799 TRACE("iface %p, index_buffer %p.\n", iface
, index_buffer
);
802 return D3DERR_INVALIDCALL
;
803 *index_buffer
= mesh
->index_buffer
;
804 IDirect3DIndexBuffer9_AddRef(mesh
->index_buffer
);
809 static HRESULT WINAPI
d3dx9_mesh_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
811 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
813 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
815 return IDirect3DVertexBuffer9_Lock(mesh
->vertex_buffer
, 0, 0, data
, flags
);
818 static HRESULT WINAPI
d3dx9_mesh_UnlockVertexBuffer(ID3DXMesh
*iface
)
820 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
822 TRACE("iface %p.\n", iface
);
824 return IDirect3DVertexBuffer9_Unlock(mesh
->vertex_buffer
);
827 static HRESULT WINAPI
d3dx9_mesh_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, void **data
)
829 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
831 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
833 return IDirect3DIndexBuffer9_Lock(mesh
->index_buffer
, 0, 0, data
, flags
);
836 static HRESULT WINAPI
d3dx9_mesh_UnlockIndexBuffer(ID3DXMesh
*iface
)
838 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
840 TRACE("iface %p.\n", iface
);
842 return IDirect3DIndexBuffer9_Unlock(mesh
->index_buffer
);
845 /* FIXME: This looks just wrong, we never check *attrib_table_size before
846 * copying the data. */
847 static HRESULT WINAPI
d3dx9_mesh_GetAttributeTable(ID3DXMesh
*iface
,
848 D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
850 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
852 TRACE("iface %p, attrib_table %p, attrib_table_size %p.\n",
853 iface
, attrib_table
, attrib_table_size
);
855 if (attrib_table_size
)
856 *attrib_table_size
= mesh
->attrib_table_size
;
859 memcpy(attrib_table
, mesh
->attrib_table
, mesh
->attrib_table_size
* sizeof(*attrib_table
));
874 struct edge_face
*entries
;
877 /* Builds up a map of which face a new edge belongs to. That way the adjacency
878 * of another edge can be looked up. An edge has an adjacent face if there
879 * is an edge going in the opposite direction in the map. For example if the
880 * edge (v1, v2) belongs to face 4, and there is a mapping (v2, v1)->7, then
881 * face 4 and 7 are adjacent.
883 * Each edge might have been replaced with another edge, or none at all. There
884 * is at most one edge to face mapping, i.e. an edge can only belong to one
887 static HRESULT
init_edge_face_map(struct edge_face_map
*edge_face_map
, const DWORD
*index_buffer
,
888 const DWORD
*point_reps
, DWORD num_faces
)
893 edge_face_map
->lists
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->lists
));
894 if (!edge_face_map
->lists
) return E_OUTOFMEMORY
;
896 edge_face_map
->entries
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->entries
));
897 if (!edge_face_map
->entries
) return E_OUTOFMEMORY
;
900 /* Initialize all lists */
901 for (i
= 0; i
< 3 * num_faces
; i
++)
903 list_init(&edge_face_map
->lists
[i
]);
905 /* Build edge face mapping */
906 for (face
= 0; face
< num_faces
; face
++)
908 for (edge
= 0; edge
< 3; edge
++)
910 DWORD v1
= index_buffer
[3*face
+ edge
];
911 DWORD v2
= index_buffer
[3*face
+ (edge
+1)%3];
912 DWORD new_v1
= point_reps
[v1
]; /* What v1 has been replaced with */
913 DWORD new_v2
= point_reps
[v2
];
915 if (v1
!= v2
) /* Only map non-collapsed edges */
918 edge_face_map
->entries
[i
].v2
= new_v2
;
919 edge_face_map
->entries
[i
].face
= face
;
920 list_add_head(&edge_face_map
->lists
[new_v1
], &edge_face_map
->entries
[i
].entry
);
928 static DWORD
find_adjacent_face(struct edge_face_map
*edge_face_map
, DWORD vertex1
, DWORD vertex2
, DWORD num_faces
)
930 struct edge_face
*edge_face_ptr
;
932 LIST_FOR_EACH_ENTRY(edge_face_ptr
, &edge_face_map
->lists
[vertex2
], struct edge_face
, entry
)
934 if (edge_face_ptr
->v2
== vertex1
)
935 return edge_face_ptr
->face
;
941 static DWORD
*generate_identity_point_reps(DWORD num_vertices
)
943 DWORD
*id_point_reps
;
946 id_point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*id_point_reps
));
950 for (i
= 0; i
< num_vertices
; i
++)
952 id_point_reps
[i
] = i
;
955 return id_point_reps
;
958 static HRESULT WINAPI
d3dx9_mesh_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
,
959 const DWORD
*point_reps
, DWORD
*adjacency
)
962 DWORD num_faces
= iface
->lpVtbl
->GetNumFaces(iface
);
963 DWORD num_vertices
= iface
->lpVtbl
->GetNumVertices(iface
);
964 DWORD options
= iface
->lpVtbl
->GetOptions(iface
);
965 BOOL indices_are_16_bit
= !(options
& D3DXMESH_32BIT
);
970 struct edge_face_map edge_face_map
= {0};
971 const DWORD
*point_reps_ptr
= NULL
;
972 DWORD
*id_point_reps
= NULL
;
974 TRACE("iface %p, point_reps %p, adjacency %p.\n", iface
, point_reps
, adjacency
);
976 if (!adjacency
) return D3DERR_INVALIDCALL
;
978 if (!point_reps
) /* Identity point reps */
980 id_point_reps
= generate_identity_point_reps(num_vertices
);
987 point_reps_ptr
= id_point_reps
;
991 point_reps_ptr
= point_reps
;
994 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &ib_ptr
);
995 if (FAILED(hr
)) goto cleanup
;
997 if (indices_are_16_bit
)
999 /* Widen 16 bit to 32 bit */
1001 WORD
*ib_16bit
= ib_ptr
;
1002 ib
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(DWORD
));
1008 for (i
= 0; i
< 3 * num_faces
; i
++)
1010 ib
[i
] = ib_16bit
[i
];
1018 hr
= init_edge_face_map(&edge_face_map
, ib
, point_reps_ptr
, num_faces
);
1019 if (FAILED(hr
)) goto cleanup
;
1021 /* Create adjacency */
1022 for (face
= 0; face
< num_faces
; face
++)
1024 for (edge
= 0; edge
< 3; edge
++)
1026 DWORD v1
= ib
[3*face
+ edge
];
1027 DWORD v2
= ib
[3*face
+ (edge
+1)%3];
1028 DWORD new_v1
= point_reps_ptr
[v1
];
1029 DWORD new_v2
= point_reps_ptr
[v2
];
1032 adj_face
= find_adjacent_face(&edge_face_map
, new_v1
, new_v2
, num_faces
);
1033 adjacency
[3*face
+ edge
] = adj_face
;
1039 HeapFree(GetProcessHeap(), 0, id_point_reps
);
1040 if (indices_are_16_bit
) HeapFree(GetProcessHeap(), 0, ib
);
1041 HeapFree(GetProcessHeap(), 0, edge_face_map
.lists
);
1042 HeapFree(GetProcessHeap(), 0, edge_face_map
.entries
);
1043 if(ib_ptr
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1047 /* ConvertAdjacencyToPointReps helper function.
1049 * Goes around the edges of each face and replaces the vertices in any adjacent
1050 * face's edge with its own vertices(if its vertices have a lower index). This
1051 * way as few as possible low index vertices are shared among the faces. The
1052 * re-ordered index buffer is stored in new_indices.
1054 * The vertices in a point representation must be ordered sequentially, e.g.
1055 * index 5 holds the index of the vertex that replaces vertex 5, i.e. if
1056 * vertex 5 is replaced by vertex 3 then index 5 would contain 3. If no vertex
1057 * replaces it, then it contains the same number as the index itself, e.g.
1058 * index 5 would contain 5. */
1059 static HRESULT
propagate_face_vertices(const DWORD
*adjacency
, DWORD
*point_reps
,
1060 const DWORD
*indices
, DWORD
*new_indices
, DWORD face
, DWORD numfaces
)
1062 const unsigned int VERTS_PER_FACE
= 3;
1063 DWORD edge
, opp_edge
;
1064 DWORD face_base
= VERTS_PER_FACE
* face
;
1066 for (edge
= 0; edge
< VERTS_PER_FACE
; edge
++)
1068 DWORD adj_face
= adjacency
[face_base
+ edge
];
1069 DWORD adj_face_base
;
1071 if (adj_face
== -1) /* No adjacent face. */
1073 else if (adj_face
>= numfaces
)
1075 /* This throws exception on Windows */
1076 WARN("Index out of bounds. Got %d expected less than %d.\n",
1077 adj_face
, numfaces
);
1078 return D3DERR_INVALIDCALL
;
1080 adj_face_base
= 3 * adj_face
;
1082 /* Find opposite edge in adjacent face. */
1083 for (opp_edge
= 0; opp_edge
< VERTS_PER_FACE
; opp_edge
++)
1085 DWORD opp_edge_index
= adj_face_base
+ opp_edge
;
1086 if (adjacency
[opp_edge_index
] == face
)
1087 break; /* Found opposite edge. */
1090 /* Replaces vertices in opposite edge with vertices from current edge. */
1091 for (i
= 0; i
< 2; i
++)
1093 DWORD from
= face_base
+ (edge
+ (1 - i
)) % VERTS_PER_FACE
;
1094 DWORD to
= adj_face_base
+ (opp_edge
+ i
) % VERTS_PER_FACE
;
1096 /* Propagate lowest index. */
1097 if (new_indices
[to
] > new_indices
[from
])
1099 new_indices
[to
] = new_indices
[from
];
1100 point_reps
[indices
[to
]] = new_indices
[from
];
1108 static HRESULT WINAPI
d3dx9_mesh_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
,
1109 const DWORD
*adjacency
, DWORD
*point_reps
)
1111 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1115 DWORD
*indices
= NULL
;
1116 WORD
*indices_16bit
= NULL
;
1117 DWORD
*new_indices
= NULL
;
1118 const unsigned int VERTS_PER_FACE
= 3;
1120 TRACE("iface %p, adjacency %p, point_reps %p.\n", iface
, adjacency
, point_reps
);
1124 WARN("NULL adjacency.\n");
1125 hr
= D3DERR_INVALIDCALL
;
1131 WARN("NULL point_reps.\n");
1132 hr
= D3DERR_INVALIDCALL
;
1136 /* Should never happen as CreateMesh does not allow meshes with 0 faces */
1137 if (This
->numfaces
== 0)
1139 ERR("Number of faces was zero.\n");
1140 hr
= D3DERR_INVALIDCALL
;
1144 new_indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1151 if (This
->options
& D3DXMESH_32BIT
)
1153 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1154 if (FAILED(hr
)) goto cleanup
;
1155 memcpy(new_indices
, indices
, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1159 /* Make a widening copy of indices_16bit into indices and new_indices
1160 * in order to re-use the helper function */
1161 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices_16bit
);
1162 if (FAILED(hr
)) goto cleanup
;
1163 indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1169 for (i
= 0; i
< VERTS_PER_FACE
* This
->numfaces
; i
++)
1171 new_indices
[i
] = indices_16bit
[i
];
1172 indices
[i
] = indices_16bit
[i
];
1176 /* Vertices are ordered sequentially in the point representation. */
1177 for (i
= 0; i
< This
->numvertices
; i
++)
1182 /* Propagate vertices with low indices so as few vertices as possible
1183 * are used in the mesh.
1185 for (face
= 0; face
< This
->numfaces
; face
++)
1187 hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
, face
, This
->numfaces
);
1188 if (FAILED(hr
)) goto cleanup
;
1190 /* Go in opposite direction to catch all face orderings */
1191 for (face
= 0; face
< This
->numfaces
; face
++)
1193 hr
= propagate_face_vertices(adjacency
, point_reps
,
1194 indices
, new_indices
,
1195 (This
->numfaces
- 1) - face
, This
->numfaces
);
1196 if (FAILED(hr
)) goto cleanup
;
1201 if (This
->options
& D3DXMESH_32BIT
)
1203 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1207 if (indices_16bit
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1208 HeapFree(GetProcessHeap(), 0, indices
);
1210 HeapFree(GetProcessHeap(), 0, new_indices
);
1214 struct vertex_metadata
{
1217 DWORD first_shared_index
;
1220 static int compare_vertex_keys(const void *a
, const void *b
)
1222 const struct vertex_metadata
*left
= a
;
1223 const struct vertex_metadata
*right
= b
;
1224 if (left
->key
== right
->key
)
1226 return left
->key
< right
->key
? -1 : 1;
1229 static HRESULT WINAPI
d3dx9_mesh_GenerateAdjacency(ID3DXMesh
*iface
, float epsilon
, DWORD
*adjacency
)
1231 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1233 BYTE
*vertices
= NULL
;
1234 const DWORD
*indices
= NULL
;
1237 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
1238 struct vertex_metadata
*sorted_vertices
;
1239 /* shared_indices links together identical indices in the index buffer so
1240 * that adjacency checks can be limited to faces sharing a vertex */
1241 DWORD
*shared_indices
= NULL
;
1242 const FLOAT epsilon_sq
= epsilon
* epsilon
;
1245 TRACE("iface %p, epsilon %.8e, adjacency %p.\n", iface
, epsilon
, adjacency
);
1248 return D3DERR_INVALIDCALL
;
1250 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
1251 if (!(This
->options
& D3DXMESH_32BIT
))
1252 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
1253 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
1254 if (!shared_indices
)
1255 return E_OUTOFMEMORY
;
1256 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
1258 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
1259 if (FAILED(hr
)) goto cleanup
;
1260 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1261 if (FAILED(hr
)) goto cleanup
;
1263 if (!(This
->options
& D3DXMESH_32BIT
)) {
1264 const WORD
*word_indices
= (const WORD
*)indices
;
1265 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
1266 indices
= dword_indices
;
1267 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1268 *dword_indices
++ = *word_indices
++;
1271 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1272 for (i
= 0; i
< This
->numvertices
; i
++) {
1273 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
1274 sorted_vertices
[i
].first_shared_index
= -1;
1275 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
1276 sorted_vertices
[i
].vertex_index
= i
;
1278 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
1279 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
1280 shared_indices
[i
] = *first_shared_index
;
1281 *first_shared_index
= i
;
1284 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
1286 for (i
= 0; i
< This
->numvertices
; i
++) {
1287 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
1288 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
1289 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
1291 while (shared_index_a
!= -1) {
1293 DWORD shared_index_b
= shared_indices
[shared_index_a
];
1294 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
1297 while (shared_index_b
!= -1) {
1298 /* faces are adjacent if they have another coincident vertex */
1299 DWORD base_a
= (shared_index_a
/ 3) * 3;
1300 DWORD base_b
= (shared_index_b
/ 3) * 3;
1301 BOOL adjacent
= FALSE
;
1304 for (k
= 0; k
< 3; k
++) {
1305 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
1311 for (k
= 1; k
<= 2; k
++) {
1312 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
1313 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
1314 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
1315 if (!adjacent
&& epsilon
>= 0.0f
) {
1316 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
1319 D3DXVec3Subtract(&delta
,
1320 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
1321 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
1322 length_sq
= D3DXVec3LengthSq(&delta
);
1323 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
1326 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
1327 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
1328 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
1329 adjacency
[adj_a
] = base_b
/ 3;
1330 adjacency
[adj_b
] = base_a
/ 3;
1337 shared_index_b
= shared_indices
[shared_index_b
];
1339 while (++j
< This
->numvertices
) {
1340 D3DXVECTOR3
*vertex_b
;
1343 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
1344 /* no more coincident vertices to try */
1345 j
= This
->numvertices
;
1348 /* check for coincidence */
1349 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
1350 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
1351 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
1352 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
1357 if (j
>= This
->numvertices
)
1359 shared_index_b
= sorted_vertex_b
->first_shared_index
;
1362 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
1363 shared_index_a
= sorted_vertex_a
->first_shared_index
;
1369 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1370 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
1371 HeapFree(GetProcessHeap(), 0, shared_indices
);
1375 static HRESULT WINAPI
d3dx9_mesh_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1377 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1379 UINT vertex_declaration_size
;
1382 TRACE("iface %p, declaration %p.\n", iface
, declaration
);
1386 WARN("Invalid declaration. Can't use NULL declaration.\n");
1387 return D3DERR_INVALIDCALL
;
1390 /* New declaration must be same size as original */
1391 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
1392 if (vertex_declaration_size
!= This
->vertex_declaration_size
)
1394 WARN("Invalid declaration. New vertex size does not match the original vertex size.\n");
1395 return D3DERR_INVALIDCALL
;
1398 /* New declaration must not contain non-zero Stream value */
1399 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1401 if (declaration
[i
].Stream
!= 0)
1403 WARN("Invalid declaration. New declaration contains non-zero Stream value.\n");
1404 return D3DERR_INVALIDCALL
;
1408 This
->num_elem
= i
+ 1;
1409 copy_declaration(This
->cached_declaration
, declaration
, This
->num_elem
);
1411 if (This
->vertex_declaration
)
1412 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
1414 /* An application can pass an invalid declaration to UpdateSemantics and
1415 * still expect D3D_OK (see tests). If the declaration is invalid, then
1416 * subsequent calls to DrawSubset will fail. This is handled by setting the
1417 * vertex declaration to NULL.
1418 * GetDeclaration, GetNumBytesPerVertex must, however, use the new
1419 * invalid declaration. This is handled by them using the cached vertex
1420 * declaration instead of the actual vertex declaration.
1422 hr
= IDirect3DDevice9_CreateVertexDeclaration(This
->device
,
1424 &This
->vertex_declaration
);
1427 WARN("Using invalid declaration. Calls to DrawSubset will fail.\n");
1428 This
->vertex_declaration
= NULL
;
1434 static HRESULT WINAPI
d3dx9_mesh_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
1436 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1438 TRACE("iface %p, flags %#x, data %p.\n", iface
, flags
, data
);
1440 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1442 if (!(flags
& D3DLOCK_READONLY
))
1444 D3DXATTRIBUTERANGE
*attrib_table
= mesh
->attrib_table
;
1445 mesh
->attrib_table_size
= 0;
1446 mesh
->attrib_table
= NULL
;
1447 HeapFree(GetProcessHeap(), 0, attrib_table
);
1450 *data
= mesh
->attrib_buffer
;
1455 static HRESULT WINAPI
d3dx9_mesh_UnlockAttributeBuffer(ID3DXMesh
*iface
)
1457 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1460 TRACE("iface %p.\n", iface
);
1462 lock_count
= InterlockedDecrement(&mesh
->attrib_buffer_lock_count
);
1465 InterlockedIncrement(&mesh
->attrib_buffer_lock_count
);
1466 return D3DERR_INVALIDCALL
;
1472 static HRESULT WINAPI
d3dx9_mesh_Optimize(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1473 DWORD
*adjacency_out
, DWORD
*face_remap
, ID3DXBuffer
**vertex_remap
, ID3DXMesh
**opt_mesh
)
1475 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1477 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
1478 ID3DXMesh
*optimized_mesh
;
1480 TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap %p, vertex_remap %p, opt_mesh %p.\n",
1481 iface
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
1484 return D3DERR_INVALIDCALL
;
1486 hr
= iface
->lpVtbl
->GetDeclaration(iface
, declaration
);
1487 if (FAILED(hr
)) return hr
;
1489 if (FAILED(hr
= iface
->lpVtbl
->CloneMesh(iface
, mesh
->options
, declaration
, mesh
->device
, &optimized_mesh
)))
1492 hr
= optimized_mesh
->lpVtbl
->OptimizeInplace(optimized_mesh
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
);
1494 *opt_mesh
= optimized_mesh
;
1496 IUnknown_Release(optimized_mesh
);
1500 /* Creates a vertex_remap that removes unused vertices.
1501 * Indices are updated according to the vertex_remap. */
1502 static HRESULT
compact_mesh(struct d3dx9_mesh
*This
, DWORD
*indices
,
1503 DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
1506 DWORD
*vertex_remap_ptr
;
1507 DWORD num_used_vertices
;
1510 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
1511 if (FAILED(hr
)) return hr
;
1512 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
1514 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1515 vertex_remap_ptr
[indices
[i
]] = 1;
1517 /* create old->new vertex mapping */
1518 num_used_vertices
= 0;
1519 for (i
= 0; i
< This
->numvertices
; i
++) {
1520 if (vertex_remap_ptr
[i
])
1521 vertex_remap_ptr
[i
] = num_used_vertices
++;
1523 vertex_remap_ptr
[i
] = -1;
1525 /* convert indices */
1526 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1527 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
1529 /* create new->old vertex mapping */
1530 num_used_vertices
= 0;
1531 for (i
= 0; i
< This
->numvertices
; i
++) {
1532 if (vertex_remap_ptr
[i
] != -1)
1533 vertex_remap_ptr
[num_used_vertices
++] = i
;
1535 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
1536 vertex_remap_ptr
[i
] = -1;
1538 *new_num_vertices
= num_used_vertices
;
1543 /* count the number of unique attribute values in a sorted attribute buffer */
1544 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
1546 DWORD last_attribute
= attrib_buffer
[0];
1547 DWORD attrib_table_size
= 1;
1549 for (i
= 1; i
< numfaces
; i
++) {
1550 if (attrib_buffer
[i
] != last_attribute
) {
1551 last_attribute
= attrib_buffer
[i
];
1552 attrib_table_size
++;
1555 return attrib_table_size
;
1558 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
1559 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
1561 DWORD attrib_table_size
= 0;
1562 DWORD last_attribute
= attrib_buffer
[0];
1563 DWORD min_vertex
, max_vertex
;
1566 attrib_table
[0].AttribId
= last_attribute
;
1567 attrib_table
[0].FaceStart
= 0;
1568 min_vertex
= (DWORD
)-1;
1570 for (i
= 0; i
< numfaces
; i
++) {
1573 if (attrib_buffer
[i
] != last_attribute
) {
1574 last_attribute
= attrib_buffer
[i
];
1575 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1576 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1577 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1578 attrib_table_size
++;
1579 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
1580 attrib_table
[attrib_table_size
].FaceStart
= i
;
1581 min_vertex
= (DWORD
)-1;
1584 for (j
= 0; j
< 3; j
++) {
1585 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
1586 if (vertex_index
< min_vertex
)
1587 min_vertex
= vertex_index
;
1588 if (vertex_index
> max_vertex
)
1589 max_vertex
= vertex_index
;
1592 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1593 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1594 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1595 attrib_table_size
++;
1598 static int attrib_entry_compare(const DWORD
**a
, const DWORD
**b
)
1600 const DWORD
*ptr_a
= *a
;
1601 const DWORD
*ptr_b
= *b
;
1602 int delta
= *ptr_a
- *ptr_b
;
1607 delta
= ptr_a
- ptr_b
; /* for stable sort */
1611 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
1612 static HRESULT
remap_faces_for_attrsort(struct d3dx9_mesh
*This
, const DWORD
*indices
,
1613 DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
1615 DWORD
**sorted_attrib_ptr_buffer
= NULL
;
1618 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
1619 if (!sorted_attrib_ptr_buffer
)
1620 return E_OUTOFMEMORY
;
1622 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
1625 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
1626 return E_OUTOFMEMORY
;
1629 for (i
= 0; i
< This
->numfaces
; i
++)
1630 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
1631 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
),
1632 (int(*)(const void *, const void *))attrib_entry_compare
);
1634 for (i
= 0; i
< This
->numfaces
; i
++)
1636 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
1637 (*face_remap
)[old_face
] = i
;
1640 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
1641 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
1642 for (i
= 0; i
< This
->numfaces
; i
++)
1643 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
1648 static HRESULT WINAPI
d3dx9_mesh_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1649 DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
1651 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(iface
);
1652 void *indices
= NULL
;
1653 DWORD
*attrib_buffer
= NULL
;
1655 ID3DXBuffer
*vertex_remap
= NULL
;
1656 DWORD
*face_remap
= NULL
; /* old -> new mapping */
1657 DWORD
*dword_indices
= NULL
;
1658 DWORD new_num_vertices
= 0;
1659 DWORD new_num_alloc_vertices
= 0;
1660 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
1661 DWORD
*sorted_attrib_buffer
= NULL
;
1664 TRACE("iface %p, flags %#x, adjacency_in %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
1665 iface
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
1668 return D3DERR_INVALIDCALL
;
1669 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
1670 return D3DERR_INVALIDCALL
;
1671 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1672 return D3DERR_INVALIDCALL
;
1674 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1676 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
1677 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
1678 if (flags
& D3DXMESHOPT_STRIPREORDER
)
1679 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
1683 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, &indices
);
1684 if (FAILED(hr
)) goto cleanup
;
1686 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
1687 if (!dword_indices
) return E_OUTOFMEMORY
;
1688 if (This
->options
& D3DXMESH_32BIT
) {
1689 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1691 WORD
*word_indices
= indices
;
1692 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1693 dword_indices
[i
] = *word_indices
++;
1696 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
1698 new_num_alloc_vertices
= This
->numvertices
;
1699 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
1700 if (FAILED(hr
)) goto cleanup
;
1701 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
1702 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
1704 FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
1709 hr
= iface
->lpVtbl
->LockAttributeBuffer(iface
, 0, &attrib_buffer
);
1710 if (FAILED(hr
)) goto cleanup
;
1712 hr
= remap_faces_for_attrsort(This
, dword_indices
, attrib_buffer
, &sorted_attrib_buffer
, &face_remap
);
1713 if (FAILED(hr
)) goto cleanup
;
1718 /* reorder the vertices using vertex_remap */
1719 D3DVERTEXBUFFER_DESC vertex_desc
;
1720 DWORD
*vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1721 DWORD vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1722 BYTE
*orig_vertices
;
1725 hr
= IDirect3DVertexBuffer9_GetDesc(This
->vertex_buffer
, &vertex_desc
);
1726 if (FAILED(hr
)) goto cleanup
;
1728 hr
= IDirect3DDevice9_CreateVertexBuffer(This
->device
, new_num_alloc_vertices
* vertex_size
,
1729 vertex_desc
.Usage
, This
->fvf
, vertex_desc
.Pool
, &vertex_buffer
, NULL
);
1730 if (FAILED(hr
)) goto cleanup
;
1732 hr
= IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, (void**)&orig_vertices
, D3DLOCK_READONLY
);
1733 if (FAILED(hr
)) goto cleanup
;
1735 hr
= IDirect3DVertexBuffer9_Lock(vertex_buffer
, 0, 0, (void**)&new_vertices
, 0);
1737 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1741 for (i
= 0; i
< new_num_vertices
; i
++)
1742 memcpy(new_vertices
+ i
* vertex_size
, orig_vertices
+ vertex_remap_ptr
[i
] * vertex_size
, vertex_size
);
1744 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1745 IDirect3DVertexBuffer9_Unlock(vertex_buffer
);
1746 } else if (vertex_remap_out
) {
1747 DWORD
*vertex_remap_ptr
;
1749 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), &vertex_remap
);
1750 if (FAILED(hr
)) goto cleanup
;
1751 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1752 for (i
= 0; i
< This
->numvertices
; i
++)
1753 *vertex_remap_ptr
++ = i
;
1756 if (flags
& D3DXMESHOPT_ATTRSORT
)
1758 D3DXATTRIBUTERANGE
*attrib_table
;
1759 DWORD attrib_table_size
;
1761 attrib_table_size
= count_attributes(sorted_attrib_buffer
, This
->numfaces
);
1762 attrib_table
= HeapAlloc(GetProcessHeap(), 0, attrib_table_size
* sizeof(*attrib_table
));
1763 if (!attrib_table
) {
1768 memcpy(attrib_buffer
, sorted_attrib_buffer
, This
->numfaces
* sizeof(*attrib_buffer
));
1770 /* reorder the indices using face_remap */
1771 if (This
->options
& D3DXMESH_32BIT
) {
1772 for (i
= 0; i
< This
->numfaces
; i
++)
1773 memcpy((DWORD
*)indices
+ face_remap
[i
] * 3, dword_indices
+ i
* 3, 3 * sizeof(DWORD
));
1775 WORD
*word_indices
= indices
;
1776 for (i
= 0; i
< This
->numfaces
; i
++) {
1777 DWORD new_pos
= face_remap
[i
] * 3;
1778 DWORD old_pos
= i
* 3;
1779 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1780 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1781 word_indices
[new_pos
] = dword_indices
[old_pos
];
1785 fill_attribute_table(attrib_buffer
, This
->numfaces
, indices
,
1786 This
->options
& D3DXMESH_32BIT
, attrib_table
);
1788 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1789 This
->attrib_table
= attrib_table
;
1790 This
->attrib_table_size
= attrib_table_size
;
1792 if (This
->options
& D3DXMESH_32BIT
) {
1793 memcpy(indices
, dword_indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1795 WORD
*word_indices
= indices
;
1796 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1797 *word_indices
++ = dword_indices
[i
];
1801 if (adjacency_out
) {
1803 for (i
= 0; i
< This
->numfaces
; i
++) {
1804 DWORD old_pos
= i
* 3;
1805 DWORD new_pos
= face_remap
[i
] * 3;
1806 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1807 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1808 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1811 memcpy(adjacency_out
, adjacency_in
, This
->numfaces
* 3 * sizeof(*adjacency_out
));
1814 if (face_remap_out
) {
1816 for (i
= 0; i
< This
->numfaces
; i
++)
1817 face_remap_out
[face_remap
[i
]] = i
;
1819 for (i
= 0; i
< This
->numfaces
; i
++)
1820 face_remap_out
[i
] = i
;
1823 if (vertex_remap_out
)
1824 *vertex_remap_out
= vertex_remap
;
1825 vertex_remap
= NULL
;
1827 if (vertex_buffer
) {
1828 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
1829 This
->vertex_buffer
= vertex_buffer
;
1830 vertex_buffer
= NULL
;
1831 This
->numvertices
= new_num_vertices
;
1836 HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer
);
1837 HeapFree(GetProcessHeap(), 0, face_remap
);
1838 HeapFree(GetProcessHeap(), 0, dword_indices
);
1839 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
1840 if (vertex_buffer
) IDirect3DVertexBuffer9_Release(vertex_buffer
);
1841 if (attrib_buffer
) iface
->lpVtbl
->UnlockAttributeBuffer(iface
);
1842 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1846 static HRESULT WINAPI
d3dx9_mesh_SetAttributeTable(ID3DXMesh
*iface
,
1847 const D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
1849 struct d3dx9_mesh
*mesh
= impl_from_ID3DXMesh(iface
);
1850 D3DXATTRIBUTERANGE
*new_table
= NULL
;
1852 TRACE("iface %p, attrib_table %p, attrib_table_size %u.\n", iface
, attrib_table
, attrib_table_size
);
1854 if (attrib_table_size
) {
1855 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
1857 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
1859 return E_OUTOFMEMORY
;
1861 CopyMemory(new_table
, attrib_table
, size
);
1862 } else if (attrib_table
) {
1863 return D3DERR_INVALIDCALL
;
1865 HeapFree(GetProcessHeap(), 0, mesh
->attrib_table
);
1866 mesh
->attrib_table
= new_table
;
1867 mesh
->attrib_table_size
= attrib_table_size
;
1872 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
1874 d3dx9_mesh_QueryInterface
,
1877 d3dx9_mesh_DrawSubset
,
1878 d3dx9_mesh_GetNumFaces
,
1879 d3dx9_mesh_GetNumVertices
,
1881 d3dx9_mesh_GetDeclaration
,
1882 d3dx9_mesh_GetNumBytesPerVertex
,
1883 d3dx9_mesh_GetOptions
,
1884 d3dx9_mesh_GetDevice
,
1885 d3dx9_mesh_CloneMeshFVF
,
1886 d3dx9_mesh_CloneMesh
,
1887 d3dx9_mesh_GetVertexBuffer
,
1888 d3dx9_mesh_GetIndexBuffer
,
1889 d3dx9_mesh_LockVertexBuffer
,
1890 d3dx9_mesh_UnlockVertexBuffer
,
1891 d3dx9_mesh_LockIndexBuffer
,
1892 d3dx9_mesh_UnlockIndexBuffer
,
1893 d3dx9_mesh_GetAttributeTable
,
1894 d3dx9_mesh_ConvertPointRepsToAdjacency
,
1895 d3dx9_mesh_ConvertAdjacencyToPointReps
,
1896 d3dx9_mesh_GenerateAdjacency
,
1897 d3dx9_mesh_UpdateSemantics
,
1898 d3dx9_mesh_LockAttributeBuffer
,
1899 d3dx9_mesh_UnlockAttributeBuffer
,
1900 d3dx9_mesh_Optimize
,
1901 d3dx9_mesh_OptimizeInplace
,
1902 d3dx9_mesh_SetAttributeTable
,
1906 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algorithm
1907 Amy Williams University of Utah
1908 Steve Barrus University of Utah
1909 R. Keith Morley University of Utah
1910 Peter Shirley University of Utah
1912 International Conference on Computer Graphics and Interactive Techniques archive
1913 ACM SIGGRAPH 2005 Courses
1914 Los Angeles, California
1916 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1918 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1919 against each slab, if there's anything left of the ray after we're
1920 done we've got an intersection of the ray with the box. */
1921 BOOL WINAPI
D3DXBoxBoundProbe(const D3DXVECTOR3
*pmin
, const D3DXVECTOR3
*pmax
,
1922 const D3DXVECTOR3
*prayposition
, const D3DXVECTOR3
*praydirection
)
1924 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
1926 div
= 1.0f
/ praydirection
->x
;
1929 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
1930 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
1934 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
1935 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
1938 if ( tmax
< 0.0f
) return FALSE
;
1940 div
= 1.0f
/ praydirection
->y
;
1943 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
1944 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
1948 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
1949 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
1952 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
1954 if ( tymin
> tmin
) tmin
= tymin
;
1955 if ( tymax
< tmax
) tmax
= tymax
;
1957 div
= 1.0f
/ praydirection
->z
;
1960 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
1961 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
1965 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
1966 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
1969 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
1974 HRESULT WINAPI
D3DXComputeBoundingBox(const D3DXVECTOR3
*pfirstposition
,
1975 DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
1980 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
1982 *pmin
= *pfirstposition
;
1985 for(i
=0; i
<numvertices
; i
++)
1987 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
1989 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
1990 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
1992 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
1993 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
1995 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
1996 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
2002 HRESULT WINAPI
D3DXComputeBoundingSphere(const D3DXVECTOR3
*pfirstposition
,
2003 DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, float *pradius
)
2009 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
2016 for(i
=0; i
<numvertices
; i
++)
2017 D3DXVec3Add(&temp
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
2019 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/ numvertices
);
2021 for(i
=0; i
<numvertices
; i
++)
2023 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
2024 if ( d
> *pradius
) *pradius
= d
;
2029 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
2030 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
2032 declaration
[*idx
].Stream
= 0;
2033 declaration
[*idx
].Offset
= *offset
;
2034 declaration
[*idx
].Type
= type
;
2035 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
2036 declaration
[*idx
].Usage
= usage
;
2037 declaration
[*idx
].UsageIndex
= usage_idx
;
2039 *offset
+= d3dx_decltype_size
[type
];
2043 /*************************************************************************
2044 * D3DXDeclaratorFromFVF
2046 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
2048 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
2049 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2050 unsigned int offset
= 0;
2051 unsigned int idx
= 0;
2054 TRACE("fvf %#x, declaration %p.\n", fvf
, declaration
);
2056 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
2058 if (fvf
& D3DFVF_POSITION_MASK
)
2060 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
2061 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
2062 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
2064 if (has_blend_idx
) --blend_count
;
2066 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
2067 || (has_blend
&& blend_count
> 4))
2068 return D3DERR_INVALIDCALL
;
2070 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
2071 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
2073 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
2077 switch (blend_count
)
2082 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2085 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2088 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2091 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2094 ERR("Invalid blend count %u.\n", blend_count
);
2100 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
2101 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
2102 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
2103 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
2108 if (fvf
& D3DFVF_NORMAL
)
2109 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
2110 if (fvf
& D3DFVF_PSIZE
)
2111 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
2112 if (fvf
& D3DFVF_DIFFUSE
)
2113 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
2114 if (fvf
& D3DFVF_SPECULAR
)
2115 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
2117 for (i
= 0; i
< tex_count
; ++i
)
2119 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
2121 case D3DFVF_TEXTUREFORMAT1
:
2122 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
2124 case D3DFVF_TEXTUREFORMAT2
:
2125 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
2127 case D3DFVF_TEXTUREFORMAT3
:
2128 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
2130 case D3DFVF_TEXTUREFORMAT4
:
2131 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
2136 declaration
[idx
] = end_element
;
2141 /*************************************************************************
2142 * D3DXFVFFromDeclarator
2144 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
2146 unsigned int i
= 0, texture
, offset
;
2148 TRACE("(%p, %p)\n", declaration
, fvf
);
2151 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
2153 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2154 declaration
[1].UsageIndex
== 0) &&
2155 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
2156 declaration
[2].UsageIndex
== 0))
2158 return D3DERR_INVALIDCALL
;
2160 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2161 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
2163 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
2165 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
2169 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
2173 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2174 declaration
[1].UsageIndex
== 0)
2176 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2177 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
2179 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
2181 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
2185 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
2187 switch (declaration
[1].Type
)
2189 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
2190 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
2191 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
2192 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
2198 switch (declaration
[1].Type
)
2200 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
2201 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
2202 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
2203 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
2214 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
2215 declaration
[0].UsageIndex
== 0)
2217 *fvf
|= D3DFVF_XYZRHW
;
2221 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
2223 *fvf
|= D3DFVF_NORMAL
;
2226 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
2227 declaration
[i
].UsageIndex
== 0)
2229 *fvf
|= D3DFVF_PSIZE
;
2232 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2233 declaration
[i
].UsageIndex
== 0)
2235 *fvf
|= D3DFVF_DIFFUSE
;
2238 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2239 declaration
[i
].UsageIndex
== 1)
2241 *fvf
|= D3DFVF_SPECULAR
;
2245 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
2247 if (declaration
[i
].Stream
== 0xFF)
2251 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2252 declaration
[i
].UsageIndex
== texture
)
2254 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
2256 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2257 declaration
[i
].UsageIndex
== texture
)
2259 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
2261 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2262 declaration
[i
].UsageIndex
== texture
)
2264 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
2266 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2267 declaration
[i
].UsageIndex
== texture
)
2269 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
2273 return D3DERR_INVALIDCALL
;
2277 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
2279 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
2280 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
2282 if (declaration
[i
].Offset
!= offset
)
2284 return D3DERR_INVALIDCALL
;
2291 /*************************************************************************
2292 * D3DXGetFVFVertexSize
2294 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
2296 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
2299 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
2303 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2305 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
2306 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
2307 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
2308 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
2310 switch (FVF
& D3DFVF_POSITION_MASK
)
2312 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
2313 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
2314 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
2315 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
2316 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
2317 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
2318 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
2319 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
2322 for (i
= 0; i
< numTextures
; i
++)
2324 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
2330 /*************************************************************************
2331 * D3DXGetDeclVertexSize
2333 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
2335 const D3DVERTEXELEMENT9
*element
;
2338 TRACE("decl %p, stream_idx %u\n", decl
, stream_idx
);
2340 if (!decl
) return 0;
2342 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
2346 if (element
->Stream
!= stream_idx
) continue;
2348 if (element
->Type
>= sizeof(d3dx_decltype_size
) / sizeof(*d3dx_decltype_size
))
2350 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
2354 type_size
= d3dx_decltype_size
[element
->Type
];
2355 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
2361 /*************************************************************************
2364 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
2366 const D3DVERTEXELEMENT9
*element
;
2368 TRACE("decl %p\n", decl
);
2370 /* null decl results in exception on Windows XP */
2372 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
2374 return element
- decl
;
2377 BOOL WINAPI
D3DXIntersectTri(const D3DXVECTOR3
*p0
, const D3DXVECTOR3
*p1
, const D3DXVECTOR3
*p2
,
2378 const D3DXVECTOR3
*praypos
, const D3DXVECTOR3
*praydir
, float *pu
, float *pv
, float *pdist
)
2383 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
2384 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
2385 m
.u
.m
[2][0] = -praydir
->x
;
2387 m
.u
.m
[0][1] = p1
->y
- p0
->z
;
2388 m
.u
.m
[1][1] = p2
->y
- p0
->z
;
2389 m
.u
.m
[2][1] = -praydir
->y
;
2391 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
2392 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
2393 m
.u
.m
[2][2] = -praydir
->z
;
2400 vec
.x
= praypos
->x
- p0
->x
;
2401 vec
.y
= praypos
->y
- p0
->y
;
2402 vec
.z
= praypos
->z
- p0
->z
;
2405 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
2407 D3DXVec4Transform(&vec
, &vec
, &m
);
2408 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
2410 if (pu
) *pu
= vec
.x
;
2411 if (pv
) *pv
= vec
.y
;
2412 if (pdist
) *pdist
= fabsf( vec
.z
);
2420 BOOL WINAPI
D3DXSphereBoundProbe(const D3DXVECTOR3
*pcenter
, float radius
,
2421 const D3DXVECTOR3
*prayposition
, const D3DXVECTOR3
*praydirection
)
2423 D3DXVECTOR3 difference
;
2426 a
= D3DXVec3LengthSq(praydirection
);
2427 if (!D3DXVec3Subtract(&difference
, prayposition
, pcenter
)) return FALSE
;
2428 b
= D3DXVec3Dot(&difference
, praydirection
);
2429 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
2432 if ( ( d
<= 0.0f
) || ( sqrt(d
) <= b
) ) return FALSE
;
2436 /*************************************************************************
2439 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2440 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2444 IDirect3DVertexDeclaration9
*vertex_declaration
;
2445 UINT vertex_declaration_size
;
2447 IDirect3DVertexBuffer9
*vertex_buffer
;
2448 IDirect3DIndexBuffer9
*index_buffer
;
2449 DWORD
*attrib_buffer
;
2450 struct d3dx9_mesh
*object
;
2451 DWORD index_usage
= 0;
2452 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
2453 D3DFORMAT index_format
= D3DFMT_INDEX16
;
2454 DWORD vertex_usage
= 0;
2455 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
2458 TRACE("numfaces %u, numvertices %u, options %#x, declaration %p, device %p, mesh %p.\n",
2459 numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2461 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
2462 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
2463 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
2465 return D3DERR_INVALIDCALL
;
2467 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
2468 if (declaration
[i
].Stream
!= 0)
2469 return D3DERR_INVALIDCALL
;
2472 if (options
& D3DXMESH_32BIT
)
2473 index_format
= D3DFMT_INDEX32
;
2475 if (options
& D3DXMESH_DONOTCLIP
) {
2476 index_usage
|= D3DUSAGE_DONOTCLIP
;
2477 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
2479 if (options
& D3DXMESH_POINTS
) {
2480 index_usage
|= D3DUSAGE_POINTS
;
2481 vertex_usage
|= D3DUSAGE_POINTS
;
2483 if (options
& D3DXMESH_RTPATCHES
) {
2484 index_usage
|= D3DUSAGE_RTPATCHES
;
2485 vertex_usage
|= D3DUSAGE_RTPATCHES
;
2487 if (options
& D3DXMESH_NPATCHES
) {
2488 index_usage
|= D3DUSAGE_NPATCHES
;
2489 vertex_usage
|= D3DUSAGE_NPATCHES
;
2492 if (options
& D3DXMESH_VB_SYSTEMMEM
)
2493 vertex_pool
= D3DPOOL_SYSTEMMEM
;
2494 else if (options
& D3DXMESH_VB_MANAGED
)
2495 vertex_pool
= D3DPOOL_MANAGED
;
2497 if (options
& D3DXMESH_VB_WRITEONLY
)
2498 vertex_usage
|= D3DUSAGE_WRITEONLY
;
2499 if (options
& D3DXMESH_VB_DYNAMIC
)
2500 vertex_usage
|= D3DUSAGE_DYNAMIC
;
2501 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
2502 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2504 if (options
& D3DXMESH_IB_SYSTEMMEM
)
2505 index_pool
= D3DPOOL_SYSTEMMEM
;
2506 else if (options
& D3DXMESH_IB_MANAGED
)
2507 index_pool
= D3DPOOL_MANAGED
;
2509 if (options
& D3DXMESH_IB_WRITEONLY
)
2510 index_usage
|= D3DUSAGE_WRITEONLY
;
2511 if (options
& D3DXMESH_IB_DYNAMIC
)
2512 index_usage
|= D3DUSAGE_DYNAMIC
;
2513 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
2514 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2516 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
2522 /* Create vertex declaration */
2523 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
2525 &vertex_declaration
);
2528 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
2531 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
2533 /* Create vertex buffer */
2534 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
2535 numvertices
* vertex_declaration_size
,
2543 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2544 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2548 /* Create index buffer */
2549 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
2550 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
2558 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2559 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2560 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2564 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
2565 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2566 if (object
== NULL
|| attrib_buffer
== NULL
)
2568 HeapFree(GetProcessHeap(), 0, object
);
2569 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
2570 IDirect3DIndexBuffer9_Release(index_buffer
);
2571 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2572 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2574 return E_OUTOFMEMORY
;
2576 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
2579 object
->numfaces
= numfaces
;
2580 object
->numvertices
= numvertices
;
2581 object
->options
= options
;
2583 object
->device
= device
;
2584 IDirect3DDevice9_AddRef(device
);
2586 copy_declaration(object
->cached_declaration
, declaration
, num_elem
);
2587 object
->vertex_declaration
= vertex_declaration
;
2588 object
->vertex_declaration_size
= vertex_declaration_size
;
2589 object
->num_elem
= num_elem
;
2590 object
->vertex_buffer
= vertex_buffer
;
2591 object
->index_buffer
= index_buffer
;
2592 object
->attrib_buffer
= attrib_buffer
;
2594 *mesh
= &object
->ID3DXMesh_iface
;
2599 /*************************************************************************
2602 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2603 DWORD fvf
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2606 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
2608 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
2610 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
2611 if (FAILED(hr
)) return hr
;
2613 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2619 DWORD num_poly_faces
;
2620 DWORD num_tri_faces
;
2621 D3DXVECTOR3
*vertices
;
2622 DWORD
*num_tri_per_face
;
2627 /* optional mesh data */
2630 D3DXVECTOR3
*normals
;
2631 DWORD
*normal_indices
;
2633 D3DXVECTOR2
*tex_coords
;
2635 DWORD
*vertex_colors
;
2637 DWORD num_materials
;
2638 D3DXMATERIAL
*materials
;
2639 DWORD
*material_indices
;
2641 struct ID3DXSkinInfo
*skin_info
;
2645 static HRESULT
parse_texture_filename(ID3DXFileData
*filedata
, char **filename_out
)
2651 char *filename
= NULL
;
2653 /* template TextureFilename {
2658 HeapFree(GetProcessHeap(), 0, *filename_out
);
2659 *filename_out
= NULL
;
2661 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2662 if (FAILED(hr
)) return hr
;
2664 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
2665 if (data_size
< sizeof(filename_in
))
2667 WARN("truncated data (%lu bytes)\n", data_size
);
2668 filedata
->lpVtbl
->Unlock(filedata
);
2671 filename_in
= *(char **)data
;
2673 filename
= HeapAlloc(GetProcessHeap(), 0, strlen(filename_in
) + 1);
2675 filedata
->lpVtbl
->Unlock(filedata
);
2676 return E_OUTOFMEMORY
;
2679 strcpy(filename
, filename_in
);
2680 *filename_out
= filename
;
2682 filedata
->lpVtbl
->Unlock(filedata
);
2687 static HRESULT
parse_material(ID3DXFileData
*filedata
, D3DXMATERIAL
*material
)
2693 ID3DXFileData
*child
;
2694 SIZE_T i
, nb_children
;
2696 material
->pTextureFilename
= NULL
;
2698 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2699 if (FAILED(hr
)) return hr
;
2702 * template ColorRGBA {
2708 * template ColorRGB {
2713 * template Material {
2714 * ColorRGBA faceColor;
2716 * ColorRGB specularColor;
2717 * ColorRGB emissiveColor;
2721 if (data_size
!= sizeof(FLOAT
) * 11) {
2722 WARN("incorrect data size (%ld bytes)\n", data_size
);
2723 filedata
->lpVtbl
->Unlock(filedata
);
2727 memcpy(&material
->MatD3D
.Diffuse
, data
, sizeof(D3DCOLORVALUE
));
2728 data
+= sizeof(D3DCOLORVALUE
);
2729 material
->MatD3D
.Power
= *(FLOAT
*)data
;
2730 data
+= sizeof(FLOAT
);
2731 memcpy(&material
->MatD3D
.Specular
, data
, sizeof(FLOAT
) * 3);
2732 material
->MatD3D
.Specular
.a
= 1.0f
;
2733 data
+= 3 * sizeof(FLOAT
);
2734 memcpy(&material
->MatD3D
.Emissive
, data
, sizeof(FLOAT
) * 3);
2735 material
->MatD3D
.Emissive
.a
= 1.0f
;
2736 material
->MatD3D
.Ambient
.r
= 0.0f
;
2737 material
->MatD3D
.Ambient
.g
= 0.0f
;
2738 material
->MatD3D
.Ambient
.b
= 0.0f
;
2739 material
->MatD3D
.Ambient
.a
= 1.0f
;
2741 filedata
->lpVtbl
->Unlock(filedata
);
2743 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2747 for (i
= 0; i
< nb_children
; i
++)
2749 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2752 hr
= child
->lpVtbl
->GetType(child
, &type
);
2756 if (IsEqualGUID(&type
, &TID_D3DRMTextureFilename
)) {
2757 hr
= parse_texture_filename(child
, &material
->pTextureFilename
);
2761 IUnknown_Release(child
);
2766 IUnknown_Release(child
);
2770 static void destroy_materials(struct mesh_data
*mesh
)
2773 for (i
= 0; i
< mesh
->num_materials
; i
++)
2774 HeapFree(GetProcessHeap(), 0, mesh
->materials
[i
].pTextureFilename
);
2775 HeapFree(GetProcessHeap(), 0, mesh
->materials
);
2776 HeapFree(GetProcessHeap(), 0, mesh
->material_indices
);
2777 mesh
->num_materials
= 0;
2778 mesh
->materials
= NULL
;
2779 mesh
->material_indices
= NULL
;
2782 static HRESULT
parse_material_list(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2786 const DWORD
*data
, *in_ptr
;
2788 ID3DXFileData
*child
= NULL
;
2789 DWORD num_materials
;
2793 destroy_materials(mesh
);
2795 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2796 if (FAILED(hr
)) return hr
;
2798 /* template MeshMaterialList {
2800 * DWORD nFaceIndexes;
2801 * array DWORD faceIndexes[nFaceIndexes];
2809 if (data_size
< sizeof(DWORD
)) {
2810 WARN("truncated data (%ld bytes)\n", data_size
);
2813 num_materials
= *in_ptr
++;
2814 if (!num_materials
) {
2819 if (data_size
< 2 * sizeof(DWORD
)) {
2820 WARN("truncated data (%ld bytes)\n", data_size
);
2823 if (*in_ptr
++ != mesh
->num_poly_faces
) {
2824 WARN("number of material face indices (%u) doesn't match number of faces (%u)\n",
2825 *(in_ptr
- 1), mesh
->num_poly_faces
);
2828 if (data_size
< 2 * sizeof(DWORD
) + mesh
->num_poly_faces
* sizeof(DWORD
)) {
2829 WARN("truncated data (%ld bytes)\n", data_size
);
2832 for (i
= 0; i
< mesh
->num_poly_faces
; i
++) {
2833 if (*in_ptr
++ >= num_materials
) {
2834 WARN("face %u: reference to undefined material %u (only %u materials)\n",
2835 i
, *(in_ptr
- 1), num_materials
);
2840 mesh
->materials
= HeapAlloc(GetProcessHeap(), 0, num_materials
* sizeof(*mesh
->materials
));
2841 mesh
->material_indices
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_poly_faces
* sizeof(*mesh
->material_indices
));
2842 if (!mesh
->materials
|| !mesh
->material_indices
) {
2846 memcpy(mesh
->material_indices
, data
+ 2, mesh
->num_poly_faces
* sizeof(DWORD
));
2848 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2852 for (i
= 0; i
< nb_children
; i
++)
2854 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2857 hr
= child
->lpVtbl
->GetType(child
, &type
);
2861 if (IsEqualGUID(&type
, &TID_D3DRMMaterial
)) {
2862 if (mesh
->num_materials
>= num_materials
) {
2863 WARN("more materials defined than declared\n");
2867 hr
= parse_material(child
, &mesh
->materials
[mesh
->num_materials
++]);
2872 IUnknown_Release(child
);
2875 if (num_materials
!= mesh
->num_materials
) {
2876 WARN("only %u of %u materials defined\n", num_materials
, mesh
->num_materials
);
2882 IUnknown_Release(child
);
2883 filedata
->lpVtbl
->Unlock(filedata
);
2887 static HRESULT
parse_texture_coords(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2893 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2894 mesh
->tex_coords
= NULL
;
2896 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2897 if (FAILED(hr
)) return hr
;
2899 /* template Coords2d {
2903 * template MeshTextureCoords {
2904 * DWORD nTextureCoords;
2905 * array Coords2d textureCoords[nTextureCoords];
2911 if (data_size
< sizeof(DWORD
)) {
2912 WARN("truncated data (%ld bytes)\n", data_size
);
2915 if (*(DWORD
*)data
!= mesh
->num_vertices
) {
2916 WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2917 *(DWORD
*)data
, mesh
->num_vertices
);
2920 data
+= sizeof(DWORD
);
2921 if (data_size
< sizeof(DWORD
) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
)) {
2922 WARN("truncated data (%ld bytes)\n", data_size
);
2926 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2927 if (!mesh
->tex_coords
) {
2931 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2933 mesh
->fvf
|= D3DFVF_TEX1
;
2938 filedata
->lpVtbl
->Unlock(filedata
);
2942 static HRESULT
parse_vertex_colors(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2950 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2951 mesh
->vertex_colors
= NULL
;
2953 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2954 if (FAILED(hr
)) return hr
;
2956 /* template IndexedColor {
2958 * ColorRGBA indexColor;
2960 * template MeshVertexColors {
2961 * DWORD nVertexColors;
2962 * array IndexedColor vertexColors[nVertexColors];
2968 if (data_size
< sizeof(DWORD
)) {
2969 WARN("truncated data (%ld bytes)\n", data_size
);
2972 num_colors
= *(DWORD
*)data
;
2973 data
+= sizeof(DWORD
);
2974 if (data_size
< sizeof(DWORD
) + num_colors
* (sizeof(DWORD
) + sizeof(D3DCOLORVALUE
))) {
2975 WARN("truncated data (%ld bytes)\n", data_size
);
2979 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(DWORD
));
2980 if (!mesh
->vertex_colors
) {
2985 for (i
= 0; i
< mesh
->num_vertices
; i
++)
2986 mesh
->vertex_colors
[i
] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2987 for (i
= 0; i
< num_colors
; i
++)
2989 D3DCOLORVALUE color
;
2990 DWORD index
= *(DWORD
*)data
;
2991 data
+= sizeof(DWORD
);
2992 if (index
>= mesh
->num_vertices
) {
2993 WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2994 i
, index
, mesh
->num_vertices
);
2997 memcpy(&color
, data
, sizeof(color
));
2998 data
+= sizeof(color
);
2999 color
.r
= min(1.0f
, max(0.0f
, color
.r
));
3000 color
.g
= min(1.0f
, max(0.0f
, color
.g
));
3001 color
.b
= min(1.0f
, max(0.0f
, color
.b
));
3002 color
.a
= min(1.0f
, max(0.0f
, color
.a
));
3003 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
3004 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
3005 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
3006 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
3009 mesh
->fvf
|= D3DFVF_DIFFUSE
;
3014 filedata
->lpVtbl
->Unlock(filedata
);
3018 static HRESULT
parse_normals(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
3023 DWORD
*index_out_ptr
;
3025 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
3027 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
3028 mesh
->num_normals
= 0;
3029 mesh
->normals
= NULL
;
3030 mesh
->normal_indices
= NULL
;
3031 mesh
->fvf
|= D3DFVF_NORMAL
;
3033 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3034 if (FAILED(hr
)) return hr
;
3036 /* template Vector {
3041 * template MeshFace {
3042 * DWORD nFaceVertexIndices;
3043 * array DWORD faceVertexIndices[nFaceVertexIndices];
3045 * template MeshNormals {
3047 * array Vector normals[nNormals];
3048 * DWORD nFaceNormals;
3049 * array MeshFace faceNormals[nFaceNormals];
3055 if (data_size
< sizeof(DWORD
) * 2) {
3056 WARN("truncated data (%ld bytes)\n", data_size
);
3059 mesh
->num_normals
= *(DWORD
*)data
;
3060 data
+= sizeof(DWORD
);
3061 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
3062 num_face_indices
* sizeof(DWORD
)) {
3063 WARN("truncated data (%ld bytes)\n", data_size
);
3067 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3068 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
3069 if (!mesh
->normals
|| !mesh
->normal_indices
) {
3074 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3075 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
3076 for (i
= 0; i
< mesh
->num_normals
; i
++)
3077 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
3079 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
3080 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
3081 *(DWORD
*)data
, mesh
->num_poly_faces
);
3084 data
+= sizeof(DWORD
);
3085 index_out_ptr
= mesh
->normal_indices
;
3086 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
3089 DWORD count
= *(DWORD
*)data
;
3090 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
3091 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
3092 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
3095 data
+= sizeof(DWORD
);
3097 for (j
= 0; j
< count
; j
++) {
3098 DWORD normal_index
= *(DWORD
*)data
;
3099 if (normal_index
>= mesh
->num_normals
) {
3100 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
3101 i
, j
, normal_index
, mesh
->num_normals
);
3104 *index_out_ptr
++ = normal_index
;
3105 data
+= sizeof(DWORD
);
3112 filedata
->lpVtbl
->Unlock(filedata
);
3116 static HRESULT
parse_skin_mesh_info(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD index
)
3122 TRACE("(%p, %p, %u)\n", filedata
, mesh_data
, index
);
3124 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3125 if (FAILED(hr
)) return hr
;
3129 if (!mesh_data
->skin_info
) {
3130 if (data_size
< sizeof(WORD
) * 3) {
3131 WARN("truncated data (%ld bytes)\n", data_size
);
3134 /* Skip nMaxSkinWeightsPerVertex and nMaxSkinWeightsPerFace */
3135 data
+= 2 * sizeof(WORD
);
3136 mesh_data
->nb_bones
= *(WORD
*)data
;
3137 hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
, mesh_data
->nb_bones
, &mesh_data
->skin_info
);
3140 DWORD nb_influences
;
3142 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
3143 name
= *(const char**)data
;
3144 data
+= sizeof(char*);
3146 nb_influences
= *(DWORD
*)data
;
3147 data
+= sizeof(DWORD
);
3149 if (data_size
< (sizeof(char*) + sizeof(DWORD
) + nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
)) + 16 * sizeof(FLOAT
))) {
3150 WARN("truncated data (%ld bytes)\n", data_size
);
3154 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneName(mesh_data
->skin_info
, index
, name
);
3156 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneInfluence(mesh_data
->skin_info
, index
, nb_influences
,
3157 (const DWORD
*)data
, (const FLOAT
*)(data
+ nb_influences
* sizeof(DWORD
)));
3159 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneOffsetMatrix(mesh_data
->skin_info
, index
,
3160 (const D3DMATRIX
*)(data
+ nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
))));
3164 filedata
->lpVtbl
->Unlock(filedata
);
3168 /* for provide_flags parameters */
3169 #define PROVIDE_MATERIALS 0x1
3170 #define PROVIDE_SKININFO 0x2
3171 #define PROVIDE_ADJACENCY 0x4
3173 static HRESULT
parse_mesh(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
3177 const BYTE
*data
, *in_ptr
;
3178 DWORD
*index_out_ptr
;
3180 ID3DXFileData
*child
= NULL
;
3183 DWORD nb_skin_weights_info
= 0;
3188 * array Vector vertices[nVertices];
3190 * array MeshFace faces[nFaces];
3195 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3196 if (FAILED(hr
)) return hr
;
3201 if (data_size
< sizeof(DWORD
) * 2) {
3202 WARN("truncated data (%ld bytes)\n", data_size
);
3205 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
3206 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
)) {
3207 WARN("truncated data (%ld bytes)\n", data_size
);
3210 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
3212 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
3213 in_ptr
+= sizeof(DWORD
);
3215 mesh_data
->num_tri_faces
= 0;
3216 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3218 DWORD num_poly_vertices
;
3221 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
)) {
3222 WARN("truncated data (%ld bytes)\n", data_size
);
3225 num_poly_vertices
= *(DWORD
*)in_ptr
;
3226 in_ptr
+= sizeof(DWORD
);
3227 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
)) {
3228 WARN("truncated data (%ld bytes)\n", data_size
);
3231 if (num_poly_vertices
< 3) {
3232 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
3235 for (j
= 0; j
< num_poly_vertices
; j
++) {
3236 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
3237 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
3238 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
3241 in_ptr
+= sizeof(DWORD
);
3243 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
3246 mesh_data
->fvf
= D3DFVF_XYZ
;
3248 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
3249 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
3250 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
3251 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
3252 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
3253 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
3254 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
) {
3259 in_ptr
= data
+ sizeof(DWORD
);
3260 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
3261 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
3263 index_out_ptr
= mesh_data
->indices
;
3264 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3268 count
= *(DWORD
*)in_ptr
;
3269 in_ptr
+= sizeof(DWORD
);
3270 mesh_data
->num_tri_per_face
[i
] = count
- 2;
3273 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
3274 in_ptr
+= sizeof(DWORD
);
3278 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3282 for (i
= 0; i
< nb_children
; i
++)
3284 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3287 hr
= child
->lpVtbl
->GetType(child
, &type
);
3291 if (IsEqualGUID(&type
, &TID_D3DRMMeshNormals
)) {
3292 hr
= parse_normals(child
, mesh_data
);
3293 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshVertexColors
)) {
3294 hr
= parse_vertex_colors(child
, mesh_data
);
3295 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshTextureCoords
)) {
3296 hr
= parse_texture_coords(child
, mesh_data
);
3297 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshMaterialList
) &&
3298 (provide_flags
& PROVIDE_MATERIALS
))
3300 hr
= parse_material_list(child
, mesh_data
);
3301 } else if (provide_flags
& PROVIDE_SKININFO
) {
3302 if (IsEqualGUID(&type
, &DXFILEOBJ_XSkinMeshHeader
)) {
3303 if (mesh_data
->skin_info
) {
3304 WARN("Skin mesh header already encountered\n");
3308 hr
= parse_skin_mesh_info(child
, mesh_data
, 0);
3311 } else if (IsEqualGUID(&type
, &DXFILEOBJ_SkinWeights
)) {
3312 if (!mesh_data
->skin_info
) {
3313 WARN("Skin weights found but skin mesh header not encountered yet\n");
3317 hr
= parse_skin_mesh_info(child
, mesh_data
, nb_skin_weights_info
);
3320 nb_skin_weights_info
++;
3326 IUnknown_Release(child
);
3330 if (mesh_data
->skin_info
&& (nb_skin_weights_info
!= mesh_data
->nb_bones
)) {
3331 WARN("Mismatch between nb skin weights info %u encountered and nb bones %u from skin mesh header\n",
3332 nb_skin_weights_info
, mesh_data
->nb_bones
);
3341 IUnknown_Release(child
);
3342 filedata
->lpVtbl
->Unlock(filedata
);
3346 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
3347 ID3DXBuffer
**effects
)
3350 D3DXEFFECTINSTANCE
*effect_ptr
;
3352 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3353 static const struct {
3354 const char *param_name
;
3358 } material_effects
[] = {
3359 #define EFFECT_TABLE_ENTRY(str, field) \
3360 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
3361 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
3362 EFFECT_TABLE_ENTRY("Power", Power
),
3363 EFFECT_TABLE_ENTRY("Specular", Specular
),
3364 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
3365 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
3366 #undef EFFECT_TABLE_ENTRY
3368 static const char texture_paramname
[] = "Texture0@Name";
3372 /* effects buffer layout:
3374 * D3DXEFFECTINSTANCE effects[num_materials];
3375 * for (effect in effects)
3377 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
3378 * for (default in defaults)
3380 * *default.pParamName;
3385 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
3386 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
3387 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
3388 buffer_size
+= material_effects
[i
].name_size
;
3389 buffer_size
+= material_effects
[i
].num_bytes
;
3391 buffer_size
*= num_materials
;
3392 for (i
= 0; i
< num_materials
; i
++) {
3393 if (material_ptr
[i
].pTextureFilename
) {
3394 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
3395 buffer_size
+= sizeof(texture_paramname
);
3396 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
3400 hr
= D3DXCreateBuffer(buffer_size
, effects
);
3401 if (FAILED(hr
)) return hr
;
3402 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
3403 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
3405 for (i
= 0; i
< num_materials
; i
++)
3408 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
3410 effect_ptr
->pDefaults
= defaults
;
3411 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
3412 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
3414 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
3416 defaults
->pParamName
= (char *)out_ptr
;
3417 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
3418 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
3419 defaults
->Type
= D3DXEDT_FLOATS
;
3420 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
3421 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
3422 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3426 if (material_ptr
->pTextureFilename
)
3428 defaults
->pParamName
= (char *)out_ptr
;
3429 strcpy(defaults
->pParamName
, texture_paramname
);
3430 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
3431 defaults
->Type
= D3DXEDT_STRING
;
3432 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
3433 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
3434 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3439 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
3444 HRESULT WINAPI
D3DXLoadSkinMeshFromXof(struct ID3DXFileData
*filedata
, DWORD options
,
3445 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
3446 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXSkinInfo
**skin_info_out
,
3447 struct ID3DXMesh
**mesh_out
)
3450 DWORD
*index_in_ptr
;
3451 struct mesh_data mesh_data
;
3452 DWORD total_vertices
;
3453 ID3DXMesh
*d3dxmesh
= NULL
;
3454 ID3DXBuffer
*adjacency
= NULL
;
3455 ID3DXBuffer
*materials
= NULL
;
3456 ID3DXBuffer
*effects
= NULL
;
3457 struct vertex_duplication
{
3460 } *duplications
= NULL
;
3462 void *vertices
= NULL
;
3463 void *indices
= NULL
;
3465 DWORD provide_flags
= 0;
3467 TRACE("(%p, %x, %p, %p, %p, %p, %p, %p, %p)\n", filedata
, options
, device
, adjacency_out
, materials_out
,
3468 effects_out
, num_materials_out
, skin_info_out
, mesh_out
);
3470 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
3472 if (num_materials_out
|| materials_out
|| effects_out
)
3473 provide_flags
|= PROVIDE_MATERIALS
;
3475 provide_flags
|= PROVIDE_SKININFO
;
3477 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
3478 if (FAILED(hr
)) goto cleanup
;
3480 total_vertices
= mesh_data
.num_vertices
;
3481 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3482 /* duplicate vertices with multiple normals */
3483 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
3484 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
3485 if (!duplications
) {
3489 for (i
= 0; i
< total_vertices
; i
++)
3491 duplications
[i
].normal_index
= -1;
3492 list_init(&duplications
[i
].entry
);
3494 for (i
= 0; i
< num_face_indices
; i
++) {
3495 DWORD vertex_index
= mesh_data
.indices
[i
];
3496 DWORD normal_index
= mesh_data
.normal_indices
[i
];
3497 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
3499 if (dup_ptr
->normal_index
== -1) {
3500 dup_ptr
->normal_index
= normal_index
;
3502 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
3503 struct list
*dup_list
= &dup_ptr
->entry
;
3505 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
3506 if (new_normal
->x
== cur_normal
->x
&&
3507 new_normal
->y
== cur_normal
->y
&&
3508 new_normal
->z
== cur_normal
->z
)
3510 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3512 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
3513 dup_ptr
= &duplications
[total_vertices
++];
3514 dup_ptr
->normal_index
= normal_index
;
3515 list_add_tail(dup_list
, &dup_ptr
->entry
);
3516 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3519 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
3520 struct vertex_duplication
, entry
);
3527 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
3528 if (FAILED(hr
)) goto cleanup
;
3530 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, 0, &vertices
);
3531 if (FAILED(hr
)) goto cleanup
;
3534 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3535 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
3536 out_ptr
+= sizeof(D3DXVECTOR3
);
3537 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3538 if (duplications
[i
].normal_index
== -1)
3539 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
3541 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
3542 out_ptr
+= sizeof(D3DXVECTOR3
);
3544 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
3545 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
3546 out_ptr
+= sizeof(DWORD
);
3548 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
3549 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
3550 out_ptr
+= sizeof(D3DXVECTOR2
);
3553 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3554 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
3556 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3557 struct vertex_duplication
*dup_ptr
;
3558 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
3560 int j
= dup_ptr
- duplications
;
3561 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
3563 memcpy(dest_vertex
, out_ptr
, vertex_size
);
3564 dest_vertex
+= sizeof(D3DXVECTOR3
);
3565 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
3567 out_ptr
+= vertex_size
;
3570 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
3572 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, 0, &indices
);
3573 if (FAILED(hr
)) goto cleanup
;
3575 index_in_ptr
= mesh_data
.indices
;
3576 #define FILL_INDEX_BUFFER(indices_var) \
3577 for (i = 0; i < mesh_data.num_poly_faces; i++) \
3579 DWORD count = mesh_data.num_tri_per_face[i]; \
3580 WORD first_index = *index_in_ptr++; \
3582 *indices_var++ = first_index; \
3583 *indices_var++ = *index_in_ptr; \
3585 *indices_var++ = *index_in_ptr; \
3589 if (options
& D3DXMESH_32BIT
) {
3590 DWORD
*dword_indices
= indices
;
3591 FILL_INDEX_BUFFER(dword_indices
)
3593 WORD
*word_indices
= indices
;
3594 FILL_INDEX_BUFFER(word_indices
)
3596 #undef FILL_INDEX_BUFFER
3597 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
3599 if (mesh_data
.material_indices
) {
3600 DWORD
*attrib_buffer
= NULL
;
3601 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, 0, &attrib_buffer
);
3602 if (FAILED(hr
)) goto cleanup
;
3603 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
3605 DWORD count
= mesh_data
.num_tri_per_face
[i
];
3607 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
3609 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
3611 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
3612 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
3613 NULL
, NULL
, NULL
, NULL
);
3614 if (FAILED(hr
)) goto cleanup
;
3617 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
3618 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
3619 char *strings_out_ptr
;
3620 D3DXMATERIAL
*materials_ptr
;
3622 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3623 if (mesh_data
.materials
[i
].pTextureFilename
)
3624 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3627 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3628 if (FAILED(hr
)) goto cleanup
;
3630 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3631 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
3632 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
3633 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3634 if (materials_ptr
[i
].pTextureFilename
) {
3635 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
3636 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
3637 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3642 if (mesh_data
.num_materials
&& effects_out
) {
3643 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
3644 if (FAILED(hr
)) goto cleanup
;
3646 if (!materials_out
) {
3647 ID3DXBuffer_Release(materials
);
3652 if (adjacency_out
) {
3653 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
3654 if (FAILED(hr
)) goto cleanup
;
3655 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
3656 if (FAILED(hr
)) goto cleanup
;
3659 *mesh_out
= d3dxmesh
;
3660 if (adjacency_out
) *adjacency_out
= adjacency
;
3661 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
3662 if (materials_out
) *materials_out
= materials
;
3663 if (effects_out
) *effects_out
= effects
;
3664 if (skin_info_out
) *skin_info_out
= mesh_data
.skin_info
;
3669 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
3670 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3671 if (materials
) ID3DXBuffer_Release(materials
);
3672 if (effects
) ID3DXBuffer_Release(effects
);
3673 if (mesh_data
.skin_info
) mesh_data
.skin_info
->lpVtbl
->Release(mesh_data
.skin_info
);
3674 if (skin_info_out
) *skin_info_out
= NULL
;
3676 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
3677 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
3678 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
3679 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
3680 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
3681 destroy_materials(&mesh_data
);
3682 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
3683 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
3684 HeapFree(GetProcessHeap(), 0, duplications
);
3688 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3689 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3690 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3696 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3697 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3698 debugstr_a(filename
), options
, device
, alloc_hier
,
3699 load_user_data
, frame_hierarchy
, anim_controller
);
3702 return D3DERR_INVALIDCALL
;
3704 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3705 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3706 if (!filenameW
) return E_OUTOFMEMORY
;
3707 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3709 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
3710 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3711 HeapFree(GetProcessHeap(), 0, filenameW
);
3716 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3717 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3718 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3724 TRACE("filename %s, options %#x, device %p, alloc_hier %p, "
3725 "load_user_data %p, frame_hierarchy %p, anim_controller %p.\n",
3726 debugstr_w(filename
), options
, device
, alloc_hier
,
3727 load_user_data
, frame_hierarchy
, anim_controller
);
3730 return D3DERR_INVALIDCALL
;
3732 hr
= map_view_of_file(filename
, &buffer
, &size
);
3734 return D3DXERR_INVALIDDATA
;
3736 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
3737 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3739 UnmapViewOfFile(buffer
);
3744 static HRESULT
filedata_get_name(ID3DXFileData
*filedata
, char **name
)
3749 hr
= filedata
->lpVtbl
->GetName(filedata
, NULL
, &name_len
);
3750 if (FAILED(hr
)) return hr
;
3754 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
3755 if (!*name
) return E_OUTOFMEMORY
;
3757 hr
= filedata
->lpVtbl
->GetName(filedata
, *name
, &name_len
);
3759 HeapFree(GetProcessHeap(), 0, *name
);
3766 static HRESULT
load_mesh_container(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3767 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXMESHCONTAINER
**mesh_container
)
3770 ID3DXBuffer
*adjacency
= NULL
;
3771 ID3DXBuffer
*materials
= NULL
;
3772 ID3DXBuffer
*effects
= NULL
;
3773 ID3DXSkinInfo
*skin_info
= NULL
;
3774 D3DXMESHDATA mesh_data
;
3775 DWORD num_materials
= 0;
3778 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
3779 mesh_data
.u
.pMesh
= NULL
;
3781 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
3782 &adjacency
, &materials
, &effects
, &num_materials
,
3783 &skin_info
, &mesh_data
.u
.pMesh
);
3784 if (FAILED(hr
)) return hr
;
3786 hr
= filedata_get_name(filedata
, &name
);
3787 if (FAILED(hr
)) goto cleanup
;
3789 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
3790 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
3791 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
3793 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
3794 skin_info
, mesh_container
);
3797 if (materials
) ID3DXBuffer_Release(materials
);
3798 if (effects
) ID3DXBuffer_Release(effects
);
3799 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3800 if (skin_info
) IUnknown_Release(skin_info
);
3801 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
3802 HeapFree(GetProcessHeap(), 0, name
);
3806 static HRESULT
parse_transform_matrix(ID3DXFileData
*filedata
, D3DXMATRIX
*transform
)
3812 /* template Matrix4x4 {
3813 * array FLOAT matrix[16];
3815 * template FrameTransformMatrix {
3816 * Matrix4x4 frameMatrix;
3820 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3821 if (FAILED(hr
)) return hr
;
3823 if (data_size
!= sizeof(D3DXMATRIX
)) {
3824 WARN("incorrect data size (%ld bytes)\n", data_size
);
3825 filedata
->lpVtbl
->Unlock(filedata
);
3829 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
3831 filedata
->lpVtbl
->Unlock(filedata
);
3835 static HRESULT
load_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3836 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXFRAME
**frame_out
)
3840 ID3DXFileData
*child
;
3842 D3DXFRAME
*frame
= NULL
;
3843 D3DXMESHCONTAINER
**next_container
;
3844 D3DXFRAME
**next_child
;
3845 SIZE_T i
, nb_children
;
3847 hr
= filedata_get_name(filedata
, &name
);
3848 if (FAILED(hr
)) return hr
;
3850 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
3851 HeapFree(GetProcessHeap(), 0, name
);
3852 if (FAILED(hr
)) return E_FAIL
;
3855 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
3856 next_child
= &frame
->pFrameFirstChild
;
3857 next_container
= &frame
->pMeshContainer
;
3859 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3863 for (i
= 0; i
< nb_children
; i
++)
3865 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3868 hr
= child
->lpVtbl
->GetType(child
, &type
);
3872 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
3873 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
3875 next_container
= &(*next_container
)->pNextMeshContainer
;
3876 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
3877 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
3878 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
3879 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
3881 next_child
= &(*next_child
)->pFrameSibling
;
3886 IUnknown_Release(child
);
3891 IUnknown_Release(child
);
3895 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
3896 struct IDirect3DDevice9
*device
, struct ID3DXAllocateHierarchy
*alloc_hier
,
3897 struct ID3DXLoadUserData
*load_user_data
, D3DXFRAME
**frame_hierarchy
,
3898 struct ID3DXAnimationController
**anim_controller
)
3901 ID3DXFile
*d3dxfile
= NULL
;
3902 ID3DXFileEnumObject
*enumobj
= NULL
;
3903 ID3DXFileData
*filedata
= NULL
;
3904 D3DXF_FILELOADMEMORY source
;
3905 D3DXFRAME
*first_frame
= NULL
;
3906 D3DXFRAME
**next_frame
= &first_frame
;
3907 SIZE_T i
, nb_children
;
3910 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3911 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3913 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
3914 return D3DERR_INVALIDCALL
;
3917 FIXME("Loading user data not implemented.\n");
3921 hr
= D3DXFileCreate(&d3dxfile
);
3922 if (FAILED(hr
)) goto cleanup
;
3924 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3925 if (FAILED(hr
)) goto cleanup
;
3927 source
.lpMemory
= (void*)memory
;
3928 source
.dSize
= memory_size
;
3929 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
3930 if (FAILED(hr
)) goto cleanup
;
3932 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
3936 for (i
= 0; i
< nb_children
; i
++)
3938 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
3942 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
3943 if (SUCCEEDED(hr
)) {
3944 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
3945 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
3951 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
3953 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
3954 if (FAILED(hr
)) goto cleanup
;
3955 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
3956 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
3957 if (FAILED(hr
)) goto cleanup
;
3960 next_frame
= &(*next_frame
)->pFrameSibling
;
3963 filedata
->lpVtbl
->Release(filedata
);
3971 } else if (first_frame
->pFrameSibling
) {
3972 D3DXFRAME
*root_frame
= NULL
;
3973 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
3978 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
3979 root_frame
->pFrameFirstChild
= first_frame
;
3980 *frame_hierarchy
= root_frame
;
3983 *frame_hierarchy
= first_frame
;
3987 if (anim_controller
)
3989 *anim_controller
= NULL
;
3990 FIXME("Animation controller creation not implemented.\n");
3994 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
3995 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
3996 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
3997 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4001 HRESULT WINAPI
D3DXCleanMesh(D3DXCLEANTYPE clean_type
, ID3DXMesh
*mesh_in
, const DWORD
*adjacency_in
,
4002 ID3DXMesh
**mesh_out
, DWORD
*adjacency_out
, ID3DXBuffer
**errors_and_warnings
)
4004 FIXME("(%u, %p, %p, %p, %p, %p)\n", clean_type
, mesh_in
, adjacency_in
, mesh_out
, adjacency_out
, errors_and_warnings
);
4009 HRESULT WINAPI
D3DXFrameDestroy(D3DXFRAME
*frame
, ID3DXAllocateHierarchy
*alloc_hier
)
4014 TRACE("(%p, %p)\n", frame
, alloc_hier
);
4016 if (!frame
|| !alloc_hier
)
4017 return D3DERR_INVALIDCALL
;
4020 D3DXMESHCONTAINER
*container
;
4021 D3DXFRAME
*current_frame
;
4023 if (frame
->pFrameSibling
) {
4024 current_frame
= frame
->pFrameSibling
;
4025 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
4026 current_frame
->pFrameSibling
= NULL
;
4028 current_frame
= frame
;
4032 if (current_frame
->pFrameFirstChild
) {
4033 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
4034 if (FAILED(hr
)) return hr
;
4035 current_frame
->pFrameFirstChild
= NULL
;
4038 container
= current_frame
->pMeshContainer
;
4040 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
4041 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
4042 if (FAILED(hr
)) return hr
;
4043 container
= next_container
;
4045 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
4046 if (FAILED(hr
)) return hr
;
4051 HRESULT WINAPI
D3DXLoadMeshFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4052 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4053 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4059 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4060 "effect_instances %p, num_materials %p, mesh %p.\n",
4061 debugstr_a(filename
), options
, device
, adjacency
, materials
,
4062 effect_instances
, num_materials
, mesh
);
4065 return D3DERR_INVALIDCALL
;
4067 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
4068 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4069 if (!filenameW
) return E_OUTOFMEMORY
;
4070 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
4072 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
4073 effect_instances
, num_materials
, mesh
);
4074 HeapFree(GetProcessHeap(), 0, filenameW
);
4079 HRESULT WINAPI
D3DXLoadMeshFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4080 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4081 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4087 TRACE("filename %s, options %#x, device %p, adjacency %p, materials %p, "
4088 "effect_instances %p, num_materials %p, mesh %p.\n",
4089 debugstr_w(filename
), options
, device
, adjacency
, materials
,
4090 effect_instances
, num_materials
, mesh
);
4093 return D3DERR_INVALIDCALL
;
4095 hr
= map_view_of_file(filename
, &buffer
, &size
);
4097 return D3DXERR_INVALIDDATA
;
4099 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4100 materials
, effect_instances
, num_materials
, mesh
);
4102 UnmapViewOfFile(buffer
);
4107 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
, const char *name
, const char *type
, DWORD options
,
4108 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
,
4109 struct ID3DXBuffer
**effect_instances
, DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4116 TRACE("module %p, name %s, type %s, options %#x, device %p, adjacency %p, "
4117 "materials %p, effect_instances %p, num_materials %p, mesh %p.\n",
4118 module
, debugstr_a(name
), debugstr_a(type
), options
, device
, adjacency
,
4119 materials
, effect_instances
, num_materials
, mesh
);
4121 resinfo
= FindResourceA(module
, name
, type
);
4122 if (!resinfo
) return D3DXERR_INVALIDDATA
;
4124 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
4125 if (FAILED(hr
)) return D3DXERR_INVALIDDATA
;
4127 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4128 materials
, effect_instances
, num_materials
, mesh
);
4131 struct mesh_container
4135 ID3DXBuffer
*adjacency
;
4136 ID3DXBuffer
*materials
;
4137 ID3DXBuffer
*effects
;
4138 DWORD num_materials
;
4139 D3DXMATRIX transform
;
4142 static HRESULT
parse_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
4143 const D3DXMATRIX
*parent_transform
, struct list
*container_list
, DWORD provide_flags
)
4146 D3DXMATRIX transform
= *parent_transform
;
4147 ID3DXFileData
*child
;
4149 SIZE_T i
, nb_children
;
4151 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
4155 for (i
= 0; i
< nb_children
; i
++)
4157 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
4160 hr
= child
->lpVtbl
->GetType(child
, &type
);
4164 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
4165 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
4171 list_add_tail(container_list
, &container
->entry
);
4172 container
->transform
= transform
;
4174 hr
= D3DXLoadSkinMeshFromXof(child
, options
, device
,
4175 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
4176 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
4177 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
4178 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
4179 D3DXMATRIX new_transform
;
4180 hr
= parse_transform_matrix(child
, &new_transform
);
4181 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
4182 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
4183 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
4188 IUnknown_Release(child
);
4193 IUnknown_Release(child
);
4197 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
4198 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
4199 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXMesh
**mesh_out
)
4202 ID3DXFile
*d3dxfile
= NULL
;
4203 ID3DXFileEnumObject
*enumobj
= NULL
;
4204 ID3DXFileData
*filedata
= NULL
;
4205 D3DXF_FILELOADMEMORY source
;
4206 ID3DXBuffer
*materials
= NULL
;
4207 ID3DXBuffer
*effects
= NULL
;
4208 ID3DXBuffer
*adjacency
= NULL
;
4209 struct list container_list
= LIST_INIT(container_list
);
4210 struct mesh_container
*container_ptr
, *next_container_ptr
;
4211 DWORD num_materials
;
4212 DWORD num_faces
, num_vertices
;
4213 D3DXMATRIX identity
;
4214 DWORD provide_flags
= 0;
4216 ID3DXMesh
*concat_mesh
= NULL
;
4217 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
4218 BYTE
*concat_vertices
= NULL
;
4219 void *concat_indices
= NULL
;
4221 DWORD concat_vertex_size
;
4222 SIZE_T i
, nb_children
;
4225 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
4226 device
, adjacency_out
, materials_out
, effects_out
, num_materials_out
, mesh_out
);
4228 if (!memory
|| !memory_size
|| !device
|| !mesh_out
)
4229 return D3DERR_INVALIDCALL
;
4231 hr
= D3DXFileCreate(&d3dxfile
);
4232 if (FAILED(hr
)) goto cleanup
;
4234 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
4235 if (FAILED(hr
)) goto cleanup
;
4237 source
.lpMemory
= (void*)memory
;
4238 source
.dSize
= memory_size
;
4239 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
4240 if (FAILED(hr
)) goto cleanup
;
4242 D3DXMatrixIdentity(&identity
);
4243 if (adjacency_out
) provide_flags
|= PROVIDE_ADJACENCY
;
4244 if (materials_out
|| effects_out
) provide_flags
|= PROVIDE_MATERIALS
;
4246 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
4250 for (i
= 0; i
< nb_children
; i
++)
4252 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
4256 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
4257 if (SUCCEEDED(hr
)) {
4258 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
4259 container_ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container_ptr
));
4260 if (!container_ptr
) {
4264 list_add_tail(&container_list
, &container_ptr
->entry
);
4265 D3DXMatrixIdentity(&container_ptr
->transform
);
4267 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
4268 (provide_flags
& PROVIDE_ADJACENCY
) ? &container_ptr
->adjacency
: NULL
,
4269 (provide_flags
& PROVIDE_MATERIALS
) ? &container_ptr
->materials
: NULL
,
4270 NULL
, &container_ptr
->num_materials
, NULL
, &container_ptr
->mesh
);
4271 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
4272 hr
= parse_frame(filedata
, options
, device
, &identity
, &container_list
, provide_flags
);
4274 if (FAILED(hr
)) goto cleanup
;
4276 filedata
->lpVtbl
->Release(filedata
);
4282 enumobj
->lpVtbl
->Release(enumobj
);
4284 d3dxfile
->lpVtbl
->Release(d3dxfile
);
4287 if (list_empty(&container_list
)) {
4296 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4298 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4299 fvf
|= mesh
->lpVtbl
->GetFVF(mesh
);
4300 num_faces
+= mesh
->lpVtbl
->GetNumFaces(mesh
);
4301 num_vertices
+= mesh
->lpVtbl
->GetNumVertices(mesh
);
4302 num_materials
+= container_ptr
->num_materials
;
4305 hr
= D3DXCreateMeshFVF(num_faces
, num_vertices
, options
, fvf
, device
, &concat_mesh
);
4306 if (FAILED(hr
)) goto cleanup
;
4308 hr
= concat_mesh
->lpVtbl
->GetDeclaration(concat_mesh
, concat_decl
);
4309 if (FAILED(hr
)) goto cleanup
;
4311 concat_vertex_size
= D3DXGetDeclVertexSize(concat_decl
, 0);
4313 hr
= concat_mesh
->lpVtbl
->LockVertexBuffer(concat_mesh
, 0, (void**)&concat_vertices
);
4314 if (FAILED(hr
)) goto cleanup
;
4316 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4318 D3DVERTEXELEMENT9 mesh_decl
[MAX_FVF_DECL_SIZE
];
4319 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4320 DWORD num_mesh_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
4321 DWORD mesh_vertex_size
;
4322 const BYTE
*mesh_vertices
;
4325 hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, mesh_decl
);
4326 if (FAILED(hr
)) goto cleanup
;
4328 mesh_vertex_size
= D3DXGetDeclVertexSize(mesh_decl
, 0);
4330 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_vertices
);
4331 if (FAILED(hr
)) goto cleanup
;
4333 for (i
= 0; i
< num_mesh_vertices
; i
++) {
4337 D3DXVec3TransformCoord((D3DXVECTOR3
*)concat_vertices
,
4338 (D3DXVECTOR3
*)mesh_vertices
,
4339 &container_ptr
->transform
);
4340 for (j
= 1; concat_decl
[j
].Stream
!= 0xff; j
++)
4342 if (concat_decl
[j
].Usage
== mesh_decl
[k
].Usage
&&
4343 concat_decl
[j
].UsageIndex
== mesh_decl
[k
].UsageIndex
)
4345 if (concat_decl
[j
].Usage
== D3DDECLUSAGE_NORMAL
) {
4346 D3DXVec3TransformCoord((D3DXVECTOR3
*)(concat_vertices
+ concat_decl
[j
].Offset
),
4347 (D3DXVECTOR3
*)(mesh_vertices
+ mesh_decl
[k
].Offset
),
4348 &container_ptr
->transform
);
4350 memcpy(concat_vertices
+ concat_decl
[j
].Offset
,
4351 mesh_vertices
+ mesh_decl
[k
].Offset
,
4352 d3dx_decltype_size
[mesh_decl
[k
].Type
]);
4357 mesh_vertices
+= mesh_vertex_size
;
4358 concat_vertices
+= concat_vertex_size
;
4361 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
4364 concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4365 concat_vertices
= NULL
;
4367 hr
= concat_mesh
->lpVtbl
->LockIndexBuffer(concat_mesh
, 0, &concat_indices
);
4368 if (FAILED(hr
)) goto cleanup
;
4371 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4373 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4374 const void *mesh_indices
;
4375 DWORD num_mesh_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4378 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_indices
);
4379 if (FAILED(hr
)) goto cleanup
;
4381 if (options
& D3DXMESH_32BIT
) {
4382 DWORD
*dest
= concat_indices
;
4383 const DWORD
*src
= mesh_indices
;
4384 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4385 *dest
++ = index_offset
+ *src
++;
4386 concat_indices
= dest
;
4388 WORD
*dest
= concat_indices
;
4389 const WORD
*src
= mesh_indices
;
4390 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4391 *dest
++ = index_offset
+ *src
++;
4392 concat_indices
= dest
;
4394 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
4396 index_offset
+= num_mesh_faces
* 3;
4399 concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4400 concat_indices
= NULL
;
4402 if (num_materials
) {
4403 DWORD
*concat_attrib_buffer
= NULL
;
4406 hr
= concat_mesh
->lpVtbl
->LockAttributeBuffer(concat_mesh
, 0, &concat_attrib_buffer
);
4407 if (FAILED(hr
)) goto cleanup
;
4409 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4411 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4412 const DWORD
*mesh_attrib_buffer
= NULL
;
4413 DWORD count
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4415 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, D3DLOCK_READONLY
, (DWORD
**)&mesh_attrib_buffer
);
4417 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4422 *concat_attrib_buffer
++ = offset
+ *mesh_attrib_buffer
++;
4424 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
4425 offset
+= container_ptr
->num_materials
;
4427 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4430 if (materials_out
|| effects_out
) {
4431 D3DXMATERIAL
*out_ptr
;
4432 if (!num_materials
) {
4433 /* create default material */
4434 hr
= D3DXCreateBuffer(sizeof(D3DXMATERIAL
), &materials
);
4435 if (FAILED(hr
)) goto cleanup
;
4437 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4438 out_ptr
->MatD3D
.Diffuse
.r
= 0.5f
;
4439 out_ptr
->MatD3D
.Diffuse
.g
= 0.5f
;
4440 out_ptr
->MatD3D
.Diffuse
.b
= 0.5f
;
4441 out_ptr
->MatD3D
.Specular
.r
= 0.5f
;
4442 out_ptr
->MatD3D
.Specular
.g
= 0.5f
;
4443 out_ptr
->MatD3D
.Specular
.b
= 0.5f
;
4444 /* D3DXCreateBuffer initializes the rest to zero */
4446 DWORD buffer_size
= num_materials
* sizeof(D3DXMATERIAL
);
4447 char *strings_out_ptr
;
4449 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4451 if (container_ptr
->materials
) {
4453 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4454 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4456 if (in_ptr
->pTextureFilename
)
4457 buffer_size
+= strlen(in_ptr
->pTextureFilename
) + 1;
4463 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
4464 if (FAILED(hr
)) goto cleanup
;
4465 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4466 strings_out_ptr
= (char*)(out_ptr
+ num_materials
);
4468 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4470 if (container_ptr
->materials
) {
4472 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4473 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4475 out_ptr
->MatD3D
= in_ptr
->MatD3D
;
4476 if (in_ptr
->pTextureFilename
) {
4477 out_ptr
->pTextureFilename
= strings_out_ptr
;
4478 strcpy(out_ptr
->pTextureFilename
, in_ptr
->pTextureFilename
);
4479 strings_out_ptr
+= strlen(in_ptr
->pTextureFilename
) + 1;
4492 generate_effects(materials
, num_materials
, &effects
);
4493 if (!materials_out
) {
4494 ID3DXBuffer_Release(materials
);
4499 if (adjacency_out
) {
4500 if (!list_next(&container_list
, list_head(&container_list
))) {
4501 container_ptr
= LIST_ENTRY(list_head(&container_list
), struct mesh_container
, entry
);
4502 adjacency
= container_ptr
->adjacency
;
4503 container_ptr
->adjacency
= NULL
;
4508 hr
= D3DXCreateBuffer(num_faces
* 3 * sizeof(DWORD
), &adjacency
);
4509 if (FAILED(hr
)) goto cleanup
;
4511 out_ptr
= ID3DXBuffer_GetBufferPointer(adjacency
);
4512 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4515 DWORD count
= 3 * container_ptr
->mesh
->lpVtbl
->GetNumFaces(container_ptr
->mesh
);
4516 DWORD
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->adjacency
);
4518 for (i
= 0; i
< count
; i
++)
4519 *out_ptr
++ = offset
+ *in_ptr
++;
4526 *mesh_out
= concat_mesh
;
4527 if (adjacency_out
) *adjacency_out
= adjacency
;
4528 if (materials_out
) *materials_out
= materials
;
4529 if (effects_out
) *effects_out
= effects
;
4530 if (num_materials_out
) *num_materials_out
= num_materials
;
4534 if (concat_indices
) concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4535 if (concat_vertices
) concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4536 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
4537 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
4538 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4540 if (concat_mesh
) IUnknown_Release(concat_mesh
);
4541 if (materials
) ID3DXBuffer_Release(materials
);
4542 if (effects
) ID3DXBuffer_Release(effects
);
4543 if (adjacency
) ID3DXBuffer_Release(adjacency
);
4545 LIST_FOR_EACH_ENTRY_SAFE(container_ptr
, next_container_ptr
, &container_list
, struct mesh_container
, entry
)
4547 if (container_ptr
->mesh
) IUnknown_Release(container_ptr
->mesh
);
4548 if (container_ptr
->adjacency
) ID3DXBuffer_Release(container_ptr
->adjacency
);
4549 if (container_ptr
->materials
) ID3DXBuffer_Release(container_ptr
->materials
);
4550 if (container_ptr
->effects
) ID3DXBuffer_Release(container_ptr
->effects
);
4551 HeapFree(GetProcessHeap(), 0, container_ptr
);
4558 D3DXVECTOR3 position
;
4562 HRESULT WINAPI
D3DXCreatePolygon(struct IDirect3DDevice9
*device
, float length
, UINT sides
,
4563 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4567 struct vertex
*vertices
;
4569 DWORD (*adjacency_buf
)[3];
4573 TRACE("device %p, length %f, sides %u, mesh %p, adjacency %p.\n",
4574 device
, length
, sides
, mesh
, adjacency
);
4576 if (!device
|| length
< 0.0f
|| sides
< 3 || !mesh
)
4577 return D3DERR_INVALIDCALL
;
4579 if (FAILED(hr
= D3DXCreateMeshFVF(sides
, sides
+ 1, D3DXMESH_MANAGED
,
4580 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &polygon
)))
4585 if (FAILED(hr
= polygon
->lpVtbl
->LockVertexBuffer(polygon
, 0, (void **)&vertices
)))
4587 polygon
->lpVtbl
->Release(polygon
);
4591 if (FAILED(hr
= polygon
->lpVtbl
->LockIndexBuffer(polygon
, 0, (void **)&faces
)))
4593 polygon
->lpVtbl
->UnlockVertexBuffer(polygon
);
4594 polygon
->lpVtbl
->Release(polygon
);
4598 scale
= 0.5f
* length
/ sinf(D3DX_PI
/ sides
);
4600 vertices
[0].position
.x
= 0.0f
;
4601 vertices
[0].position
.y
= 0.0f
;
4602 vertices
[0].position
.z
= 0.0f
;
4603 vertices
[0].normal
.x
= 0.0f
;
4604 vertices
[0].normal
.y
= 0.0f
;
4605 vertices
[0].normal
.z
= 1.0f
;
4607 for (i
= 0; i
< sides
; ++i
)
4609 vertices
[i
+ 1].position
.x
= cosf(2.0f
* D3DX_PI
* i
/ sides
) * scale
;
4610 vertices
[i
+ 1].position
.y
= sinf(2.0f
* D3DX_PI
* i
/ sides
) * scale
;
4611 vertices
[i
+ 1].position
.z
= 0.0f
;
4612 vertices
[i
+ 1].normal
.x
= 0.0f
;
4613 vertices
[i
+ 1].normal
.y
= 0.0f
;
4614 vertices
[i
+ 1].normal
.z
= 1.0f
;
4617 faces
[i
][1] = i
+ 1;
4618 faces
[i
][2] = i
+ 2;
4621 faces
[sides
- 1][2] = 1;
4623 polygon
->lpVtbl
->UnlockVertexBuffer(polygon
);
4624 polygon
->lpVtbl
->UnlockIndexBuffer(polygon
);
4628 if (FAILED(hr
= D3DXCreateBuffer(sides
* sizeof(DWORD
) * 3, adjacency
)))
4630 polygon
->lpVtbl
->Release(polygon
);
4634 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4635 for (i
= 0; i
< sides
; ++i
)
4637 adjacency_buf
[i
][0] = i
- 1;
4638 adjacency_buf
[i
][1] = ~0U;
4639 adjacency_buf
[i
][2] = i
+ 1;
4641 adjacency_buf
[0][0] = sides
- 1;
4642 adjacency_buf
[sides
- 1][2] = 0;
4650 HRESULT WINAPI
D3DXCreateBox(struct IDirect3DDevice9
*device
, float width
, float height
,
4651 float depth
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4655 struct vertex
*vertices
;
4657 DWORD
*adjacency_buf
;
4658 unsigned int i
, face
;
4659 static const D3DXVECTOR3 unit_box
[] =
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
},
4665 {-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 {-0.5f
, -0.5f
, -0.5f
}, {-0.5f
, 0.5f
, -0.5f
}, { 0.5f
, 0.5f
, -0.5f
}, { 0.5f
, -0.5f
, -0.5f
}
4668 static const D3DXVECTOR3 normals
[] =
4670 {-1.0f
, 0.0f
, 0.0f
}, { 0.0f
, 1.0f
, 0.0f
}, { 1.0f
, 0.0f
, 0.0f
},
4671 { 0.0f
, -1.0f
, 0.0f
}, { 0.0f
, 0.0f
, 1.0f
}, { 0.0f
, 0.0f
, -1.0f
}
4673 static const DWORD adjacency_table
[] =
4675 6, 9, 1, 2, 10, 0, 1, 9, 3, 4, 10, 2,
4676 3, 8, 5, 7, 11, 4, 0, 11, 7, 5, 8, 6,
4677 7, 4, 9, 2, 0, 8, 1, 3, 11, 5, 6, 10
4680 TRACE("device %p, width %f, height %f, depth %f, mesh %p, adjacency %p\n",
4681 device
, width
, height
, depth
, mesh
, adjacency
);
4683 if (!device
|| width
< 0.0f
|| height
< 0.0f
|| depth
< 0.0f
|| !mesh
)
4685 return D3DERR_INVALIDCALL
;
4688 if (FAILED(hr
= D3DXCreateMeshFVF(12, 24, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &box
)))
4693 if (FAILED(hr
= box
->lpVtbl
->LockVertexBuffer(box
, 0, (void **)&vertices
)))
4695 box
->lpVtbl
->Release(box
);
4699 if (FAILED(hr
= box
->lpVtbl
->LockIndexBuffer(box
, 0, (void **)&faces
)))
4701 box
->lpVtbl
->UnlockVertexBuffer(box
);
4702 box
->lpVtbl
->Release(box
);
4706 for (i
= 0; i
< 24; i
++)
4708 vertices
[i
].position
.x
= width
* unit_box
[i
].x
;
4709 vertices
[i
].position
.y
= height
* unit_box
[i
].y
;
4710 vertices
[i
].position
.z
= depth
* unit_box
[i
].z
;
4711 vertices
[i
].normal
.x
= normals
[i
/ 4].x
;
4712 vertices
[i
].normal
.y
= normals
[i
/ 4].y
;
4713 vertices
[i
].normal
.z
= normals
[i
/ 4].z
;
4717 for (i
= 0; i
< 12; i
++)
4719 faces
[i
][0] = face
++;
4720 faces
[i
][1] = face
++;
4721 faces
[i
][2] = (i
% 2) ? face
- 4 : face
;
4724 box
->lpVtbl
->UnlockIndexBuffer(box
);
4725 box
->lpVtbl
->UnlockVertexBuffer(box
);
4729 if (FAILED(hr
= D3DXCreateBuffer(sizeof(adjacency_table
), adjacency
)))
4731 box
->lpVtbl
->Release(box
);
4735 adjacency_buf
= ID3DXBuffer_GetBufferPointer(*adjacency
);
4736 memcpy(adjacency_buf
, adjacency_table
, sizeof(adjacency_table
));
4744 typedef WORD face
[3];
4752 static void free_sincos_table(struct sincos_table
*sincos_table
)
4754 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
4755 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4758 /* pre compute sine and cosine tables; caller must free */
4759 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
4764 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
4765 if (!sincos_table
->sin
)
4769 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
4770 if (!sincos_table
->cos
)
4772 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4776 angle
= angle_start
;
4777 for (i
= 0; i
< n
; i
++)
4779 sincos_table
->sin
[i
] = sinf(angle
);
4780 sincos_table
->cos
[i
] = cosf(angle
);
4781 angle
+= angle_step
;
4787 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
4789 return stack
*slices
+slice
+1;
4792 HRESULT WINAPI
D3DXCreateSphere(struct IDirect3DDevice9
*device
, float radius
, UINT slices
,
4793 UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4795 DWORD number_of_vertices
, number_of_faces
;
4798 struct vertex
*vertices
;
4800 float phi_step
, phi_start
;
4801 struct sincos_table phi
;
4802 float theta_step
, theta
, sin_theta
, cos_theta
;
4803 DWORD vertex
, face
, stack
, slice
;
4805 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
4807 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
4809 return D3DERR_INVALIDCALL
;
4812 number_of_vertices
= 2 + slices
* (stacks
-1);
4813 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
4815 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4816 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
4822 if (FAILED(hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, 0, (void **)&vertices
)))
4824 sphere
->lpVtbl
->Release(sphere
);
4828 if (FAILED(hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, 0, (void **)&faces
)))
4830 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4831 sphere
->lpVtbl
->Release(sphere
);
4835 /* phi = angle on xz plane wrt z axis */
4836 phi_step
= -2.0f
* D3DX_PI
/ slices
;
4837 phi_start
= D3DX_PI
/ 2.0f
;
4839 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
4841 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4842 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4843 sphere
->lpVtbl
->Release(sphere
);
4844 return E_OUTOFMEMORY
;
4847 /* theta = angle on xy plane wrt x axis */
4848 theta_step
= D3DX_PI
/ stacks
;
4854 vertices
[vertex
].normal
.x
= 0.0f
;
4855 vertices
[vertex
].normal
.y
= 0.0f
;
4856 vertices
[vertex
].normal
.z
= 1.0f
;
4857 vertices
[vertex
].position
.x
= 0.0f
;
4858 vertices
[vertex
].position
.y
= 0.0f
;
4859 vertices
[vertex
].position
.z
= radius
;
4862 for (stack
= 0; stack
< stacks
- 1; stack
++)
4864 sin_theta
= sinf(theta
);
4865 cos_theta
= cosf(theta
);
4867 for (slice
= 0; slice
< slices
; slice
++)
4869 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
4870 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
4871 vertices
[vertex
].normal
.z
= cos_theta
;
4872 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
4873 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
4874 vertices
[vertex
].position
.z
= radius
* cos_theta
;
4881 /* top stack is triangle fan */
4883 faces
[face
][1] = slice
+ 1;
4884 faces
[face
][2] = slice
;
4889 /* stacks in between top and bottom are quad strips */
4890 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4891 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4892 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4895 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4896 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
4897 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4903 theta
+= theta_step
;
4909 faces
[face
][2] = slice
;
4914 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4915 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4916 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4919 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4920 faces
[face
][1] = vertex_index(slices
, 0, stack
);
4921 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4926 vertices
[vertex
].position
.x
= 0.0f
;
4927 vertices
[vertex
].position
.y
= 0.0f
;
4928 vertices
[vertex
].position
.z
= -radius
;
4929 vertices
[vertex
].normal
.x
= 0.0f
;
4930 vertices
[vertex
].normal
.y
= 0.0f
;
4931 vertices
[vertex
].normal
.z
= -1.0f
;
4933 /* bottom stack is triangle fan */
4934 for (slice
= 1; slice
< slices
; slice
++)
4936 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4937 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4938 faces
[face
][2] = vertex
;
4942 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4943 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4944 faces
[face
][2] = vertex
;
4946 free_sincos_table(&phi
);
4947 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4948 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4953 if (FAILED(hr
= D3DXCreateBuffer(number_of_faces
* sizeof(DWORD
) * 3, adjacency
)))
4955 sphere
->lpVtbl
->Release(sphere
);
4959 if (FAILED(hr
= sphere
->lpVtbl
->GenerateAdjacency(sphere
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
4961 (*adjacency
)->lpVtbl
->Release(*adjacency
);
4962 sphere
->lpVtbl
->Release(sphere
);
4972 HRESULT WINAPI
D3DXCreateCylinder(struct IDirect3DDevice9
*device
, float radius1
, float radius2
,
4973 float length
, UINT slices
, UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4975 DWORD number_of_vertices
, number_of_faces
;
4977 ID3DXMesh
*cylinder
;
4978 struct vertex
*vertices
;
4980 float theta_step
, theta_start
;
4981 struct sincos_table theta
;
4982 float delta_radius
, radius
, radius_step
;
4983 float z
, z_step
, z_normal
;
4984 DWORD vertex
, face
, slice
, stack
;
4986 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
4988 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
4990 return D3DERR_INVALIDCALL
;
4993 number_of_vertices
= 2 + (slices
* (3 + stacks
));
4994 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
4996 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4997 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
5003 if (FAILED(hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, 0, (void **)&vertices
)))
5005 cylinder
->lpVtbl
->Release(cylinder
);
5009 if (FAILED(hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, 0, (void **)&faces
)))
5011 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5012 cylinder
->lpVtbl
->Release(cylinder
);
5016 /* theta = angle on xy plane wrt x axis */
5017 theta_step
= -2.0f
* D3DX_PI
/ slices
;
5018 theta_start
= D3DX_PI
/ 2.0f
;
5020 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
5022 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5023 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5024 cylinder
->lpVtbl
->Release(cylinder
);
5025 return E_OUTOFMEMORY
;
5031 delta_radius
= radius1
- radius2
;
5033 radius_step
= delta_radius
/ stacks
;
5036 z_step
= length
/ stacks
;
5037 z_normal
= delta_radius
/ length
;
5038 if (isnan(z_normal
))
5043 vertices
[vertex
].normal
.x
= 0.0f
;
5044 vertices
[vertex
].normal
.y
= 0.0f
;
5045 vertices
[vertex
].normal
.z
= -1.0f
;
5046 vertices
[vertex
].position
.x
= 0.0f
;
5047 vertices
[vertex
].position
.y
= 0.0f
;
5048 vertices
[vertex
++].position
.z
= z
;
5050 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5052 vertices
[vertex
].normal
.x
= 0.0f
;
5053 vertices
[vertex
].normal
.y
= 0.0f
;
5054 vertices
[vertex
].normal
.z
= -1.0f
;
5055 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5056 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5057 vertices
[vertex
].position
.z
= z
;
5062 faces
[face
][1] = slice
;
5063 faces
[face
++][2] = slice
+ 1;
5068 faces
[face
][1] = slice
;
5069 faces
[face
++][2] = 1;
5071 for (stack
= 1; stack
<= stacks
+1; stack
++)
5073 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5075 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
5076 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
5077 vertices
[vertex
].normal
.z
= z_normal
;
5078 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
5079 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5080 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5081 vertices
[vertex
].position
.z
= z
;
5083 if (stack
> 1 && slice
> 0)
5085 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
5086 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5087 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
5089 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
5090 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5091 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5097 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
5098 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5099 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
5101 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
5102 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
5103 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
5106 if (stack
< stacks
+ 1)
5109 radius
-= radius_step
;
5113 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
5115 vertices
[vertex
].normal
.x
= 0.0f
;
5116 vertices
[vertex
].normal
.y
= 0.0f
;
5117 vertices
[vertex
].normal
.z
= 1.0f
;
5118 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
5119 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
5120 vertices
[vertex
].position
.z
= z
;
5124 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5125 faces
[face
][1] = number_of_vertices
- 1;
5126 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
5130 vertices
[vertex
].position
.x
= 0.0f
;
5131 vertices
[vertex
].position
.y
= 0.0f
;
5132 vertices
[vertex
].position
.z
= z
;
5133 vertices
[vertex
].normal
.x
= 0.0f
;
5134 vertices
[vertex
].normal
.y
= 0.0f
;
5135 vertices
[vertex
].normal
.z
= 1.0f
;
5137 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
5138 faces
[face
][1] = number_of_vertices
- 1;
5139 faces
[face
][2] = vertex_index(slices
, 0, stack
);
5141 free_sincos_table(&theta
);
5142 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
5143 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
5147 if (FAILED(hr
= D3DXCreateBuffer(number_of_faces
* sizeof(DWORD
) * 3, adjacency
)))
5149 cylinder
->lpVtbl
->Release(cylinder
);
5153 if (FAILED(hr
= cylinder
->lpVtbl
->GenerateAdjacency(cylinder
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
5155 (*adjacency
)->lpVtbl
->Release(*adjacency
);
5156 cylinder
->lpVtbl
->Release(cylinder
);
5166 HRESULT WINAPI
D3DXCreateTeapot(struct IDirect3DDevice9
*device
,
5167 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
5169 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
5174 HRESULT WINAPI
D3DXCreateTextA(struct IDirect3DDevice9
*device
, HDC hdc
, const char *text
, float deviation
,
5175 float extrusion
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5181 TRACE("device %p, hdc %p, text %s, deviation %.8e, extrusion %.8e, mesh %p, adjacency %p, glyphmetrics %p.\n",
5182 device
, hdc
, debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
5185 return D3DERR_INVALIDCALL
;
5187 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
5188 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5189 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
5191 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
5192 mesh
, adjacency
, glyphmetrics
);
5193 HeapFree(GetProcessHeap(), 0, textW
);
5198 HRESULT WINAPI
D3DXCreateTorus(struct IDirect3DDevice9
*device
,
5199 float innerradius
, float outerradius
, UINT sides
, UINT rings
, struct ID3DXMesh
**mesh
, ID3DXBuffer
**adjacency
)
5204 struct vertex
*vertices
;
5205 float phi
, phi_step
, sin_phi
, cos_phi
;
5206 float theta
, theta_step
, sin_theta
, cos_theta
;
5207 unsigned int i
, j
, numvert
, numfaces
;
5209 TRACE("device %p, innerradius %.8e, outerradius %.8e, sides %u, rings %u, mesh %p, adjacency %p.\n",
5210 device
, innerradius
, outerradius
, sides
, rings
, mesh
, adjacency
);
5212 numvert
= sides
* rings
;
5213 numfaces
= numvert
* 2;
5215 if (!device
|| innerradius
< 0.0f
|| outerradius
< 0.0f
|| sides
< 3 || rings
< 3 || !mesh
)
5217 WARN("Invalid arguments.\n");
5218 return D3DERR_INVALIDCALL
;
5221 if (FAILED(hr
= D3DXCreateMeshFVF(numfaces
, numvert
, D3DXMESH_MANAGED
, D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &torus
)))
5224 if (FAILED(hr
= torus
->lpVtbl
->LockVertexBuffer(torus
, 0, (void **)&vertices
)))
5226 torus
->lpVtbl
->Release(torus
);
5230 if (FAILED(hr
= torus
->lpVtbl
->LockIndexBuffer(torus
, 0, (void **)&faces
)))
5232 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5233 torus
->lpVtbl
->Release(torus
);
5237 phi_step
= D3DX_PI
/ sides
* 2.0f
;
5238 theta_step
= D3DX_PI
/ rings
* -2.0f
;
5242 for (i
= 0; i
< rings
; ++i
)
5246 sin_theta
= sinf(theta
);
5247 cos_theta
= cosf(theta
);
5249 for (j
= 0; j
< sides
; ++j
)
5251 sin_phi
= sinf(phi
);
5252 cos_phi
= cosf(phi
);
5254 vertices
[i
* sides
+ j
].position
.x
= (innerradius
* cos_phi
+ outerradius
) * cos_theta
;
5255 vertices
[i
* sides
+ j
].position
.y
= (innerradius
* cos_phi
+ outerradius
) * sin_theta
;
5256 vertices
[i
* sides
+ j
].position
.z
= innerradius
* sin_phi
;
5257 vertices
[i
* sides
+ j
].normal
.x
= cos_phi
* cos_theta
;
5258 vertices
[i
* sides
+ j
].normal
.y
= cos_phi
* sin_theta
;
5259 vertices
[i
* sides
+ j
].normal
.z
= sin_phi
;
5264 theta
+= theta_step
;
5267 for (i
= 0; i
< numfaces
- sides
* 2; ++i
)
5269 faces
[i
][0] = i
% 2 ? i
/ 2 + sides
: i
/ 2;
5270 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5271 faces
[i
][2] = (i
+ 1) % (sides
* 2) ? (i
+ 1) / 2 + sides
: (i
+ 1) / 2;
5274 for (j
= 0; i
< numfaces
; ++i
, ++j
)
5276 faces
[i
][0] = i
% 2 ? j
/ 2 : i
/ 2;
5277 faces
[i
][1] = (i
/ 2 + 1) % sides
? i
/ 2 + 1 : i
/ 2 + 1 - sides
;
5278 faces
[i
][2] = i
== numfaces
- 1 ? 0 : (j
+ 1) / 2;
5281 torus
->lpVtbl
->UnlockIndexBuffer(torus
);
5282 torus
->lpVtbl
->UnlockVertexBuffer(torus
);
5286 if (FAILED(hr
= D3DXCreateBuffer(numfaces
* sizeof(DWORD
) * 3, adjacency
)))
5288 torus
->lpVtbl
->Release(torus
);
5292 if (FAILED(hr
= torus
->lpVtbl
->GenerateAdjacency(torus
, 0.0f
, (*adjacency
)->lpVtbl
->GetBufferPointer(*adjacency
))))
5294 (*adjacency
)->lpVtbl
->Release(*adjacency
);
5295 torus
->lpVtbl
->Release(torus
);
5306 POINTTYPE_CURVE
= 0,
5308 POINTTYPE_CURVE_START
,
5309 POINTTYPE_CURVE_END
,
5310 POINTTYPE_CURVE_MIDDLE
,
5316 enum pointtype corner
;
5319 struct dynamic_array
5321 int count
, capacity
;
5325 /* is a dynamic_array */
5328 int count
, capacity
;
5329 struct point2d
*items
;
5332 /* is a dynamic_array */
5333 struct outline_array
5335 int count
, capacity
;
5336 struct outline
*items
;
5345 struct point2d_index
5347 struct outline
*outline
;
5351 struct point2d_index_array
5354 struct point2d_index
*items
;
5359 struct outline_array outlines
;
5360 struct face_array faces
;
5361 struct point2d_index_array ordered_vertices
;
5365 /* is an dynamic_array */
5368 int count
, capacity
;
5372 /* complex polygons are split into monotone polygons, which have
5373 * at most 2 intersections with the vertical sweep line */
5374 struct triangulation
5376 struct word_array vertex_stack
;
5377 BOOL last_on_top
, merging
;
5380 /* is an dynamic_array */
5381 struct triangulation_array
5383 int count
, capacity
;
5384 struct triangulation
*items
;
5386 struct glyphinfo
*glyph
;
5389 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
5391 if (count
> array
->capacity
) {
5394 if (array
->items
&& array
->capacity
) {
5395 new_capacity
= max(array
->capacity
* 2, count
);
5396 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
5398 new_capacity
= max(16, count
);
5399 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
5403 array
->items
= new_buffer
;
5404 array
->capacity
= new_capacity
;
5409 static struct point2d
*add_points(struct outline
*array
, int num
)
5411 struct point2d
*item
;
5413 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
5416 item
= &array
->items
[array
->count
];
5417 array
->count
+= num
;
5421 static struct outline
*add_outline(struct outline_array
*array
)
5423 struct outline
*item
;
5425 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5428 item
= &array
->items
[array
->count
++];
5429 ZeroMemory(item
, sizeof(*item
));
5433 static inline face
*add_face(struct face_array
*array
)
5435 return &array
->items
[array
->count
++];
5438 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
5440 struct triangulation
*item
;
5442 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5445 item
= &array
->items
[array
->count
++];
5446 ZeroMemory(item
, sizeof(*item
));
5450 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
5452 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5453 return E_OUTOFMEMORY
;
5455 array
->items
[array
->count
++] = vertex_index
;
5459 /* assume fixed point numbers can be converted to float point in place */
5460 C_ASSERT(sizeof(FIXED
) == sizeof(float));
5461 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
5463 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, unsigned int emsquare
)
5465 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
5467 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
5468 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
5469 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
5475 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
5476 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
5477 float max_deviation_sq
)
5479 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
5482 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
5483 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
5484 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
5486 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
5487 if (deviation_sq
< max_deviation_sq
) {
5488 struct point2d
*pt
= add_points(outline
, 1);
5489 if (!pt
) return E_OUTOFMEMORY
;
5491 pt
->corner
= POINTTYPE_CURVE
;
5492 /* the end point is omitted because the end line merges into the next segment of
5493 * the split bezier curve, and the end of the split bezier curve is added outside
5494 * this recursive function. */
5496 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
5497 if (hr
!= S_OK
) return hr
;
5498 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
5499 if (hr
!= S_OK
) return hr
;
5505 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
5507 /* dot product = cos(theta) */
5508 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
5511 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
5513 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
5523 static BOOL
attempt_line_merge(struct outline
*outline
,
5525 const D3DXVECTOR2
*nextpt
,
5527 const struct cos_table
*table
)
5529 D3DXVECTOR2 curdir
, lastdir
;
5530 struct point2d
*prevpt
, *pt
;
5533 pt
= &outline
->items
[pt_index
];
5534 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5535 prevpt
= &outline
->items
[pt_index
];
5538 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
5540 if (outline
->count
< 2)
5543 /* remove last point if the next line continues the last line */
5544 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5545 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5546 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
5549 if (pt
->corner
== POINTTYPE_CURVE_END
)
5550 prevpt
->corner
= pt
->corner
;
5551 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
5552 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5556 if (outline
->count
< 2)
5559 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5560 prevpt
= &outline
->items
[pt_index
];
5561 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5562 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5567 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
5568 float max_deviation_sq
, unsigned int emsquare
,
5569 const struct cos_table
*cos_table
)
5571 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
5573 while ((char *)header
< (char *)raw_outline
+ datasize
)
5575 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
5576 struct point2d
*lastpt
, *pt
;
5577 D3DXVECTOR2 lastdir
;
5578 D3DXVECTOR2
*pt_flt
;
5580 struct outline
*outline
= add_outline(&glyph
->outlines
);
5583 return E_OUTOFMEMORY
;
5585 pt
= add_points(outline
, 1);
5587 return E_OUTOFMEMORY
;
5588 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
5590 pt
->corner
= POINTTYPE_CORNER
;
5592 if (header
->dwType
!= TT_POLYGON_TYPE
)
5593 FIXME("Unknown header type %d\n", header
->dwType
);
5595 while ((char *)curve
< (char *)header
+ header
->cb
)
5597 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
5598 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
5599 unsigned int j2
= 0;
5602 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5606 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
5608 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
5613 int count
= curve
->cpfx
;
5617 D3DXVECTOR2 bezier_end
;
5619 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j2
], &pt_flt
[j2
+1]), 0.5f
);
5620 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &bezier_end
, max_deviation_sq
);
5623 bezier_start
= bezier_end
;
5627 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &pt_flt
[j2
+1], max_deviation_sq
);
5631 pt
= add_points(outline
, 1);
5633 return E_OUTOFMEMORY
;
5635 pt
->pos
= pt_flt
[j2
];
5636 pt
->corner
= POINTTYPE_CURVE_END
;
5638 pt
= add_points(outline
, curve
->cpfx
);
5640 return E_OUTOFMEMORY
;
5641 for (j2
= 0; j2
< curve
->cpfx
; j2
++)
5643 pt
->pos
= pt_flt
[j2
];
5644 pt
->corner
= POINTTYPE_CORNER
;
5649 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5652 /* remove last point if the next line continues the last line */
5653 if (outline
->count
>= 3) {
5656 lastpt
= &outline
->items
[outline
->count
- 1];
5657 pt
= &outline
->items
[0];
5658 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
5659 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
5661 if (pt
->corner
== POINTTYPE_CURVE_START
)
5662 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5664 pt
->corner
= POINTTYPE_CURVE_END
;
5667 lastpt
= &outline
->items
[outline
->count
- 1];
5669 /* outline closed with a line from end to start point */
5670 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
5672 lastpt
= &outline
->items
[0];
5673 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
5674 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
5675 lastpt
->corner
= POINTTYPE_CORNER
;
5676 pt
= &outline
->items
[1];
5677 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
5678 *lastpt
= outline
->items
[outline
->count
];
5681 lastpt
= &outline
->items
[outline
->count
- 1];
5682 pt
= &outline
->items
[0];
5683 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
5684 for (j
= 0; j
< outline
->count
; j
++)
5689 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
5690 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
5692 switch (lastpt
->corner
)
5694 case POINTTYPE_CURVE_START
:
5695 case POINTTYPE_CURVE_END
:
5696 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
5697 lastpt
->corner
= POINTTYPE_CORNER
;
5699 case POINTTYPE_CURVE_MIDDLE
:
5700 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
5701 lastpt
->corner
= POINTTYPE_CORNER
;
5703 lastpt
->corner
= POINTTYPE_CURVE
;
5711 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
5716 /* Get the y-distance from a line to a point */
5717 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
5718 D3DXVECTOR2
*line_pt2
,
5721 D3DXVECTOR2 line_vec
= {0, 0};
5725 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
5726 line_pt_dx
= point
->x
- line_pt1
->x
;
5727 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
5728 return point
->y
- line_y
;
5731 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
5733 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
5736 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
5738 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
5741 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
5743 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
5744 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
5748 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
5749 struct triangulation_array
*triangulations
,
5753 struct glyphinfo
*glyph
= triangulations
->glyph
;
5754 struct triangulation
*t
= *t_ptr
;
5759 if (t
->last_on_top
) {
5767 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
5768 /* consume all vertices on the stack */
5769 WORD last_pt
= t
->vertex_stack
.items
[0];
5771 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
5773 face
= add_face(&glyph
->faces
);
5774 if (!face
) return E_OUTOFMEMORY
;
5775 (*face
)[0] = vtx_idx
;
5776 (*face
)[f1
] = last_pt
;
5777 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
5779 t
->vertex_stack
.items
[0] = last_pt
;
5780 t
->vertex_stack
.count
= 1;
5781 } else if (t
->vertex_stack
.count
> 1) {
5782 int i
= t
->vertex_stack
.count
- 1;
5783 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
5784 WORD top_idx
= t
->vertex_stack
.items
[i
--];
5785 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
5789 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
5790 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
5792 if (prev_pt
->x
!= top_pt
->x
&&
5793 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
5794 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
5797 face
= add_face(&glyph
->faces
);
5798 if (!face
) return E_OUTOFMEMORY
;
5799 (*face
)[0] = vtx_idx
;
5800 (*face
)[f1
] = prev_idx
;
5801 (*face
)[f2
] = top_idx
;
5805 t
->vertex_stack
.count
--;
5808 t
->last_on_top
= to_top
;
5810 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
5812 if (hr
== S_OK
&& t
->merging
) {
5813 struct triangulation
*t2
;
5815 t2
= to_top
? t
- 1 : t
+ 1;
5816 t2
->merging
= FALSE
;
5817 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
5818 if (hr
!= S_OK
) return hr
;
5819 remove_triangulation(triangulations
, t
);
5827 /* check if the point is next on the outline for either the top or bottom */
5828 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
5830 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
5831 WORD idx
= t
->vertex_stack
.items
[i
];
5832 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
5833 struct outline
*outline
= pt_idx
->outline
;
5836 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
5838 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
5840 return &outline
->items
[i
].pos
;
5843 static int compare_vertex_indices(const void *a
, const void *b
)
5845 const struct point2d_index
*idx1
= a
, *idx2
= b
;
5846 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
5847 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
5848 float diff
= p1
->x
- p2
->x
;
5851 diff
= p1
->y
- p2
->y
;
5853 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
5856 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
5860 struct glyphinfo
*glyph
= triangulations
->glyph
;
5861 int nb_vertices
= 0;
5863 struct point2d_index
*idx_ptr
;
5865 /* Glyphs without outlines do not generate any vertices. */
5866 if (!glyph
->outlines
.count
)
5869 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5870 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
5872 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
5873 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
5874 if (!glyph
->ordered_vertices
.items
)
5875 return E_OUTOFMEMORY
;
5877 idx_ptr
= glyph
->ordered_vertices
.items
;
5878 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5880 struct outline
*outline
= &glyph
->outlines
.items
[i
];
5883 idx_ptr
->outline
= outline
;
5884 idx_ptr
->vertex
= 0;
5886 for (j
= outline
->count
- 1; j
> 0; j
--)
5888 idx_ptr
->outline
= outline
;
5889 idx_ptr
->vertex
= j
;
5893 glyph
->ordered_vertices
.count
= nb_vertices
;
5895 /* Native implementation seems to try to create a triangle fan from
5896 * the first outline point if the glyph only has one outline. */
5897 if (glyph
->outlines
.count
== 1)
5899 struct outline
*outline
= glyph
->outlines
.items
;
5900 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
5901 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
5904 for (i
= 2; i
< outline
->count
; i
++)
5906 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
5907 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
5908 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
5910 D3DXVec2Subtract(&v1
, base
, last
);
5911 D3DXVec2Subtract(&v2
, last
, next
);
5912 ccw
= D3DXVec2CCW(&v1
, &v2
);
5920 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5921 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
5922 if (!glyph
->faces
.items
)
5923 return E_OUTOFMEMORY
;
5925 glyph
->faces
.count
= outline
->count
- 2;
5926 for (i
= 0; i
< glyph
->faces
.count
; i
++)
5928 glyph
->faces
.items
[i
][0] = 0;
5929 glyph
->faces
.items
[i
][1] = i
+ 1;
5930 glyph
->faces
.items
[i
][2] = i
+ 2;
5936 /* Perform 2D polygon triangulation for complex glyphs.
5937 * Triangulation is performed using a sweep line concept, from right to left,
5938 * by processing vertices in sorted order. Complex polygons are split into
5939 * monotone polygons which are triangulated separately. */
5940 /* FIXME: The order of the faces is not consistent with the native implementation. */
5942 /* Reserve space for maximum possible faces from triangulation.
5943 * # faces for outer outlines = outline->count - 2
5944 * # faces for inner outlines = outline->count + 2
5945 * There must be at least 1 outer outline. */
5946 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5947 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
5948 if (!glyph
->faces
.items
)
5949 return E_OUTOFMEMORY
;
5951 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
5952 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
5953 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
5956 int end
= triangulations
->count
;
5960 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
5961 int current
= (start
+ end
) / 2;
5962 struct triangulation
*t
= &triangulations
->items
[current
];
5963 BOOL on_top_outline
= FALSE
;
5964 D3DXVECTOR2
*top_next
, *bottom_next
;
5965 WORD top_idx
, bottom_idx
;
5967 if (t
->merging
&& t
->last_on_top
)
5968 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
5970 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
5971 if (sweep_vtx
== top_next
)
5973 if (t
->merging
&& t
->last_on_top
)
5975 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
5976 if (hr
!= S_OK
) return hr
;
5978 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
5979 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
5981 /* point also on bottom outline of higher triangulation */
5982 struct triangulation
*t2
= t
+ 1;
5983 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
5984 if (hr
!= S_OK
) return hr
;
5989 on_top_outline
= TRUE
;
5992 if (t
->merging
&& !t
->last_on_top
)
5993 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
5995 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
5996 if (sweep_vtx
== bottom_next
)
5998 if (t
->merging
&& !t
->last_on_top
)
6000 if (on_top_outline
) {
6001 /* outline finished */
6002 remove_triangulation(triangulations
, t
);
6006 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
6007 if (hr
!= S_OK
) return hr
;
6009 if (t
> triangulations
->items
&&
6010 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
6012 struct triangulation
*t2
= t
- 1;
6013 /* point also on top outline of lower triangulation */
6014 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
6015 if (hr
!= S_OK
) return hr
;
6016 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
6026 if (t
->last_on_top
) {
6027 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
6028 bottom_idx
= t
->vertex_stack
.items
[0];
6030 top_idx
= t
->vertex_stack
.items
[0];
6031 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
6034 /* check if the point is inside or outside this polygon */
6035 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
6036 top_next
, sweep_vtx
) > 0)
6038 start
= current
+ 1;
6039 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
6040 bottom_next
, sweep_vtx
) < 0)
6043 } else if (t
->merging
) {
6044 /* inside, so cancel merging */
6045 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
6047 t2
->merging
= FALSE
;
6048 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
6049 if (hr
!= S_OK
) return hr
;
6050 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
6051 if (hr
!= S_OK
) return hr
;
6054 /* inside, so split polygon into two monotone parts */
6055 struct triangulation
*t2
= add_triangulation(triangulations
);
6056 if (!t2
) return E_OUTOFMEMORY
;
6057 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
6058 if (t
->last_on_top
) {
6065 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
6066 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
6067 if (hr
!= S_OK
) return hr
;
6068 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
6069 if (hr
!= S_OK
) return hr
;
6070 t2
->last_on_top
= !t
->last_on_top
;
6072 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
6073 if (hr
!= S_OK
) return hr
;
6079 struct triangulation
*t
;
6080 struct triangulation
*t2
= add_triangulation(triangulations
);
6081 if (!t2
) return E_OUTOFMEMORY
;
6082 t
= &triangulations
->items
[start
];
6083 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
6084 ZeroMemory(t
, sizeof(*t
));
6085 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
6086 if (hr
!= S_OK
) return hr
;
6092 HRESULT WINAPI
D3DXCreateTextW(struct IDirect3DDevice9
*device
, HDC hdc
, const WCHAR
*text
, float deviation
,
6093 float extrusion
, struct ID3DXMesh
**mesh_ptr
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
6096 ID3DXMesh
*mesh
= NULL
;
6097 DWORD nb_vertices
, nb_faces
;
6098 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
6099 struct vertex
*vertices
= NULL
;
6104 OUTLINETEXTMETRICW otm
;
6105 HFONT font
= NULL
, oldfont
= NULL
;
6106 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
6107 void *raw_outline
= NULL
;
6109 struct glyphinfo
*glyphs
= NULL
;
6111 struct triangulation_array triangulations
= {0, 0, NULL
};
6113 struct vertex
*vertex_ptr
;
6115 float max_deviation_sq
;
6116 const struct cos_table cos_table
= {
6117 cosf(D3DXToRadian(0.5f
)),
6118 cosf(D3DXToRadian(45.0f
)),
6119 cosf(D3DXToRadian(90.0f
)),
6123 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
6124 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
6126 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
6127 return D3DERR_INVALIDCALL
;
6131 FIXME("Case of adjacency != NULL not implemented.\n");
6135 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
6136 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
6138 return D3DERR_INVALIDCALL
;
6141 if (deviation
== 0.0f
)
6142 deviation
= 1.0f
/ otm
.otmEMSquare
;
6143 max_deviation_sq
= deviation
* deviation
;
6145 lf
.lfHeight
= otm
.otmEMSquare
;
6147 font
= CreateFontIndirectW(&lf
);
6152 oldfont
= SelectObject(hdc
, font
);
6154 textlen
= strlenW(text
);
6155 for (i
= 0; i
< textlen
; i
++)
6157 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
6159 return D3DERR_INVALIDCALL
;
6160 if (bufsize
< datasize
)
6163 if (!bufsize
) { /* e.g. text == " " */
6164 hr
= D3DERR_INVALIDCALL
;
6168 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
6169 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
6170 if (!glyphs
|| !raw_outline
) {
6176 for (i
= 0; i
< textlen
; i
++)
6178 /* get outline points from data returned from GetGlyphOutline */
6181 glyphs
[i
].offset_x
= offset_x
;
6183 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
6184 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
6185 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
6186 if (hr
!= S_OK
) goto error
;
6188 triangulations
.glyph
= &glyphs
[i
];
6189 hr
= triangulate(&triangulations
);
6190 if (hr
!= S_OK
) goto error
;
6191 if (triangulations
.count
) {
6192 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
6193 triangulations
.count
= 0;
6198 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
6199 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
6200 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
6201 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
6202 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6203 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
6205 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
6208 /* corner points need an extra vertex for the different side faces normals */
6210 nb_outline_points
= 0;
6212 for (i
= 0; i
< textlen
; i
++)
6215 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
6216 nb_front_faces
+= glyphs
[i
].faces
.count
;
6217 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6220 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6221 nb_corners
++; /* first outline point always repeated as a corner */
6222 for (k
= 1; k
< outline
->count
; k
++)
6223 if (outline
->items
[k
].corner
)
6228 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
6229 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
6232 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
6233 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
6237 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
6240 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, (void **)&faces
)))
6243 /* convert 2D vertices and faces into 3D mesh */
6244 vertex_ptr
= vertices
;
6246 if (extrusion
== 0.0f
) {
6253 for (i
= 0; i
< textlen
; i
++)
6257 struct vertex
*back_vertices
;
6260 /* side vertices and faces */
6261 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6263 struct vertex
*outline_vertices
= vertex_ptr
;
6264 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
6266 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
6267 struct point2d
*pt
= &outline
->items
[0];
6269 for (k
= 1; k
<= outline
->count
; k
++)
6272 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
6273 WORD vtx_idx
= vertex_ptr
- vertices
;
6276 if (pt
->corner
== POINTTYPE_CURVE_START
)
6277 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
6278 else if (pt
->corner
)
6279 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6281 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
6282 D3DXVec2Normalize(&vec
, &vec
);
6283 vtx
.normal
.x
= -vec
.y
;
6284 vtx
.normal
.y
= vec
.x
;
6287 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
6288 vtx
.position
.y
= pt
->pos
.y
;
6290 *vertex_ptr
++ = vtx
;
6292 vtx
.position
.z
= -extrusion
;
6293 *vertex_ptr
++ = vtx
;
6295 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
6296 vtx
.position
.y
= nextpt
->pos
.y
;
6297 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
6298 vtx
.position
.z
= -extrusion
;
6299 *vertex_ptr
++ = vtx
;
6301 *vertex_ptr
++ = vtx
;
6303 (*face_ptr
)[0] = vtx_idx
;
6304 (*face_ptr
)[1] = vtx_idx
+ 2;
6305 (*face_ptr
)[2] = vtx_idx
+ 1;
6308 (*face_ptr
)[0] = vtx_idx
;
6309 (*face_ptr
)[1] = vtx_idx
+ 3;
6310 (*face_ptr
)[2] = vtx_idx
+ 2;
6313 if (nextpt
->corner
) {
6314 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
6315 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
6316 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
6318 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
6320 D3DXVec2Normalize(&vec
, &vec
);
6321 vtx
.normal
.x
= -vec
.y
;
6322 vtx
.normal
.y
= vec
.x
;
6325 *vertex_ptr
++ = vtx
;
6326 vtx
.position
.z
= -extrusion
;
6327 *vertex_ptr
++ = vtx
;
6330 (*face_ptr
)[0] = vtx_idx
;
6331 (*face_ptr
)[1] = vtx_idx
+ 3;
6332 (*face_ptr
)[2] = vtx_idx
+ 1;
6335 (*face_ptr
)[0] = vtx_idx
;
6336 (*face_ptr
)[1] = vtx_idx
+ 2;
6337 (*face_ptr
)[2] = vtx_idx
+ 3;
6345 *vertex_ptr
++ = *outline_vertices
++;
6346 *vertex_ptr
++ = *outline_vertices
++;
6350 /* back vertices and faces */
6351 back_faces
= face_ptr
;
6352 back_vertices
= vertex_ptr
;
6353 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
6355 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
6356 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
6357 vertex_ptr
->position
.y
= pt
->y
;
6358 vertex_ptr
->position
.z
= 0;
6359 vertex_ptr
->normal
.x
= 0;
6360 vertex_ptr
->normal
.y
= 0;
6361 vertex_ptr
->normal
.z
= 1;
6364 count
= back_vertices
- vertices
;
6365 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
6367 face
*f
= &glyphs
[i
].faces
.items
[j
];
6368 (*face_ptr
)[0] = (*f
)[0] + count
;
6369 (*face_ptr
)[1] = (*f
)[1] + count
;
6370 (*face_ptr
)[2] = (*f
)[2] + count
;
6374 /* front vertices and faces */
6375 j
= count
= vertex_ptr
- back_vertices
;
6378 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
6379 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
6380 vertex_ptr
->position
.z
= -extrusion
;
6381 vertex_ptr
->normal
.x
= 0;
6382 vertex_ptr
->normal
.y
= 0;
6383 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
6387 j
= face_ptr
- back_faces
;
6390 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
6391 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
6392 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
6402 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6403 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6404 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
6407 for (i
= 0; i
< textlen
; i
++)
6410 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6411 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
6412 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
6413 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
6414 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
6416 HeapFree(GetProcessHeap(), 0, glyphs
);
6418 if (triangulations
.items
) {
6420 for (i
= 0; i
< triangulations
.count
; i
++)
6421 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
6422 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
6424 HeapFree(GetProcessHeap(), 0, raw_outline
);
6425 if (oldfont
) SelectObject(hdc
, oldfont
);
6426 if (font
) DeleteObject(font
);
6431 HRESULT WINAPI
D3DXValidMesh(ID3DXMesh
*mesh
, const DWORD
*adjacency
, ID3DXBuffer
**errors_and_warnings
)
6433 FIXME("(%p, %p, %p): stub\n", mesh
, adjacency
, *errors_and_warnings
);
6438 static BOOL
weld_float1(void *to
, void *from
, FLOAT epsilon
)
6443 if (fabsf(*v1
- *v2
) <= epsilon
)
6453 static BOOL
weld_float2(void *to
, void *from
, FLOAT epsilon
)
6455 D3DXVECTOR2
*v1
= to
;
6456 D3DXVECTOR2
*v2
= from
;
6457 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6458 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6459 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6461 if (max_abs_diff
<= epsilon
)
6463 memcpy(to
, from
, sizeof(D3DXVECTOR2
));
6471 static BOOL
weld_float3(void *to
, void *from
, FLOAT epsilon
)
6473 D3DXVECTOR3
*v1
= to
;
6474 D3DXVECTOR3
*v2
= from
;
6475 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6476 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6477 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6478 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6479 max_abs_diff
= max(diff_z
, max_abs_diff
);
6481 if (max_abs_diff
<= epsilon
)
6483 memcpy(to
, from
, sizeof(D3DXVECTOR3
));
6491 static BOOL
weld_float4(void *to
, void *from
, FLOAT epsilon
)
6493 D3DXVECTOR4
*v1
= to
;
6494 D3DXVECTOR4
*v2
= from
;
6495 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6496 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6497 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6498 FLOAT diff_w
= fabsf(v1
->w
- v2
->w
);
6499 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6500 max_abs_diff
= max(diff_z
, max_abs_diff
);
6501 max_abs_diff
= max(diff_w
, max_abs_diff
);
6503 if (max_abs_diff
<= epsilon
)
6505 memcpy(to
, from
, sizeof(D3DXVECTOR4
));
6513 static BOOL
weld_ubyte4(void *to
, void *from
, FLOAT epsilon
)
6517 BYTE truncated_epsilon
= (BYTE
)epsilon
;
6518 BYTE diff_x
= b1
[0] > b2
[0] ? b1
[0] - b2
[0] : b2
[0] - b1
[0];
6519 BYTE diff_y
= b1
[1] > b2
[1] ? b1
[1] - b2
[1] : b2
[1] - b1
[1];
6520 BYTE diff_z
= b1
[2] > b2
[2] ? b1
[2] - b2
[2] : b2
[2] - b1
[2];
6521 BYTE diff_w
= b1
[3] > b2
[3] ? b1
[3] - b2
[3] : b2
[3] - b1
[3];
6522 BYTE max_diff
= max(diff_x
, diff_y
);
6523 max_diff
= max(diff_z
, max_diff
);
6524 max_diff
= max(diff_w
, max_diff
);
6526 if (max_diff
<= truncated_epsilon
)
6528 memcpy(to
, from
, 4 * sizeof(BYTE
));
6536 static BOOL
weld_ubyte4n(void *to
, void *from
, FLOAT epsilon
)
6538 return weld_ubyte4(to
, from
, epsilon
* UCHAR_MAX
);
6541 static BOOL
weld_d3dcolor(void *to
, void *from
, FLOAT epsilon
)
6543 return weld_ubyte4n(to
, from
, epsilon
);
6546 static BOOL
weld_short2(void *to
, void *from
, FLOAT epsilon
)
6550 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6551 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6552 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6553 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6555 if (max_abs_diff
<= truncated_epsilon
)
6557 memcpy(to
, from
, 2 * sizeof(SHORT
));
6565 static BOOL
weld_short2n(void *to
, void *from
, FLOAT epsilon
)
6567 return weld_short2(to
, from
, epsilon
* SHRT_MAX
);
6570 static BOOL
weld_short4(void *to
, void *from
, FLOAT epsilon
)
6574 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6575 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6576 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6577 SHORT diff_z
= abs(s1
[2] - s2
[2]);
6578 SHORT diff_w
= abs(s1
[3] - s2
[3]);
6579 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6580 max_abs_diff
= max(diff_z
, max_abs_diff
);
6581 max_abs_diff
= max(diff_w
, max_abs_diff
);
6583 if (max_abs_diff
<= truncated_epsilon
)
6585 memcpy(to
, from
, 4 * sizeof(SHORT
));
6593 static BOOL
weld_short4n(void *to
, void *from
, FLOAT epsilon
)
6595 return weld_short4(to
, from
, epsilon
* SHRT_MAX
);
6598 static BOOL
weld_ushort2n(void *to
, void *from
, FLOAT epsilon
)
6602 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6603 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6604 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6605 USHORT max_diff
= max(diff_x
, diff_y
);
6607 if (max_diff
<= scaled_epsilon
)
6609 memcpy(to
, from
, 2 * sizeof(USHORT
));
6617 static BOOL
weld_ushort4n(void *to
, void *from
, FLOAT epsilon
)
6621 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6622 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6623 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6624 USHORT diff_z
= s1
[2] > s2
[2] ? s1
[2] - s2
[2] : s2
[2] - s1
[2];
6625 USHORT diff_w
= s1
[3] > s2
[3] ? s1
[3] - s2
[3] : s2
[3] - s1
[3];
6626 USHORT max_diff
= max(diff_x
, diff_y
);
6627 max_diff
= max(diff_z
, max_diff
);
6628 max_diff
= max(diff_w
, max_diff
);
6630 if (max_diff
<= scaled_epsilon
)
6632 memcpy(to
, from
, 4 * sizeof(USHORT
));
6648 static struct udec3
dword_to_udec3(DWORD d
)
6653 v
.y
= (d
& 0xffc00) >> 10;
6654 v
.z
= (d
& 0x3ff00000) >> 20;
6655 v
.w
= (d
& 0xc0000000) >> 30;
6660 static BOOL
weld_udec3(void *to
, void *from
, FLOAT epsilon
)
6664 struct udec3 v1
= dword_to_udec3(*d1
);
6665 struct udec3 v2
= dword_to_udec3(*d2
);
6666 UINT truncated_epsilon
= (UINT
)epsilon
;
6667 UINT diff_x
= v1
.x
> v2
.x
? v1
.x
- v2
.x
: v2
.x
- v1
.x
;
6668 UINT diff_y
= v1
.y
> v2
.y
? v1
.y
- v2
.y
: v2
.y
- v1
.y
;
6669 UINT diff_z
= v1
.z
> v2
.z
? v1
.z
- v2
.z
: v2
.z
- v1
.z
;
6670 UINT diff_w
= v1
.w
> v2
.w
? v1
.w
- v2
.w
: v2
.w
- v1
.w
;
6671 UINT max_diff
= max(diff_x
, diff_y
);
6672 max_diff
= max(diff_z
, max_diff
);
6673 max_diff
= max(diff_w
, max_diff
);
6675 if (max_diff
<= truncated_epsilon
)
6677 memcpy(to
, from
, sizeof(DWORD
));
6693 static struct dec3n
dword_to_dec3n(DWORD d
)
6698 v
.y
= (d
& 0xffc00) >> 10;
6699 v
.z
= (d
& 0x3ff00000) >> 20;
6700 v
.w
= (d
& 0xc0000000) >> 30;
6705 static BOOL
weld_dec3n(void *to
, void *from
, FLOAT epsilon
)
6707 const UINT MAX_DEC3N
= 511;
6710 struct dec3n v1
= dword_to_dec3n(*d1
);
6711 struct dec3n v2
= dword_to_dec3n(*d2
);
6712 INT scaled_epsilon
= (INT
)(epsilon
* MAX_DEC3N
);
6713 INT diff_x
= abs(v1
.x
- v2
.x
);
6714 INT diff_y
= abs(v1
.y
- v2
.y
);
6715 INT diff_z
= abs(v1
.z
- v2
.z
);
6716 INT diff_w
= abs(v1
.w
- v2
.w
);
6717 INT max_abs_diff
= max(diff_x
, diff_y
);
6718 max_abs_diff
= max(diff_z
, max_abs_diff
);
6719 max_abs_diff
= max(diff_w
, max_abs_diff
);
6721 if (max_abs_diff
<= scaled_epsilon
)
6723 memcpy(to
, from
, sizeof(DWORD
));
6731 static BOOL
weld_float16_2(void *to
, void *from
, FLOAT epsilon
)
6733 D3DXFLOAT16
*v1_float16
= to
;
6734 D3DXFLOAT16
*v2_float16
= from
;
6742 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6743 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6745 diff_x
= fabsf(v1
[0] - v2
[0]);
6746 diff_y
= fabsf(v1
[1] - v2
[1]);
6747 max_abs_diff
= max(diff_x
, diff_y
);
6749 if (max_abs_diff
<= epsilon
)
6751 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6760 static BOOL
weld_float16_4(void *to
, void *from
, FLOAT epsilon
)
6762 D3DXFLOAT16
*v1_float16
= to
;
6763 D3DXFLOAT16
*v2_float16
= from
;
6773 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6774 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6776 diff_x
= fabsf(v1
[0] - v2
[0]);
6777 diff_y
= fabsf(v1
[1] - v2
[1]);
6778 diff_z
= fabsf(v1
[2] - v2
[2]);
6779 diff_w
= fabsf(v1
[3] - v2
[3]);
6780 max_abs_diff
= max(diff_x
, diff_y
);
6781 max_abs_diff
= max(diff_z
, max_abs_diff
);
6782 max_abs_diff
= max(diff_w
, max_abs_diff
);
6784 if (max_abs_diff
<= epsilon
)
6786 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6795 /* Sets the vertex components to the same value if they are within epsilon. */
6796 static BOOL
weld_component(void *to
, void *from
, D3DDECLTYPE type
, FLOAT epsilon
)
6798 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6799 BOOL fixme_once_unused
= FALSE
;
6800 BOOL fixme_once_unknown
= FALSE
;
6804 case D3DDECLTYPE_FLOAT1
:
6805 return weld_float1(to
, from
, epsilon
);
6807 case D3DDECLTYPE_FLOAT2
:
6808 return weld_float2(to
, from
, epsilon
);
6810 case D3DDECLTYPE_FLOAT3
:
6811 return weld_float3(to
, from
, epsilon
);
6813 case D3DDECLTYPE_FLOAT4
:
6814 return weld_float4(to
, from
, epsilon
);
6816 case D3DDECLTYPE_D3DCOLOR
:
6817 return weld_d3dcolor(to
, from
, epsilon
);
6819 case D3DDECLTYPE_UBYTE4
:
6820 return weld_ubyte4(to
, from
, epsilon
);
6822 case D3DDECLTYPE_SHORT2
:
6823 return weld_short2(to
, from
, epsilon
);
6825 case D3DDECLTYPE_SHORT4
:
6826 return weld_short4(to
, from
, epsilon
);
6828 case D3DDECLTYPE_UBYTE4N
:
6829 return weld_ubyte4n(to
, from
, epsilon
);
6831 case D3DDECLTYPE_SHORT2N
:
6832 return weld_short2n(to
, from
, epsilon
);
6834 case D3DDECLTYPE_SHORT4N
:
6835 return weld_short4n(to
, from
, epsilon
);
6837 case D3DDECLTYPE_USHORT2N
:
6838 return weld_ushort2n(to
, from
, epsilon
);
6840 case D3DDECLTYPE_USHORT4N
:
6841 return weld_ushort4n(to
, from
, epsilon
);
6843 case D3DDECLTYPE_UDEC3
:
6844 return weld_udec3(to
, from
, epsilon
);
6846 case D3DDECLTYPE_DEC3N
:
6847 return weld_dec3n(to
, from
, epsilon
);
6849 case D3DDECLTYPE_FLOAT16_2
:
6850 return weld_float16_2(to
, from
, epsilon
);
6852 case D3DDECLTYPE_FLOAT16_4
:
6853 return weld_float16_4(to
, from
, epsilon
);
6855 case D3DDECLTYPE_UNUSED
:
6856 if (!fixme_once_unused
++)
6857 FIXME("D3DDECLTYPE_UNUSED welding not implemented.\n");
6861 if (!fixme_once_unknown
++)
6862 FIXME("Welding of unknown declaration type %d is not implemented.\n", type
);
6869 static FLOAT
get_component_epsilon(const D3DVERTEXELEMENT9
*decl_ptr
, const D3DXWELDEPSILONS
*epsilons
)
6871 FLOAT epsilon
= 0.0f
;
6872 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6873 static BOOL fixme_once_blendindices
= FALSE
;
6874 static BOOL fixme_once_positiont
= FALSE
;
6875 static BOOL fixme_once_fog
= FALSE
;
6876 static BOOL fixme_once_depth
= FALSE
;
6877 static BOOL fixme_once_sample
= FALSE
;
6878 static BOOL fixme_once_unknown
= FALSE
;
6880 switch (decl_ptr
->Usage
)
6882 case D3DDECLUSAGE_POSITION
:
6883 epsilon
= epsilons
->Position
;
6885 case D3DDECLUSAGE_BLENDWEIGHT
:
6886 epsilon
= epsilons
->BlendWeights
;
6888 case D3DDECLUSAGE_NORMAL
:
6889 epsilon
= epsilons
->Normals
;
6891 case D3DDECLUSAGE_PSIZE
:
6892 epsilon
= epsilons
->PSize
;
6894 case D3DDECLUSAGE_TEXCOORD
:
6896 BYTE usage_index
= decl_ptr
->UsageIndex
;
6897 if (usage_index
> 7)
6899 epsilon
= epsilons
->Texcoords
[usage_index
];
6902 case D3DDECLUSAGE_TANGENT
:
6903 epsilon
= epsilons
->Tangent
;
6905 case D3DDECLUSAGE_BINORMAL
:
6906 epsilon
= epsilons
->Binormal
;
6908 case D3DDECLUSAGE_TESSFACTOR
:
6909 epsilon
= epsilons
->TessFactor
;
6911 case D3DDECLUSAGE_COLOR
:
6912 if (decl_ptr
->UsageIndex
== 0)
6913 epsilon
= epsilons
->Diffuse
;
6914 else if (decl_ptr
->UsageIndex
== 1)
6915 epsilon
= epsilons
->Specular
;
6919 case D3DDECLUSAGE_BLENDINDICES
:
6920 if (!fixme_once_blendindices
++)
6921 FIXME("D3DDECLUSAGE_BLENDINDICES welding not implemented.\n");
6923 case D3DDECLUSAGE_POSITIONT
:
6924 if (!fixme_once_positiont
++)
6925 FIXME("D3DDECLUSAGE_POSITIONT welding not implemented.\n");
6927 case D3DDECLUSAGE_FOG
:
6928 if (!fixme_once_fog
++)
6929 FIXME("D3DDECLUSAGE_FOG welding not implemented.\n");
6931 case D3DDECLUSAGE_DEPTH
:
6932 if (!fixme_once_depth
++)
6933 FIXME("D3DDECLUSAGE_DEPTH welding not implemented.\n");
6935 case D3DDECLUSAGE_SAMPLE
:
6936 if (!fixme_once_sample
++)
6937 FIXME("D3DDECLUSAGE_SAMPLE welding not implemented.\n");
6940 if (!fixme_once_unknown
++)
6941 FIXME("Unknown usage %x\n", decl_ptr
->Usage
);
6948 /* Helper function for reading a 32-bit index buffer. */
6949 static inline DWORD
read_ib(void *index_buffer
, BOOL indices_are_32bit
,
6952 if (indices_are_32bit
)
6954 DWORD
*indices
= index_buffer
;
6955 return indices
[index
];
6959 WORD
*indices
= index_buffer
;
6960 return indices
[index
];
6964 /* Helper function for writing to a 32-bit index buffer. */
6965 static inline void write_ib(void *index_buffer
, BOOL indices_are_32bit
,
6966 DWORD index
, DWORD value
)
6968 if (indices_are_32bit
)
6970 DWORD
*indices
= index_buffer
;
6971 indices
[index
] = value
;
6975 WORD
*indices
= index_buffer
;
6976 indices
[index
] = value
;
6980 /*************************************************************************
6981 * D3DXWeldVertices (D3DX9_36.@)
6983 * Welds together similar vertices. The similarity between vert-
6984 * ices can be the position and other components such as
6988 * mesh [I] Mesh which vertices will be welded together.
6989 * flags [I] D3DXWELDEPSILONSFLAGS specifying how to weld.
6990 * epsilons [I] How similar a component needs to be for welding.
6991 * adjacency [I] Which faces are adjacent to other faces.
6992 * adjacency_out [O] Updated adjacency after welding.
6993 * face_remap_out [O] Which faces the old faces have been mapped to.
6994 * vertex_remap_out [O] Which vertices the old vertices have been mapped to.
6998 * Failure: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
7001 * Attribute sorting not implemented.
7004 HRESULT WINAPI
D3DXWeldVertices(ID3DXMesh
*mesh
, DWORD flags
, const D3DXWELDEPSILONS
*epsilons
,
7005 const DWORD
*adjacency
, DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
7007 DWORD
*adjacency_generated
= NULL
;
7008 const DWORD
*adjacency_ptr
;
7009 DWORD
*attributes
= NULL
;
7010 const FLOAT DEFAULT_EPSILON
= 1.0e-6f
;
7013 void *indices
= NULL
;
7014 BOOL indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
7015 DWORD optimize_flags
;
7016 DWORD
*point_reps
= NULL
;
7017 struct d3dx9_mesh
*This
= impl_from_ID3DXMesh(mesh
);
7018 DWORD
*vertex_face_map
= NULL
;
7019 BYTE
*vertices
= NULL
;
7021 TRACE("mesh %p, flags %#x, epsilons %p, adjacency %p, adjacency_out %p, face_remap_out %p, vertex_remap_out %p.\n",
7022 mesh
, flags
, epsilons
, adjacency
, adjacency_out
, face_remap_out
, vertex_remap_out
);
7026 WARN("No flags are undefined. Using D3DXWELDEPSILONS_WELDPARTIALMATCHES instead.\n");
7027 flags
= D3DXWELDEPSILONS_WELDPARTIALMATCHES
;
7030 if (adjacency
) /* Use supplied adjacency. */
7032 adjacency_ptr
= adjacency
;
7034 else /* Adjacency has to be generated. */
7036 adjacency_generated
= HeapAlloc(GetProcessHeap(), 0, 3 * This
->numfaces
* sizeof(*adjacency_generated
));
7037 if (!adjacency_generated
)
7039 ERR("Couldn't allocate memory for adjacency_generated.\n");
7043 hr
= mesh
->lpVtbl
->GenerateAdjacency(mesh
, DEFAULT_EPSILON
, adjacency_generated
);
7046 ERR("Couldn't generate adjacency.\n");
7049 adjacency_ptr
= adjacency_generated
;
7052 /* Point representation says which vertices can be replaced. */
7053 point_reps
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*point_reps
));
7057 ERR("Couldn't allocate memory for point_reps.\n");
7060 hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency_ptr
, point_reps
);
7063 ERR("ConvertAdjacencyToPointReps failed.\n");
7067 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
);
7070 ERR("Couldn't lock index buffer.\n");
7074 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, 0, &attributes
);
7077 ERR("Couldn't lock attribute buffer.\n");
7080 vertex_face_map
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*vertex_face_map
));
7081 if (!vertex_face_map
)
7084 ERR("Couldn't allocate memory for vertex_face_map.\n");
7087 /* Build vertex face map, so that a vertex's face can be looked up. */
7088 for (i
= 0; i
< This
->numfaces
; i
++)
7091 for (j
= 0; j
< 3; j
++)
7093 DWORD index
= read_ib(indices
, indices_are_32bit
, 3*i
+ j
);
7094 vertex_face_map
[index
] = i
;
7098 if (flags
& D3DXWELDEPSILONS_WELDPARTIALMATCHES
)
7100 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void**)&vertices
);
7103 ERR("Couldn't lock vertex buffer.\n");
7106 /* For each vertex that can be removed, compare its vertex components
7107 * with the vertex components from the vertex that can replace it. A
7108 * vertex is only fully replaced if all the components match and the
7109 * flag D3DXWELDEPSILONS_DONOTREMOVEVERTICES is not set, and they
7110 * belong to the same attribute group. Otherwise the vertex components
7111 * that are within epsilon are set to the same value.
7113 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
7115 D3DVERTEXELEMENT9
*decl_ptr
;
7116 DWORD vertex_size
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
7117 DWORD num_vertex_components
;
7120 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7122 for (decl_ptr
= This
->cached_declaration
, num_vertex_components
= 0; decl_ptr
->Stream
!= 0xFF; decl_ptr
++, num_vertex_components
++)
7124 BYTE
*to
= &vertices
[vertex_size
*index
+ decl_ptr
->Offset
];
7125 BYTE
*from
= &vertices
[vertex_size
*point_reps
[index
] + decl_ptr
->Offset
];
7126 FLOAT epsilon
= get_component_epsilon(decl_ptr
, epsilons
);
7128 /* Don't weld self */
7129 if (index
== point_reps
[index
])
7135 if (weld_component(to
, from
, decl_ptr
->Type
, epsilon
))
7139 all_match
= (num_vertex_components
== matches
);
7140 if (all_match
&& !(flags
& D3DXWELDEPSILONS_DONOTREMOVEVERTICES
))
7142 DWORD to_face
= vertex_face_map
[index
];
7143 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7144 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7146 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7149 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7152 else if (flags
& D3DXWELDEPSILONS_WELDALL
)
7154 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
7156 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
7157 DWORD to_face
= vertex_face_map
[index
];
7158 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
7159 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
7161 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
7164 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7166 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7169 /* Compact mesh using OptimizeInplace */
7170 optimize_flags
= D3DXMESHOPT_COMPACT
;
7171 hr
= mesh
->lpVtbl
->OptimizeInplace(mesh
, optimize_flags
, adjacency_ptr
, adjacency_out
, face_remap_out
, vertex_remap_out
);
7174 ERR("Couldn't compact mesh.\n");
7180 HeapFree(GetProcessHeap(), 0, adjacency_generated
);
7181 HeapFree(GetProcessHeap(), 0, point_reps
);
7182 HeapFree(GetProcessHeap(), 0, vertex_face_map
);
7183 if (attributes
) mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
7184 if (indices
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7185 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7190 /*************************************************************************
7191 * D3DXOptimizeFaces (D3DX9_36.@)
7193 * Re-orders the faces so the vertex cache is used optimally.
7196 * indices [I] Pointer to an index buffer belonging to a mesh.
7197 * num_faces [I] Number of faces in the mesh.
7198 * num_vertices [I] Number of vertices in the mesh.
7199 * indices_are_32bit [I] Specifies whether indices are 32- or 16-bit.
7200 * face_remap [I/O] The new order the faces should be drawn in.
7204 * Failure: D3DERR_INVALIDCALL.
7207 * The face re-ordering does not use the vertex cache optimally.
7210 HRESULT WINAPI
D3DXOptimizeFaces(const void *indices
, UINT num_faces
,
7211 UINT num_vertices
, BOOL indices_are_32bit
, DWORD
*face_remap
)
7214 UINT j
= num_faces
- 1;
7215 UINT limit_16_bit
= 2 << 15; /* According to MSDN */
7216 HRESULT hr
= D3D_OK
;
7218 FIXME("indices %p, num_faces %u, num_vertices %u, indices_are_32bit %#x, face_remap %p semi-stub. "
7219 "Face order will not be optimal.\n",
7220 indices
, num_faces
, num_vertices
, indices_are_32bit
, face_remap
);
7222 if (!indices_are_32bit
&& num_faces
>= limit_16_bit
)
7224 WARN("Number of faces must be less than %d when using 16-bit indices.\n",
7226 hr
= D3DERR_INVALIDCALL
;
7232 WARN("Face remap pointer is NULL.\n");
7233 hr
= D3DERR_INVALIDCALL
;
7237 /* The faces are drawn in reverse order for simple meshes. This ordering
7238 * is not optimal for complicated meshes, but will not break anything
7239 * either. The ordering should be changed to take advantage of the vertex
7240 * cache on the graphics card.
7242 * TODO Re-order to take advantage of vertex cache.
7244 for (i
= 0; i
< num_faces
; i
++)
7246 face_remap
[i
] = j
--;
7255 static D3DXVECTOR3
*vertex_element_vec3(BYTE
*vertices
, const D3DVERTEXELEMENT9
*declaration
,
7256 DWORD vertex_stride
, DWORD index
)
7258 return (D3DXVECTOR3
*)(vertices
+ declaration
->Offset
+ index
* vertex_stride
);
7261 static D3DXVECTOR3
read_vec3(BYTE
*vertices
, const D3DVERTEXELEMENT9
*declaration
,
7262 DWORD vertex_stride
, DWORD index
)
7264 D3DXVECTOR3 vec3
= {0};
7265 const D3DXVECTOR3
*src
= vertex_element_vec3(vertices
, declaration
, vertex_stride
, index
);
7267 switch (declaration
->Type
)
7269 case D3DDECLTYPE_FLOAT1
:
7272 case D3DDECLTYPE_FLOAT2
:
7276 case D3DDECLTYPE_FLOAT3
:
7277 case D3DDECLTYPE_FLOAT4
:
7281 ERR("Cannot read vec3\n");
7288 /*************************************************************************
7289 * D3DXComputeTangentFrameEx (D3DX9_36.@)
7291 HRESULT WINAPI
D3DXComputeTangentFrameEx(ID3DXMesh
*mesh
, DWORD texture_in_semantic
, DWORD texture_in_index
,
7292 DWORD u_partial_out_semantic
, DWORD u_partial_out_index
, DWORD v_partial_out_semantic
,
7293 DWORD v_partial_out_index
, DWORD normal_out_semantic
, DWORD normal_out_index
, DWORD options
,
7294 const DWORD
*adjacency
, float partial_edge_threshold
, float singular_point_threshold
,
7295 float normal_edge_threshold
, ID3DXMesh
**mesh_out
, ID3DXBuffer
**vertex_mapping
)
7298 void *indices
= NULL
;
7299 BYTE
*vertices
= NULL
;
7300 DWORD
*point_reps
= NULL
;
7302 BOOL indices_are_32bit
;
7303 DWORD i
, j
, num_faces
, num_vertices
, vertex_stride
;
7304 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
7305 D3DVERTEXELEMENT9
*position_declaration
= NULL
, *normal_declaration
= NULL
;
7306 DWORD weighting_method
= options
& (D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
);
7308 TRACE("mesh %p, texture_in_semantic %u, texture_in_index %u, u_partial_out_semantic %u, u_partial_out_index %u, "
7309 "v_partial_out_semantic %u, v_partial_out_index %u, normal_out_semantic %u, normal_out_index %u, "
7310 "options %#x, adjacency %p, partial_edge_threshold %f, singular_point_threshold %f, "
7311 "normal_edge_threshold %f, mesh_out %p, vertex_mapping %p\n",
7312 mesh
, texture_in_semantic
, texture_in_index
, u_partial_out_semantic
, u_partial_out_index
,
7313 v_partial_out_semantic
, v_partial_out_index
, normal_out_semantic
, normal_out_index
, options
, adjacency
,
7314 partial_edge_threshold
, singular_point_threshold
, normal_edge_threshold
, mesh_out
, vertex_mapping
);
7318 WARN("mesh is NULL\n");
7319 return D3DERR_INVALIDCALL
;
7322 if (weighting_method
== (D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
))
7324 WARN("D3DXTANGENT_WEIGHT_BY_AREA and D3DXTANGENT_WEIGHT_EQUAL are mutally exclusive\n");
7325 return D3DERR_INVALIDCALL
;
7328 if (u_partial_out_semantic
!= D3DX_DEFAULT
)
7330 FIXME("tangent vectors computation is not supported\n");
7334 if (v_partial_out_semantic
!= D3DX_DEFAULT
)
7336 FIXME("binormal vectors computation is not supported\n");
7340 if (options
& ~(D3DXTANGENT_GENERATE_IN_PLACE
| D3DXTANGENT_CALCULATE_NORMALS
| D3DXTANGENT_WEIGHT_EQUAL
| D3DXTANGENT_WEIGHT_BY_AREA
))
7342 FIXME("unsupported options %#x\n", options
);
7346 if (!(options
& D3DXTANGENT_CALCULATE_NORMALS
))
7348 FIXME("only normals computation is supported\n");
7352 if (!(options
& D3DXTANGENT_GENERATE_IN_PLACE
) || mesh_out
|| vertex_mapping
)
7354 FIXME("only D3DXTANGENT_GENERATE_IN_PLACE is supported\n");
7358 if (FAILED(hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, declaration
)))
7361 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
7363 if (declaration
[i
].Usage
== D3DDECLUSAGE_POSITION
&& !declaration
[i
].UsageIndex
)
7364 position_declaration
= &declaration
[i
];
7365 if (declaration
[i
].Usage
== normal_out_semantic
&& declaration
[i
].UsageIndex
== normal_out_index
)
7366 normal_declaration
= &declaration
[i
];
7369 if (!position_declaration
|| !normal_declaration
)
7370 return D3DERR_INVALIDCALL
;
7372 if (normal_declaration
->Type
== D3DDECLTYPE_FLOAT3
)
7374 normal_size
= sizeof(D3DXVECTOR3
);
7376 else if (normal_declaration
->Type
== D3DDECLTYPE_FLOAT4
)
7378 normal_size
= sizeof(D3DXVECTOR4
);
7382 WARN("unsupported normals type %u\n", normal_declaration
->Type
);
7383 return D3DERR_INVALIDCALL
;
7386 num_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
7387 num_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
7388 vertex_stride
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
7389 indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
7391 point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*point_reps
));
7400 if (FAILED(hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency
, point_reps
)))
7405 for (i
= 0; i
< num_vertices
; i
++)
7409 if (FAILED(hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
)))
7412 if (FAILED(hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void **)&vertices
)))
7415 for (i
= 0; i
< num_vertices
; i
++)
7417 static const D3DXVECTOR4 default_vector
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
7418 void *normal
= vertices
+ normal_declaration
->Offset
+ i
* vertex_stride
;
7420 memcpy(normal
, &default_vector
, normal_size
);
7423 for (i
= 0; i
< num_faces
; i
++)
7425 float denominator
, weights
[3];
7426 D3DXVECTOR3 a
, b
, cross
, face_normal
;
7427 const DWORD face_indices
[3] =
7429 read_ib(indices
, indices_are_32bit
, 3 * i
+ 0),
7430 read_ib(indices
, indices_are_32bit
, 3 * i
+ 1),
7431 read_ib(indices
, indices_are_32bit
, 3 * i
+ 2)
7433 const D3DXVECTOR3 v0
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[0]);
7434 const D3DXVECTOR3 v1
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[1]);
7435 const D3DXVECTOR3 v2
= read_vec3(vertices
, position_declaration
, vertex_stride
, face_indices
[2]);
7437 D3DXVec3Cross(&cross
, D3DXVec3Subtract(&a
, &v0
, &v1
), D3DXVec3Subtract(&b
, &v0
, &v2
));
7439 switch (weighting_method
)
7441 case D3DXTANGENT_WEIGHT_EQUAL
:
7442 weights
[0] = weights
[1] = weights
[2] = 1.0f
;
7444 case D3DXTANGENT_WEIGHT_BY_AREA
:
7445 weights
[0] = weights
[1] = weights
[2] = D3DXVec3Length(&cross
);
7448 /* weight by angle */
7449 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7453 weights
[0] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7455 D3DXVec3Subtract(&a
, &v1
, &v0
);
7456 D3DXVec3Subtract(&b
, &v1
, &v2
);
7457 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7461 weights
[1] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7463 D3DXVec3Subtract(&a
, &v2
, &v0
);
7464 D3DXVec3Subtract(&b
, &v2
, &v1
);
7465 denominator
= D3DXVec3Length(&a
) * D3DXVec3Length(&b
);
7469 weights
[2] = acosf(D3DXVec3Dot(&a
, &b
) / denominator
);
7474 D3DXVec3Normalize(&face_normal
, &cross
);
7476 for (j
= 0; j
< 3; j
++)
7479 DWORD rep_index
= point_reps
[face_indices
[j
]];
7480 D3DXVECTOR3
*rep_normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, rep_index
);
7482 D3DXVec3Scale(&normal
, &face_normal
, weights
[j
]);
7483 D3DXVec3Add(rep_normal
, rep_normal
, &normal
);
7487 for (i
= 0; i
< num_vertices
; i
++)
7489 DWORD rep_index
= point_reps
[i
];
7490 D3DXVECTOR3
*normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, i
);
7491 D3DXVECTOR3
*rep_normal
= vertex_element_vec3(vertices
, normal_declaration
, vertex_stride
, rep_index
);
7494 D3DXVec3Normalize(rep_normal
, rep_normal
);
7496 *normal
= *rep_normal
;
7503 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
7506 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
7508 HeapFree(GetProcessHeap(), 0, point_reps
);
7513 /*************************************************************************
7514 * D3DXComputeNormals (D3DX9_36.@)
7516 HRESULT WINAPI
D3DXComputeNormals(struct ID3DXBaseMesh
*mesh
, const DWORD
*adjacency
)
7518 TRACE("mesh %p, adjacency %p\n", mesh
, adjacency
);
7520 if (mesh
&& (ID3DXMeshVtbl
*)mesh
->lpVtbl
!= &D3DXMesh_Vtbl
)
7522 ERR("Invalid virtual table\n");
7523 return D3DERR_INVALIDCALL
;
7526 return D3DXComputeTangentFrameEx((ID3DXMesh
*)mesh
, D3DX_DEFAULT
, 0,
7527 D3DX_DEFAULT
, 0, D3DX_DEFAULT
, 0, D3DDECLUSAGE_NORMAL
, 0,
7528 D3DXTANGENT_GENERATE_IN_PLACE
| D3DXTANGENT_CALCULATE_NORMALS
,
7529 adjacency
, -1.01f
, -0.01f
, -1.01f
, NULL
, NULL
);
7532 /*************************************************************************
7533 * D3DXIntersect (D3DX9_36.@)
7535 HRESULT WINAPI
D3DXIntersect(ID3DXBaseMesh
*mesh
, const D3DXVECTOR3
*ray_pos
, const D3DXVECTOR3
*ray_dir
,
7536 BOOL
*hit
, DWORD
*face_index
, float *u
, float *v
, float *distance
, ID3DXBuffer
**all_hits
, DWORD
*count_of_hits
)
7538 FIXME("mesh %p, ray_pos %p, ray_dir %p, hit %p, face_index %p, u %p, v %p, distance %p, all_hits %p, "
7539 "count_of_hits %p stub!\n", mesh
, ray_pos
, ray_dir
, hit
, face_index
, u
, v
, distance
, all_hits
, count_of_hits
);
7544 HRESULT WINAPI
D3DXTessellateNPatches(ID3DXMesh
*mesh
, const DWORD
*adjacency_in
, float num_segs
,
7545 BOOL quadratic_normals
, ID3DXMesh
**mesh_out
, ID3DXBuffer
**adjacency_out
)
7547 FIXME("mesh %p, adjacency_in %p, num_segs %f, quadratic_normals %d, mesh_out %p, adjacency_out %p stub.\n",
7548 mesh
, adjacency_in
, num_segs
, quadratic_normals
, mesh_out
, adjacency_out
);
7553 HRESULT WINAPI
D3DXConvertMeshSubsetToSingleStrip(struct ID3DXBaseMesh
*mesh_in
, DWORD attribute_id
,
7554 DWORD ib_flags
, struct IDirect3DIndexBuffer9
**index_buffer
, DWORD
*index_count
)
7556 FIXME("mesh_in %p, attribute_id %u, ib_flags %u, index_buffer %p, index_count %p stub.\n",
7557 mesh_in
, attribute_id
, ib_flags
, index_buffer
, index_count
);